1480093f4SDimitry Andric //=== Iterator.cpp - Common functions for iterator checkers. -------*- C++ -*-// 2480093f4SDimitry Andric // 3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6480093f4SDimitry Andric // 7480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8480093f4SDimitry Andric // 9480093f4SDimitry Andric // Defines common functions to be used by the itertor checkers . 10480093f4SDimitry Andric // 11480093f4SDimitry Andric //===----------------------------------------------------------------------===// 12480093f4SDimitry Andric 13480093f4SDimitry Andric #include "Iterator.h" 14480093f4SDimitry Andric 15480093f4SDimitry Andric namespace clang { 16480093f4SDimitry Andric namespace ento { 17480093f4SDimitry Andric namespace iterator { 18480093f4SDimitry Andric 19480093f4SDimitry Andric bool isIteratorType(const QualType &Type) { 20480093f4SDimitry Andric if (Type->isPointerType()) 21480093f4SDimitry Andric return true; 22480093f4SDimitry Andric 23480093f4SDimitry Andric const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); 24480093f4SDimitry Andric return isIterator(CRD); 25480093f4SDimitry Andric } 26480093f4SDimitry Andric 27480093f4SDimitry Andric bool isIterator(const CXXRecordDecl *CRD) { 28480093f4SDimitry Andric if (!CRD) 29480093f4SDimitry Andric return false; 30480093f4SDimitry Andric 31480093f4SDimitry Andric const auto Name = CRD->getName(); 32480093f4SDimitry Andric if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") || 33480093f4SDimitry Andric Name.endswith_lower("it"))) 34480093f4SDimitry Andric return false; 35480093f4SDimitry Andric 36480093f4SDimitry Andric bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false, 37480093f4SDimitry Andric HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false; 38480093f4SDimitry Andric for (const auto *Method : CRD->methods()) { 39480093f4SDimitry Andric if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) { 40480093f4SDimitry Andric if (Ctor->isCopyConstructor()) { 41480093f4SDimitry Andric HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public; 42480093f4SDimitry Andric } 43480093f4SDimitry Andric continue; 44480093f4SDimitry Andric } 45480093f4SDimitry Andric if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) { 46480093f4SDimitry Andric HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public; 47480093f4SDimitry Andric continue; 48480093f4SDimitry Andric } 49480093f4SDimitry Andric if (Method->isCopyAssignmentOperator()) { 50480093f4SDimitry Andric HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public; 51480093f4SDimitry Andric continue; 52480093f4SDimitry Andric } 53480093f4SDimitry Andric if (!Method->isOverloadedOperator()) 54480093f4SDimitry Andric continue; 55480093f4SDimitry Andric const auto OPK = Method->getOverloadedOperator(); 56480093f4SDimitry Andric if (OPK == OO_PlusPlus) { 57480093f4SDimitry Andric HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0); 58480093f4SDimitry Andric HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1); 59480093f4SDimitry Andric continue; 60480093f4SDimitry Andric } 61480093f4SDimitry Andric if (OPK == OO_Star) { 62480093f4SDimitry Andric HasDerefOp = (Method->getNumParams() == 0); 63480093f4SDimitry Andric continue; 64480093f4SDimitry Andric } 65480093f4SDimitry Andric } 66480093f4SDimitry Andric 67480093f4SDimitry Andric return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp && 68480093f4SDimitry Andric HasPostIncrOp && HasDerefOp; 69480093f4SDimitry Andric } 70480093f4SDimitry Andric 71480093f4SDimitry Andric bool isComparisonOperator(OverloadedOperatorKind OK) { 72480093f4SDimitry Andric return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less || 73480093f4SDimitry Andric OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual; 74480093f4SDimitry Andric } 75480093f4SDimitry Andric 76480093f4SDimitry Andric bool isInsertCall(const FunctionDecl *Func) { 77480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 78480093f4SDimitry Andric if (!IdInfo) 79480093f4SDimitry Andric return false; 80480093f4SDimitry Andric if (Func->getNumParams() < 2 || Func->getNumParams() > 3) 81480093f4SDimitry Andric return false; 82480093f4SDimitry Andric if (!isIteratorType(Func->getParamDecl(0)->getType())) 83480093f4SDimitry Andric return false; 84480093f4SDimitry Andric return IdInfo->getName() == "insert"; 85480093f4SDimitry Andric } 86480093f4SDimitry Andric 87480093f4SDimitry Andric bool isEmplaceCall(const FunctionDecl *Func) { 88480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 89480093f4SDimitry Andric if (!IdInfo) 90480093f4SDimitry Andric return false; 91480093f4SDimitry Andric if (Func->getNumParams() < 2) 92480093f4SDimitry Andric return false; 93480093f4SDimitry Andric if (!isIteratorType(Func->getParamDecl(0)->getType())) 94480093f4SDimitry Andric return false; 95480093f4SDimitry Andric return IdInfo->getName() == "emplace"; 96480093f4SDimitry Andric } 97480093f4SDimitry Andric 98480093f4SDimitry Andric bool isEraseCall(const FunctionDecl *Func) { 99480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 100480093f4SDimitry Andric if (!IdInfo) 101480093f4SDimitry Andric return false; 102480093f4SDimitry Andric if (Func->getNumParams() < 1 || Func->getNumParams() > 2) 103480093f4SDimitry Andric return false; 104480093f4SDimitry Andric if (!isIteratorType(Func->getParamDecl(0)->getType())) 105480093f4SDimitry Andric return false; 106480093f4SDimitry Andric if (Func->getNumParams() == 2 && 107480093f4SDimitry Andric !isIteratorType(Func->getParamDecl(1)->getType())) 108480093f4SDimitry Andric return false; 109480093f4SDimitry Andric return IdInfo->getName() == "erase"; 110480093f4SDimitry Andric } 111480093f4SDimitry Andric 112480093f4SDimitry Andric bool isEraseAfterCall(const FunctionDecl *Func) { 113480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 114480093f4SDimitry Andric if (!IdInfo) 115480093f4SDimitry Andric return false; 116480093f4SDimitry Andric if (Func->getNumParams() < 1 || Func->getNumParams() > 2) 117480093f4SDimitry Andric return false; 118480093f4SDimitry Andric if (!isIteratorType(Func->getParamDecl(0)->getType())) 119480093f4SDimitry Andric return false; 120480093f4SDimitry Andric if (Func->getNumParams() == 2 && 121480093f4SDimitry Andric !isIteratorType(Func->getParamDecl(1)->getType())) 122480093f4SDimitry Andric return false; 123480093f4SDimitry Andric return IdInfo->getName() == "erase_after"; 124480093f4SDimitry Andric } 125480093f4SDimitry Andric 126480093f4SDimitry Andric bool isAccessOperator(OverloadedOperatorKind OK) { 127480093f4SDimitry Andric return isDereferenceOperator(OK) || isIncrementOperator(OK) || 128480093f4SDimitry Andric isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK); 129480093f4SDimitry Andric } 130480093f4SDimitry Andric 131*5ffd83dbSDimitry Andric bool isAccessOperator(UnaryOperatorKind OK) { 132*5ffd83dbSDimitry Andric return isDereferenceOperator(OK) || isIncrementOperator(OK) || 133*5ffd83dbSDimitry Andric isDecrementOperator(OK); 134*5ffd83dbSDimitry Andric } 135*5ffd83dbSDimitry Andric 136*5ffd83dbSDimitry Andric bool isAccessOperator(BinaryOperatorKind OK) { 137*5ffd83dbSDimitry Andric return isDereferenceOperator(OK) || isRandomIncrOrDecrOperator(OK); 138*5ffd83dbSDimitry Andric } 139*5ffd83dbSDimitry Andric 140480093f4SDimitry Andric bool isDereferenceOperator(OverloadedOperatorKind OK) { 141480093f4SDimitry Andric return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar || 142480093f4SDimitry Andric OK == OO_Subscript; 143480093f4SDimitry Andric } 144480093f4SDimitry Andric 145*5ffd83dbSDimitry Andric bool isDereferenceOperator(UnaryOperatorKind OK) { 146*5ffd83dbSDimitry Andric return OK == UO_Deref; 147*5ffd83dbSDimitry Andric } 148*5ffd83dbSDimitry Andric 149*5ffd83dbSDimitry Andric bool isDereferenceOperator(BinaryOperatorKind OK) { 150*5ffd83dbSDimitry Andric return OK == BO_PtrMemI; 151*5ffd83dbSDimitry Andric } 152*5ffd83dbSDimitry Andric 153480093f4SDimitry Andric bool isIncrementOperator(OverloadedOperatorKind OK) { 154480093f4SDimitry Andric return OK == OO_PlusPlus; 155480093f4SDimitry Andric } 156480093f4SDimitry Andric 157*5ffd83dbSDimitry Andric bool isIncrementOperator(UnaryOperatorKind OK) { 158*5ffd83dbSDimitry Andric return OK == UO_PreInc || OK == UO_PostInc; 159*5ffd83dbSDimitry Andric } 160*5ffd83dbSDimitry Andric 161480093f4SDimitry Andric bool isDecrementOperator(OverloadedOperatorKind OK) { 162480093f4SDimitry Andric return OK == OO_MinusMinus; 163480093f4SDimitry Andric } 164480093f4SDimitry Andric 165*5ffd83dbSDimitry Andric bool isDecrementOperator(UnaryOperatorKind OK) { 166*5ffd83dbSDimitry Andric return OK == UO_PreDec || OK == UO_PostDec; 167*5ffd83dbSDimitry Andric } 168*5ffd83dbSDimitry Andric 169480093f4SDimitry Andric bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) { 170480093f4SDimitry Andric return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus || 171480093f4SDimitry Andric OK == OO_MinusEqual; 172480093f4SDimitry Andric } 173480093f4SDimitry Andric 174*5ffd83dbSDimitry Andric bool isRandomIncrOrDecrOperator(BinaryOperatorKind OK) { 175*5ffd83dbSDimitry Andric return OK == BO_Add || OK == BO_AddAssign || 176*5ffd83dbSDimitry Andric OK == BO_Sub || OK == BO_SubAssign; 177*5ffd83dbSDimitry Andric } 178*5ffd83dbSDimitry Andric 179480093f4SDimitry Andric const ContainerData *getContainerData(ProgramStateRef State, 180480093f4SDimitry Andric const MemRegion *Cont) { 181480093f4SDimitry Andric return State->get<ContainerMap>(Cont); 182480093f4SDimitry Andric } 183480093f4SDimitry Andric 184480093f4SDimitry Andric const IteratorPosition *getIteratorPosition(ProgramStateRef State, 185480093f4SDimitry Andric const SVal &Val) { 186480093f4SDimitry Andric if (auto Reg = Val.getAsRegion()) { 187480093f4SDimitry Andric Reg = Reg->getMostDerivedObjectRegion(); 188480093f4SDimitry Andric return State->get<IteratorRegionMap>(Reg); 189480093f4SDimitry Andric } else if (const auto Sym = Val.getAsSymbol()) { 190480093f4SDimitry Andric return State->get<IteratorSymbolMap>(Sym); 191480093f4SDimitry Andric } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { 192480093f4SDimitry Andric return State->get<IteratorRegionMap>(LCVal->getRegion()); 193480093f4SDimitry Andric } 194480093f4SDimitry Andric return nullptr; 195480093f4SDimitry Andric } 196480093f4SDimitry Andric 197480093f4SDimitry Andric ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, 198480093f4SDimitry Andric const IteratorPosition &Pos) { 199480093f4SDimitry Andric if (auto Reg = Val.getAsRegion()) { 200480093f4SDimitry Andric Reg = Reg->getMostDerivedObjectRegion(); 201480093f4SDimitry Andric return State->set<IteratorRegionMap>(Reg, Pos); 202480093f4SDimitry Andric } else if (const auto Sym = Val.getAsSymbol()) { 203480093f4SDimitry Andric return State->set<IteratorSymbolMap>(Sym, Pos); 204480093f4SDimitry Andric } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { 205480093f4SDimitry Andric return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos); 206480093f4SDimitry Andric } 207480093f4SDimitry Andric return nullptr; 208480093f4SDimitry Andric } 209480093f4SDimitry Andric 210*5ffd83dbSDimitry Andric ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val, 211*5ffd83dbSDimitry Andric const MemRegion *Cont, const Stmt* S, 212*5ffd83dbSDimitry Andric const LocationContext *LCtx, 213*5ffd83dbSDimitry Andric unsigned blockCount) { 214*5ffd83dbSDimitry Andric auto &StateMgr = State->getStateManager(); 215*5ffd83dbSDimitry Andric auto &SymMgr = StateMgr.getSymbolManager(); 216*5ffd83dbSDimitry Andric auto &ACtx = StateMgr.getContext(); 217*5ffd83dbSDimitry Andric 218*5ffd83dbSDimitry Andric auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount); 219*5ffd83dbSDimitry Andric State = assumeNoOverflow(State, Sym, 4); 220*5ffd83dbSDimitry Andric return setIteratorPosition(State, Val, 221*5ffd83dbSDimitry Andric IteratorPosition::getPosition(Cont, Sym)); 222*5ffd83dbSDimitry Andric } 223*5ffd83dbSDimitry Andric 224480093f4SDimitry Andric ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter, 225480093f4SDimitry Andric OverloadedOperatorKind Op, 226480093f4SDimitry Andric const SVal &Distance) { 227480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 228480093f4SDimitry Andric if (!Pos) 229480093f4SDimitry Andric return nullptr; 230480093f4SDimitry Andric 231480093f4SDimitry Andric auto &SymMgr = State->getStateManager().getSymbolManager(); 232480093f4SDimitry Andric auto &SVB = State->getStateManager().getSValBuilder(); 233*5ffd83dbSDimitry Andric auto &BVF = State->getStateManager().getBasicVals(); 234480093f4SDimitry Andric 235480093f4SDimitry Andric assert ((Op == OO_Plus || Op == OO_PlusEqual || 236480093f4SDimitry Andric Op == OO_Minus || Op == OO_MinusEqual) && 237480093f4SDimitry Andric "Advance operator must be one of +, -, += and -=."); 238480093f4SDimitry Andric auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub; 239*5ffd83dbSDimitry Andric const auto IntDistOp = Distance.getAs<nonloc::ConcreteInt>(); 240*5ffd83dbSDimitry Andric if (!IntDistOp) 241*5ffd83dbSDimitry Andric return nullptr; 242*5ffd83dbSDimitry Andric 243480093f4SDimitry Andric // For concrete integers we can calculate the new position 244*5ffd83dbSDimitry Andric nonloc::ConcreteInt IntDist = *IntDistOp; 245*5ffd83dbSDimitry Andric 246*5ffd83dbSDimitry Andric if (IntDist.getValue().isNegative()) { 247*5ffd83dbSDimitry Andric IntDist = nonloc::ConcreteInt(BVF.getValue(-IntDist.getValue())); 248*5ffd83dbSDimitry Andric BinOp = (BinOp == BO_Add) ? BO_Sub : BO_Add; 249*5ffd83dbSDimitry Andric } 250480093f4SDimitry Andric const auto NewPos = 251480093f4SDimitry Andric Pos->setTo(SVB.evalBinOp(State, BinOp, 252480093f4SDimitry Andric nonloc::SymbolVal(Pos->getOffset()), 253*5ffd83dbSDimitry Andric IntDist, SymMgr.getType(Pos->getOffset())) 254480093f4SDimitry Andric .getAsSymbol()); 255480093f4SDimitry Andric return setIteratorPosition(State, Iter, NewPos); 256480093f4SDimitry Andric } 257480093f4SDimitry Andric 258*5ffd83dbSDimitry Andric // This function tells the analyzer's engine that symbols produced by our 259*5ffd83dbSDimitry Andric // checker, most notably iterator positions, are relatively small. 260*5ffd83dbSDimitry Andric // A distance between items in the container should not be very large. 261*5ffd83dbSDimitry Andric // By assuming that it is within around 1/8 of the address space, 262*5ffd83dbSDimitry Andric // we can help the analyzer perform operations on these symbols 263*5ffd83dbSDimitry Andric // without being afraid of integer overflows. 264*5ffd83dbSDimitry Andric // FIXME: Should we provide it as an API, so that all checkers could use it? 265*5ffd83dbSDimitry Andric ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, 266*5ffd83dbSDimitry Andric long Scale) { 267*5ffd83dbSDimitry Andric SValBuilder &SVB = State->getStateManager().getSValBuilder(); 268*5ffd83dbSDimitry Andric BasicValueFactory &BV = SVB.getBasicValueFactory(); 269*5ffd83dbSDimitry Andric 270*5ffd83dbSDimitry Andric QualType T = Sym->getType(); 271*5ffd83dbSDimitry Andric assert(T->isSignedIntegerOrEnumerationType()); 272*5ffd83dbSDimitry Andric APSIntType AT = BV.getAPSIntType(T); 273*5ffd83dbSDimitry Andric 274*5ffd83dbSDimitry Andric ProgramStateRef NewState = State; 275*5ffd83dbSDimitry Andric 276*5ffd83dbSDimitry Andric llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale); 277*5ffd83dbSDimitry Andric SVal IsCappedFromAbove = 278*5ffd83dbSDimitry Andric SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym), 279*5ffd83dbSDimitry Andric nonloc::ConcreteInt(Max), SVB.getConditionType()); 280*5ffd83dbSDimitry Andric if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) { 281*5ffd83dbSDimitry Andric NewState = NewState->assume(*DV, true); 282*5ffd83dbSDimitry Andric if (!NewState) 283*5ffd83dbSDimitry Andric return State; 284*5ffd83dbSDimitry Andric } 285*5ffd83dbSDimitry Andric 286*5ffd83dbSDimitry Andric llvm::APSInt Min = -Max; 287*5ffd83dbSDimitry Andric SVal IsCappedFromBelow = 288*5ffd83dbSDimitry Andric SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym), 289*5ffd83dbSDimitry Andric nonloc::ConcreteInt(Min), SVB.getConditionType()); 290*5ffd83dbSDimitry Andric if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) { 291*5ffd83dbSDimitry Andric NewState = NewState->assume(*DV, true); 292*5ffd83dbSDimitry Andric if (!NewState) 293*5ffd83dbSDimitry Andric return State; 294*5ffd83dbSDimitry Andric } 295*5ffd83dbSDimitry Andric 296*5ffd83dbSDimitry Andric return NewState; 297480093f4SDimitry Andric } 298480093f4SDimitry Andric 299480093f4SDimitry Andric bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, 300480093f4SDimitry Andric BinaryOperator::Opcode Opc) { 301480093f4SDimitry Andric return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc); 302480093f4SDimitry Andric } 303480093f4SDimitry Andric 304480093f4SDimitry Andric bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2, 305480093f4SDimitry Andric BinaryOperator::Opcode Opc) { 306480093f4SDimitry Andric auto &SVB = State->getStateManager().getSValBuilder(); 307480093f4SDimitry Andric 308480093f4SDimitry Andric const auto comparison = 309480093f4SDimitry Andric SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType()); 310480093f4SDimitry Andric 311480093f4SDimitry Andric assert(comparison.getAs<DefinedSVal>() && 312480093f4SDimitry Andric "Symbol comparison must be a `DefinedSVal`"); 313480093f4SDimitry Andric 314480093f4SDimitry Andric return !State->assume(comparison.castAs<DefinedSVal>(), false); 315480093f4SDimitry Andric } 316480093f4SDimitry Andric 317480093f4SDimitry Andric } // namespace iterator 318480093f4SDimitry Andric } // namespace ento 319480093f4SDimitry Andric } // namespace clang 320