[Bug c/13757] New: -fstack-check can crash Hello World
gcc-bugzilla at gcc dot gnu dot org
gcc-bugzilla@gcc.gnu.org
Tue Jan 20 04:30:00 GMT 2004
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.
------- Additional Comments From duncan_roe at acslink dot net dot au 2004-01-20 04:29 -------
Fix:
Workaround: don't use -fstack-check
--
Summary: -fstack-check can crash Hello World
Product: gcc
Version: 3.3.2
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: duncan_roe at acslink dot net dot au
CC: gcc-bugs at gcc dot gnu dot org
GCC build triplet: i686-pc-linux-gnu
GCC host triplet: i686-pc-linux-gnu
GCC target triplet: i686-pc-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13757
More information about the Gcc-bugs
mailing list