Tenho o seguinte código:
#include <stdlib.h>
#include <stdio.h>
int main() {
void* a = malloc(10);
printf("%p\n", a);
}
Quando compilado e executado:
clang-19 -std=c23 -fsanitize=address -g -Weverything -o test_mem.exe test_mem.c
./test_mem.exe
0x502000000010
=================================================================
==212167==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 10 byte(s) in 1 object(s) allocated from:
#0 0x55f0442625cf in malloc (/home/xxx/xxx/xxx/test_mem.exe+0xcb5cf) (BuildId: fe83f3b1cd62d6171e5d431d34ee529cce48f18f)
#1 0x55f0442a2a68 in main /xxx/xxx/xxx/xxx/test_mem.c:8:11
#2 0x7fa09f96fd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: 10 byte(s) leaked in 1 allocation(s).
O vazamento de memória foi detectado. Ótimo!
Entretanto, se eu alterar o código para:
#include <stdio.h>
#include <stdlib.h>
void* a = nullptr;
int main() {
a = malloc(10);
printf("%p\n", a);
}
e compilar/executar:
clang-19 -std=c23 -fsanitize=address -g -Weverything -o test_mem.exe test_mem.c
... compiler complains about `int* a` not being static, fine...
./test_mem.exe
0x502000000010
Nenhum vazamento de memória é detectado. Fazer o int* a
static
não altera esse comportamento (o compilador apenas o relata como um aviso).
Tenho certeza de que há um "bom motivo" pelo qual o vazamento de memória não é relatado quando a variável é declarada globalmente, mas:
Por que isso acontece? Existe uma razão específica para esse comportamento? Poderia ser que quando uma variável é declarada no escopo global, sua memória é liberada automaticamente, mesmo quando alocada dinamicamente? Se esse for o caso, isso significa que liberar essa memória, como fazer um free(a), não é estritamente necessário?
Existe uma maneira de configurar o sanitizer ou compilador para detectar tais vazamentos de memória para variáveis globais? Alguns sinalizadores, talvez?
Um vazamento de memória ocorre quando todos os ponteiros para um bloco de memória alocada são perdidos antes que o tempo de vida desse bloco termine, ou seja, antes que o ponteiro seja passado para
free
.Se tal ponteiro for armazenado em uma variável global, ou mais precisamente, em uma variável no escopo do arquivo cujo tempo de vida é o de todo o programa, então esse ponteiro para a memória alocada nunca será perdido durante a vida útil do programa, portanto, não haverá vazamento de memória.
Ferramentas como o valgrind (que verifica o comportamento em tempo de execução) observarão algo assim, informando que a memória alocada "ainda está acessível", e não vazada.
A saída do valgrind para este código é a seguinte: