dlopen/dlsym/dlclose (dlfcn.h) causes memory leak - c

When using the dlfcn family like so:
#include <stdio.h>
#include <dlfcn.h>
typedef int(*timefunc_t)(void*);
int main()
{
timefunc_t fun;
void* handle;
handle = dlopen("libc.so.6", RTLD_LAZY);
fun = (timefunc_t)dlsym(handle, "time");
printf("time=%d\n", fun(NULL));
dlclose(handle);
return 0;
}
It causes a Memory leak:
==28803== Memcheck, a memory error detector
==28803== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==28803== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==28803== Command: ./dl
==28803==
time=1309249569
==28803==
==28803== HEAP SUMMARY:
==28803== in use at exit: 20 bytes in 1 blocks
==28803== total heap usage: 1 allocs, 0 frees, 20 bytes allocated
==28803==
==28803== LEAK SUMMARY:
==28803== definitely lost: 0 bytes in 0 blocks
==28803== indirectly lost: 0 bytes in 0 blocks
==28803== possibly lost: 0 bytes in 0 blocks
==28803== still reachable: 20 bytes in 1 blocks
==28803== suppressed: 0 bytes in 0 blocks
==28803== Rerun with --leak-check=full to see details of leaked memory
==28803==
==28803== For counts of detected and suppressed errors, rerun with: -v
==28803== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 6)
My question is, Is this a programming error, or rather a bug in dlfcn/libdl.so?

Looks like the latter. However this does not appear to be a big deal because if you repeat the dlopen/dlsym/dlclose calling another routine you'll see that the memory leak is of the same size, it does not grow with the number of dlopen/dlclose calls.

Related

How declaring a variable with malloc lead to lost bits?

First, I have ran valgrind to make sure that (on the default settings) there are zero errors. Then, I decided to check for leaks with something like: --leak-check=full
I have code that looks something like char* variable=malloc(sizeof(char)*(strlen(in)+1)); and valgrind reports that memory is "definitely lost."
The only other line of code I have access to (this is in a library callback function) is the line of code where in is declared. This is a function argument of type void * (though in this case I'm hoping we can safely assume the value to be null terminated.)
Having
#include <stdlib.h>
char * G;
int main()
{
char * l = malloc(10);
G = malloc(20);
}
The execution under valgrind gives :
pi#raspberrypi:/tmp $ valgrind --leak-check=full ./a.out
==11087== Memcheck, a memory error detector
==11087== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11087== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==11087== Command: ./a.out
==11087==
==11087==
==11087== HEAP SUMMARY:
==11087== in use at exit: 30 bytes in 2 blocks
==11087== total heap usage: 2 allocs, 0 frees, 30 bytes allocated
==11087==
==11087== 10 bytes in 1 blocks are definitely lost in loss record 1 of 2
==11087== at 0x4847568: malloc (vg_replace_malloc.c:299)
==11087== by 0x10453: main (mm.c:7)
==11087==
==11087== LEAK SUMMARY:
==11087== definitely lost: 10 bytes in 1 blocks
==11087== indirectly lost: 0 bytes in 0 blocks
==11087== possibly lost: 0 bytes in 0 blocks
==11087== still reachable: 20 bytes in 1 blocks
==11087== suppressed: 0 bytes in 0 blocks
==11087== Reachable blocks (those to which a pointer was found) are not shown.
==11087== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==11087==
==11087== For counts of detected and suppressed errors, rerun with: -v
==11087== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 3)
The malloc(10) is definitely lost because there is no way to access it at the end of the execution (here out of main)
The malloc(20) is not lost because still reachable through G

Valgrind and "#pragma pack(2)"

