On Unix, the memory allocated by QFile::map() is not always dealocated by QFile::unmap().
The extra memory required by the offset is not taken into account when munmap() is called.
Here is an example to reproduce the bug:
#include <QCoreApplication>
#include <QFile>
#include <QString>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void maps(QString label)
{
puts(label.toAscii().data());
system(QString("grep /bigfile$ /proc/%2/maps")
.arg(getpid()).toAscii().data());
}
int main(int argc, char** argv)
{
unsigned char* addr;
QCoreApplication app(argc, argv);
QFile file("bigfile");
file.open(QIODevice::WriteOnly);
file.resize(4097);
file.close();
maps("Initial state:");
file.open(QIODevice::ReadOnly);
maps("After open():");
addr = file.map(1, file.size() - 1);
maps("After map():");
file.unmap(addr);
maps("After unmap():");
addr = file.map(1, file.size() - 1);
maps("After second map():");
file.unmap(addr);
maps("After second unmap():");
addr = file.map(1, file.size() - 1);
maps("After third map():");
file.unmap(addr);
maps("After third unmap():");
file.close();
maps("After close():");
return 0;
}
Here is a patch by Andy Goth to solve the issue:
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index bb64773..1788470 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -988,8 +988,9 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
return false;
}
- uchar *start = ptr - maps[ptr].first;
- int len = maps[ptr].second;
+ const int extra = maps[ptr].first;
+ uchar *start = ptr - extra;
+ int len = maps[ptr].second + extra;
if (-1 == munmap(start, len)) {
q->setError(QFile::UnspecifiedError, qt_error_string(errno));
return false;