Created attachment 172371 [details] Binary triggering the assertion failure SUMMARY I managed to trigger this assertion by creating a C program that directly implements _start. This may be out of scope for Valgrind, but other small programs directly written in assembler (with nasm) work under it, so please consider. STEPS TO REPRODUCE ``` % cat foo.c void _start() { _exit(0); } % gcc -v -o foo foo.c -nostdlib -lc -static -Os ... gcc version 13.2.0 (GCC) ... % valgrind ./foo ==5452== Memcheck, a memory error detector ==5452== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al. ==5452== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info ==5452== Command: ./foo ==5452== valgrind: m_debuginfo/storage.c:796 (vgModuleLocal_addDiCfSI): Assertion 'di->fsm.have_rx_map && di->fsm.rw_map_count' failed. zsh: segmentation fault valgrind ./foo ``` (Binary is attached.) OBSERVED RESULT Valgrind crashes with assertion failure. EXPECTED RESULT Valgrind runs the program which exits immediately. SOFTWARE/OS VERSIONS valgrind-3.23.0 Linux 6.9.5 x86_64 glibc ADDITIONAL INFORMATION Perhaps relevant: ``` % readelf -a foo ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x401000 Start of program headers: 64 (bytes into file) Start of section headers: 8672 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 8 Size of section headers: 64 (bytes) Number of section headers: 10 Section header string table index: 9 Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .note.gnu.pr[...] NOTE 0000000000400200 00000200 0000000000000030 0000000000000000 A 0 0 8 [ 2] .note.gnu.bu[...] NOTE 0000000000400230 00000230 0000000000000024 0000000000000000 A 0 0 4 [ 3] .text PROGBITS 0000000000401000 00001000 0000000000000034 0000000000000000 AX 0 0 16 [ 4] .eh_frame PROGBITS 0000000000402000 00002000 0000000000000044 0000000000000000 A 0 0 8 [ 5] .tbss NOBITS 0000000000403000 00002044 0000000000000004 0000000000000000 WAT 0 0 4 [ 6] .comment PROGBITS 0000000000000000 00002044 0000000000000012 0000000000000001 MS 0 0 1 [ 7] .symtab SYMTAB 0000000000000000 00002058 00000000000000f0 0000000000000018 8 2 8 [ 8] .strtab STRTAB 0000000000000000 00002148 0000000000000038 0000000000000000 0 0 1 [ 9] .shstrtab STRTAB 0000000000000000 00002180 0000000000000060 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), D (mbind), l (large), p (processor specific) There are no section groups in this file. Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x0000000000000254 0x0000000000000254 R 0x1000 LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000 0x0000000000000034 0x0000000000000034 R E 0x1000 LOAD 0x0000000000002000 0x0000000000402000 0x0000000000402000 0x0000000000000044 0x0000000000000044 R 0x1000 NOTE 0x0000000000000200 0x0000000000400200 0x0000000000400200 0x0000000000000030 0x0000000000000030 R 0x8 NOTE 0x0000000000000230 0x0000000000400230 0x0000000000400230 0x0000000000000024 0x0000000000000024 R 0x4 TLS 0x0000000000002044 0x0000000000403000 0x0000000000403000 0x0000000000000000 0x0000000000000004 R 0x4 GNU_PROPERTY 0x0000000000000200 0x0000000000400200 0x0000000000400200 0x0000000000000030 0x0000000000000030 R 0x8 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 Section to Segment mapping: Segment Sections... 00 .note.gnu.property .note.gnu.build-id 01 .text 02 .eh_frame 03 .note.gnu.property 04 .note.gnu.build-id 05 .tbss 06 .note.gnu.property 07 There is no dynamic section in this file. There are no relocations in this file. No processor specific unwind information to decode Symbol table '.symtab' contains 10 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS foo.c 2: 0000000000000000 4 TLS GLOBAL DEFAULT 5 errno 3: 0000000000401010 36 FUNC WEAK DEFAULT 3 _Exit 4: 0000000000401000 8 FUNC GLOBAL DEFAULT 3 _start 5: 0000000000000000 4 TLS GLOBAL HIDDEN 5 __libc_errno 6: 0000000000403000 0 NOTYPE GLOBAL DEFAULT 4 __bss_start 7: 0000000000403000 0 NOTYPE GLOBAL DEFAULT 4 _edata 8: 0000000000403000 0 NOTYPE GLOBAL DEFAULT 4 _end 9: 0000000000401010 36 FUNC GLOBAL HIDDEN 3 _exit No version information found in this file. Displaying notes found in: .note.gnu.property Owner Data size Description GNU 0x00000020 NT_GNU_PROPERTY_TYPE_0 Properties: x86 feature used: x86 x86 ISA used: x86-64-baseline Displaying notes found in: .note.gnu.build-id Owner Data size Description GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) Build ID: f317ecf6b96dc58f1e331a97a66e54b49afdf923 ```
I’ll take a look when l get back from holidays.
I have no problem on FreeBSD. I think that the issue is the Linux ld.bfd isn't generating a RW PT_LOAD and Valgrind is expecting at least 1.
If you can build Valgrind from source, can you try this diff please? diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c index 148de6f17..ef6a40051 100644 --- a/coregrind/m_debuginfo/storage.c +++ b/coregrind/m_debuginfo/storage.c @@ -793,7 +793,7 @@ void ML_(addDiCfSI) ( struct _DebugInfo* di, "warning: DiCfSI %#lx .. %#lx is huge; length = %u (%s)\n", base, base + len - 1, len, di->soname); - vg_assert(di->fsm.have_rx_map && di->fsm.rw_map_count); + vg_assert(di->fsm.have_rx_map); /* Find mapping where at least one end of the CFSI falls into. */ map = ML_(find_rx_mapping)(di, base, base); map2 = ML_(find_rx_mapping)(di, base + len - 1, @@ -1298,7 +1298,7 @@ void ML_(addVar)( struct _DebugInfo* di, seems a reasonable assumption to me. */ /* This is assured us by top level steering logic in debuginfo.c, and it is re-checked at the start of ML_(read_elf_object). */ - vg_assert(di->fsm.have_rx_map && di->fsm.rw_map_count); + vg_assert(di->fsm.have_rx_map); if (level > 0 && ML_(find_rx_mapping)(di, aMin, aMax) == NULL) { if (VG_(clo_verbosity) > 1) { VG_(message)(Vg_DebugMsg,
Indeed, the binary has no RW PT_LOAD (because it doesn't need one, data size is 0). When I use mold as a linker, it adds one and valgrind works again. Your patch fixes the issue for me, thanks!
I'm about ready to push the changes. On Debian i386 the testcase crashes for some reason. I'll try to dig into that a bit.
The code crashes on i686 due to using uninitialized %gs (for thread-local storage I assume).
The code for handling ELF segments needs to be refactored. commit b87649504136fc3e72684b176651912ba1514c6d (HEAD -> master, origin/users/paulf/try-bug491394, origin/master, origin/HEAD, bug491394) Author: Paul Floyd <pjfloyd@wanadoo.fr> Date: Tue Aug 20 21:44:00 2024 +0200 Bug 491394i - (vgModuleLocal_addDiCfSI): Assertion 'di->fsm.have_rx_map && di->fsm.rw_map_count' failed.
*** Bug 396476 has been marked as a duplicate of this bug. ***