Domanda

Con Linux / GCC / C ++, vorrei registrare qualcosa su stderr ogni volta che vengono chiamati malloc / free / new / delete. Sto cercando di capire le allocazioni di memoria di una libreria, quindi mi piacerebbe generare questo output mentre eseguo i test unitari. Uso valgrind per il rilevamento delle perdite di mem, ma non riesco a trovare un'opzione per renderlo solo log allocazioni.

Qualche idea? Sto cercando la soluzione più semplice possibile. La ricompilazione della libreria non è un'opzione.

È stato utile?

Soluzione

malloc_hook (3) ti consente di fare tutto il mondo interporre la propria funzione malloc . (C'è anche __realloc_hook __free_hook ecc., Li ho lasciati fuori per semplicità.)

#include <stdio.h>
#include <malloc.h>

static void *(*old_malloc_hook)(size_t, const void *);

static void *new_malloc_hook(size_t size, const void *caller) {
    void *mem;

    __malloc_hook = old_malloc_hook;
    mem = malloc(size);
    fprintf(stderr, "%p: malloc(%zu) = %p\n", caller, size, mem);
    __malloc_hook = new_malloc_hook;

    return mem;
}

static void init_my_hooks(void) {
    old_malloc_hook = __malloc_hook;
    __malloc_hook = new_malloc_hook;
}

void (*__malloc_initialize_hook)(void) = init_my_hooks;
$ cat >mem.c <<'EOF'
(the code above)
EOF
$ cc -fPIC -shared -o mem.so mem.c
$ LD_PRELOAD=./mem.so ls
0x7ffc14931adc: malloc(5) = 0xb40010
0x7ffc1492c6b0: malloc(120) = 0xb40030
0x7ffc1497f61a: malloc(12) = 0xb40010
0x7ffc1492be38: malloc(776) = 0xb400b0
…

printf potrebbe chiamare malloc , motivo per cui annulliamo temporaneamente l'hook. Fai attenzione se agganci malloc in qualsiasi modo.

Altri suggerimenti

Puoi tracciare le chiamate su malloc / free con ltrace:

#include <stdlib.h>

int main (void)
{
  void *ptr = malloc(10);
  free(ptr);

  return 0;
}


$ g++ test.cpp -o test
$ ltrace -e malloc,free ./test
malloc(10)                                       = 0x804a008
free(0x804a008)                                  = <void>
+++ exited (status 0) +++

Per rintracciare nuove / eliminare chiamate senza ricompilare probabilmente dovrai usare qualcosa come LD_PRELOAD per sovrascrivere le chiamate con le tue versioni, questo è esattamente ciò che LeakTracer fa ciò che potrebbe fare quello che vuoi.

Questo articolo (scorri verso il basso) fornisce una descrizione molto chiara e concisa di come sovrascrivere gli operatori globali new e delete in C ++ (si noti che non fornisce un esempio per new [] , ma è simile nel concetto).

Per quanto riguarda l'override di malloc e free, poiché stai lavorando su Linux e con GCC, il metodo più semplice è usare malloc_hook e free_hook . Qui è un'ottima descrizione di come funzionano queste funzioni.

Non l'ho provato io stesso, ma sono abbastanza sicuro che funzionerebbe:

  • Poiché non si desidera ricompilare la libreria, è possibile che sia necessario ottenere una traccia dello stack per ottenere un output significativo (anziché solo "nuovo chiamato per 23 byte"). Ricordo di aver usato le funzioni per navigare nello stack, ma non riesco a trovarle in questo momento. Forse una chiamata a system () e pstack (1) può fare il trucco.

  • È possibile ridefinire l'operatore new ed delete e mettere questa nuova definizione davanti alla libreria std c ++. Ciò potrebbe non acquisire le chiamate dai contenitori e dai componenti standard utilizzati dalla libreria in questione. Ciò richiederebbe un ricollegamento.

  • L'utilizzo può utilizzare LD_PRELOAD per cambiare operatore nuovo ed eliminare dinamicamente. Ciò non richiederebbe un nuovo collegamento se l'applicazione è collegata dinamicamente.

Spero che questi suggerimenti siano d'aiuto, mi dispiace non avere una ricetta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top