Bug 13757 - -fstack-check causes segfaults
Summary: -fstack-check causes segfaults
Status: RESOLVED DUPLICATE of bug 10127
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 3.3.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
: 39306 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-01-20 04:29 UTC by duncan_roe@acslink.net.au
Modified: 2009-08-04 10:09 UTC (History)
8 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed: 2004-01-21 06:22:17


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description duncan_roe@acslink.net.au 2004-01-20 04:29:51 UTC
The -fstack-check compiler option emits code which can make any program
segfault on entering its mainline.
The placement of the stack relative to page boundaries needs to be right
to demonstrate the problem.
This placement varies with environment, length of pathname used to invoke the
program, whether it is invoked directly or via GDB,
and quite possibly other factors also.
This is an old problem, I first saw it at gcc 2.95.3.
Shell/expect scripts in How-To-Repeat demonstrate the problem reliably.

This is a dissasem of main() :-

0x8048354 <main>:       push   %ebp
0x8048355 <main+1>:     mov    %esp,%ebp
0x8048357 <main+3>:     sub    $0x18,%esp
0x804835a <main+6>:     and    $0xfffffff0,%esp
0x804835d <main+9>:     movl   $0x0,0xfffffffc(%ebp)
0x8048364 <main+16>:    lea    0xffffded8(%esp,1),%eax
0x804836b <main+23>:    mov    %eax,0xfffffff8(%ebp)
0x804836e <main+26>:    mov    0xfffffffc(%ebp),%eax
0x8048371 <main+29>:    add    $0x1128,%eax
0x8048376 <main+34>:    mov    %esp,%edx
0x8048378 <main+36>:    sub    %eax,%edx
0x804837a <main+38>:    mov    %edx,0xfffffff4(%ebp)
0x804837d <main+41>:    jmp    0x804838f <main+59>
0x804837f <main+43>:    mov    0xfffffff8(%ebp),%eax
0x8048382 <main+46>:    movl   $0x0,(%eax)
0x8048388 <main+52>:    subl   $0x1000,0xfffffff8(%ebp)
0x804838f <main+59>:    mov    0xfffffff4(%ebp),%edx
0x8048392 <main+62>:    cmp    %edx,0xfffffff8(%ebp)
0x8048395 <main+65>:    ja     0x804837f <main+43>
0x8048397 <main+67>:    mov    0xfffffff4(%ebp),%eax
0x804839a <main+70>:    movl   $0x0,(%eax)
0x80483a0 <main+76>:    sub    0xfffffffc(%ebp),%esp
0x80483a3 <main+79>:    lea    0xffffeed8(%esp,1),%eax
0x80483aa <main+86>:    movl   $0x0,(%eax)
0x80483b0 <main+92>:    movl   $0x8048424,(%esp,1)
0x80483b7 <main+99>:    call   0x8048278 <printf>
0x80483bc <main+104>:   mov    $0x0,%eax
0x80483c1 <main+109>:   leave  
0x80483c2 <main+110>:   ret    

The segfault occurs at 0x804839a <main+70>:    movl   $0x0,(%eax)

Environment:
System: Linux dimstar 2.4.24 #1 Sat Jan 10 17:03:52 EST 2004 i686 unknown
Architecture: i686

	
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: /usr/src/gcc-3.3.2/configure --prefix=/usr/local/gcc3.2

How-To-Repeat:
The preprocessed source:-

---------------------------- START hello.i ----------------------------
extern int printf (__const char *__restrict __format, ...) ;
int main(int argc,char**argv)
{
        printf("\nHello World!\n\n");
        return 0 ;
}
---------------------------- END hello.i ----------------------------

This test script will verify that we get the crash.
It works by increasing the length of the pathname of hello
in 16 byte increnents until it crashes (copious output) :- 

