https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65749
Bug ID: 65749 Summary: sanitizer stack trace pc off by 1 Product: gcc Version: 5.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: sanitizer Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org, jakub at gcc dot gnu.org, kcc at gcc dot gnu.org The PC printed in sanitizer stack traces is consistently off by 1. Either off by 1 byte, or by 1 instruction, depending on the target. The problem can be seen in any stack trace, including the one below. The StackTrace::Print() function in libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc computes the PC to include in the backtrace like so: // PCs in stack traces are actually the return addresses, that is, // addresses of the next instructions after the call. uptr pc = GetPreviousInstructionPc(trace[i]); GetPreviousInstructionPc() simply returns its argument decremented by the width of the smallest instruction on a target, or 4 on powerpc and 1 on x86_64. This computation is incorrect because it results in PC values that don't match up with either the faulting address in the case of the active frame, or with the address of either the subsequent instruction that would have been executed had the faulting function returned to the caller or with the call instruction (on x86_64). As a side effect of this defect the sanitizer stack trace also sometimes lists different line numbers (for programs compiled with -g) than GDB (and than is recorded in the DWARF line program). $ cat -n t.c && ./gcc/xgcc -Bgcc -L$PWD/x86_64-unknown-linux-gnu/libsanitizer/asan/.libs -O2 -fno-builtin-memset -fsanitize=address -g t.c && LD_LIBRARY_PATH=$PWD/x86_64-unknown-linux-gnu/libsanitizer/asan/.libs ./a.out; LD_LIBRARY_PATH=$PWD/x86_64-unknown-linux-gnu/libsanitizer/asan/.libs gdb -batch -ex r -ex 'x/1i $pc' -ex bt -quiet a.out 1 void __attribute__ ((weak)) foo (int *p) 2 { 3 *p = 0xdeadbeef; 4 } 5 6 void __attribute__ ((weak)) bar (int *p) 7 { 8 int a; 9 foo (&a); 10 11 foo (p); 12 } 13 14 int main (void) 15 { 16 bar (0); 17 18 return 0; 19 } 20 ASAN:SIGSEGV ================================================================= ==7883==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x0000004007ef bp 0x0ffffffffbc4 sp 0x7fffffffde18 T0) #0 0x4007ee in foo /build/gcc-65479/t.c:2 #1 0x400869 in bar /build/gcc-65479/t.c:11 #2 0x4006ba in main /build/gcc-65479/t.c:16 #3 0x7ffff6ad3fdf in __libc_start_main (/lib64/libc.so.6+0x1ffdf) #4 0x4006fd (/home/msebor/build/gcc-65479/a.out+0x4006fd) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /build/gcc-65479/t.c:2 foo ==7883==ABORTING [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Program received signal SIGSEGV, Segmentation fault. 0x00000000004007ef in foo (p=p@entry=0x0) at t.c:3 3 *p = 0xdeadbeef; => 0x4007ef <foo+31>: movl $0xdeadbeef,(%rdi) #0 0x00000000004007ef in foo (p=p@entry=0x0) at t.c:3 #1 0x000000000040086a in bar (p=p@entry=0x0) at t.c:11 #2 0x00000000004006bb in main () at t.c:16