|
From: John R.
|
> ==11556== Conditional jump or move depends on uninitialised value(s)
> ==11556== at 0x40008A4A: elf_dynamic_do_rela.8 (in /lib/ld-2.2.93.so)
> ==11556== by 0x40008CBA: _dl_relocate_object_internal (in
> /lib/ld-2.2.93.so)
Glibc/elf uses some uninitialized values that happen to work because
the same uninit value is used twice and "cancels." This reveals
an opportunity for enhancement in memcheck, and sleazy code in glibc.
Look at this code for elf_dynamic_do_rela() in elf/dynamic-link.h:
-----
struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \
ranges[0].lazy = 0; \
ranges[0].size = ranges[1].size = 0; \
ranges[0].start = 0; \
-----
and notice that ranges[1].lazy and .start are not initialized. Later:
-----
for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
elf_dynamic_do_##reloc ((map), \
ranges[ranges_index].start, \
ranges[ranges_index].size, \
ranges[ranges_index].lazy); \
-----
and for elf_dynamic_do_rela in elf/do-rel.h:
-----
const ElfW(Rel) *r = (const void *) reladdr; ## .start
const ElfW(Rel) *end = (const void *) (reladdr + relsize); ## .start + .size
-----
and later in elf_dynamic_do_rela:
-----
for (; r < end; ++r)
-----
Valgrind notices that "r < end" depends on reladdr, and reladdr is
uninitialized. The C standard says that therefore _any_ behavior
is allowed: infinite loop, wrong answer, random answer, "correct"
answer. It just happens that gcc-compiled code works.
Several years ago, the maintainer of glibc boasted of pride in this code.
All executables that are supervised by ld-linux.so.2 suffer this, but
vagrind [memcheck] usually does not notice because it happens before
any LD_PRELOAD module gets control. Memcheck does see the problem
on some subsequent dynamic loads, as here.
--
|