26using namespace iterator;
30class MismatchedIteratorChecker
31 :
public Checker<check::PreCall, check::PreStmt<BinaryOperator>> {
33 const BugType MismatchedBugType{
this,
"Iterator(s) mismatched",
41 void reportBug(StringRef Message,
SVal Val,
const MemRegion *Reg,
52void MismatchedIteratorChecker::checkPreCall(
const CallEvent &
Call,
55 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
59 if (
Func->isOverloadedOperator() &&
62 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&
Call)) {
63 if (
Call.getNumArgs() < 1)
70 verifyMatch(
C, InstCall->getCXXThisVal(),
Call.getArgSVal(0));
72 if (
Call.getNumArgs() < 2)
79 verifyMatch(
C,
Call.getArgSVal(0),
Call.getArgSVal(1));
81 }
else if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&
Call)) {
82 const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
87 verifyMatch(
C,
Call.getArgSVal(0),
88 InstCall->getCXXThisVal().getAsRegion());
89 if (
Call.getNumArgs() == 2) {
90 verifyMatch(
C,
Call.getArgSVal(1),
91 InstCall->getCXXThisVal().getAsRegion());
94 verifyMatch(
C,
Call.getArgSVal(0),
95 InstCall->getCXXThisVal().getAsRegion());
96 if (
Call.getNumArgs() == 3 &&
99 verifyMatch(
C,
Call.getArgSVal(1),
Call.getArgSVal(2));
102 verifyMatch(
C,
Call.getArgSVal(0),
103 InstCall->getCXXThisVal().getAsRegion());
105 }
else if (isa<CXXConstructorCall>(&
Call)) {
107 if (
Call.getNumArgs() < 2)
110 const auto *Ctr = cast<CXXConstructorDecl>(
Call.getDecl());
111 if (Ctr->getNumParams() < 2)
114 if (Ctr->getParamDecl(0)->getName() !=
"first" ||
115 Ctr->getParamDecl(1)->getName() !=
"last")
122 verifyMatch(
C,
Call.getArgSVal(0),
Call.getArgSVal(1));
140 const auto *Templ =
Func->getPrimaryTemplate();
144 const auto *TParams = Templ->getTemplateParameters();
145 const auto *TArgs =
Func->getTemplateSpecializationArgs();
148 for (
size_t I = 0; I < TParams->size(); ++I) {
149 const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
153 if (TPDecl->isParameterPack())
156 const auto TAType = TArgs->get(I).getAsType();
165 for (
auto J = 0
U; J <
Func->getNumParams(); ++J) {
166 const auto *Param =
Func->getParamDecl(J);
167 const auto *ParamType =
175 LHS =
Call.getArgSVal(J);
177 verifyMatch(
C, LHS,
Call.getArgSVal(J));
184void MismatchedIteratorChecker::checkPreStmt(
const BinaryOperator *BO,
190 SVal LVal = State->getSVal(BO->
getLHS(),
C.getLocationContext());
191 SVal RVal = State->getSVal(BO->
getRHS(),
C.getLocationContext());
192 verifyMatch(
C, LVal, RVal);
201 if (isa<SymbolConjured>(ContSym->getSymbol()))
205 auto State =
C.getState();
210 const auto *IterCont = Pos->getContainer();
216 if (
const auto *ContSym = IterCont->getSymbolicBase()) {
217 if (isa<SymbolConjured>(ContSym->getSymbol()))
221 if (IterCont != Cont) {
222 auto *N =
C.generateNonFatalErrorNode(State);
226 reportBug(
"Container accessed using foreign iterator argument.",
234 auto State =
C.getState();
239 const auto *IterCont1 = Pos1->getContainer();
245 if (
const auto *ContSym = IterCont1->getSymbolicBase()) {
246 if (isa<SymbolConjured>(ContSym->getSymbol()))
254 const auto *IterCont2 = Pos2->getContainer();
255 if (
const auto *ContSym = IterCont2->getSymbolicBase()) {
256 if (isa<SymbolConjured>(ContSym->getSymbol()))
260 if (IterCont1 != IterCont2) {
261 auto *N =
C.generateNonFatalErrorNode(State);
264 reportBug(
"Iterators of different containers used where the "
265 "same container is expected.", Iter1, Iter2,
C, N);
269void MismatchedIteratorChecker::reportBug(StringRef Message,
SVal Val1,
272 auto R = std::make_unique<PathSensitiveBugReport>(MismatchedBugType, Message,
274 R->markInteresting(Val1);
275 R->markInteresting(Val2);
276 C.emitReport(std::move(R));
279void MismatchedIteratorChecker::reportBug(StringRef Message,
SVal Val,
283 auto R = std::make_unique<PathSensitiveBugReport>(MismatchedBugType, Message,
285 R->markInteresting(Val);
286 R->markInteresting(Reg);
287 C.emitReport(std::move(R));
290void ento::registerMismatchedIteratorChecker(
CheckerManager &mgr) {
294bool 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)
const IteratorPosition * getIteratorPosition(ProgramStateRef State, SVal Val)
bool isInsertCall(const FunctionDecl *Func)
bool isIteratorType(const QualType &Type)
bool isEmplaceCall(const FunctionDecl *Func)
bool isEraseAfterCall(const FunctionDecl *Func)
bool isComparisonOperator(OverloadedOperatorKind OK)
The JSON file list parser is used to communicate input to InstallAPI.