Moved registration of basic path-sensitive checks from GRSimpleVals.cpp to GRExprEngineInternalChecks.cpp.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@53909 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
new file mode 100644
index 0000000..c1128cc
--- /dev/null
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -0,0 +1,332 @@
+//=-- GRExprEngineInternalChecks.cpp - Builtin GRExprEngine 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 the BugType classes used by GRExprEngine to report
+// bugs derived from builtin checks in the path-sensitive engine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "llvm/Support/Compiler.h"
+
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+template <typename ITERATOR> inline
+ExplodedNode<ValueState>* GetNode(ITERATOR I) {
+ return *I;
+}
+
+template <> inline
+ExplodedNode<ValueState>* GetNode(GRExprEngine::undef_arg_iterator I) {
+ return I->first;
+}
+
+//===----------------------------------------------------------------------===//
+// Bug Descriptions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN BuiltinBug : public BugTypeCacheLocation {
+ const char* name;
+ const char* desc;
+public:
+ BuiltinBug(const char* n, const char* d) : name(n), desc(d) {}
+ virtual const char* getName() const { return name; }
+ virtual const char* getDescription() const { return desc; }
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) = 0;
+ virtual void EmitWarnings(BugReporter& BR) {
+ EmitBuiltinWarnings(BR, cast<GRBugReporter>(BR).getEngine());
+ }
+
+ template <typename ITER>
+ void Emit(BugReporter& BR, ITER I, ITER E) {
+ for (; I != E; ++I) {
+ BugReport R(*this, GetNode(I));
+ BR.EmitWarning(R);
+ }
+ }
+};
+
+class VISIBILITY_HIDDEN NullDeref : public BuiltinBug {
+public:
+ NullDeref() : BuiltinBug("null dereference",
+ "Dereference of null pointer.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end());
+ }
+};
+
+class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug {
+public:
+ UndefinedDeref() : BuiltinBug("bad dereference",
+ "Dereference of undefined value.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.undef_derefs_begin(), Eng.undef_derefs_end());
+ }
+};
+
+class VISIBILITY_HIDDEN DivZero : public BuiltinBug {
+public:
+ DivZero() : BuiltinBug("divide-by-zero",
+ "Division by zero/undefined value.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.explicit_bad_divides_begin(), Eng.explicit_bad_divides_end());
+ }
+};
+
+class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
+public:
+ UndefResult() : BuiltinBug("undefined result",
+ "Result of operation is undefined.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.undef_results_begin(), Eng.undef_results_end());
+ }
+};
+
+class VISIBILITY_HIDDEN BadCall : public BuiltinBug {
+public:
+ BadCall()
+ : BuiltinBug("invalid function call",
+ "Called function is a NULL or undefined function pointer value.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.bad_calls_begin(), Eng.bad_calls_end());
+ }
+};
+
+class VISIBILITY_HIDDEN BadArg : public BuiltinBug {
+public:
+ BadArg() : BuiltinBug("bad argument",
+ "Pass-by-value argument in function is undefined.") {}
+
+ BadArg(const char* d) : BuiltinBug("bad argument", d) {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::UndefArgsTy::iterator I = Eng.undef_arg_begin(),
+ E = Eng.undef_arg_end(); I!=E; ++I) {
+
+ // Generate a report for this bug.
+ RangedBugReport report(*this, I->first);
+ report.addRange(I->second->getSourceRange());
+
+ // Emit the warning.
+ BR.EmitWarning(report);
+ }
+ }
+};
+
+class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
+public:
+ BadMsgExprArg()
+ : BadArg("Pass-by-value argument in message expression is undefined.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(),
+ E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) {
+
+ // Generate a report for this bug.
+ RangedBugReport report(*this, I->first);
+ report.addRange(I->second->getSourceRange());
+
+ // Emit the warning.
+ BR.EmitWarning(report);
+ }
+ }
+};
+
+class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug {
+public:
+ BadReceiver()
+ : BuiltinBug("bad receiver",
+ "Receiver in message expression is an uninitialized value.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::UndefReceiversTy::iterator I=Eng.undef_receivers_begin(),
+ End = Eng.undef_receivers_end(); I!=End; ++I) {
+
+ // Generate a report for this bug.
+ RangedBugReport report(*this, *I);
+
+ ExplodedNode<ValueState>* N = *I;
+ Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
+ Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
+ assert (E && "Receiver cannot be NULL");
+ report.addRange(E->getSourceRange());
+
+ // Emit the warning.
+ BR.EmitWarning(report);
+ }
+ }
+};
+
+class VISIBILITY_HIDDEN RetStack : public BuiltinBug {
+public:
+ RetStack() : BuiltinBug("return of stack address",
+ "Address of stack-allocated variable returned.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ Emit(BR, Eng.ret_stackaddr_begin(), Eng.ret_stackaddr_end());
+ }
+};
+
+
+class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
+ struct VISIBILITY_HIDDEN FindUndefExpr {
+ ValueStateManager& VM;
+ const ValueState* St;
+
+ FindUndefExpr(ValueStateManager& V, const ValueState* S) : VM(V), St(S) {}
+
+ Expr* FindExpr(Expr* Ex) {
+
+ if (!MatchesCriteria(Ex))
+ return 0;
+
+ for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end(); I!=E; ++I)
+ if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
+ Expr* E2 = FindExpr(ExI);
+ if (E2) return E2;
+ }
+
+ return Ex;
+ }
+
+ bool MatchesCriteria(Expr* Ex) { return VM.GetRVal(St, Ex).isUndef(); }
+ };
+
+public:
+ UndefBranch()
+ : BuiltinBug("uninitialized value",
+ "Branch condition evaluates to an uninitialized value.") {}
+
+ virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(),
+ E=Eng.undef_branches_end(); I!=E; ++I) {
+
+ // What's going on here: we want to highlight the subexpression of the
+ // condition that is the most likely source of the "uninitialized
+ // branch condition." We do a recursive walk of the condition's
+ // subexpressions and roughly look for the most nested subexpression
+ // that binds to Undefined. We then highlight that expression's range.
+
+ BlockEdge B = cast<BlockEdge>((*I)->getLocation());
+ Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
+ assert (Ex && "Block must have a terminator.");
+
+ // Get the predecessor node and check if is a PostStmt with the Stmt
+ // being the terminator condition. We want to inspect the state
+ // of that node instead because it will contain main information about
+ // the subexpressions.
+
+ assert (!(*I)->pred_empty());
+
+ // Note: any predecessor will do. They should have identical state,
+ // since all the BlockEdge did was act as an error sink since the value
+ // had to already be undefined.
+ ExplodedNode<ValueState> *N = *(*I)->pred_begin();
+ ProgramPoint P = N->getLocation();
+
+ const ValueState* St = (*I)->getState();
+
+ if (PostStmt* PS = dyn_cast<PostStmt>(&P))
+ if (PS->getStmt() == Ex)
+ St = N->getState();
+
+ FindUndefExpr FindIt(Eng.getStateManager(), St);
+ Ex = FindIt.FindExpr(Ex);
+
+ RangedBugReport R(*this, *I);
+ R.addRange(Ex->getSourceRange());
+
+ BR.EmitWarning(R);
+ }
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// __attribute__(nonnull) checking
+
+class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck {
+ SimpleBugType BT;
+ std::list<RangedBugReport> Reports;
+
+public:
+ CheckAttrNonNull() :
+ BT("'nonnull' argument passed null",
+ "Null pointer passed as an argument to a 'nonnull' parameter") {}
+
+ virtual bool Audit(ExplodedNode<ValueState>* N, ValueStateManager& VMgr) {
+ CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+ const ValueState* state = N->getState();
+
+ RVal X = VMgr.GetRVal(state, CE->getCallee());
+
+ if (!isa<lval::FuncVal>(X))
+ return false;
+
+ FunctionDecl* FD = dyn_cast<FunctionDecl>(cast<lval::FuncVal>(X).getDecl());
+ const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
+
+ if (!Att)
+ return false;
+
+ // Iterate through the arguments of CE and check them for null.
+
+ unsigned idx = 0;
+ bool hasError = false;
+
+ for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
+ ++I, ++idx) {
+
+ if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx))
+ continue;
+
+ RangedBugReport R(BT, N);
+ R.addRange((*I)->getSourceRange());
+ Reports.push_back(R);
+ hasError = true;
+ }
+
+ return hasError;
+ }
+
+ virtual void EmitWarnings(BugReporter& BR) {
+ for (std::list<RangedBugReport>::iterator I=Reports.begin(),
+ E=Reports.end(); I!=E; ++I)
+ BR.EmitWarning(*I);
+ }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Check registration.
+
+void GRExprEngine::RegisterInternalChecks() {
+ Register(new NullDeref());
+ Register(new UndefinedDeref());
+ Register(new UndefBranch());
+ Register(new DivZero());
+ Register(new UndefResult());
+ Register(new BadCall());
+ Register(new RetStack());
+ Register(new BadArg());
+ Register(new BadMsgExprArg());
+ Register(new BadReceiver());
+ AddCheck(new CheckAttrNonNull(), Stmt::CallExprClass);
+}