Thread overview
Optimizer bug (allocation of local variables on the stack)
Apr 05, 2003
Christof Meerwald
Apr 07, 2003
Heinz Saathoff
Apr 07, 2003
Walter
Apr 08, 2003
Heinz Saathoff
Apr 08, 2003
Walter
Apr 10, 2003
Mark Junker
Apr 10, 2003
Walter
April 05, 2003
#include <stdio.h>

void f();

int main()
{
  f();
}

void f()
{
  int i1 = 1234, i2 = 5678;
  char c[8*4096];

  printf("%08x %08x %08x\n", &c, &i1, &i2);
}


Compiled with (-o+speed) I get:

4067ae54 000004d2 0000162e


Obviously, 0x4d2 and 0x162e aren't the addresses of i1 and i2 (but the values), so let's have a look at the generated code:


?f@@YAXXZ:
		push	EBP
		mov	EBP,ESP
		mov	EDX,8

; allocation of 8*4096 bytes on the stack
L18:		sub	ESP,01000h
		test	[ESP],ESP
		dec	EDX
		jne	L18

; and here the compiler assumes that EDX is still 8 (but it is 0 now)
; this doesn't allocate any space on the stack
		sub	ESP,EDX
		lea	EAX,-08004h[EBP]
		lea	ECX,-08008h[EBP]
		push	EAX
		lea	EDX,-08000h[EBP]
		push	ECX
		push	EDX

; finally overwrites the passed arguments to printf
		mov	dword ptr -08008h[EBP],04D2h
		mov	dword ptr -08004h[EBP],0162Eh

		push	offset FLAT:_DATA
		call	near ptr _printf
		add	ESP,010h
		mov	ESP,EBP
		pop	EBP
		ret


bye, Christof

-- 
http://cmeerw.org                                 JID: cmeerw@jabber.at mailto cmeerw at web.de

...and what have you contributed to the Net?
April 07, 2003
Hello Christof, Hello Walter,

Christof Meerwald schrieb...
> [snip]
> void f()
> {
>   int i1 = 1234, i2 = 5678;
>   char c[8*4096];
> 
>   printf("%08x %08x %08x\n", &c, &i1, &i2);
> }
> 
> 
> Compiled with (-o+speed) I get:
> 
> 4067ae54 000004d2 0000162e
> 
> 
> Obviously, 0x4d2 and 0x162e aren't the addresses of i1 and i2 (but the values), so let's have a look at the generated code:
> 
> 
> ?f@@YAXXZ:
> 		push	EBP
> 		mov	EBP,ESP
> 		mov	EDX,8
> 
> ; allocation of 8*4096 bytes on the stack
> L18:		sub	ESP,01000h
> 		test	[ESP],ESP
              ^^^^^^^^^^^^^^^^^
why test ESP with [ESP]? Doesn't make much sense to me except to force a
protection fault in case of stack overflow
> 		dec	EDX
> 		jne	L18
Why allocate the 8*4096 in a loop and not direct? If a early stack
protection fault should be forced the allocation could be done as
		sub	ESP,08000h    ; allocate at once
		test	[ESP],ESP	; early protection fault when
					; stack overflows

> 
> ; and here the compiler assumes that EDX is still 8 (but it is 0 now)
> ; this doesn't allocate any space on the stack
> 		sub	ESP,EDX
> 		lea	EAX,-08004h[EBP]
> 		lea	ECX,-08008h[EBP]
> 		push	EAX
> 		lea	EDX,-08000h[EBP]
> 		push	ECX
> 		push	EDX
> 
> ; finally overwrites the passed arguments to printf
> 		mov	dword ptr -08008h[EBP],04D2h

BTW, the space allocation on the stack for i1 and i2 is also missing. ESP should be subtracted by 08008h instead of only 08000h.

- Heinz
April 07, 2003
Christof's reported bug was corrected in the latest beta. The code looks a little wierd, but it works because the stack cannot be extended by more than 4k at a time (or else you get a stack overflow exception). Thus, it does it 4k at a time, doing a read from each 4k block to get win32 to allocate another page to the stack.


April 08, 2003
Walter schrieb...
> Christof's reported bug was corrected in the latest beta. The code looks a little wierd, but it works because the stack cannot be extended by more than 4k at a time (or else you get a stack overflow exception). Thus, it does it 4k at a time, doing a read from each 4k block to get win32 to allocate another page to the stack.

To check if I get the stack overflow exception I tried this code:
/*------------- ST.C --------------*/
#include <stdio.h>

void Func()
{
asm {
   push  EBP
   mov   EBP,ESP
   sub   ESP,0100000h  /* 1M on stack */
   mov   EBX,ESP
   mov   ECX,0100000h/4
LL:
   mov   dword ptr [EBX],0
   add   EBX,4
   loop  LL
   mov   ESP,EBP
   pop   EBP
}
}//Func

int main()
{
   printf("call Func\n");
   Func();
   printf("ready\n");
   return 0;
}
/*------------ end ST.C -----------*/


Compiled with  sc -nm st.c and run on NT4 I didn't get any exception.

- Heinz
April 08, 2003
That's because a certain amount of stack is preallocated. I don't know how much it is, I'm sure that it changes from version to version of win32.

"Heinz Saathoff" <hsaat@bre.ipnet.de> wrote in message news:MPG.18fc9d4b387f5b289896b8@news.digitalmars.com...
> Walter schrieb...
> > Christof's reported bug was corrected in the latest beta. The code looks
a
> > little wierd, but it works because the stack cannot be extended by more
than
> > 4k at a time (or else you get a stack overflow exception). Thus, it does
it
> > 4k at a time, doing a read from each 4k block to get win32 to allocate another page to the stack.
>
> To check if I get the stack overflow exception I tried this code:
> /*------------- ST.C --------------*/
> #include <stdio.h>
>
> void Func()
> {
> asm {
>    push  EBP
>    mov   EBP,ESP
>    sub   ESP,0100000h  /* 1M on stack */
>    mov   EBX,ESP
>    mov   ECX,0100000h/4
> LL:
>    mov   dword ptr [EBX],0
>    add   EBX,4
>    loop  LL
>    mov   ESP,EBP
>    pop   EBP
> }
> }//Func
>
> int main()
> {
>    printf("call Func\n");
>    Func();
>    printf("ready\n");
>    return 0;
> }
> /*------------ end ST.C -----------*/
>
>
> Compiled with  sc -nm st.c and run on NT4 I didn't get any exception.
>
> - Heinz


April 10, 2003
> That's because a certain amount of stack is preallocated. I don't know how much it is, I'm sure that it changes from version to version of win32.
Isn't that defined by the linker-produced PE file?

Regards,
MJS

April 10, 2003
Probably; I'd have to read the spec again.

"Mark Junker" <mjs@NOSPAM.hannover.sgh-net.de> wrote in message news:8j$7UuRd8gB@hannover.sgh-net.de...
> > That's because a certain amount of stack is preallocated. I don't know
how
> > much it is, I'm sure that it changes from version to version of win32.
> Isn't that defined by the linker-produced PE file?
>
> Regards,
> MJS
>