I've got a problem using valgrind. In my project all structures are surrounded by #pragma pack(2) to reduce memory usage.
Now, allocating memory to a pointer within a structure leads to a valgrind error, e. g.: 14 bytes in 7 blocks are definitely lost in loss record 2 of 3.
EDIT: I was not precise enough. Sure, there is a memory leak as I never call free. But the problem is, that valgrind says the memory is definetly lost. This it not the case, since param_info is static.
So why does valgrind says definitely lost and not still reachable? If I remove the pragma directives the output is as expected.
Is this to be expected? And if so, can anybody please explain why?
Here is a minimal example to reproduce the error:
#include <stdlib.h>
#pragma pack(push)
#pragma pack(2)
struct param_ref
{
short *p;
short max_p;
};
#pragma pack(pop)
int main()
{
static struct param_ref *param_info = NULL;
static short param_max = 0;
int i;
if (param_info == NULL)
{
param_max = 10;
param_info = malloc(sizeof (struct param_ref) * param_max);
for (i = 0; i < param_max; i++)
{
param_info[i].p = malloc(sizeof (short));
param_info[i].max_p = 1;
}
}
return 0;
}
And the valgrind output:
xxx#homer:~/val$ valgrind --leak-check=full ./a.out
==4156== Memcheck, a memory error detector
==4156== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4156== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4156== Command: ./a.out
==4156==
==4156==
==4156== HEAP SUMMARY:
==4156== in use at exit: 120 bytes in 11 blocks
==4156== total heap usage: 11 allocs, 0 frees, 120 bytes allocated
==4156==
==4156== 14 bytes in 7 blocks are definitely lost in loss record 2 of 3
==4156== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4156== by 0x4005AF: main (in /home/xxx/val/a.out)
==4156==
==4156== LEAK SUMMARY:
==4156== definitely lost: 14 bytes in 7 blocks
==4156== indirectly lost: 0 bytes in 0 blocks
==4156== possibly lost: 0 bytes in 0 blocks
==4156== still reachable: 106 bytes in 4 blocks
==4156== suppressed: 0 bytes in 0 blocks
==4156== Reachable blocks (those to which a pointer was found) are not shown.
==4156== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==4156==
==4156== For counts of detected and suppressed errors, rerun with: -v
==4156== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
EDIT2: Output of valgrind without pragma directives:
xxx#homer:~/val$ valgrind --leak-check=full ./a.out
==5374== Memcheck, a memory error detector
==5374== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==5374== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==5374== Command: ./a.out
==5374==
==5374==
==5374== HEAP SUMMARY:
==5374== in use at exit: 180 bytes in 11 blocks
==5374== total heap usage: 11 allocs, 0 frees, 180 bytes allocated
==5374==
==5374== LEAK SUMMARY:
==5374== definitely lost: 0 bytes in 0 blocks
==5374== indirectly lost: 0 bytes in 0 blocks
==5374== possibly lost: 0 bytes in 0 blocks
==5374== still reachable: 180 bytes in 11 blocks
==5374== suppressed: 0 bytes in 0 blocks
==5374== Reachable blocks (those to which a pointer was found) are not shown.
==5374== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==5374==
==5374== For counts of detected and suppressed errors, rerun with: -v
==5374== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Some pointers to the memory are not properly aligned for valgrind to find them due to the packing hence valgrind reports them as definitely lost. It seems it has no option for this like LeakSanitizer:
LSAN_OPTIONS=use_unaligned=1
use_unaligned : If 0, LSan will only consider properly aligned 8-byte patterns when looking for pointers. Set to 1 to include unaligned patterns. This refers to the pointer itself, not the memory being pointed at.
$ gcc so.c -fsanitize=address -g
$ ./a.out
=================================================================
==4943==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 14 byte(s) in 7 object(s) allocated from:
#0 0x7fe18898ba0a in malloc (/lib64/libasan.so.2+0x98a0a)
#1 0x4008d2 in main /home/m/so.c:28
#2 0x7fe18855378f in __libc_start_main (/lib64/libc.so.6+0x2078f)
SUMMARY: AddressSanitizer: 14 byte(s) leaked in 7 allocation(s).
$ LSAN_OPTIONS=use_unaligned=1 ./a.out
$

