Hi,
I believe that there is a flaw in the memory allocation hooks as they
implemented in the GNU C library that make impossible correct
implementation of the memory debugging software that suppose to work
in multi-threaded environment.
When I started to implement a simple memory de* (very similar to
mcheck/-lmcheck) I looked first at the manual. Here is what is written
in the manual:
So I setup these hooks at the initialization time (usingQuote:> Variable __malloc_hook
> The value of this variable is a pointer to the function
> that malloc uses whenever it is called.
> ………
__malloc_initialize_hook) and call called functions that are pointed
by old values by hook variables whenever I needed to call
malloc/free/.. functions internally, to avoid endless recursion.
What I’ve found is that it works only if MALLOC_CHECK_
environment variable
is set – otherwise initial value of __malloc_hook variable (and
others)
is zero and my code crash trying to call a function with zero address.
After studying libc sources and some experiments I found:
- Implementation of hooks is different from how it described in the
manual. Initial value of hooks is zero and “malloc.c” code
check it for zero and if
it is not zero calls the hook function. Otherwise it is just continue
the execution. And, which is important, this call of the hook is being
executed before taking a lock.
- Example code from the manual using a different method. When it needs
to call malloc internally it restore previous value of __malloc_hook,
calls the regular malloc() entry point and then set up its own hook
pointer to this variable again. Note that it could not work correctly
if there are more than one thread calls memory allocation functions
– there are short periods of time when hook variables are
restored to their old values and if a different thread calls the
corresponding memory allocation function at this time, it will go
directly to native malloc code (or to the previously installed hook)
rather than our hook code. And test I’ve written have showed
this.
After I studied MALLOC_CHECK_ implementation I’ve found that it
avoids this error by using internal malloc function (_int_malloc) and
never removes its hook. Another similar library function
mcheck(-lmcheck) does not do it – it uses technique similar to
the one used in the example from the manual and it will crash if used
in multi-threaded program with intensive use of memory allocation
functions.
So:
I would consider it as a bug in the GNU libc memory allocation
function. I see two ways to fix it:
1. To implement what is described in the manual. Make hook variables
pointing to the standard malloc/… functions implementation at
the very beginning and do indirect call from external
malloc/free/… functions.
2. Call hooks from under a global lock (arena locks do not good for
that and this solution could decrease performance).
And there is a way around (though also hitting performance) –
enable MALLOCK_CHECK_ (which is installed first) and then use my
initial techniques, calling function indirectly and never deinstalling
hooks.
Any ideas / notes?
Regards,
Michael Furman