1  /* { dg-additional-options "-fno-analyzer-call-summaries -fanalyzer-transitivity" } */
       2  
       3  #include <stdlib.h>
       4  #include "analyzer-decls.h"
       5  
       6  extern int foo (int);
       7  
       8  static int __attribute__((noinline))
       9  do_stuff (int *p, int n)
      10  {
      11    int sum = 0;
      12    int i;
      13    for (i = 0; i < n; i++)
      14      p[i] = i; /* { dg-warning "dereference of possibly-NULL 'p'" } */
      15    for (i = 0; i < n; i++)
      16      sum += foo (p[i]); /* { dg-bogus "uninitialized" } */
      17    return sum;
      18  }
      19  
      20  static int __attribute__((noinline))
      21  do_stuff_2 (int *p, int n)
      22  {
      23    return 0;
      24  }
      25  
      26  /* Various examples of functions that use either a malloc buffer
      27     or a local buffer, do something, then conditionally free the
      28     buffer, tracking whether "free" is necessary in various
      29     ways.
      30  
      31     In each case, there ought to be only two paths through the function,
      32     not four.  */
      33  
      34  /* Repeated (n > 10) predicate.  */
      35  
      36  int test_repeated_predicate_1 (int n)
      37  {
      38    int buf[10];
      39    int *ptr;
      40    int result;
      41  
      42    if (n > 10)
      43      ptr = (int *)malloc (sizeof (int) * n);
      44    else
      45      ptr = buf;
      46  
      47    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
      48  
      49    result = do_stuff (ptr, n);
      50  
      51    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
      52  
      53    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
      54  
      55  
      56    if (n > 10)
      57      free (ptr); /* { dg-bogus "not on the heap" } */
      58  
      59    return result; /* { dg-bogus "leak" } */
      60  }
      61  
      62  /* A simpler version of the above.  */
      63  
      64  int test_repeated_predicate_2 (int n)
      65  {
      66    int buf[10];
      67    int *ptr;
      68    int result;
      69  
      70    if (n > 10)
      71      ptr = (int *)malloc (sizeof (int) * n);
      72    else
      73      ptr = buf;
      74  
      75    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
      76  
      77    result = do_stuff_2 (ptr, n);
      78  
      79    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
      80  
      81    if (n > 10)
      82      free (ptr); /* { dg-bogus "not on the heap" } */
      83  
      84    return result; /* { dg-bogus "leak" } */
      85  }
      86  
      87  /* A predicate that sets a flag for the 2nd test.  */
      88  
      89  int test_explicit_flag (int n)
      90  {
      91    int buf[10];
      92    int *ptr;
      93    int result;
      94    int need_to_free = 0;
      95  
      96    if (n > 10)
      97      {
      98        ptr = (int *)malloc (sizeof (int) * n);
      99        need_to_free = 1;
     100      }
     101    else
     102      ptr = buf;
     103  
     104    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
     105  
     106    result = do_stuff (ptr, n);
     107  
     108    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
     109  
     110  
     111    if (need_to_free)
     112      free (ptr); /* { dg-bogus "not on the heap" } */
     113  
     114    return result; /* { dg-bogus "leak" } */
     115  }
     116  
     117  /* Pointer comparison.  */
     118  
     119  int test_pointer_comparison (int n)
     120  {
     121    int buf[10];
     122    int *ptr;
     123    int result;
     124  
     125    if (n > 10)
     126      ptr = (int *)malloc (sizeof (int) * n);
     127    else
     128      ptr = buf;
     129  
     130    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
     131  
     132    result = do_stuff (ptr, n);
     133  
     134    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
     135  
     136  
     137    if (ptr != buf)
     138      free (ptr); /* { dg-bogus "not on the heap" } */
     139  
     140    return result; /* { dg-bogus "leak" } */
     141  }
     142  
     143  /* Set a flag based on a conditional, then use it, then reuse the
     144     conditional.  */
     145  
     146  int test_initial_flag (int n)
     147  {
     148    int buf[10];
     149    int *ptr;
     150    int result;
     151    int on_heap = 0;
     152  
     153    if (n > 10)
     154      on_heap = 1;
     155    else
     156      on_heap = 0;
     157  
     158    /* Due to state-merging, we lose the relationship between 'n > 10'
     159       and 'on_heap' here; we have to rely on feasibility-checking
     160       in the diagnostic_manager to reject the false warnings.  */
     161    __analyzer_dump_exploded_nodes (0); /* { dg-warning "1 processed enode" } */
     162  
     163    if (on_heap)
     164      ptr = (int *)malloc (sizeof (int) * n);
     165    else
     166      ptr = buf;
     167  
     168    __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
     169  
     170    result = do_stuff (ptr, n);
     171  
     172    __analyzer_dump_exploded_nodes (0); /* { dg-warning "3 processed enodes" } */
     173    // FIXME: why 3 here?
     174  
     175    if (n > 10)
     176      free (ptr); /* { dg-bogus "not on the heap" } */
     177  
     178    return result; /* { dg-bogus "leak" } */
     179  }