summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2014-09-19 14:17:46 -0700
committerThiago Macieira <thiago.macieira@intel.com>2014-10-31 03:56:11 +0100
commit85da1625e47cadf0b41e24863e8988e771e50943 (patch)
tree892b2a86a0951e4521c6c3fd4a311005d0baf127 /src
parentf91b81ca398c64a22fd6fb2006dbec39a3e3b2c0 (diff)
Attempt to make QFile I/O 64-bit safe
Use qint64 wherever possible. The linear buffer is never requested to allocate that much memory (always limited), but at least we ensure we're not dropping bits where we shouldn't. Windows's POSIX compatibility layer is never largefile enabled, so it is always necessary to chunk large reads and writes. On Unix, this will be rare, unless someone passed -no-largefile to configure, for some weird reason. Unfortunately, this is not testable, unless we can allocate a buffer with 4 GB or more in size. The test for this would be to open a file we know to be small, then try to read 4 GB + 1 byte. If everything works correctly, we'll read the full file; if there was a truncation, we'd read one byte. Change-Id: If3ee511bf1de17e0123c85bbcaa463b9972746ce Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/io/qfsfileengine.cpp41
-rw-r--r--src/corelib/io/qiodevice.cpp2
-rw-r--r--src/corelib/io/qiodevice_p.h18
3 files changed, 39 insertions, 22 deletions
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 42250b629d..a126690240 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -73,6 +73,17 @@ QT_BEGIN_NAMESPACE
# endif
#endif
+#ifdef Q_OS_WIN
+// on Windows, read() and write() use int and unsigned int
+typedef int SignedIOType;
+typedef unsigned int UnsignedIOType;
+#else
+typedef ssize_t SignedIOType;
+typedef size_t UnsignedIOType;
+Q_STATIC_ASSERT_X(sizeof(SignedIOType) == sizeof(UnsignedIOType),
+ "Unsupported: read/write return a type with different size as the len parameter");
+#endif
+
/*! \class QFSFileEngine
\inmodule QtCore
\brief The QFSFileEngine class implements Qt's default file engine.
@@ -605,13 +616,16 @@ qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
} else if (fd != -1) {
// Unbuffered stdio mode.
-#ifdef Q_OS_WIN
- int result;
-#else
- ssize_t result;
-#endif
+ SignedIOType result;
do {
- result = QT_READ(fd, data + readBytes, size_t(len - readBytes));
+ // calculate the chunk size
+ // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
+ // we limit to the size of the signed type, otherwise we could get a negative number as a result
+ quint64 wantedBytes = quint64(len) - quint64(readBytes);
+ UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
+ if (chunkSize > wantedBytes)
+ chunkSize = wantedBytes;
+ result = QT_READ(fd, data + readBytes, chunkSize);
} while (result > 0 && (readBytes += result) < len);
eof = !(result == -1);
@@ -722,13 +736,16 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
} else if (fd != -1) {
// Unbuffered stdio mode.
-#ifdef Q_OS_WIN
- int result;
-#else
- ssize_t result;
-#endif
+ SignedIOType result;
do {
- result = QT_WRITE(fd, data + writtenBytes, size_t(len - writtenBytes));
+ // calculate the chunk size
+ // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks
+ // we limit to the size of the signed type, otherwise we could get a negative number as a result
+ quint64 wantedBytes = quint64(len) - quint64(writtenBytes);
+ UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max();
+ if (chunkSize > wantedBytes)
+ chunkSize = wantedBytes;
+ result = QT_WRITE(fd, data + writtenBytes, chunkSize);
} while (result > 0 && (writtenBytes += result) < len);
}
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 89209e6118..0709a93bad 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -786,7 +786,7 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
bool moreToRead = true;
do {
// Try reading from the buffer.
- int lastReadChunkSize = d->buffer.read(data, maxSize);
+ qint64 lastReadChunkSize = d->buffer.read(data, maxSize);
if (lastReadChunkSize > 0) {
*d->pPos += lastReadChunkSize;
readSoFar += lastReadChunkSize;
diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h
index 10d92a896d..d764cb0fbb 100644
--- a/src/corelib/io/qiodevice_p.h
+++ b/src/corelib/io/qiodevice_p.h
@@ -98,19 +98,19 @@ public:
first++;
return ch;
}
- int read(char* target, qint64 size) {
- int r = qMin(size, len);
+ qint64 read(char* target, qint64 size) {
+ qint64 r = qMin(size, len);
memcpy(target, first, r);
len -= r;
first += r;
return r;
}
- int peek(char* target, qint64 size) {
- int r = qMin(size, len);
+ qint64 peek(char* target, qint64 size) {
+ qint64 r = qMin(size, len);
memcpy(target, first, r);
return r;
}
- char* reserve(int size) {
+ char* reserve(qint64 size) {
makeSpace(size + len, freeSpaceAtEnd);
char* writePtr = first + len;
len += size;
@@ -128,16 +128,16 @@ public:
clear();
return retVal;
}
- int readLine(char* target, qint64 size) {
- int r = qMin(size, len);
+ qint64 readLine(char* target, qint64 size) {
+ qint64 r = qMin(size, len);
char* eol = static_cast<char*>(memchr(first, '\n', r));
if (eol)
r = 1+(eol-first);
memcpy(target, first, r);
len -= r;
first += r;
- return int(r);
- }
+ return r;
+ }
bool canReadLine() const {
return memchr(first, '\n', len);
}