[cfe-commits] r109561 - in /cfe/trunk: lib/Checker/UnreachableCodeChecker.cpp test/Analysis/additive-folding.c test/Analysis/bstring.c test/Analysis/constant-folding.c test/Analysis/string.c test/Analysis/unreachable-code-path.c
Tom Care
tcare at apple.com
Tue Jul 27 16:30:21 PDT 2010
Author: tcare
Date: Tue Jul 27 18:30:21 2010
New Revision: 109561
URL: http://llvm.org/viewvc/llvm-project?rev=109561&view=rev
Log:
Added some false positive checking to UnreachableCodeChecker
- Allowed reporting of dead macros
- Added path walking function to search for false positives in conditional statements
- Updated some affected tests
- Added some false positive test cases
Modified:
cfe/trunk/lib/Checker/UnreachableCodeChecker.cpp
cfe/trunk/test/Analysis/additive-folding.c
cfe/trunk/test/Analysis/bstring.c
cfe/trunk/test/Analysis/constant-folding.c
cfe/trunk/test/Analysis/string.c
cfe/trunk/test/Analysis/unreachable-code-path.c
Modified: cfe/trunk/lib/Checker/UnreachableCodeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/UnreachableCodeChecker.cpp?rev=109561&r1=109560&r2=109561&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/UnreachableCodeChecker.cpp (original)
+++ cfe/trunk/lib/Checker/UnreachableCodeChecker.cpp Tue Jul 27 18:30:21 2010
@@ -13,13 +13,14 @@
// A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
//===----------------------------------------------------------------------===//
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/CheckerHelpers.h"
#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineExperimentalChecks.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/Basic/Builtins.h"
#include "llvm/ADT/SmallPtrSet.h"
// The number of CFGBlock pointers we want to reserve memory for. This is used
@@ -35,9 +36,13 @@
void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
bool hasWorkRemaining);
private:
+ typedef bool (*ExplodedNodeHeuristic)(const ExplodedNode &EN);
+
static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R);
void FindUnreachableEntryPoints(const CFGBlock *CB);
void MarkSuccessorsReachable(const CFGBlock *CB);
+ static const Expr *getConditon(const Stmt *S);
+ static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
llvm::SmallPtrSet<const CFGBlock*, DEFAULT_CFGBLOCKS> reachable;
llvm::SmallPtrSet<const CFGBlock*, DEFAULT_CFGBLOCKS> visited;
@@ -61,14 +66,18 @@
return;
CFG *C = 0;
+ ParentMap *PM = 0;
// Iterate over ExplodedGraph
for (ExplodedGraph::node_iterator I = G.nodes_begin(); I != G.nodes_end();
++I) {
const ProgramPoint &P = I->getLocation();
+ const LocationContext *LC = P.getLocationContext();
// Save the CFG if we don't have it already
if (!C)
- C = P.getLocationContext()->getCFG();
+ C = LC->getCFG();
+ if (!PM)
+ PM = &LC->getParentMap();
if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
const CFGBlock *CB = BE->getBlock();
@@ -76,8 +85,8 @@
}
}
- // Bail out if we didn't get the CFG
- if (!C)
+ // Bail out if we didn't get the CFG or the ParentMap.
+ if (!C || !PM)
return;
ASTContext &Ctx = B.getContext();
@@ -86,34 +95,39 @@
for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
const CFGBlock *CB = *I;
// Check if the block is unreachable
- if (!reachable.count(CB)) {
- // Find the entry points for this block
- FindUnreachableEntryPoints(CB);
- // This block may have been pruned; check if we still want to report it
- if (reachable.count(CB))
- continue;
-
- // We found a statement that wasn't covered
- SourceRange S;
- SourceLocation SL = GetUnreachableLoc(*CB, S);
- if (S.getBegin().isMacroID() || S.getEnd().isMacroID() || S.isInvalid()
- || SL.isInvalid())
- continue;
-
- // Special case for __builtin_unreachable.
- // FIXME: This should be extended to include other unreachable markers,
- // such as llvm_unreachable.
- if (!CB->empty()) {
- const Stmt *First = CB->front();
- if (const CallExpr *CE = dyn_cast<CallExpr>(First)) {
- if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
- continue;
- }
- }
+ if (reachable.count(CB))
+ continue;
+
+ // Find the entry points for this block
+ FindUnreachableEntryPoints(CB);
- B.EmitBasicReport("Unreachable code", "This statement is never executed",
- SL, S);
+ // This block may have been pruned; check if we still want to report it
+ if (reachable.count(CB))
+ continue;
+
+ // Check for false positives
+ if (CB->size() > 0 && isInvalidPath(CB, *PM))
+ continue;
+
+ // We found a statement that wasn't covered
+ SourceRange S;
+ SourceLocation SL = GetUnreachableLoc(*CB, S);
+ if (S.isInvalid() || SL.isInvalid())
+ continue;
+
+ // Special case for __builtin_unreachable.
+ // FIXME: This should be extended to include other unreachable markers,
+ // such as llvm_unreachable.
+ if (!CB->empty()) {
+ const Stmt *First = CB->front();
+ if (const CallExpr *CE = dyn_cast<CallExpr>(First)) {
+ if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
+ continue;
+ }
}
+
+ B.EmitBasicReport("Unreachable code", "This statement is never executed",
+ SL, S);
}
}
@@ -156,3 +170,50 @@
R = S->getSourceRange();
return S->getLocStart();
}
+
+// Returns the Expr* condition if this is a conditional statement, or 0
+// otherwise
+const Expr *UnreachableCodeChecker::getConditon(const Stmt *S) {
+ if (const IfStmt *IS = dyn_cast<IfStmt>(S)) {
+ return IS->getCond();
+ }
+ else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(S)) {
+ return SS->getCond();
+ }
+ else if (const WhileStmt *WS = dyn_cast<WhileStmt>(S)) {
+ return WS->getCond();
+ }
+ else if (const DoStmt *DS = dyn_cast<DoStmt>(S)) {
+ return DS->getCond();
+ }
+ else if (const ForStmt *FS = dyn_cast<ForStmt>(S)) {
+ return FS->getCond();
+ }
+ else if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(S)) {
+ return CO->getCond();
+ }
+
+ return 0;
+}
+
+// Traverse the predecessor Stmt*s from this CFGBlock to find any signs of a
+// path that is a false positive.
+bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
+ const ParentMap &PM) {
+
+ // Start at the end of the block and work up the path.
+ const Stmt *S = CB->back().getStmt();
+ while (S) {
+ // Find any false positives in the conditions on this path.
+ if (const Expr *cond = getConditon(S)) {
+ if (containsMacro(cond) || containsEnum(cond)
+ || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
+ || containsStmt<SizeOfAlignOfExpr>(cond))
+ return true;
+ }
+ // Get the previous statement.
+ S = PM.getParent(S);
+ }
+
+ return false;
+}
Modified: cfe/trunk/test/Analysis/additive-folding.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/additive-folding.c?rev=109561&r1=109560&r2=109561&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/additive-folding.c (original)
+++ cfe/trunk/test/Analysis/additive-folding.c Tue Jul 27 18:30:21 2010
@@ -61,7 +61,7 @@
if (a+1 != 0)
return; // no-warning
if (a-1 != UINT_MAX-1)
- return; // expected-warning{{never executed}}
+ return; // no-warning
free(b);
}
@@ -72,7 +72,7 @@
if (a+1 == 0)
return; // no-warning
if (a-1 == UINT_MAX-1)
- return; // expected-warning{{never executed}}
+ return; // no-warning
free(b);
}
@@ -177,7 +177,7 @@
void tautologyGT (unsigned a) {
char* b = malloc(1);
if (a > UINT_MAX)
- return; // expected-warning{{never executed}}
+ return; // no-warning
free(b);
}
Modified: cfe/trunk/test/Analysis/bstring.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/bstring.c?rev=109561&r1=109560&r2=109561&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/bstring.c (original)
+++ cfe/trunk/test/Analysis/bstring.c Tue Jul 27 18:30:21 2010
@@ -53,7 +53,7 @@
memcpy(dst, src, 4); // no-warning
if (memcpy(dst, src, 4) != dst) {
- (void)*(char*)0; // expected-warning{{never executed}}
+ (void)*(char*)0; // no-warning
}
}
@@ -155,7 +155,7 @@
memmove(dst, src, 4); // no-warning
if (memmove(dst, src, 4) != dst) {
- (void)*(char*)0; // expected-warning{{never executed}}
+ (void)*(char*)0; // no-warning
}
}
@@ -217,7 +217,7 @@
char a[] = {1, 2, 3, 4};
if (memcmp(a, a, 4))
- (void)*(char*)0; // expected-warning{{never executed}}
+ (void)*(char*)0; // no-warning
}
void memcmp4 (char *input) {
@@ -231,11 +231,11 @@
char a[] = {1, 2, 3, 4};
if (memcmp(a, 0, 0)) // no-warning
- (void)*(char*)0; // expected-warning{{never executed}}
+ (void)*(char*)0; // no-warning
if (memcmp(0, a, 0)) // no-warning
- (void)*(char*)0; // expected-warning{{never executed}}
+ (void)*(char*)0; // no-warning
if (memcmp(a, input, 0)) // no-warning
- (void)*(char*)0; // expected-warning{{never executed}}
+ (void)*(char*)0; // no-warning
}
void memcmp6 (char *a, char *b, size_t n) {
Modified: cfe/trunk/test/Analysis/constant-folding.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/constant-folding.c?rev=109561&r1=109560&r2=109561&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/constant-folding.c (original)
+++ cfe/trunk/test/Analysis/constant-folding.c Tue Jul 27 18:30:21 2010
@@ -9,51 +9,51 @@
// Sema can already catch the simple comparison a==a,
// since that's usually a logic error (and not path-dependent).
int b = a;
- if (!(b==a)) WARN;
- if (!(b>=a)) WARN;
- if (!(b<=a)) WARN;
- if (b!=a) WARN;
- if (b>a) WARN;
- if (b<a) WARN;
+ if (!(b==a)) WARN; // expected-warning{{never executed}}
+ if (!(b>=a)) WARN; // expected-warning{{never executed}}
+ if (!(b<=a)) WARN; // expected-warning{{never executed}}
+ if (b!=a) WARN; // expected-warning{{never executed}}
+ if (b>a) WARN; // expected-warning{{never executed}}
+ if (b<a) WARN; // expected-warning{{never executed}}
}
void testSelfOperations (int a) {
- if ((a|a) != a) WARN; // expected-warning{{Both operands to '|' always have the same value}}
- if ((a&a) != a) WARN; // expected-warning{{Both operands to '&' always have the same value}}
- if ((a^a) != 0) WARN; // expected-warning{{Both operands to '^' always have the same value}}
- if ((a-a) != 0) WARN; // expected-warning{{Both operands to '-' always have the same value}}
+ if ((a|a) != a) WARN; // expected-warning{{Both operands to '|' always have the same value}} expected-warning{{never executed}}
+ if ((a&a) != a) WARN; // expected-warning{{Both operands to '&' always have the same value}} expected-warning{{never executed}}
+ if ((a^a) != 0) WARN; // expected-warning{{Both operands to '^' always have the same value}} expected-warning{{never executed}}
+ if ((a-a) != 0) WARN; // expected-warning{{Both operands to '-' always have the same value}} expected-warning{{never executed}}
}
void testIdempotent (int a) {
- if ((a*1) != a) WARN;
- if ((a/1) != a) WARN;
- if ((a+0) != a) WARN;
- if ((a-0) != a) WARN;
- if ((a<<0) != a) WARN;
- if ((a>>0) != a) WARN;
- if ((a^0) != a) WARN;
- if ((a&(~0)) != a) WARN;
- if ((a|0) != a) WARN;
+ if ((a*1) != a) WARN; // expected-warning{{never executed}}
+ if ((a/1) != a) WARN; // expected-warning{{never executed}}
+ if ((a+0) != a) WARN; // expected-warning{{never executed}}
+ if ((a-0) != a) WARN; // expected-warning{{never executed}}
+ if ((a<<0) != a) WARN; // expected-warning{{never executed}}
+ if ((a>>0) != a) WARN; // expected-warning{{never executed}}
+ if ((a^0) != a) WARN; // expected-warning{{never executed}}
+ if ((a&(~0)) != a) WARN; // expected-warning{{never executed}}
+ if ((a|0) != a) WARN; // expected-warning{{never executed}}
}
void testReductionToConstant (int a) {
- if ((a*0) != 0) WARN;
- if ((a&0) != 0) WARN;
- if ((a|(~0)) != (~0)) WARN;
+ if ((a*0) != 0) WARN; // expected-warning{{never executed}}
+ if ((a&0) != 0) WARN; // expected-warning{{never executed}}
+ if ((a|(~0)) != (~0)) WARN; // expected-warning{{never executed}}
}
void testSymmetricIntSymOperations (int a) {
- if ((2+a) != (a+2)) WARN;
- if ((2*a) != (a*2)) WARN;
- if ((2&a) != (a&2)) WARN;
- if ((2^a) != (a^2)) WARN;
- if ((2|a) != (a|2)) WARN;
+ if ((2+a) != (a+2)) WARN; // expected-warning{{never executed}}
+ if ((2*a) != (a*2)) WARN; // expected-warning{{never executed}}
+ if ((2&a) != (a&2)) WARN; // expected-warning{{never executed}}
+ if ((2^a) != (a^2)) WARN; // expected-warning{{never executed}}
+ if ((2|a) != (a|2)) WARN; // expected-warning{{never executed}}
}
void testAsymmetricIntSymOperations (int a) {
- if (((~0) >> a) != (~0)) WARN;
- if ((0 >> a) != 0) WARN;
- if ((0 << a) != 0) WARN;
+ if (((~0) >> a) != (~0)) WARN; // expected-warning{{never executed}}
+ if ((0 >> a) != 0) WARN; // expected-warning{{never executed}}
+ if ((0 << a) != 0) WARN; // expected-warning{{never executed}}
// Unsigned right shift shifts in zeroes.
if ((((unsigned)(~0)) >> ((unsigned) a)) != ((unsigned)(~0)))
@@ -62,11 +62,11 @@
void testLocations (char *a) {
char *b = a;
- if (!(b==a)) WARN;
- if (!(b>=a)) WARN;
- if (!(b<=a)) WARN;
- if (b!=a) WARN;
- if (b>a) WARN;
- if (b<a) WARN;
- if (b-a) WARN; // expected-warning{{Both operands to '-' always have the same value}}
+ if (!(b==a)) WARN; // expected-warning{{never executed}}
+ if (!(b>=a)) WARN; // expected-warning{{never executed}}
+ if (!(b<=a)) WARN; // expected-warning{{never executed}}
+ if (b!=a) WARN; // expected-warning{{never executed}}
+ if (b>a) WARN; // expected-warning{{never executed}}
+ if (b<a) WARN; // expected-warning{{never executed}}
+ if (b-a) WARN; // expected-warning{{Both operands to '-' always have the same value}} expected-warning{{never executed}}
}
Modified: cfe/trunk/test/Analysis/string.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/string.c?rev=109561&r1=109560&r2=109561&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/string.c (original)
+++ cfe/trunk/test/Analysis/string.c Tue Jul 27 18:30:21 2010
@@ -35,13 +35,13 @@
void strlen_constant0() {
if (strlen("123") != 3)
- (void)*(char*)0; // expected-warning{{never executed}}
+ (void)*(char*)0;
}
void strlen_constant1() {
const char *a = "123";
if (strlen(a) != 3)
- (void)*(char*)0; // expected-warning{{never executed}}
+ (void)*(char*)0;
}
void strlen_constant2(char x) {
Modified: cfe/trunk/test/Analysis/unreachable-code-path.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unreachable-code-path.c?rev=109561&r1=109560&r2=109561&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/unreachable-code-path.c (original)
+++ cfe/trunk/test/Analysis/unreachable-code-path.c Tue Jul 27 18:30:21 2010
@@ -2,6 +2,8 @@
extern void foo(int a);
+// The first few tests are non-path specific - we should be able to find them
+
void test(unsigned a) {
switch (a) {
a += 5; // expected-warning{{never executed}}
@@ -23,7 +25,16 @@
goto help;
}
-void test3() {
+void test3(unsigned a) {
+ while(1);
+ if (a > 5) { // expected-warning{{never executed}}
+ return;
+ }
+}
+
+// These next tests are path-sensitive
+
+void test4() {
int a = 5;
while (a > 1)
@@ -36,13 +47,6 @@
foo(a);
}
-void test4(unsigned a) {
- while(1);
- if (a > 5) { // expected-warning{{never executed}}
- return;
- }
-}
-
extern void bar(char c);
void test5(const char *c) {
@@ -53,9 +57,34 @@
}
}
+// These next tests are false positives and should not generate warnings
+
void test6(const char *c) {
if (c) return;
if (!c) return;
__builtin_unreachable(); // no-warning
}
+// Compile-time constant false positives
+#define CONSTANT 0
+enum test_enum { Off, On };
+void test7() {
+ if (CONSTANT)
+ return; // no-warning
+
+ if (sizeof(int))
+ return; // no-warning
+
+ if (Off)
+ return; // no-warning
+}
+
+void test8() {
+ static unsigned a = 0;
+
+ if (a)
+ a = 123; // no-warning
+
+ a = 5;
+}
+
More information about the cfe-commits
mailing list