diff --git a/widget/windows/nsDataObj.cpp b/widget/windows/nsDataObj.cpp index 6112eab4a977..a9541f760dbc 100644 --- a/widget/windows/nsDataObj.cpp +++ b/widget/windows/nsDataObj.cpp @@ -125,25 +125,49 @@ nsDataObj::CStream::OnDataAvailable( uint64_t aOffset, // offset within the stream uint32_t aCount) // bytes available on this call { + // If we've been asked to read zero bytes, call `Read` once, just to ensure + // any side-effects take place, and return immediately. + if (aCount == 0) { + char buffer[1] = {0}; + uint32_t bytesReadByCall = 0; + nsresult rv = aInputStream->Read(buffer, 0, &bytesReadByCall); + MOZ_ASSERT(bytesReadByCall == 0); + return rv; + } + // Extend the write buffer for the incoming data. - uint8_t* buffer = mChannelData.AppendElements(aCount, fallible); + size_t oldLength = mChannelData.Length(); + char* buffer = + reinterpret_cast(mChannelData.AppendElements(aCount, fallible)); if (!buffer) { return NS_ERROR_OUT_OF_MEMORY; } - NS_ASSERTION((mChannelData.Length() == (aOffset + aCount)), - "stream length mismatch w/write buffer"); + MOZ_ASSERT(mChannelData.Length() == (aOffset + aCount), + "stream length mismatch w/write buffer"); // Read() may not return aCount on a single call, so loop until we've // accumulated all the data OnDataAvailable has promised. - nsresult rv; - uint32_t odaBytesReadTotal = 0; - do { + uint32_t bytesRead = 0; + while (bytesRead < aCount) { uint32_t bytesReadByCall = 0; - rv = aInputStream->Read((char*)(buffer + odaBytesReadTotal), aCount, - &bytesReadByCall); - odaBytesReadTotal += bytesReadByCall; - } while (aCount < odaBytesReadTotal && NS_SUCCEEDED(rv)); - return rv; + nsresult rv = aInputStream->Read(buffer + bytesRead, aCount - bytesRead, + &bytesReadByCall); + bytesRead += bytesReadByCall; + + if (bytesReadByCall == 0) { + // A `bytesReadByCall` of zero indicates EOF without failure... but we + // were promised `aCount` elements and haven't gotten them. Return a + // generic failure. + rv = NS_ERROR_FAILURE; + } + + if (NS_FAILED(rv)) { + // Drop any trailing uninitialized elements before erroring out. + mChannelData.RemoveElementsAt(oldLength + bytesRead, aCount - bytesRead); + return rv; + } + } + return NS_OK; } NS_IMETHODIMP nsDataObj::CStream::OnStartRequest(nsIRequest* aRequest) {