From 27156c8c9f791741a5ee3a76d0aac94e3be55f54 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Thu, 27 Mar 2008 21:15:17 +0000 Subject: [PATCH] Hooked up initial NSString interface checking to GRSimpleVals. llvm-svn: 48895 --- .../Analysis/PathSensitive/AnnotatedPath.h | 4 +- .../Analysis/PathSensitive/GRCoreEngine.h | 48 +++++++++---------- .../Analysis/PathSensitive/GRSimpleAPICheck.h | 4 +- .../Analysis/BasicObjCFoundationChecks.cpp | 46 ++++++++++++++---- clang/lib/Analysis/GRExprEngine.cpp | 8 ++-- clang/lib/Analysis/GRSimpleVals.cpp | 2 +- 6 files changed, 71 insertions(+), 41 deletions(-) diff --git a/clang/include/clang/Analysis/PathSensitive/AnnotatedPath.h b/clang/include/clang/Analysis/PathSensitive/AnnotatedPath.h index 5056b77aab28..3873bd45d290 100644 --- a/clang/include/clang/Analysis/PathSensitive/AnnotatedPath.h +++ b/clang/include/clang/Analysis/PathSensitive/AnnotatedPath.h @@ -34,7 +34,7 @@ public: Expr* e = NULL) : Node(N), annotation(annot), E(e) {} - ExplodedNode getNode() const { return Node; } + ExplodedNode* 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& back() { return path.back(); } + const AnnotatedNode& back() const { return path.back(); } }; } // end clang namespace diff --git a/clang/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/clang/include/clang/Analysis/PathSensitive/GRCoreEngine.h index e22df35ab61a..4228531fb2b3 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/clang/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 -class GRNodeAuditor { -public: - typedef ExplodedNode NodeTy; - - virtual ~GRNodeAuditor() {} - virtual bool Audit(NodeTy* N) = 0; -}; template @@ -181,8 +173,8 @@ class GRStmtNodeBuilder { GRStmtNodeBuilderImpl& NB; StateTy* CleanedState; - GRNodeAuditor **CallExprAuditBeg, **CallExprAuditEnd; - GRNodeAuditor **ObjCMsgExprAuditBeg, **ObjCMsgExprAuditEnd; + GRAuditor **CallExprAuditBeg, **CallExprAuditEnd; + GRAuditor **ObjCMsgExprAuditBeg, **ObjCMsgExprAuditEnd; public: GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb) : NB(nb), @@ -192,14 +184,14 @@ public: CleanedState = getLastNode()->getState(); } - void setObjCMsgExprAuditors(GRNodeAuditor **B, - GRNodeAuditor **E) { + void setObjCMsgExprAuditors(GRAuditor **B, + GRAuditor **E) { ObjCMsgExprAuditBeg = B; ObjCMsgExprAuditEnd = E; } - void setCallExprAuditors(GRNodeAuditor **B, - GRNodeAuditor **E) { + void setCallExprAuditors(GRAuditor **B, + GRAuditor **E) { CallExprAuditBeg = B; CallExprAuditEnd = E; } @@ -240,8 +232,22 @@ public: StateTy* PredState = GetState(Pred); + GRAuditor **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(S)) - for (GRNodeAuditor** I = CallExprAuditBeg; - I != CallExprAuditEnd; ++I) - (*I)->Audit(N); - else if (isa(S)) - for (GRNodeAuditor** I = ObjCMsgExprAuditBeg; - I != ObjCMsgExprAuditEnd; ++I) - (*I)->Audit(N); + for ( ; AB != AE; ++AB) + (*AB)->Audit(N); } } diff --git a/clang/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/clang/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h index 2da2cb4045a0..16db80229049 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h +++ b/clang/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h @@ -21,13 +21,13 @@ namespace clang { class ValueState; +class Diagnostic; class GRSimpleAPICheck : public GRAuditor { public: GRSimpleAPICheck() {} virtual ~GRSimpleAPICheck() {} - - + virtual void ReportResults(Diagnostic& D) {} }; } // end namespace clang diff --git a/clang/lib/Analysis/BasicObjCFoundationChecks.cpp b/clang/lib/Analysis/BasicObjCFoundationChecks.cpp index 4d7a4d99db8b..d2a2dd6a51b0 100644 --- a/clang/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/clang/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -32,16 +32,18 @@ namespace { class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { - ASTContext &Ctx; - ValueStateManager* VMgr; - std::list > Errors; + ASTContext &Ctx; + ValueStateManager* VMgr; + + typedef std::list > 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* N); + + virtual void ReportResults(Diagnostic& D); + }; } // end anonymous namespace @@ -98,6 +103,10 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode* N) { return false; } +static inline bool isNil(RVal X) { + return isa(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& AN = I->back(); + + unsigned diag = D.getCustomDiagID(Diagnostic::Warning, + AN.getString().c_str()); + + Stmt* S = cast(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(X)) { + if (isNil(X)) RegisterError(N, E, "Argument to NSString method 'compare:' cannot be nil."); - } } return false; diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index b6f164a57f10..b70e21977bec 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -411,14 +411,14 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { if (!MsgExprChecks.empty()) Builder->setObjCMsgExprAuditors( - (GRNodeAuditor**) &MsgExprChecks[0], - (GRNodeAuditor**) (&MsgExprChecks[0] + MsgExprChecks.size())); + (GRAuditor**) &MsgExprChecks[0], + (GRAuditor**) (&MsgExprChecks[0] + MsgExprChecks.size())); if (!CallChecks.empty()) Builder->setCallExprAuditors( - (GRNodeAuditor**) &CallChecks[0], - (GRNodeAuditor**) (&CallChecks[0] + CallChecks.size())); + (GRAuditor**) &CallChecks[0], + (GRAuditor**) (&CallChecks[0] + CallChecks.size())); // Create the cleaned state. diff --git a/clang/lib/Analysis/GRSimpleVals.cpp b/clang/lib/Analysis/GRSimpleVals.cpp index 520f6246bfef..94cedc03529f 100644 --- a/clang/lib/Analysis/GRSimpleVals.cpp +++ b/clang/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