ole32: Fix reads past the end of streams.
authorVincent Povirk <vincent@codeweavers.com>
Thu, 6 May 2010 16:36:41 +0000 (11:36 -0500)
committerAlexandre Julliard <julliard@winehq.org>
Fri, 7 May 2010 10:46:50 +0000 (12:46 +0200)
dlls/ole32/storage32.c
dlls/ole32/tests/storage32.c

index 9ac794e84470b4542b7491fbb361acf8446a9f93..bc1fb96cbb9f085b5ca285a9af95ac300b85c5ac 100644 (file)
@@ -3584,6 +3584,9 @@ HRESULT StorageImpl_ReadRawDirEntry(StorageImpl *This, ULONG index, BYTE *buffer
                     buffer,
                     &bytesRead);
 
+  if (bytesRead != RAW_DIRENTRY_SIZE)
+    return STG_E_READFAULT;
+
   return hr;
 }
 
@@ -3929,6 +3932,11 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
 
         offset.u.LowPart += cbRead;
     }
+    else
+    {
+        resRead = STG_E_READFAULT;
+        break;
+    }
   } while (cbTotalRead.QuadPart < size.QuadPart);
   HeapFree(GetProcessHeap(),0,buffer);
 
@@ -4027,6 +4035,11 @@ SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks(
 
             offset.u.LowPart += cbRead;
         }
+        else
+        {
+            resRead = STG_E_READFAULT;
+            break;
+        }
     }while(cbTotalRead.QuadPart < size.QuadPart);
     HeapFree(GetProcessHeap(), 0, buffer);
 
@@ -5810,6 +5823,7 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
   ULONG bytesToReadInBuffer;
   ULONG blockIndex;
   BYTE* bufferWalker;
+  ULARGE_INTEGER stream_size;
 
   TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
 
@@ -5818,13 +5832,17 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
    */
   blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
 
-  if (blockIndex == BLOCK_END_OF_CHAIN)
-      return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */
+  *bytesRead   = 0;
+
+  stream_size = BlockChainStream_GetSize(This);
+  if (stream_size.QuadPart > offset.QuadPart)
+    size = min(stream_size.QuadPart - offset.QuadPart, size);
+  else
+    return S_OK;
 
   /*
    * Start reading the buffer.
    */
-  *bytesRead   = 0;
   bufferWalker = buffer;
 
   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
@@ -5862,7 +5880,7 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
         break;
   }
 
-  return (size == 0) ? S_OK : STG_E_READFAULT;
+  return S_OK;
 }
 
 /******************************************************************************
@@ -6295,6 +6313,9 @@ static HRESULT SmallBlockChainStream_GetNextBlockInChain(
               &buffer,
               &bytesRead);
 
+  if (SUCCEEDED(res) && bytesRead != sizeof(DWORD))
+    res = STG_E_READFAULT;
+
   if (SUCCEEDED(res))
   {
     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
@@ -6386,7 +6407,7 @@ static ULONG SmallBlockChainStream_GetNextFreeBlock(
     /*
      * If we run out of space for the small block depot, enlarge it
      */
