Consider the following program:
#include <iostream>
int main() { std::cout << "Hello, World!\n"; }
I compile it with on Ubuntu 20.04 (Focal Fossa) with g++ a.cpp -o a and run under Valgrind with valgrind ./a. Valgrind takes few moments to spin up and completes successfully.
However, if I press Ctrl + C (presumably sending SIGINT) right after the Valgrind has started, but the program did not execute yet, I frequently get SIGSEGV and Segmentation fault message, like so:
valgrind ./a
==11071== Memcheck, a memory error detector
==11071== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11071== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==11071== Command: ./a
==11071==
^C==11071==
==11071== Process terminating with default action of signal 2 (SIGINT)
==11071== at 0x401EF56: __open_nocancel (open64_nocancel.c:45)
==11071== by 0x40083BA: open_verify.constprop.0 (dl-load.c:1536)
==11071== by 0x4008C15: open_path (dl-load.c:1827)
==11071== by 0x400A7A2: _dl_map_object (dl-load.c:2067)
==11071== by 0x400F504: openaux (dl-deps.c:64)
==11071== by 0x401DCA9: _dl_catch_exception (dl-error-skeleton.c:208)
==11071== by 0x400F952: _dl_map_object_deps (dl-deps.c:248)
==11071== by 0x4004063: dl_main (rtld.c:1805)
==11071== by 0x401CC3A: _dl_sysdep_start (dl-sysdep.c:252)
==11071== by 0x400204B: _dl_start_final (rtld.c:449)
==11071== by 0x400204B: _dl_start (rtld.c:539)
==11071== by 0x4001107: ??? (in /usr/lib/x86_64-linux-gnu/ld-2.31.so)
==11071== Jump to the invalid address stated on the next line
==11071== at 0x1030: ???
==11071== by 0x40083BA: open_verify.constprop.0 (dl-load.c:1536)
==11071== by 0x4008C15: open_path (dl-load.c:1827)
==11071== by 0x400A7A2: _dl_map_object (dl-load.c:2067)
==11071== by 0x400F504: openaux (dl-deps.c:64)
==11071== by 0x401DCA9: _dl_catch_exception (dl-error-skeleton.c:208)
==11071== by 0x400F952: _dl_map_object_deps (dl-deps.c:248)
==11071== by 0x4004063: dl_main (rtld.c:1805)
==11071== by 0x401CC3A: _dl_sysdep_start (dl-sysdep.c:252)
==11071== by 0x400204B: _dl_start_final (rtld.c:449)
==11071== by 0x400204B: _dl_start (rtld.c:539)
==11071== by 0x4001107: ??? (in /usr/lib/x86_64-linux-gnu/ld-2.31.so)
==11071== Address 0x1030 is not stack'd, malloc'd or (recently) free'd
==11071==
==11071==
==11071== Process terminating with default action of signal 11 (SIGSEGV)
==11071== Bad permissions for mapped region at address 0x1030
==11071== at 0x1030: ???
==11071== by 0x40083BA: open_verify.constprop.0 (dl-load.c:1536)
==11071== by 0x4008C15: open_path (dl-load.c:1827)
==11071== by 0x400A7A2: _dl_map_object (dl-load.c:2067)
==11071== by 0x400F504: openaux (dl-deps.c:64)
==11071== by 0x401DCA9: _dl_catch_exception (dl-error-skeleton.c:208)
==11071== by 0x400F952: _dl_map_object_deps (dl-deps.c:248)
==11071== by 0x4004063: dl_main (rtld.c:1805)
==11071== by 0x401CC3A: _dl_sysdep_start (dl-sysdep.c:252)
==11071== by 0x400204B: _dl_start_final (rtld.c:449)
==11071== by 0x400204B: _dl_start (rtld.c:539)
==11071== by 0x4001107: ??? (in /usr/lib/x86_64-linux-gnu/ld-2.31.so)
==11071==
==11071== HEAP SUMMARY:
==11071== in use at exit: 0 bytes in 0 blocks
==11071== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==11071==
==11071== All heap blocks were freed -- no leaks are possible
==11071==
==11071== For lists of detected and suppressed errors, rerun with: -s
==11071== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault
More rare occasion: everything gets handled just fine, SIGINT is propagated:
valgrind ./a
==11070== Memcheck, a memory error detector
==11070== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11070== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==11070== Command: ./a
==11070==
^C==11070==
==11070== Process terminating with default action of signal 2 (SIGINT)
==11070== at 0x4B480A5: write (write.c:26)
==11070== by 0x4AC8EBC: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1181)
==11070== by 0x4ACA980: new_do_write (fileops.c:449)
==11070== by 0x4ACA980: _IO_new_do_write (fileops.c:426)
==11070== by 0x4ACA980: _IO_do_write@@GLIBC_2.2.5 (fileops.c:423)
==11070== by 0x4ACAEC2: _IO_file_overflow@@GLIBC_2.2.5 (fileops.c:784)
==11070== by 0x4ACC053: _IO_default_xsputn (genops.c:399)
==11070== by 0x4ACC053: _IO_default_xsputn (genops.c:370)
==11070== by 0x4AC9729: _IO_new_file_xsputn (fileops.c:1265)
==11070== by 0x4AC9729: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1197)
==11070== by 0x4ABD3F0: fwrite (iofwrite.c:39)
==11070== by 0x498B823: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==11070== by 0x498BBDB: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==11070== by 0x1091A3: main (in /home/yeputons/a)
Hello World
==11070==
==11070== HEAP SUMMARY:
==11070== in use at exit: 0 bytes in 0 blocks
==11070== total heap usage: 2 allocs, 2 frees, 73,728 bytes allocated
==11070==
==11070== All heap blocks were freed -- no leaks are possible
==11070==
==11070== For lists of detected and suppressed errors, rerun with: -s
==11070== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I use the default Valgrind from Ubuntu 20.04: valgrind-3.15.0. The behavior happens with all compilers that I have installed: g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, g++-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0, Ubuntu clang version 12.0.0-3ubuntu1~20.04.5, as well as Ubuntu clang version 12.0.0-3ubuntu1~20.04.5 with -stdlib=libc++. I've tested these inside WSL 2, but the same behavior happens on a Linux VPS.
Why does this program crash on Ctrl + C when run in Valgrind? Is there some hidden signal unsafety, presumably in some initialization code?