This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug sanitizer/65749] New: sanitizer stack trace pc off by 1


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]