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]);

Reply via email to