Valgrind definitely lost and reachable with exit vs main return

Valgrind reports definitely lost memory if I exit main with return 0;, but reports still reachable memory if I exit main with exit(0);.
test-reachable.c:
#include <stdlib.h>
int main() {
void *data = malloc(256);
exit(0);
}
test-lost.c:
#include <stdlib.h>
int main() {
void *data = malloc(256);
return 0;
}
Behavior:
$ gcc test-reachable.c -o test-reachable
$ valgrind --leak-check=yes ./test-reachable
==7696== Memcheck, a memory error detector
==7696== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7696== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==7696== Command: ./test-reachable
==7696==
==7696==
==7696== HEAP SUMMARY:
==7696== in use at exit: 256 bytes in 1 blocks
==7696== total heap usage: 1 allocs, 0 frees, 256 bytes allocated
==7696==
==7696== LEAK SUMMARY:
==7696== definitely lost: 0 bytes in 0 blocks
==7696== indirectly lost: 0 bytes in 0 blocks
==7696== possibly lost: 0 bytes in 0 blocks
==7696== still reachable: 256 bytes in 1 blocks
==7696== suppressed: 0 bytes in 0 blocks
==7696== Reachable blocks (those to which a pointer was found) are not shown.
==7696== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==7696==
==7696== For counts of detected and suppressed errors, rerun with: -v
==7696== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$ gcc test-lost.c -o test-lost
$ valgrind --leak-check=yes ./test-lost
==7774== Memcheck, a memory error detector
==7774== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7774== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==7774== Command: ./test-lost
==7774==
==7774==
==7774== HEAP SUMMARY:
==7774== in use at exit: 256 bytes in 1 blocks
==7774== total heap usage: 1 allocs, 0 frees, 256 bytes allocated
==7774==
==7774== 256 bytes in 1 blocks are definitely lost in loss record 1 of 1
==7774== at 0x4C2C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7774== by 0x40051C: main (in /tmp/test-lost)
==7774==
==7774== LEAK SUMMARY:
==7774== definitely lost: 256 bytes in 1 blocks
==7774== indirectly lost: 0 bytes in 0 blocks
==7774== possibly lost: 0 bytes in 0 blocks
==7774== still reachable: 0 bytes in 0 blocks
==7774== suppressed: 0 bytes in 0 blocks
==7774==
==7774== For counts of detected and suppressed errors, rerun with: -v
==7774== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Shouldn't these behave the same?
Shouldn't these behave the same?
No.
In test-reachable.c the memory is referenced by the stack variable data at the time of the exit of the program, so it is still reachable, while in test-lost.c the memory is not referenced anymore because the main function has already returned, the reference does not exist anymore, the memory is definitely lost.
In C++ when return in main() is called then the destructors will be called for locally scoped objects whereas if exit() is called then no destructor will be called for locally scoped objects.
I think this is similar in C with regards to objects allocated on the stack.
That probably explains why in the return case non freed memory is treated as definitely lost and in the exit(0) case the memory is reported as still reachable.

Why valgrind report my memory as "definitely lost"?

