[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: bug in check for stack growth direction in _AC_LIBOBJ_ALLOCA
From: |
Andrew W. Nosenko |
Subject: |
Re: bug in check for stack growth direction in _AC_LIBOBJ_ALLOCA |
Date: |
Sat, 18 Jun 2011 23:25:42 +0300 |
On Fri, Jun 17, 2011 at 13:21, Andy Wingo <address@hidden> wrote:
> Hello,
>
> The following transcript indicates a problem with the stack growth
> direction check, present at functions.m4:328 in autoconf 2.68:
>
> address@hidden:/tmp$ cat foo.c
> int
> find_stack_direction ()
> {
> static char *addr = 0;
Try to rewrite this line as
volatile static char *addr = 0;
It should help.
> auto char dummy;
> if (addr == 0)
> {
> addr = &dummy;
> return find_stack_direction ();
> }
> else
> return (&dummy > addr) ? 1 : -1;
> }
>
> int
> main ()
> {
> return find_stack_direction () < 0;
> }
> address@hidden:/tmp$ gcc -O1 -o test foo.c
> address@hidden:/tmp$ ./test; echo $?
> 1
> address@hidden:/tmp$ gcc -O3 -o test foo.c
> address@hidden:/tmp$ ./test; echo $?
> 0
> $ gcc --version
> gcc (Debian 4.6.0-13) 4.6.1 20110611 (prerelease)
> Copyright (C) 2011 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions. There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
> As you see, the check (on an x86-64 system) gives the correct result at
> -O1 but not at -O3.
>
> (I don't actually use this check from _AC_LIBOBJ_ALLOCA, but Guile has
> the exact same test to check for stack growth direction, so it's the
> same issue. Reported by Marco Maggi.)
>
> Looking a bit more closely at this, I find the assembly to be a bit odd
> here:
>
> 00000000004004a0 <find_stack_direction>:
> 4004a0: mov 0x2003f9(%rip),%rax # 6008a0 <addr.1586>
> 4004a7: test %rax,%rax
> 4004aa: je 4004c0 <find_stack_direction+0x20>
> 4004ac: lea -0x2(%rsp),%rdx
> 4004b1: cmp %rdx,%rax
> 4004b4: sbb %eax,%eax
> 4004b6: and $0x2,%eax
> 4004b9: sub $0x1,%eax
> 4004bc: retq
> 4004bd: nopl (%rax)
> 4004c0: lea -0x2(%rsp),%rax
> 4004c5: lea -0x1(%rsp),%rdx
> 4004ca: cmp %rdx,%rax
> 4004cd: mov %rax,0x2003cc(%rip) # 6008a0 <addr.1586>
> 4004d4: sbb %eax,%eax
> 4004d6: and $0x2,%eax
> 4004d9: sub $0x1,%eax
> 4004dc: retq
> 4004dd: nop
> 4004de: nop
> 4004df: nop
>
> As you can see there is no call. The test will always be true, thus the
> second branch is always taken. I don't know what allows GCC to do this
> inlining. Could it be a GCC bug? Every time I think I have a GCC bug
> I'm wrong, though :)
No. It indeed traceable. Just start from main() and you will have
full trace even with pen and paper.
>
> I tried changing the test to the following:
>
> int
> find_stack_direction (char *addr)
> {
> char dummy;
> if (addr == 0)
> return find_stack_direction (&dummy);
> else
> return (&dummy > addr) ? 1 : -1;
> }
>
> int
> main ()
> {
> return find_stack_direction (0) < 0;
> }
>
> But I get the same behavior.
Just because it still traceable :-) And modern Gcc is smart enough
for do it :-)
--
Andrew W. Nosenko <address@hidden>