BUG: /G3 Option Generates Bad Code for sscanf and Structures

ID: Q115701

1.00 1.50 WINDOWS kbtool kbbuglist

The information in this article applies to:

SYMPTOMS

Compiling code which uses sscanf() to fill fields within a structure using the /G3 compiler option (generate 386 code) will cause the compiler to push incorrect values for the structure variables being passed to sscanf(). This may result in an access violation.

RESOLUTION

There are two workarounds to this problem:

1. Compile with the /G2 instead of /G3 compiler switch.

   -or-

2. Create temporary pointers to store the addresses of the structure
   variables and pass those temporary pointers to sscanf().

      typedef struct tagSIZE {
         int cx;
         int cy;
      } SIZE;

      char  sz[256];
      SIZE  Size;

      void main( void )
      {
         int *x, *y;

         strcpy(sz, "3,4" );
         x=&Size.cx; y=&Size.cy;
         sscanf(sz, "%d,%d", x, y);
      }

STATUS

Microsoft has confirmed this to be a problem in the products listed at the beginning of this article. We are researching this problem and will post new information here in the Microsoft Knowledge Base as it becomes available.

This problem does not occur in the C/C++ 32-bit compiler, version 8.0.

MORE INFORMATION

The following is the assembly code generated when the call to sscanf() is made from the sample code below. You can generate this output by compiling the code below with the /Fc compiler option.

;|***    sscanf( sz, "%d,%d", &Size.cx, &Size.cy );
;Line 17
    *** 000011  66 68 00 00        push OFFSET DGROUP:_Size
    *** 000015  68 00 00           push OFFSET DGROUP:$SG259
    *** 000018  68 00 00           push OFFSET DGROUP:_sz
    *** 00001b  e8 00 00           call _sscanf
    *** 00001e  83 c4 08           add sp,8

In the assembly code listed here, the optimizer is trying to push both cx and cy as a 32-bit word. This would work, if the function required integer variables as the parameters. The problem here is that the two parameters are supposed to be pointers. The compiler is trying to push one 32-bit offset onto the stack, which is incorrect.

Now, look at the same code fragment compiled with the /G2 option:

;|***     sscanf( sz, "%d,%d", &Size.cx, &Size.cy );
; Line 17
    *** 000017  68 02 00           push OFFSET _Size+2
    *** 00001a  68 00 00           push OFFSET _Size
    *** 00001d  68 00 00           push OFFSET L00259
    *** 000020  68 00 00           push OFFSET _sz
    *** 000023  e8 00 00           call _sscanf
    *** 000026  83 c4 08           add sp,OFFSET 8

In this code, two separate values are correctly pushed as the addresses of cx and cy.

Sample Code

/* Compile options needed: /G3 /f-
*/ 

#include  <stdio.h>
#include  <string.h>

typedef struct tagSIZE {
    int cx;
    int cy;
} SIZE;

char     sz[256];
SIZE     Size;

void main( void )
{
    strcpy( sz, "3,4" );
    sscanf( sz, "%d,%d", &Size.cx, &Size.cy );
    printf( "%d, %d\n", Size.cx, Size.cy );
}

Additional reference words: 8.00 8.00c 1.00 1.50 KBCategory: kbtool kbbuglist KBSubcategory: CodeGen Keywords : kb16bitonly

Last Reviewed: July 23, 1997