diff --git a/dom/chrome-webidl/IOUtils.webidl b/dom/chrome-webidl/IOUtils.webidl index 86af3b6e1df3..a4ce4840013e 100644 --- a/dom/chrome-webidl/IOUtils.webidl +++ b/dom/chrome-webidl/IOUtils.webidl @@ -284,7 +284,7 @@ dictionary ReadOptions : ReadUTF8Options { * The offset into the file to read from. If unspecified, the file will be read * from the start. */ - unsigned long offset = 0; + unsigned long long offset = 0; /** * The max bytes to read from the file at path. If unspecified, the entire diff --git a/dom/system/IOUtils.cpp b/dom/system/IOUtils.cpp index d77b0824c950..3405e3d42e60 100644 --- a/dom/system/IOUtils.cpp +++ b/dom/system/IOUtils.cpp @@ -829,7 +829,7 @@ already_AddRefed IOUtils::CreateJSPromise(GlobalObject& aGlobal) { /* static */ Result IOUtils::ReadSync( - nsIFile* aFile, const uint32_t aOffset, const Maybe aMaxBytes, + nsIFile* aFile, const uint64_t aOffset, const Maybe aMaxBytes, const bool aDecompress, IOUtils::BufferKind aBufferKind) { MOZ_ASSERT(!NS_IsMainThread()); @@ -840,6 +840,15 @@ Result IOUtils::ReadSync( "The `maxBytes` and `decompress` options are not compatible")); } + if (aOffset > static_cast(INT64_MAX)) { + return Err(IOError(NS_ERROR_ILLEGAL_INPUT) + .WithMessage("Requested offset is too large (%" PRIu64 + " > %" PRId64 ")", + aOffset, INT64_MAX)); + } + + const int64_t offset = static_cast(aOffset); + RefPtr stream = new nsFileStream(); if (nsresult rv = stream->Init(aFile, PR_RDONLY | nsIFile::OS_READAHEAD, 0666, 0); @@ -847,43 +856,45 @@ Result IOUtils::ReadSync( return Err(IOError(rv).WithMessage("Could not open the file at %s", aFile->HumanReadablePath().get())); } - int64_t bufSize = 0; + + uint32_t bufSize = 0; if (aMaxBytes.isNothing()) { - // Limitation: We cannot read files that are larger than the max size of a - // TypedArray (UINT32_MAX bytes). Reject if the file is too - // big to be read. + // Limitation: We cannot read more than the maximum size of a TypedArray + // (UINT32_MAX bytes). Reject if we have been requested to + // perform too large of a read. - int64_t streamSize = -1; - if (nsresult rv = stream->GetSize(&streamSize); NS_FAILED(rv)) { + int64_t rawStreamSize = -1; + if (nsresult rv = stream->GetSize(&rawStreamSize); NS_FAILED(rv)) { return Err(IOError(NS_ERROR_FILE_ACCESS_DENIED) .WithMessage("Could not get info for the file at %s", aFile->HumanReadablePath().get())); } - MOZ_RELEASE_ASSERT(streamSize >= 0); + MOZ_RELEASE_ASSERT(rawStreamSize >= 0); - if (streamSize > static_cast(UINT32_MAX)) { - return Err( - IOError(NS_ERROR_FILE_TOO_BIG) - .WithMessage("Could not read the file at %s because it is too " - "large(size=%" PRId64 " bytes)", - aFile->HumanReadablePath().get(), streamSize)); - } - bufSize = static_cast(streamSize); - - if (aOffset >= bufSize) { + uint64_t streamSize = static_cast(rawStreamSize); + if (aOffset >= streamSize) { bufSize = 0; } else { - bufSize = bufSize - aOffset; + if (streamSize - offset > static_cast(UINT32_MAX)) { + return Err(IOError(NS_ERROR_FILE_TOO_BIG) + .WithMessage( + "Could not read the file at %s with offset %" PRIu32 + " because it is too large(size=%" PRIu64 " bytes)", + aFile->HumanReadablePath().get(), offset, + streamSize)); + } + + bufSize = static_cast(streamSize - offset); } } else { bufSize = aMaxBytes.value(); } - if (aOffset > 0) { - if (nsresult rv = stream->Seek(PR_SEEK_SET, aOffset); NS_FAILED(rv)) { + if (offset > 0) { + if (nsresult rv = stream->Seek(PR_SEEK_SET, offset); NS_FAILED(rv)) { return Err(IOError(rv).WithMessage( - "Could not seek to position %" PRId64 " in file %s", aOffset, + "Could not seek to position %" PRId64 " in file %s", offset, aFile->HumanReadablePath().get())); } } diff --git a/dom/system/IOUtils.h b/dom/system/IOUtils.h index 1365f9fc15cd..367580451405 100644 --- a/dom/system/IOUtils.h +++ b/dom/system/IOUtils.h @@ -197,7 +197,7 @@ class IOUtils final { * error. */ static Result ReadSync(nsIFile* aFile, - const uint32_t aOffset, + const uint64_t aOffset, const Maybe aMaxBytes, const bool aDecompress, BufferKind aBufferKind);