aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2008-03-27 21:15:17 +0000
committerTed Kremenek <kremenek@apple.com>2008-03-27 21:15:17 +0000
commite5d5c204c761cc3b2a6374a15b035420f207c7af (patch)
tree3a17ff2a287a423e6685351aa3639b522fb000bf
parent0f9063c116b7c3b05d8042b5976463c2dae04861 (diff)
Hooked up initial NSString interface checking to GRSimpleVals.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@48895 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Analysis/PathSensitive/AnnotatedPath.h4
-rw-r--r--include/clang/Analysis/PathSensitive/GRCoreEngine.h48
-rw-r--r--include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h4
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp46
-rw-r--r--lib/Analysis/GRExprEngine.cpp8
-rw-r--r--lib/Analysis/GRSimpleVals.cpp2
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