tst_largefile: fix the mapOffsetOverflow case to match actual behavior
Unix mmap(2) system calls do allow for mapping beyond the end of the file, though what happens after you try to dereference the pointers it gives is unspecified. POSIX[1] says that implementations shouldn't allow it: The system shall always zero-fill any partial page at the end of an object. Further, the system shall never write out any modified portions of the last page of an object which are beyond its end. References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal. However, Linux allows this in read-write mode and extends the file (depending on the filesystem). Windows MapViewOfFile never allows mapping beyond the end. [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html Change-Id: Ie67d35dff21147e99ad9fffd14acc8d9a1a0c38d Reviewed-by: Sami Nurmenniemi <sami.nurmenniemi@qt.io> Reviewed-by: Teemu Holappa <teemu.holappa@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
9b5b44207e
commit
9a0d47bcf1
@ -502,23 +502,42 @@ void tst_LargeFile::mapFile()
|
||||
}
|
||||
|
||||
//Mac: memory-mapping beyond EOF may succeed but it could generate bus error on access
|
||||
//FreeBSD: same
|
||||
//Linux: memory-mapping beyond EOF usually succeeds, but depends on the filesystem
|
||||
// 32-bit: limited to 44-bit offsets
|
||||
//Windows: memory-mapping beyond EOF is not allowed
|
||||
void tst_LargeFile::mapOffsetOverflow()
|
||||
{
|
||||
#ifndef Q_OS_MAC
|
||||
// Out-of-range mappings should fail, and not silently clip the offset
|
||||
for (int i = 50; i < 63; ++i) {
|
||||
enum {
|
||||
#ifdef Q_OS_WIN
|
||||
Succeeds = false,
|
||||
MaxOffset = 63
|
||||
#else
|
||||
Succeeds = true,
|
||||
# if (defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)) && Q_PROCESSOR_WORDSIZE == 4
|
||||
MaxOffset = 43
|
||||
# else
|
||||
MaxOffset = 63
|
||||
# endif
|
||||
#endif
|
||||
};
|
||||
|
||||
QByteArray zeroPage(blockSize, '\0');
|
||||
for (int i = maxSizeBits + 1; i < 63; ++i) {
|
||||
bool succeeds = Succeeds && (i <= MaxOffset);
|
||||
uchar *address = 0;
|
||||
qint64 offset = Q_INT64_C(1) << i;
|
||||
|
||||
address = largeFile.map(((qint64)1 << i), blockSize);
|
||||
#if defined(__x86_64__)
|
||||
QEXPECT_FAIL("", "fails on 64-bit Linux (QTBUG-21175)", Abort);
|
||||
#endif
|
||||
QVERIFY( !address );
|
||||
if (succeeds)
|
||||
QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::map: Mapping a file beyond its size is not portable");
|
||||
address = largeFile.map(offset, blockSize);
|
||||
QCOMPARE(!!address, succeeds);
|
||||
|
||||
address = largeFile.map(((qint64)1 << i) + blockSize, blockSize);
|
||||
QVERIFY( !address );
|
||||
if (succeeds)
|
||||
QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::map: Mapping a file beyond its size is not portable");
|
||||
address = largeFile.map(offset + blockSize, blockSize);
|
||||
QCOMPARE(!!address, succeeds);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_LargeFile)
|
||||
|
Loading…
Reference in New Issue
Block a user