Pergunta

Com o Linux/GCC/C ++, eu gostaria de gravar algo para Stderr sempre que o Malloc/Free/New/Delete for chamado. Estou tentando entender as alocações de memória de uma biblioteca e, portanto, gostaria de gerar essa saída enquanto estiver executando testes de unidade. Eu uso Valgrind para detecção de vazamento de MEM, mas não consigo encontrar uma opção para fazê -lo apenas alocações de log.

Alguma ideia? Estou procurando a solução mais simples possível. Recomitar a biblioteca não é uma opção.

Foi útil?

Solução

malloc_hook(3) permite que você interponha globalmente o seu próprio malloc função. (Há __realloc_hook __free_hook etc. também, eu apenas os deixei de fora por simplicidade.)

#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'
(o código acima)
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 pode ligar malloc, é por isso que desfazemos o gancho temporariamente. Tenha cuidado com isso se quando você conectar malloc de qualquer maneira.

Outras dicas

Você pode rastrear chamadas para Malloc/Free com 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) +++

Para rastrear chamadas novas/excluir sem recompilar, você provavelmente precisará usar algo como LD_PRELOAD para substituir as chamadas com suas próprias versões, é exatamente isso Vazamento faz o que pode fazer o que você deseja.

Este artigo (role para baixo até o fundo) fornece uma descrição muito clara e concisa de como substituir o global new e delete operadores em C ++ (observe que ele não fornece um exemplo para new[], mas é semelhante em conceito).

Quanto a substituir o Malloc e gratuito, já que você está trabalhando no Linux e com o GCC, o método mais fácil é usar malloc_hook e free_hook. Aqui é uma descrição muito boa de como essas funções funcionam.

Eu não testei isso sozinho, mas tenho certeza de que isso funcionaria:

  • Como você não deseja recompensar a biblioteca, fornecer saída significativa (vs. apenas "novo chamado para 23 bytes") pode exigir um rastreamento de pilha. Lembro -me de usar funções para navegar na pilha, mas não consigo encontrá -las agora. Talvez uma chamada para System () e Pstack (1) possam fazer o truque.

  • Você pode redefinir o operador novo e excluir e colocar essa nova definição à frente da biblioteca STD C ++. Isso não pode capturar as chamadas de contêineres e componentes padrão que a biblioteca em questão está usando. Isso exigiria uma renúncia.

  • O uso pode usar LD_PRELOAD para alterar o operador novo e excluir dinamicamente. Isso não exigiria um re-vincular se o seu aplicativo estiver vinculado dinamicamente.

Espero que esses ponteiros ajudem, lamento não ter uma receita.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top