diff options
author | Ted Kremenek <kremenek@apple.com> | 2009-05-07 00:45:33 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2009-05-07 00:45:33 +0000 |
commit | dd986cc9989f665370cef0917ba8ba3b4871e3e6 (patch) | |
tree | 6def900ba04c0f7fc8e1689d9d80ce0775d8e319 /lib/Analysis/GRExprEngineInternalChecks.cpp | |
parent | 46a54eb500aa1f841308ad78ef356d28b1bbb0cc (diff) |
Add preliminary support for enhancing null-pointer dereference diagnostics.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71135 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/GRExprEngineInternalChecks.cpp')
-rw-r--r-- | lib/Analysis/GRExprEngineInternalChecks.cpp | 165 |
1 files changed, 160 insertions, 5 deletions
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index a40eff8fc4..541282da3e 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -14,6 +14,7 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" @@ -35,10 +36,28 @@ ExplodedNode<GRState>* GetNode(GRExprEngine::undef_arg_iterator I) { } //===----------------------------------------------------------------------===// +// Forward declarations for bug reporter visitors. +//===----------------------------------------------------------------------===// + +static void registerTrackNullValue(BugReporterContext& BRC, + const ExplodedNode<GRState>* N); + +//===----------------------------------------------------------------------===// // Bug Descriptions. //===----------------------------------------------------------------------===// namespace { + +class VISIBILITY_HIDDEN BuiltinBugReport : public BugReport { +public: + BuiltinBugReport(BugType& bt, const char* desc, + const ExplodedNode<GRState> *n) + : BugReport(bt, desc, n) {} + + void registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode<GRState>* N); +}; + class VISIBILITY_HIDDEN BuiltinBug : public BugType { GRExprEngine &Eng; protected: @@ -54,13 +73,25 @@ public: void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); } - template <typename ITER> - void Emit(BugReporter& BR, ITER I, ITER E) { - for (; I != E; ++I) BR.EmitReport(new BugReport(*this, desc.c_str(), - GetNode(I))); - } + virtual void registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode<GRState>* N, + BuiltinBugReport *R) {} + + template <typename ITER> void Emit(BugReporter& BR, ITER I, ITER E); }; + +template <typename ITER> +void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) { + for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(), + GetNode(I))); +} + +void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode<GRState>* N) { + static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this); +} + class VISIBILITY_HIDDEN NullDeref : public BuiltinBug { public: NullDeref(GRExprEngine* eng) @@ -69,6 +100,12 @@ public: void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end()); } + + void registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode<GRState>* N, + BuiltinBugReport *R) { + registerTrackNullValue(BRC, N); + } }; class VISIBILITY_HIDDEN NilReceiverStructRet : public BugType { @@ -484,6 +521,124 @@ public: } // end anonymous namespace //===----------------------------------------------------------------------===// +// Definitions for bug reporter visitors. +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN TrackConstraintBRVisitor : public BugReporterVisitor { + SVal Constraint; + const bool Assumption; + bool isSatisfied; +public: + TrackConstraintBRVisitor(SVal constraint, bool assumption) + : Constraint(constraint), Assumption(assumption), isSatisfied(false) {} + + PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N, + const ExplodedNode<GRState>* PrevN, + BugReporterContext& BRC) { + if (isSatisfied) + return NULL; + + // Check if in the previous state it was feasible for this constraint + // to *not* be true. + + GRStateManager &StateMgr = BRC.getStateManager(); + bool isFeasible = false; + if (StateMgr.Assume(PrevN->getState(), Constraint, !Assumption, + isFeasible)) { + assert(isFeasible); // Eventually we don't need 'isFeasible'. + + isSatisfied = true; + + // As a sanity check, make sure that the negation of the constraint + // was infeasible in the current state. If it is feasible, we somehow + // missed the transition point. + isFeasible = false; + if (StateMgr.Assume(N->getState(), Constraint, !Assumption, + isFeasible)) { + assert(isFeasible); + return NULL; + } + + // We found the transition point for the constraint. We now need to + // pretty-print the constraint. (work-in-progress) + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + + if (isa<Loc>(Constraint)) { + os << "Assuming pointer value is "; + os << (Assumption ? "non-NULL" : "NULL"); + } + + if (os.str().empty()) + return NULL; + + // FIXME: Refactor this into BugReporterContext. + Stmt *S = 0; + ProgramPoint P = N->getLocation(); + + if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { + CFGBlock *BSrc = BE->getSrc(); + S = BSrc->getTerminatorCondition(); + } + else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) { + S = PS->getStmt(); + } + + if (!S) + return NULL; + + // Construct a new PathDiagnosticPiece. + PathDiagnosticLocation L(S, BRC.getSourceManager()); + return new PathDiagnosticEventPiece(L, os.str()); + } + + return NULL; + } +}; +} // end anonymous namespace + +static void registerTrackConstraint(BugReporterContext& BRC, SVal Constraint, + bool Assumption) { + BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption)); +} + +static void registerTrackNullValue(BugReporterContext& BRC, + const ExplodedNode<GRState>* N) { + + ProgramPoint P = N->getLocation(); + PostStmt *PS = dyn_cast<PostStmt>(&P); + + if (!PS) + return; + + Stmt *S = PS->getStmt(); + + if (ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) { + S = AE->getBase(); + } + + SVal V = BRC.getStateManager().GetSValAsScalarOrLoc(N->getState(), S); + + // Uncomment this to find cases where we aren't properly getting the + // base value that was dereferenced. + // assert(!V.isUnknownOrUndef()); + + // For now just track when a symbolic value became null. + if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { + const SubRegion *R = cast<SubRegion>(L->getRegion()); + while (R && !isa<SymbolicRegion>(R)) { + R = dyn_cast<SubRegion>(R->getSuperRegion()); + } + + if (R) { + assert(isa<SymbolicRegion>(R)); + registerTrackConstraint(BRC, loc::MemRegionVal(R), false); + } + } +} + +//===----------------------------------------------------------------------===// // Check registration. //===----------------------------------------------------------------------===// |