1 /* Tests for data model handling of unknown fns. */
2
3 #include <stddef.h>
4 #include "analyzer-decls.h"
5
6 void unknown_fn (void *);
7
8 void test_1 (void)
9 {
10 int i;
11
12 i = 42;
13 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
14
15 unknown_fn (NULL);
16 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
17
18 unknown_fn (&i);
19 __analyzer_eval (i == 42); /* { dg-warning "UNKNOWN" } */
20
21 i = 17;
22 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
23
24 /* Even though we're not passing &i to unknown_fn, it escaped
25 above, so unknown_fn could write to it. */
26 unknown_fn (NULL);
27 __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */
28 }
29
30 /* As test_1, but with an unknown fn_ptr. */
31
32 void test_1a (void (*fn_ptr) (void *))
33 {
34 int i;
35
36 i = 42;
37 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
38
39 fn_ptr (NULL);
40 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
41
42 fn_ptr (&i);
43 __analyzer_eval (i == 42); /* { dg-warning "UNKNOWN" } */
44
45 i = 17;
46 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
47
48 /* Even though we're not passing &i to unknown_fn, it escaped
49 above, so fn_ptr (NULL) could write to it. */
50 fn_ptr (NULL);
51 __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */
52 }
53
54 int *global_for_test_2;
55
56 void test_2 (void)
57 {
58 int i;
59
60 i = 42;
61 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
62
63 global_for_test_2 = &i;
64 unknown_fn (NULL);
65 __analyzer_eval (i == 42); /* { dg-warning "UNKNOWN" } */
66
67 global_for_test_2 = NULL;
68
69 i = 17;
70 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
71
72 /* Even though the global no longer points to i, it escaped
73 above, so unknown_fn could write to it. */
74 unknown_fn (NULL);
75 __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */
76 }
77
78 struct used_by_test_3
79 {
80 int *int_ptr;
81 };
82
83 void test_3 (void)
84 {
85 int i;
86
87 struct used_by_test_3 s;
88 s.int_ptr = &i;
89
90 i = 42;
91 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
92
93 unknown_fn (NULL);
94 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
95 __analyzer_eval (s.int_ptr == &i); /* { dg-warning "TRUE" } */
96
97 /* i should escape here. */
98 unknown_fn (&s);
99 __analyzer_eval (i == 42); /* { dg-warning "UNKNOWN" } */
100 __analyzer_eval (s.int_ptr == &i); /* { dg-warning "UNKNOWN" } */
101
102 s.int_ptr = NULL;
103 __analyzer_eval (s.int_ptr == NULL); /* { dg-warning "TRUE" } */
104
105 i = 17;
106 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
107
108 /* Even though nothing we know about points to i, it escaped
109 above, so unknown_fn could write to it. */
110 unknown_fn (NULL);
111 __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */
112 }
113
114 struct used_by_test_4
115 {
116 int *int_ptr;
117 };
118
119 void test_4 (struct used_by_test_4 *st4_ptr)
120 {
121 /* Something unknown called "test_4", and hence *st4_ptr has
122 effectively already escaped. */
123
124 int i = 42;
125 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
126
127 unknown_fn (NULL);
128 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
129
130 /* Given that *st4_ptr has effectively already escaped, calling
131 an unknown fn should invalidate our knowledge of i". */
132 st4_ptr->int_ptr = &i;
133 unknown_fn (NULL);
134 __analyzer_eval (i == 42); /* { dg-warning "UNKNOWN" } */
135
136 /* ...and "&i" should now be treated as having escaped. */
137 i = 17;
138 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
139 st4_ptr->int_ptr = NULL;
140 unknown_fn (NULL);
141 __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */
142 }
143
144 static void __attribute__((noinline))
145 known_fn (void *ptr)
146 {
147 /* Empty. */
148 }
149
150 void test_5 (void)
151 {
152 int i;
153
154 i = 42;
155 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
156
157 known_fn (&i);
158 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
159
160 i = 17;
161 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
162
163 /* Ensure that we don't consider &i to have escaped. */
164 unknown_fn (NULL);
165 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
166 }
167
168 extern int __attribute__ ((__pure__))
169 unknown_pure_fn (void *);
170
171 void test_6 (void)
172 {
173 int i;
174
175 i = 42;
176 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
177
178 unknown_pure_fn (&i);
179 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
180
181 i = 17;
182 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
183
184 /* Ensure that we don't consider &i to have escaped. */
185 unknown_fn (NULL);
186 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
187 }
188
189 extern void unknown_const_fn (const void *);
190
191 void test_7 (void)
192 {
193 int i;
194
195 i = 42;
196 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
197
198 /* &i is passed as a const void *, so i shouldn't be clobbered by
199 the call. */
200 unknown_const_fn (&i);
201 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
202
203 i = 17;
204 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
205
206 /* Ensure that we don't consider &i to have escaped. */
207 unknown_fn (NULL);
208 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
209 }
210
211 struct used_by_test_8
212 {
213 int *int_ptr;
214 };
215
216 void test_8 (void)
217 {
218 int i;
219
220 i = 42;
221 __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */
222
223 struct used_by_test_8 st8;
224 st8.int_ptr = &i;
225
226 /* Although unknown_const_fn takes a const void *, the
227 int_ptr is a non-const int *, and so &i should be considered
228 writable. */
229 unknown_const_fn (&st8);
230 __analyzer_eval (i == 42); /* { dg-warning "UNKNOWN" } */
231
232 i = 17;
233 __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */
234
235 /* &i should be considered to have escaped. */
236 unknown_fn (NULL);
237 __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */
238 }