Hooked up initial NSString interface checking to GRSimpleVals.
llvm-svn: 48895
This commit is contained in:
parent
f740509e58
commit
27156c8c9f
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue