C9201004: Bad Code Generation When Passing Structures in C 5.1

ID Number: Q80103

5.10 | 5.10

MS-DOS | OS/2

buglist5.10 fixlist6.00

Summary:

PROBLEM ID: C9201004

SYMPTOMS

When using the Microsoft C Compiler version 5.1, incorrect code may

be generated when passing structures to a function and compiling

with the compact (/AC) or large (/AL) memory model.

RESOLUTION

To work around this problem, do one of the following:

1. Change the code so the problem no longer occurs. For example,

declare the structure variable as a static array rather than an

array of pointers. Then remove the for loop that allocates space

to those pointers.

-or-

2. Use different optimizations. In the sample below, /Oa causes the

compiler to generate the correct code.

STATUS

Microsoft has confirmed this to be a problem in Microsoft C version

5.1. This problem was corrected in Microsoft C version 6.0.

More Information:

The sample code below demonstrates a code generation error for the

following line:

writing(a[i][j]);

The compiler generates a stack pointer subtraction immediately before

a data segment push causing an incorrect value to be popped into the

DS register after the memory moves take place. Below is the assembly

listing of the line that is incorrect:

Assemble Listing

----------------

;|*** writing(a[i][j]);

mov ax,17

imul WORD PTR [bp-4] ;j

mov bx,WORD PTR [bp-2]

shl bx,1

shl bx,1

mov es,$T20001

mov cx,WORD PTR es:_a[bx]

mov si,WORD PTR es:_a[bx+2]

add cx,ax

sub sp,18 ; The order of these two lines should be changed.

push ds

push si

mov si,cx

mov di,sp

push ss

pop es

pop ds

ASSUME DS: DGROUP

mov cx,8

rep

movsw

movsb

pop ds

ASSUME DS: DGROUP

push cs

call _writing

add sp,18

Note that the code above pops a value off of the stack into the DS

register. Because the area of the stack that is popped off is

overwritten by the memory moves, the program hangs on the call to

_writing.

Sample Code

-----------

/* Compile options needed: /AL

*/

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

struct str

{

char string[17];

}*a[2];

void writing(struct str b)

{

printf("b.string=%s\n",b.string);

}

void main(void)

{

int i,j;

for(i=0;i<2;i++)

{

if((a[i]=malloc(2*sizeof(struct str)))==NULL)

{

printf("Could not allocate.\n");

exit(1);

}

}

strcpy(a[i=0][j=0].string,"test");

printf("a[%d][%d]=",i,j);

writing(a[i][j]);

}

Additional reference words: 5.10 6.00