}
-static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) {
+static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf,
+ bool StandardWarnings = true) {
llvm::OwningPtr<GRTransferFuncs> TF(tf);
GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L);
Eng.setTransferFunctions(tf);
+ if (StandardWarnings) {
+ Eng.RegisterInternalChecks();
+ RegisterAppleChecks(Eng);
+ }
+
// Execute the worklist algorithm.
Eng.ExecuteWorkList();
}
static void ActionCheckerCFRefAux(AnalysisManager& mgr, bool GCEnabled,
- bool StandardWarnings) {
-
+ bool StandardWarnings) {
+
GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
GCEnabled,
- StandardWarnings,
mgr.getLangOptions());
- ActionGRExprEngine(mgr, TF);
+ ActionGRExprEngine(mgr, TF, StandardWarnings);
}
static void ActionCheckerCFRef(AnalysisManager& mgr) {
class BugReporter;
class ObjCImplementationDecl;
class LangOptions;
+class GRExprEngine;
void CheckDeadStores(LiveVariables& L, BugReporter& BR);
GRTransferFuncs* MakeGRSimpleValsTF();
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
- bool StandardWarnings,
const LangOptions& lopts);
void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L,
void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR);
+void RegisterAppleChecks(GRExprEngine& Eng);
+
} // end namespace clang
#endif
BugTypes.push_back(B);
}
+ void RegisterInternalChecks();
+
void EmitWarnings(BugReporterData& BRData);
bool isRetStackAddr(const NodeTy* N) const {
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/ValueState.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/LocalCheckers.h"
+
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
return new AuditCFNumberCreate(Ctx, VMgr);
}
+//===----------------------------------------------------------------------===//
+// Check registration.
+
+void clang::RegisterAppleChecks(GRExprEngine& Eng) {
+ ASTContext& Ctx = Eng.getContext();
+ ValueStateManager* VMgr = &Eng.getStateManager();
+
+ Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr),
+ Stmt::ObjCMessageExprClass);
+
+ Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr), Stmt::CallExprClass);
+}
// Instance variables.
RetainSummaryManager Summaries;
- const bool EmitStandardWarnings;
const LangOptions& LOpts;
RefBFactoryTy RefBFactory;
public:
- CFRefCount(ASTContext& Ctx, bool gcenabled, bool StandardWarnings,
- const LangOptions& lopts)
+ CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
: Summaries(Ctx, gcenabled),
- EmitStandardWarnings(StandardWarnings),
LOpts(lopts),
RetainSelector(GetNullarySelector("retain", Ctx)),
ReleaseSelector(GetNullarySelector("release", Ctx)),
} // end anonymous namespace
void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
- if (EmitStandardWarnings) GRSimpleVals::RegisterChecks(Eng);
Eng.Register(new UseAfterRelease(*this));
Eng.Register(new BadRelease(*this));
Eng.Register(new Leak(*this));
//===----------------------------------------------------------------------===//
GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
- bool StandardWarnings,
const LangOptions& lopts) {
- return new CFRefCount(Ctx, GCEnabled, StandardWarnings, lopts);
+ return new CFRefCount(Ctx, GCEnabled, lopts);
}
--- /dev/null
+//=-- 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);
+}
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;
-}
-
-template <typename ITER>
-void GenericEmitWarnings(BugReporter& BR, BugType& D, ITER I, ITER E) {
-
- for (; I != E; ++I) {
- BugReport R(D, GetNode(I));
- BR.EmitWarning(R);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Bug Descriptions.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class VISIBILITY_HIDDEN NullDeref : public BugTypeCacheLocation {
-public:
- virtual const char* getName() const {
- return "null dereference";
- }
-
- virtual const char* getDescription() const {
- return "Dereference of null pointer.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
- GenericEmitWarnings(BR, *this, Eng.null_derefs_begin(),
- Eng.null_derefs_end());
- }
-};
-
-class VISIBILITY_HIDDEN UndefDeref : public BugTypeCacheLocation {
-public:
- virtual const char* getName() const {
- return "bad dereference";
- }
-
- virtual const char* getDescription() const {
- return "Dereference of undefined value.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
- GenericEmitWarnings(BR, *this, Eng.undef_derefs_begin(),
- Eng.undef_derefs_end());
- }
-};
-
-class VISIBILITY_HIDDEN UndefBranch : public BugTypeCacheLocation {
-public:
- virtual const char* getName() const {
- return "uninitialized value";
- }
-
- virtual const char* getDescription() const {
- return "Branch condition evaluates to an uninitialized value.";
- }
-
- virtual void EmitWarnings(BugReporter& BR);
-};
-
-class VISIBILITY_HIDDEN DivZero : public BugTypeCacheLocation {
-public:
- virtual const char* getName() const {
- return "divide-by-zero";
- }
-
- virtual const char* getDescription() const {
- return "Division by zero/undefined value.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
- GenericEmitWarnings(BR, *this, Eng.explicit_bad_divides_begin(),
- Eng.explicit_bad_divides_end());
- }
-};
-
-class VISIBILITY_HIDDEN UndefResult : public BugTypeCacheLocation {
-public:
- virtual const char* getName() const {
- return "undefined result";
- }
-
- virtual const char* getDescription() const {
- return "Result of operation is undefined.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
- GenericEmitWarnings(BR, *this, Eng.undef_results_begin(),
- Eng.undef_results_end());
- }
-};
-
-class VISIBILITY_HIDDEN BadCall : public BugTypeCacheLocation {
-public:
- virtual const char* getName() const {
- return "invalid function call";
- }
-
- virtual const char* getDescription() const {
- return "Called function is a NULL or undefined function pointer value.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
- GenericEmitWarnings(BR, *this, Eng.bad_calls_begin(),
- Eng.bad_calls_end());
- }
-};
-
-
-class VISIBILITY_HIDDEN BadArg : public BugTypeCacheLocation {
-public:
-
- virtual ~BadArg() {}
-
- virtual const char* getName() const {
- return "bad argument";
- }
-
- virtual const char* getDescription() const {
- return "Pass-by-value argument in function is undefined.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
-
- 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:
- virtual const char* getName() const {
- return "bad argument";
- }
-
- virtual const char* getDescription() const {
- return "Pass-by-value argument in message expression is undefined.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
-
- 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 BugTypeCacheLocation {
-public:
- virtual const char* getName() const {
- return "bad receiver";
- }
-
- virtual const char* getDescription() const {
- return "Receiver in message expression is an uninitialized value.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
-
- 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 BugTypeCacheLocation {
-public:
- virtual const char* getName() const {
- return "return of stack address";
- }
-
- virtual const char* getDescription() const {
- return "Address of stack-allocated variable returned.";
- }
-
- virtual void EmitWarnings(BugReporter& BR) {
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
- GenericEmitWarnings(BR, *this, Eng.ret_stackaddr_begin(),
- Eng.ret_stackaddr_end());
- }
-};
-
-} // end anonymous namespace
-
-
-namespace {
-
-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(); }
-};
-
-} // end anonymous namespace
-
-
-void UndefBranch::EmitWarnings(BugReporter& BR) {
-
- GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
-
- 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);
- }
-};
-
-//===----------------------------------------------------------------------===//
-// Check registration.
-
-void GRSimpleVals::RegisterChecks(GRExprEngine& Eng) {
-
- // Path-sensitive checks.
- Eng.Register(new NullDeref());
- Eng.Register(new UndefDeref());
- Eng.Register(new UndefBranch());
- Eng.Register(new DivZero());
- Eng.Register(new UndefResult());
- Eng.Register(new BadCall());
- Eng.Register(new RetStack());
- Eng.Register(new BadArg());
- Eng.Register(new BadMsgExprArg());
- Eng.Register(new BadReceiver());
-
- // Add extra checkers.
- ASTContext& Ctx = Eng.getContext();
- ValueStateManager* VMgr = &Eng.getStateManager();
-
- GRSimpleAPICheck* Check = CreateBasicObjCFoundationChecks(Ctx, VMgr);
- Eng.AddCheck(Check, Stmt::ObjCMessageExprClass);
-
- Check = CreateAuditCFNumberCreate(Ctx, VMgr);
- Eng.AddCheck(Check, Stmt::CallExprClass);
-
- Eng.AddCheck(new CheckAttrNonNull(), Stmt::CallExprClass);
-}
-
//===----------------------------------------------------------------------===//
// Transfer Function creation for External clients.
//===----------------------------------------------------------------------===//
GRSimpleVals() {}
virtual ~GRSimpleVals() {}
- virtual void RegisterChecks(GRExprEngine& Eng);
-
// Casts.
virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT);