1*480093f4SDimitry Andric //=== Iterator.cpp - Common functions for iterator checkers. -------*- C++ -*-// 2*480093f4SDimitry Andric // 3*480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*480093f4SDimitry Andric // 7*480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8*480093f4SDimitry Andric // 9*480093f4SDimitry Andric // Defines common functions to be used by the itertor checkers . 10*480093f4SDimitry Andric // 11*480093f4SDimitry Andric //===----------------------------------------------------------------------===// 12*480093f4SDimitry Andric 13*480093f4SDimitry Andric #include "Iterator.h" 14*480093f4SDimitry Andric 15*480093f4SDimitry Andric namespace clang { 16*480093f4SDimitry Andric namespace ento { 17*480093f4SDimitry Andric namespace iterator { 18*480093f4SDimitry Andric 19*480093f4SDimitry Andric bool isIteratorType(const QualType &Type) { 20*480093f4SDimitry Andric if (Type->isPointerType()) 21*480093f4SDimitry Andric return true; 22*480093f4SDimitry Andric 23*480093f4SDimitry Andric const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); 24*480093f4SDimitry Andric return isIterator(CRD); 25*480093f4SDimitry Andric } 26*480093f4SDimitry Andric 27*480093f4SDimitry Andric bool isIterator(const CXXRecordDecl *CRD) { 28*480093f4SDimitry Andric if (!CRD) 29*480093f4SDimitry Andric return false; 30*480093f4SDimitry Andric 31*480093f4SDimitry Andric const auto Name = CRD->getName(); 32*480093f4SDimitry Andric if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") || 33*480093f4SDimitry Andric Name.endswith_lower("it"))) 34*480093f4SDimitry Andric return false; 35*480093f4SDimitry Andric 36*480093f4SDimitry Andric bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false, 37*480093f4SDimitry Andric HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false; 38*480093f4SDimitry Andric for (const auto *Method : CRD->methods()) { 39*480093f4SDimitry Andric if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) { 40*480093f4SDimitry Andric if (Ctor->isCopyConstructor()) { 41*480093f4SDimitry Andric HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public; 42*480093f4SDimitry Andric } 43*480093f4SDimitry Andric continue; 44*480093f4SDimitry Andric } 45*480093f4SDimitry Andric if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) { 46*480093f4SDimitry Andric HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public; 47*480093f4SDimitry Andric continue; 48*480093f4SDimitry Andric } 49*480093f4SDimitry Andric if (Method->isCopyAssignmentOperator()) { 50*480093f4SDimitry Andric HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public; 51*480093f4SDimitry Andric continue; 52*480093f4SDimitry Andric } 53*480093f4SDimitry Andric if (!Method->isOverloadedOperator()) 54*480093f4SDimitry Andric continue; 55*480093f4SDimitry Andric const auto OPK = Method->getOverloadedOperator(); 56*480093f4SDimitry Andric if (OPK == OO_PlusPlus) { 57*480093f4SDimitry Andric HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0); 58*480093f4SDimitry Andric HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1); 59*480093f4SDimitry Andric continue; 60*480093f4SDimitry Andric } 61*480093f4SDimitry Andric if (OPK == OO_Star) { 62*480093f4SDimitry Andric HasDerefOp = (Method->getNumParams() == 0); 63*480093f4SDimitry Andric continue; 64*480093f4SDimitry Andric } 65*480093f4SDimitry Andric } 66*480093f4SDimitry Andric 67*480093f4SDimitry Andric return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp && 68*480093f4SDimitry Andric HasPostIncrOp && HasDerefOp; 69*480093f4SDimitry Andric } 70*480093f4SDimitry Andric 71*480093f4SDimitry Andric bool isComparisonOperator(OverloadedOperatorKind OK) { 72*480093f4SDimitry Andric return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less || 73*480093f4SDimitry Andric OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual; 74*480093f4SDimitry Andric } 75*480093f4SDimitry Andric 76*480093f4SDimitry Andric bool isInsertCall(const FunctionDecl *Func) { 77*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 78*480093f4SDimitry Andric if (!IdInfo) 79*480093f4SDimitry Andric return false; 80*480093f4SDimitry Andric if (Func->getNumParams() < 2 || Func->getNumParams() > 3) 81*480093f4SDimitry Andric return false; 82*480093f4SDimitry Andric if (!isIteratorType(Func->getParamDecl(0)->getType())) 83*480093f4SDimitry Andric return false; 84*480093f4SDimitry Andric return IdInfo->getName() == "insert"; 85*480093f4SDimitry Andric } 86*480093f4SDimitry Andric 87*480093f4SDimitry Andric bool isEmplaceCall(const FunctionDecl *Func) { 88*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 89*480093f4SDimitry Andric if (!IdInfo) 90*480093f4SDimitry Andric return false; 91*480093f4SDimitry Andric if (Func->getNumParams() < 2) 92*480093f4SDimitry Andric return false; 93*480093f4SDimitry Andric if (!isIteratorType(Func->getParamDecl(0)->getType())) 94*480093f4SDimitry Andric return false; 95*480093f4SDimitry Andric return IdInfo->getName() == "emplace"; 96*480093f4SDimitry Andric } 97*480093f4SDimitry Andric 98*480093f4SDimitry Andric bool isEraseCall(const FunctionDecl *Func) { 99*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 100*480093f4SDimitry Andric if (!IdInfo) 101*480093f4SDimitry Andric return false; 102*480093f4SDimitry Andric if (Func->getNumParams() < 1 || Func->getNumParams() > 2) 103*480093f4SDimitry Andric return false; 104*480093f4SDimitry Andric if (!isIteratorType(Func->getParamDecl(0)->getType())) 105*480093f4SDimitry Andric return false; 106*480093f4SDimitry Andric if (Func->getNumParams() == 2 && 107*480093f4SDimitry Andric !isIteratorType(Func->getParamDecl(1)->getType())) 108*480093f4SDimitry Andric return false; 109*480093f4SDimitry Andric return IdInfo->getName() == "erase"; 110*480093f4SDimitry Andric } 111*480093f4SDimitry Andric 112*480093f4SDimitry Andric bool isEraseAfterCall(const FunctionDecl *Func) { 113*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 114*480093f4SDimitry Andric if (!IdInfo) 115*480093f4SDimitry Andric return false; 116*480093f4SDimitry Andric if (Func->getNumParams() < 1 || Func->getNumParams() > 2) 117*480093f4SDimitry Andric return false; 118*480093f4SDimitry Andric if (!isIteratorType(Func->getParamDecl(0)->getType())) 119*480093f4SDimitry Andric return false; 120*480093f4SDimitry Andric if (Func->getNumParams() == 2 && 121*480093f4SDimitry Andric !isIteratorType(Func->getParamDecl(1)->getType())) 122*480093f4SDimitry Andric return false; 123*480093f4SDimitry Andric return IdInfo->getName() == "erase_after"; 124*480093f4SDimitry Andric } 125*480093f4SDimitry Andric 126*480093f4SDimitry Andric bool isAccessOperator(OverloadedOperatorKind OK) { 127*480093f4SDimitry Andric return isDereferenceOperator(OK) || isIncrementOperator(OK) || 128*480093f4SDimitry Andric isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK); 129*480093f4SDimitry Andric } 130*480093f4SDimitry Andric 131*480093f4SDimitry Andric bool isDereferenceOperator(OverloadedOperatorKind OK) { 132*480093f4SDimitry Andric return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar || 133*480093f4SDimitry Andric OK == OO_Subscript; 134*480093f4SDimitry Andric } 135*480093f4SDimitry Andric 136*480093f4SDimitry Andric bool isIncrementOperator(OverloadedOperatorKind OK) { 137*480093f4SDimitry Andric return OK == OO_PlusPlus; 138*480093f4SDimitry Andric } 139*480093f4SDimitry Andric 140*480093f4SDimitry Andric bool isDecrementOperator(OverloadedOperatorKind OK) { 141*480093f4SDimitry Andric return OK == OO_MinusMinus; 142*480093f4SDimitry Andric } 143*480093f4SDimitry Andric 144*480093f4SDimitry Andric bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) { 145*480093f4SDimitry Andric return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus || 146*480093f4SDimitry Andric OK == OO_MinusEqual; 147*480093f4SDimitry Andric } 148*480093f4SDimitry Andric 149*480093f4SDimitry Andric const ContainerData *getContainerData(ProgramStateRef State, 150*480093f4SDimitry Andric const MemRegion *Cont) { 151*480093f4SDimitry Andric return State->get<ContainerMap>(Cont); 152*480093f4SDimitry Andric } 153*480093f4SDimitry Andric 154*480093f4SDimitry Andric const IteratorPosition *getIteratorPosition(ProgramStateRef State, 155*480093f4SDimitry Andric const SVal &Val) { 156*480093f4SDimitry Andric if (auto Reg = Val.getAsRegion()) { 157*480093f4SDimitry Andric Reg = Reg->getMostDerivedObjectRegion(); 158*480093f4SDimitry Andric return State->get<IteratorRegionMap>(Reg); 159*480093f4SDimitry Andric } else if (const auto Sym = Val.getAsSymbol()) { 160*480093f4SDimitry Andric return State->get<IteratorSymbolMap>(Sym); 161*480093f4SDimitry Andric } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { 162*480093f4SDimitry Andric return State->get<IteratorRegionMap>(LCVal->getRegion()); 163*480093f4SDimitry Andric } 164*480093f4SDimitry Andric return nullptr; 165*480093f4SDimitry Andric } 166*480093f4SDimitry Andric 167*480093f4SDimitry Andric ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, 168*480093f4SDimitry Andric const IteratorPosition &Pos) { 169*480093f4SDimitry Andric if (auto Reg = Val.getAsRegion()) { 170*480093f4SDimitry Andric Reg = Reg->getMostDerivedObjectRegion(); 171*480093f4SDimitry Andric return State->set<IteratorRegionMap>(Reg, Pos); 172*480093f4SDimitry Andric } else if (const auto Sym = Val.getAsSymbol()) { 173*480093f4SDimitry Andric return State->set<IteratorSymbolMap>(Sym, Pos); 174*480093f4SDimitry Andric } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { 175*480093f4SDimitry Andric return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos); 176*480093f4SDimitry Andric } 177*480093f4SDimitry Andric return nullptr; 178*480093f4SDimitry Andric } 179*480093f4SDimitry Andric 180*480093f4SDimitry Andric ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter, 181*480093f4SDimitry Andric OverloadedOperatorKind Op, 182*480093f4SDimitry Andric const SVal &Distance) { 183*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 184*480093f4SDimitry Andric if (!Pos) 185*480093f4SDimitry Andric return nullptr; 186*480093f4SDimitry Andric 187*480093f4SDimitry Andric auto &SymMgr = State->getStateManager().getSymbolManager(); 188*480093f4SDimitry Andric auto &SVB = State->getStateManager().getSValBuilder(); 189*480093f4SDimitry Andric 190*480093f4SDimitry Andric assert ((Op == OO_Plus || Op == OO_PlusEqual || 191*480093f4SDimitry Andric Op == OO_Minus || Op == OO_MinusEqual) && 192*480093f4SDimitry Andric "Advance operator must be one of +, -, += and -=."); 193*480093f4SDimitry Andric auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub; 194*480093f4SDimitry Andric if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) { 195*480093f4SDimitry Andric // For concrete integers we can calculate the new position 196*480093f4SDimitry Andric const auto NewPos = 197*480093f4SDimitry Andric Pos->setTo(SVB.evalBinOp(State, BinOp, 198*480093f4SDimitry Andric nonloc::SymbolVal(Pos->getOffset()), 199*480093f4SDimitry Andric *IntDist, SymMgr.getType(Pos->getOffset())) 200*480093f4SDimitry Andric .getAsSymbol()); 201*480093f4SDimitry Andric return setIteratorPosition(State, Iter, NewPos); 202*480093f4SDimitry Andric } 203*480093f4SDimitry Andric 204*480093f4SDimitry Andric return nullptr; 205*480093f4SDimitry Andric } 206*480093f4SDimitry Andric 207*480093f4SDimitry Andric bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, 208*480093f4SDimitry Andric BinaryOperator::Opcode Opc) { 209*480093f4SDimitry Andric return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc); 210*480093f4SDimitry Andric } 211*480093f4SDimitry Andric 212*480093f4SDimitry Andric bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2, 213*480093f4SDimitry Andric BinaryOperator::Opcode Opc) { 214*480093f4SDimitry Andric auto &SVB = State->getStateManager().getSValBuilder(); 215*480093f4SDimitry Andric 216*480093f4SDimitry Andric const auto comparison = 217*480093f4SDimitry Andric SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType()); 218*480093f4SDimitry Andric 219*480093f4SDimitry Andric assert(comparison.getAs<DefinedSVal>() && 220*480093f4SDimitry Andric "Symbol comparison must be a `DefinedSVal`"); 221*480093f4SDimitry Andric 222*480093f4SDimitry Andric return !State->assume(comparison.castAs<DefinedSVal>(), false); 223*480093f4SDimitry Andric } 224*480093f4SDimitry Andric 225*480093f4SDimitry Andric } // namespace iterator 226*480093f4SDimitry Andric } // namespace ento 227*480093f4SDimitry Andric } // namespace clang 228