Microsoft KB Archive/105372

{|
 * width="100%"|

FIX: GetNextAssoc Crashes _AFXDLL Application

 * }

Q105372

1.00 WINDOWS kbprg kbfixlist kbbuglist -- The information in this article applies to: - The Microsoft Foundation Classes (MFC) included with: - Microsoft Visual C++ for Windows, version 1.0 -- SYMPTOMS ======== When using one of the map classes (for example, CMapStringToOb) and iterating through the map in a retail build of an _AFXDLL application, a general protection (GP) fault occurs in GetNextAssoc. A debug build of the same application, or a non-AFXDLL version (debug or retail), does not cause a GP fault. CAUSE ===== GetStartPosition returns the predefined value BEFORE_START_POSITION, which is defined incorrectly in AFX.H. GetNextAssoc does not identify this as the beginning of the map and incorrectly uses this value as a pointer. RESOLUTION ========== Because an _AFXDLL application makes use of MFC200.DLL, it is insufficient to correct the definition of BEFORE_START_POSITION and rebuild the application. MFC200.DLL contains references to BEFORE_START_POSITION that were set at compile time (of the DLL), and therefore changing the definition without also rebuilding MFC200.DLL will not solve the problem. Microsoft does not recommend shipping modified versions of MFC200.DLL with applications. To work around the problem, derive a new map class and override GetNextAssoc by copying the code from the appropriate MAP_XX.CPP file in ~\MFC\SRC. No changes to the code are necessary, and it is not necessary to correct the definition of BEFORE_START_POSITION. Use the new map class in place of the original. STATUS ====== Microsoft has confirmed this to be a problem with version 2.0 of the Microsoft Foundation Classes for Windows. This problem was corrected in MFC 2.5. MORE INFORMATION ================ In AFX.H, BEFORE_START_POSITION is defined as: #define BEFORE_START_POSITION ((void*)(void NEAR*)-1) The explicit NEAR cast in this definition combined with the large memory model (required by _AFXDLL) causes this to evaluate to DS:-1. The correct definition should be ((void*)-1), which does not depend on DS. In a retail build, GetStartPosition is an inline function, which causes it to exist in the application's code. This means that BEFORE_START_POSITION as returned by GetStartPosition contains the application's DS. On the other hand, GetNextAssoc is not inline and exists in MFC200.DLL. Consider CMapStringToOb. On line 249 of MAP_SO.CPP is the comparison: if (pAssocRet == (CAssoc*) BEFORE_START_POSITION) This comparison is intended to succeed when pAssocRet is the value returned by GetStartPosition. However, BEFORE_START_POSITION in the above line contains the DLL's DS, and thus the comparison fails, in which case GetNextAssoc proceeds to use pAssocRet, and a GP fault results. When building a debug version of the application, inlining is turned off and both GetStartPosition and GetNextAssoc exist in MFC200D.DLL. For a non-AFXDLL application, both functions are linked into the application's code (both debug and retail). The same DS is used in all of these cases and GetNextAssoc works correctly. Additional reference words: 1.00 2.00 CMapWordToOb CMapWordToPtr CMapPtrToWord CMapPtrToPtr CMapStringToPtr CMapStringToString KBCategory: kbprg kbfixlist kbbuglist KBSubcategory: MfcMisc

Keywords : kb16bitonly kbnokeyword kbMFC kbVC

Issue type :

Technology : kbAudDeveloper kbMFC