1 /* As per stdarg-1.c, but using the sysv_abi versions of the builtins. */
2
3 /* { dg-additional-options "-fno-analyzer-suppress-followups" } */
4 /* { dg-do compile { target { x86_64-*-* && lp64 } } } */
5
6 #include "analyzer-decls.h"
7
8 /* Unpacking a va_list. */
9
10 static void __attribute__((noinline))
11 __analyzer_called_by_test_1 (int placeholder, ...)
12 {
13 const char *s;
14 int i;
15 char c;
16
17 __builtin_sysv_va_list ap;
18 __builtin_sysv_va_start (ap, placeholder);
19
20 s = __builtin_va_arg (ap, char *);
21 __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
22
23 i = __builtin_va_arg (ap, int);
24 __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
25
26 c = (char)__builtin_va_arg (ap, int);
27 __analyzer_eval (c == '@'); /* { dg-warning "TRUE" } */
28
29 __builtin_sysv_va_end (ap);
30 }
31
32 void test_1 (void)
33 {
34 __analyzer_called_by_test_1 (42, "foo", 1066, '@');
35 }
36
37 /* Unpacking a va_list passed from an intermediate function. */
38
39 static void __attribute__((noinline))
40 __analyzer_test_2_inner (__builtin_sysv_va_list ap)
41 {
42 const char *s;
43 int i;
44 char c;
45
46 s = __builtin_va_arg (ap, char *);
47 __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
48
49 i = __builtin_va_arg (ap, int);
50 __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
51
52 c = (char)__builtin_va_arg (ap, int);
53 __analyzer_eval (c == '@'); /* { dg-warning "TRUE" } */
54 }
55
56 static void __attribute__((noinline))
57 __analyzer_test_2_middle (int placeholder, ...)
58 {
59 __builtin_sysv_va_list ap;
60 __builtin_sysv_va_start (ap, placeholder);
61 __analyzer_test_2_inner (ap);
62 __builtin_sysv_va_end (ap);
63 }
64
65 void test_2 (void)
66 {
67 __analyzer_test_2_middle (42, "foo", 1066, '@');
68 }
69
70 /* Not enough args. */
71
72 static void __attribute__((noinline))
73 __analyzer_called_by_test_not_enough_args (int placeholder, ...)
74 {
75 const char *s;
76 int i;
77
78 __builtin_sysv_va_list ap;
79 __builtin_sysv_va_start (ap, placeholder);
80
81 s = __builtin_va_arg (ap, char *);
82 __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
83
84 i = __builtin_va_arg (ap, int); /* { dg-warning "'ap' has no more arguments \\(1 consumed\\) \\\[CWE-685\\\]" } */
85
86 __builtin_sysv_va_end (ap);
87 }
88
89 void test_not_enough_args (void)
90 {
91 __analyzer_called_by_test_not_enough_args (42, "foo");
92 }
93
94 /* Not enough args, with an intermediate function. */
95
96 static void __attribute__((noinline))
97 __analyzer_test_not_enough_args_2_inner (__builtin_sysv_va_list ap)
98 {
99 const char *s;
100 int i;
101
102 s = __builtin_va_arg (ap, char *);
103 __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
104
105 i = __builtin_va_arg (ap, int); /* { dg-warning "'ap' has no more arguments \\(1 consumed\\)" } */
106 }
107
108 static void __attribute__((noinline))
109 __analyzer_test_not_enough_args_2_middle (int placeholder, ...)
110 {
111 __builtin_sysv_va_list ap;
112 __builtin_sysv_va_start (ap, placeholder);
113 __analyzer_test_not_enough_args_2_inner (ap);
114 __builtin_sysv_va_end (ap);
115 }
116
117 void test_not_enough_args_2 (void)
118 {
119 __analyzer_test_not_enough_args_2_middle (42, "foo");
120 }
121
122 /* Excess args (not a problem). */
123
124 static void __attribute__((noinline))
125 __analyzer_called_by_test_excess_args (int placeholder, ...)
126 {
127 const char *s;
128
129 __builtin_sysv_va_list ap;
130 __builtin_sysv_va_start (ap, placeholder);
131
132 s = __builtin_va_arg (ap, char *);
133 __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
134
135 __builtin_sysv_va_end (ap);
136 }
137
138 void test_excess_args (void)
139 {
140 __analyzer_called_by_test_excess_args (42, "foo", "bar");
141 }
142
143 /* Missing va_start. */
144
145 void test_missing_va_start (int placeholder, ...)
146 {
147 __builtin_sysv_va_list ap; /* { dg-message "region created on stack here" } */
148 int i = __builtin_va_arg (ap, int); /* { dg-warning "use of uninitialized value 'ap'" } */
149 }
150
151 /* Missing va_end. */
152
153 void test_missing_va_end (int placeholder, ...)
154 {
155 int i;
156 __builtin_sysv_va_list ap;
157 __builtin_sysv_va_start (ap, placeholder); /* { dg-message "\\(1\\) 'va_start' called here" } */
158 i = __builtin_va_arg (ap, int);
159 } /* { dg-warning "missing call to 'va_end'" "warning" } */
160 /* { dg-message "\\(2\\) missing call to 'va_end' to match 'va_start' at \\(1\\)" "final event" { target *-*-* } .-1 } */
161
162 /* Missing va_end due to error-handling. */
163
164 int test_missing_va_end_2 (int placeholder, ...)
165 {
166 int i, j;
167 __builtin_sysv_va_list ap;
168 __builtin_sysv_va_start (ap, placeholder); /* { dg-message "\\(1\\) 'va_start' called here" } */
169 i = __builtin_va_arg (ap, int);
170 if (i == 42)
171 {
172 __builtin_sysv_va_end (ap);
173 return -1;
174 }
175 j = __builtin_va_arg (ap, int);
176 if (j == 1066) /* { dg-message "branch" } */
177 return -1; /* { dg-message "here" } */
178 __builtin_sysv_va_end (ap);
179 return 0;
180 } /* { dg-warning "missing call to 'va_end'" "warning" } */
181
182 /* va_arg after va_end. */
183
184 void test_va_arg_after_va_end (int placeholder, ...)
185 {
186 int i;
187 __builtin_sysv_va_list ap;
188 __builtin_sysv_va_start (ap, placeholder);
189 __builtin_sysv_va_end (ap); /* { dg-message "'va_end' called here" } */
190 i = __builtin_va_arg (ap, int); /* { dg-warning "'va_arg' after 'va_end'" } */
191 }
192
193 /* Type mismatch: expect int, but passed a char *. */
194
195 static void __attribute__((noinline))
196 __analyzer_called_by_test_type_mismatch_1 (int placeholder, ...)
197 {
198 int i;
199
200 __builtin_sysv_va_list ap;
201 __builtin_sysv_va_start (ap, placeholder);
202
203 i = __builtin_va_arg (ap, int); /* { dg-warning "'va_arg' expected 'int' but received '\[^\n\r\]*' for variadic argument 1 of 'ap' \\\[CWE-686\\\]" } */
204
205 __builtin_sysv_va_end (ap);
206 }
207
208 void test_type_mismatch_1 (void)
209 {
210 __analyzer_called_by_test_type_mismatch_1 (42, "foo");
211 }
212
213 /* Type mismatch: expect char *, but passed an int. */
214
215 static void __attribute__((noinline))
216 __analyzer_called_by_test_type_mismatch_2 (int placeholder, ...)
217 {
218 const char *str;
219
220 __builtin_sysv_va_list ap;
221 __builtin_sysv_va_start (ap, placeholder);
222
223 str = __builtin_va_arg (ap, const char *); /* { dg-warning "'va_arg' expected 'const char \\*' but received 'int' for variadic argument 1" } */
224
225 __builtin_sysv_va_end (ap);
226 }
227
228 void test_type_mismatch_2 (void)
229 {
230 __analyzer_called_by_test_type_mismatch_2 (42, 1066);
231 }
232
233 /* As above, but with an intermediate function. */
234
235 static void __attribute__((noinline))
236 __analyzer_test_type_mismatch_3_inner (__builtin_sysv_va_list ap)
237 {
238 const char *str;
239
240 str = __builtin_va_arg (ap, const char *); /* { dg-warning "'va_arg' expected 'const char \\*' but received 'int' for variadic argument 1 of 'ap'" } */
241 }
242
243 static void __attribute__((noinline))
244 __analyzer_test_type_mismatch_3_middle (int placeholder, ...)
245 {
246 __builtin_sysv_va_list ap;
247 __builtin_sysv_va_start (ap, placeholder);
248
249 __analyzer_test_type_mismatch_3_inner (ap);
250
251 __builtin_sysv_va_end (ap);
252 }
253
254 void test_type_mismatch_3 (void)
255 {
256 __analyzer_test_type_mismatch_3_middle (42, 1066);
257 }
258
259 /* Multiple traversals of the args. */
260
261 static void __attribute__((noinline))
262 __analyzer_called_by_test_multiple_traversals (int placeholder, ...)
263 {
264 __builtin_sysv_va_list ap;
265
266 /* First traversal. */
267 {
268 int i, j;
269
270 __builtin_sysv_va_start (ap, placeholder);
271
272 i = __builtin_va_arg (ap, int);
273 __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
274
275 j = __builtin_va_arg (ap, int);
276 __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
277
278 __builtin_sysv_va_end (ap);
279 }
280
281 /* Second traversal. */
282 {
283 int i, j;
284
285 __builtin_sysv_va_start (ap, placeholder);
286
287 i = __builtin_va_arg (ap, int);
288 __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
289
290 j = __builtin_va_arg (ap, int);
291 __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
292
293 __builtin_sysv_va_end (ap);
294 }
295 }
296
297 void test_multiple_traversals (void)
298 {
299 __analyzer_called_by_test_multiple_traversals (0, 1066, 42);
300 }
301
302 /* Multiple traversals, using va_copy. */
303
304 static void __attribute__((noinline))
305 __analyzer_called_by_test_multiple_traversals_2 (int placeholder, ...)
306 {
307 int i, j;
308 __builtin_sysv_va_list args1;
309 __builtin_sysv_va_list args2;
310
311 __builtin_sysv_va_start (args1, placeholder);
312 __builtin_sysv_va_copy (args2, args1);
313
314 /* First traversal. */
315 i = __builtin_va_arg (args1, int);
316 __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
317 j = __builtin_va_arg (args1, int);
318 __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
319 __builtin_sysv_va_end (args1);
320
321 /* Traversal of copy. */
322 i = __builtin_va_arg (args2, int);
323 __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
324 j = __builtin_va_arg (args2, int);
325 __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
326 __builtin_sysv_va_end (args2);
327 }
328
329 void test_multiple_traversals_2 (void)
330 {
331 __analyzer_called_by_test_multiple_traversals_2 (0, 1066, 42);
332 }
333
334 /* Multiple traversals, using va_copy after a va_arg. */
335
336 static void __attribute__((noinline))
337 __analyzer_called_by_test_multiple_traversals_3 (int placeholder, ...)
338 {
339 int i, j;
340 __builtin_sysv_va_list args1;
341 __builtin_sysv_va_list args2;
342
343 __builtin_sysv_va_start (args1, placeholder);
344
345 /* First traversal. */
346 i = __builtin_va_arg (args1, int);
347 __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
348
349 /* va_copy after the first va_arg. */
350 __builtin_sysv_va_copy (args2, args1);
351
352 j = __builtin_va_arg (args1, int);
353 __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
354 __builtin_sysv_va_end (args1);
355
356 /* Traversal of copy. */
357 j = __builtin_va_arg (args2, int);
358 __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
359 __builtin_sysv_va_end (args2);
360 }
361
362 void test_multiple_traversals_3 (void)
363 {
364 __analyzer_called_by_test_multiple_traversals_3 (0, 1066, 42);
365 }
366
367 /* va_copy after va_end. */
368
369 void test_va_copy_after_va_end (int placeholder, ...)
370 {
371 __builtin_sysv_va_list ap1, ap2;
372 __builtin_sysv_va_start (ap1, placeholder);
373 __builtin_sysv_va_end (ap1); /* { dg-message "'va_end' called here" } */
374 __builtin_sysv_va_copy (ap2, ap1); /* { dg-warning "'va_copy' after 'va_end'" } */
375 __builtin_sysv_va_end (ap2);
376 }
377
378 /* leak of va_copy. */
379
380 void test_leak_of_va_copy (int placeholder, ...)
381 {
382 __builtin_sysv_va_list ap1, ap2;
383 __builtin_sysv_va_start (ap1, placeholder);
384 __builtin_sysv_va_copy (ap2, ap1); /* { dg-message "'va_copy' called here" } */
385 __builtin_sysv_va_end (ap1);
386 } /* { dg-warning "missing call to 'va_end'" "warning" } */
387 /* { dg-message "missing call to 'va_end' to match 'va_copy' at \\(1\\)" "final event" { target *-*-* } .-1 } */
388
389 /* double va_end. */
390
391 void test_double_va_end (int placeholder, ...)
392 {
393 __builtin_sysv_va_list ap;
394 __builtin_sysv_va_start (ap, placeholder);
395 __builtin_sysv_va_end (ap); /* { dg-message "'va_end' called here" } */
396 __builtin_sysv_va_end (ap); /* { dg-warning "'va_end' after 'va_end'" } */
397 }
398
399 /* double va_start. */
400
401 void test_double_va_start (int placeholder, ...)
402 {
403 int i;
404 __builtin_sysv_va_list ap;
405 __builtin_sysv_va_start (ap, placeholder); /* { dg-message "'va_start' called here" } */
406 __builtin_sysv_va_start (ap, placeholder); /* { dg-warning "missing call to 'va_end'" "warning" } */
407 /* { dg-message "missing call to 'va_end' to match 'va_start' at \\(1\\)" "final event" { target *-*-* } .-1 } */
408 __builtin_sysv_va_end (ap);
409 }
410
411 /* va_copy before va_start. */
412
413 void test_va_copy_before_va_start (int placeholder, ...)
414 {
415 __builtin_sysv_va_list ap1; /* { dg-message "region created on stack here" } */
416 __builtin_sysv_va_list ap2;
417 __builtin_sysv_va_copy (ap2, ap1); /* { dg-warning "use of uninitialized value 'ap1'" } */
418 __builtin_sysv_va_end (ap2);
419 }
420
421 /* Verify that we complain about uses of a va_list after the function
422 in which va_start was called has returned. */
423
424 __builtin_sysv_va_list global_ap;
425
426 static void __attribute__((noinline))
427 __analyzer_called_by_test_va_arg_after_return (int placeholder, ...)
428 {
429 __builtin_sysv_va_start (global_ap, placeholder);
430 __builtin_sysv_va_end (global_ap);
431 }
432
433 void test_va_arg_after_return (void)
434 {
435 int i;
436 __analyzer_called_by_test_va_arg_after_return (42, 1066);
437 i = __builtin_va_arg (global_ap, int); /* { dg-warning "dereferencing pointer 'global_ap' to within stale stack frame" } */
438 }
439
440 void pr107349 (void)
441 {
442 __builtin_sysv_va_list x,y;
443 __builtin_sysv_va_copy(x,y); /* { dg-warning "use of uninitialized value 'y'" } */
444 } /* { dg-warning "missing call to 'va_end'" } */