diff options
author | Tom Care <tcare@apple.com> | 2010-07-16 20:41:41 +0000 |
---|---|---|
committer | Tom Care <tcare@apple.com> | 2010-07-16 20:41:41 +0000 |
commit | df4ca423ec7d9b62842e112d1b824faa08b64810 (patch) | |
tree | ebe74672aed0a760164184326524521e32b8ac3f /lib | |
parent | 35dda71933d2e71b7a865b6ba41cf703e8b99c56 (diff) |
Improved false positive rate for the idempotent operations checker and moved it into the default path-sensitive analysis options.
- Added checks for static local variables, self assigned parameters, and truncating/extending self assignments
- Removed command line option (now default with --analyze)
- Updated test cases to pass with idempotent operation warnings
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108550 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Checker/AnalysisConsumer.cpp | 3 | ||||
-rw-r--r-- | lib/Checker/GRExprEngine.cpp | 1 | ||||
-rw-r--r-- | lib/Checker/GRExprEngineExperimentalChecks.h | 1 | ||||
-rw-r--r-- | lib/Checker/GRExprEngineInternalChecks.h | 1 | ||||
-rw-r--r-- | lib/Checker/IdempotentOperationChecker.cpp | 83 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 4 |
6 files changed, 82 insertions, 11 deletions
diff --git a/lib/Checker/AnalysisConsumer.cpp b/lib/Checker/AnalysisConsumer.cpp index 524f37e396..6c7a294b1d 100644 --- a/lib/Checker/AnalysisConsumer.cpp +++ b/lib/Checker/AnalysisConsumer.cpp @@ -341,9 +341,6 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); - if (C.Opts.EnableIdempotentOperationChecker) - RegisterIdempotentOperationChecker(Eng); - // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; if (mgr.shouldVisualizeUbigraph()) { diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 07fee9d39e..1424820f3b 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -361,6 +361,7 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { RegisterDereferenceChecker(Eng); RegisterVLASizeChecker(Eng); RegisterDivZeroChecker(Eng); + RegisterIdempotentOperationChecker(Eng); RegisterReturnUndefChecker(Eng); RegisterUndefinedArraySubscriptChecker(Eng); RegisterUndefinedAssignmentChecker(Eng); diff --git a/lib/Checker/GRExprEngineExperimentalChecks.h b/lib/Checker/GRExprEngineExperimentalChecks.h index 7d1eb77f9f..3c1c95ffef 100644 --- a/lib/Checker/GRExprEngineExperimentalChecks.h +++ b/lib/Checker/GRExprEngineExperimentalChecks.h @@ -23,7 +23,6 @@ void RegisterCStringChecker(GRExprEngine &Eng); void RegisterPthreadLockChecker(GRExprEngine &Eng); void RegisterMallocChecker(GRExprEngine &Eng); void RegisterStreamChecker(GRExprEngine &Eng); -void RegisterIdempotentOperationChecker(GRExprEngine &Eng); } // end clang namespace #endif diff --git a/lib/Checker/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h index f91a759b32..9644eafcb3 100644 --- a/lib/Checker/GRExprEngineInternalChecks.h +++ b/lib/Checker/GRExprEngineInternalChecks.h @@ -30,6 +30,7 @@ void RegisterCastSizeChecker(GRExprEngine &Eng); void RegisterDereferenceChecker(GRExprEngine &Eng); void RegisterDivZeroChecker(GRExprEngine &Eng); void RegisterFixedAddressChecker(GRExprEngine &Eng); +void RegisterIdempotentOperationChecker(GRExprEngine &Eng); void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); void RegisterPointerArithChecker(GRExprEngine &Eng); void RegisterPointerSubChecker(GRExprEngine &Eng); diff --git a/lib/Checker/IdempotentOperationChecker.cpp b/lib/Checker/IdempotentOperationChecker.cpp index 6ed18417a2..744fe2ba99 100644 --- a/lib/Checker/IdempotentOperationChecker.cpp +++ b/lib/Checker/IdempotentOperationChecker.cpp @@ -48,7 +48,7 @@ // - Handle mixed assumptions (which assumptions can belong together?) // - Finer grained false positive control (levels) -#include "GRExprEngineExperimentalChecks.h" +#include "GRExprEngineInternalChecks.h" #include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/SVals.h" @@ -78,6 +78,10 @@ class IdempotentOperationChecker /// element somewhere. Used in static analysis to reduce false positives. static bool containsMacro(const Stmt *S); static bool containsEnum(const Stmt *S); + static bool containsStaticLocal(const Stmt *S); + static bool isParameterSelfAssign(const Expr *LHS, const Expr *RHS); + static bool isTruncationExtensionAssignment(const Expr *LHS, + const Expr *RHS); static bool containsBuiltinOffsetOf(const Stmt *S); static bool containsZeroConstant(const Stmt *S); static bool containsOneConstant(const Stmt *S); @@ -128,7 +132,7 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( // Skip binary operators containing common false positives if (containsMacro(B) || containsEnum(B) || containsStmt<SizeOfAlignOfExpr>(B) || containsZeroConstant(B) || containsOneConstant(B) - || containsBuiltinOffsetOf(B)) { + || containsBuiltinOffsetOf(B) || containsStaticLocal(B)) { A = Impossible; return; } @@ -181,12 +185,19 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( break; // We don't care about any other operators. // Fall through intentional + case BinaryOperator::Assign: + // x Assign x has a few more false positives we can check for + if (isParameterSelfAssign(RHS, LHS) + || isTruncationExtensionAssignment(RHS, LHS)) { + A = Impossible; + return; + } + case BinaryOperator::SubAssign: case BinaryOperator::DivAssign: case BinaryOperator::AndAssign: case BinaryOperator::OrAssign: case BinaryOperator::XorAssign: - case BinaryOperator::Assign: case BinaryOperator::Sub: case BinaryOperator::Div: case BinaryOperator::And: @@ -399,6 +410,70 @@ bool IdempotentOperationChecker::containsEnum(const Stmt *S) { return false; } +// Recursively find any substatements containing static vars +bool IdempotentOperationChecker::containsStaticLocal(const Stmt *S) { + const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S); + + if (DR) + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) + if (VD->isStaticLocal()) + return true; + + for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); + ++I) + if (const Stmt *child = *I) + if (containsStaticLocal(child)) + return true; + + return false; +} + +// Check for a statement were a parameter is self assigned (to avoid an unused +// variable warning) +bool IdempotentOperationChecker::isParameterSelfAssign(const Expr *LHS, + const Expr *RHS) { + LHS = LHS->IgnoreParenCasts(); + RHS = RHS->IgnoreParenCasts(); + + const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS); + if (!LHS_DR) + return false; + + const ParmVarDecl *PD = dyn_cast<ParmVarDecl>(LHS_DR->getDecl()); + if (!PD) + return false; + + const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS); + if (!RHS_DR) + return false; + + return PD == RHS_DR->getDecl(); +} + +// Check for self casts truncating/extending a variable +bool IdempotentOperationChecker::isTruncationExtensionAssignment( + const Expr *LHS, + const Expr *RHS) { + + const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts()); + if (!LHS_DR) + return false; + + const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl()); + if (!VD) + return false; + + const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts()); + if (!RHS_DR) + return false; + + if (VD != RHS_DR->getDecl()) + return false; + + return dyn_cast<DeclRefExpr>(RHS->IgnoreParens()) == NULL; +} + + // Recursively find any substatements containing __builtin_offset_of bool IdempotentOperationChecker::containsBuiltinOffsetOf(const Stmt *S) { const UnaryOperator *UO = dyn_cast<UnaryOperator>(S); @@ -415,6 +490,7 @@ bool IdempotentOperationChecker::containsBuiltinOffsetOf(const Stmt *S) { return false; } +// Check for a integer or float constant of 0 bool IdempotentOperationChecker::containsZeroConstant(const Stmt *S) { const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S); if (IL && IL->getValue() == 0) @@ -433,6 +509,7 @@ bool IdempotentOperationChecker::containsZeroConstant(const Stmt *S) { return false; } +// Check for an integer or float constant of 1 bool IdempotentOperationChecker::containsOneConstant(const Stmt *S) { const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S); if (IL && IL->getValue() == 1) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 418d25b0d4..00363d91fd 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -112,8 +112,6 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-experimental-checks"); if (Opts.EnableExperimentalInternalChecks) Res.push_back("-analyzer-experimental-internal-checks"); - if (Opts.EnableIdempotentOperationChecker) - Res.push_back("-analyzer-idempotent-operation"); } static void CodeGenOptsToArgs(const CodeGenOptions &Opts, @@ -792,8 +790,6 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks); Opts.EnableExperimentalInternalChecks = Args.hasArg(OPT_analyzer_experimental_internal_checks); - Opts.EnableIdempotentOperationChecker = - Args.hasArg(OPT_analyzer_idempotent_operation); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags); |