From d000b852022bcd4fc14029b48d2fa873f63e4032 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 3 Oct 2013 16:57:03 +0000 Subject: [PATCH] [analyzer] Add new debug helper clang_analyzer_warnIfReached. This will emit a warning if a call to clang_analyzer_warnIfReached is executed, printing REACHABLE. This is a more explicit way to declare expected reachability than using clang_analyzer_eval or triggering a bug (divide-by-zero or null dereference), and unlike the former will work the same in inlined functions and top-level functions. Like the other debug helpers, it is part of the debug.ExprInspection checker. Patch by Jared Grubb! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191909 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/analyzer/DebugChecks.rst | 13 ++++ .../Checkers/ExprInspectionChecker.cpp | 13 ++++ test/Analysis/func.c | 5 +- test/Analysis/misc-ps-region-store.cpp | 65 +++++++------------ 4 files changed, 54 insertions(+), 42 deletions(-) diff --git a/docs/analyzer/DebugChecks.rst b/docs/analyzer/DebugChecks.rst index a0f2a07a00..14d6ae4c4c 100644 --- a/docs/analyzer/DebugChecks.rst +++ b/docs/analyzer/DebugChecks.rst @@ -125,6 +125,19 @@ ExprInspection checks clang_analyzer_eval(value == 42); // expected-warning{{TRUE}} } +- void clang_analyzer_warnIfReached(); + + Generate a warning if this line of code gets reached by the analyzer. + + Example usage:: + + if (true) { + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} + } + else { + clang_analyzer_warnIfReached(); // no-warning + } + Statistics ========== diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 9522d1d638..3ed2435b92 100644 --- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -22,6 +22,7 @@ class ExprInspectionChecker : public Checker< eval::Call > { void analyzerEval(const CallExpr *CE, CheckerContext &C) const; void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const; + void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const; void analyzerCrash(const CallExpr *CE, CheckerContext &C) const; typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, @@ -41,6 +42,7 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE, .Case("clang_analyzer_checkInlined", &ExprInspectionChecker::analyzerCheckInlined) .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) + .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached) .Default(0); if (!Handler) @@ -99,6 +101,17 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE, C.emitReport(R); } +void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE, + CheckerContext &C) const { + ExplodedNode *N = C.getPredecessor(); + + if (!BT) + BT.reset(new BugType("Checking analyzer assumptions", "debug")); + + BugReport *R = new BugReport(*BT, "REACHABLE", N); + C.emitReport(R); +} + void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const { ExplodedNode *N = C.getPredecessor(); diff --git a/test/Analysis/func.c b/test/Analysis/func.c index 275a82da2e..78afb45da6 100644 --- a/test/Analysis/func.c +++ b/test/Analysis/func.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s void clang_analyzer_eval(int); +void clang_analyzer_warnIfReached(); void f(void) { void (*p)(void); @@ -29,12 +30,12 @@ void f3(void (*f)(void), void (*g)(void)) { void nullFunctionPointerConstant() { void (*f)(void) = 0; f(); // expected-warning{{Called function pointer is null}} - clang_analyzer_eval(0); // no-warning + clang_analyzer_warnIfReached(); // no-warning } void nullFunctionPointerConstraint(void (*f)(void)) { if (f) return; f(); // expected-warning{{Called function pointer is null}} - clang_analyzer_eval(0); // no-warning + clang_analyzer_warnIfReached(); // no-warning } diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp index 902a5e5271..6a873f01b3 100644 --- a/test/Analysis/misc-ps-region-store.cpp +++ b/test/Analysis/misc-ps-region-store.cpp @@ -1,5 +1,7 @@ -// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions -// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions + +void clang_analyzer_warnIfReached(); // Test basic handling of references. char &test1_aux(); @@ -54,9 +56,7 @@ int test_init_in_condition_switch() { if (x == 2) return 0; else { - // Unreachable. - int *p = 0; - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // unreachable } default: break; @@ -74,8 +74,7 @@ int test_init_in_condition_while() { if (z == 2) return 0; - int *p = 0; - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // unreachable return 0; } @@ -89,8 +88,7 @@ int test_init_in_condition_for() { if (z == 1) return 0; - int *p = 0; - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // unreachable return 0; } @@ -117,8 +115,7 @@ int TestHandleThis::null_deref_negative() { if (x == 10) { return 1; } - int *p = 0; - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // unreachable return 0; } @@ -127,8 +124,7 @@ int TestHandleThis::null_deref_positive() { if (x == 9) { return 1; } - int *p = 0; - *p = 0xDEADBEEF; // expected-warning{{null pointer}} + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} return 0; } @@ -143,9 +139,9 @@ void pr7675_test() { pr7675(10); pr7675('c'); pr7675_i(4.0i); - // Add null deref to ensure we are analyzing the code up to this point. - int *p = 0; - *p = 0xDEADBEEF; // expected-warning{{null pointer}} + + // Add check to ensure we are analyzing the code up to this point. + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } // - CFGBuilder should handle temporaries. @@ -328,26 +324,23 @@ class RDar9267815 { }; void RDar9267815::test_pos() { - int *p = 0; if (x == 42) return; - *p = 0xDEADBEEF; // expected-warning {{null}} + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } void RDar9267815::test() { - int *p = 0; if (x == 42) return; if (x == 42) - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // no-warning } void RDar9267815::test2() { - int *p = 0; if (x == 42) return; invalidate(); if (x == 42) - *p = 0xDEADBEEF; // expected-warning {{null}} + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } // Test reference parameters. @@ -440,8 +433,7 @@ int rdar9948787_negative() { unsigned value = classWithStatic.value; if (value == 1) return 1; - int *p = 0; - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // no-warning return 0; } @@ -450,8 +442,7 @@ int rdar9948787_positive() { unsigned value = classWithStatic.value; if (value == 0) return 1; - int *p = 0; - *p = 0xDEADBEEF; // expected-warning {{null}} + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} return 0; } @@ -467,8 +458,7 @@ void rdar10202899_test1() { void rdar10202899_test2() { if (val == rdar10202899_ValTA) return; - int *p = 0; - *p = 0xDEADBEEF; + clang_analyzer_warnIfReached(); // no-warning } void rdar10202899_test3() { @@ -476,8 +466,7 @@ void rdar10202899_test3() { case rdar10202899_ValTA: return; default: ; }; - int *p = 0; - *p = 0xDEADBEEF; + clang_analyzer_warnIfReached(); // no-warning } // This used to crash the analyzer because of the unnamed bitfield. @@ -489,13 +478,12 @@ void PR11249() char f2[1]; char f3; } V = { 1, {2}, 3 }; - int *p = 0; if (V.f1 != 1) - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // no-warning if (V.f2[0] != 2) - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // no-warning if (V.f3 != 3) - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // no-warning } // Handle doing a load from the memory associated with the code for @@ -599,12 +587,10 @@ void rdar10924675(unsigned short x[], int index, int index2) { void rdar11401827() { int x = int(); if (!x) { - int *p = 0; - *p = 0xDEADBEEF; // expected-warning {{null pointer}} + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } else { - int *p = 0; - *p = 0xDEADBEEF; + clang_analyzer_warnIfReached(); // no-warning } } @@ -701,8 +687,7 @@ const Rdar12755044_foo *radar12755044() { void rdar12759044() { int flag = 512; if (!(flag & 512)) { - int *p = 0; - *p = 0xDEADBEEF; // no-warning + clang_analyzer_warnIfReached(); // no-warning } } -- 2.40.0