Iterator.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. //=== Iterator.cpp - Common functions for iterator checkers. -------*- C++ -*-//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Defines common functions to be used by the itertor checkers .
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "Iterator.h"
  13. namespace clang {
  14. namespace ento {
  15. namespace iterator {
  16. bool isIteratorType(const QualType &Type) {
  17. if (Type->isPointerType())
  18. return true;
  19. const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
  20. return isIterator(CRD);
  21. }
  22. bool isIterator(const CXXRecordDecl *CRD) {
  23. if (!CRD)
  24. return false;
  25. const auto Name = CRD->getName();
  26. if (!(Name.endswith_insensitive("iterator") ||
  27. Name.endswith_insensitive("iter") || Name.endswith_insensitive("it")))
  28. return false;
  29. bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
  30. HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
  31. for (const auto *Method : CRD->methods()) {
  32. if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
  33. if (Ctor->isCopyConstructor()) {
  34. HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
  35. }
  36. continue;
  37. }
  38. if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
  39. HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
  40. continue;
  41. }
  42. if (Method->isCopyAssignmentOperator()) {
  43. HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
  44. continue;
  45. }
  46. if (!Method->isOverloadedOperator())
  47. continue;
  48. const auto OPK = Method->getOverloadedOperator();
  49. if (OPK == OO_PlusPlus) {
  50. HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
  51. HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
  52. continue;
  53. }
  54. if (OPK == OO_Star) {
  55. HasDerefOp = (Method->getNumParams() == 0);
  56. continue;
  57. }
  58. }
  59. return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
  60. HasPostIncrOp && HasDerefOp;
  61. }
  62. bool isComparisonOperator(OverloadedOperatorKind OK) {
  63. return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
  64. OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
  65. }
  66. bool isInsertCall(const FunctionDecl *Func) {
  67. const auto *IdInfo = Func->getIdentifier();
  68. if (!IdInfo)
  69. return false;
  70. if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
  71. return false;
  72. if (!isIteratorType(Func->getParamDecl(0)->getType()))
  73. return false;
  74. return IdInfo->getName() == "insert";
  75. }
  76. bool isEmplaceCall(const FunctionDecl *Func) {
  77. const auto *IdInfo = Func->getIdentifier();
  78. if (!IdInfo)
  79. return false;
  80. if (Func->getNumParams() < 2)
  81. return false;
  82. if (!isIteratorType(Func->getParamDecl(0)->getType()))
  83. return false;
  84. return IdInfo->getName() == "emplace";
  85. }
  86. bool isEraseCall(const FunctionDecl *Func) {
  87. const auto *IdInfo = Func->getIdentifier();
  88. if (!IdInfo)
  89. return false;
  90. if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
  91. return false;
  92. if (!isIteratorType(Func->getParamDecl(0)->getType()))
  93. return false;
  94. if (Func->getNumParams() == 2 &&
  95. !isIteratorType(Func->getParamDecl(1)->getType()))
  96. return false;
  97. return IdInfo->getName() == "erase";
  98. }
  99. bool isEraseAfterCall(const FunctionDecl *Func) {
  100. const auto *IdInfo = Func->getIdentifier();
  101. if (!IdInfo)
  102. return false;
  103. if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
  104. return false;
  105. if (!isIteratorType(Func->getParamDecl(0)->getType()))
  106. return false;
  107. if (Func->getNumParams() == 2 &&
  108. !isIteratorType(Func->getParamDecl(1)->getType()))
  109. return false;
  110. return IdInfo->getName() == "erase_after";
  111. }
  112. bool isAccessOperator(OverloadedOperatorKind OK) {
  113. return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
  114. isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
  115. }
  116. bool isAccessOperator(UnaryOperatorKind OK) {
  117. return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
  118. isDecrementOperator(OK);
  119. }
  120. bool isAccessOperator(BinaryOperatorKind OK) {
  121. return isDereferenceOperator(OK) || isRandomIncrOrDecrOperator(OK);
  122. }
  123. bool isDereferenceOperator(OverloadedOperatorKind OK) {
  124. return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
  125. OK == OO_Subscript;
  126. }
  127. bool isDereferenceOperator(UnaryOperatorKind OK) {
  128. return OK == UO_Deref;
  129. }
  130. bool isDereferenceOperator(BinaryOperatorKind OK) {
  131. return OK == BO_PtrMemI;
  132. }
  133. bool isIncrementOperator(OverloadedOperatorKind OK) {
  134. return OK == OO_PlusPlus;
  135. }
  136. bool isIncrementOperator(UnaryOperatorKind OK) {
  137. return OK == UO_PreInc || OK == UO_PostInc;
  138. }
  139. bool isDecrementOperator(OverloadedOperatorKind OK) {
  140. return OK == OO_MinusMinus;
  141. }
  142. bool isDecrementOperator(UnaryOperatorKind OK) {
  143. return OK == UO_PreDec || OK == UO_PostDec;
  144. }
  145. bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
  146. return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
  147. OK == OO_MinusEqual;
  148. }
  149. bool isRandomIncrOrDecrOperator(BinaryOperatorKind OK) {
  150. return OK == BO_Add || OK == BO_AddAssign ||
  151. OK == BO_Sub || OK == BO_SubAssign;
  152. }
  153. const ContainerData *getContainerData(ProgramStateRef State,
  154. const MemRegion *Cont) {
  155. return State->get<ContainerMap>(Cont);
  156. }
  157. const IteratorPosition *getIteratorPosition(ProgramStateRef State,
  158. const SVal &Val) {
  159. if (auto Reg = Val.getAsRegion()) {
  160. Reg = Reg->getMostDerivedObjectRegion();
  161. return State->get<IteratorRegionMap>(Reg);
  162. } else if (const auto Sym = Val.getAsSymbol()) {
  163. return State->get<IteratorSymbolMap>(Sym);
  164. } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
  165. return State->get<IteratorRegionMap>(LCVal->getRegion());
  166. }
  167. return nullptr;
  168. }
  169. ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
  170. const IteratorPosition &Pos) {
  171. if (auto Reg = Val.getAsRegion()) {
  172. Reg = Reg->getMostDerivedObjectRegion();
  173. return State->set<IteratorRegionMap>(Reg, Pos);
  174. } else if (const auto Sym = Val.getAsSymbol()) {
  175. return State->set<IteratorSymbolMap>(Sym, Pos);
  176. } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
  177. return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
  178. }
  179. return nullptr;
  180. }
  181. ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
  182. const MemRegion *Cont, const Stmt* S,
  183. const LocationContext *LCtx,
  184. unsigned blockCount) {
  185. auto &StateMgr = State->getStateManager();
  186. auto &SymMgr = StateMgr.getSymbolManager();
  187. auto &ACtx = StateMgr.getContext();
  188. auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount);
  189. State = assumeNoOverflow(State, Sym, 4);
  190. return setIteratorPosition(State, Val,
  191. IteratorPosition::getPosition(Cont, Sym));
  192. }
  193. ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter,
  194. OverloadedOperatorKind Op,
  195. const SVal &Distance) {
  196. const auto *Pos = getIteratorPosition(State, Iter);
  197. if (!Pos)
  198. return nullptr;
  199. auto &SymMgr = State->getStateManager().getSymbolManager();
  200. auto &SVB = State->getStateManager().getSValBuilder();
  201. auto &BVF = State->getStateManager().getBasicVals();
  202. assert ((Op == OO_Plus || Op == OO_PlusEqual ||
  203. Op == OO_Minus || Op == OO_MinusEqual) &&
  204. "Advance operator must be one of +, -, += and -=.");
  205. auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
  206. const auto IntDistOp = Distance.getAs<nonloc::ConcreteInt>();
  207. if (!IntDistOp)
  208. return nullptr;
  209. // For concrete integers we can calculate the new position
  210. nonloc::ConcreteInt IntDist = *IntDistOp;
  211. if (IntDist.getValue().isNegative()) {
  212. IntDist = nonloc::ConcreteInt(BVF.getValue(-IntDist.getValue()));
  213. BinOp = (BinOp == BO_Add) ? BO_Sub : BO_Add;
  214. }
  215. const auto NewPos =
  216. Pos->setTo(SVB.evalBinOp(State, BinOp,
  217. nonloc::SymbolVal(Pos->getOffset()),
  218. IntDist, SymMgr.getType(Pos->getOffset()))
  219. .getAsSymbol());
  220. return setIteratorPosition(State, Iter, NewPos);
  221. }
  222. // This function tells the analyzer's engine that symbols produced by our
  223. // checker, most notably iterator positions, are relatively small.
  224. // A distance between items in the container should not be very large.
  225. // By assuming that it is within around 1/8 of the address space,
  226. // we can help the analyzer perform operations on these symbols
  227. // without being afraid of integer overflows.
  228. // FIXME: Should we provide it as an API, so that all checkers could use it?
  229. ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
  230. long Scale) {
  231. SValBuilder &SVB = State->getStateManager().getSValBuilder();
  232. BasicValueFactory &BV = SVB.getBasicValueFactory();
  233. QualType T = Sym->getType();
  234. assert(T->isSignedIntegerOrEnumerationType());
  235. APSIntType AT = BV.getAPSIntType(T);
  236. ProgramStateRef NewState = State;
  237. llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
  238. SVal IsCappedFromAbove =
  239. SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
  240. nonloc::ConcreteInt(Max), SVB.getConditionType());
  241. if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
  242. NewState = NewState->assume(*DV, true);
  243. if (!NewState)
  244. return State;
  245. }
  246. llvm::APSInt Min = -Max;
  247. SVal IsCappedFromBelow =
  248. SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
  249. nonloc::ConcreteInt(Min), SVB.getConditionType());
  250. if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
  251. NewState = NewState->assume(*DV, true);
  252. if (!NewState)
  253. return State;
  254. }
  255. return NewState;
  256. }
  257. bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
  258. BinaryOperator::Opcode Opc) {
  259. return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
  260. }
  261. bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
  262. BinaryOperator::Opcode Opc) {
  263. auto &SVB = State->getStateManager().getSValBuilder();
  264. const auto comparison =
  265. SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
  266. assert(comparison.getAs<DefinedSVal>() &&
  267. "Symbol comparison must be a `DefinedSVal`");
  268. return !State->assume(comparison.castAs<DefinedSVal>(), false);
  269. }
  270. } // namespace iterator
  271. } // namespace ento
  272. } // namespace clang