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(&amp;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(&amp;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( &quot;Will this , cause a crash?&quot;)</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( &quot;Will this ( cause a crash?&quot;)</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( &quot;Will this ) cause a crash?&quot;)</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(&amp;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(&amp;a, &quot;Hello!&quot;)</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( &amp;a, &quot;Hello!&quot;)</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>([&amp;ptr, str] () mutable { setToNull(&amp;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( &amp;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, &quot;haha!&quot;)</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( &quot;Will this ## cause a crash?&quot;)</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(&quot;Hello&quot;); 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( &quot;Will this # cause a crash?&quot;)</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&lt;0 ){A=-A;} if ( B&lt;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 *)&quot;Remember the Vasa&quot;); ptr = nullptr;</string>
443