1 /* { dg-additional-options "-fanalyzer-call-summaries" } */
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 "2 processed enodes" } */
52 
53   if (n > 10)
54     free (ptr); /* { dg-bogus "not on the heap" } */
55 
56   return result; /* { dg-bogus "leak" } */
57 }
58 
59 /* A simpler version of the above.  */
60 
test_repeated_predicate_2(int n)61 int test_repeated_predicate_2 (int n)
62 {
63   int buf[10];
64   int *ptr;
65   int result;
66 
67   if (n > 10)
68     ptr = (int *)malloc (sizeof (int) * n);
69   else
70     ptr = buf;
71 
72   __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
73 
74   result = do_stuff_2 (ptr, n);
75 
76   __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
77 
78   if (n > 10)
79     free (ptr); /* { dg-bogus "not on the heap" } */
80 
81   return result; /* { dg-bogus "leak" } */
82 }
83 
84 /* A predicate that sets a flag for the 2nd test.  */
85 
test_explicit_flag(int n)86 int test_explicit_flag (int n)
87 {
88   int buf[10];
89   int *ptr;
90   int result;
91   int need_to_free = 0;
92 
93   if (n > 10)
94     {
95       ptr = (int *)malloc (sizeof (int) * n);
96       need_to_free = 1;
97     }
98   else
99     ptr = buf;
100 
101   __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
102 
103   result = do_stuff (ptr, n);
104 
105   __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
106 
107   if (need_to_free)
108     free (ptr); /* { dg-bogus "not on the heap" } */
109 
110   return result; /* { dg-bogus "leak" } */
111 }
112 
113 /* Pointer comparison.  */
114 
test_pointer_comparison(int n)115 int test_pointer_comparison (int n)
116 {
117   int buf[10];
118   int *ptr;
119   int result;
120 
121   if (n > 10)
122     ptr = (int *)malloc (sizeof (int) * n);
123   else
124     ptr = buf;
125 
126   __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
127 
128   result = do_stuff (ptr, n);
129 
130   __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
131 
132   if (ptr != buf)
133     free (ptr); /* { dg-bogus "not on the heap" } */
134 
135   return result; /* { dg-bogus "leak" } */
136 }
137 
138 /* Set a flag based on a conditional, then use it, then reuse the
139    conditional.  */
140 
test_initial_flag(int n)141 int test_initial_flag (int n)
142 {
143   int buf[10];
144   int *ptr;
145   int result;
146   int on_heap = 0;
147 
148   if (n > 10)
149     on_heap = 1;
150   else
151     on_heap = 0;
152 
153   /* Due to state-merging, we lose the relationship between 'n > 10'
154      and 'on_heap' here; we have to rely on feasibility-checking
155      in the diagnostic_manager to reject the false warnings.  */
156   __analyzer_dump_exploded_nodes (0); /* { dg-warning "1 processed enode" } */
157 
158   if (on_heap)
159     ptr = (int *)malloc (sizeof (int) * n);
160   else
161     ptr = buf;
162 
163   __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
164 
165   result = do_stuff (ptr, n);
166 
167   __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
168 
169   if (n > 10)
170     free (ptr); /* { dg-bogus "not on the heap" } */
171 
172   return result; /* { dg-bogus "leak" } */
173 }
174