Description of problem: When code is compiled/linked with `-O2 -flto=auto`, valgrind reports memory handling errors with non-existing paths to source files. Version-Release number of selected component (if applicable): binutils-2.35.1-33.fc34.x86_64 gcc-11.0.0-0.18.fc34.x86_64 valgrind-3.16.1-18.fc34.x86_64 Steps to Reproduce: 1. Prepare a pair of source/build directories: $ mkdir -p /tmp/test-valgrind/build $ cd /tmp/test-valgrind $ echo 'void foo(){}' > empty-fn.c $ echo 'int main() {free(main); foo();}' > bad-free.c $ cd build 2. Without `-flto=auto`, valgrind's output is correct: $ gcc -g -w -O2 ../{bad-free,empty-fn}.c && valgrind --xml=yes --xml-file=>(grep '<dir') ./a.out <dir>/builddir/build/BUILD/valgrind-3.16.1/coregrind/m_replacemalloc</dir> <dir>/tmp/test-valgrind/build/..</dir> <dir>/tmp/test-valgrind/build/..</dir> 3. With `-flto=auto`, valgrind's output is incorrect: $ gcc -g -w -O2 -flto=auto ../{bad-free,empty-fn}.c && valgrind --xml=yes --xml-file=>(grep '<dir') ./a.out <dir>/builddir/build/BUILD/valgrind-3.16.1/coregrind/m_replacemalloc</dir> <dir>/tmp/test-valgrind/build</dir> <dir>/tmp/test-valgrind/build</dir> Additional info: This causes problems with automated dynamic analysis of source RPM packages because -flto=auto is used in default build flags.
Does this happen only with XML output or do you also see this with: valgrind -q --fullpath-after="" ./a.out (The --fullpath-after="" shows the full path, default is to only show the file name.) I cannot replicate on f33, so this might be related to the combination of gcc 11 defaulting to DWARF5 and LTO.
(In reply to Mark Wielaard from comment #1) > Does this happen only with XML output or do you also see this with: > > valgrind -q --fullpath-after="" ./a.out > > (The --fullpath-after="" shows the full path, default is to only show the > file name.) Same problem with `valgrind -q --fullpath-after=""`: $ gcc -g -w -O2 ../{bad-free,empty-fn}.c && valgrind -q --fullpath-after="" ./a.out ==852== Invalid free() / delete / delete[] / realloc() ==852== at 0x483E9F1: free (/builddir/build/BUILD/valgrind-3.16.1/coregrind/m_replacemalloc/vg_replace_malloc.c:538) ==852== by 0x40104D: main (/tmp/test-valgrind/build/../bad-free.c:1) ==852== Address 0x401040 is in the Text segment of /tmp/test-valgrind/build/a.out ==852== at 0x401040: main (/tmp/test-valgrind/build/../bad-free.c:1) ==852== $ gcc -g -w -O2 -flto=auto ../{bad-free,empty-fn}.c && valgrind -q --fullpath-after="" ./a.out ==870== Invalid free() / delete / delete[] / realloc() ==870== at 0x483E9F1: free (/builddir/build/BUILD/valgrind-3.16.1/coregrind/m_replacemalloc/vg_replace_malloc.c:538) ==870== by 0x40104D: main (/tmp/test-valgrind/build/bad-free.c:1) ==870== Address 0x401040 is in the Text segment of /tmp/test-valgrind/build/a.out ==870== at 0x401040: main (/tmp/test-valgrind/build/bad-free.c:1) ==870== > I cannot replicate on f33 I confirm the problem is not observable on f33 with the above steps to reproduce.
Note that gdb prints paths to source files correctly for the same binary: $ valgrind -q --fullpath-after="" ./a.out ==985== Invalid free() / delete / delete[] / realloc() ==985== at 0x483E9F1: free (/builddir/build/BUILD/valgrind-3.16.1/coregrind/m_replacemalloc/vg_replace_malloc.c:538) ==985== by 0x40104D: main (/tmp/test-valgrind/build/bad-free.c:1) ==985== Address 0x401040 is in the Text segment of /tmp/test-valgrind/build/a.out ==985== at 0x401040: main (/tmp/test-valgrind/build/bad-free.c:1) ==985== $ rpm -q gdb gdb-10.1-4.fc34.x86_64 $ echo info sources | gdb -q ./a.out Reading symbols from ./a.out... (gdb) Source files for which symbols have been read in: Source files for which symbols will be read in on demand: /tmp/test-valgrind/empty-fn.c, /tmp/test-valgrind/bad-free.c, /tmp/test-valgrind/build/<artificial>@0x0
$ gdb -q ./a.out Reading symbols from ./a.out... (gdb) start Temporary breakpoint 1 at 0x401040: file ../bad-free.c, line 1. Starting program: /tmp/test-valgrind/build/a.out Temporary breakpoint 1, main () at ../bad-free.c:1 1 int main() {free(main); foo();}
The directory table looks as follows: Directory table: [path(line_strp)] 0 /tmp/test-valgrind/build (0) 1 .. (38) File name table: [path(line_strp), directory_index(udata)] 0 <artificial> (25), 0 1 empty-fn.c (69), 1 2 bad-free.c (55), 1 3 <built-in> (41), 0 So we are looking at file name 2 (bad-free.c), with directory 1 (..) and compdir /tmp/test-valgrind/build For some reason valgrind drops the .. (dir 1) part.
Found it, it was a typo in the valgrind DWARF5 line table reader: diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c index 88d5d99f1..3996623ed 100644 --- a/coregrind/m_debuginfo/readdwarf.c +++ b/coregrind/m_debuginfo/readdwarf.c @@ -796,7 +796,7 @@ void read_dwarf2_lineblock ( struct _DebugInfo* di, if (f == p_ndx) name = get_line_str (di, ui, &data, form, debugstr_img, debuglinestr_img); - else if (n == d_ndx) + else if (f == d_ndx) diridx = get_line_ndx (di, &data, form); else data = skip_line_form (di, ui, data, form); That meant it got the dir index wrong, in this case it believed the dir index was zero instead of one.
https://bodhi.fedoraproject.org/updates/FEDORA-2021-6fee690344
I confirm that valgrind-3.16.1-19.fc35 works as expected. Thank you for fixing it!