diff options
Diffstat (limited to 'lib/Analysis/GRExprEngineInternalChecks.cpp')
-rw-r--r-- | lib/Analysis/GRExprEngineInternalChecks.cpp | 249 |
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); } |