24 using namespace clang;
30 class MismatchedIteratorChecker
31 :
public Checker<check::PreCall> {
33 std::unique_ptr<BugType> MismatchedBugType;
35 void verifyMatch(CheckerContext &C,
const SVal &Iter,
36 const MemRegion *Cont)
const;
37 void verifyMatch(CheckerContext &C,
const SVal &Iter1,
38 const SVal &Iter2)
const;
39 void reportBug(
const StringRef &Message,
const SVal &Val1,
40 const SVal &Val2, CheckerContext &C,
41 ExplodedNode *ErrNode)
const;
42 void reportBug(
const StringRef &Message,
const SVal &Val,
43 const MemRegion *Reg, CheckerContext &C,
44 ExplodedNode *ErrNode)
const;
47 MismatchedIteratorChecker();
49 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
55 MismatchedIteratorChecker::MismatchedIteratorChecker() {
56 MismatchedBugType.reset(
57 new BugType(
this,
"Iterator(s) mismatched",
"Misuse of STL APIs",
61 void MismatchedIteratorChecker::checkPreCall(
const CallEvent &Call,
62 CheckerContext &C)
const {
64 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
68 if (Func->isOverloadedOperator() &&
71 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
72 if (Call.getNumArgs() < 1)
79 verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
81 if (Call.getNumArgs() < 2)
88 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
90 }
else if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
91 const auto *ContReg = InstCall->getCXXThisVal().getAsRegion();
96 verifyMatch(C, Call.getArgSVal(0),
97 InstCall->getCXXThisVal().getAsRegion());
98 if (Call.getNumArgs() == 2) {
99 verifyMatch(C, Call.getArgSVal(1),
100 InstCall->getCXXThisVal().getAsRegion());
103 verifyMatch(C, Call.getArgSVal(0),
104 InstCall->getCXXThisVal().getAsRegion());
105 if (Call.getNumArgs() == 3 &&
108 verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2));
111 verifyMatch(C, Call.getArgSVal(0),
112 InstCall->getCXXThisVal().getAsRegion());
114 }
else if (isa<CXXConstructorCall>(&Call)) {
116 if (Call.getNumArgs() < 2)
119 const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl());
120 if (Ctr->getNumParams() < 2)
123 if (Ctr->getParamDecl(0)->getName() !=
"first" ||
124 Ctr->getParamDecl(1)->getName() !=
"last")
131 verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1));
149 const auto *Templ = Func->getPrimaryTemplate();
153 const auto *TParams = Templ->getTemplateParameters();
154 const auto *TArgs = Func->getTemplateSpecializationArgs();
157 for (
size_t I = 0; I < TParams->size(); ++I) {
162 if (TPDecl->isParameterPack())
165 const auto TAType = TArgs->get(I).getAsType();
169 SVal LHS = UndefinedVal();
174 for (
auto J = 0U; J < Func->getNumParams(); ++J) {
175 const auto *Param = Func->getParamDecl(J);
176 const auto *ParamType =
179 ParamType->getReplacedParameter()->getDecl() != TPDecl)
182 LHS = Call.getArgSVal(J);
184 verifyMatch(C, LHS, Call.getArgSVal(J));
191 void MismatchedIteratorChecker::verifyMatch(CheckerContext &C,
const SVal &Iter,
192 const MemRegion *Cont)
const {
194 Cont = Cont->getMostDerivedObjectRegion();
196 if (
const auto *ContSym = Cont->getSymbolicBase()) {
197 if (isa<SymbolConjured>(ContSym->getSymbol()))
201 auto State = C.getState();
206 const auto *IterCont = Pos->getContainer();
212 if (
const auto *ContSym = IterCont->getSymbolicBase()) {
213 if (isa<SymbolConjured>(ContSym->getSymbol()))
217 if (IterCont != Cont) {
218 auto *N = C.generateNonFatalErrorNode(
State);
222 reportBug(
"Container accessed using foreign iterator argument.",
227 void MismatchedIteratorChecker::verifyMatch(CheckerContext &C,
229 const SVal &Iter2)
const {
231 auto State = C.getState();
236 const auto *IterCont1 = Pos1->getContainer();
242 if (
const auto *ContSym = IterCont1->getSymbolicBase()) {
243 if (isa<SymbolConjured>(ContSym->getSymbol()))
251 const auto *IterCont2 = Pos2->getContainer();
252 if (
const auto *ContSym = IterCont2->getSymbolicBase()) {
253 if (isa<SymbolConjured>(ContSym->getSymbol()))
257 if (IterCont1 != IterCont2) {
258 auto *N = C.generateNonFatalErrorNode(
State);
261 reportBug(
"Iterators of different containers used where the " 262 "same container is expected.", Iter1, Iter2, C, N);
266 void MismatchedIteratorChecker::reportBug(
const StringRef &Message,
270 ExplodedNode *ErrNode)
const {
271 auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
273 R->markInteresting(Val1);
274 R->markInteresting(Val2);
275 C.emitReport(std::move(R));
278 void MismatchedIteratorChecker::reportBug(
const StringRef &Message,
279 const SVal &Val,
const MemRegion *Reg,
281 ExplodedNode *ErrNode)
const {
282 auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
284 R->markInteresting(Val);
285 R->markInteresting(Reg);
286 C.emitReport(std::move(R));
289 void ento::registerMismatchedIteratorChecker(CheckerManager &mgr) {
290 mgr.registerChecker<MismatchedIteratorChecker>();
293 bool ento::shouldRegisterMismatchedIteratorChecker(
const LangOptions &LO) {
Represents the result of substituting a type for a template type parameter.
bool isComparisonOperator(OverloadedOperatorKind OK)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
bool isIteratorType(const QualType &Type)
const IteratorPosition * getIteratorPosition(ProgramStateRef State, const SVal &Val)
Declaration of a template type parameter.
bool isEraseCall(const FunctionDecl *Func)
bool isEraseAfterCall(const FunctionDecl *Func)
Dataflow Directional Tag Classes.
bool isInsertCall(const FunctionDecl *Func)
bool isEmplaceCall(const FunctionDecl *Func)