non cumulative memory leak in dlopen/dlclose

Bug #883775 reported by Ivan Sorokin
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
eglibc (Ubuntu)
Confirmed
Undecided
Unassigned

Bug Description

Ubuntu 11.10, libc6 2.13-20ubuntu5.

After calling dlopen/dlclose few blocks of memory left unfreed. They number is not grow when dlopen/dlclose are called several times.

This is not fatal bug, but it makes it harder to find memory leaks in other parts of program.

Source code:

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

void print_dlerror()
{
      char const* msg = dlerror();
      if (msg == NULL)
         fprintf(stderr, "unknown error at dynamic linking");
      else
         fprintf(stderr, "dynamic linking error: %s", msg);
}

int main()
{
   void* asound = dlopen("/usr/lib/x86_64-linux-gnu/libasound.so.2", RTLD_LAZY);
   if (asound == NULL)
   {
      print_dlerror();
      return EXIT_FAILURE;
   }

   printf("module is loaded successfully: %p\n", asound);

   dlclose(asound);

   return EXIT_SUCCESS;
}

Valgrind output:

valgrind --leak-check=full --show-reachable=yes -v ./a.out

==2114== HEAP SUMMARY:
==2114== in use at exit: 3,361 bytes in 12 blocks
==2114== total heap usage: 22 allocs, 10 frees, 6,638 bytes allocated
==2114==
==2114== Searching for pointers to 12 not-freed blocks
==2114== Checked 114,056 bytes
==2114==
==2114== 64 bytes in 2 blocks are still reachable in loss record 1 of 6
==2114== at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==2114== by 0x40141B6: _dl_close_worker (dl-close.c:374)
==2114== by 0x401469D: _dl_close (dl-close.c:754)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4E3052E: _dlerror_run (dlerror.c:164)
==2114== by 0x4E3000E: dlclose (dlclose.c:48)
==2114== by 0x4007AA: main (in /home/ivan/a.out)
==2114==
==2114== 71 bytes in 2 blocks are still reachable in loss record 2 of 6
==2114== at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==2114== by 0x40085B3: _dl_map_object (dl-load.c:162)
==2114== by 0x400C8A1: openaux (dl-deps.c:65)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x400CF65: _dl_map_object_deps (dl-deps.c:247)
==2114== by 0x4012BA6: dl_open_worker (dl-open.c:263)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4013379: _dl_open (dl-open.c:569)
==2114== by 0x4E2FF25: dlopen_doit (dlopen.c:67)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4E3052E: _dlerror_run (dlerror.c:164)
==2114== by 0x4E2FFC0: dlopen@@GLIBC_2.2.5 (dlopen.c:88)
==2114==
==2114== 71 bytes in 2 blocks are still reachable in loss record 3 of 6
==2114== at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==2114== by 0x400B42C: _dl_new_object (dl-object.c:161)
==2114== by 0x40065B5: _dl_map_object_from_fd (dl-load.c:957)
==2114== by 0x400831C: _dl_map_object (dl-load.c:2250)
==2114== by 0x400C8A1: openaux (dl-deps.c:65)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x400CF65: _dl_map_object_deps (dl-deps.c:247)
==2114== by 0x4012BA6: dl_open_worker (dl-open.c:263)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4013379: _dl_open (dl-open.c:569)
==2114== by 0x4E2FF25: dlopen_doit (dlopen.c:67)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114==
==2114== 112 bytes in 2 blocks are still reachable in loss record 4 of 6
==2114== at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==2114== by 0x400D016: _dl_map_object_deps (dl-deps.c:470)
==2114== by 0x4012BA6: dl_open_worker (dl-open.c:263)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4013379: _dl_open (dl-open.c:569)
==2114== by 0x4E2FF25: dlopen_doit (dlopen.c:67)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4E3052E: _dlerror_run (dlerror.c:164)
==2114== by 0x4E2FFC0: dlopen@@GLIBC_2.2.5 (dlopen.c:88)
==2114== by 0x400771: main (in /home/ivan/a.out)
==2114==
==2114== 696 bytes in 2 blocks are still reachable in loss record 5 of 6
==2114== at 0x4C279F2: calloc (vg_replace_malloc.c:467)
==2114== by 0x4010329: _dl_check_map_versions (dl-version.c:300)
==2114== by 0x4012EC0: dl_open_worker (dl-open.c:269)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4013379: _dl_open (dl-open.c:569)
==2114== by 0x4E2FF25: dlopen_doit (dlopen.c:67)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4E3052E: _dlerror_run (dlerror.c:164)
==2114== by 0x4E2FFC0: dlopen@@GLIBC_2.2.5 (dlopen.c:88)
==2114== by 0x400771: main (in /home/ivan/a.out)
==2114==
==2114== 2,347 bytes in 2 blocks are still reachable in loss record 6 of 6
==2114== at 0x4C279F2: calloc (vg_replace_malloc.c:467)
==2114== by 0x400B1BD: _dl_new_object (dl-object.c:77)
==2114== by 0x40065B5: _dl_map_object_from_fd (dl-load.c:957)
==2114== by 0x400831C: _dl_map_object (dl-load.c:2250)
==2114== by 0x400C8A1: openaux (dl-deps.c:65)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x400CF65: _dl_map_object_deps (dl-deps.c:247)
==2114== by 0x4012BA6: dl_open_worker (dl-open.c:263)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114== by 0x4013379: _dl_open (dl-open.c:569)
==2114== by 0x4E2FF25: dlopen_doit (dlopen.c:67)
==2114== by 0x400E995: _dl_catch_error (dl-error.c:178)
==2114==
==2114== LEAK SUMMARY:
==2114== definitely lost: 0 bytes in 0 blocks
==2114== indirectly lost: 0 bytes in 0 blocks
==2114== possibly lost: 0 bytes in 0 blocks
==2114== still reachable: 3,361 bytes in 12 blocks
==2114== suppressed: 0 bytes in 0 blocks

