IteratorModeling.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. //===-- IteratorModeling.cpp --------------------------------------*- 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 a modeling-checker for modeling STL iterator-like iterators.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. //
  13. // In the code, iterator can be represented as a:
  14. // * type-I: typedef-ed pointer. Operations over such iterator, such as
  15. // comparisons or increments, are modeled straightforwardly by the
  16. // analyzer.
  17. // * type-II: structure with its method bodies available. Operations over such
  18. // iterator are inlined by the analyzer, and results of modeling
  19. // these operations are exposing implementation details of the
  20. // iterators, which is not necessarily helping.
  21. // * type-III: completely opaque structure. Operations over such iterator are
  22. // modeled conservatively, producing conjured symbols everywhere.
  23. //
  24. // To handle all these types in a common way we introduce a structure called
  25. // IteratorPosition which is an abstraction of the position the iterator
  26. // represents using symbolic expressions. The checker handles all the
  27. // operations on this structure.
  28. //
  29. // Additionally, depending on the circumstances, operators of types II and III
  30. // can be represented as:
  31. // * type-IIa, type-IIIa: conjured structure symbols - when returned by value
  32. // from conservatively evaluated methods such as
  33. // `.begin()`.
  34. // * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
  35. // variables or temporaries, when the iterator object is
  36. // currently treated as an lvalue.
  37. // * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
  38. // iterator object is treated as an rvalue taken of a
  39. // particular lvalue, eg. a copy of "type-a" iterator
  40. // object, or an iterator that existed before the
  41. // analysis has started.
  42. //
  43. // To handle any of these three different representations stored in an SVal we
  44. // use setter and getters functions which separate the three cases. To store
  45. // them we use a pointer union of symbol and memory region.
  46. //
  47. // The checker works the following way: We record the begin and the
  48. // past-end iterator for all containers whenever their `.begin()` and `.end()`
  49. // are called. Since the Constraint Manager cannot handle such SVals we need
  50. // to take over its role. We post-check equality and non-equality comparisons
  51. // and record that the two sides are equal if we are in the 'equal' branch
  52. // (true-branch for `==` and false-branch for `!=`).
  53. //
  54. // In case of type-I or type-II iterators we get a concrete integer as a result
  55. // of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
  56. // this latter case we record the symbol and reload it in evalAssume() and do
  57. // the propagation there. We also handle (maybe double) negated comparisons
  58. // which are represented in the form of (x == 0 or x != 0) where x is the
  59. // comparison itself.
  60. //
  61. // Since `SimpleConstraintManager` cannot handle complex symbolic expressions
  62. // we only use expressions of the format S, S+n or S-n for iterator positions
  63. // where S is a conjured symbol and n is an unsigned concrete integer. When
  64. // making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as
  65. // a constraint which we later retrieve when doing an actual comparison.
  66. #include "clang/AST/DeclTemplate.h"
  67. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  68. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  69. #include "clang/StaticAnalyzer/Core/Checker.h"
  70. #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
  71. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  72. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  73. #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
  74. #include "Iterator.h"
  75. #include <utility>
  76. using namespace clang;
  77. using namespace ento;
  78. using namespace iterator;
  79. namespace {
  80. class IteratorModeling
  81. : public Checker<check::PostCall, check::PostStmt<UnaryOperator>,
  82. check::PostStmt<BinaryOperator>,
  83. check::PostStmt<MaterializeTemporaryExpr>,
  84. check::Bind, check::LiveSymbols, check::DeadSymbols> {
  85. using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *,
  86. SVal, SVal, SVal) const;
  87. void handleOverloadedOperator(CheckerContext &C, const CallEvent &Call,
  88. OverloadedOperatorKind Op) const;
  89. void handleAdvanceLikeFunction(CheckerContext &C, const CallEvent &Call,
  90. const Expr *OrigExpr,
  91. const AdvanceFn *Handler) const;
  92. void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
  93. const SVal &LVal, const SVal &RVal,
  94. OverloadedOperatorKind Op) const;
  95. void processComparison(CheckerContext &C, ProgramStateRef State,
  96. SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal,
  97. OverloadedOperatorKind Op) const;
  98. void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
  99. bool Postfix) const;
  100. void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
  101. bool Postfix) const;
  102. void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
  103. OverloadedOperatorKind Op, const SVal &RetVal,
  104. const SVal &Iterator, const SVal &Amount) const;
  105. void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator,
  106. OverloadedOperatorKind OK, SVal Offset) const;
  107. void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
  108. SVal Amount) const;
  109. void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
  110. SVal Amount) const;
  111. void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
  112. SVal Amount) const;
  113. void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
  114. const MemRegion *Cont) const;
  115. bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const;
  116. void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
  117. const char *Sep) const override;
  118. // std::advance, std::prev & std::next
  119. CallDescriptionMap<AdvanceFn> AdvanceLikeFunctions = {
  120. // template<class InputIt, class Distance>
  121. // void advance(InputIt& it, Distance n);
  122. {{{"std", "advance"}, 2}, &IteratorModeling::handleAdvance},
  123. // template<class BidirIt>
  124. // BidirIt prev(
  125. // BidirIt it,
  126. // typename std::iterator_traits<BidirIt>::difference_type n = 1);
  127. {{{"std", "prev"}, 2}, &IteratorModeling::handlePrev},
  128. // template<class ForwardIt>
  129. // ForwardIt next(
  130. // ForwardIt it,
  131. // typename std::iterator_traits<ForwardIt>::difference_type n = 1);
  132. {{{"std", "next"}, 2}, &IteratorModeling::handleNext},
  133. };
  134. public:
  135. IteratorModeling() = default;
  136. void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
  137. void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
  138. void checkPostStmt(const UnaryOperator *UO, CheckerContext &C) const;
  139. void checkPostStmt(const BinaryOperator *BO, CheckerContext &C) const;
  140. void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
  141. void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
  142. void checkPostStmt(const MaterializeTemporaryExpr *MTE,
  143. CheckerContext &C) const;
  144. void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
  145. void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
  146. };
  147. bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
  148. bool isSimpleComparisonOperator(BinaryOperatorKind OK);
  149. ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
  150. ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
  151. SymbolRef Sym2, bool Equal);
  152. bool isBoundThroughLazyCompoundVal(const Environment &Env,
  153. const MemRegion *Reg);
  154. const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call);
  155. } // namespace
  156. void IteratorModeling::checkPostCall(const CallEvent &Call,
  157. CheckerContext &C) const {
  158. // Record new iterator positions and iterator position changes
  159. const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
  160. if (!Func)
  161. return;
  162. if (Func->isOverloadedOperator()) {
  163. const auto Op = Func->getOverloadedOperator();
  164. handleOverloadedOperator(C, Call, Op);
  165. return;
  166. }
  167. const auto *OrigExpr = Call.getOriginExpr();
  168. if (!OrigExpr)
  169. return;
  170. const AdvanceFn *Handler = AdvanceLikeFunctions.lookup(Call);
  171. if (Handler) {
  172. handleAdvanceLikeFunction(C, Call, OrigExpr, Handler);
  173. return;
  174. }
  175. if (!isIteratorType(Call.getResultType()))
  176. return;
  177. auto State = C.getState();
  178. // Already bound to container?
  179. if (getIteratorPosition(State, Call.getReturnValue()))
  180. return;
  181. // Copy-like and move constructors
  182. if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
  183. if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
  184. State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
  185. if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
  186. State = removeIteratorPosition(State, Call.getArgSVal(0));
  187. }
  188. C.addTransition(State);
  189. return;
  190. }
  191. }
  192. // Assumption: if return value is an iterator which is not yet bound to a
  193. // container, then look for the first iterator argument of the
  194. // same type as the return value and bind the return value to
  195. // the same container. This approach works for STL algorithms.
  196. // FIXME: Add a more conservative mode
  197. for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
  198. if (isIteratorType(Call.getArgExpr(i)->getType()) &&
  199. Call.getArgExpr(i)->getType().getNonReferenceType().getDesugaredType(
  200. C.getASTContext()).getTypePtr() ==
  201. Call.getResultType().getDesugaredType(C.getASTContext()).getTypePtr()) {
  202. if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
  203. assignToContainer(C, OrigExpr, Call.getReturnValue(),
  204. Pos->getContainer());
  205. return;
  206. }
  207. }
  208. }
  209. }
  210. void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S,
  211. CheckerContext &C) const {
  212. auto State = C.getState();
  213. const auto *Pos = getIteratorPosition(State, Val);
  214. if (Pos) {
  215. State = setIteratorPosition(State, Loc, *Pos);
  216. C.addTransition(State);
  217. } else {
  218. const auto *OldPos = getIteratorPosition(State, Loc);
  219. if (OldPos) {
  220. State = removeIteratorPosition(State, Loc);
  221. C.addTransition(State);
  222. }
  223. }
  224. }
  225. void IteratorModeling::checkPostStmt(const UnaryOperator *UO,
  226. CheckerContext &C) const {
  227. UnaryOperatorKind OK = UO->getOpcode();
  228. if (!isIncrementOperator(OK) && !isDecrementOperator(OK))
  229. return;
  230. auto &SVB = C.getSValBuilder();
  231. handlePtrIncrOrDecr(C, UO->getSubExpr(),
  232. isIncrementOperator(OK) ? OO_Plus : OO_Minus,
  233. SVB.makeArrayIndex(1));
  234. }
  235. void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
  236. CheckerContext &C) const {
  237. const ProgramStateRef State = C.getState();
  238. const BinaryOperatorKind OK = BO->getOpcode();
  239. const Expr *const LHS = BO->getLHS();
  240. const Expr *const RHS = BO->getRHS();
  241. const SVal LVal = State->getSVal(LHS, C.getLocationContext());
  242. const SVal RVal = State->getSVal(RHS, C.getLocationContext());
  243. if (isSimpleComparisonOperator(BO->getOpcode())) {
  244. SVal Result = State->getSVal(BO, C.getLocationContext());
  245. handleComparison(C, BO, Result, LVal, RVal,
  246. BinaryOperator::getOverloadedOperator(OK));
  247. } else if (isRandomIncrOrDecrOperator(OK)) {
  248. // In case of operator+ the iterator can be either on the LHS (eg.: it + 1),
  249. // or on the RHS (eg.: 1 + it). Both cases are modeled.
  250. const bool IsIterOnLHS = BO->getLHS()->getType()->isPointerType();
  251. const Expr *const &IterExpr = IsIterOnLHS ? LHS : RHS;
  252. const Expr *const &AmountExpr = IsIterOnLHS ? RHS : LHS;
  253. // The non-iterator side must have an integral or enumeration type.
  254. if (!AmountExpr->getType()->isIntegralOrEnumerationType())
  255. return;
  256. const SVal &AmountVal = IsIterOnLHS ? RVal : LVal;
  257. handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK),
  258. AmountVal);
  259. }
  260. }
  261. void IteratorModeling::checkPostStmt(const MaterializeTemporaryExpr *MTE,
  262. CheckerContext &C) const {
  263. /* Transfer iterator state to temporary objects */
  264. auto State = C.getState();
  265. const auto *Pos = getIteratorPosition(State, C.getSVal(MTE->getSubExpr()));
  266. if (!Pos)
  267. return;
  268. State = setIteratorPosition(State, C.getSVal(MTE), *Pos);
  269. C.addTransition(State);
  270. }
  271. void IteratorModeling::checkLiveSymbols(ProgramStateRef State,
  272. SymbolReaper &SR) const {
  273. // Keep symbolic expressions of iterator positions alive
  274. auto RegionMap = State->get<IteratorRegionMap>();
  275. for (const auto &Reg : RegionMap) {
  276. const auto Offset = Reg.second.getOffset();
  277. for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
  278. if (isa<SymbolData>(*i))
  279. SR.markLive(*i);
  280. }
  281. auto SymbolMap = State->get<IteratorSymbolMap>();
  282. for (const auto &Sym : SymbolMap) {
  283. const auto Offset = Sym.second.getOffset();
  284. for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i)
  285. if (isa<SymbolData>(*i))
  286. SR.markLive(*i);
  287. }
  288. }
  289. void IteratorModeling::checkDeadSymbols(SymbolReaper &SR,
  290. CheckerContext &C) const {
  291. // Cleanup
  292. auto State = C.getState();
  293. auto RegionMap = State->get<IteratorRegionMap>();
  294. for (const auto &Reg : RegionMap) {
  295. if (!SR.isLiveRegion(Reg.first)) {
  296. // The region behind the `LazyCompoundVal` is often cleaned up before
  297. // the `LazyCompoundVal` itself. If there are iterator positions keyed
  298. // by these regions their cleanup must be deferred.
  299. if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) {
  300. State = State->remove<IteratorRegionMap>(Reg.first);
  301. }
  302. }
  303. }
  304. auto SymbolMap = State->get<IteratorSymbolMap>();
  305. for (const auto &Sym : SymbolMap) {
  306. if (!SR.isLive(Sym.first)) {
  307. State = State->remove<IteratorSymbolMap>(Sym.first);
  308. }
  309. }
  310. C.addTransition(State);
  311. }
  312. void
  313. IteratorModeling::handleOverloadedOperator(CheckerContext &C,
  314. const CallEvent &Call,
  315. OverloadedOperatorKind Op) const {
  316. if (isSimpleComparisonOperator(Op)) {
  317. const auto *OrigExpr = Call.getOriginExpr();
  318. if (!OrigExpr)
  319. return;
  320. if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
  321. handleComparison(C, OrigExpr, Call.getReturnValue(),
  322. InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
  323. return;
  324. }
  325. handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
  326. Call.getArgSVal(1), Op);
  327. return;
  328. } else if (isRandomIncrOrDecrOperator(Op)) {
  329. const auto *OrigExpr = Call.getOriginExpr();
  330. if (!OrigExpr)
  331. return;
  332. if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
  333. if (Call.getNumArgs() >= 1 &&
  334. Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
  335. handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
  336. InstCall->getCXXThisVal(), Call.getArgSVal(0));
  337. return;
  338. }
  339. } else if (Call.getNumArgs() >= 2) {
  340. const Expr *FirstArg = Call.getArgExpr(0);
  341. const Expr *SecondArg = Call.getArgExpr(1);
  342. const QualType FirstType = FirstArg->getType();
  343. const QualType SecondType = SecondArg->getType();
  344. if (FirstType->isIntegralOrEnumerationType() ||
  345. SecondType->isIntegralOrEnumerationType()) {
  346. // In case of operator+ the iterator can be either on the LHS (eg.:
  347. // it + 1), or on the RHS (eg.: 1 + it). Both cases are modeled.
  348. const bool IsIterFirst = FirstType->isStructureOrClassType();
  349. const SVal FirstArg = Call.getArgSVal(0);
  350. const SVal SecondArg = Call.getArgSVal(1);
  351. const SVal &Iterator = IsIterFirst ? FirstArg : SecondArg;
  352. const SVal &Amount = IsIterFirst ? SecondArg : FirstArg;
  353. handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
  354. Iterator, Amount);
  355. return;
  356. }
  357. }
  358. } else if (isIncrementOperator(Op)) {
  359. if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
  360. handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
  361. Call.getNumArgs());
  362. return;
  363. }
  364. handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0),
  365. Call.getNumArgs());
  366. return;
  367. } else if (isDecrementOperator(Op)) {
  368. if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
  369. handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
  370. Call.getNumArgs());
  371. return;
  372. }
  373. handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0),
  374. Call.getNumArgs());
  375. return;
  376. }
  377. }
  378. void
  379. IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
  380. const CallEvent &Call,
  381. const Expr *OrigExpr,
  382. const AdvanceFn *Handler) const {
  383. if (!C.wasInlined) {
  384. (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
  385. Call.getArgSVal(0), Call.getArgSVal(1));
  386. return;
  387. }
  388. // If std::advance() was inlined, but a non-standard function it calls inside
  389. // was not, then we have to model it explicitly
  390. const auto *IdInfo = cast<FunctionDecl>(Call.getDecl())->getIdentifier();
  391. if (IdInfo) {
  392. if (IdInfo->getName() == "advance") {
  393. if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) {
  394. (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
  395. Call.getArgSVal(0), Call.getArgSVal(1));
  396. }
  397. }
  398. }
  399. }
  400. void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
  401. SVal RetVal, const SVal &LVal,
  402. const SVal &RVal,
  403. OverloadedOperatorKind Op) const {
  404. // Record the operands and the operator of the comparison for the next
  405. // evalAssume, if the result is a symbolic expression. If it is a concrete
  406. // value (only one branch is possible), then transfer the state between
  407. // the operands according to the operator and the result
  408. auto State = C.getState();
  409. const auto *LPos = getIteratorPosition(State, LVal);
  410. const auto *RPos = getIteratorPosition(State, RVal);
  411. const MemRegion *Cont = nullptr;
  412. if (LPos) {
  413. Cont = LPos->getContainer();
  414. } else if (RPos) {
  415. Cont = RPos->getContainer();
  416. }
  417. if (!Cont)
  418. return;
  419. // At least one of the iterators has recorded positions. If one of them does
  420. // not then create a new symbol for the offset.
  421. SymbolRef Sym;
  422. if (!LPos || !RPos) {
  423. auto &SymMgr = C.getSymbolManager();
  424. Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
  425. C.getASTContext().LongTy, C.blockCount());
  426. State = assumeNoOverflow(State, Sym, 4);
  427. }
  428. if (!LPos) {
  429. State = setIteratorPosition(State, LVal,
  430. IteratorPosition::getPosition(Cont, Sym));
  431. LPos = getIteratorPosition(State, LVal);
  432. } else if (!RPos) {
  433. State = setIteratorPosition(State, RVal,
  434. IteratorPosition::getPosition(Cont, Sym));
  435. RPos = getIteratorPosition(State, RVal);
  436. }
  437. // If the value for which we just tried to set a new iterator position is
  438. // an `SVal`for which no iterator position can be set then the setting was
  439. // unsuccessful. We cannot handle the comparison in this case.
  440. if (!LPos || !RPos)
  441. return;
  442. // We cannot make assumptions on `UnknownVal`. Let us conjure a symbol
  443. // instead.
  444. if (RetVal.isUnknown()) {
  445. auto &SymMgr = C.getSymbolManager();
  446. auto *LCtx = C.getLocationContext();
  447. RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
  448. CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
  449. State = State->BindExpr(CE, LCtx, RetVal);
  450. }
  451. processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
  452. }
  453. void IteratorModeling::processComparison(CheckerContext &C,
  454. ProgramStateRef State, SymbolRef Sym1,
  455. SymbolRef Sym2, const SVal &RetVal,
  456. OverloadedOperatorKind Op) const {
  457. if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
  458. if ((State = relateSymbols(State, Sym1, Sym2,
  459. (Op == OO_EqualEqual) ==
  460. (TruthVal->getValue() != 0)))) {
  461. C.addTransition(State);
  462. } else {
  463. C.generateSink(State, C.getPredecessor());
  464. }
  465. return;
  466. }
  467. const auto ConditionVal = RetVal.getAs<DefinedSVal>();
  468. if (!ConditionVal)
  469. return;
  470. if (auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) {
  471. StateTrue = StateTrue->assume(*ConditionVal, true);
  472. C.addTransition(StateTrue);
  473. }
  474. if (auto StateFalse = relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual)) {
  475. StateFalse = StateFalse->assume(*ConditionVal, false);
  476. C.addTransition(StateFalse);
  477. }
  478. }
  479. void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal,
  480. const SVal &Iter, bool Postfix) const {
  481. // Increment the symbolic expressions which represents the position of the
  482. // iterator
  483. auto State = C.getState();
  484. auto &BVF = C.getSymbolManager().getBasicVals();
  485. const auto *Pos = getIteratorPosition(State, Iter);
  486. if (!Pos)
  487. return;
  488. auto NewState =
  489. advancePosition(State, Iter, OO_Plus,
  490. nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
  491. assert(NewState &&
  492. "Advancing position by concrete int should always be successful");
  493. const auto *NewPos = getIteratorPosition(NewState, Iter);
  494. assert(NewPos &&
  495. "Iterator should have position after successful advancement");
  496. State = setIteratorPosition(State, Iter, *NewPos);
  497. State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos);
  498. C.addTransition(State);
  499. }
  500. void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal,
  501. const SVal &Iter, bool Postfix) const {
  502. // Decrement the symbolic expressions which represents the position of the
  503. // iterator
  504. auto State = C.getState();
  505. auto &BVF = C.getSymbolManager().getBasicVals();
  506. const auto *Pos = getIteratorPosition(State, Iter);
  507. if (!Pos)
  508. return;
  509. auto NewState =
  510. advancePosition(State, Iter, OO_Minus,
  511. nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))));
  512. assert(NewState &&
  513. "Advancing position by concrete int should always be successful");
  514. const auto *NewPos = getIteratorPosition(NewState, Iter);
  515. assert(NewPos &&
  516. "Iterator should have position after successful advancement");
  517. State = setIteratorPosition(State, Iter, *NewPos);
  518. State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos);
  519. C.addTransition(State);
  520. }
  521. void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
  522. OverloadedOperatorKind Op,
  523. const SVal &RetVal,
  524. const SVal &Iterator,
  525. const SVal &Amount) const {
  526. // Increment or decrement the symbolic expressions which represents the
  527. // position of the iterator
  528. auto State = C.getState();
  529. const auto *Pos = getIteratorPosition(State, Iterator);
  530. if (!Pos)
  531. return;
  532. const auto *Value = &Amount;
  533. SVal Val;
  534. if (auto LocAmount = Amount.getAs<Loc>()) {
  535. Val = State->getRawSVal(*LocAmount);
  536. Value = &Val;
  537. }
  538. const auto &TgtVal =
  539. (Op == OO_PlusEqual || Op == OO_MinusEqual) ? Iterator : RetVal;
  540. // `AdvancedState` is a state where the position of `LHS` is advanced. We
  541. // only need this state to retrieve the new position, but we do not want
  542. // to change the position of `LHS` (in every case).
  543. auto AdvancedState = advancePosition(State, Iterator, Op, *Value);
  544. if (AdvancedState) {
  545. const auto *NewPos = getIteratorPosition(AdvancedState, Iterator);
  546. assert(NewPos &&
  547. "Iterator should have position after successful advancement");
  548. State = setIteratorPosition(State, TgtVal, *NewPos);
  549. C.addTransition(State);
  550. } else {
  551. assignToContainer(C, CE, TgtVal, Pos->getContainer());
  552. }
  553. }
  554. void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C,
  555. const Expr *Iterator,
  556. OverloadedOperatorKind OK,
  557. SVal Offset) const {
  558. if (!Offset.getAs<DefinedSVal>())
  559. return;
  560. QualType PtrType = Iterator->getType();
  561. if (!PtrType->isPointerType())
  562. return;
  563. QualType ElementType = PtrType->getPointeeType();
  564. ProgramStateRef State = C.getState();
  565. SVal OldVal = State->getSVal(Iterator, C.getLocationContext());
  566. const IteratorPosition *OldPos = getIteratorPosition(State, OldVal);
  567. if (!OldPos)
  568. return;
  569. SVal NewVal;
  570. if (OK == OO_Plus || OK == OO_PlusEqual) {
  571. NewVal = State->getLValue(ElementType, Offset, OldVal);
  572. } else {
  573. auto &SVB = C.getSValBuilder();
  574. SVal NegatedOffset = SVB.evalMinus(Offset.castAs<NonLoc>());
  575. NewVal = State->getLValue(ElementType, NegatedOffset, OldVal);
  576. }
  577. // `AdvancedState` is a state where the position of `Old` is advanced. We
  578. // only need this state to retrieve the new position, but we do not want
  579. // ever to change the position of `OldVal`.
  580. auto AdvancedState = advancePosition(State, OldVal, OK, Offset);
  581. if (AdvancedState) {
  582. const IteratorPosition *NewPos = getIteratorPosition(AdvancedState, OldVal);
  583. assert(NewPos &&
  584. "Iterator should have position after successful advancement");
  585. ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos);
  586. C.addTransition(NewState);
  587. } else {
  588. assignToContainer(C, Iterator, NewVal, OldPos->getContainer());
  589. }
  590. }
  591. void IteratorModeling::handleAdvance(CheckerContext &C, const Expr *CE,
  592. SVal RetVal, SVal Iter,
  593. SVal Amount) const {
  594. handleRandomIncrOrDecr(C, CE, OO_PlusEqual, RetVal, Iter, Amount);
  595. }
  596. void IteratorModeling::handlePrev(CheckerContext &C, const Expr *CE,
  597. SVal RetVal, SVal Iter, SVal Amount) const {
  598. handleRandomIncrOrDecr(C, CE, OO_Minus, RetVal, Iter, Amount);
  599. }
  600. void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE,
  601. SVal RetVal, SVal Iter, SVal Amount) const {
  602. handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount);
  603. }
  604. void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
  605. const SVal &RetVal,
  606. const MemRegion *Cont) const {
  607. Cont = Cont->getMostDerivedObjectRegion();
  608. auto State = C.getState();
  609. const auto *LCtx = C.getLocationContext();
  610. State = createIteratorPosition(State, RetVal, Cont, CE, LCtx, C.blockCount());
  611. C.addTransition(State);
  612. }
  613. bool IteratorModeling::noChangeInAdvance(CheckerContext &C, SVal Iter,
  614. const Expr *CE) const {
  615. // Compare the iterator position before and after the call. (To be called
  616. // from `checkPostCall()`.)
  617. const auto StateAfter = C.getState();
  618. const auto *PosAfter = getIteratorPosition(StateAfter, Iter);
  619. // If we have no position after the call of `std::advance`, then we are not
  620. // interested. (Modeling of an inlined `std::advance()` should not remove the
  621. // position in any case.)
  622. if (!PosAfter)
  623. return false;
  624. const ExplodedNode *N = findCallEnter(C.getPredecessor(), CE);
  625. assert(N && "Any call should have a `CallEnter` node.");
  626. const auto StateBefore = N->getState();
  627. const auto *PosBefore = getIteratorPosition(StateBefore, Iter);
  628. // FIXME: `std::advance()` should not create a new iterator position but
  629. // change existing ones. However, in case of iterators implemented as
  630. // pointers the handling of parameters in `std::advance()`-like
  631. // functions is still incomplete which may result in cases where
  632. // the new position is assigned to the wrong pointer. This causes
  633. // crash if we use an assertion here.
  634. if (!PosBefore)
  635. return false;
  636. return PosBefore->getOffset() == PosAfter->getOffset();
  637. }
  638. void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State,
  639. const char *NL, const char *Sep) const {
  640. auto SymbolMap = State->get<IteratorSymbolMap>();
  641. auto RegionMap = State->get<IteratorRegionMap>();
  642. // Use a counter to add newlines before every line except the first one.
  643. unsigned Count = 0;
  644. if (!SymbolMap.isEmpty() || !RegionMap.isEmpty()) {
  645. Out << Sep << "Iterator Positions :" << NL;
  646. for (const auto &Sym : SymbolMap) {
  647. if (Count++)
  648. Out << NL;
  649. Sym.first->dumpToStream(Out);
  650. Out << " : ";
  651. const auto Pos = Sym.second;
  652. Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == ";
  653. Pos.getContainer()->dumpToStream(Out);
  654. Out<<" ; Offset == ";
  655. Pos.getOffset()->dumpToStream(Out);
  656. }
  657. for (const auto &Reg : RegionMap) {
  658. if (Count++)
  659. Out << NL;
  660. Reg.first->dumpToStream(Out);
  661. Out << " : ";
  662. const auto Pos = Reg.second;
  663. Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == ";
  664. Pos.getContainer()->dumpToStream(Out);
  665. Out<<" ; Offset == ";
  666. Pos.getOffset()->dumpToStream(Out);
  667. }
  668. }
  669. }
  670. namespace {
  671. bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
  672. return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
  673. }
  674. bool isSimpleComparisonOperator(BinaryOperatorKind OK) {
  675. return OK == BO_EQ || OK == BO_NE;
  676. }
  677. ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
  678. if (auto Reg = Val.getAsRegion()) {
  679. Reg = Reg->getMostDerivedObjectRegion();
  680. return State->remove<IteratorRegionMap>(Reg);
  681. } else if (const auto Sym = Val.getAsSymbol()) {
  682. return State->remove<IteratorSymbolMap>(Sym);
  683. } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
  684. return State->remove<IteratorRegionMap>(LCVal->getRegion());
  685. }
  686. return nullptr;
  687. }
  688. ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
  689. SymbolRef Sym2, bool Equal) {
  690. auto &SVB = State->getStateManager().getSValBuilder();
  691. // FIXME: This code should be reworked as follows:
  692. // 1. Subtract the operands using evalBinOp().
  693. // 2. Assume that the result doesn't overflow.
  694. // 3. Compare the result to 0.
  695. // 4. Assume the result of the comparison.
  696. const auto comparison =
  697. SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1),
  698. nonloc::SymbolVal(Sym2), SVB.getConditionType());
  699. assert(comparison.getAs<DefinedSVal>() &&
  700. "Symbol comparison must be a `DefinedSVal`");
  701. auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal);
  702. if (!NewState)
  703. return nullptr;
  704. if (const auto CompSym = comparison.getAsSymbol()) {
  705. assert(isa<SymIntExpr>(CompSym) &&
  706. "Symbol comparison must be a `SymIntExpr`");
  707. assert(BinaryOperator::isComparisonOp(
  708. cast<SymIntExpr>(CompSym)->getOpcode()) &&
  709. "Symbol comparison must be a comparison");
  710. return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2);
  711. }
  712. return NewState;
  713. }
  714. bool isBoundThroughLazyCompoundVal(const Environment &Env,
  715. const MemRegion *Reg) {
  716. for (const auto &Binding : Env) {
  717. if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) {
  718. if (LCVal->getRegion() == Reg)
  719. return true;
  720. }
  721. }
  722. return false;
  723. }
  724. const ExplodedNode *findCallEnter(const ExplodedNode *Node, const Expr *Call) {
  725. while (Node) {
  726. ProgramPoint PP = Node->getLocation();
  727. if (auto Enter = PP.getAs<CallEnter>()) {
  728. if (Enter->getCallExpr() == Call)
  729. break;
  730. }
  731. Node = Node->getFirstPred();
  732. }
  733. return Node;
  734. }
  735. } // namespace
  736. void ento::registerIteratorModeling(CheckerManager &mgr) {
  737. mgr.registerChecker<IteratorModeling>();
  738. }
  739. bool ento::shouldRegisterIteratorModeling(const CheckerManager &mgr) {
  740. return true;
  741. }