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 
calls_free_1(void * ptr)6 void calls_free_1 (void *ptr)
7 {
8   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
9 }
10 
test_1(void * ptr,int a,int b)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 
calls_free_2(void * ptr)89 void calls_free_2 (void *ptr)
90 {
91   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
92 }
93 
test_2(void * ptr,int a,int b)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 
called_by_test_3(void)196 void called_by_test_3 (void)
197 {
198 }
199 
test_3(void * ptr)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 "" } */
223