google / sanitizers

AddressSanitizer, ThreadSanitizer, MemorySanitizer
Other
11.01k stars 998 forks source link

Empty code randomly crashes with SEGV on unknown address #1724

Open mechakotik opened 5 months ago

mechakotik commented 5 months ago

Have the following code:

// main.cpp

int main()
{
    return 0;
}

Compiled it with this command:

g++ -fsanitize=address,leak,undefined main.cpp -o main

If I run it, I randomly (~20%) get an error like this:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==18624==ERROR: AddressSanitizer: SEGV on unknown address 0x6164e1cc7e78 (pc 0x7042e816438f bp 0x000000000000 sp 0x7fff2a9243f0 T0)
==18624==The signal is caused by a READ memory access.
AddressSanitizer:DEADLYSIGNAL
AddressSanitizer: nested bug in the same thread, aborting.

Using latest Arch Linux. No such error appeared until recent update.

vrodedanya commented 5 months ago

I've encountered a similar problem in my project, where tests built with the address, undefined and leak sanitizers randomly crash at startup, showing the following error:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==322304==ERROR: AddressSanitizer: SEGV on unknown address 0x609b5ffd8e58 (pc 0x78fce8a7338f bp 0x000000000000 sp 0x7ffc9381d410 T0)
==322304==The signal is caused by a READ memory access.
AddressSanitizer:DEADLYSIGNAL
AddressSanitizer: nested bug in the same thread, aborting.

GDB output (the same for my tests and empty main function):

44            return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
(gdb) bt
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1  0x00007ffff72ac8a3 in __pthread_kill_internal (signo=6, threadid=<optimized out>) at pthread_kill.c:78
#2  0x00007ffff725c668 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3  0x00007ffff72444b8 in __GI_abort () at abort.c:79
#4  0x00007ffff79035d4 in __sanitizer::Abort () at /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:143
#5  0x00007ffff7914632 in __sanitizer::Die () at /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_termination.cpp:58
#6  0x00007ffff791c656 in __lsan::CheckForLeaks () at /usr/src/debug/gcc/gcc/libsanitizer/lsan/lsan_common.cpp:767
#7  0x00007ffff791c6e8 in __lsan::DoLeakCheck () at /usr/src/debug/gcc/gcc/libsanitizer/lsan/lsan_common.cpp:801
#8  0x00007ffff725e731 in __cxa_finalize (d=0x7ffff7975000) at cxa_finalize.c:82
#9  0x00007ffff7826c28 in __do_global_dtors_aux () from /usr/lib/libasan.so.8
#10 0x00007ffff7f95000 in ?? ()
#11 0x00007ffff7fcb0e2 in _dl_call_fini (closure_map=0x7fffffffdbd0, closure_map@entry=0x7ffff7f95000) at dl-call_fini.c:43
#12 0x00007ffff7fced9c in _dl_fini () at dl-fini.c:78
#13 0x00007ffff725ecc6 in __run_exit_handlers (status=0, listp=0x7ffff73f6680 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true, 
    run_dtors=run_dtors@entry=true) at exit.c:111
#14 0x00007ffff725ee10 in __GI_exit (status=<optimized out>) at exit.c:141
#15 0x00007ffff7245cd7 in __libc_start_call_main (main=main@entry=0x555555555149 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffddb8)
    at ../sysdeps/nptl/libc_start_call_main.h:74
#16 0x00007ffff7245d8a in __libc_start_main_impl (main=0x555555555149 <main>, argc=1, argv=0x7fffffffddb8, init=<optimized out>, 
    fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdda8) at ../csu/libc-start.c:360
#17 0x0000555555555075 in _start ()

ldd output for binary

    linux-vdso.so.1 (0x00007fffc33c0000)
    libasan.so.8 => /usr/lib/libasan.so.8 (0x000071c22f800000)
    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x000071c22f400000)
    libm.so.6 => /usr/lib/libm.so.6 (0x000071c22ff17000)
    libubsan.so.1 => /usr/lib/libubsan.so.1 (0x000071c22ec00000)
    libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x000071c22fef2000)
    libc.so.6 => /usr/lib/libc.so.6 (0x000071c22f21e000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x000071c230038000)
$ g++ --version
g++ (GCC) 13.2.1 20230801
$ uname -a
Linux 6.7.1-arch1-1 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux

Hope this information will be useful

vrodedanya commented 5 months ago

I can't reproduce this with clang. Probably gcc problem?

Compiled as follows: For GCC

g++ main.cpp -fsanitize=address -o main_g++ -std=c++20

For clang

clang main.cpp -fsanitize=address -o main_clang -std=c++20

trilader commented 5 months ago

I'm also hitting this (g++ crashes and clang++ works) with versions:

% g++ --version
g++ (GCC) 13.2.1 20230801

and

% clang++ --version
clang version 16.0.6

Files are compiled with: g++ -g -o test_g++ -fno-omit-frame-pointer -fsanitize=address test.cpp and clang++ -g -o test_clang++ -fno-omit-frame-pointer -fsanitize=address test.cpp respectively.

I'm testing using this shell snippet to run the binary until it crashes (or the break file exists in the current folder) and output the number of runs before abnormal exit:

The clang++ test works fine and runs as long as I want:

I=0; while [ $? -eq 0 -a ! -f break ]; do I=$((I+1)); ./test_clang++; done; echo $I

The g++ test crashes after a while:

I=0; while [ $? -eq 0 -a ! -f break ]; do I=$((I+1)); ./test_g++; done; echo $I
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1536175==ERROR: AddressSanitizer: SEGV on unknown address 0x62748ec6ee78 (pc 0x78bfa64b738f bp 0x000000000000 sp 0x7ffdad842a50 T0)
==1536175==The signal is caused by a READ memory access.
AddressSanitizer:DEADLYSIGNAL
AddressSanitizer: nested bug in the same thread, aborting.
7

Here it crashed on the 7th run but I've also seen lower and higher numbers.

vrodedanya commented 5 months ago

I've found this issue. And the solution from this comment helped me

AE1020 commented 3 months ago

If I run it, I randomly (~20%) get an error like this:

I was seeing about the same 20% DEADLYSIGNAL on startup in a program where I had no problems before.

The problem occurred before main() was entered.

What I gathered is that this is a problem of interactions between address sanitizer and the OS's address space layout randomization feature. So it may have started as a result of a conscious (or unconscious) upgrade of files in the OS.

I was able to get the DEADLYSIGNAL to go away by invoking the program as:

setarch `uname -m` -R ./name-of-executable