Как исправить приложение Qt, которое не работает с системным файлом proc / stat в linux - PullRequest
0 голосов
/ 20 января 2019

Я пишу некоторое приложение 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 голосов
/ 20 января 2019

Код, предоставляемый OP, имеет различные недостатки, из-за которых он может не работать:

  1. QFile file("proc/stat"); пытается открыть proc/stat в текущем каталоге.Если это не случайно корневой каталог, он может не открыть то, что ожидает OP, или просто потерпеть неудачу.Его следует заменить на QFile file("<b>/</b>proc/stat");, который открывает абсолютный путь (независимо от текущего каталога).

  2. Успех file.open(QIODevice::ReadOnly); не проверен.QFile::open() имеет тип возврата bool и

    , возвращающие true в случае успеха;в противном случае - false.

    Это следует проверить.

  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() могут потенциально выделить память, которая может дать сбой, но, опять же, я нене вижу, что может привести к сбою здесь.

Итак, я не имею ни малейшего понятия, что может произойти сбой этого кода, за исключением того, что другой, ранее выполненный код вызвал неопределенное поведение , котороеслучайно начинает становиться видимым в выставленном коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...