30class MismatchedIteratorChecker
31 :
public Checker<check::PreCall, check::PreStmt<BinaryOperator>> {
33 const BugType MismatchedBugType{
this,
"Iterator(s) mismatched",
37 void verifyMatch(CheckerContext &
C, SVal Iter,
const MemRegion *Cont)
const;
38 void verifyMatch(CheckerContext &
C, SVal Iter1, SVal Iter2)
const;
39 void reportBug(StringRef Message, SVal Val1, SVal Val2, CheckerContext &
C,
40 ExplodedNode *ErrNode)
const;
41 void reportBug(StringRef Message, SVal Val,
const MemRegion *Reg,
42 CheckerContext &
C, ExplodedNode *ErrNode)
const;
45 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
46 void checkPreStmt(
const BinaryOperator *BO, CheckerContext &
C)
const;
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 if (
Call.getNumArgs() == 2 &&
97 verifyMatch(
C,
Call.getArgSVal(0),
Call.getArgSVal(1));
99 verifyMatch(
C,
Call.getArgSVal(0),
100 InstCall->getCXXThisVal().getAsRegion());
101 if (
Call.getNumArgs() == 3 &&
104 verifyMatch(
C,
Call.getArgSVal(1),
Call.getArgSVal(2));
108 verifyMatch(
C,
Call.getArgSVal(0),
109 InstCall->getCXXThisVal().getAsRegion());
113 if (
Call.getNumArgs() < 2)
117 if (Ctr->getNumParams() < 2)
120 if (Ctr->getParamDecl(0)->getName() !=
"first" ||
121 Ctr->getParamDecl(1)->getName() !=
"last")
128 verifyMatch(
C,
Call.getArgSVal(0),
Call.getArgSVal(1));
146 const auto *Templ =
Func->getPrimaryTemplate();
150 const auto *TParams = Templ->getTemplateParameters();
151 const auto *TArgs =
Func->getTemplateSpecializationArgs();
154 for (
size_t I = 0; I < TParams->size(); ++I) {
155 const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I));
159 if (TPDecl->isParameterPack())
162 const auto TAType = TArgs->get(I).getAsType();
166 SVal LHS = UndefinedVal();
171 for (
auto J = 0U; J <
Func->getNumParams(); ++J) {
172 const auto *Param =
Func->getParamDecl(J);
173 const auto *ParamType =
174 Param->getType()->getAs<SubstTemplateTypeParmType>();
177 const TemplateTypeParmDecl *D = ParamType->getReplacedParameter();
181 LHS =
Call.getArgSVal(J);
183 verifyMatch(
C, LHS,
Call.getArgSVal(J));
190void MismatchedIteratorChecker::checkPreStmt(
const BinaryOperator *BO,
191 CheckerContext &
C)
const {
196 SVal LVal = State->getSVal(BO->
getLHS(),
C.getLocationContext());
197 SVal RVal = State->getSVal(BO->
getRHS(),
C.getLocationContext());
198 verifyMatch(
C, LVal, RVal);
201void MismatchedIteratorChecker::verifyMatch(CheckerContext &
C, SVal Iter,
202 const MemRegion *Cont)
const {
211 auto State =
C.getState();
216 const auto *IterCont = Pos->getContainer();
222 if (
const auto *ContSym = IterCont->getSymbolicBase()) {
227 if (IterCont != Cont) {
228 auto *N =
C.generateNonFatalErrorNode(State);
232 reportBug(
"Container accessed using foreign iterator argument.",
237void MismatchedIteratorChecker::verifyMatch(CheckerContext &
C, SVal Iter1,
240 auto State =
C.getState();
245 const auto *IterCont1 = Pos1->getContainer();
251 if (
const auto *ContSym = IterCont1->getSymbolicBase()) {
260 const auto *IterCont2 = Pos2->getContainer();
261 if (
const auto *ContSym = IterCont2->getSymbolicBase()) {
266 if (IterCont1 != IterCont2) {
267 auto *N =
C.generateNonFatalErrorNode(State);
270 reportBug(
"Iterators of different containers used where the "
271 "same container is expected.", Iter1, Iter2,
C, N);
275void MismatchedIteratorChecker::reportBug(StringRef Message, SVal Val1,
276 SVal Val2, CheckerContext &
C,
277 ExplodedNode *ErrNode)
const {
278 auto R = std::make_unique<PathSensitiveBugReport>(MismatchedBugType, Message,
280 R->markInteresting(Val1);
281 R->markInteresting(Val2);
282 C.emitReport(std::move(R));
285void MismatchedIteratorChecker::reportBug(StringRef Message, SVal Val,
286 const MemRegion *Reg,
288 ExplodedNode *ErrNode)
const {
289 auto R = std::make_unique<PathSensitiveBugReport>(MismatchedBugType, Message,
291 R->markInteresting(Val);
292 R->markInteresting(Reg);
293 C.emitReport(std::move(R));
296void ento::registerMismatchedIteratorChecker(CheckerManager &mgr) {
300bool ento::shouldRegisterMismatchedIteratorChecker(
const CheckerManager &mgr) {
static bool isComparisonOp(Opcode Opc)
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
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...
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)
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)