Revision history for this message
Martin Pokorny (martin-truffulatree) wrote :

Thanks for reporting this bug, and taking the time to make Ubuntu better! I have been able to duplicate this bug using the information you provided, and will therefore mark this bug as "confirmed".

This bug appears to be a known problem in either valgrind or glibc. If the fault lies with glibc, this would seem to indicate a trivial memory leak. There are several possible valgrind suppressions you can use to clean up its output. In my testing I found the following suppressions to be useful, although l can't claim that the set is optimal:

{
  dl_catch_error-leak-1
  Memcheck:Leak
  ...
  fun:dl_open_worker
  fun:_dl_catch_error
  ...
}
{
  dl_catch_error-leak-2
  Memcheck:Leak
  ...
  fun:_dl_close_worker
  fun:_dl_close
  fun:_dl_catch_error
  ...
}

Changed in eglibc (Ubuntu):
status: New → Confirmed
Revision history for this message
Martin Pokorny (martin-truffulatree) wrote :

A brief look at libc6 source code indicates that perhaps any call to _dl_catch_error may give rise to these valgrind warnings. The valgrind suppressions I indicated above may not be sufficient in that case to catch all dl-related valgrind warnings. You can probably suppress all these valgrind warnings with the following:
{
  dl_catch_error-leak
  Memcheck:Leak
  ...
  fun:_dl_catch_error
  ...
}
I'm no expert in either the glibc codebase or valgrind, so please evaluate this workaround for yourself.

Revision history for this message
Ivan Sorokin (sorokin) wrote :

Thank you, Martin. Suppression seems to be the only feasible solution, because libc6 code is really complicated in this function.

Should we report this bug upstream or let it stay here? eglibc (http://www.eglibc.org/issues/) bug-tracker seems to be not very popular.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.