-    if (SUCCEEDED(res))
+    if (SUCCEEDED(res) && bytesRead == sizeof(DWORD))
     {
       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
 
@@ -6482,12 +6503,21 @@ HRESULT SmallBlockChainStream_ReadAt(
   ULONG blockIndex;
   ULONG bytesReadFromBigBlockFile;
   BYTE* bufferWalker;
+  ULARGE_INTEGER stream_size;
 
   /*
    * This should never happen on a small block file.
    */
   assert(offset.u.HighPart==0);
 
+  *bytesRead   = 0;
+
+  stream_size = SmallBlockChainStream_GetSize(This);
+  if (stream_size.QuadPart > offset.QuadPart)
+    size = min(stream_size.QuadPart - offset.QuadPart, size);
+  else
+    return S_OK;
+
   /*
    * Find the first block in the stream that contains part of the buffer.
    */
@@ -6504,7 +6534,6 @@ HRESULT SmallBlockChainStream_ReadAt(
   /*
    * Start reading the buffer.
    */
-  *bytesRead   = 0;
   bufferWalker = buffer;
 
   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
@@ -6538,6 +6567,9 @@ HRESULT SmallBlockChainStream_ReadAt(
     if (FAILED(rc))
       return rc;
 
+    if (!bytesReadFromBigBlockFile)
+      return STG_E_DOCFILECORRUPT;
+
     /*
      * Step to the next big block.
      */
@@ -6551,7 +6583,7 @@ HRESULT SmallBlockChainStream_ReadAt(
     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
   }
 
-  return (size == 0) ? S_OK : STG_E_READFAULT;
+  return S_OK;
 }
 
 /******************************************************************************
index 8fa1afdaca7308c057ef73c88f450ac6ad82dd77..9bd8f339844c0755eac320f64512a9e622cb5c42 100644 (file)
@@ -315,6 +315,55 @@ static void test_storage_stream(void)
     r = IStream_Commit(stm, STGC_DEFAULT );
     ok(r==S_OK, "failed to commit stream\n");
 
+    /* Read past the end of the stream. */
+    pos.QuadPart = 3;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
+    ok(r==S_OK, "failed to seek stream\n");
+    ok(p.QuadPart == 3, "at wrong place\n");
+    r = IStream_Read(stm, buffer, sizeof buffer, &count );
+    ok(r==S_OK, "failed to read\n");
+    ok(count == 3, "read bytes past end of stream\n");
+    pos.QuadPart = 10;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
+    ok(r==S_OK, "failed to seek stream\n");
+    ok(p.QuadPart == 10, "at wrong place\n");
+    r = IStream_Read(stm, buffer, sizeof buffer, &count );
+    ok(r==S_OK, "failed to read\n");
+    ok(count == 0, "read bytes past end of stream\n");
+    pos.QuadPart = 10000;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
+    ok(r==S_OK, "failed to seek stream\n");
+    ok(p.QuadPart == 10000, "at wrong place\n");
+    r = IStream_Read(stm, buffer, sizeof buffer, &count );
+    ok(r==S_OK, "failed to read\n");
+    ok(count == 0, "read bytes past end of stream\n");
+
+    /* Convert to a big block stream, and read past the end. */
+    p.QuadPart = 5000;
+    r = IStream_SetSize(stm,p);
+    ok(r==S_OK, "failed to set pos\n");
+    pos.QuadPart = 4997;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
+    ok(r==S_OK, "failed to seek stream\n");
+    ok(p.QuadPart == 4997, "at wrong place\n");
+    r = IStream_Read(stm, buffer, sizeof buffer, &count );
+    ok(r==S_OK, "failed to read\n");
+    ok(count == 3, "read bytes past end of stream\n");
+    pos.QuadPart = 5001;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
+    ok(r==S_OK, "failed to seek stream\n");
+    ok(p.QuadPart == 5001, "at wrong place\n");
+    r = IStream_Read(stm, buffer, sizeof buffer, &count );
+    ok(r==S_OK, "failed to read\n");
+    ok(count == 0, "read bytes past end of stream\n");
+    pos.QuadPart = 10000;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
+    ok(r==S_OK, "failed to seek stream\n");
+    ok(p.QuadPart == 10000, "at wrong place\n");
+    r = IStream_Read(stm, buffer, sizeof buffer, &count );
+    ok(r==S_OK, "failed to read\n");
+    ok(count == 0, "read bytes past end of stream\n");
+
     /* seek round a bit, reset the stream size */
     pos.QuadPart = 0;
     r = IStream_Seek(stm, pos, 3, &p );
@@ -329,6 +378,16 @@ static void test_storage_stream(void)
     r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
     ok(r==S_OK, "failed to seek stream\n");
     ok(p.QuadPart == 10, "at wrong place\n");
+    r = IStream_Read(stm, buffer, sizeof buffer, &count );
+    ok(r==S_OK, "failed to set pos\n");
+    ok(count == 0, "read bytes from empty stream\n");
+    pos.QuadPart = 10000;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &p );
+    ok(r==S_OK, "failed to seek stream\n");
+    ok(p.QuadPart == 10000, "at wrong place\n");
+    r = IStream_Read(stm, buffer, sizeof buffer, &count );
+    ok(r==S_OK, "failed to set pos\n");
+    ok(count == 0, "read bytes from empty stream\n");
     pos.QuadPart = 0;
     r = IStream_Seek(stm, pos, STREAM_SEEK_END, &p );
     ok(r==S_OK, "failed to seek stream\n");