FIX: Setting Bitfields with /Oe Overwrites Stored BP

ID: 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:

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.

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 kbbuglist kbfixlist
Version           : 6.00 6.00a 7.00 | 6.00 6.00a | 1
Platform          : MS-DOS OS/2 WINDOWS
Solution Type     : kbfix

Last Reviewed: September 22, 1997