2011-10-18 8 views
5

Estoy tratando de interponer malloc/free/calloc/realloc etc. con algunos intercaladores a través de LD_PRELOAD. En mi pequeña prueba, solo malloc parece estar interpuesto, aunque se detectó free (ver salida).LD_PRELOAD solo funciona para malloc, no es gratuito

Espero que la salida contenga una línea "NANO: libre (x)" - pero esta línea falta.

Dada

// compile with: gcc test.cc 
#include <stdio.h> 
#include <stdlib.h> 

int main(int argc, char* argv[]) { 

    void* p = malloc(123); 
    printf("HOST p=%p\n", p); 
    free(p); 
} 

Y

// compile with: g++ -O2 -Wall -fPIC -ldl -o libnano.so -shared main.cc 
#include <stdio.h> 
#include <dlfcn.h> 

typedef void *(*MallocFunc)(size_t size); 
typedef void (*FreeFunc)(void*); 

// Original functions 
static MallocFunc real_malloc = NULL; 
static FreeFunc real_free = NULL; 

static void __nano_init(void) { 
    // Override original functions 
    real_malloc = (MallocFunc)dlsym(RTLD_NEXT, "malloc"); 
    if (NULL == real_malloc) { 
     fprintf(stderr, "Error in `dlsym`: %s\n", dlerror()); 
    } else { 
     fprintf(stderr, "NANO: malloc() replaced @%p\n", real_malloc); 
    } 

    real_free = (FreeFunc)dlsym(RTLD_NEXT, "free"); 
    if (NULL == real_free) { 
     fprintf(stderr, "Error in `dlsym`: %s\n", dlerror()); 
    } else { 
     fprintf(stderr, "NANO: free() replaced @%p\n", real_free); 
    } 
} 

// replacement functions 
void *malloc(size_t size) { 
    if(real_malloc==NULL) __nano_init(); 

    void *p = NULL; 
    fprintf(stderr, "NANO: malloc(%lu) = ", size); 
    p = real_malloc(size); 
    fprintf(stderr, "%p\n", p); 

    return p; 
} 

void free(void* ptr) { 
    if(real_free==NULL) __nano_init(); 

    fprintf(stderr, "NANO: free(%p)\n", ptr); 
    real_free(ptr); 

    return; 
} 

La salida real es:

% ./a.out 
NANO: malloc() replaced @0x3b36274dc0 
NANO: free() replaced @0x3b36272870 
NANO: malloc(123) = 0x601010 
HOST p=0x601010 

Respuesta

9

está compilando un C++; esto significa que (de forma predeterminada) las funciones tienen nombres desglosados ​​para adaptarse a C++ ABI. Desafortunadamente, las funciones que intentas conectar son no con nombres desarticulados, por lo que terminas enganchando la función incorrecta (inexistente).

La solución es a) definir sus envoltorios en un bloque extern "C" { } o a) asegúrese de incluir el encabezado para la función, como en #include <cstdlib>. Esto extraerá las declaraciones para malloc y free con un contenedor extern "C", indicándole al compilador que no use el comando name-mangle.

La razón malloc funciona es probablemente porque <stdio.h> o <dlfcn.h> tirones en una declaración para mallocpero nofree. Por lo tanto, malloc no está alterado, pero free está mutilado.

También tenga en cuenta: Si está utilizando glibc, debe utilizar malloc hooks para enganchar funciones de asignación de memoria. glibc hace algunas cosas bastante extrañas con versiones de símbolos que de lo contrario pueden interferir con tus ganchos. Un ejemplo de cómo usarlo está en la documentación vinculada; ¡no olvides extern "C" s si estás usando C++, sin embargo!

+0

Argh name mangling. Spot on. Calcula que todos los ejemplos que estaba usando son C/gcc. Debería haberme dado cuenta cuando fui a g ++. Gracias por el consejo, por ahora preferiría evaluar la técnica LD_PRELOAD directa. No estoy seguro de las ventajas de los ganchos Malloc. – Justicle

+0

@bdonian si es un juego Tengo una pregunta de seguimiento aquí: http://stackoverflow.com/questions/7910666/problems-with-ld-preload-and-calloc-interposition-for-certain-executables – Justicle

Cuestiones relacionadas