Refactor bad callee check into a Checker.

Now bad callee is checked as a PreVisit to the CallExpr.

llvm-svn: 80771
This commit is contained in:
Zhongxing Xu 2009-09-02 08:10:35 +00:00
parent 656b10a1fa
commit 79affb7b94
3 changed files with 35 additions and 29 deletions

View File

@ -63,7 +63,8 @@ clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
const Stmt*
clang::bugreporter::GetCalleeExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
// Callee is checked as a PreVisit to the CallExpr.
const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
if (const CallExpr *CE = dyn_cast<CallExpr>(S))
return CE->getCallee();
return NULL;

View File

@ -1493,20 +1493,7 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
// Check for undefined control-flow or calls to NULL.
if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
ExplodedNode* N = Builder->generateNode(CE, state, *DI);
if (N) {
N->markAsSink();
BadCalls.insert(N);
}
continue;
}
// Check for the "noreturn" attribute.
SaveAndRestore<bool> OldSink(Builder->BuildSinks);

View File

@ -70,7 +70,7 @@ public:
const std::string &getDescription() const { return desc; }
virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) = 0;
virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {}
void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); }
@ -220,14 +220,10 @@ public:
class VISIBILITY_HIDDEN BadCall : public BuiltinBug {
public:
BadCall(GRExprEngine *eng)
BadCall(GRExprEngine *eng = 0)
: BuiltinBug(eng, "Invalid function call",
"Called function pointer is a null or undefined pointer value") {}
void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.bad_calls_begin(), Eng.bad_calls_end());
}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode* N,
BuiltinBugReport *R) {
@ -252,18 +248,12 @@ public:
class VISIBILITY_HIDDEN BadArg : public BuiltinBug {
public:
BadArg() : BuiltinBug(0, "Uninitialized argument",
"Pass-by-value argument in function call is undefined.") {}
BadArg(GRExprEngine* eng) : BuiltinBug(eng,"Uninitialized argument",
BadArg(GRExprEngine* eng=0) : BuiltinBug(eng,"Uninitialized argument",
"Pass-by-value argument in function call is undefined.") {}
BadArg(GRExprEngine* eng, const char* d)
: BuiltinBug(eng,"Uninitialized argument", d) {}
void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode* N,
BuiltinBugReport *R) {
@ -662,6 +652,34 @@ void CheckUndefinedArg::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE){
}
}
class VISIBILITY_HIDDEN CheckBadCall : public CheckerVisitor<CheckBadCall> {
BadCall *BT;
public:
CheckBadCall() : BT(0) {}
~CheckBadCall() {}
const void *getTag() {
static int x = 0;
return &x;
}
void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
};
void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
const Expr *Callee = CE->getCallee()->IgnoreParens();
SVal L = C.getState()->getSVal(Callee);
if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
if (ExplodedNode *N = C.generateNode(CE, C.getState(), true)) {
if (!BT)
BT = new BadCall();
C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
}
}
}
}
//===----------------------------------------------------------------------===//
// Check registration.
@ -678,7 +696,6 @@ void GRExprEngine::RegisterInternalChecks() {
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 BadMsgExprArg(this));
@ -695,4 +712,5 @@ void GRExprEngine::RegisterInternalChecks() {
// object.
registerCheck(new CheckAttrNonNull());
registerCheck(new CheckUndefinedArg());
registerCheck(new CheckBadCall());
}