diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/AnnotatedPath.h | 4 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRCoreEngine.h | 48 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h | 4 | ||||
-rw-r--r-- | lib/Analysis/BasicObjCFoundationChecks.cpp | 46 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 8 | ||||
-rw-r--r-- | lib/Analysis/GRSimpleVals.cpp | 2 |
6 files changed, 71 insertions, 41 deletions
diff --git a/include/clang/Analysis/PathSensitive/AnnotatedPath.h b/include/clang/Analysis/PathSensitive/AnnotatedPath.h index 5056b77aab..3873bd45d2 100644 --- a/include/clang/Analysis/PathSensitive/AnnotatedPath.h +++ b/include/clang/Analysis/PathSensitive/AnnotatedPath.h @@ -34,7 +34,7 @@ public: Expr* e = NULL) : Node(N), annotation(annot), E(e) {} - ExplodedNode<STATE> getNode() const { return Node; } + ExplodedNode<STATE>* getNode() const { return Node; } const std::string& getString() const { return annotation; } @@ -58,6 +58,8 @@ public: iterator begin() { return path.begin(); } iterator end() { return path.end(); } + AnnotatedNode<STATE>& back() { return path.back(); } + const AnnotatedNode<STATE>& back() const { return path.back(); } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h index e22df35ab6..4228531fb2 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -19,6 +19,7 @@ #include "clang/Analysis/PathSensitive/ExplodedGraph.h" #include "clang/Analysis/PathSensitive/GRWorkList.h" #include "clang/Analysis/PathSensitive/GRBlockCounter.h" +#include "clang/Analysis/PathSensitive/GRAuditor.h" #include "llvm/ADT/OwningPtr.h" namespace clang { @@ -162,15 +163,6 @@ public: CFGBlock* getBlock() const { return &B; } }; - -template <typename STATE> -class GRNodeAuditor { -public: - typedef ExplodedNode<STATE> NodeTy; - - virtual ~GRNodeAuditor() {} - virtual bool Audit(NodeTy* N) = 0; -}; template<typename STATE> @@ -181,8 +173,8 @@ class GRStmtNodeBuilder { GRStmtNodeBuilderImpl& NB; StateTy* CleanedState; - GRNodeAuditor<StateTy> **CallExprAuditBeg, **CallExprAuditEnd; - GRNodeAuditor<StateTy> **ObjCMsgExprAuditBeg, **ObjCMsgExprAuditEnd; + GRAuditor<StateTy> **CallExprAuditBeg, **CallExprAuditEnd; + GRAuditor<StateTy> **ObjCMsgExprAuditBeg, **ObjCMsgExprAuditEnd; public: GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb) : NB(nb), @@ -192,14 +184,14 @@ public: CleanedState = getLastNode()->getState(); } - void setObjCMsgExprAuditors(GRNodeAuditor<StateTy> **B, - GRNodeAuditor<StateTy> **E) { + void setObjCMsgExprAuditors(GRAuditor<StateTy> **B, + GRAuditor<StateTy> **E) { ObjCMsgExprAuditBeg = B; ObjCMsgExprAuditEnd = E; } - void setCallExprAuditors(GRNodeAuditor<StateTy> **B, - GRNodeAuditor<StateTy> **E) { + void setCallExprAuditors(GRAuditor<StateTy> **B, + GRAuditor<StateTy> **E) { CallExprAuditBeg = B; CallExprAuditEnd = E; } @@ -240,8 +232,22 @@ public: StateTy* PredState = GetState(Pred); + GRAuditor<StateTy> **AB = NULL, **AE = NULL; + + switch (S->getStmtClass()) { + default: break; + case Stmt::CallExprClass: + AB = CallExprAuditBeg; + AE = CallExprAuditEnd; + break; + case Stmt::ObjCMessageExprClass: + AB = ObjCMsgExprAuditBeg; + AE = ObjCMsgExprAuditEnd; + break; + } + // If the state hasn't changed, don't generate a new node. - if (!BuildSinks && St == PredState) { + if (!BuildSinks && St == PredState && AB == NULL) { Dst.Add(Pred); return NULL; } @@ -254,14 +260,8 @@ public: else { Dst.Add(N); - if (isa<CallExpr>(S)) - for (GRNodeAuditor<StateTy>** I = CallExprAuditBeg; - I != CallExprAuditEnd; ++I) - (*I)->Audit(N); - else if (isa<ObjCMessageExpr>(S)) - for (GRNodeAuditor<StateTy>** I = ObjCMsgExprAuditBeg; - I != ObjCMsgExprAuditEnd; ++I) - (*I)->Audit(N); + for ( ; AB != AE; ++AB) + (*AB)->Audit(N); } } diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h index 2da2cb4045..16db802290 100644 --- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h +++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h @@ -21,13 +21,13 @@ namespace clang { class ValueState; +class Diagnostic; class GRSimpleAPICheck : public GRAuditor<ValueState> { public: GRSimpleAPICheck() {} virtual ~GRSimpleAPICheck() {} - - + virtual void ReportResults(Diagnostic& D) {} }; } // end namespace clang diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index 4d7a4d99db..d2a2dd6a51 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -32,16 +32,18 @@ namespace { class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { - ASTContext &Ctx; - ValueStateManager* VMgr; - std::list<AnnotatedPath<ValueState> > Errors; + ASTContext &Ctx; + ValueStateManager* VMgr; + + typedef std::list<AnnotatedPath<ValueState> > ErrorsTy; + ErrorsTy Errors; - RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); } + RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); } - bool isNSString(ObjCInterfaceType* T, const char* suffix); - bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME); + bool isNSString(ObjCInterfaceType* T, const char* suffix); + bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME); - void RegisterError(NodeTy* N, Expr* E, const char *msg); + void RegisterError(NodeTy* N, Expr* E, const char *msg); public: BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr) @@ -50,6 +52,9 @@ public: virtual ~BasicObjCFoundationChecks() {} virtual bool Audit(ExplodedNode<ValueState>* N); + + virtual void ReportResults(Diagnostic& D); + }; } // end anonymous namespace @@ -98,6 +103,10 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) { return false; } +static inline bool isNil(RVal X) { + return isa<lval::ConcreteInt>(X); +} + //===----------------------------------------------------------------------===// // Error reporting. //===----------------------------------------------------------------------===// @@ -110,6 +119,26 @@ void BasicObjCFoundationChecks::RegisterError(NodeTy* N, Errors.back().push_back(N, msg, E); } +void BasicObjCFoundationChecks::ReportResults(Diagnostic& D) { + + // FIXME: Expand errors into paths. For now, just issue warnings. + + for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I) { + + AnnotatedNode<ValueState>& AN = I->back(); + + unsigned diag = D.getCustomDiagID(Diagnostic::Warning, + AN.getString().c_str()); + + Stmt* S = cast<PostStmt>(AN.getNode()->getLocation()).getStmt(); + FullSourceLoc L(S->getLocStart(), Ctx.getSourceManager()); + + SourceRange R = AN.getExpr()->getSourceRange(); + + D.Report(diag, &AN.getString(), 1, &R, 1); + } +} + //===----------------------------------------------------------------------===// // NSString checking. //===----------------------------------------------------------------------===// @@ -139,10 +168,9 @@ bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N, Expr * E = ME->getArg(0); RVal X = GetRVal(St, E); - if (isa<lval::ConcreteInt>(X)) { + if (isNil(X)) RegisterError(N, E, "Argument to NSString method 'compare:' cannot be nil."); - } } return false; diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index b6f164a57f..b70e21977b 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -411,14 +411,14 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { if (!MsgExprChecks.empty()) Builder->setObjCMsgExprAuditors( - (GRNodeAuditor<ValueState>**) &MsgExprChecks[0], - (GRNodeAuditor<ValueState>**) (&MsgExprChecks[0] + MsgExprChecks.size())); + (GRAuditor<ValueState>**) &MsgExprChecks[0], + (GRAuditor<ValueState>**) (&MsgExprChecks[0] + MsgExprChecks.size())); if (!CallChecks.empty()) Builder->setCallExprAuditors( - (GRNodeAuditor<ValueState>**) &CallChecks[0], - (GRNodeAuditor<ValueState>**) (&CallChecks[0] + CallChecks.size())); + (GRAuditor<ValueState>**) &CallChecks[0], + (GRAuditor<ValueState>**) (&CallChecks[0] + CallChecks.size())); // Create the cleaned state. diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp index 520f6246bf..94cedc0352 100644 --- a/lib/Analysis/GRSimpleVals.cpp +++ b/lib/Analysis/GRSimpleVals.cpp @@ -167,7 +167,7 @@ unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx, CheckerState->undef_receivers_end(), "Receiver in message expression is an uninitialized value."); - + FoundationCheck.get()->ReportResults(Diag); #ifndef NDEBUG if (Visualize) CheckerState->ViewGraph(TrimGraph); #endif |