FIX: CArchive May Corrupt Memory or Write Incorrect Data

ID: Q133433


The information in this article applies to:


SYMPTOMS

The CArchive insertion operator (CArchive::operator<<) may, in rare circumstances, write incorrect data to its associated CFile or may overwrite other application memory. Likewise, the CArchive extraction operator (CArchive::operator>>) may incorrectly read data from its CFile object.


CAUSE

The CArchive class uses buffering for all of its operations. When extracting data from the archive, it maintains a pointer to the current location in the buffer. When the pointer goes past the end of the currently retrieved buffer, it retrieves another block of data from the associated CFile object. The extraction operators for CArchive do not properly check for the condition where the buffer pointer reaches the end of the block. In some cases, the pointer wraps to the beginning of its segment. Later calls to extract data from the CArchive retrieve the data from the wrong memory address.

The CArchive class uses a similar procedure when data is inserted into the CArchive. The "More Information" section of this article gives more details.


RESOLUTION

Below are three approaches to resolving this problem:


STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. This problem has been corrected in the 16- bit component that comes with Visual C++ version 2.2.


MORE INFORMATION

The problem with the CArchive insertion and extraction operators is in the way they check the pointer to the current location in the buffer (m_lpBufCur). For example, CArchive::operator<<(WORD w) is defined as:


   _AFX_INLINE CArchive& CArchive::operator<<(WORD w)
     { if (m_lpBufCur + sizeof(WORD) > m_lpBufMax) Flush();
         *(WORD FAR*)m_lpBufCur = w; m_lpBufCur += sizeof(WORD);
         return *this; } 
It is possible that an allocated buffer could end up with a memory block ending address close to <s>:0xFFFF. As call insert data into your buffer consecutively, m_lpBufCur approaches the end of the address block that might be somewhere near <s>:0xFFFF.

For example, consider this scenario:

   m_lpBufCur==<s>:0xFFFE 
In this scenario, the 'if' statement would evaluate as:

   if (<s>:0xFFFE + 2 > <s>:0xFFFE) Flush(); 
Because both pointers are far pointers this is equivalent to:

   if ( <s>:0x0000 > <s>:0xFFFE ) Flush(); 
This evaluation is not desirable. It appears that there is enough room left in the buffer to put the WORD into it and then m_lpBufCur is set to <s>:0x0000. Because the beginning of the buffer may not have been at the beginning of the segment, subsequent operations will begin to write at whatever data happens to be located at <s>:0x0000 on up to the beginning of the buffer.

The same boundary checks exist for the extraction operators. When m_lpBufCur is set back to 0x0000, all further extraction operators get data from the wrong location.

IMPORTANT NOTE: Because the problem occurs only when a particular memory block is allocated at a very specific address, the odds of encountering this problem are very low. There are cases where the layout of your application's heap and the thread of execution of the code causes this to occur every time you run your application, but if you are experiencing memory corruption, it is unlikely that this is the cause, so you shouldn't necessarily expect these workarounds to take care of the problem.

Additional query words: 1.00 1.50 1.51 1.52 2.00 2.50 2.51 2.52 StoreFields LoadFields SaveToStorage LoadFromStorage


Keywords          : kbnokeyword kbMFC kbVC 
Version           : 1.00 1.50 1.51 1.52
Platform          : WINDOWS 
Issue type        : 

Last Reviewed: July 29, 1999