Bug 41318 - Access to char * generates segmentation fault
Summary: Access to char * generates segmentation fault
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.2.4
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-09-09 13:22 UTC by Aaron Rocha
Modified: 2009-09-30 03:09 UTC (History)
1 user (show)

See Also:
Host: i486-linux-gnu
Target: i486-linux-gnu
Build: i486-linux-gnu
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Aaron Rocha 2009-09-09 13:22:52 UTC
I have stumbled upon a problem that, I believe, can be attributed to a bug in GCC. The following source code can be used to reproduce the problem:


int foo(void)
{
   char * str = "test";
   str[1] = 'a';
   return 0;
}

int main() {
  foo();
  return 0;
}


On a Solaris 10 system, I can compile and execute this code successfully using the following compiler: 

# /usr/bin/cc -V
cc: Sun C 5.9 SunOS_i386 Patch 124868-01 2007/07/12
usage: cc [ options] files.  Use 'cc -flags' for details

If I try to do the same with GCC on my linux box, I get a segmentation fault on str[1] = 'a'. Here are the details:

$ gcc -v -save-temps tst.c
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c
++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/l
ib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-inc
lude-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enabl
e-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --enable-c
hecking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux
-gnu
Thread model: posix
gcc version 4.2.4 (Ubuntu 4.2.4-1ubuntu4)
 /usr/lib/gcc/i486-linux-gnu/4.2.4/cc1 -E -quiet -v tst.c -mtune=generic -fpch-p
reprocess -o tst.i
ignoring nonexistent directory "/usr/local/include/i486-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/i486-linux-gnu/4.2.4/../../../../i4
86-linux-gnu/include"
ignoring nonexistent directory "/usr/include/i486-linux-gnu"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /usr/lib/gcc/i486-linux-gnu/4.2.4/include
 /usr/include
End of search list.
 /usr/lib/gcc/i486-linux-gnu/4.2.4/cc1 -fpreprocessed tst.i -quiet -dumpbase tst
.c -mtune=generic -auxbase tst -version -fstack-protector -fstack-protector -o t
st.s
GNU C version 4.2.4 (Ubuntu 4.2.4-1ubuntu4) (i486-linux-gnu)
        compiled by GNU C version 4.2.4 (Ubuntu 4.2.4-1ubuntu4).
GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=64446
Compiler executable checksum: cbbe762aad92f3ea8e83d46e5489fd3e
 as --traditional-format -V -Qy -o tst.o tst.s
GNU assembler version 2.18.0 (i486-linux-gnu) using BFD version (GNU Binutils fo
r Ubuntu) 2.18.0.20080103
 /usr/lib/gcc/i486-linux-gnu/4.2.4/collect2 --eh-frame-hdr -m elf_i386 --hash-st
yle=both -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc/i486-linux-gnu/4.2.4/..
/../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.2.4/../../../../lib/crti.o /u
sr/lib/gcc/i486-linux-gnu/4.2.4/crtbegin.o -L/usr/lib/gcc/i486-linux-gnu/4.2.4 -
L/usr/lib/gcc/i486-linux-gnu/4.2.4 -L/usr/lib/gcc/i486-linux-gnu/4.2.4/../../../
../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.2.4/../..
/.. tst.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s
 --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.2.4/crtend.o /usr/lib/gcc/i486-lin
ux-gnu/4.2.4/../../../../lib/crtn.o

$ ./a.out
Segmentation fault

Interestingly enough, if I declare str as :

   char str[] = "test";

rather than:

   char * str = "test";

the code will compile and execute properly.

I tried using -Wall and -pedantic to check whether GCC would produce any warnings but that does not seem to be the case.

I got the same results with another version of GCC as well. Here are the details:

$ gcc -v -save-temps tst.c
Reading specs from /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/specs
Configured with: ../gcc-3.3.6/configure --prefix=/usr --enable-shared --enable-t
hreads=posix --enable-__cxa_atexit --disable-checking --with-gnu-ld --verbose --
target=i486-slackware-linux --host=i486-slackware-linux
Thread model: posix
gcc version 3.3.6
 /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/cc1 -E -quiet -v -D__GNUC__=3 -D__G
NUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=6 tst.c tst.i
ignoring nonexistent directory "/usr/i486-slackware-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/include
 /usr/include
End of search list.
 /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/cc1 -fpreprocessed tst.i -quiet -du
mpbase tst.c -auxbase tst -version -o tst.s
GNU C version 3.3.6 (i486-slackware-linux)
        compiled by GNU C version 3.3.6.
GGC heuristics: --param ggc-min-expand=90 --param ggc-min-heapsize=113245
 /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/../../../../i486-slackware-linux/bi
n/as -V -Qy -o tst.o tst.s
GNU assembler version 2.15.92.0.2 (i486-slackware-linux) using BFD version 2.15.
92.0.2 20040927
 /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/collect2 --eh-frame-hdr -m elf_i386
 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/
../../../crt1.o /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/../../../crti.o /usr
/lib/gcc-lib/i486-slackware-linux/3.3.6/crtbegin.o -L/usr/lib/gcc-lib/i486-slack
ware-linux/3.3.6 -L/usr/lib/gcc-lib/i486-slackware-linux/3.3.6/../../../../i486-
slackware-linux/lib -L/usr/lib/gcc-lib/i486-slackware-linux/3.3.6/../../.. tst.o
 -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-
needed /usr/lib/gcc-lib/i486-slackware-linux/3.3.6/crtend.o /usr/lib/gcc-lib/i48
6-slackware-linux/3.3.6/../../../crtn.o

$ ./a.out
Segmentation fault

Any ideas?

Cheers,
Iran Rocha
Comment 1 Paolo Carlini 2009-09-09 13:28:52 UTC
Your code is clearly invalid: str points to "test", but that memory itself is read-only, roughly speaking. More correctly, the Standard says that the effect of attempting to modify a string literal is undefined, ie, *anything* can happen.
Comment 2 Aaron Rocha 2009-09-30 03:09:25 UTC
Thank you for the clarification. My friend and I ran across this while comparing the assembly generated by different compilers/platforms when manipulating strings. A largely academic exercise. That piece of code did not look right to me at first but what threw us off is the fact that the code worked with the Sun compiler and that -Wall -pedantic on gcc did not give us any warnings. We were puzzled by it.

You are correct though. I checked the standard and it does specify that the result of such operation is undefined, which explains why it may work with some compilers but certainly something that shouldn't be relied on.

Thanks again