---------------------------- START sh.sh ----------------------------
#!/bin/sh
gcc -g -Wall -fstack-check -o hello hello.i
i=aaaaaaaaaaaaaaa
j=`/bin/pwd`
while(true);do
$j/hello || break
j=$j/$i
mkdir -p $j
cp hello $j
done
echo "Failing path is $j"
---------------------------- END sh.sh ----------------------------

This script discovers the required pathname to see the problem under gdb.
It saves this in the command file "cmd" for future use :-

---------------------------- START demo.sh ----------------------------
#!/bin/sh
# expect treats all the shell lines as comment comtinuations \
gcc -g -Wall -fstack-check -o hello hello.i; \
i=aaaaaaaaaaaaaaa; \
exec expect -f "$0" -- $i `/bin/pwd`

# We need to find a path that shows the problem when run under gdb

set i [lindex $argv 0]
set j [lindex $argv 1]

puts "Finding a pathname that displays the problem."
puts "This may take a while..."
log_user 0

spawn sh
expect "$ "
set k 0
set l 0
while {1} \
{
  puts -nonewline "$l\r"
  flush stdout
  set l [incr l]
  exp_send "gdb $j/hello\r"
  expect "(gdb) "
  exp_send "run\r"
  expect \
  {
    signal \
    {
      set k 1
      expect "(gdb) "
      exp_send "q\r"
      expect "(y or n) "
      exp_send "y\r"
    }
    normally \
    {
      expect "(gdb) "
      exp_send "q\r"
    }
  }
  expect "$ "
  if {$k} break
  set j $j/$i
  exec mkdir -p $j
  exec cp hello $j
}
puts "\nFailing path is $j"
exec echo "gdb $j/hello" > cmd
exec chmod a+x cmd
puts "gdb invocation command stored in ./cmd"
---------------------------- END demo.sh ----------------------------

After running demo.sh, you can invoke gdb by running cmd directly.
Alternatively, you can run the following script to get directly to
the first machine instruction in main() :-

---------------------------- START run_gdb.sh ----------------------------
#!/bin/sh
# expect treats all the shell lines as comment comtinuations \
exec expect -f "$0"
spawn ./cmd
expect "(gdb) "
exp_send "b __libc_start_main\r"
expect "(gdb) "
exp_send "run\r"
expect "(gdb) "
exp_send "n 11\r"
expect "(gdb) "
exp_send "si 10\r"
expect "(gdb) "
puts "\n\nYou can now interact with gdb."
puts "If it won't exit for you (lost LWP or whatever), type \"////\" to kill it"
exp_send " \r"
interact //// exit
---------------------------- END run_gdb.sh ----------------------------

At gcc3.2.2, you can use "si 17" to get to the actual failing instruction.
At that point if you note the contents of eax and use "x" to examine that
location, the program will continue without failing.

Otherwise, 'movl   $0x0,(%eax)' will fail.
I do not understand why this should be.
Comment 1 duncan_roe@acslink.net.au 2004-01-20 04:29:51 UTC
Fix:
Workaround: don't use -fstack-check
Comment 2 Andrew Pinski 2004-01-20 04:38:36 UTC
I really think -fstack-check should be removed from the compiler, its use is no longer needed.
Comment 3 Dara Hazeghi 2004-01-21 06:22:12 UTC
Confirmed with mainline. You have to run the testcase a few times, but on one, it'll inevitably 
crash. Only options needed to reproduce are "-fstack-check"
Comment 4 Karsten Burger 2004-08-04 11:35:49 UTC
I would not like the "-fstack-check" to be removed from the compiler - it is needed to 
debug multi-threaded applications. Found the bug on Mandrake 9.1 with gcc 3.2.2, too. 
 
