1  /* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-verbosity=3" } */
       2  /* { dg-enable-nn-line-numbers "" } */
       3  
       4  #include <stdlib.h>
       5  
       6  void calls_free_1 (void *ptr)
       7  {
       8    free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
       9  }
      10  
      11  void test_1 (void *ptr, int a, int b)
      12  {
      13    if (a)
      14      calls_free_1 (ptr);
      15  
      16    if (b)
      17      {
      18      }
      19    else
      20      calls_free_1 (ptr);
      21  }
      22  
      23  /* { dg-begin-multiline-output "" }
      24     NN |   free (ptr);
      25        |   ^~~~~~~~~~
      26    'test_1': events 1-4
      27      |
      28      |   NN | void test_1 (void *ptr, int a, int b)
      29      |      |      ^~~~~~
      30      |      |      |
      31      |      |      (1) entry to 'test_1'
      32      |   NN | {
      33      |   NN |   if (a)
      34      |      |      ~
      35      |      |      |
      36      |      |      (2) following 'true' branch (when 'a != 0')...
      37      |   NN |     calls_free_1 (ptr);
      38      |      |     ~~~~~~~~~~~~~~~~~~
      39      |      |     |
      40      |      |     (3) ...to here
      41      |      |     (4) calling 'calls_free_1' from 'test_1'
      42      |
      43      +--> 'calls_free_1': events 5-6
      44             |
      45             |   NN | void calls_free_1 (void *ptr)
      46             |      |      ^~~~~~~~~~~~
      47             |      |      |
      48             |      |      (5) entry to 'calls_free_1'
      49             |   NN | {
      50             |   NN |   free (ptr);
      51             |      |   ~~~~~~~~~~
      52             |      |   |
      53             |      |   (6) first 'free' here
      54             |
      55      <------+
      56      |
      57    'test_1': events 7-10
      58      |
      59      |   NN |     calls_free_1 (ptr);
      60      |      |     ^~~~~~~~~~~~~~~~~~
      61      |      |     |
      62      |      |     (7) returning to 'test_1' from 'calls_free_1'
      63      |   NN | 
      64      |   NN |   if (b)
      65      |      |      ~
      66      |      |      |
      67      |      |      (8) following 'false' branch (when 'b == 0')...
      68      |......
      69      |   NN |     calls_free_1 (ptr);
      70      |      |     ~~~~~~~~~~~~~~~~~~
      71      |      |     |
      72      |      |     (9) ...to here
      73      |      |     (10) passing freed pointer 'ptr' in call to 'calls_free_1' from 'test_1'
      74      |
      75      +--> 'calls_free_1': events 11-12
      76             |
      77             |   NN | void calls_free_1 (void *ptr)
      78             |      |      ^~~~~~~~~~~~
      79             |      |      |
      80             |      |      (11) entry to 'calls_free_1'
      81             |   NN | {
      82             |   NN |   free (ptr);
      83             |      |   ~~~~~~~~~~
      84             |      |   |
      85             |      |   (12) second 'free' here; first 'free' was at (6)
      86             |
      87    { dg-end-multiline-output "" } */
      88  
      89  void calls_free_2 (void *ptr)
      90  {
      91    free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
      92  }
      93  
      94  void test_2 (void *ptr, int a, int b)
      95  {
      96    switch (a)
      97      {
      98      default:
      99        break;
     100      case 1:
     101        break;
     102      case 3:
     103        calls_free_2 (ptr);
     104        break;
     105      }
     106  
     107    switch (b)
     108      {
     109      default:
     110        calls_free_2 (ptr);
     111        break;
     112      case 1:
     113        break;
     114      case 42:
     115        break;
     116      }
     117  }
     118  
     119  /* { dg-begin-multiline-output "" }
     120     NN |   free (ptr);
     121        |   ^~~~~~~~~~
     122    'test_2': events 1-4
     123      |
     124      |   NN | void test_2 (void *ptr, int a, int b)
     125      |      |      ^~~~~~
     126      |      |      |
     127      |      |      (1) entry to 'test_2'
     128      |   NN | {
     129      |   NN |   switch (a)
     130      |      |   ~~~~~~
     131      |      |   |
     132      |      |   (2) following 'case 3:' branch...
     133      |......
     134      |   NN |     case 3:
     135      |      |     ~~~~
     136      |      |     |
     137      |      |     (3) ...to here
     138      |   NN |       calls_free_2 (ptr);
     139      |      |       ~~~~~~~~~~~~~~~~~~
     140      |      |       |
     141      |      |       (4) calling 'calls_free_2' from 'test_2'
     142      |
     143      +--> 'calls_free_2': events 5-6
     144             |
     145             |   NN | void calls_free_2 (void *ptr)
     146             |      |      ^~~~~~~~~~~~
     147             |      |      |
     148             |      |      (5) entry to 'calls_free_2'
     149             |   NN | {
     150             |   NN |   free (ptr);
     151             |      |   ~~~~~~~~~~
     152             |      |   |
     153             |      |   (6) first 'free' here
     154             |
     155      <------+
     156      |
     157    'test_2': events 7-10
     158      |
     159      |   NN |       calls_free_2 (ptr);
     160      |      |       ^~~~~~~~~~~~~~~~~~
     161      |      |       |
     162      |      |       (7) returning to 'test_2' from 'calls_free_2'
     163      |......
     164      |   NN |   switch (b)
     165      |      |   ~~~~~~
     166      |      |   |
     167      |      |   (8) following 'default:' branch...
     168      |   NN |     {
     169      |   NN |     default:
     170      |      |     ~~~~~~~
     171      |      |     |
     172      |      |     (9) ...to here
     173      |   NN |       calls_free_2 (ptr);
     174      |      |       ~~~~~~~~~~~~~~~~~~
     175      |      |       |
     176      |      |       (10) passing freed pointer 'ptr' in call to 'calls_free_2' from 'test_2'
     177      |
     178      +--> 'calls_free_2': events 11-12
     179             |
     180             |   NN | void calls_free_2 (void *ptr)
     181             |      |      ^~~~~~~~~~~~
     182             |      |      |
     183             |      |      (11) entry to 'calls_free_2'
     184             |   NN | {
     185             |   NN |   free (ptr);
     186             |      |   ~~~~~~~~~~
     187             |      |   |
     188             |      |   (12) second 'free' here; first 'free' was at (6)
     189             |
     190    { dg-end-multiline-output "" } */
     191  
     192  // TODO: range cases
     193  
     194  /* The call/return to this function shouldn't appear in the path.  */
     195  
     196  void called_by_test_3 (void)
     197  {
     198  }
     199  
     200  void test_3 (void *ptr)
     201  {
     202    free (ptr);
     203    called_by_test_3 ();
     204    free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
     205  }
     206  
     207  /* { dg-begin-multiline-output "" }
     208     NN |   free (ptr);
     209        |   ^~~~~~~~~~
     210    'test_3': events 1-2
     211      |
     212      |   NN |   free (ptr);
     213      |      |   ^~~~~~~~~~
     214      |      |   |
     215      |      |   (1) first 'free' here
     216      |   NN |   called_by_test_3 ();
     217      |   NN |   free (ptr);
     218      |      |   ~~~~~~~~~~
     219      |      |   |
     220      |      |   (2) second 'free' here; first 'free' was at (1)
     221      |
     222    { dg-end-multiline-output "" } */