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