|
From: Amir S. <ki...@gm...> - 2012-10-19 23:56:28
|
I'm trying to use __malloc_hook in some unit test code to verify the
code handles memory allocation failures properly. It's basically a
counter that makes malloc() fail when it reaches 0.
This works fine without Valgrind, but when run under Valgrind, the
hook never gets called and malloc() always succeeds, causing the test
to fail.
I've tested using Valgrind 3.7 and 3.8.1.
I've also looked in the source code, and there is no mention of
__malloc_hook, expcet in perf/test_input_for_tinycc.c and even there
it's just preprocessor output.
Valgrind does seem to set its own __malloc_hook. Without Valgrind, the
initial value of __malloc_hook is NULL, but with it, it points to
something in libc.
Even so, I can change __malloc_hook just fine, and it sticks too.
However, it's never called.
Does anyone know what code in Valgrind might change the value of
__malloc_hook? And what would cause the hook I set not to get called?
Or even better, how can I successfully use __malloc_hook while running
under Valgrind?
---------------------------
Code example
-------------------------
/*
* Copyright (c) 2012, Juniper Networks, Inc.
* All rights reserved.
*/
#include <stdio.h>
#include <malloc.h>
static unsigned int malloc_num_to_fail = 0;
// HOOKS
static void init_malloc_fail_hook(void);
static void *malloc_fail_hook(size_t, const void *);
static void *(*old_malloc_hook)(size_t size, const void *caller);
void (*__malloc_initialize_hook) (void) = init_malloc_fail_hook;
static void init_malloc_fail_hook(void)
{
printf("XXXXXX BEFORE %p\n", __malloc_hook);
old_malloc_hook = __malloc_hook;
__malloc_hook = malloc_fail_hook;
printf("XXXXXX AFTER %p\n", __malloc_hook);
printf("XXXXXX hook %p\n", malloc_fail_hook);
}
static void *malloc_fail_hook(size_t size, const void *caller)
{
printf("XXXXXXX malloc_fail_hook\n");
if (malloc_num_to_fail)
{
if (--malloc_num_to_fail == 0)
{
printf("Deliberate memory allocation failure
[size=%zu,caller=%p]\n", size, caller);
return NULL;
}
}
void *result;
__malloc_hook = old_malloc_hook;
result = malloc(size);
__malloc_hook = malloc_fail_hook;
return result;
}
// INTERFACE
void malloc_dbg_set_num_to_fail(unsigned int num)
{
init_malloc_fail_hook();
malloc_num_to_fail = num;
}
int main()
{
malloc_dbg_set_num_to_fail(1);
malloc(5);
printf("XXXXXX hook %p ?= %p\n", __malloc_hook, malloc_fail_hook);
}
--------------------
Output
Notice malloc_fail_hook never gets called
---------------
==23701== Memcheck, a memory error detector
==23701== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==23701== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==23701== Command: ./a.out
==23701==
XXXXXX BEFORE 0x41b2ae0
XXXXXX AFTER 0x8048584
XXXXXX hook 0x8048584
XXXXXX hook still 0x8048584 ?= 0x8048584
==23701==
==23701== HEAP SUMMARY:
==23701== in use at exit: 5 bytes in 1 blocks
==23701== total heap usage: 2 allocs, 1 frees, 7 bytes allocated
==23701==
==23701== LEAK SUMMARY:
==23701== definitely lost: 5 bytes in 1 blocks
==23701== indirectly lost: 0 bytes in 0 blocks
==23701== possibly lost: 0 bytes in 0 blocks
==23701== still reachable: 0 bytes in 0 blocks
==23701== suppressed: 0 bytes in 0 blocks
==23701== Rerun with --leak-check=full to see details of leaked memory
==23701==
==23701== For counts of detected and suppressed errors, rerun with: -v
==23701== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 19 from 8)
-----------------
Output without Valgrind
--------------------
XXXXXX BEFORE (nil)
XXXXXX AFTER 0x8048584
XXXXXX hook 0x8048584
XXXXXXX malloc_fail_hook
XXXXXX BEFORE 0x8048584
XXXXXX AFTER 0x8048584
XXXXXX hook 0x8048584
XXXXXXX malloc_fail_hook
Deliberate memory allocation failure [size=5,caller=0x8048633]
XXXXXX hook still 0x8048584 ?= 0x8048584
|
|
From: John R. <jr...@bi...> - 2012-10-20 02:51:40
|
> Or even better, how can I successfully use __malloc_hook while running > under Valgrind? You cannot. "man 3 malloc_hook" says "These functions are GNU extensions." Memcheck's implementation of malloc has "nothing to do" with glibc's implementation, except of course the C89/C99 syntax and semantics, which do not include __malloc_hook. Using something such as __malloc_hook presumes that you have an agreement with the implementor of malloc, and obviously you don't have that agreement when malloc is implemented by memcheck. (The "__" double underscore prefix to '__malloc_hook' *tells* you that you are doing something "naughty"; read the standard!) In order to use memcheck, then the program must use only the standard semantics of malloc, free, calloc, realloc, memalign, posix_memalign. Also see the NOTES: "The use of these hook functions is not safe in multithreaded programs, and they are now deprecated." -- |
|
From: Amir S. <ki...@gm...> - 2012-10-22 22:05:58
|
Thanks John. I was willing to go with the "naughty" way and whatever workarounds it required, if it meant not having to start wrapping all of our allocations. Does Valgrind, by any chance, have its own set of non-standard hooks? That would be a good solution for me. I looked in the source code and documentation, but could only find hooks that notify Valgrind about memory. On Fri, Oct 19, 2012 at 7:52 PM, John Reiser <jr...@bi...> wrote: >> Or even better, how can I successfully use __malloc_hook while running >> under Valgrind? > > You cannot. "man 3 malloc_hook" says "These functions are GNU extensions." > Memcheck's implementation of malloc has "nothing to do" with glibc's > implementation, except of course the C89/C99 syntax and semantics, > which do not include __malloc_hook. Using something such as __malloc_hook > presumes that you have an agreement with the implementor of malloc, > and obviously you don't have that agreement when malloc is implemented > by memcheck. (The "__" double underscore prefix to '__malloc_hook' > *tells* you that you are doing something "naughty"; read the standard!) > > In order to use memcheck, then the program must use only the standard > semantics of malloc, free, calloc, realloc, memalign, posix_memalign. > Also see the NOTES: "The use of these hook functions is not safe in > multithreaded programs, and they are now deprecated." > > -- > > > ------------------------------------------------------------------------------ > Everyone hates slow websites. So do we. > Make your web apps faster with AppDynamics > Download AppDynamics Lite for free today: > http://p.sf.net/sfu/appdyn_sfd2d_oct > _______________________________________________ > Valgrind-users mailing list > Val...@li... > https://lists.sourceforge.net/lists/listinfo/valgrind-users |
|
From: John R. <jr...@bi...> - 2012-10-22 23:58:45
|
> I was willing to go with the "naughty" way and whatever workarounds it > required, if it meant not having to start wrapping all of our > allocations. The intended way to do this is by "intercepting", "superseding", or "over-riding" the symbol 'malloc': Make your own shared library containing a malloc() routine, and load it into your app via environment variable LD_PRELOAD, so that calls from the app to malloc() go to your LD_PRELOADed library. Your malloc can do whatever it wants, probably including finding the "real" malloc by dlsym(RTLD_NEXT, "malloc") and calling that as a subroutine. See the manual page for dlsym. Remember to "#define _GNU_SOURCE 1" before "#include <dlfcn.h>". -- |
|
From: Amir S. <ki...@gm...> - 2012-10-24 01:29:16
|
That works perfectly. Thanks John!
I had to add a Valgrind suppression as dlsym() always leaves 20-bytes
"still reachable" block.
---------
{
dlsym in malloc_fail.cpp:malloc()
Memcheck:Leak
fun:calloc
obj:/lib/libdl-2.5.so
fun:dlsym
fun:malloc
...
}
---------
For anyone interested, this is the code I ended up using:
---------
/*
* Copyright (c) 2012, Juniper Networks, Inc.
* All rights reserved.
*/
#include "malloc_fail.h"
#include <cxxtest/TestSuite.h>
#define _GNU_SOURCE 1
#include <dlfcn.h>
static unsigned int malloc_num_to_fail = 0;
void malloc_dbg_set_num_to_fail(unsigned int num)
{
malloc_num_to_fail = num;
}
void *malloc(size_t size)
{
if (malloc_num_to_fail)
{
if (--malloc_num_to_fail == 0)
{
printf("Deliberate memory allocation failure [size=%zu]\n", size);
return NULL;
}
}
void * (*real_malloc) (size_t) = (void * (*) (size_t))
dlsym(RTLD_NEXT, "malloc");
return real_malloc(size);
}
-------
> The intended way to do this is by "intercepting", "superseding",
> or "over-riding" the symbol 'malloc': Make your own shared library
> containing a malloc() routine, and load it into your app via
> environment variable LD_PRELOAD, so that calls from the app to
> malloc() go to your LD_PRELOADed library. Your malloc can do
> whatever it wants, probably including finding the "real" malloc
> by dlsym(RTLD_NEXT, "malloc") and calling that as a subroutine.
> See the manual page for dlsym. Remember to "#define _GNU_SOURCE 1"
> before "#include <dlfcn.h>".
|