## 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

Last Reviewed: May 5, 2001 © 2001 Microsoft Corporation. All rights reserved. Terms of Use.