ldso libdl dl_cleanup issue - Possible Fix

Peter Kjellerstedt peter.kjellerstedt at axis.com
Thu May 15 16:19:52 UTC 2008


> -----Original Message-----
> From: uclibc-bounces at uclibc.org
> [mailto:uclibc-bounces at uclibc.org] On Behalf Of Kevin Day
> Sent: den 15 maj 2008 17:54
> To: uClibc
> Subject: ldso libdl dl_cleanup issue - Possible Fix
>
>
> 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

>From a quick look at the code in ldso/libdl/libdl.c I would say
that your assessment is correct. Here is a cleaner solution (this
is based on dl_cleanup() from SVN, not the 0.9.28.3 version):

void dl_cleanup(void)
{
        struct dyn_elf *d;
        struct dyn_elf *n;

        for (d = _dl_handles; d; d = n) {
                n = d->next_handle;
                do_dlclose(d, 1);
        }
}

//Peter



More information about the uClibc mailing list