0

I'm writing some Qt application for read cpu/memory states. However, appears a some error: Cannot open proc/stat device. Application is crashed. Please tell me where is problem ? Bellow i will also provide a piece of code.

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;
}
zex_coder
  • 11
  • 1
  • Thanks for the effort. I've included code changes, also does not work. However, when I start it from the command line with the command cat stat from exactly folder, the program working. I am think in Qt frameworks is something wrong ?! – zex_coder Jan 20 '19 at 12:04
  • This depends on how it _does not work_. Could you explain in more detail? Does it fail to open `"/proc/stat"`? – Scheff's Cat Jan 20 '19 at 12:07
  • Yes, /proc/stat/ not does not work in application. I can not find how. I would try to insert the c++ stl library instead of qt to work with files, maybe then it succeeds. – zex_coder Jan 20 '19 at 12:38
  • The `QFile` is only a wrapper for the I/O functions of C library or OS API. (I tried to find the resp. source code on woboq.org but it's engine based and I gave up. You may dig deeper if interested.) However, if you can get it working with C++ or C I/O functions, then I would agree with your doubt about a broken Qt installation. File access permissions could be an issue as well although I'm not sure why reading of `/proc/stat` should be prohibited. – Scheff's Cat Jan 20 '19 at 12:56
  • I am find some interesting when debugging: can't find linker symbol for virtual table for `SysInfoWidget', but i have override correctly so, something wrong is in Qt. I'll have to investigate further. Thanks again for the effort. – zex_coder Jan 20 '19 at 13:26

1 Answers1

0

The code exposed by OP has various flaws where it may fail:

  1. QFile file("proc/stat"); tries to open proc/stat in the current directory. If this isn't accidentally the root directory it might not open what OP expects or just fail.
    This should be replaced with QFile file("/proc/stat"); which opens an absolute path (independent of current directory).

  2. The success of file.open(QIODevice::ReadOnly); isn't tested. QFile::open() has return type bool and

    returning true if successful; otherwise false.

    This should be checked.

  3. The success of std::sscanf(line.data(), "cpu %llu %llu %llu %llu", &totalUser, &totalUserNice, &totalSystem, &totalIdle); isn't checked as well. std::sscanf() has return type int and returns

    Number of receiving arguments successfully assigned (which may be zero in case a matching failure occurred before the first receiving argument was assigned), or EOF if input failure occurs before the first receiving argument was assigned.

I turned the sample code of OP into an MCVE and added some diagnostics to demonstrate the issues:

#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;
}

I compiled and tested the code on cygwin (I'm on Windows 10) and got the following output:

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

Finally, I'm not quite sure why OP claims that

Application is crashed.

I strongly believe that the crash doesn't occur in the exposed code (but somewhere else). I think so because:

  1. QByteArray line = file.readLine(); (when tries to read from file which failed to open) results in an empty array (QIODevice::readLine(), QByteArray) but even an empty array always ensures that the data is followed by a '\0' terminator.

  2. Hence, the access to line.data() in std::sscanf(line.data(), "cpu %llu %llu %llu %llu", &totalUser, &totalUserNice, &totalSystem, &totalIdle); should be safe even if none of the variables are assigned. The variables in turn are initialized and have defined values even if sscanf() failed.

  3. The final calls of rawData.append() might potentially allocate memory which may fail but, again, I don't see what might crash here.

So, I haven't any clue what of this code may crash except that other, previously executed code caused Undefined Behavior which accidentally starts to become visible in the exposed code.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56