Consider this code:
#include <stdlib.h>
int* alloc()
{
return malloc(250 * sizeof(int));
}
int main()
{
int i;
int *vars[3];
for(i = 0; i < 3; ++i) {
vars[i] = alloc();
}
}
Valgrind output:
$ valgrind --leak-check=full ./lala
==16775== Memcheck, a memory error detector
==16775== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==16775== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==16775== Command: ./lala
==16775==
==16775==
==16775== HEAP SUMMARY:
==16775== in use at exit: 3,000 bytes in 3 blocks
==16775== total heap usage: 3 allocs, 0 frees, 3,000 bytes allocated
==16775==
==16775== 3,000 bytes in 3 blocks are definitely lost in loss record 1 of 1
==16775== at 0x4C2BBA0: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16775== by 0x4005B3: alloc (lala.c:5)
==16775== by 0x4005DF: main (lala.c:13)
==16775==
==16775== LEAK SUMMARY:
==16775== definitely lost: 3,000 bytes in 3 blocks
==16775== indirectly lost: 0 bytes in 0 blocks
==16775== possibly lost: 0 bytes in 0 blocks
==16775== still reachable: 0 bytes in 0 blocks
==16775== suppressed: 0 bytes in 0 blocks
==16775==
==16775== For counts of detected and suppressed errors, rerun with: -v
==16775== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
According to Valgrind's manual:
If --leak-check is set appropriately, for each remaining block,
Memcheck determines if the block is reachable from pointers within the
root-set. The root-set consists of (a) general purpose registers of
all threads, and (b) initialized, aligned, pointer-sized data words in
accessible client memory, including stacks.
For what I understand, since the "definitely lost" memory are still pointed to from the main() function's stack, they should be categorized as "still reachable", right?
If not, how can I configure Valgrind to try to reach memory blocks from main's stack, to determine if they are "still reachable"?
EDIT:
Please don't tell me to free the pointers at the end of main, that is not what I am asking about. For the distinction between "still reachable" and "definitely lost" on Valgrind terms, see this answer: https://stackoverflow.com/a/3857638/578749
Your memory is definitely lost when the stack of main is destroyed, that is, when it returns. Thus, the solution is not to return.
#include <stdlib.h>
int main()
{
/* your code here */
exit(0);
}
The behavior or main returning 0 or exit(0) should be equivalent.
Now the output is:
==5035== Memcheck, a memory error detector
==5035== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==5035== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==5035== Command: ./a.out
==5035==
==5035==
==5035== HEAP SUMMARY:
==5035== in use at exit: 3,000 bytes in 3 blocks
==5035== total heap usage: 3 allocs, 0 frees, 3,000 bytes allocated
==5035==
==5035== LEAK SUMMARY:
==5035== definitely lost: 0 bytes in 0 blocks
==5035== indirectly lost: 0 bytes in 0 blocks
==5035== possibly lost: 0 bytes in 0 blocks
==5035== still reachable: 3,000 bytes in 3 blocks
==5035== suppressed: 0 bytes in 0 blocks
==5035== Reachable blocks (those to which a pointer was found) are not shown.
==5035== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==5035==
==5035== For counts of detected and suppressed errors, rerun with: -v
==5035== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Valgrind and FCGI: How to free all memory correctly after use

Using this simple program:
#include "fcgi_stdio.h"
int main(void)
{
while(FCGI_Accept() >= 0)
{
}
FCGI_Finish();
return(0);
}
I get this result from valgrind:
Memcheck, a memory error detector
Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
Command: ./val
HEAP SUMMARY:
in use at exit: 768 bytes in 1 blocks
total heap usage: 1 allocs, 0 frees, 768 bytes allocated
768 bytes in 1 blocks are still reachable in loss record 1 of 1
at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x4E3D986: OS_LibInit (os_unix.c:171)
by 0x4E3C80A: FCGX_Init (fcgiapp.c:2088)
by 0x4E3C89A: FCGX_IsCGI (fcgiapp.c:1946)
by 0x4E3CCA4: FCGI_Accept (fcgi_stdio.c:120)
by 0x4006F6: main (in /home/[me]/kod/val)
LEAK SUMMARY:
definitely lost: 0 bytes in 0 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 768 bytes in 1 blocks
suppressed: 0 bytes in 0 blocks
For counts of detected and suppressed errors, rerun with: -v
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
How do I free all memory correctly after using FCGI?
I ran into the same issue. Seems like a bug in FCGI. Workaround is calling a library function directly for cleanup. OS_LibShutdown() frees the memory init by FCGI_Accept() which internally calls FCGX_Init(). For multithread apps, you have to call FCGX_Init() yourself.
// Declare this (extern "C" is only required if from CPP)...
extern "C"
{
void OS_LibShutdown(void);
}
// From clean up code, call this...
OS_LibShutdown();

Resources