tst_QFile: update virtualFile() to check if readLine() reads all
We know that all lines from /proc/<PID>/maps end in a newline, so we trim exactly that one byte, then we put it all back together with .join('\n') to check if we've read the entire file. Linux virtual files are usually served in 4 kB increments; tst_qfile's maps file is about 16000 bytes for me, just short of the QIODevice buffer: [pid 414315] read(5, "55c6afe04000-55c6afe11000 r--p 0"..., 16384) = 4049 [pid 414315] read(5, "7f215fd25000-7f215fd26000 r--p 0"..., 12335) = 4038 [pid 414315] read(5, "7f2160800000-7f21608c7000 r--p 0"..., 8297) = 4072 [pid 414315] read(5, "7f216119f000-7f21611a0000 rw-p 0"..., 4225) = 3994 It is not a coincidence that the reads are at line boundaries, though it's not a guarantee from the kernel. We appear to have accidentally fixed the QEMU emulation bug by reading another process' /proc/<PID>/maps (hypothesis: QMU emulates the target system in /proc/self, hiding itself in maps, but makes no translation for other process map files. Change-Id: Ifbf974a4d10745b099b1fffd1777ac919b12dc90 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
9d4579c1cd
commit
7ca82250e0
@ -52,7 +52,9 @@ QT_END_NAMESPACE
|
||||
#ifdef Q_OS_DARWIN
|
||||
# include <sys/mount.h>
|
||||
#elif defined(Q_OS_LINUX)
|
||||
# include <sys/eventfd.h>
|
||||
# include <sys/vfs.h>
|
||||
# include <sys/wait.h>
|
||||
#elif defined(Q_OS_FREEBSD)
|
||||
# include <sys/param.h>
|
||||
# include <sys/mount.h>
|
||||
@ -2613,8 +2615,29 @@ void tst_QFile::writeToReadOnlyFile()
|
||||
// This platform have 0-sized virtual files
|
||||
void tst_QFile::virtualFile()
|
||||
{
|
||||
// test if QFile works with virtual files
|
||||
QString fname = "/proc/self/maps";
|
||||
// We need to test a large-ish /proc file on Linux, one that is usually
|
||||
// over 4 kB (because the kernel writes in chunks of that), has a
|
||||
// cross-platform file format, and is definitely readable. The best
|
||||
// candidate and the one we can verify anything in is /proc/<PID>/maps.
|
||||
// However, our act of reading may change the map because we allocate
|
||||
// memory, so we fork() here so we have a frozen snapshot of the file.
|
||||
|
||||
int efd = eventfd(0, EFD_CLOEXEC);
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
// child
|
||||
uint64_t val;
|
||||
eventfd_read(efd, &val);
|
||||
_exit(0);
|
||||
}
|
||||
QVERIFY2(pid > 0, "fork failed: " + qt_error_string().toLocal8Bit());
|
||||
auto waitForChild = qScopeGuard([=] {
|
||||
eventfd_write(efd, 1);
|
||||
close(efd);
|
||||
waitpid(pid, nullptr, 0);
|
||||
});
|
||||
|
||||
QString fname = u"/proc/%1/maps"_s.arg(pid);
|
||||
|
||||
// consistency check
|
||||
QFileInfo fi(fname);
|
||||
@ -2625,11 +2648,7 @@ void tst_QFile::virtualFile()
|
||||
// open the file
|
||||
QFile f(fname);
|
||||
QVERIFY2(f.open(QIODevice::ReadOnly), msgOpenFailed(f).constData());
|
||||
if (QTestPrivate::isRunningArmOnX86())
|
||||
QEXPECT_FAIL("","QEMU does not read /proc/self/maps size correctly", Continue);
|
||||
QCOMPARE(f.size(), Q_INT64_C(0));
|
||||
if (QTestPrivate::isRunningArmOnX86())
|
||||
QEXPECT_FAIL("","QEMU does not read /proc/self/maps size correctly", Continue);
|
||||
QVERIFY(f.atEnd());
|
||||
|
||||
// read data
|
||||
@ -2637,18 +2656,27 @@ void tst_QFile::virtualFile()
|
||||
QCOMPARE(data.size(), 16);
|
||||
QCOMPARE(f.pos(), Q_INT64_C(16));
|
||||
|
||||
// seeking
|
||||
QVERIFY(f.seek(1));
|
||||
QCOMPARE(f.pos(), Q_INT64_C(1));
|
||||
QVERIFY(f.seek(0));
|
||||
QCOMPARE(f.pos(), Q_INT64_C(0));
|
||||
|
||||
// line-reading
|
||||
data = f.readLine();
|
||||
QVERIFY(!data.isEmpty());
|
||||
QList<QByteArray> lines;
|
||||
for (data = f.readLine(); !data.isEmpty(); data = f.readLine()) {
|
||||
// chop the newline -- not using .trimmed() so cut exactly one byte
|
||||
data.chop(1);
|
||||
lines += std::move(data);
|
||||
}
|
||||
|
||||
// read all:
|
||||
QVERIFY(f.seek(0));
|
||||
data = f.readAll();
|
||||
QVERIFY(f.pos() != 0);
|
||||
QVERIFY(!data.isEmpty());
|
||||
|
||||
// seeking
|
||||
QVERIFY(f.seek(1));
|
||||
QCOMPARE(f.pos(), Q_INT64_C(1));
|
||||
QCOMPARE(data, lines.join('\n') + '\n');
|
||||
}
|
||||
#endif // defined(Q_OS_LINUX) || defined(Q_OS_AIX) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user