如何修复无法在Linux中使用proc / stat系统文件的Qt应用程序

时间:2019-01-20 10:18:56

标签: c++ qt5

我正在为读取CPU /内存状态编写一些Qt应用程序。但是,出现一些错误:无法打开proc / stat设备。应用程序崩溃了。请告诉我哪里出了问题?在下面,我还将提供一段代码。

QVector<qulonglong> SysInfoLinuxImpl::cpuRawData()
{
    QFile file("proc/stat");
    file.open(QIODevice::ReadOnly);
    QByteArray line = file.readLine();
    file.close();
    qulonglong totalUser = 0, totalUserNice = 0, totalSystem = 0, totalIdle = 0;
    std::sscanf(line.data(), "cpu %llu %llu %llu %llu", &totalUser, &totalUserNice, &totalSystem, &totalIdle);
    QVector<qulonglong> rawData;
    rawData.append(totalUser);
    rawData.append(totalUserNice);
    rawData.append(totalSystem);
    rawData.append(totalIdle);
    return rawData;
}

1 个答案:

答案 0 :(得分:0)

OP公开的代码可能会导致多种缺陷:

  1. QFile file("proc/stat");尝试在当前目录中打开proc/stat。如果这不是偶然的根目录,则可能无法打开OP期望的目录,或者只是失败。
    应该用QFile file("/proc/stat");代替,它打开一个绝对路径(独立于当前目录)。

  2. file.open(QIODevice::ReadOnly);的成功未得到测试。 QFile::open()的返回类型为bool

      

    成功则返回true;否则为假。

    应该选中它。

  3. 也未检查std::sscanf(line.data(), "cpu %llu %llu %llu %llu", &totalUser, &totalUserNice, &totalSystem, &totalIdle);是否成功。 std::sscanf()的返回类型为int并返回

      

    成功分配的接收参数的数量(如果在分配第一个接收参数之前发生匹配失败,则为零);如果在分配第一个接收参数之前发生输入失败,则为EOF。

我将OP的示例代码转换为MCVE,并添加了一些诊断程序来演示问题:

#include <QtWidgets>

namespace SysInfoLinuxImpl {

template <bool FIX = false>
QVector<qulonglong> cpuRawData();

} // namespace SysInfoLinuxImpl

template <bool FIX = false>
QVector<qulonglong> SysInfoLinuxImpl::cpuRawData()
{
  QFile file(FIX ? "/proc/stat" : "proc/stat");
  file.open(QIODevice::ReadOnly);
  QByteArray line = file.readLine();
  file.close();
  qDebug() << "line:" << line;
  qulonglong totalUser = 0, totalUserNice = 0, totalSystem = 0, totalIdle = 0;
  int ret =
  std::sscanf(line.data(), "cpu %llu %llu %llu %llu", &totalUser, &totalUserNice, &totalSystem, &totalIdle);
  qDebug() << "sscanf(): " << ret;
  qDebug() << "totalUser:    " << totalUser;
  qDebug() << "totalUserNice:" << totalUserNice;
  qDebug() << "totalSystem:  " << totalSystem;
  qDebug() << "totalIdle:    " << totalIdle;
  QVector<qulonglong> rawData;
  rawData.append(totalUser);
  rawData.append(totalUserNice);
  rawData.append(totalSystem);
  rawData.append(totalIdle);
  return rawData;
}

int main()
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  // check original code
  qDebug() << "with 'proc/stat'";
  SysInfoLinuxImpl::cpuRawData();
  // check fixed code
  qDebug() << "with '/proc/stat'";
  SysInfoLinuxImpl::cpuRawData<true>();
  return 0;
}

我在cygwin(在Windows 10上)上编译并测试了代码,并得到以下输出:

Qt Version: 5.9.4
with 'proc/stat'
QIODevice::read (QFile, "proc/stat"): device not open
line: ""
sscanf():  -1
totalUser:     0
totalUserNice: 0
totalSystem:   0
totalIdle:     0
with '/proc/stat'
line: "cpu 137982341 0 106654637 1152709669\n"
sscanf():  4
totalUser:     137982341
totalUserNice: 0
totalSystem:   106654637
totalIdle:     1152709669

最后,我不太确定为什么OP会这么说

  

应用程序崩溃了。

我坚信崩溃不会在公开代码中发生(而是在其他地方)。我认为是因为:

  1. QByteArray line = file.readLine();(尝试从无法打开的file读取时)会导致一个空数组(QIODevice::readLine()QByteArray),甚至会导致一个空数组始终确保数据后跟一个'\ 0'终止符

  2. 因此,即使未分配任何变量,对line.data()std::sscanf(line.data(), "cpu %llu %llu %llu %llu", &totalUser, &totalUserNice, &totalSystem, &totalIdle);的访问也应该是安全的。即使sscanf()失败,变量也会被初始化并具有定义的值。

  3. rawData.append()的最终调用可能会分配内存,这可能会失败,但是再次,我看不到这里会崩溃。

因此,除了其他先前执行的代码导致Undefined Behavior意外地在公开代码中变得可见之外,我不知道这段代码可能会崩溃的原因。