www.digitalmars.com         C & C++   DMDScript  

c++ - Optimizer bug (allocation of local variables on the stack)

reply Christof Meerwald <cmeerw web.de> writes:
#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?
Apr 05 2003
parent reply Heinz Saathoff <hsaat bre.ipnet.de> writes:
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
Apr 07 2003
parent reply "Walter" <walter digitalmars.com> writes:
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.
Apr 07 2003
parent reply Heinz Saathoff <hsaat bre.ipnet.de> writes:
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
Apr 08 2003
parent reply "Walter" <walter digitalmars.com> writes:
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
Apr 08 2003
parent reply mjs NOSPAM.hannover.sgh-net.de (Mark Junker) writes:
 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
Apr 10 2003
parent "Walter" <walter digitalmars.com> writes:
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
Apr 10 2003