26using namespace iterator;
30class MismatchedIteratorChecker
31 :
public Checker<check::PreCall, check::PreStmt<BinaryOperator>> {
33 std::unique_ptr<BugType> MismatchedBugType;
38 const SVal &Iter2)
const;
39 void reportBug(
const StringRef &Message,
const SVal &Val1,
42 void reportBug(
const StringRef &Message,
const SVal &Val,
47 MismatchedIteratorChecker();
56MismatchedIteratorChecker::MismatchedIteratorChecker() {
57 MismatchedBugType.reset(
58 new BugType(
this,
"Iterator(s) mismatched",
"Misuse of STL APIs",
62void MismatchedIteratorChecker::checkPreCall(
const CallEvent &
Call,
65 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
69 if (
Func->isOverloadedOperator() &&
72 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&
Call)) {
73 if (
Call.getNumArgs() < 1)
80 verifyMatch(
C, InstCall->getCXXThisVal(),
Call.getArgSVal(0));
82 if (
Call.getNumArgs() < 2)
89 verifyMatch(
C,
Call.getArgSVal(0),
Call.getArgSVal(1));
91 }
else if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&
Call)) {
92 const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
97 verifyMatch(
C,
Call.getArgSVal(0),
98 InstCall->getCXXThisVal().getAsRegion());
99 if (
Call.getNumArgs() == 2) {
100 verifyMatch(
C,
Call.getArgSVal(1),
101 InstCall->getCXXThisVal().getAsRegion());
104 verifyMatch(
C,
Call.getArgSVal(0),
105 InstCall->getCXXThisVal().getAsRegion());
106 if (
Call.getNumArgs() == 3 &&
109 verifyMatch(
C,
Call.getArgSVal(1),
Call.getArgSVal(2));
112 verifyMatch(
C,
Call.getArgSVal(0),
113 InstCall->getCXXThisVal().getAsRegion());
115 }
else if (isa<CXXConstructorCall>(&
Call)) {
117 if (
Call.getNumArgs() < 2)
120 const auto *Ctr = cast<CXXConstructorDecl>(
Call.getDecl());
121 if (Ctr->getNumParams() < 2)
124 if (Ctr->getParamDecl(0)->getName() !=
"first" ||
125 Ctr->getParamDecl(1)->getName() !=
"last")
132 verifyMatch(
C,
Call.getArgSVal(0),
Call.getArgSVal(1));
150 const auto *Templ =
Func->getPrimaryTemplate();
154 const auto *TParams = Templ->getTemplateParameters();
155 const auto *TArgs =
Func->getTemplateSpecializationArgs();
158 for (
size_t I = 0; I < TParams->size(); ++I) {
159 const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
163 if (TPDecl->isParameterPack())
166 const auto TAType = TArgs->get(I).getAsType();
175 for (
auto J = 0
U; J <
Func->getNumParams(); ++J) {
176 const auto *Param =
Func->getParamDecl(J);
177 const auto *ParamType =
185 LHS =
Call.getArgSVal(J);
187 verifyMatch(
C, LHS,
Call.getArgSVal(J));
194void MismatchedIteratorChecker::checkPreStmt(
const BinaryOperator *BO,
200 SVal LVal = State->getSVal(BO->
getLHS(),
C.getLocationContext());
201 SVal RVal = State->getSVal(BO->
getRHS(),
C.getLocationContext());
202 verifyMatch(
C, LVal, RVal);
211 if (isa<SymbolConjured>(ContSym->getSymbol()))
215 auto State =
C.getState();
220 const auto *IterCont = Pos->getContainer();
226 if (
const auto *ContSym = IterCont->getSymbolicBase()) {
227 if (isa<SymbolConjured>(ContSym->getSymbol()))
231 if (IterCont != Cont) {
232 auto *N =
C.generateNonFatalErrorNode(State);
236 reportBug(
"Container accessed using foreign iterator argument.",
243 const SVal &Iter2)
const {
245 auto State =
C.getState();
250 const auto *IterCont1 = Pos1->getContainer();
256 if (
const auto *ContSym = IterCont1->getSymbolicBase()) {
257 if (isa<SymbolConjured>(ContSym->getSymbol()))
265 const auto *IterCont2 = Pos2->getContainer();
266 if (
const auto *ContSym = IterCont2->getSymbolicBase()) {
267 if (isa<SymbolConjured>(ContSym->getSymbol()))
271 if (IterCont1 != IterCont2) {
272 auto *N =
C.generateNonFatalErrorNode(State);
275 reportBug(
"Iterators of different containers used where the "
276 "same container is expected.", Iter1, Iter2,
C, N);
280void MismatchedIteratorChecker::reportBug(
const StringRef &Message,
285 auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
287 R->markInteresting(Val1);
288 R->markInteresting(Val2);
289 C.emitReport(std::move(R));
292void MismatchedIteratorChecker::reportBug(
const StringRef &Message,
296 auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
298 R->markInteresting(Val);
299 R->markInteresting(Reg);
300 C.emitReport(std::move(R));
303void ento::registerMismatchedIteratorChecker(
CheckerManager &mgr) {
307bool ento::shouldRegisterMismatchedIteratorChecker(
const CheckerManager &mgr) {
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isComparisonOp(Opcode Opc)
Represents the result of substituting a type for a template type parameter.
Declaration of a template type parameter.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
MemRegion - The root abstract class for all memory regions.
const SymbolicRegion * getSymbolicBase() const
If this is a symbolic region, returns the region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getMostDerivedObjectRegion() const
Recursively retrieve the region of the most derived class instance of regions of C++ base class insta...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isEraseCall(const FunctionDecl *Func)
bool isInsertCall(const FunctionDecl *Func)
bool isIteratorType(const QualType &Type)
bool isEmplaceCall(const FunctionDecl *Func)
const IteratorPosition * getIteratorPosition(ProgramStateRef State, const SVal &Val)
bool isEraseAfterCall(const FunctionDecl *Func)
bool isComparisonOperator(OverloadedOperatorKind OK)