Home | History | Annotate | Download | only in inlining
      1 // RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
      2 // RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -verify -DSUPPRESSED=1 %s
      3 // RUN: %clang_cc1 -analyze -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
      4 
      5 int opaquePropertyCheck(void *object);
      6 int coin();
      7 
      8 int *getNull() {
      9   return 0;
     10 }
     11 
     12 int* getPtr();
     13 
     14 int *dynCastToInt(void *ptr) {
     15   if (opaquePropertyCheck(ptr))
     16     return (int *)ptr;
     17   return 0;
     18 }
     19 
     20 int *dynCastOrNull(void *ptr) {
     21   if (!ptr)
     22     return 0;
     23   if (opaquePropertyCheck(ptr))
     24     return (int *)ptr;
     25   return 0;
     26 }
     27 
     28 
     29 void testDynCast(void *p) {
     30   int *casted = dynCastToInt(p);
     31   *casted = 1;
     32 #ifndef SUPPRESSED
     33   // expected-warning@-2 {{Dereference of null pointer}}
     34 #endif
     35 }
     36 
     37 void testDynCastOrNull(void *p) {
     38   int *casted = dynCastOrNull(p);
     39   *casted = 1;
     40 #ifndef SUPPRESSED
     41   // expected-warning@-2 {{Dereference of null pointer}}
     42 #endif
     43 }
     44 
     45 
     46 void testBranch(void *p) {
     47   int *casted;
     48 
     49   // Although the report will be suppressed on one branch, it should still be
     50   // valid on the other.
     51   if (coin()) {
     52     casted = dynCastToInt(p);
     53   } else {
     54     if (p)
     55       return;
     56     casted = (int *)p;
     57   }
     58 
     59   *casted = 1; // expected-warning {{Dereference of null pointer}}
     60 }
     61 
     62 void testBranchReversed(void *p) {
     63   int *casted;
     64 
     65   // Although the report will be suppressed on one branch, it should still be
     66   // valid on the other.
     67   if (coin()) {
     68     if (p)
     69       return;
     70     casted = (int *)p;
     71   } else {
     72     casted = dynCastToInt(p);
     73   }
     74 
     75   *casted = 1; // expected-warning {{Dereference of null pointer}}
     76 }
     77 
     78 void testMultipleStore(void *p) {
     79   int *casted = 0;
     80   casted = dynCastToInt(p);
     81   *casted = 1;
     82 #ifndef SUPPRESSED
     83   // expected-warning@-2 {{Dereference of null pointer}}
     84 #endif
     85 }
     86 
     87 // Test that div by zero does not get suppressed. This is a policy choice.
     88 int retZero() {
     89   return 0;
     90 }
     91 int triggerDivZero () {
     92   int y = retZero();
     93   return 5/y; // expected-warning {{Division by zero}}
     94 }
     95 
     96 // Treat a function-like macro similarly to an inlined function, so suppress
     97 // warnings along paths resulting from inlined checks.
     98 #define MACRO_WITH_CHECK(a) ( ((a) != 0) ? *a : 17)
     99 void testInlineCheckInMacro(int *p) {
    100   int i = MACRO_WITH_CHECK(p);
    101   (void)i;
    102 
    103   *p = 1; // no-warning
    104 }
    105 
    106 #define MACRO_WITH_NESTED_CHECK(a) ( { int j = MACRO_WITH_CHECK(a); j; } )
    107 void testInlineCheckInNestedMacro(int *p) {
    108   int i = MACRO_WITH_NESTED_CHECK(p);
    109   (void)i;
    110 
    111   *p = 1; // no-warning
    112 }
    113 
    114 // If there is a check in a macro that is not function-like, don't treat
    115 // it like a function so don't suppress.
    116 #define NON_FUNCTION_MACRO_WITH_CHECK ( ((p) != 0) ? *p : 17)
    117 void testNonFunctionMacro(int *p) {
    118   int i = NON_FUNCTION_MACRO_WITH_CHECK ;
    119   (void)i;
    120 
    121   *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
    122 }
    123 
    124 
    125 // This macro will dereference its argument if the argument is NULL.
    126 #define MACRO_WITH_ERROR(a) ( ((a) != 0) ? 0 : *a)
    127 void testErrorInMacro(int *p) {
    128   int i = MACRO_WITH_ERROR(p); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
    129   (void)i;
    130 }
    131 
    132 // Here the check (the "if") is not in a macro, so we should still warn.
    133 #define MACRO_IN_GUARD(a) (!(a))
    134 void testMacroUsedAsGuard(int *p) {
    135   if (MACRO_IN_GUARD(p))
    136     *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
    137 }
    138 
    139 // When a nil case split is introduced in a macro and the macro is in a guard,
    140 // we still shouldn't warn.
    141 int isNull(int *p);
    142 int isEqual(int *p, int *q);
    143 #define ISNULL(ptr)    ((ptr) == 0 || isNull(ptr))
    144 #define ISEQUAL(a, b)    ((int *)(a) == (int *)(b) || (ISNULL(a) && ISNULL(b)) || isEqual(a,b))
    145 #define ISNOTEQUAL(a, b)   (!ISEQUAL(a, b))
    146 void testNestedDisjunctiveMacro(int *p, int *q) {
    147   if (ISNOTEQUAL(p,q)) {
    148     *p = 1; // no-warning
    149     *q = 1; // no-warning
    150   }
    151 
    152   *p = 1; // no-warning
    153   *q = 1; // no-warning
    154 }
    155 
    156 void testNestedDisjunctiveMacro2(int *p, int *q) {
    157   if (ISEQUAL(p,q)) {
    158     return;
    159   }
    160 
    161   *p = 1; // no-warning
    162   *q = 1; // no-warning
    163 }
    164 
    165 
    166 // Here the check is entirely in non-macro code even though the code itself
    167 // is a macro argument.
    168 #define MACRO_DO_IT(a) (a)
    169 void testErrorInArgument(int *p) {
    170   int i = MACRO_DO_IT((p ? 0 : *p)); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}c
    171   (void)i;
    172 }
    173 
    174 // --------------------------
    175 // "Suppression suppression"
    176 // --------------------------
    177 
    178 void testDynCastOrNullOfNull() {
    179   // Don't suppress when one of the arguments is NULL.
    180   int *casted = dynCastOrNull(0);
    181   *casted = 1;
    182 #if !SUPPRESSED || NULL_ARGS
    183   // expected-warning@-2 {{Dereference of null pointer}}
    184 #endif
    185 }
    186 
    187 void testDynCastOfNull() {
    188   // Don't suppress when one of the arguments is NULL.
    189   int *casted = dynCastToInt(0);
    190   *casted = 1;
    191 #if !SUPPRESSED || NULL_ARGS
    192   // expected-warning@-2 {{Dereference of null pointer}}
    193 #endif
    194 }
    195 
    196 int *lookUpInt(int unused) {
    197   if (coin())
    198     return 0;
    199   static int x;
    200   return &x;
    201 }
    202 
    203 void testZeroIsNotNull() {
    204   // /Do/ suppress when the argument is 0 (an integer).
    205   int *casted = lookUpInt(0);
    206   *casted = 1;
    207 #ifndef SUPPRESSED
    208   // expected-warning@-2 {{Dereference of null pointer}}
    209 #endif
    210 }
    211 
    212 void testTrackNull() {
    213   // /Do/ suppress if the null argument came from another call returning null.
    214   int *casted = dynCastOrNull(getNull());
    215   *casted = 1;
    216 #ifndef SUPPRESSED
    217   // expected-warning@-2 {{Dereference of null pointer}}
    218 #endif
    219 }
    220 
    221 void testTrackNullVariable() {
    222   // /Do/ suppress if the null argument came from another call returning null.
    223   int *ptr;
    224   ptr = getNull();
    225   int *casted = dynCastOrNull(ptr);
    226   *casted = 1;
    227 #ifndef SUPPRESSED
    228   // expected-warning@-2 {{Dereference of null pointer}}
    229 #endif
    230 }
    231 
    232 void inlinedIsDifferent(int inlined) {
    233   int i;
    234 
    235   // We were erroneously picking up the inner stack frame's initialization,
    236   // even though the error occurs in the outer stack frame!
    237   int *p = inlined ? &i : getNull();
    238 
    239   if (!inlined)
    240     inlinedIsDifferent(1);
    241 
    242   *p = 1;
    243 #ifndef SUPPRESSED
    244   // expected-warning@-2 {{Dereference of null pointer}}
    245 #endif
    246 }
    247 
    248 void testInlinedIsDifferent() {
    249   // <rdar://problem/13787723>
    250   inlinedIsDifferent(0);
    251 }
    252 
    253 
    254 // ---------------------------------------
    255 // FALSE NEGATIVES (over-suppression)
    256 // ---------------------------------------
    257 
    258 void testNoArguments() {
    259   // In this case the function has no branches, and MUST return null.
    260   int *casted = getNull();
    261   *casted = 1;
    262 #ifndef SUPPRESSED
    263   // expected-warning@-2 {{Dereference of null pointer}}
    264 #endif
    265 }
    266 
    267 int *getNullIfNonNull(void *input) {
    268   if (input)
    269     return 0;
    270   static int x;
    271   return &x;
    272 }
    273 
    274 void testKnownPath(void *input) {
    275   if (!input)
    276     return;
    277 
    278   // In this case we have a known value for the argument, and thus the path
    279   // through the function doesn't ever split.
    280   int *casted = getNullIfNonNull(input);
    281   *casted = 1;
    282 #ifndef SUPPRESSED
    283   // expected-warning@-2 {{Dereference of null pointer}}
    284 #endif
    285 }
    286 
    287 int *alwaysReturnNull(void *input) {
    288   if (opaquePropertyCheck(input))
    289     return 0;
    290   return 0;
    291 }
    292 
    293 void testAlwaysReturnNull(void *input) {
    294   // In this case all paths out of the function return 0, but they are all
    295   // dominated by a branch whose condition we don't know!
    296   int *casted = alwaysReturnNull(input);
    297   *casted = 1;
    298 #ifndef SUPPRESSED
    299   // expected-warning@-2 {{Dereference of null pointer}}
    300 #endif
    301 }
    302 
    303 int derefArg(int *p) {
    304 	return *p;
    305 #ifndef SUPPRESSED
    306   // expected-warning@-2 {{Dereference of null pointer}}
    307 #endif
    308 }
    309 void ternaryArg(char cond) {
    310 	static int x;
    311 	derefArg(cond ? &x : getNull());
    312 }
    313 
    314 int derefArgCast(char *p) {
    315 	return *p;
    316 #ifndef SUPPRESSED
    317   // expected-warning@-2 {{Dereference of null pointer}}
    318 #endif
    319 }
    320 void ternaryArgCast(char cond) {
    321 	static int x;
    322 	derefArgCast((char*)((unsigned)cond ? &x : getNull()));
    323 }
    324 
    325 int derefAssignment(int *p) {
    326 	return *p;
    327 #ifndef SUPPRESSED
    328   // expected-warning@-2 {{Dereference of null pointer}}
    329 #endif
    330 }
    331 
    332 void ternaryAssignment(char cond) {
    333   static int x;
    334   int *p = cond ? getNull() : getPtr();
    335   derefAssignment(p);
    336 }
    337 
    338 int *retNull(char cond) {
    339   static int x;
    340   return cond ? &x : getNull();
    341 }
    342 int ternaryRetNull(char cond) {
    343   int *p = retNull(cond);
    344   return *p;
    345 #ifndef SUPPRESSED
    346   // expected-warning@-2 {{Dereference of null pointer}}
    347 #endif
    348 }
    349 
    350 // Test suppression of nested conditional operators.
    351 int testConditionalOperatorSuppress(int x) {
    352   return *(x ? getNull() : getPtr());
    353 #ifndef SUPPRESSED
    354   // expected-warning@-2 {{Dereference of null pointer}}
    355 #endif
    356 }
    357 int testNestedConditionalOperatorSuppress(int x) {
    358   return *(x ? (x ? getNull() : getPtr()) : getPtr());
    359 #ifndef SUPPRESSED
    360   // expected-warning@-2 {{Dereference of null pointer}}
    361 #endif
    362 }
    363 int testConditionalOperator(int x) {
    364   return *(x ? 0 : getPtr()); // expected-warning {{Dereference of null pointer}}
    365 }
    366 int testNestedConditionalOperator(int x) {
    367   return *(x ? (x ? 0 : getPtr()) : getPtr()); // expected-warning {{Dereference of null pointer}}
    368 }
    369 
    370 int testConditionalOperatorSuppressFloatCond(float x) {
    371   return *(x ? getNull() : getPtr());
    372 #ifndef SUPPRESSED
    373   // expected-warning@-2 {{Dereference of null pointer}}
    374 #endif
    375 }
    376 
    377