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))
do_stuff(int * p,int n)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;
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))
do_stuff_2(int * p,int n)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 
test_repeated_predicate_1(int n)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 "3 processed enodes" } */
52   // FIXME: why 3 here?
53   __analyzer_dump_exploded_nodes (0); /* { dg-warning "3 processed enodes" } */
54   // FIXME: why 3 here?
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 
test_repeated_predicate_2(int n)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 
test_explicit_flag(int n)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 "3 processed enodes" } */
109   // FIXME: why 3 here?
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 
test_pointer_comparison(int n)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 "3 processed enodes" } */
135   // FIXME: why 3 here?
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 
test_initial_flag(int n)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 "5 processed enodes" } */
173   // FIXME: why 5 here?
174 
175   if (n > 10)
176     free (ptr); /* { dg-bogus "not on the heap" } */
177 
178   return result; /* { dg-bogus "leak" } */
179 }
180