## FIX: Setting Bitfields with /Oe Overwrites Stored BP

Q114074

    6.00 6.00a 7.00 | 6.00 6.00a | 1.00
    MS-DOS          | OS/2       | WINDOWS
    kbtool kbfixlist kbbuglist

    ----------------------------------------------------------------------
    The information in this article applies to:

     - The Microsoft C/C++ Compiler (CL.EXE), included with:

        - Microsoft C for MS-DOS, versions 6.0, 6.0a, and 6.0ax
        - Microsoft C for OS/2, versions 6.0 and 6.0a
        - Microsoft C/C++ for MS-DOS, version 7.0
        - Microsoft Visual C++ for Windows, version 1.0
    ----------------------------------------------------------------------

    SYMPTOMS
    ========

    Returning from a function which modifies bitfields of a global
    structure causes the system to hang, crash with a memory violation, or
    execute an invalid instruction.

    CAUSE
    =====

    Incorrect code can be generated when bitfields of a global structure
    are modified and /Oe (global register allocation) optimization is
    used. For the problem to be reproduced, /Gt<n> (data size threshold)
    must be specified with n less than the size of the global struct.

    This incorrect code overwrites the value of BP pushed onto the stack
    on entry into the function.

    The sample code at the end of this article demonstrates the problem.

    RESOLUTION
    ==========

    There are a few possible ways to work around this problem.

     - Compile without the /Oe (global register allocation)
       optimization.  Similarly, use #pragma optimize ( "e", off)
       to turn /Oe optimization off just for the one function.

     - Compile with /Gt<n> (data size threshold) where n is
       greater than or equal to the size of the global structure.

     - Rebuild with Visual C++ 1.5 or later, which corrects this
       problem.

    STATUS
    ======

    Microsoft has confirmed this to be a problem in the Microsoft products
    listed above. This is not a problem in Visual C++, 32-bit Edition. This
    problem was corrected in Visual C++ version 1.5.

    Sample Code
    -----------

    /* Compile options needed:  /AL /Oe /Fc /Gt14
       Description: This code, when compiled with Microsoft C/C++
                    compilers previous to version 8.0c and with /Oe,
                    overwrite a stored BP on the line indicated.
                    Without /Oe, the problem does not occur.

                    The printf's do not demonstrate the problem,
                    it is the failure to return from the function call,
                    or examination of the .COD listing, which
                    demonstrates this.
    */

    #include <stdio.h>

    struct test_struct {
        char *text;
        int iTest;
        unsigned unsigned_1:1;
        unsigned unsigned_2:1;
        unsigned unsigned_3:1;
        unsigned unsigned_4:1;
        unsigned unsigned_5:1;
        unsigned unsigned_6:1;
        unsigned unsigned_7:1;
        unsigned unsigned_8:1;
        unsigned unsigned_9:1;
        };

    static struct test_struct tst_strct[2];

    void oe_error( int iX, char *text, int iTest,
                   int test_1, int test_2, int test_3, int test_4,
                   int test_5, int test_6, int test_7, int test_8,
                   int test_9);

    void test(void);

    void main(int argc, char *argv)
    {
       int iTest_1;

       iTest_1 = 10;

       // The following is needed for creation of a stackframe in main():
       if(iTest_1+argc < 10) {
          // will never be reached.
          test();
       }

       test();

       printf("It should be: iTest_1 = 10\n" );
       printf("       It is: iTest_1 = %d\n", iTest_1);
    }

    // Take comment off following line to work around problem
    // #pragma optimize ( "e", off)

    void test(void)
    {
       int iX = 1;

       oe_error( iX, "TEXT", 5, 1, 1, 1, 1, 0, 0, 0, 0, 0);
    }

    void oe_error( int iX, char *text, int iTest,
                   int test_1, int test_2, int test_3, int test_4,
                   int test_5, int test_6, int test_7, int test_8,
                   int test_9)
    {
       tst_strct[iX].text = text;
       tst_strct[iX].iTest = iTest;
       tst_strct[iX].unsigned_1 = test_1;
       tst_strct[iX].unsigned_2 = test_2;
       tst_strct[iX].unsigned_3 = test_3;
       tst_strct[iX].unsigned_4 = test_4;
       tst_strct[iX].unsigned_5 = test_5;
       tst_strct[iX].unsigned_6 = test_6;
       tst_strct[iX].unsigned_7 = test_7;
       tst_strct[iX].unsigned_8 = test_8;
       tst_strct[iX].unsigned_9 = test_9;
       /* The stored BP is overwritten here */
    }

    // Uncomment for work around
    // #pragma optimize ("", on)

    /* The code which causes BP to be overwritten comes immediately after
       the line tst_strct[iX].unsigned_9 = test_9; in the .COD listing.
       The problem is that this code does

       *** 000099    81 c3 06 00    add    bx,OFFSET $S175_tst_strct+6
       *** 00009d    89 5e fe       mov    WORD PTR [bp-2],bx

    >> *** 0000a0    8c 5e 00       mov   WORD PTR [bp],ds
    >> This will overwrite the stored BP, so that BP is not correctly
    >> retrieved at the end of this function.

       See the .COD listing produced when compiling for more information.
    */

    Additional reference words: 8.00 1.00
    KBCategory: kbtool kbfixlist kbbuglist
    KBSubcategory: CLIss

Keywords : kb16bitonly kbCompiler
Issue type :
Technology : kbVCsearch kbAudDeveloper kbCVCComp

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