summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2008-03-27 07:25:52 +0000
committerTed Kremenek <kremenek@apple.com>2008-03-27 07:25:52 +0000
commitc04149299cc44f447c4bff8699db3dda757b027a (patch)
treefe68fbedccfea4b347fd2dd482cbaafc428f0af7 /clang/lib/Analysis
parentf6d2919a3e4e0c5de4c2d2dc28983538ab1038c0 (diff)
downloadbcm5719-llvm-c04149299cc44f447c4bff8699db3dda757b027a.tar.gz
bcm5719-llvm-c04149299cc44f447c4bff8699db3dda757b027a.zip
Added "GRAuditor" and "GRSimpleAPICheck" interface to allow simple stateless checkers to be injected into the analyzer.
Added "AnnotatedPath" class to record an annotated path that will be useful for inspecting paths. Added some boilerplate code for simple checks of Apple's Foundation API. llvm-svn: 48867
Diffstat (limited to 'clang/lib/Analysis')
-rw-r--r--clang/lib/Analysis/BasicObjCFoundationChecks.cpp139
-rw-r--r--clang/lib/Analysis/GRExprEngine.cpp13
2 files changed, 152 insertions, 0 deletions
diff --git a/clang/lib/Analysis/BasicObjCFoundationChecks.cpp b/clang/lib/Analysis/BasicObjCFoundationChecks.cpp
new file mode 100644
index 00000000000..0fae7ddcd38
--- /dev/null
+++ b/clang/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -0,0 +1,139 @@
+//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines BasicObjCFoundationChecks, a class that encapsulates
+// a set of simple checks to run on Objective-C code using Apple's Foundation
+// classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Analysis/PathSensitive/ValueState.h"
+#include "clang/Analysis/PathSensitive/AnnotatedPath.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/Compiler.h"
+
+#include <vector>
+
+using namespace clang;
+
+namespace {
+
+class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
+
+ ASTContext &Ctx;
+ ValueStateManager* VMgr;
+ std::list<AnnotatedPath<ValueState> > Errors;
+
+ RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
+
+ bool isNSString(ObjCInterfaceType* T, const char* suffix);
+ bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
+
+ void RegisterError(NodeTy* N, Expr* E, const char *msg);
+
+public:
+ BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr)
+ : Ctx(ctx), VMgr(vmgr) {}
+
+ virtual ~BasicObjCFoundationChecks() {}
+
+ virtual bool Audit(ExplodedNode<ValueState>* N);
+};
+
+} // end anonymous namespace
+
+
+bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {
+
+ ObjCMessageExpr* ME =
+ cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+
+ Expr* Receiver = ME->getReceiver();
+
+ if (!Receiver)
+ return false;
+
+ assert (Receiver->getType()->isPointerType());
+
+ const PointerType* T = Receiver->getType()->getAsPointerType();
+
+ ObjCInterfaceType* ReceiverType =
+ dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
+
+ if (!ReceiverType)
+ return false;
+
+ const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
+
+ if (name[0] != 'N' || name[1] != 'S')
+ return false;
+
+ name += 2;
+
+ // FIXME: Make all of this faster.
+
+ if (isNSString(ReceiverType, name))
+ return AuditNSString(N, ME);
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Error reporting.
+//===----------------------------------------------------------------------===//
+
+
+void BasicObjCFoundationChecks::RegisterError(NodeTy* N,
+ Expr* E, const char *msg) {
+
+ Errors.push_back(AnnotatedPath<ValueState>());
+ Errors.back().push_back(N, msg, E);
+}
+
+//===----------------------------------------------------------------------===//
+// NSString checking.
+//===----------------------------------------------------------------------===//
+
+bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
+ const char* suffix) {
+
+ return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
+}
+
+bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
+ ObjCMessageExpr* ME) {
+
+ Selector S = ME->getSelector();
+
+ if (S.isUnarySelector())
+ return false;
+
+ // FIXME: This is going to be really slow doing these checks with
+ // lexical comparisons.
+
+ std::string name = S.getName();
+ ValueState* St = N->getState();
+
+ if (name == "compare:") {
+ // Check if the compared NSString is nil.
+ Expr * E = ME->getArg(0);
+ RVal X = GetRVal(St, E);
+
+ if (isa<lval::ConcreteInt>(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 bce1cbd90c7..b6f164a57f1 100644
--- a/clang/lib/Analysis/GRExprEngine.cpp
+++ b/clang/lib/Analysis/GRExprEngine.cpp
@@ -407,6 +407,19 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) {
CurrentStmt = S;
NodeSet Dst;
+ // Set up our simple checks.
+
+ if (!MsgExprChecks.empty())
+ Builder->setObjCMsgExprAuditors(
+ (GRNodeAuditor<ValueState>**) &MsgExprChecks[0],
+ (GRNodeAuditor<ValueState>**) (&MsgExprChecks[0] + MsgExprChecks.size()));
+
+
+ if (!CallChecks.empty())
+ Builder->setCallExprAuditors(
+ (GRNodeAuditor<ValueState>**) &CallChecks[0],
+ (GRNodeAuditor<ValueState>**) (&CallChecks[0] + CallChecks.size()));
+
// Create the cleaned state.
CleanedState = StateMgr.RemoveDeadBindings(StmtEntryNode->getState(),
OpenPOWER on IntegriCloud