1 // RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
2 //
3 // RUN: %clang_analyze_cc1 -analyzer-checker=core %s \
4 // RUN: -analyzer-output=plist -o %t.plist \
5 // RUN: -analyzer-config expand-macros=true
6 //
7 // Check the actual plist output.
8 // RUN: cat %t.plist | %diff_plist \
9 // RUN: %S/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist -
10 //
11 // Check the macro expansions from the plist output here, to make the test more
12 // understandable.
13 // RUN: FileCheck --input-file=%t.plist %s
14
15 void print(const void*);
16
17 //===----------------------------------------------------------------------===//
18 // Tests for non-function-like macro expansions.
19 //===----------------------------------------------------------------------===//
20
21 #define SET_PTR_VAR_TO_NULL \
22 ptr = 0
23
24 void nonFunctionLikeMacroTest() {
25 int *ptr;
26 SET_PTR_VAR_TO_NULL;
27 *ptr = 5; // expected-warning{{Dereference of null pointer}}
28 }
29
30 // CHECK: <key>name</key><string>SET_PTR_VAR_TO_NULL</string>
31 // CHECK-NEXT: <key>expansion</key><string>ptr = 0</string>
32
33 #define NULL 0
34 #define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \
35 ptr = NULL
36
37 void nonFunctionLikeNestedMacroTest() {
38 int *ptr;
39 SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO;
40 *ptr = 5; // expected-warning{{Dereference of null pointer}}
41 }
42
43 // CHECK: <key>name</key><string>SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO</string>
44 // CHECK-NEXT: <key>expansion</key><string>ptr =0</string>
45
46 //===----------------------------------------------------------------------===//
47 // Tests for function-like macro expansions.
48 //===----------------------------------------------------------------------===//
49
50 void setToNull(int **vptr) {
51 *vptr = nullptr;
52 }
53
54 #define TO_NULL(x) \
55 setToNull(x)
56
57 void functionLikeMacroTest() {
58 int *ptr;
59 TO_NULL(&ptr);
60 *ptr = 5; // expected-warning{{Dereference of null pointer}}
61 }
62
63 // CHECK: <key>name</key><string>TO_NULL</string>
64 // CHECK-NEXT: <key>expansion</key><string>setToNull(&ptr)</string>
65
66 #define DOES_NOTHING(x) \
67 { \
68 int b; \
69 b = 5; \
70 } \
71 print(x)
72
73 #define DEREF(x) \
74 DOES_NOTHING(x); \
75 *x
76
77 void functionLikeNestedMacroTest() {
78 int *a;
79 TO_NULL(&a);
80 DEREF(a) = 5; // expected-warning{{Dereference of null pointer}}
81 }
82
83 // CHECK: <key>name</key><string>TO_NULL</string>
84 // CHECK-NEXT: <key>expansion</key><string>setToNull(&a)</string>
85
86 // CHECK: <key>name</key><string>DEREF</string>
87 // CHECK-NEXT: <key>expansion</key><string>{ int b; b = 5; } print(a); *a</string>
88
89 //===----------------------------------------------------------------------===//
90 // Tests for undefining and/or redifining macros.
91 //===----------------------------------------------------------------------===//
92
93 #define WILL_UNDEF_SET_NULL_TO_PTR(ptr) \
94 ptr = nullptr;
95
96 void undefinedMacroByTheEndOfParsingTest() {
97 int *ptr;
98 WILL_UNDEF_SET_NULL_TO_PTR(ptr);
99 *ptr = 5; // expected-warning{{Dereference of null pointer}}
100 }
101
102 #undef WILL_UNDEF_SET_NULL_TO_PTR
103
104 // CHECK: <key>name</key><string>WILL_UNDEF_SET_NULL_TO_PTR</string>
105 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string>
106
107 #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \
108 /* Nothing */
109 #undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL
110 #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \
111 ptr = nullptr;
112
113 void macroRedefinedMultipleTimesTest() {
114 int *ptr;
115 WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr)
116 *ptr = 5; // expected-warning{{Dereference of null pointer}}
117 }
118
119 #undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL
120 #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \
121 print("This string shouldn't be in the plist file at all. Or anywhere, " \
122 "but here.");
123
124 // CHECK: <key>name</key><string>WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL</string>
125 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string>
126
127 #define WILL_UNDEF_SET_NULL_TO_PTR_2(ptr) \
128 ptr = nullptr;
129
130 #define PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr) \
131 WILL_UNDEF_SET_NULL_TO_PTR_2(ptr)
132
133 void undefinedMacroInsideAnotherMacroTest() {
134 int *ptr;
135 PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr);
136 *ptr = 5; // expected-warning{{Dereference of null pointer}}
137 }
138
139 // TODO: Expand arguments.
140 // CHECK: <key>name</key><string>PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD</string>
141 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string>
142
143 #undef WILL_UNDEF_SET_NULL_TO_PTR_2
144
145 //===----------------------------------------------------------------------===//
146 // Tests for macro arguments containing commas and parantheses.
internalStructFunc()147 //
148 // As of writing these tests, the algorithm expands macro arguments by lexing
149 // the macro's expansion location, and relies on finding tok::comma and
150 // tok::l_paren/tok::r_paren.
151 //===----------------------------------------------------------------------===//
152
153 // Note that this commas, parantheses in strings aren't parsed as tok::comma or
154 // tok::l_paren/tok::r_paren, but why not test them.
155
156 #define TO_NULL_AND_PRINT(x, str) \
157 x = 0; \
158 print(str)
159
160 void macroArgContainsCommaInStringTest() {
161 int *a;
162 TO_NULL_AND_PRINT(a, "Will this , cause a crash?");
typedefStructFunc()163 *a = 5; // expected-warning{{Dereference of null pointer}}
164 }
165
166 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
167 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( "Will this , cause a crash?")</string>
168
169 void macroArgContainsLParenInStringTest() {
170 int *a;
171 TO_NULL_AND_PRINT(a, "Will this ( cause a crash?");
172 *a = 5; // expected-warning{{Dereference of null pointer}}
173 }
174
175 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
176 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( "Will this ( cause a crash?")</string>
177
178 void macroArgContainsRParenInStringTest() {
179 int *a;
180 TO_NULL_AND_PRINT(a, "Will this ) cause a crash?");
181 *a = 5; // expected-warning{{Dereference of null pointer}}
182 }
183
184 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
185 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( "Will this ) cause a crash?")</string>
186
187 #define CALL_FUNCTION(funcCall) \
188 funcCall
189
190 // Function calls do contain both tok::comma and tok::l_paren/tok::r_paren.
191
192 void macroArgContainsLParenRParenTest() {
193 int *a;
194 CALL_FUNCTION(setToNull(&a));
195 *a = 5; // expected-warning{{Dereference of null pointer}}
196 }
197
198 // CHECK: <key>name</key><string>CALL_FUNCTION</string>
199 // CHECK-NEXT: <key>expansion</key><string>setToNull(&a)</string>
200
201 void setToNullAndPrint(int **vptr, const char *str) {
202 setToNull(vptr);
203 print(str);
204 }
205
206 void macroArgContainsCommaLParenRParenTest() {
207 int *a;
208 CALL_FUNCTION(setToNullAndPrint(&a, "Hello!"));
209 *a = 5; // expected-warning{{Dereference of null pointer}}
210 }
211
212 // CHECK: <key>name</key><string>CALL_FUNCTION</string>
213 // CHECK-NEXT: <key>expansion</key><string>setToNullAndPrint(&a, "Hello!")</string>
214
215 #define CALL_FUNCTION_WITH_TWO_PARAMS(funcCall, param1, param2) \
216 funcCall(param1, param2)
217
arrayHolder()218 void macroArgContainsCommaLParenRParenTest2() {
219 int *a;
220 CALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &a, "Hello!");
221 *a = 5; // expected-warning{{Dereference of null pointer}}
222 }
223
224 // CHECK: <key>name</key><string>CALL_FUNCTION_WITH_TWO_PARAMS</string>
225 // CHECK-NEXT: <key>expansion</key><string>setToNullAndPrint( &a, "Hello!")</string>
226
227 #define CALL_LAMBDA(l) \
228 l()
229
foo()230 void commaInBracketsTest() {
231 int *ptr;
232 const char str[] = "Hello!";
233 // You need to add parantheses around a lambda expression to compile this,
234 // else the comma in the capture will be parsed as divider of macro args.
235 CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); }));
236 *ptr = 5; // expected-warning{{Dereference of null pointer}}
237 }
238
239 // CHECK: <key>name</key><string>CALL_LAMBDA</string>
240 // CHECK-NEXT: <key>expansion</key><string>([&ptr, str] () mutable { setToNull(&ptr); })()</string>
241
242 #define PASTE_CODE(code) \
243 code
244
245 void commaInBracesTest() {
246 PASTE_CODE({ // expected-warning{{Dereference of null pointer}}
247 // NOTE: If we were to add a new variable here after a comma, we'd get a
248 // compilation error, so this test is mainly here to show that this was also
249 // investigated.
250
251 // int *ptr = nullptr, a;
252 int *ptr = nullptr;
253 *ptr = 5;
254 })
255 }
256
257 // CHECK: <key>name</key><string>PASTE_CODE</string>
258 // CHECK-NEXT: <key>expansion</key><string>{ int *ptr = nullptr; *ptr = 5; }</string>
259
260 // Example taken from
261 // https://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html#Macro-Arguments.
262
263 #define POTENTIALLY_EMPTY_PARAM(x, y) \
264 x; \
265 y = nullptr
266
267 void emptyParamTest() {
268 int *ptr;
269
270 POTENTIALLY_EMPTY_PARAM(,ptr);
271 *ptr = 5; // expected-warning{{Dereference of null pointer}}
272 }
273
274 // CHECK: <key>name</key><string>POTENTIALLY_EMPTY_PARAM</string>
275 // CHECK-NEXT: <key>expansion</key><string>;ptr = nullptr</string>
276
277 #define NESTED_EMPTY_PARAM(a, b) \
278 POTENTIALLY_EMPTY_PARAM(a, b);
279
280
281 void nestedEmptyParamTest() {
282 int *ptr;
283
284 NESTED_EMPTY_PARAM(, ptr);
285 *ptr = 5; // expected-warning{{Dereference of null pointer}}
286 }
287
288 // CHECK: <key>name</key><string>NESTED_EMPTY_PARAM</string>
289 // CHECK-NEXT: <key>expansion</key><string>; ptr = nullptr;</string>
290
291 #define CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(func, param) \
292 CALL_FUNCTION(func(param))
293
294 void lParenRParenInNestedMacro() {
295 int *ptr;
296 CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &ptr);
297 *ptr = 5; // expected-warning{{Dereference of null pointer}}
298 }
299
300 // CHECK: <key>name</key><string>CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO</string>
301 // CHECK-NEXT: <key>expansion</key><string>setToNull( &ptr)</string>
302
303 //===----------------------------------------------------------------------===//
304 // Tests for variadic macro arguments.
305 //===----------------------------------------------------------------------===//
306
307 template <typename ...Args>
308 void variadicFunc(Args ...args);
309
310 #define VARIADIC_SET_TO_NULL(ptr, ...) \
311 ptr = nullptr; \
312 variadicFunc(__VA_ARGS__)
313
314 void variadicMacroArgumentTest() {
315 int *ptr;
316 VARIADIC_SET_TO_NULL(ptr, 1, 5, "haha!");
317 *ptr = 5; // expected-warning{{Dereference of null pointer}}
318 }
319
320 // CHECK: <key>name</key><string>VARIADIC_SET_TO_NULL</string>
321 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr; variadicFunc( 1, 5, "haha!")</string>
322
323 void variadicMacroArgumentWithoutAnyArgumentTest() {
324 int *ptr;
325 // Not adding a single parameter to ... is silly (and also causes a
326 // preprocessor warning), but is not an excuse to crash on it.
327 VARIADIC_SET_TO_NULL(ptr);
328 *ptr = 5; // expected-warning{{Dereference of null pointer}}
329 }
330
331 // CHECK: <key>name</key><string>VARIADIC_SET_TO_NULL</string>
332 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr; variadicFunc()</string>
333
334 //===----------------------------------------------------------------------===//
335 // Tests for # and ##.
336 //===----------------------------------------------------------------------===//
337
338 #define DECLARE_FUNC_AND_SET_TO_NULL(funcName, ptr) \
339 void generated_##funcName(); \
340 ptr = nullptr;
341
342 void hashHashOperatorTest() {
343 int *ptr;
344 DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr);
345 *ptr = 5; // expected-warning{{Dereference of null pointer}}
346 }
347
348 // CHECK: <key>name</key><string>DECLARE_FUNC_AND_SET_TO_NULL</string>
349 // CHECK-NEXT: <key>expansion</key><string>void generated_whatever(); ptr = nullptr;</string>
350
351 void macroArgContainsHashHashInStringTest() {
352 int *a;
353 TO_NULL_AND_PRINT(a, "Will this ## cause a crash?");
354 *a = 5; // expected-warning{{Dereference of null pointer}}
355 }
356
357 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
358 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( "Will this ## cause a crash?")</string>
359
360 #define PRINT_STR(str, ptr) \
361 print(#str); \
362 ptr = nullptr
363
364 void hashOperatorTest() {
365 int *ptr;
366 PRINT_STR(Hello, ptr);
367 *ptr = 5; // expected-warning{{Dereference of null pointer}}
368 }
369
370 // CHECK: <key>name</key><string>PRINT_STR</string>
371 // CHECK-NEXT: <key>expansion</key><string>print("Hello"); ptr = nullptr</string>
372
373 void macroArgContainsHashInStringTest() {
374 int *a;
375 TO_NULL_AND_PRINT(a, "Will this # cause a crash?");
376 *a = 5; // expected-warning{{Dereference of null pointer}}
377 }
378
379 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
380 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( "Will this # cause a crash?")</string>
381
382 //===----------------------------------------------------------------------===//
383 // Tests for more complex macro expansions.
384 //
385 // We won't cover anything that wasn't covered up to this point, but rather
386 // show more complex, macros with deeper nesting, more arguments (some unused)
387 // and so on.
388 //===----------------------------------------------------------------------===//
389
390 #define IF(Condition) \
391 if ( Condition )
392
393 #define L_BRACE {
394 #define R_BRACE }
395 #define LESS <
396 #define GREATER >
397 #define EQUALS =
398 #define SEMICOLON ;
399 #define NEGATIVE -
400 #define RETURN return
401 #define ZERO 0
402
403 #define EUCLIDEAN_ALGORITHM(A, B) \
404 IF(A LESS ZERO) L_BRACE \
405 A EQUALS NEGATIVE A SEMICOLON \
406 R_BRACE \
407 IF(B LESS ZERO) L_BRACE \
408 B EQUALS NEGATIVE B SEMICOLON \
409 R_BRACE \
410 \
411 /* This is where a while loop would be, but that seems to be too complex */ \
412 /* for the analyzer just yet. Let's just pretend that this algorithm */ \
413 /* works. */ \
414 \
415 RETURN B / (B - B) SEMICOLON
416
417 int getLowestCommonDenominator(int A, int B) {
418 EUCLIDEAN_ALGORITHM(A, B) // expected-warning{{Division by zero}}
419 }
420
421 void testVeryComplexAlgorithm() {
422 int tmp = 8 / (getLowestCommonDenominator(5, 7) - 1);
423 print(&tmp);
424 }
425 // CHECK: <key>name</key><string>EUCLIDEAN_ALGORITHM</string>
426 // CHECK-NEXT: <key>expansion</key><string>if (A<0 ){A=-A;} if ( B<0 ){ B=- B;}return B / ( B - B);</string>
427
428 #define YET_ANOTHER_SET_TO_NULL(x, y, z) \
429 print((void *) x); \
430 print((void *) y); \
431 z = nullptr;
432
433 #define DO_NOTHING(str) str
434 #define DO_NOTHING2(str2) DO_NOTHING(str2)
435
436 void test() {
437 int *ptr;
438 YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr);
439 *ptr = 5; // expected-warning{{Dereference of null pointer}}
440 }
441 // CHECK: <key>name</key><string>YET_ANOTHER_SET_TO_NULL</string>
442 // CHECK-NEXT: <key>expansion</key><string>print((void *)5); print((void *)"Remember the Vasa"); ptr = nullptr;</string>
443