(In reply to comment #0) 
> The -fstack-check compiler option emits code which can make any program 
> segfault on entering its mainline. 
> The placement of the stack relative to page boundaries needs to be right 
> to demonstrate the problem. 
> This placement varies with environment, length of pathname used to invoke the 
> program, whether it is invoked directly or via GDB, 
> and quite possibly other factors also. 
> This is an old problem, I first saw it at gcc 2.95.3. 
> Shell/expect scripts in How-To-Repeat demonstrate the problem reliably. 
>  
> This is a dissasem of main() :- 
>  
> 0x8048354 <main>:       push   %ebp 
> 0x8048355 <main+1>:     mov    %esp,%ebp 
> 0x8048357 <main+3>:     sub    $0x18,%esp 
> 0x804835a <main+6>:     and    $0xfffffff0,%esp 
> 0x804835d <main+9>:     movl   $0x0,0xfffffffc(%ebp) 
> 0x8048364 <main+16>:    lea    0xffffded8(%esp,1),%eax 
> 0x804836b <main+23>:    mov    %eax,0xfffffff8(%ebp) 
> 0x804836e <main+26>:    mov    0xfffffffc(%ebp),%eax 
> 0x8048371 <main+29>:    add    $0x1128,%eax 
> 0x8048376 <main+34>:    mov    %esp,%edx 
> 0x8048378 <main+36>:    sub    %eax,%edx 
> 0x804837a <main+38>:    mov    %edx,0xfffffff4(%ebp) 
> 0x804837d <main+41>:    jmp    0x804838f <main+59> 
> 0x804837f <main+43>:    mov    0xfffffff8(%ebp),%eax 
> 0x8048382 <main+46>:    movl   $0x0,(%eax) 
> 0x8048388 <main+52>:    subl   $0x1000,0xfffffff8(%ebp) 
> 0x804838f <main+59>:    mov    0xfffffff4(%ebp),%edx 
> 0x8048392 <main+62>:    cmp    %edx,0xfffffff8(%ebp) 
> 0x8048395 <main+65>:    ja     0x804837f <main+43> 
> 0x8048397 <main+67>:    mov    0xfffffff4(%ebp),%eax 
> 0x804839a <main+70>:    movl   $0x0,(%eax) 
> 0x80483a0 <main+76>:    sub    0xfffffffc(%ebp),%esp 
> 0x80483a3 <main+79>:    lea    0xffffeed8(%esp,1),%eax 
> 0x80483aa <main+86>:    movl   $0x0,(%eax) 
> 0x80483b0 <main+92>:    movl   $0x8048424,(%esp,1) 
> 0x80483b7 <main+99>:    call   0x8048278 <printf> 
> 0x80483bc <main+104>:   mov    $0x0,%eax 
> 0x80483c1 <main+109>:   leave   
> 0x80483c2 <main+110>:   ret     
>  
> The segfault occurs at 0x804839a <main+70>:    movl   $0x0,(%eax) 
>  
> Environment: 
> System: Linux dimstar 2.4.24 #1 Sat Jan 10 17:03:52 EST 2004 i686 unknown 
> Architecture: i686 
>  
>          
> host: i686-pc-linux-gnu 
> build: i686-pc-linux-gnu 
> target: i686-pc-linux-gnu 
> configured with: /usr/src/gcc-3.3.2/configure --prefix=/usr/local/gcc3.2 
>  
> How-To-Repeat: 
> The preprocessed source:- 
>  
> ---------------------------- START hello.i ---------------------------- 
> extern int printf (__const char *__restrict __format, ...) ; 
> int main(int argc,char**argv) 
> { 
>         printf("\nHello World!\n\n"); 
>         return 0 ; 
> } 
> ---------------------------- END hello.i ---------------------------- 
>  
> This test script will verify that we get the crash. 
> It works by increasing the length of the pathname of hello 
> in 16 byte increnents until it crashes (copious output) :-  
>  
> ---------------------------- START sh.sh ---------------------------- 
> #!/bin/sh 
> gcc -g -Wall -fstack-check -o hello hello.i 
> i=aaaaaaaaaaaaaaa 
> j=`/bin/pwd` 
> while(true);do 
> $j/hello || break 
> j=$j/$i 
> mkdir -p $j 
> cp hello $j 
> done 
> echo "Failing path is $j" 
> ---------------------------- END sh.sh ---------------------------- 
>  
> This script discovers the required pathname to see the problem under gdb. 
> It saves this in the command file "cmd" for future use :- 
>  
> ---------------------------- START demo.sh ---------------------------- 
> #!/bin/sh 
> # expect treats all the shell lines as comment comtinuations \ 
> gcc -g -Wall -fstack-check -o hello hello.i; \ 
> i=aaaaaaaaaaaaaaa; \ 
> exec expect -f "$0" -- $i `/bin/pwd` 
>  
> # We need to find a path that shows the problem when run under gdb 
>  
> set i [lindex $argv 0] 
> set j [lindex $argv 1] 
>  
> puts "Finding a pathname that displays the problem." 
> puts "This may take a while..." 
> log_user 0 
>  
> spawn sh 
> expect "$ " 
> set k 0 
> set l 0 
> while {1} \ 
> { 
>   puts -nonewline "$l\r" 
>   flush stdout 
>   set l [incr l] 
>   exp_send "gdb $j/hello\r" 
>   expect "(gdb) " 
>   exp_send "run\r" 
>   expect \ 
>   { 
>     signal \ 
>     { 
>       set k 1 
>       expect "(gdb) " 
>       exp_send "q\r" 
>       expect "(y or n) " 
>       exp_send "y\r" 
>     } 
>     normally \ 
>     { 
>       expect "(gdb) " 
>       exp_send "q\r" 
>     } 
>   } 
>   expect "$ " 
>   if {$k} break 
>   set j $j/$i 
>   exec mkdir -p $j 
>   exec cp hello $j 
> } 
> puts "\nFailing path is $j" 
> exec echo "gdb $j/hello" > cmd 
> exec chmod a+x cmd 
> puts "gdb invocation command stored in ./cmd" 
> ---------------------------- END demo.sh ---------------------------- 
>  
> After running demo.sh, you can invoke gdb by running cmd directly. 
> Alternatively, you can run the following script to get directly to 
> the first machine instruction in main() :- 
>  
> ---------------------------- START run_gdb.sh ---------------------------- 
> #!/bin/sh 
> # expect treats all the shell lines as comment comtinuations \ 
> exec expect -f "$0" 
> spawn ./cmd 
> expect "(gdb) " 
> exp_send "b __libc_start_main\r" 
> expect "(gdb) " 
> exp_send "run\r" 
> expect "(gdb) " 
> exp_send "n 11\r" 
> expect "(gdb) " 
> exp_send "si 10\r" 
> expect "(gdb) " 
> puts "\n\nYou can now interact with gdb." 
> puts "If it won't exit for you (lost LWP or whatever), type \"////\" to kill it" 
> exp_send " \r" 
> interact //// exit 
> ---------------------------- END run_gdb.sh ---------------------------- 
>  
> At gcc3.2.2, you can use "si 17" to get to the actual failing instruction. 
> At that point if you note the contents of eax and use "x" to examine that 
> location, the program will continue without failing. 
>  
> Otherwise, 'movl   $0x0,(%eax)' will fail. 
> I do not understand why this should be. 
 
 
Comment 5 Andrew B. Lundgren 2006-02-17 19:27:31 UTC
I am experiencing the same bug with GCC 4.0.1 & 4.0.2 on SLES 9 with:
gcc -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../gcc-4.0.2/configure --enable-threads=posix --prefix=/usr/local/gcc4.0.2/
Thread model: posix
gcc version 4.0.2
Comment 6 Eric Botcazou 2009-02-26 08:16:51 UTC
*** Bug 39306 has been marked as a duplicate of this bug. ***
Comment 7 Eric Botcazou 2009-08-04 10:09:37 UTC

*** This bug has been marked as a duplicate of 10127 ***