Wrapper functions on malloc, free

Memory leak is a challenge that awaits any developer working in c. There are many tools, which perform both static and dynamic (run-time) analysis of the source code. These tools report memory leaks, if any. Klocwork is one such tool that can do. However, these are tools which require license fees. There are quite a few open-source projects which basically wraps all calls to malloc and free to custom functions. These functions monitor the usage of memory and finally call the actual memory allocation/deallocation routines.


[Code]

#include

int main()
{
int *ptr = (int*)malloc(sizeof(int)*32);
return(0);
}


Few tools have a macro,

#define malloc custom_malloc
#define free custom_free

It is this custom_malloc, which gets invoked,

void* custom_malloc(size_t size)
{
// Update report with the requested size
return(malloc(size));
}

And once the program is executed, the developer gets a chance to have a look at the report (stored in a file) along with other details like line number in the code, file etc. This information is good enough for the developer to start working on the leak.

This sounds fine, but they have one problem. These tools tend to modify the files of the project. These files have to be re-build and linked. This would be fine for a small project which might not require a lot of time, however large projects, like that of embedded systems which require cross-compilation might take quite a lot of time (I have worked on projects taking 30 minutes to produce a executable link format file).


So here comes an alternative, called library inter positioning. This works for APIs provided in a shared library. malloc is often implemented as a shared library by various vendors in libc. Any call to malloc is resolved by the dynamic linker/loader. We can have a custom function with the same name as that of malloc and create a shared library, memory.so. The functionality of this custom malloc would be same as that of the previous approach [Details shown below]. Once the shared object is created, LD_PRELOAD environment variable can be set with the appropriate values. The dynamic linker searches for the shared objects identified by LD_PRELOAD first followed by other shared objects identified by LD_LIBRARY_PATH.

Now, as the shared object (having new malloc) is registered, we can execute our program to have the dynamic linker resolve all calls of malloc to the malloc, defined in memory.so. There isn't any need to re-link the entire program [Advantage offered by shared library]. As earlier, once the program finishes, we would have the report having all the memory usage. Once the leak is identified and fixed, we can remove the memory.so. Again, there isn't any need to re-link the entire code.

------------------------------------------------------------------------------------------------

void *malloc(size_t size)
{
static void * (*func)();

if(!func)
func = (void *(*)()) dlsym(RTLD_NEXT, "malloc");
printf("malloc(%d) is called\n", size);
return(func(size));
}

Note that the actual malloc should be called only using function pointers. A direct call to malloc would become a recursive call to the very same function.
-----------------------------------------------------------------------------------------------

No comments: