aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/GRExprEngineInternalChecks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis/GRExprEngineInternalChecks.cpp')
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp249
1 files changed, 117 insertions, 132 deletions
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index e7a644ce19..76286f4dbf 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -39,154 +39,143 @@ ExplodedNode<GRState>* GetNode(GRExprEngine::undef_arg_iterator I) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN BuiltinBug : public BugTypeCacheLocation {
+class VISIBILITY_HIDDEN BuiltinBug : public BugType {
+ GRExprEngine &Eng;
protected:
- const char* name;
- const char* desc;
+ const std::string desc;
public:
- BuiltinBug(const char* n, const char* d = 0) : name(n), desc(d) {}
- virtual const char* getName() const { return name; }
- virtual const char* getDescription() const {
- return desc ? desc : name;
- }
+ BuiltinBug(GRExprEngine *eng, const char* n, const char* d)
+ : BugType(n, "Logic Errors"), Eng(*eng), desc(d) {}
+
+ BuiltinBug(GRExprEngine *eng, const char* n)
+ : BugType(n, "Logic Errors"), Eng(*eng), desc(n) {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) = 0;
- virtual void EmitWarnings(BugReporter& BR) {
- EmitBuiltinWarnings(BR, cast<GRBugReporter>(BR).getEngine());
- }
+ virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) = 0;
+
+ void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); }
template <typename ITER>
void Emit(BugReporter& BR, ITER I, ITER E) {
- for (; I != E; ++I) {
- BugReport R(*this, GetNode(I));
- BR.EmitWarning(R);
- }
- }
-
- virtual const char* getCategory() const { return "Logic Errors"; }
+ for (; I != E; ++I) BR.EmitReport(new BugReport(*this, desc.c_str(),
+ GetNode(I)));
+ }
};
class VISIBILITY_HIDDEN NullDeref : public BuiltinBug {
public:
- NullDeref() : BuiltinBug("null dereference",
- "Dereference of null pointer.") {}
+ NullDeref(GRExprEngine* eng)
+ : BuiltinBug(eng,"null dereference", "Dereference of null pointer.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end());
}
};
class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug {
public:
- UndefinedDeref() : BuiltinBug("uninitialized pointer dereference",
- "Dereference of undefined value.") {}
+ UndefinedDeref(GRExprEngine* eng)
+ : BuiltinBug(eng,"uninitialized pointer dereference",
+ "Dereference of undefined value.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(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.") {}
+ DivZero(GRExprEngine* eng)
+ : BuiltinBug(eng,"divide-by-zero", "Division by zero/undefined value.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(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",
+ UndefResult(GRExprEngine* eng) : BuiltinBug(eng,"undefined result",
"Result of operation is undefined.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(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",
+ BadCall(GRExprEngine *eng)
+ : BuiltinBug(eng,"invalid function call",
"Called function is a NULL or undefined function pointer value.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.bad_calls_begin(), Eng.bad_calls_end());
}
};
class VISIBILITY_HIDDEN BadArg : public BuiltinBug {
public:
- BadArg() : BuiltinBug("uninitialized argument",
+ BadArg(GRExprEngine* eng) : BuiltinBug(eng,"uninitialized argument",
"Pass-by-value argument in function is undefined.") {}
- BadArg(const char* d) : BuiltinBug("uninitialized argument", d) {}
+ BadArg(GRExprEngine* eng, const char* d)
+ : BuiltinBug(eng,"uninitialized argument", d) {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(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);
+ RangedBugReport *report = new RangedBugReport(*this, desc.c_str(),
+ I->first);
+ report->addRange(I->second->getSourceRange());
+ BR.EmitReport(report);
}
}
};
class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
public:
- BadMsgExprArg()
- : BadArg("Pass-by-value argument in message expression is undefined.") {}
+ BadMsgExprArg(GRExprEngine* eng)
+ : BadArg(eng,"Pass-by-value argument in message expression is undefined."){}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(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) {
-
+ 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);
+ RangedBugReport *report = new RangedBugReport(*this, desc.c_str(), I->first);
+ report->addRange(I->second->getSourceRange());
+ BR.EmitReport(report);
}
}
};
class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug {
public:
- BadReceiver()
- : BuiltinBug("uninitialized receiver",
+ BadReceiver(GRExprEngine* eng)
+ : BuiltinBug(eng,"uninitialized receiver",
"Receiver in message expression is an uninitialized value.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
for (GRExprEngine::ErrorNodes::iterator I=Eng.undef_receivers_begin(),
End = Eng.undef_receivers_end(); I!=End; ++I) {
// Generate a report for this bug.
- RangedBugReport report(*this, *I);
-
+ RangedBugReport *report = new RangedBugReport(*this, desc.c_str(), *I);
ExplodedNode<GRState>* 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);
+ report->addRange(E->getSourceRange());
+ BR.EmitReport(report);
}
}
};
class VISIBILITY_HIDDEN RetStack : public BuiltinBug {
public:
- RetStack() : BuiltinBug("return of stack address") {}
+ RetStack(GRExprEngine* eng) : BuiltinBug(eng, "return of stack address") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
for (GRExprEngine::ret_stackaddr_iterator I=Eng.ret_stackaddr_begin(),
End = Eng.ret_stackaddr_end(); I!=End; ++I) {
@@ -232,22 +221,20 @@ public:
<< V.getRegion()->getString() << "' returned.";
}
- RangedBugReport report(*this, N, os.str().c_str());
- report.addRange(E->getSourceRange());
- if (R.isValid()) report.addRange(R);
-
- // Emit the warning.
- BR.EmitWarning(report);
+ RangedBugReport *report = new RangedBugReport(*this, os.str().c_str(), N);
+ report->addRange(E->getSourceRange());
+ if (R.isValid()) report->addRange(R);
+ BR.EmitReport(report);
}
}
};
class VISIBILITY_HIDDEN RetUndef : public BuiltinBug {
public:
- RetUndef() : BuiltinBug("uninitialized return value",
+ RetUndef(GRExprEngine* eng) : BuiltinBug(eng,"uninitialized return value",
"Uninitialized or undefined return value returned to caller.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.ret_undef_begin(), Eng.ret_undef_end());
}
};
@@ -276,11 +263,11 @@ class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
};
public:
- UndefBranch()
- : BuiltinBug("uninitialized value",
+ UndefBranch(GRExprEngine *eng)
+ : BuiltinBug(eng,"uninitialized value",
"Branch condition evaluates to an uninitialized value.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(),
E=Eng.undef_branches_end(); I!=E; ++I) {
@@ -289,7 +276,6 @@ public:
// 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.");
@@ -298,7 +284,6 @@ public:
// 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,
@@ -306,7 +291,6 @@ public:
// had to already be undefined.
ExplodedNode<GRState> *N = *(*I)->pred_begin();
ProgramPoint P = N->getLocation();
-
const GRState* St = (*I)->getState();
if (PostStmt* PS = dyn_cast<PostStmt>(&P))
@@ -316,31 +300,29 @@ public:
FindUndefExpr FindIt(Eng.getStateManager(), St);
Ex = FindIt.FindExpr(Ex);
- RangedBugReport R(*this, *I);
- R.addRange(Ex->getSourceRange());
-
- BR.EmitWarning(R);
+ RangedBugReport *R = new RangedBugReport(*this, desc.c_str(), *I);
+ R->addRange(Ex->getSourceRange());
+ BR.EmitReport(R);
}
}
};
class VISIBILITY_HIDDEN OutOfBoundMemoryAccess : public BuiltinBug {
public:
- OutOfBoundMemoryAccess() : BuiltinBug("out-of-bound memory access",
- "Load or store into an out-of-bound memory position.") {}
+ OutOfBoundMemoryAccess(GRExprEngine* eng)
+ : BuiltinBug(eng,"out-of-bound memory access",
+ "Load or store into an out-of-bound memory position.") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.explicit_oob_memacc_begin(), Eng.explicit_oob_memacc_end());
}
};
class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug {
-
public:
- BadSizeVLA() : BuiltinBug("Zero-sized VLA",
- "VLAs with zero-size are undefined.") {}
+ BadSizeVLA(GRExprEngine* eng) : BuiltinBug(eng, "bad VLA size") {}
- virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
+ void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
for (GRExprEngine::ErrorNodes::iterator
I = Eng.ExplicitBadSizedVLA.begin(),
E = Eng.ExplicitBadSizedVLA.end(); I!=E; ++I) {
@@ -358,24 +340,16 @@ public:
std::string buf;
llvm::raw_string_ostream os(buf);
os << "The expression used to specify the number of elements in the VLA '"
- << VD->getNameAsString() << "' evaluates to ";
+ << VD->getNameAsString() << "' evaluates to ";
- SVal X = Eng.getStateManager().GetSVal(N->getState(), SizeExpr);
- if (X.isUndef()) {
- name = "Undefined size for VLA";
+ if (Eng.getStateManager().GetSVal(N->getState(), SizeExpr).isUndef())
os << "an undefined or garbage value.";
- }
- else {
- name = "Zero-sized VLA";
- os << " to 0. VLAs with no elements have undefined behavior.";
- }
+ else
+ os << "0. VLAs with no elements have undefined behavior.";
- desc = os.str().c_str();
- RangedBugReport report(*this, N);
- report.addRange(SizeExpr->getSourceRange());
-
- // Emit the warning.
- BR.EmitWarning(report);
+ RangedBugReport *report = new RangedBugReport(*this, os.str().c_str(), N);
+ report->addRange(SizeExpr->getSourceRange());
+ BR.EmitReport(report);
}
}
};
@@ -384,13 +358,11 @@ public:
// __attribute__(nonnull) checking
class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck {
- SimpleBugType BT;
- std::list<RangedBugReport> Reports;
+ BugType *BT;
+ BugReporter &BR;
public:
- CheckAttrNonNull() :
- BT("'nonnull' argument passed null", "API",
- "Null pointer passed as an argument to a 'nonnull' parameter") {}
+ CheckAttrNonNull(BugReporter &br) : BT(0), BR(br) {}
virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager& VMgr) {
CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
@@ -408,7 +380,6 @@ public:
return false;
// Iterate through the arguments of CE and check them for null.
-
unsigned idx = 0;
bool hasError = false;
@@ -417,40 +388,54 @@ public:
if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx))
continue;
+
+ // Lazily allocate the BugType object if it hasn't already been created.
+ // Ownership is transferred to the BugReporter object once the BugReport
+ // is passed to 'EmitWarning'.
+ if (!BT) BT = new BugType("'nonnull' argument passed null", "API");
- RangedBugReport R(BT, N);
- R.addRange((*I)->getSourceRange());
- Reports.push_back(R);
+ RangedBugReport *R = new RangedBugReport(*BT,
+ "Null pointer passed as an argument to a "
+ "'nonnull' parameter", N);
+
+ R->addRange((*I)->getSourceRange());
+ BR.EmitReport(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 RetUndef());
- Register(new BadArg());
- Register(new BadMsgExprArg());
- Register(new BadReceiver());
- Register(new OutOfBoundMemoryAccess());
- Register(new BadSizeVLA());
- AddCheck(new CheckAttrNonNull(), Stmt::CallExprClass);
+ // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
+ // are different than what probably many checks will do since they don't
+ // create BugReports on-the-fly but instead wait until GRExprEngine finishes
+ // analyzing a function. Generation of BugReport objects is done via a call
+ // to 'FlushReports' from BugReporter.
+ BR.Register(new NullDeref(this));
+ BR.Register(new UndefinedDeref(this));
+ BR.Register(new UndefBranch(this));
+ BR.Register(new DivZero(this));
+ BR.Register(new UndefResult(this));
+ BR.Register(new BadCall(this));
+ BR.Register(new RetStack(this));
+ BR.Register(new RetUndef(this));
+ BR.Register(new BadArg(this));
+ BR.Register(new BadMsgExprArg(this));
+ BR.Register(new BadReceiver(this));
+ BR.Register(new OutOfBoundMemoryAccess(this));
+ BR.Register(new BadSizeVLA(this));
+
+ // The following checks do not need to have their associated BugTypes
+ // explicitly registered with the BugReporter. If they issue any BugReports,
+ // their associated BugType will get registered with the BugReporter
+ // automatically. Note that the check itself is owned by the GRExprEngine
+ // object.
+ AddCheck(new CheckAttrNonNull(BR), Stmt::CallExprClass);
}