https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93695
Bug ID: 93695 Summary: Allocation and freeing memory for array members in loops is not handled properly by the analyzer Product: gcc Version: 10.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: analyzer Assignee: dmalcolm at gcc dot gnu.org Reporter: asolokha at gmx dot com Target Milestone: --- gcc-10.0.1-alpha20200209 snapshot (g:8686c4d84517b54cf3dfe98fca3a814b7d606502) fails to notice that in the following testcase memory in fact gets allocated (and then freed) for different array members, so there are neither leaks nor double-'free's there. It can be easily spotted when using the analyzer on various real-world codebases, but I fail to see the corresponding item in the Limitations section, hence the report. Control flow in real-world code is more complex, of course, but a testcase can be reduced to something as trivial as the one posted above. #define NELEMS 2 #define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0])) void f (void) { int *p[NELEMS]; int i; for (i = 0; i < ARRAY_SIZE (p); ++i) p[i] = __builtin_malloc (sizeof (i)); for (i = 0; i < ARRAY_SIZE (p); ++i) __builtin_free (p [i]); } % gcc-10.0.1 -O1 -fanalyzer -c n0hgjbog.c n0hgjbog.c: In function 'f': n0hgjbog.c:10:17: warning: leak of '<unknown>' [CWE-401] [-Wanalyzer-malloc-leak] 10 | for (i = 0; i < ARRAY_SIZE (p); ++i) | ^ 'f': events 1-9 | | 10 | for (i = 0; i < ARRAY_SIZE (p); ++i) | | ^~~ | | | | | (1) following 'true' branch... | | (4) following 'true' branch... | | (6) following 'true' branch... | | (9) following 'false' branch... | 11 | p[i] = __builtin_malloc (sizeof (i)); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (2) ...to here | | (3) allocated here | | (5) ...to here | | (7) ...to here | | (8) allocated here | 'f': event 10 | |cc1: | (10): ...to here | 'f': events 11-14 | | 13 | for (i = 0; i < ARRAY_SIZE (p); ++i) | | ^~~ | | | | | (11) following 'true' branch... | | (13) following 'false' branch... | 14 | __builtin_free (p [i]); | | ~~~~~ | | | | | (12) ...to here | 15 | } | | ~ | | | | | (14) ...to here | 'f': event 15 | | 10 | for (i = 0; i < ARRAY_SIZE (p); ++i) | | ^ | | | | | (15) '<unknown>' leaks here; was allocated at (8) | n0hgjbog.c:14:5: warning: double-'free' of '<unknown>' [CWE-415] [-Wanalyzer-double-free] 14 | __builtin_free (p [i]); | ^~~~~~~~~~~~~~~~~~~~~~ 'f': events 1-3 | | 10 | for (i = 0; i < ARRAY_SIZE (p); ++i) | | ^~~ | | | | | (1) following 'true' branch... | | (3) following 'false' branch... | 11 | p[i] = __builtin_malloc (sizeof (i)); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (2) ...to here | 'f': event 4 | |cc1: | (4): ...to here | 'f': events 5-13 | | 13 | for (i = 0; i < ARRAY_SIZE (p); ++i) | | ^~~ | | | | | (5) following 'true' branch... | | (8) following 'true' branch... | | (11) following 'true' branch... | 14 | __builtin_free (p [i]); | | ~~~~~~~~~~~~~~~~~~~~~~ | | | | | | | (6) ...to here | | | (7) first 'free' here | | | (9) ...to here | | | (10) first 'free' here | | | (12) ...to here | | (13) second 'free' here; first 'free' was at (10) | n0hgjbog.c:14:5: note: 1 duplicate 14 | __builtin_free (p [i]);