#include <stdio.h>
#include <stdlib.h>
int main()
{
int ***new = malloc(sizeof(int **));
*new = malloc(sizeof(int *));
**new = malloc(sizeof(int));
***new = 2137;
printf("%i\n", ***new);
free(**new);
free(*new);
free(new);
return EXIT_FAILURE;
}
This code, when compiled using command gcc -Wall -Wextra -fanalyzer -g -O0 -fsanitize=address,undefined -o test2 test2.c
produces output:
test2.c: In function ‘main’:
test2.c:10:7: warning: leak of ‘malloc(4)’ [CWE-401] [-Wanalyzer-malloc-leak]
10 | ***new = 2137;
| ^~~~
‘main’: events 1-2
|
| 8 | **new = malloc(sizeof(int));
| | ^~~~~~~~~~~~~~~~~~~
| | |
| | (1) allocated here
| 9 |
| 10 | ***new = 2137;
| | ~~~~
| | |
| | (2) ‘malloc(4)’ leaks here; was allocated at (1)
|
I have narrowed down my code do something as simple as this, but still cannot find the problem. I know I am not checking malloc errors, doing so does not help, I have removed them to improve clarity. How do I fix this?
This is a bug in the analyzer. If we look closely at the output:
|
| 8 | **new = (int*) malloc(sizeof(int));
| | ^~~~~~~~~~~~~~~~~~~
| | |
| | (1) allocated here
| 9 |
| 10 | ***new = 2137;
| | ~~~~
| | |
| | (2) ‘malloc(4)’ leaks here; was allocated at (1)
We can see that the assigned pointer it's checking is not the same one where the leak happens. Specifically, it incorrectly thinks that an assignment to ***new
overwrites as assignment to **new
.
To verify, we can run the code through valgrind, which shows there is no memory leak:
==23502== Memcheck, a memory error detector
==23502== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==23502== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==23502== Command: ./x1
==23502==
2137
==23502==
==23502== HEAP SUMMARY:
==23502== in use at exit: 0 bytes in 0 blocks
==23502== total heap usage: 3 allocs, 3 frees, 20 bytes allocated
==23502==
==23502== All heap blocks were freed -- no leaks are possible
==23502==
==23502== For lists of detected and suppressed errors, rerun with: -s
==23502== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
When compiling with versions 10 and 11 of gcc with these options, no warnings appear. The warning you show start with version 12 of gcc.