brintos

brintos / llvm-project-archived public Read only

0
0
Text · 33.4 KiB · d57bb0f Raw
951 lines · cpp
1// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core %s  \2// RUN:   -analyzer-output=plist -o %t.plist \3// RUN:   -analyzer-config expand-macros=true -verify4//5// RUN: FileCheck --input-file=%t.plist %s6 7void print(const void*);8 9//===----------------------------------------------------------------------===//10// Tests for non-function-like macro expansions.11//===----------------------------------------------------------------------===//12 13#define SET_PTR_VAR_TO_NULL \14  ptr = 015 16void nonFunctionLikeMacroTest() {17  int *ptr;18  SET_PTR_VAR_TO_NULL;19  *ptr = 5; // expected-warning{{Dereference of null pointer}}20}21 22// CHECK:      <key>macro_expansions</key>23// CHECK-NEXT: <array>24// CHECK-NEXT:  <dict>25// CHECK-NEXT:   <key>location</key>26// CHECK-NEXT:   <dict>27// CHECK-NEXT:    <key>line</key><integer>18</integer>28// CHECK-NEXT:    <key>col</key><integer>3</integer>29// CHECK-NEXT:    <key>file</key><integer>0</integer>30// CHECK-NEXT:   </dict>31// CHECK-NEXT:   <key>name</key><string>SET_PTR_VAR_TO_NULL</string>32// CHECK-NEXT:   <key>expansion</key><string>ptr =0</string>33// CHECK-NEXT:  </dict>34// CHECK-NEXT: </array>35 36#define NULL 037#define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \38  ptr = NULL39 40void nonFunctionLikeNestedMacroTest() {41  int *ptr;42  SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO;43  *ptr = 5; // expected-warning{{Dereference of null pointer}}44}45 46// CHECK:      <key>macro_expansions</key>47// CHECK-NEXT: <array>48// CHECK-NEXT:  <dict>49// CHECK-NEXT:   <key>location</key>50// CHECK-NEXT:   <dict>51// CHECK-NEXT:    <key>line</key><integer>42</integer>52// CHECK-NEXT:    <key>col</key><integer>3</integer>53// CHECK-NEXT:    <key>file</key><integer>0</integer>54// CHECK-NEXT:   </dict>55// CHECK-NEXT:  <key>name</key><string>SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO</string>56// CHECK-NEXT:  <key>expansion</key><string>ptr =0</string>57// CHECK-NEXT:  </dict>58// CHECK-NEXT: </array>59 60//===----------------------------------------------------------------------===//61// Tests for function-like macro expansions.62//===----------------------------------------------------------------------===//63 64void setToNull(int **vptr) {65  *vptr = nullptr;66}67 68#define TO_NULL(x) \69  setToNull(x)70 71void functionLikeMacroTest() {72  int *ptr;73  TO_NULL(&ptr);74  *ptr = 5; // expected-warning{{Dereference of null pointer}}75}76 77// CHECK:      <key>macro_expansions</key>78// CHECK-NEXT: <array>79// CHECK-NEXT:  <dict>80// CHECK-NEXT:   <key>location</key>81// CHECK-NEXT:   <dict>82// CHECK-NEXT:    <key>line</key><integer>73</integer>83// CHECK-NEXT:    <key>col</key><integer>3</integer>84// CHECK-NEXT:    <key>file</key><integer>0</integer>85// CHECK-NEXT:   </dict>86// CHECK-NEXT:  <key>name</key><string>TO_NULL(&amp;ptr)</string>87// CHECK-NEXT:  <key>expansion</key><string>setToNull (&amp;ptr )</string>88// CHECK-NEXT:  </dict>89// CHECK-NEXT: </array>90 91#define DOES_NOTHING(x) \92  {                     \93    int b;              \94    b = 5;              \95  }                     \96  print(x)97 98#define DEREF(x)   \99  DOES_NOTHING(x); \100  *x101 102void functionLikeNestedMacroTest() {103  int *a;104  TO_NULL(&a);105  DEREF(a) = 5; // expected-warning{{Dereference of null pointer}}106}107 108// CHECK:      <key>macro_expansions</key>109// CHECK-NEXT: <array>110// CHECK-NEXT:  <dict>111// CHECK-NEXT:   <key>location</key>112// CHECK-NEXT:   <dict>113// CHECK-NEXT:    <key>line</key><integer>104</integer>114// CHECK-NEXT:    <key>col</key><integer>3</integer>115// CHECK-NEXT:    <key>file</key><integer>0</integer>116// CHECK-NEXT:   </dict>117// CHECK-NEXT:   <key>name</key><string>TO_NULL(&amp;a)</string>118// CHECK-NEXT:   <key>expansion</key><string>setToNull (&amp;a )</string>119// CHECK-NEXT:  </dict>120// CHECK-NEXT:  <dict>121// CHECK-NEXT:   <key>location</key>122// CHECK-NEXT:   <dict>123// CHECK-NEXT:    <key>line</key><integer>105</integer>124// CHECK-NEXT:    <key>col</key><integer>3</integer>125// CHECK-NEXT:    <key>file</key><integer>0</integer>126// CHECK-NEXT:   </dict>127// CHECK-NEXT:   <key>name</key><string>DEREF(a)</string>128// CHECK-NEXT:   <key>expansion</key><string>{int b ;b =5;}print (a );*a </string>129// CHECK-NEXT:  </dict>130// CHECK-NEXT: </array>131 132//===----------------------------------------------------------------------===//133// Tests for undefining and/or redifining macros.134//===----------------------------------------------------------------------===//135 136#define WILL_UNDEF_SET_NULL_TO_PTR(ptr) \137  ptr = nullptr;138 139void undefinedMacroByTheEndOfParsingTest() {140  int *ptr;141  WILL_UNDEF_SET_NULL_TO_PTR(ptr);142  *ptr = 5; // expected-warning{{Dereference of null pointer}}143}144 145#undef WILL_UNDEF_SET_NULL_TO_PTR146 147// CHECK:      <key>macro_expansions</key>148// CHECK-NEXT: <array>149// CHECK-NEXT:  <dict>150// CHECK-NEXT:   <key>location</key>151// CHECK-NEXT:   <dict>152// CHECK-NEXT:    <key>line</key><integer>141</integer>153// CHECK-NEXT:    <key>col</key><integer>3</integer>154// CHECK-NEXT:    <key>file</key><integer>0</integer>155// CHECK-NEXT:   </dict>156// CHECK-NEXT:   <key>name</key><string>WILL_UNDEF_SET_NULL_TO_PTR(ptr)</string>157// CHECK-NEXT:   <key>expansion</key><string>ptr =nullptr ;</string>158// CHECK-NEXT:  </dict>159// CHECK-NEXT: </array>160 161#define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \162  /* Nothing */163#undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL164#define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \165  ptr = nullptr;166 167void macroRedefinedMultipleTimesTest() {168  int *ptr;169  WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr)170  *ptr = 5; // expected-warning{{Dereference of null pointer}}171}172 173#undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL174#define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr)                      \175  print("This string shouldn't be in the plist file at all. Or anywhere, " \176        "but here.");177 178// CHECK:      <key>macro_expansions</key>179// CHECK-NEXT: <array>180// CHECK-NEXT:  <dict>181// CHECK-NEXT:   <key>location</key>182// CHECK-NEXT:   <dict>183// CHECK-NEXT:    <key>line</key><integer>169</integer>184// CHECK-NEXT:    <key>col</key><integer>3</integer>185// CHECK-NEXT:    <key>file</key><integer>0</integer>186// CHECK-NEXT:   </dict>187// CHECK-NEXT:   <key>name</key><string>WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr)</string>188// CHECK-NEXT:   <key>expansion</key><string>ptr =nullptr ;</string>189// CHECK-NEXT:  </dict>190// CHECK-NEXT: </array>191 192#define WILL_UNDEF_SET_NULL_TO_PTR_2(ptr) \193  ptr = nullptr;194 195#define PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr) \196  WILL_UNDEF_SET_NULL_TO_PTR_2(ptr)197 198void undefinedMacroInsideAnotherMacroTest() {199  int *ptr;200  PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr);201  *ptr = 5; // expected-warning{{Dereference of null pointer}}202}203 204// CHECK:      <key>macro_expansions</key>205// CHECK-NEXT: <array>206// CHECK-NEXT:  <dict>207// CHECK-NEXT:   <key>location</key>208// CHECK-NEXT:   <dict>209// CHECK-NEXT:    <key>line</key><integer>200</integer>210// CHECK-NEXT:    <key>col</key><integer>3</integer>211// CHECK-NEXT:    <key>file</key><integer>0</integer>212// CHECK-NEXT:   </dict>213// CHECK-NEXT:   <key>name</key><string>PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr)</string>214// CHECK-NEXT:   <key>expansion</key><string>ptr =nullptr ;</string>215// CHECK-NEXT:  </dict>216// CHECK-NEXT: </array>217 218#undef WILL_UNDEF_SET_NULL_TO_PTR_2219 220//===----------------------------------------------------------------------===//221// Tests for macro arguments containing commas and parantheses.222//223// As of writing these tests, the algorithm expands macro arguments by lexing224// the macro's expansion location, and relies on finding tok::comma and225// tok::l_paren/tok::r_paren.226//===----------------------------------------------------------------------===//227 228// Note that this commas, parantheses in strings aren't parsed as tok::comma or229// tok::l_paren/tok::r_paren, but why not test them.230 231#define TO_NULL_AND_PRINT(x, str) \232  x = 0; \233  print(str)234 235void macroArgContainsCommaInStringTest() {236  int *a;237  TO_NULL_AND_PRINT(a, "Will this , cause a crash?");238  *a = 5; // expected-warning{{Dereference of null pointer}}239}240 241// CHECK:      <key>macro_expansions</key>242// CHECK-NEXT: <array>243// CHECK-NEXT:  <dict>244// CHECK-NEXT:   <key>location</key>245// CHECK-NEXT:   <dict>246// CHECK-NEXT:    <key>line</key><integer>237</integer>247// CHECK-NEXT:    <key>col</key><integer>3</integer>248// CHECK-NEXT:    <key>file</key><integer>0</integer>249// CHECK-NEXT:   </dict>250// CHECK-NEXT:   <key>name</key><string>TO_NULL_AND_PRINT(a, &quot;Will this , cause a crash?&quot;)</string>251// CHECK-NEXT:   <key>expansion</key><string>a =0;print (&quot;Will this , cause a crash?&quot;)</string>252// CHECK-NEXT:  </dict>253// CHECK-NEXT: </array>254 255void macroArgContainsLParenInStringTest() {256  int *a;257  TO_NULL_AND_PRINT(a, "Will this ( cause a crash?");258  *a = 5; // expected-warning{{Dereference of null pointer}}259}260 261// CHECK:      <key>macro_expansions</key>262// CHECK-NEXT: <array>263// CHECK-NEXT:  <dict>264// CHECK-NEXT:   <key>location</key>265// CHECK-NEXT:   <dict>266// CHECK-NEXT:    <key>line</key><integer>257</integer>267// CHECK-NEXT:    <key>col</key><integer>3</integer>268// CHECK-NEXT:    <key>file</key><integer>0</integer>269// CHECK-NEXT:   </dict>270// CHECK-NEXT:   <key>name</key><string>TO_NULL_AND_PRINT(a, &quot;Will this ( cause a crash?&quot;)</string>271// CHECK-NEXT:   <key>expansion</key><string>a =0;print (&quot;Will this ( cause a crash?&quot;)</string>272// CHECK-NEXT:  </dict>273// CHECK-NEXT: </array>274 275void macroArgContainsRParenInStringTest() {276  int *a;277  TO_NULL_AND_PRINT(a, "Will this ) cause a crash?");278  *a = 5; // expected-warning{{Dereference of null pointer}}279}280 281// CHECK:      <key>macro_expansions</key>282// CHECK-NEXT: <array>283// CHECK-NEXT:  <dict>284// CHECK-NEXT:   <key>location</key>285// CHECK-NEXT:   <dict>286// CHECK-NEXT:    <key>line</key><integer>277</integer>287// CHECK-NEXT:    <key>col</key><integer>3</integer>288// CHECK-NEXT:    <key>file</key><integer>0</integer>289// CHECK-NEXT:   </dict>290// CHECK-NEXT:   <key>name</key><string>TO_NULL_AND_PRINT(a, &quot;Will this ) cause a crash?&quot;)</string>291// CHECK-NEXT:   <key>expansion</key><string>a =0;print (&quot;Will this ) cause a crash?&quot;)</string>292// CHECK-NEXT:  </dict>293// CHECK-NEXT: </array>294 295#define CALL_FUNCTION(funcCall)   \296  funcCall297 298// Function calls do contain both tok::comma and tok::l_paren/tok::r_paren.299 300void macroArgContainsLParenRParenTest() {301  int *a;302  CALL_FUNCTION(setToNull(&a));303  *a = 5; // expected-warning{{Dereference of null pointer}}304}305 306// CHECK:      <key>macro_expansions</key>307// CHECK-NEXT: <array>308// CHECK-NEXT:  <dict>309// CHECK-NEXT:   <key>location</key>310// CHECK-NEXT:   <dict>311// CHECK-NEXT:    <key>line</key><integer>302</integer>312// CHECK-NEXT:    <key>col</key><integer>3</integer>313// CHECK-NEXT:    <key>file</key><integer>0</integer>314// CHECK-NEXT:   </dict>315// CHECK-NEXT:   <key>name</key><string>CALL_FUNCTION(setToNull(&amp;a))</string>316// CHECK-NEXT:   <key>expansion</key><string>setToNull (&amp;a )</string>317// CHECK-NEXT:  </dict>318// CHECK-NEXT: </array>319 320void setToNullAndPrint(int **vptr, const char *str) {321  setToNull(vptr);322  print(str);323}324 325void macroArgContainsCommaLParenRParenTest() {326  int *a;327  CALL_FUNCTION(setToNullAndPrint(&a, "Hello!"));328  *a = 5; // expected-warning{{Dereference of null pointer}}329}330 331// CHECK:      <key>macro_expansions</key>332// CHECK-NEXT: <array>333// CHECK-NEXT:  <dict>334// CHECK-NEXT:   <key>location</key>335// CHECK-NEXT:   <dict>336// CHECK-NEXT:    <key>line</key><integer>327</integer>337// CHECK-NEXT:    <key>col</key><integer>3</integer>338// CHECK-NEXT:    <key>file</key><integer>0</integer>339// CHECK-NEXT:   </dict>340// CHECK-NEXT:   <key>name</key><string>CALL_FUNCTION(setToNullAndPrint(&amp;a, &quot;Hello!&quot;))</string>341// CHECK-NEXT:   <key>expansion</key><string>setToNullAndPrint (&amp;a ,&quot;Hello!&quot;)</string>342// CHECK-NEXT:  </dict>343// CHECK-NEXT: </array>344 345#define CALL_FUNCTION_WITH_TWO_PARAMS(funcCall, param1, param2) \346  funcCall(param1, param2)347 348void macroArgContainsCommaLParenRParenTest2() {349  int *a;350  CALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &a, "Hello!");351  *a = 5; // expected-warning{{Dereference of null pointer}}352}353 354// CHECK:      <key>macro_expansions</key>355// CHECK-NEXT: <array>356// CHECK-NEXT:  <dict>357// CHECK-NEXT:   <key>location</key>358// CHECK-NEXT:   <dict>359// CHECK-NEXT:    <key>line</key><integer>350</integer>360// CHECK-NEXT:    <key>col</key><integer>3</integer>361// CHECK-NEXT:    <key>file</key><integer>0</integer>362// CHECK-NEXT:   </dict>363// CHECK-NEXT:   <key>name</key><string>CALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &amp;a, &quot;Hello!&quot;)</string>364// CHECK-NEXT:   <key>expansion</key><string>setToNullAndPrint (&amp;a ,&quot;Hello!&quot;)</string>365// CHECK-NEXT:  </dict>366// CHECK-NEXT: </array>367 368#define CALL_LAMBDA(l) \369  l()370 371void commaInBracketsTest() {372  int *ptr;373  const char str[] = "Hello!";374  // You need to add parantheses around a lambda expression to compile this,375  // else the comma in the capture will be parsed as divider of macro args.376  CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); }));377  *ptr = 5; // expected-warning{{Dereference of null pointer}}378}379// FIXME: Why does the expansion appear twice?380// CHECK:      <key>macro_expansions</key>381// CHECK-NEXT: <array>382// CHECK-NEXT:  <dict>383// CHECK-NEXT:   <key>location</key>384// CHECK-NEXT:   <dict>385// CHECK-NEXT:    <key>line</key><integer>376</integer>386// CHECK-NEXT:    <key>col</key><integer>3</integer>387// CHECK-NEXT:    <key>file</key><integer>0</integer>388// CHECK-NEXT:   </dict>389// CHECK-NEXT:   <key>name</key><string>CALL_LAMBDA(([&amp;ptr, str] () mutable { TO_NULL(&amp;ptr); }))</string>390// CHECK-NEXT:   <key>expansion</key><string>([&amp;ptr ,str ]()mutable {setToNull (&amp;ptr );})()</string>391// CHECK-NEXT:  </dict>392// CHECK-NEXT:  <dict>393// CHECK-NEXT:   <key>location</key>394// CHECK-NEXT:   <dict>395// CHECK-NEXT:    <key>line</key><integer>376</integer>396// CHECK-NEXT:    <key>col</key><integer>3</integer>397// CHECK-NEXT:    <key>file</key><integer>0</integer>398// CHECK-NEXT:   </dict>399// CHECK-NEXT:   <key>name</key><string>CALL_LAMBDA(([&amp;ptr, str] () mutable { TO_NULL(&amp;ptr); }))</string>400// CHECK-NEXT:   <key>expansion</key><string>([&amp;ptr ,str ]()mutable {setToNull (&amp;ptr );})()</string>401// CHECK-NEXT:  </dict>402// CHECK-NEXT: </array>403 404#define PASTE_CODE(code) \405  code406 407void commaInBracesTest() {408  PASTE_CODE({ // expected-warning{{Dereference of null pointer}}409    // NOTE: If we were to add a new variable here after a comma, we'd get a410    // compilation error, so this test is mainly here to show that this was also411    // investigated.412    //413    // int *ptr = nullptr, a;414    int *ptr = nullptr;415    *ptr = 5;416  })417}418 419// CHECK:        <key>macro_expansions</key>420// CHECK-NEXT:   <array>421// CHECK-NEXT:    <dict>422// CHECK-NEXT:     <key>location</key>423// CHECK-NEXT:     <dict>424// CHECK-NEXT:      <key>line</key><integer>408</integer>425// CHECK-NEXT:      <key>col</key><integer>3</integer>426// CHECK-NEXT:      <key>file</key><integer>0</integer>427// CHECK-NEXT:     </dict>428// CHECK-NEXT:     <key>name</key><string>PASTE_CODE({ // expected-429// CHECK-NEXT:    // NOTE: If we were to add a new variable here after a comma, we&apos;d get a430// CHECK-NEXT:    // compilation error, so this test is mainly here to show that this was also431// CHECK-NEXT:    // investigated.432// CHECK-NEXT:    //433// CHECK-NEXT:    // int *ptr = nullptr, a;434// CHECK-NEXT:    int *ptr = nullptr;435// CHECK-NEXT:    *ptr = 5;436// CHECK-NEXT:  })</string>437// CHECK-NEXT:     <key>expansion</key><string>{int *ptr =nullptr ;*ptr =5;}</string>438// CHECK-NEXT:    </dict>439// CHECK-NEXT:   </array>440 441// Example taken from442// https://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html#Macro-Arguments.443 444#define POTENTIALLY_EMPTY_PARAM(x, y) \445  x;                                  \446  y = nullptr447 448void emptyParamTest() {449  int *ptr;450 451  POTENTIALLY_EMPTY_PARAM(,ptr);452  *ptr = 5; // expected-warning{{Dereference of null pointer}}453}454 455// CHECK:      <key>macro_expansions</key>456// CHECK-NEXT: <array>457// CHECK-NEXT:  <dict>458// CHECK-NEXT:   <key>location</key>459// CHECK-NEXT:   <dict>460// CHECK-NEXT:    <key>line</key><integer>451</integer>461// CHECK-NEXT:    <key>col</key><integer>3</integer>462// CHECK-NEXT:    <key>file</key><integer>0</integer>463// CHECK-NEXT:   </dict>464// CHECK-NEXT:   <key>name</key><string>POTENTIALLY_EMPTY_PARAM(,ptr)</string>465// CHECK-NEXT:   <key>expansion</key><string>;ptr =nullptr </string>466// CHECK-NEXT:  </dict>467// CHECK-NEXT: </array>468 469#define NESTED_EMPTY_PARAM(a, b) \470  POTENTIALLY_EMPTY_PARAM(a, b);471 472 473void nestedEmptyParamTest() {474  int *ptr;475 476  NESTED_EMPTY_PARAM(, ptr);477  *ptr = 5; // expected-warning{{Dereference of null pointer}}478}479 480// CHECK:      <key>macro_expansions</key>481// CHECK-NEXT: <array>482// CHECK-NEXT:  <dict>483// CHECK-NEXT:   <key>location</key>484// CHECK-NEXT:   <dict>485// CHECK-NEXT:    <key>line</key><integer>476</integer>486// CHECK-NEXT:    <key>col</key><integer>3</integer>487// CHECK-NEXT:    <key>file</key><integer>0</integer>488// CHECK-NEXT:   </dict>489// CHECK-NEXT:   <key>name</key><string>NESTED_EMPTY_PARAM(, ptr)</string>490// CHECK-NEXT:   <key>expansion</key><string>;ptr =nullptr ;</string>491// CHECK-NEXT:  </dict>492// CHECK-NEXT: </array>493 494#define CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(func, param) \495  CALL_FUNCTION(func(param))496 497void lParenRParenInNestedMacro() {498  int *ptr;499  CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &ptr);500  *ptr = 5; // expected-warning{{Dereference of null pointer}}501}502 503// CHECK:      <key>macro_expansions</key>504// CHECK-NEXT: <array>505// CHECK-NEXT:  <dict>506// CHECK-NEXT:   <key>location</key>507// CHECK-NEXT:   <dict>508// CHECK-NEXT:    <key>line</key><integer>499</integer>509// CHECK-NEXT:    <key>col</key><integer>3</integer>510// CHECK-NEXT:    <key>file</key><integer>0</integer>511// CHECK-NEXT:   </dict>512// CHECK-NEXT:   <key>name</key><string>CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &amp;ptr)</string>513// CHECK-NEXT:   <key>expansion</key><string>setToNull (&amp;ptr )</string>514// CHECK-NEXT:  </dict>515// CHECK-NEXT: </array>516 517//===----------------------------------------------------------------------===//518// Tests for variadic macro arguments.519//===----------------------------------------------------------------------===//520 521template <typename ...Args>522void variadicFunc(Args ...args);523 524#define VARIADIC_SET_TO_NULL(ptr, ...) \525  ptr = nullptr;                       \526  variadicFunc(__VA_ARGS__)527 528void variadicMacroArgumentTest() {529  int *ptr;530  VARIADIC_SET_TO_NULL(ptr, 1, 5, "haha!");531  *ptr = 5; // expected-warning{{Dereference of null pointer}}532}533 534// CHECK:      <key>macro_expansions</key>535// CHECK-NEXT: <array>536// CHECK-NEXT:  <dict>537// CHECK-NEXT:   <key>location</key>538// CHECK-NEXT:   <dict>539// CHECK-NEXT:    <key>line</key><integer>530</integer>540// CHECK-NEXT:    <key>col</key><integer>3</integer>541// CHECK-NEXT:    <key>file</key><integer>0</integer>542// CHECK-NEXT:   </dict>543// CHECK-NEXT:   <key>name</key><string>VARIADIC_SET_TO_NULL(ptr, 1, 5, &quot;haha!&quot;)</string>544// CHECK-NEXT:   <key>expansion</key><string>ptr =nullptr ;variadicFunc (1,5,&quot;haha!&quot;)</string>545// CHECK-NEXT:  </dict>546// CHECK-NEXT: </array>547 548void variadicMacroArgumentWithoutAnyArgumentTest() {549  int *ptr;550  // Not adding a single parameter to ... is silly (and also causes a551  // preprocessor warning), but is not an excuse to crash on it.552  VARIADIC_SET_TO_NULL(ptr);553  *ptr = 5; // expected-warning{{Dereference of null pointer}}554}555 556// CHECK:      <key>macro_expansions</key>557// CHECK-NEXT: <array>558// CHECK-NEXT:  <dict>559// CHECK-NEXT:   <key>location</key>560// CHECK-NEXT:   <dict>561// CHECK-NEXT:    <key>line</key><integer>552</integer>562// CHECK-NEXT:    <key>col</key><integer>3</integer>563// CHECK-NEXT:    <key>file</key><integer>0</integer>564// CHECK-NEXT:   </dict>565// CHECK-NEXT:   <key>name</key><string>VARIADIC_SET_TO_NULL(ptr)</string>566// CHECK-NEXT:   <key>expansion</key><string>ptr =nullptr ;variadicFunc ()</string>567// CHECK-NEXT:  </dict>568// CHECK-NEXT: </array>569 570//===----------------------------------------------------------------------===//571// Tests for # and ##.572//===----------------------------------------------------------------------===//573 574#define DECLARE_FUNC_AND_SET_TO_NULL(funcName, ptr) \575  void generated_##funcName();                      \576  ptr = nullptr;577 578void hashHashOperatorTest() {579  int *ptr;580  DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr);581  *ptr = 5; // expected-warning{{Dereference of null pointer}}582}583 584// CHECK:      <key>macro_expansions</key>585// CHECK-NEXT: <array>586// CHECK-NEXT:  <dict>587// CHECK-NEXT:   <key>location</key>588// CHECK-NEXT:   <dict>589// CHECK-NEXT:    <key>line</key><integer>580</integer>590// CHECK-NEXT:    <key>col</key><integer>3</integer>591// CHECK-NEXT:    <key>file</key><integer>0</integer>592// CHECK-NEXT:   </dict>593// CHECK-NEXT:   <key>name</key><string>DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr)</string>594// CHECK-NEXT:   <key>expansion</key><string>void generated_whatever ();ptr =nullptr ;</string>595// CHECK-NEXT:  </dict>596// CHECK-NEXT: </array>597 598void macroArgContainsHashHashInStringTest() {599  int *a;600  TO_NULL_AND_PRINT(a, "Will this ## cause a crash?");601  *a = 5; // expected-warning{{Dereference of null pointer}}602}603 604// CHECK:      <key>macro_expansions</key>605// CHECK-NEXT: <array>606// CHECK-NEXT:  <dict>607// CHECK-NEXT:   <key>location</key>608// CHECK-NEXT:   <dict>609// CHECK-NEXT:    <key>line</key><integer>600</integer>610// CHECK-NEXT:    <key>col</key><integer>3</integer>611// CHECK-NEXT:    <key>file</key><integer>0</integer>612// CHECK-NEXT:   </dict>613// CHECK-NEXT:   <key>name</key><string>TO_NULL_AND_PRINT(a, &quot;Will this ## cause a crash?&quot;)</string>614// CHECK-NEXT:   <key>expansion</key><string>a =0;print (&quot;Will this ## cause a crash?&quot;)</string>615// CHECK-NEXT:  </dict>616// CHECK-NEXT: </array>617 618#define PRINT_STR(str, ptr) \619  print(#str);              \620  ptr = nullptr621 622void hashOperatorTest() {623  int *ptr;624  PRINT_STR(Hello, ptr);625  *ptr = 5; // expected-warning{{Dereference of null pointer}}626}627 628// CHECK:      <key>macro_expansions</key>629// CHECK-NEXT: <array>630// CHECK-NEXT:  <dict>631// CHECK-NEXT:   <key>location</key>632// CHECK-NEXT:   <dict>633// CHECK-NEXT:    <key>line</key><integer>624</integer>634// CHECK-NEXT:    <key>col</key><integer>3</integer>635// CHECK-NEXT:    <key>file</key><integer>0</integer>636// CHECK-NEXT:   </dict>637// CHECK-NEXT:   <key>name</key><string>PRINT_STR(Hello, ptr)</string>638// CHECK-NEXT:   <key>expansion</key><string>print (&quot;Hello&quot;);ptr =nullptr </string>639// CHECK-NEXT:  </dict>640// CHECK-NEXT: </array>641 642void macroArgContainsHashInStringTest() {643  int *a;644  TO_NULL_AND_PRINT(a, "Will this # cause a crash?");645  *a = 5; // expected-warning{{Dereference of null pointer}}646}647 648// CHECK:      <key>macro_expansions</key>649// CHECK-NEXT: <array>650// CHECK-NEXT:  <dict>651// CHECK-NEXT:   <key>location</key>652// CHECK-NEXT:   <dict>653// CHECK-NEXT:    <key>line</key><integer>644</integer>654// CHECK-NEXT:    <key>col</key><integer>3</integer>655// CHECK-NEXT:    <key>file</key><integer>0</integer>656// CHECK-NEXT:   </dict>657// CHECK-NEXT:   <key>name</key><string>TO_NULL_AND_PRINT(a, &quot;Will this # cause a crash?&quot;)</string>658// CHECK-NEXT:   <key>expansion</key><string>a =0;print (&quot;Will this # cause a crash?&quot;)</string>659// CHECK-NEXT:  </dict>660// CHECK-NEXT: </array>661 662//===----------------------------------------------------------------------===//663// Tests for more complex macro expansions.664//665// We won't cover anything that wasn't covered up to this point, but rather666// show more complex, macros with deeper nesting, more arguments (some unused)667// and so on.668//===----------------------------------------------------------------------===//669 670#define IF(Condition) \671  if ( Condition )672 673#define L_BRACE {674#define R_BRACE }675#define LESS <676#define GREATER >677#define EQUALS =678#define SEMICOLON ;679#define NEGATIVE -680#define RETURN return681#define ZERO 0682 683#define EUCLIDEAN_ALGORITHM(A, B)                                              \684  IF(A LESS ZERO) L_BRACE                                                      \685    A EQUALS NEGATIVE A SEMICOLON                                              \686  R_BRACE                                                                      \687  IF(B LESS ZERO) L_BRACE                                                      \688    B EQUALS NEGATIVE B SEMICOLON                                              \689  R_BRACE                                                                      \690                                                                               \691  /* This is where a while loop would be, but that seems to be too complex */  \692  /* for the analyzer just yet. Let's just pretend that this algorithm     */  \693  /* works.                                                                */  \694                                                                               \695  RETURN B / (B - B) SEMICOLON696 697int getLowestCommonDenominator(int A, int B) {698  EUCLIDEAN_ALGORITHM(A, B) // expected-warning{{Division by zero}}699}700 701void testVeryComplexAlgorithm() {702  int tmp = 8 / (getLowestCommonDenominator(5, 7) - 1);703  print(&tmp);704}705 706// CHECK:      <key>macro_expansions</key>707// CHECK-NEXT: <array>708// CHECK-NEXT:  <dict>709// CHECK-NEXT:   <key>location</key>710// CHECK-NEXT:   <dict>711// CHECK-NEXT:    <key>line</key><integer>698</integer>712// CHECK-NEXT:    <key>col</key><integer>3</integer>713// CHECK-NEXT:    <key>file</key><integer>0</integer>714// CHECK-NEXT:   </dict>715// CHECK-NEXT:   <key>name</key><string>EUCLIDEAN_ALGORITHM(A, B)</string>716// CHECK-NEXT:   <key>expansion</key><string>if (A &lt;0){A =-A ;}if (B &lt;0){B =-B ;}return B /(B -B );</string>717// CHECK-NEXT:  </dict>718// CHECK-NEXT: </array>719 720#define YET_ANOTHER_SET_TO_NULL(x, y, z)   \721  print((void *) x);                       \722  print((void *) y);                       \723  z = nullptr;724 725#define DO_NOTHING(str) str726#define DO_NOTHING2(str2) DO_NOTHING(str2)727 728void test() {729  int *ptr;730  YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr);731  *ptr = 5; // expected-warning{{Dereference of null pointer}}732}733 734// CHECK:      <key>macro_expansions</key>735// CHECK-NEXT: <array>736// CHECK-NEXT:  <dict>737// CHECK-NEXT:   <key>location</key>738// CHECK-NEXT:   <dict>739// CHECK-NEXT:    <key>line</key><integer>730</integer>740// CHECK-NEXT:    <key>col</key><integer>3</integer>741// CHECK-NEXT:    <key>file</key><integer>0</integer>742// CHECK-NEXT:   </dict>743// CHECK-NEXT:   <key>name</key><string>YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2(&quot;Remember the Vasa&quot;), ptr)</string>744// CHECK-NEXT:   <key>expansion</key><string>print ((void *)5);print ((void *)&quot;Remember the Vasa&quot;);ptr =nullptr ;</string>745// CHECK-NEXT:  </dict>746// CHECK-NEXT: </array>747 748int garbage_value;749 750#define REC_MACRO_FUNC(REC_MACRO_PARAM) garbage_##REC_MACRO_PARAM751#define value REC_MACRO_FUNC(value)752 753void recursiveMacroUser() {754  if (value == 0)755    1 / value; // expected-warning{{Division by zero}}756               // expected-warning@-1{{expression result unused}}757}758 759// CHECK:      <key>macro_expansions</key>760// CHECK-NEXT: <array>761// CHECK-NEXT:  <dict>762// CHECK-NEXT:   <key>location</key>763// CHECK-NEXT:   <dict>764// CHECK-NEXT:    <key>line</key><integer>754</integer>765// CHECK-NEXT:    <key>col</key><integer>7</integer>766// CHECK-NEXT:    <key>file</key><integer>0</integer>767// CHECK-NEXT:   </dict>768// CHECK-NEXT:   <key>name</key><string>value</string>769// CHECK-NEXT:   <key>expansion</key><string>garbage_value </string>770// CHECK-NEXT:  </dict>771// CHECK-NEXT: </array>772 773#define FOO(x) int foo() { return x; }774#define APPLY_ZERO1(function) function(0)775 776APPLY_ZERO1(FOO)777void useZeroApplier1() { (void)(1 / foo()); } // expected-warning{{Division by zero}}778 779// CHECK:      <key>macro_expansions</key>780// CHECK-NEXT: <array>781// CHECK-NEXT:  <dict>782// CHECK-NEXT:   <key>location</key>783// CHECK-NEXT:   <dict>784// CHECK-NEXT:    <key>line</key><integer>776</integer>785// CHECK-NEXT:    <key>col</key><integer>1</integer>786// CHECK-NEXT:    <key>file</key><integer>0</integer>787// CHECK-NEXT:   </dict>788// CHECK-NEXT:   <key>name</key><string>APPLY_ZERO1(FOO)</string>789// CHECK-NEXT:   <key>expansion</key><string>int foo (){return 0;}</string>790// CHECK-NEXT:  </dict>791// CHECK-NEXT: </array>792 793#define BAR(x) int bar() { return x; }794#define APPLY_ZERO2 BAR(0)795 796APPLY_ZERO2797void useZeroApplier2() { (void)(1 / bar()); } // expected-warning{{Division by zero}}798 799// CHECK:      <key>macro_expansions</key>800// CHECK-NEXT: <array>801// CHECK-NEXT:  <dict>802// CHECK-NEXT:   <key>location</key>803// CHECK-NEXT:   <dict>804// CHECK-NEXT:    <key>line</key><integer>796</integer>805// CHECK-NEXT:    <key>col</key><integer>1</integer>806// CHECK-NEXT:    <key>file</key><integer>0</integer>807// CHECK-NEXT:   </dict>808// CHECK-NEXT:   <key>name</key><string>APPLY_ZERO2</string>809// CHECK-NEXT:   <key>expansion</key><string>int bar (){return 0;}</string>810// CHECK-NEXT:  </dict>811// CHECK-NEXT: </array>812 813void foo(int &x, const char *str);814 815#define PARAMS_RESOLVE_TO_VA_ARGS(i, fmt) foo(i, fmt); \816  i = 0;817#define DISPATCH(...) PARAMS_RESOLVE_TO_VA_ARGS(__VA_ARGS__);818 819void mulitpleParamsResolveToVA_ARGS(void) {820  int x = 1;821  DISPATCH(x, "LF1M healer");822  (void)(10 / x); // expected-warning{{Division by zero}}823}824 825// CHECK:      <key>macro_expansions</key>826// CHECK-NEXT: <array>827// CHECK-NEXT:  <dict>828// CHECK-NEXT:   <key>location</key>829// CHECK-NEXT:   <dict>830// CHECK-NEXT:    <key>line</key><integer>821</integer>831// CHECK-NEXT:    <key>col</key><integer>3</integer>832// CHECK-NEXT:    <key>file</key><integer>0</integer>833// CHECK-NEXT:   </dict>834// CHECK-NEXT:   <key>name</key><string>DISPATCH(x, &quot;LF1M healer&quot;)</string>835// CHECK-NEXT:   <key>expansion</key><string>foo (x ,&quot;LF1M healer&quot;);x =0;;</string>836// CHECK-NEXT:  </dict>837// CHECK-NEXT: </array>838 839void variadicCFunction(int &x, const char *str, ...);840 841#define CONCAT_VA_ARGS(i, fmt, ...) variadicCFunction(i, fmt, ##__VA_ARGS__); \842  i = 0;843 844void concatVA_ARGS(void) {845  int x = 1;846  CONCAT_VA_ARGS(x, "You need to construct additional pylons.", 'c', 9);847  (void)(10 / x); // expected-warning{{Division by zero}}848}849 850// CHECK:      <key>macro_expansions</key>851// CHECK-NEXT: <array>852// CHECK-NEXT:  <dict>853// CHECK-NEXT:   <key>location</key>854// CHECK-NEXT:   <dict>855// CHECK-NEXT:    <key>line</key><integer>846</integer>856// CHECK-NEXT:    <key>col</key><integer>3</integer>857// CHECK-NEXT:    <key>file</key><integer>0</integer>858// CHECK-NEXT:   </dict>859// CHECK-NEXT:   <key>name</key><string>CONCAT_VA_ARGS(x, &quot;You need to construct additional pylons.&quot;, &apos;c&apos;, 9)</string>860// CHECK-NEXT:   <key>expansion</key><string>variadicCFunction (x ,&quot;You need to construct additional pylons.&quot;,&apos;c&apos;,9);x =0;</string>861// CHECK-NEXT:  </dict>862// CHECK-NEXT: </array>863 864void concatVA_ARGSEmpty(void) {865  int x = 1;866  CONCAT_VA_ARGS(x, "You need to construct");867  (void)(10 / x); // expected-warning{{Division by zero}}868}869 870// CHECK:      <key>macro_expansions</key>871// CHECK-NEXT: <array>872// CHECK-NEXT:  <dict>873// CHECK-NEXT:   <key>location</key>874// CHECK-NEXT:   <dict>875// CHECK-NEXT:    <key>line</key><integer>866</integer>876// CHECK-NEXT:    <key>col</key><integer>3</integer>877// CHECK-NEXT:    <key>file</key><integer>0</integer>878// CHECK-NEXT:   </dict>879// CHECK-NEXT:   <key>name</key><string>CONCAT_VA_ARGS(x, &quot;You need to construct&quot;)</string>880// CHECK-NEXT:   <key>expansion</key><string>variadicCFunction (x ,&quot;You need to construct&quot;);x =0;</string>881// CHECK-NEXT:  </dict>882// CHECK-NEXT: </array>883 884#define STRINGIFIED_VA_ARGS(i, fmt, ...) variadicCFunction(i, fmt, #__VA_ARGS__); \885  i = 0;886 887void stringifyVA_ARGS(void) {888  int x = 1;889  STRINGIFIED_VA_ARGS(x, "Additional supply depots required.", 'a', 10);890  (void)(10 / x); // expected-warning{{Division by zero}}891}892 893// CHECK:      <key>macro_expansions</key>894// CHECK-NEXT: <array>895// CHECK-NEXT:  <dict>896// CHECK-NEXT:   <key>location</key>897// CHECK-NEXT:   <dict>898// CHECK-NEXT:    <key>line</key><integer>889</integer>899// CHECK-NEXT:    <key>col</key><integer>3</integer>900// CHECK-NEXT:    <key>file</key><integer>0</integer>901// CHECK-NEXT:   </dict>902// CHECK-NEXT:   <key>name</key><string>STRINGIFIED_VA_ARGS(x, &quot;Additional supply depots required.&quot;, &apos;a&apos;, 10)</string>903// CHECK-NEXT:   <key>expansion</key><string>variadicCFunction (x ,&quot;Additional supply depots required.&quot;,&quot;&apos;a&apos;, 10&quot;);x =0;</string>904// CHECK-NEXT:  </dict>905// CHECK-NEXT: </array>906 907void stringifyVA_ARGSEmpty(void) {908  int x = 1;909  STRINGIFIED_VA_ARGS(x, "Additional supply depots required.");910  (void)(10 / x); // expected-warning{{Division by zero}}911}912 913// CHECK:      <key>macro_expansions</key>914// CHECK-NEXT: <array>915// CHECK-NEXT:  <dict>916// CHECK-NEXT:   <key>location</key>917// CHECK-NEXT:   <dict>918// CHECK-NEXT:    <key>line</key><integer>909</integer>919// CHECK-NEXT:    <key>col</key><integer>3</integer>920// CHECK-NEXT:    <key>file</key><integer>0</integer>921// CHECK-NEXT:   </dict>922// CHECK-NEXT:   <key>name</key><string>STRINGIFIED_VA_ARGS(x, &quot;Additional supply depots required.&quot;)</string>923// CHECK-NEXT:   <key>expansion</key><string>variadicCFunction (x ,&quot;Additional supply depots required.&quot;,&quot;&quot;);x =0;</string>924// CHECK-NEXT:  </dict>925// CHECK-NEXT: </array>926 927// bz44493: Support GNU-style named variadic arguments in plister928#define BZ44493_GNUVA(i, args...)  --(i);929 930int bz44493(void) {931  int a = 2;932  BZ44493_GNUVA(a);933  BZ44493_GNUVA(a, "arg2");934  (void)(10 / a); // expected-warning{{Division by zero}}935  return 0;936}937 938// CHECK:      <key>macro_expansions</key>939// CHECK-NEXT: <array>940// CHECK-NEXT:  <dict>941// CHECK-NEXT:   <key>location</key>942// CHECK-NEXT:   <dict>943// CHECK-NEXT:    <key>line</key><integer>933</integer>944// CHECK-NEXT:    <key>col</key><integer>3</integer>945// CHECK-NEXT:    <key>file</key><integer>0</integer>946// CHECK-NEXT:   </dict>947// CHECK-NEXT:   <key>name</key><string>BZ44493_GNUVA(a, &quot;arg2&quot;)</string>948// CHECK-NEXT:   <key>expansion</key><string>--(a );</string>949// CHECK-NEXT:  </dict>950// CHECK-NEXT: </array>951