blob: c692178dfb2648e2f33c8e1e8afe80d253cd00c2 [file] [log] [blame]
Kristof Umann7d6d9eb2018-10-31 14:54:27 +00001// 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
15void 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
24void nonFunctionLikeMacroTest() {
25 int *ptr;
26 SET_PTR_VAR_TO_NULL;
27 *ptr = 5; // expected-warning{{Dereference of null pointer}}
28}
29
Kristof Umann38002572018-11-05 02:14:36 +000030// CHECK: <key>name</key><string>SET_PTR_VAR_TO_NULL</string>
31// CHECK-NEXT: <key>expansion</key><string>ptr = 0</string>
Kristof Umann7d6d9eb2018-10-31 14:54:27 +000032
33#define NULL 0
34#define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \
35 ptr = NULL
36
37void nonFunctionLikeNestedMacroTest() {
38 int *ptr;
39 SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO;
40 *ptr = 5; // expected-warning{{Dereference of null pointer}}
41}
42
Kristof Umann38002572018-11-05 02:14:36 +000043// 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
50void setToNull(int **vptr) {
51 *vptr = nullptr;
52}
53
54#define TO_NULL(x) \
55 setToNull(x)
56
57void functionLikeMacroTest() {
58 int *ptr;
59 TO_NULL(&ptr);
60 *ptr = 5; // expected-warning{{Dereference of null pointer}}
61}
62
Kristof Umann38002572018-11-05 02:14:36 +000063// CHECK: <key>name</key><string>TO_NULL</string>
Kristof Umann08d92e42018-11-27 02:28:23 +000064// CHECK-NEXT: <key>expansion</key><string>setToNull(&amp;ptr)</string>
Kristof Umann38002572018-11-05 02:14:36 +000065
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
77void functionLikeNestedMacroTest() {
78 int *a;
79 TO_NULL(&a);
80 DEREF(a) = 5; // expected-warning{{Dereference of null pointer}}
81}
82
Kristof Umann38002572018-11-05 02:14:36 +000083// CHECK: <key>name</key><string>TO_NULL</string>
Kristof Umann08d92e42018-11-27 02:28:23 +000084// CHECK-NEXT: <key>expansion</key><string>setToNull(&amp;a)</string>
Kristof Umann38002572018-11-05 02:14:36 +000085
Kristof Umann38002572018-11-05 02:14:36 +000086// CHECK: <key>name</key><string>DEREF</string>
Kristof Umann08d92e42018-11-27 02:28:23 +000087// CHECK-NEXT: <key>expansion</key><string>{ int b; b = 5; } print(a); *a</string>
Kristof Umann38002572018-11-05 02:14:36 +000088
89//===----------------------------------------------------------------------===//
90// Tests for undefining and/or redifining macros.
91//===----------------------------------------------------------------------===//
92
93#define WILL_UNDEF_SET_NULL_TO_PTR(ptr) \
94 ptr = nullptr;
95
96void 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
Kristof Umann38002572018-11-05 02:14:36 +0000104// 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
113void 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
Kristof Umann38002572018-11-05 02:14:36 +0000124// 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
133void 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
Kristof Umann08d92e42018-11-27 02:28:23 +0000144
145//===----------------------------------------------------------------------===//
146// Tests for macro arguments containing commas and parantheses.
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
160void macroArgContainsCommaInStringTest() {
161 int *a;
162 TO_NULL_AND_PRINT(a, "Will this , cause a crash?");
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
169void 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
178void 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
192void 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
201void setToNullAndPrint(int **vptr, const char *str) {
202 setToNull(vptr);
203 print(str);
204}
205
206void 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
218void 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
230void 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
245void 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
267void 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
281void 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
294void 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
307template <typename ...Args>
308void variadicFunc(Args ...args);
309
310#define VARIADIC_SET_TO_NULL(ptr, ...) \
311 ptr = nullptr; \
312 variadicFunc(__VA_ARGS__)
313
314void 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// TODO: Should correctly display the rest of the parameters.
321// CHECK: <key>name</key><string>VARIADIC_SET_TO_NULL</string>
322// CHECK-NEXT: <key>expansion</key><string>ptr = nullptr; variadicFunc( 1)</string>
323
324//===----------------------------------------------------------------------===//
325// Tests for # and ##.
326//===----------------------------------------------------------------------===//
327
328#define DECLARE_FUNC_AND_SET_TO_NULL(funcName, ptr) \
329 void generated_##funcName(); \
330 ptr = nullptr;
331
332void hashHashOperatorTest() {
333 int *ptr;
334 DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr);
335 *ptr = 5; // expected-warning{{Dereference of null pointer}}
336}
337
338// TODO: Should expand correctly.
339// CHECK: <key>name</key><string>DECLARE_FUNC_AND_SET_TO_NULL</string>
340// CHECK-NEXT: <key>expansion</key><string>void generated_##whatever(); ptr = nullptr;</string>
341
342#define PRINT_STR(str, ptr) \
343 print(#str); \
344 ptr = nullptr
345
346void hashOperatorTest() {
347 int *ptr;
348 PRINT_STR(Hello, ptr);
349 *ptr = 5; // expected-warning{{Dereference of null pointer}}
350}
351
352// TODO: Should expand correctly.
353// CHECK: <key>name</key><string>PRINT_STR</string>
354// CHECK-NEXT: <key>expansion</key><string>print(#Hello); ptr = nullptr</string>
355
356//===----------------------------------------------------------------------===//
357// Tests for more complex macro expansions.
358//
359// We won't cover anything that wasn't covered up to this point, but rather
360// show more complex, macros with deeper nesting, more arguments (some unused)
361// and so on.
362//===----------------------------------------------------------------------===//
363
364#define IF(Condition) \
365 if ( Condition )
366
367#define L_BRACE {
368#define R_BRACE }
369#define LESS <
370#define GREATER >
371#define EQUALS =
372#define SEMICOLON ;
373#define NEGATIVE -
374#define RETURN return
375#define ZERO 0
376
377#define EUCLIDEAN_ALGORITHM(A, B) \
378 IF(A LESS ZERO) L_BRACE \
379 A EQUALS NEGATIVE A SEMICOLON \
380 R_BRACE \
381 IF(B LESS ZERO) L_BRACE \
382 B EQUALS NEGATIVE B SEMICOLON \
383 R_BRACE \
384 \
385 /* This is where a while loop would be, but that seems to be too complex */ \
386 /* for the analyzer just yet. Let's just pretend that this algorithm */ \
387 /* works. */ \
388 \
389 RETURN B / (B - B) SEMICOLON
390
391int getLowestCommonDenominator(int A, int B) {
392 EUCLIDEAN_ALGORITHM(A, B) // expected-warning{{Division by zero}}
393}
394
395void testVeryComplexAlgorithm() {
396 int tmp = 8 / (getLowestCommonDenominator(5, 7) - 1);
397 print(&tmp);
398}
399// CHECK: <key>name</key><string>EUCLIDEAN_ALGORITHM</string>
400// CHECK-NEXT: <key>expansion</key><string>if (A&lt;0 ){A=-A;} if ( B&lt;0 ){ B=- B;}return B / ( B - B);</string>
401
402#define YET_ANOTHER_SET_TO_NULL(x, y, z) \
403 print((void *) x); \
404 print((void *) y); \
405 z = nullptr;
406
407#define DO_NOTHING(str) str
408#define DO_NOTHING2(str2) DO_NOTHING(str2)
409
410void test() {
411 int *ptr;
412 YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr);
413 *ptr = 5; // expected-warning{{Dereference of null pointer}}
414}
415// CHECK: <key>name</key><string>YET_ANOTHER_SET_TO_NULL</string>
416// CHECK-NEXT: <key>expansion</key><string>print((void *)5); print((void *)&quot;Remember the Vasa&quot;); ptr = nullptr;</string>