The code exposed by OP has various flaws where it may fail:
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).
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.
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:
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.
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.
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.