// RUN: %clang_analyze_cc1 -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s // RUN: %clang_analyze_cc1 -analyzer-eagerly-assume -analyzer-checker=core -verify -DSUPPRESSED=1 %s // RUN: %clang_analyze_cc1 -analyzer-eagerly-assume -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s int opaquePropertyCheck(void *object); int coin(); int *getNull() { return 0; } int* getPtr(); int *dynCastToInt(void *ptr) { if (opaquePropertyCheck(ptr)) return (int *)ptr; return 0; } int *dynCastOrNull(void *ptr) { if (!ptr) return 0; if (opaquePropertyCheck(ptr)) return (int *)ptr; return 0; } void testDynCast(void *p) { int *casted = dynCastToInt(p); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void testDynCastOrNull(void *p) { int *casted = dynCastOrNull(p); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void testBranch(void *p) { int *casted; // Although the report will be suppressed on one branch, it should still be // valid on the other. if (coin()) { casted = dynCastToInt(p); } else { if (p) return; casted = (int *)p; } *casted = 1; // expected-warning {{Dereference of null pointer}} } void testBranchReversed(void *p) { int *casted; // Although the report will be suppressed on one branch, it should still be // valid on the other. if (coin()) { if (p) return; casted = (int *)p; } else { casted = dynCastToInt(p); } *casted = 1; // expected-warning {{Dereference of null pointer}} } void testMultipleStore(void *p) { int *casted = 0; casted = dynCastToInt(p); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } // Test that div by zero does not get suppressed. This is a policy choice. int retZero() { return 0; } int triggerDivZero () { int y = retZero(); return 5/y; // expected-warning {{Division by zero}} } // Treat a function-like macro similarly to an inlined function, so suppress // warnings along paths resulting from inlined checks. #define MACRO_WITH_CHECK(a) ( ((a) != 0) ? *a : 17) void testInlineCheckInMacro(int *p) { int i = MACRO_WITH_CHECK(p); (void)i; *p = 1; // no-warning } #define MACRO_WITH_NESTED_CHECK(a) ( { int j = MACRO_WITH_CHECK(a); j; } ) void testInlineCheckInNestedMacro(int *p) { int i = MACRO_WITH_NESTED_CHECK(p); (void)i; *p = 1; // no-warning } #define NON_FUNCTION_MACRO_WITH_CHECK ( ((p) != 0) ? *p : 17) void testNonFunctionMacro(int *p) { int i = NON_FUNCTION_MACRO_WITH_CHECK ; (void)i; *p = 1; // no-warning } // This macro will dereference its argument if the argument is NULL. #define MACRO_WITH_ERROR(a) ( ((a) != 0) ? 0 : *a) void testErrorInMacro(int *p) { int i = MACRO_WITH_ERROR(p); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} (void)i; } // Here the check (the "if") is not in a macro, so we should still warn. #define MACRO_IN_GUARD(a) (!(a)) void testMacroUsedAsGuard(int *p) { if (MACRO_IN_GUARD(p)) *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} } // When a nil case split is introduced in a macro and the macro is in a guard, // we still shouldn't warn. int isNull(int *p); int isEqual(int *p, int *q); #define ISNULL(ptr) ((ptr) == 0 || isNull(ptr)) #define ISEQUAL(a, b) ((int *)(a) == (int *)(b) || (ISNULL(a) && ISNULL(b)) || isEqual(a,b)) #define ISNOTEQUAL(a, b) (!ISEQUAL(a, b)) void testNestedDisjunctiveMacro(int *p, int *q) { if (ISNOTEQUAL(p,q)) { *p = 1; // no-warning *q = 1; // no-warning } *p = 1; // no-warning *q = 1; // no-warning } void testNestedDisjunctiveMacro2(int *p, int *q) { if (ISEQUAL(p,q)) { return; } *p = 1; // no-warning *q = 1; // no-warning } // Here the check is entirely in non-macro code even though the code itself // is a macro argument. #define MACRO_DO_IT(a) (a) void testErrorInArgument(int *p) { int i = MACRO_DO_IT((p ? 0 : *p)); // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}c (void)i; } // No warning should be emitted if dereference is performed from a different // macro. #define MACRO_CHECK(a) if (a) {} #define MACRO_DEREF(a) (*a) int testDifferentMacro(int *p) { MACRO_CHECK(p); return MACRO_DEREF(p); // no-warning } // -------------------------- // "Suppression suppression" // -------------------------- void testDynCastOrNullOfNull() { // Don't suppress when one of the arguments is NULL. int *casted = dynCastOrNull(0); *casted = 1; #if !SUPPRESSED || NULL_ARGS // expected-warning@-2 {{Dereference of null pointer}} #endif } void testDynCastOfNull() { // Don't suppress when one of the arguments is NULL. int *casted = dynCastToInt(0); *casted = 1; #if !SUPPRESSED || NULL_ARGS // expected-warning@-2 {{Dereference of null pointer}} #endif } int *lookUpInt(int unused) { if (coin()) return 0; static int x; return &x; } void testZeroIsNotNull() { // /Do/ suppress when the argument is 0 (an integer). int *casted = lookUpInt(0); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void testTrackNull() { // /Do/ suppress if the null argument came from another call returning null. int *casted = dynCastOrNull(getNull()); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void testTrackNullVariable() { // /Do/ suppress if the null argument came from another call returning null. int *ptr; ptr = getNull(); int *casted = dynCastOrNull(ptr); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void inlinedIsDifferent(int inlined) { int i; // We were erroneously picking up the inner stack frame's initialization, // even though the error occurs in the outer stack frame! int *p = inlined ? &i : getNull(); if (!inlined) inlinedIsDifferent(1); *p = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void testInlinedIsDifferent() { // inlinedIsDifferent(0); } // --------------------------------------- // FALSE NEGATIVES (over-suppression) // --------------------------------------- void testNoArguments() { // In this case the function has no branches, and MUST return null. int *casted = getNull(); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } int *getNullIfNonNull(void *input) { if (input) return 0; static int x; return &x; } void testKnownPath(void *input) { if (!input) return; // In this case we have a known value for the argument, and thus the path // through the function doesn't ever split. int *casted = getNullIfNonNull(input); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } int *alwaysReturnNull(void *input) { if (opaquePropertyCheck(input)) return 0; return 0; } void testAlwaysReturnNull(void *input) { // In this case all paths out of the function return 0, but they are all // dominated by a branch whose condition we don't know! int *casted = alwaysReturnNull(input); *casted = 1; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } int derefArg(int *p) { return *p; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void ternaryArg(char cond) { static int x; derefArg(cond ? &x : getNull()); } int derefArgCast(char *p) { return *p; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void ternaryArgCast(char cond) { static int x; derefArgCast((char*)((unsigned)cond ? &x : getNull())); } int derefAssignment(int *p) { return *p; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } void ternaryAssignment(char cond) { static int x; int *p = cond ? getNull() : getPtr(); derefAssignment(p); } int *retNull(char cond) { static int x; return cond ? &x : getNull(); } int ternaryRetNull(char cond) { int *p = retNull(cond); return *p; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } // Test suppression of nested conditional operators. int testConditionalOperatorSuppress(int x) { return *(x ? getNull() : getPtr()); #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } int testNestedConditionalOperatorSuppress(int x) { return *(x ? (x ? getNull() : getPtr()) : getPtr()); #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif } int testConditionalOperator(int x) { return *(x ? 0 : getPtr()); // expected-warning {{Dereference of null pointer}} } int testNestedConditionalOperator(int x) { return *(x ? (x ? 0 : getPtr()) : getPtr()); // expected-warning {{Dereference of null pointer}} } int testConditionalOperatorSuppressFloatCond(float x) { return *(x ? getNull() : getPtr()); #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} #endif }