ldso libdl dl_cleanup issue - Possible Fix
Kevin Day
thekevinday at gmail.com
Thu May 15 15:54:11 UTC 2008
I distantly remember swinging at everything in sight trying to find
and resolve this problem.
This happened on a number of projects and is shown by valgrind, but
I've historically got from uClibc that it was "X Project"'s problem
and when I went to "X Project" they said it was uClibc's problem.
So, I was recently looking at the same problem again, this time with
abiword as the "X project".
I got the usual:
==2807== Invalid read of size 4
==2807== at 0x4600D8C: dl_cleanup (in /lib/libdl-0.9.28.so)
==2807== by 0x4000ADC: (within /lib/ld-uClibc-0.9.28.so)
==2807== by 0x4B4E021: exit (in /lib/libuClibc-0.9.28.so)
==2807== by 0x4B2C46D: __uClibc_main (in /lib/libuClibc-0.9.28.so)
==2807== by 0x8171D1F: _start (in /bin/abiword)
==2807== Address 0x5a0f96c is 4 bytes inside a block of size 24 free'd
==2807== at 0x401933C: free (in
/toolchain/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2807== by 0x4600C8A: (within /lib/libdl-0.9.28.so)
==2807== by 0x4600D8B: dl_cleanup (in /lib/libdl-0.9.28.so)
==2807== by 0x4000ADC: (within /lib/ld-uClibc-0.9.28.so)
==2807== by 0x4B4E021: exit (in /lib/libuClibc-0.9.28.so)
==2807== by 0x4B2C46D: __uClibc_main (in /lib/libuClibc-0.9.28.so)
==2807== by 0x8171D1F: _start (in /bin/abiword)
again, dl_cleanup seems to be reading unallocated memory according to valgrind.
After recompiling uClibc with debug symbols, I noticed that it was
caused by two lines in: uClibc-0.9.28.3/ldso/libdl/libdl.c
Line 136: do_dlclose(d, 1);
and in depth, Line 578: free(handle);
Considering that handle was being used during this entire process it
should be allocated..
I decided to look at the logic of the dl_cleanup function and the
do_dlclose function.
Here is a simple explanation of the problem I see:
dl_cleanup will call do_dlclose with the pointer "d"
Inside of do_dlclose, "d" will ultimately get free'd
After do_dlclose finishes executing, the for loop from dl_cleanup will
then take the pointer "d" and move it to the next pointer.
And this is where I am confused, if "d" was free'd by the do_dlclose
function, then how can it use the "d" pointer to iterate along the
next location?
So it makes sense that d(NULL)->(Next Pointer) generates an invalid
read according to valgrind.
To test this, I changed the contents of dl_cleanup to:
{
struct dyn_elf *d = _dl_handles;
struct dyn_elf *n;
if (d){
n = d->next;
do_dlclose(d, 1);
while (n){
d = n;
n = d->next;
do_dlclose(d, 1);
}
}
}
I then installed libdl.so, and re-ran valgrind on abiword and the
invalid read no longer appeared.
Does this sound right or is there some loophole in my logic or some
aspect of do_dlclose(..) I am missing?
--
Kevin Day
More information about the uClibc
mailing list