1 /* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-verbosity=0" } */
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': event 1
27     |
28     |   NN |     calls_free_1 (ptr);
29     |      |     ^~~~~~~~~~~~~~~~~~
30     |      |     |
31     |      |     (1) calling 'calls_free_1' from 'test_1'
32     |
33     +--> 'calls_free_1': event 2
34            |
35            |   NN |   free (ptr);
36            |      |   ^~~~~~~~~~
37            |      |   |
38            |      |   (2) first 'free' here
39            |
40     <------+
41     |
42   'test_1': events 3-4
43     |
44     |   NN |     calls_free_1 (ptr);
45     |      |     ^~~~~~~~~~~~~~~~~~
46     |      |     |
47     |      |     (3) returning to 'test_1' from 'calls_free_1'
48     |......
49     |   NN |     calls_free_1 (ptr);
50     |      |     ~~~~~~~~~~~~~~~~~~
51     |      |     |
52     |      |     (4) passing freed pointer 'ptr' in call to 'calls_free_1' from 'test_1'
53     |
54     +--> 'calls_free_1': event 5
55            |
56            |   NN |   free (ptr);
57            |      |   ^~~~~~~~~~
58            |      |   |
59            |      |   (5) second 'free' here; first 'free' was at (2)
60            |
61   { dg-end-multiline-output "" } */
62 
calls_free_2(void * ptr)63 void calls_free_2 (void *ptr)
64 {
65   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
66 }
67 
test_2(void * ptr,int a,int b)68 void test_2 (void *ptr, int a, int b)
69 {
70   switch (a)
71     {
72     default:
73       break;
74     case 1:
75       break;
76     case 3:
77       calls_free_2 (ptr);
78       break;
79     }
80 
81   switch (b)
82     {
83     default:
84       calls_free_2 (ptr);
85       break;
86     case 1:
87       break;
88     case 42:
89       break;
90     }
91 }
92 
93 /* { dg-begin-multiline-output "" }
94    NN |   free (ptr);
95       |   ^~~~~~~~~~
96   'test_2': event 1
97     |
98     |   NN |       calls_free_2 (ptr);
99     |      |       ^~~~~~~~~~~~~~~~~~
100     |      |       |
101     |      |       (1) calling 'calls_free_2' from 'test_2'
102     |
103     +--> 'calls_free_2': event 2
104            |
105            |   NN |   free (ptr);
106            |      |   ^~~~~~~~~~
107            |      |   |
108            |      |   (2) first 'free' here
109            |
110     <------+
111     |
112   'test_2': events 3-4
113     |
114     |   NN |       calls_free_2 (ptr);
115     |      |       ^~~~~~~~~~~~~~~~~~
116     |      |       |
117     |      |       (3) returning to 'test_2' from 'calls_free_2'
118     |......
119     |   NN |       calls_free_2 (ptr);
120     |      |       ~~~~~~~~~~~~~~~~~~
121     |      |       |
122     |      |       (4) passing freed pointer 'ptr' in call to 'calls_free_2' from 'test_2'
123     |
124     +--> 'calls_free_2': event 5
125            |
126            |   NN |   free (ptr);
127            |      |   ^~~~~~~~~~
128            |      |   |
129            |      |   (5) second 'free' here; first 'free' was at (2)
130            |
131   { dg-end-multiline-output "" } */
132 
133 // TODO: range cases
134 
135 /* The call/return to this function shouldn't appear in the path.  */
136 
called_by_test_3(void)137 void called_by_test_3 (void)
138 {
139 }
140 
test_3(void * ptr)141 void test_3 (void *ptr)
142 {
143   free (ptr);
144   called_by_test_3 ();
145   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
146 }
147 
148 /* { dg-begin-multiline-output "" }
149    NN |   free (ptr);
150       |   ^~~~~~~~~~
151   'test_3': events 1-2
152     |
153     |   NN |   free (ptr);
154     |      |   ^~~~~~~~~~
155     |      |   |
156     |      |   (1) first 'free' here
157     |   NN |   called_by_test_3 ();
158     |   NN |   free (ptr);
159     |      |   ~~~~~~~~~~
160     |      |   |
161     |      |   (2) second 'free' here; first 'free' was at (1)
162     |
163   { dg-end-multiline-output "" } */
164