SmartPtrModeling.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. // SmartPtrModeling.cpp - Model behavior of C++ smart pointers - 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. // This file defines a checker that models various aspects of
  10. // C++ smart pointer behavior.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "Move.h"
  14. #include "SmartPtr.h"
  15. #include "clang/AST/DeclCXX.h"
  16. #include "clang/AST/DeclarationName.h"
  17. #include "clang/AST/ExprCXX.h"
  18. #include "clang/AST/Type.h"
  19. #include "clang/Basic/LLVM.h"
  20. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  21. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  22. #include "clang/StaticAnalyzer/Core/Checker.h"
  23. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
  25. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  26. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  27. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
  28. #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
  29. #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
  30. #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
  31. #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
  32. #include "llvm/ADT/StringMap.h"
  33. #include "llvm/Support/ErrorHandling.h"
  34. #include <string>
  35. using namespace clang;
  36. using namespace ento;
  37. namespace {
  38. class SmartPtrModeling
  39. : public Checker<eval::Call, check::DeadSymbols, check::RegionChanges,
  40. check::LiveSymbols> {
  41. bool isBoolConversionMethod(const CallEvent &Call) const;
  42. public:
  43. // Whether the checker should model for null dereferences of smart pointers.
  44. DefaultBool ModelSmartPtrDereference;
  45. bool evalCall(const CallEvent &Call, CheckerContext &C) const;
  46. void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
  47. void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
  48. ProgramStateRef
  49. checkRegionChanges(ProgramStateRef State,
  50. const InvalidatedSymbols *Invalidated,
  51. ArrayRef<const MemRegion *> ExplicitRegions,
  52. ArrayRef<const MemRegion *> Regions,
  53. const LocationContext *LCtx, const CallEvent *Call) const;
  54. void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
  55. const char *Sep) const override;
  56. void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
  57. private:
  58. void handleReset(const CallEvent &Call, CheckerContext &C) const;
  59. void handleRelease(const CallEvent &Call, CheckerContext &C) const;
  60. void handleSwapMethod(const CallEvent &Call, CheckerContext &C) const;
  61. void handleGet(const CallEvent &Call, CheckerContext &C) const;
  62. bool handleAssignOp(const CallEvent &Call, CheckerContext &C) const;
  63. bool handleMoveCtr(const CallEvent &Call, CheckerContext &C,
  64. const MemRegion *ThisRegion) const;
  65. bool updateMovedSmartPointers(CheckerContext &C, const MemRegion *ThisRegion,
  66. const MemRegion *OtherSmartPtrRegion) const;
  67. void handleBoolConversion(const CallEvent &Call, CheckerContext &C) const;
  68. bool handleComparisionOp(const CallEvent &Call, CheckerContext &C) const;
  69. bool handleOstreamOperator(const CallEvent &Call, CheckerContext &C) const;
  70. bool handleSwap(ProgramStateRef State, SVal First, SVal Second,
  71. CheckerContext &C) const;
  72. std::pair<SVal, ProgramStateRef>
  73. retrieveOrConjureInnerPtrVal(ProgramStateRef State,
  74. const MemRegion *ThisRegion, const Expr *E,
  75. QualType Type, CheckerContext &C) const;
  76. using SmartPtrMethodHandlerFn =
  77. void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
  78. CallDescriptionMap<SmartPtrMethodHandlerFn> SmartPtrMethodHandlers{
  79. {{"reset"}, &SmartPtrModeling::handleReset},
  80. {{"release"}, &SmartPtrModeling::handleRelease},
  81. {{"swap", 1}, &SmartPtrModeling::handleSwapMethod},
  82. {{"get"}, &SmartPtrModeling::handleGet}};
  83. const CallDescription StdSwapCall{{"std", "swap"}, 2};
  84. const CallDescription StdMakeUniqueCall{{"std", "make_unique"}};
  85. const CallDescription StdMakeUniqueForOverwriteCall{
  86. {"std", "make_unique_for_overwrite"}};
  87. };
  88. } // end of anonymous namespace
  89. REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, SVal)
  90. // Checks if RD has name in Names and is in std namespace
  91. static bool hasStdClassWithName(const CXXRecordDecl *RD,
  92. ArrayRef<llvm::StringLiteral> Names) {
  93. if (!RD || !RD->getDeclContext()->isStdNamespace())
  94. return false;
  95. if (RD->getDeclName().isIdentifier())
  96. return llvm::is_contained(Names, RD->getName());
  97. return false;
  98. }
  99. constexpr llvm::StringLiteral STD_PTR_NAMES[] = {"shared_ptr", "unique_ptr",
  100. "weak_ptr"};
  101. static bool isStdSmartPtr(const CXXRecordDecl *RD) {
  102. return hasStdClassWithName(RD, STD_PTR_NAMES);
  103. }
  104. static bool isStdSmartPtr(const Expr *E) {
  105. return isStdSmartPtr(E->getType()->getAsCXXRecordDecl());
  106. }
  107. // Define the inter-checker API.
  108. namespace clang {
  109. namespace ento {
  110. namespace smartptr {
  111. bool isStdSmartPtrCall(const CallEvent &Call) {
  112. const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
  113. if (!MethodDecl || !MethodDecl->getParent())
  114. return false;
  115. return isStdSmartPtr(MethodDecl->getParent());
  116. }
  117. bool isStdSmartPtr(const CXXRecordDecl *RD) {
  118. if (!RD || !RD->getDeclContext()->isStdNamespace())
  119. return false;
  120. if (RD->getDeclName().isIdentifier()) {
  121. StringRef Name = RD->getName();
  122. return Name == "shared_ptr" || Name == "unique_ptr" || Name == "weak_ptr";
  123. }
  124. return false;
  125. }
  126. bool isStdSmartPtr(const Expr *E) {
  127. return isStdSmartPtr(E->getType()->getAsCXXRecordDecl());
  128. }
  129. bool isNullSmartPtr(const ProgramStateRef State, const MemRegion *ThisRegion) {
  130. const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
  131. return InnerPointVal &&
  132. !State->assume(InnerPointVal->castAs<DefinedOrUnknownSVal>(), true);
  133. }
  134. } // namespace smartptr
  135. } // namespace ento
  136. } // namespace clang
  137. // If a region is removed all of the subregions need to be removed too.
  138. static TrackedRegionMapTy
  139. removeTrackedSubregions(TrackedRegionMapTy RegionMap,
  140. TrackedRegionMapTy::Factory &RegionMapFactory,
  141. const MemRegion *Region) {
  142. if (!Region)
  143. return RegionMap;
  144. for (const auto &E : RegionMap) {
  145. if (E.first->isSubRegionOf(Region))
  146. RegionMap = RegionMapFactory.remove(RegionMap, E.first);
  147. }
  148. return RegionMap;
  149. }
  150. static ProgramStateRef updateSwappedRegion(ProgramStateRef State,
  151. const MemRegion *Region,
  152. const SVal *RegionInnerPointerVal) {
  153. if (RegionInnerPointerVal) {
  154. State = State->set<TrackedRegionMap>(Region, *RegionInnerPointerVal);
  155. } else {
  156. State = State->remove<TrackedRegionMap>(Region);
  157. }
  158. return State;
  159. }
  160. static QualType getInnerPointerType(CheckerContext C, const CXXRecordDecl *RD) {
  161. if (!RD || !RD->isInStdNamespace())
  162. return {};
  163. const auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD);
  164. if (!TSD)
  165. return {};
  166. auto TemplateArgs = TSD->getTemplateArgs().asArray();
  167. if (TemplateArgs.empty())
  168. return {};
  169. auto InnerValueType = TemplateArgs[0].getAsType();
  170. return C.getASTContext().getPointerType(InnerValueType.getCanonicalType());
  171. }
  172. // This is for use with standalone-functions like std::make_unique,
  173. // std::make_unique_for_overwrite, etc. It reads the template parameter and
  174. // returns the pointer type corresponding to it,
  175. static QualType getPointerTypeFromTemplateArg(const CallEvent &Call,
  176. CheckerContext &C) {
  177. const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
  178. if (!FD || !FD->isFunctionTemplateSpecialization())
  179. return {};
  180. const auto &TemplateArgs = FD->getTemplateSpecializationArgs()->asArray();
  181. if (TemplateArgs.size() == 0)
  182. return {};
  183. auto ValueType = TemplateArgs[0].getAsType();
  184. return C.getASTContext().getPointerType(ValueType.getCanonicalType());
  185. }
  186. // Helper method to get the inner pointer type of specialized smart pointer
  187. // Returns empty type if not found valid inner pointer type.
  188. static QualType getInnerPointerType(const CallEvent &Call, CheckerContext &C) {
  189. const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
  190. if (!MethodDecl || !MethodDecl->getParent())
  191. return {};
  192. const auto *RecordDecl = MethodDecl->getParent();
  193. return getInnerPointerType(C, RecordDecl);
  194. }
  195. // Helper method to pretty print region and avoid extra spacing.
  196. static void checkAndPrettyPrintRegion(llvm::raw_ostream &OS,
  197. const MemRegion *Region) {
  198. if (Region->canPrintPretty()) {
  199. OS << " ";
  200. Region->printPretty(OS);
  201. }
  202. }
  203. bool SmartPtrModeling::isBoolConversionMethod(const CallEvent &Call) const {
  204. // TODO: Update CallDescription to support anonymous calls?
  205. // TODO: Handle other methods, such as .get() or .release().
  206. // But once we do, we'd need a visitor to explain null dereferences
  207. // that are found via such modeling.
  208. const auto *CD = dyn_cast_or_null<CXXConversionDecl>(Call.getDecl());
  209. return CD && CD->getConversionType()->isBooleanType();
  210. }
  211. constexpr llvm::StringLiteral BASIC_OSTREAM_NAMES[] = {"basic_ostream"};
  212. bool isStdBasicOstream(const Expr *E) {
  213. const auto *RD = E->getType()->getAsCXXRecordDecl();
  214. return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
  215. }
  216. static bool isStdFunctionCall(const CallEvent &Call) {
  217. return Call.getDecl() && Call.getDecl()->getDeclContext()->isStdNamespace();
  218. }
  219. bool isStdOstreamOperatorCall(const CallEvent &Call) {
  220. if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
  221. return false;
  222. const auto *FC = dyn_cast<SimpleFunctionCall>(&Call);
  223. if (!FC)
  224. return false;
  225. const FunctionDecl *FD = FC->getDecl();
  226. if (!FD->isOverloadedOperator())
  227. return false;
  228. const OverloadedOperatorKind OOK = FD->getOverloadedOperator();
  229. if (OOK != clang::OO_LessLess)
  230. return false;
  231. return isStdSmartPtr(Call.getArgExpr(1)) &&
  232. isStdBasicOstream(Call.getArgExpr(0));
  233. }
  234. static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
  235. if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
  236. return false;
  237. return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
  238. smartptr::isStdSmartPtr(Call.getArgExpr(1));
  239. }
  240. bool SmartPtrModeling::evalCall(const CallEvent &Call,
  241. CheckerContext &C) const {
  242. ProgramStateRef State = C.getState();
  243. // If any one of the arg is a unique_ptr, then
  244. // we can try this function
  245. if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
  246. if (handleComparisionOp(Call, C))
  247. return true;
  248. if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
  249. return handleOstreamOperator(Call, C);
  250. if (StdSwapCall.matches(Call)) {
  251. // Check the first arg, if it is of std::unique_ptr type.
  252. assert(Call.getNumArgs() == 2 && "std::swap should have two arguments");
  253. const Expr *FirstArg = Call.getArgExpr(0);
  254. if (!smartptr::isStdSmartPtr(FirstArg->getType()->getAsCXXRecordDecl()))
  255. return false;
  256. return handleSwap(State, Call.getArgSVal(0), Call.getArgSVal(1), C);
  257. }
  258. if (matchesAny(Call, StdMakeUniqueCall, StdMakeUniqueForOverwriteCall)) {
  259. if (!ModelSmartPtrDereference)
  260. return false;
  261. const Optional<SVal> ThisRegionOpt = Call.getReturnValueUnderConstruction();
  262. if (!ThisRegionOpt)
  263. return false;
  264. const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal(
  265. Call.getOriginExpr(), C.getLocationContext(),
  266. getPointerTypeFromTemplateArg(Call, C), C.blockCount());
  267. const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion();
  268. State = State->set<TrackedRegionMap>(ThisRegion, PtrVal);
  269. State = State->assume(PtrVal, true);
  270. // TODO: ExprEngine should do this for us.
  271. // For a bit more context:
  272. // 1) Why do we need this? Since we are modelling a "function"
  273. // that returns a constructed object we need to store this information in
  274. // the program state.
  275. //
  276. // 2) Why does this work?
  277. // `updateObjectsUnderConstruction` does exactly as it sounds.
  278. //
  279. // 3) How should it look like when moved to the Engine?
  280. // It would be nice if we can just
  281. // pretend we don't need to know about this - ie, completely automatic work.
  282. // However, realistically speaking, I think we would need to "signal" the
  283. // ExprEngine evalCall handler that we are constructing an object with this
  284. // function call (constructors obviously construct, hence can be
  285. // automatically deduced).
  286. auto &Engine = State->getStateManager().getOwningEngine();
  287. State = Engine.updateObjectsUnderConstruction(
  288. *ThisRegionOpt, nullptr, State, C.getLocationContext(),
  289. Call.getConstructionContext(), {});
  290. // We don't leave a note here since it is guaranteed the
  291. // unique_ptr from this call is non-null (hence is safe to de-reference).
  292. C.addTransition(State);
  293. return true;
  294. }
  295. if (!smartptr::isStdSmartPtrCall(Call))
  296. return false;
  297. if (isBoolConversionMethod(Call)) {
  298. const MemRegion *ThisR =
  299. cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
  300. if (ModelSmartPtrDereference) {
  301. // The check for the region is moved is duplicated in handleBoolOperation
  302. // method.
  303. // FIXME: Once we model std::move for smart pointers clean up this and use
  304. // that modeling.
  305. handleBoolConversion(Call, C);
  306. return true;
  307. } else {
  308. if (!move::isMovedFrom(State, ThisR)) {
  309. // TODO: Model this case as well. At least, avoid invalidation of
  310. // globals.
  311. return false;
  312. }
  313. // TODO: Add a note to bug reports describing this decision.
  314. C.addTransition(State->BindExpr(
  315. Call.getOriginExpr(), C.getLocationContext(),
  316. C.getSValBuilder().makeZeroVal(Call.getResultType())));
  317. return true;
  318. }
  319. }
  320. if (!ModelSmartPtrDereference)
  321. return false;
  322. if (const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
  323. if (CC->getDecl()->isCopyConstructor())
  324. return false;
  325. const MemRegion *ThisRegion = CC->getCXXThisVal().getAsRegion();
  326. if (!ThisRegion)
  327. return false;
  328. if (CC->getDecl()->isMoveConstructor())
  329. return handleMoveCtr(Call, C, ThisRegion);
  330. if (Call.getNumArgs() == 0) {
  331. auto NullVal = C.getSValBuilder().makeNull();
  332. State = State->set<TrackedRegionMap>(ThisRegion, NullVal);
  333. C.addTransition(
  334. State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR,
  335. llvm::raw_ostream &OS) {
  336. if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
  337. !BR.isInteresting(ThisRegion))
  338. return;
  339. OS << "Default constructed smart pointer";
  340. checkAndPrettyPrintRegion(OS, ThisRegion);
  341. OS << " is null";
  342. }));
  343. } else {
  344. const auto *TrackingExpr = Call.getArgExpr(0);
  345. assert(TrackingExpr->getType()->isPointerType() &&
  346. "Adding a non pointer value to TrackedRegionMap");
  347. auto ArgVal = Call.getArgSVal(0);
  348. State = State->set<TrackedRegionMap>(ThisRegion, ArgVal);
  349. C.addTransition(State, C.getNoteTag([ThisRegion, TrackingExpr,
  350. ArgVal](PathSensitiveBugReport &BR,
  351. llvm::raw_ostream &OS) {
  352. if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
  353. !BR.isInteresting(ThisRegion))
  354. return;
  355. bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR);
  356. OS << "Smart pointer";
  357. checkAndPrettyPrintRegion(OS, ThisRegion);
  358. if (ArgVal.isZeroConstant())
  359. OS << " is constructed using a null value";
  360. else
  361. OS << " is constructed";
  362. }));
  363. }
  364. return true;
  365. }
  366. if (handleAssignOp(Call, C))
  367. return true;
  368. const SmartPtrMethodHandlerFn *Handler = SmartPtrMethodHandlers.lookup(Call);
  369. if (!Handler)
  370. return false;
  371. (this->**Handler)(Call, C);
  372. return C.isDifferent();
  373. }
  374. std::pair<SVal, ProgramStateRef> SmartPtrModeling::retrieveOrConjureInnerPtrVal(
  375. ProgramStateRef State, const MemRegion *ThisRegion, const Expr *E,
  376. QualType Type, CheckerContext &C) const {
  377. const auto *Ptr = State->get<TrackedRegionMap>(ThisRegion);
  378. if (Ptr)
  379. return {*Ptr, State};
  380. auto Val = C.getSValBuilder().conjureSymbolVal(E, C.getLocationContext(),
  381. Type, C.blockCount());
  382. State = State->set<TrackedRegionMap>(ThisRegion, Val);
  383. return {Val, State};
  384. }
  385. bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call,
  386. CheckerContext &C) const {
  387. const auto *FC = dyn_cast<SimpleFunctionCall>(&Call);
  388. if (!FC)
  389. return false;
  390. const FunctionDecl *FD = FC->getDecl();
  391. if (!FD->isOverloadedOperator())
  392. return false;
  393. const OverloadedOperatorKind OOK = FD->getOverloadedOperator();
  394. if (!(OOK == OO_EqualEqual || OOK == OO_ExclaimEqual || OOK == OO_Less ||
  395. OOK == OO_LessEqual || OOK == OO_Greater || OOK == OO_GreaterEqual ||
  396. OOK == OO_Spaceship))
  397. return false;
  398. // There are some special cases about which we can infer about
  399. // the resulting answer.
  400. // For reference, there is a discussion at https://reviews.llvm.org/D104616.
  401. // Also, the cppreference page is good to look at
  402. // https://en.cppreference.com/w/cpp/memory/unique_ptr/operator_cmp.
  403. auto makeSValFor = [&C, this](ProgramStateRef State, const Expr *E,
  404. SVal S) -> std::pair<SVal, ProgramStateRef> {
  405. if (S.isZeroConstant()) {
  406. return {S, State};
  407. }
  408. const MemRegion *Reg = S.getAsRegion();
  409. assert(Reg &&
  410. "this pointer of std::unique_ptr should be obtainable as MemRegion");
  411. QualType Type = getInnerPointerType(C, E->getType()->getAsCXXRecordDecl());
  412. return retrieveOrConjureInnerPtrVal(State, Reg, E, Type, C);
  413. };
  414. SVal First = Call.getArgSVal(0);
  415. SVal Second = Call.getArgSVal(1);
  416. const auto *FirstExpr = Call.getArgExpr(0);
  417. const auto *SecondExpr = Call.getArgExpr(1);
  418. const auto *ResultExpr = Call.getOriginExpr();
  419. const auto *LCtx = C.getLocationContext();
  420. auto &Bldr = C.getSValBuilder();
  421. ProgramStateRef State = C.getState();
  422. SVal FirstPtrVal, SecondPtrVal;
  423. std::tie(FirstPtrVal, State) = makeSValFor(State, FirstExpr, First);
  424. std::tie(SecondPtrVal, State) = makeSValFor(State, SecondExpr, Second);
  425. BinaryOperatorKind BOK =
  426. operationKindFromOverloadedOperator(OOK, true).GetBinaryOpUnsafe();
  427. auto RetVal = Bldr.evalBinOp(State, BOK, FirstPtrVal, SecondPtrVal,
  428. Call.getResultType());
  429. if (OOK != OO_Spaceship) {
  430. ProgramStateRef TrueState, FalseState;
  431. std::tie(TrueState, FalseState) =
  432. State->assume(*RetVal.getAs<DefinedOrUnknownSVal>());
  433. if (TrueState)
  434. C.addTransition(
  435. TrueState->BindExpr(ResultExpr, LCtx, Bldr.makeTruthVal(true)));
  436. if (FalseState)
  437. C.addTransition(
  438. FalseState->BindExpr(ResultExpr, LCtx, Bldr.makeTruthVal(false)));
  439. } else {
  440. C.addTransition(State->BindExpr(ResultExpr, LCtx, RetVal));
  441. }
  442. return true;
  443. }
  444. bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call,
  445. CheckerContext &C) const {
  446. // operator<< does not modify the smart pointer.
  447. // And we don't really have much of modelling of basic_ostream.
  448. // So, we are better off:
  449. // 1) Invalidating the mem-region of the ostream object at hand.
  450. // 2) Setting the SVal of the basic_ostream as the return value.
  451. // Not very satisfying, but it gets the job done, and is better
  452. // than the default handling. :)
  453. ProgramStateRef State = C.getState();
  454. const auto StreamVal = Call.getArgSVal(0);
  455. const MemRegion *StreamThisRegion = StreamVal.getAsRegion();
  456. if (!StreamThisRegion)
  457. return false;
  458. State =
  459. State->invalidateRegions({StreamThisRegion}, Call.getOriginExpr(),
  460. C.blockCount(), C.getLocationContext(), false);
  461. State =
  462. State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal);
  463. C.addTransition(State);
  464. return true;
  465. }
  466. void SmartPtrModeling::checkDeadSymbols(SymbolReaper &SymReaper,
  467. CheckerContext &C) const {
  468. ProgramStateRef State = C.getState();
  469. // Clean up dead regions from the region map.
  470. TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
  471. for (auto E : TrackedRegions) {
  472. const MemRegion *Region = E.first;
  473. bool IsRegDead = !SymReaper.isLiveRegion(Region);
  474. if (IsRegDead)
  475. State = State->remove<TrackedRegionMap>(Region);
  476. }
  477. C.addTransition(State);
  478. }
  479. void SmartPtrModeling::printState(raw_ostream &Out, ProgramStateRef State,
  480. const char *NL, const char *Sep) const {
  481. TrackedRegionMapTy RS = State->get<TrackedRegionMap>();
  482. if (!RS.isEmpty()) {
  483. Out << Sep << "Smart ptr regions :" << NL;
  484. for (auto I : RS) {
  485. I.first->dumpToStream(Out);
  486. if (smartptr::isNullSmartPtr(State, I.first))
  487. Out << ": Null";
  488. else
  489. Out << ": Non Null";
  490. Out << NL;
  491. }
  492. }
  493. }
  494. ProgramStateRef SmartPtrModeling::checkRegionChanges(
  495. ProgramStateRef State, const InvalidatedSymbols *Invalidated,
  496. ArrayRef<const MemRegion *> ExplicitRegions,
  497. ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
  498. const CallEvent *Call) const {
  499. TrackedRegionMapTy RegionMap = State->get<TrackedRegionMap>();
  500. TrackedRegionMapTy::Factory &RegionMapFactory =
  501. State->get_context<TrackedRegionMap>();
  502. for (const auto *Region : Regions)
  503. RegionMap = removeTrackedSubregions(RegionMap, RegionMapFactory,
  504. Region->getBaseRegion());
  505. return State->set<TrackedRegionMap>(RegionMap);
  506. }
  507. void SmartPtrModeling::checkLiveSymbols(ProgramStateRef State,
  508. SymbolReaper &SR) const {
  509. // Marking tracked symbols alive
  510. TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
  511. for (auto I = TrackedRegions.begin(), E = TrackedRegions.end(); I != E; ++I) {
  512. SVal Val = I->second;
  513. for (auto si = Val.symbol_begin(), se = Val.symbol_end(); si != se; ++si) {
  514. SR.markLive(*si);
  515. }
  516. }
  517. }
  518. void SmartPtrModeling::handleReset(const CallEvent &Call,
  519. CheckerContext &C) const {
  520. ProgramStateRef State = C.getState();
  521. const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
  522. if (!IC)
  523. return;
  524. const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
  525. if (!ThisRegion)
  526. return;
  527. assert(Call.getArgExpr(0)->getType()->isPointerType() &&
  528. "Adding a non pointer value to TrackedRegionMap");
  529. State = State->set<TrackedRegionMap>(ThisRegion, Call.getArgSVal(0));
  530. const auto *TrackingExpr = Call.getArgExpr(0);
  531. C.addTransition(
  532. State, C.getNoteTag([ThisRegion, TrackingExpr](PathSensitiveBugReport &BR,
  533. llvm::raw_ostream &OS) {
  534. if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
  535. !BR.isInteresting(ThisRegion))
  536. return;
  537. bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR);
  538. OS << "Smart pointer";
  539. checkAndPrettyPrintRegion(OS, ThisRegion);
  540. OS << " reset using a null value";
  541. }));
  542. // TODO: Make sure to ivalidate the region in the Store if we don't have
  543. // time to model all methods.
  544. }
  545. void SmartPtrModeling::handleRelease(const CallEvent &Call,
  546. CheckerContext &C) const {
  547. ProgramStateRef State = C.getState();
  548. const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
  549. if (!IC)
  550. return;
  551. const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
  552. if (!ThisRegion)
  553. return;
  554. const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
  555. if (InnerPointVal) {
  556. State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
  557. *InnerPointVal);
  558. }
  559. auto ValueToUpdate = C.getSValBuilder().makeNull();
  560. State = State->set<TrackedRegionMap>(ThisRegion, ValueToUpdate);
  561. C.addTransition(State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR,
  562. llvm::raw_ostream &OS) {
  563. if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
  564. !BR.isInteresting(ThisRegion))
  565. return;
  566. OS << "Smart pointer";
  567. checkAndPrettyPrintRegion(OS, ThisRegion);
  568. OS << " is released and set to null";
  569. }));
  570. // TODO: Add support to enable MallocChecker to start tracking the raw
  571. // pointer.
  572. }
  573. void SmartPtrModeling::handleSwapMethod(const CallEvent &Call,
  574. CheckerContext &C) const {
  575. // To model unique_ptr::swap() method.
  576. const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
  577. if (!IC)
  578. return;
  579. auto State = C.getState();
  580. handleSwap(State, IC->getCXXThisVal(), Call.getArgSVal(0), C);
  581. }
  582. bool SmartPtrModeling::handleSwap(ProgramStateRef State, SVal First,
  583. SVal Second, CheckerContext &C) const {
  584. const MemRegion *FirstThisRegion = First.getAsRegion();
  585. if (!FirstThisRegion)
  586. return false;
  587. const MemRegion *SecondThisRegion = Second.getAsRegion();
  588. if (!SecondThisRegion)
  589. return false;
  590. const auto *FirstInnerPtrVal = State->get<TrackedRegionMap>(FirstThisRegion);
  591. const auto *SecondInnerPtrVal =
  592. State->get<TrackedRegionMap>(SecondThisRegion);
  593. State = updateSwappedRegion(State, FirstThisRegion, SecondInnerPtrVal);
  594. State = updateSwappedRegion(State, SecondThisRegion, FirstInnerPtrVal);
  595. C.addTransition(State, C.getNoteTag([FirstThisRegion, SecondThisRegion](
  596. PathSensitiveBugReport &BR,
  597. llvm::raw_ostream &OS) {
  598. if (&BR.getBugType() != smartptr::getNullDereferenceBugType())
  599. return;
  600. if (BR.isInteresting(FirstThisRegion) &&
  601. !BR.isInteresting(SecondThisRegion)) {
  602. BR.markInteresting(SecondThisRegion);
  603. BR.markNotInteresting(FirstThisRegion);
  604. }
  605. if (BR.isInteresting(SecondThisRegion) &&
  606. !BR.isInteresting(FirstThisRegion)) {
  607. BR.markInteresting(FirstThisRegion);
  608. BR.markNotInteresting(SecondThisRegion);
  609. }
  610. // TODO: We need to emit some note here probably!!
  611. }));
  612. return true;
  613. }
  614. void SmartPtrModeling::handleGet(const CallEvent &Call,
  615. CheckerContext &C) const {
  616. ProgramStateRef State = C.getState();
  617. const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
  618. if (!IC)
  619. return;
  620. const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
  621. if (!ThisRegion)
  622. return;
  623. SVal InnerPointerVal;
  624. std::tie(InnerPointerVal, State) = retrieveOrConjureInnerPtrVal(
  625. State, ThisRegion, Call.getOriginExpr(), Call.getResultType(), C);
  626. State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
  627. InnerPointerVal);
  628. // TODO: Add NoteTag, for how the raw pointer got using 'get' method.
  629. C.addTransition(State);
  630. }
  631. bool SmartPtrModeling::handleAssignOp(const CallEvent &Call,
  632. CheckerContext &C) const {
  633. ProgramStateRef State = C.getState();
  634. const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
  635. if (!OC)
  636. return false;
  637. OverloadedOperatorKind OOK = OC->getOverloadedOperator();
  638. if (OOK != OO_Equal)
  639. return false;
  640. const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
  641. if (!ThisRegion)
  642. return false;
  643. const MemRegion *OtherSmartPtrRegion = OC->getArgSVal(0).getAsRegion();
  644. // In case of 'nullptr' or '0' assigned
  645. if (!OtherSmartPtrRegion) {
  646. bool AssignedNull = Call.getArgSVal(0).isZeroConstant();
  647. if (!AssignedNull)
  648. return false;
  649. auto NullVal = C.getSValBuilder().makeNull();
  650. State = State->set<TrackedRegionMap>(ThisRegion, NullVal);
  651. C.addTransition(State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR,
  652. llvm::raw_ostream &OS) {
  653. if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
  654. !BR.isInteresting(ThisRegion))
  655. return;
  656. OS << "Smart pointer";
  657. checkAndPrettyPrintRegion(OS, ThisRegion);
  658. OS << " is assigned to null";
  659. }));
  660. return true;
  661. }
  662. return updateMovedSmartPointers(C, ThisRegion, OtherSmartPtrRegion);
  663. }
  664. bool SmartPtrModeling::handleMoveCtr(const CallEvent &Call, CheckerContext &C,
  665. const MemRegion *ThisRegion) const {
  666. const auto *OtherSmartPtrRegion = Call.getArgSVal(0).getAsRegion();
  667. if (!OtherSmartPtrRegion)
  668. return false;
  669. return updateMovedSmartPointers(C, ThisRegion, OtherSmartPtrRegion);
  670. }
  671. bool SmartPtrModeling::updateMovedSmartPointers(
  672. CheckerContext &C, const MemRegion *ThisRegion,
  673. const MemRegion *OtherSmartPtrRegion) const {
  674. ProgramStateRef State = C.getState();
  675. const auto *OtherInnerPtr = State->get<TrackedRegionMap>(OtherSmartPtrRegion);
  676. if (OtherInnerPtr) {
  677. State = State->set<TrackedRegionMap>(ThisRegion, *OtherInnerPtr);
  678. auto NullVal = C.getSValBuilder().makeNull();
  679. State = State->set<TrackedRegionMap>(OtherSmartPtrRegion, NullVal);
  680. bool IsArgValNull = OtherInnerPtr->isZeroConstant();
  681. C.addTransition(
  682. State,
  683. C.getNoteTag([ThisRegion, OtherSmartPtrRegion, IsArgValNull](
  684. PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
  685. if (&BR.getBugType() != smartptr::getNullDereferenceBugType())
  686. return;
  687. if (BR.isInteresting(OtherSmartPtrRegion)) {
  688. OS << "Smart pointer";
  689. checkAndPrettyPrintRegion(OS, OtherSmartPtrRegion);
  690. OS << " is null after being moved to";
  691. checkAndPrettyPrintRegion(OS, ThisRegion);
  692. }
  693. if (BR.isInteresting(ThisRegion) && IsArgValNull) {
  694. OS << "A null pointer value is moved to";
  695. checkAndPrettyPrintRegion(OS, ThisRegion);
  696. BR.markInteresting(OtherSmartPtrRegion);
  697. }
  698. }));
  699. return true;
  700. } else {
  701. // In case we dont know anything about value we are moving from
  702. // remove the entry from map for which smart pointer got moved to.
  703. auto NullVal = C.getSValBuilder().makeNull();
  704. State = State->remove<TrackedRegionMap>(ThisRegion);
  705. State = State->set<TrackedRegionMap>(OtherSmartPtrRegion, NullVal);
  706. C.addTransition(State, C.getNoteTag([OtherSmartPtrRegion,
  707. ThisRegion](PathSensitiveBugReport &BR,
  708. llvm::raw_ostream &OS) {
  709. if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
  710. !BR.isInteresting(OtherSmartPtrRegion))
  711. return;
  712. OS << "Smart pointer";
  713. checkAndPrettyPrintRegion(OS, OtherSmartPtrRegion);
  714. OS << " is null after; previous value moved to";
  715. checkAndPrettyPrintRegion(OS, ThisRegion);
  716. }));
  717. return true;
  718. }
  719. return false;
  720. }
  721. void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
  722. CheckerContext &C) const {
  723. // To model unique_ptr::operator bool
  724. ProgramStateRef State = C.getState();
  725. const Expr *CallExpr = Call.getOriginExpr();
  726. const MemRegion *ThisRegion =
  727. cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
  728. SVal InnerPointerVal;
  729. if (const auto *InnerValPtr = State->get<TrackedRegionMap>(ThisRegion)) {
  730. InnerPointerVal = *InnerValPtr;
  731. } else {
  732. // In case of inner pointer SVal is not available we create
  733. // conjureSymbolVal for inner pointer value.
  734. auto InnerPointerType = getInnerPointerType(Call, C);
  735. if (InnerPointerType.isNull())
  736. return;
  737. const LocationContext *LC = C.getLocationContext();
  738. InnerPointerVal = C.getSValBuilder().conjureSymbolVal(
  739. CallExpr, LC, InnerPointerType, C.blockCount());
  740. State = State->set<TrackedRegionMap>(ThisRegion, InnerPointerVal);
  741. }
  742. if (State->isNull(InnerPointerVal).isConstrainedTrue()) {
  743. State = State->BindExpr(CallExpr, C.getLocationContext(),
  744. C.getSValBuilder().makeTruthVal(false));
  745. C.addTransition(State);
  746. return;
  747. } else if (State->isNonNull(InnerPointerVal).isConstrainedTrue()) {
  748. State = State->BindExpr(CallExpr, C.getLocationContext(),
  749. C.getSValBuilder().makeTruthVal(true));
  750. C.addTransition(State);
  751. return;
  752. } else if (move::isMovedFrom(State, ThisRegion)) {
  753. C.addTransition(
  754. State->BindExpr(CallExpr, C.getLocationContext(),
  755. C.getSValBuilder().makeZeroVal(Call.getResultType())));
  756. return;
  757. } else {
  758. ProgramStateRef NotNullState, NullState;
  759. std::tie(NotNullState, NullState) =
  760. State->assume(InnerPointerVal.castAs<DefinedOrUnknownSVal>());
  761. auto NullVal = C.getSValBuilder().makeNull();
  762. // Explicitly tracking the region as null.
  763. NullState = NullState->set<TrackedRegionMap>(ThisRegion, NullVal);
  764. NullState = NullState->BindExpr(CallExpr, C.getLocationContext(),
  765. C.getSValBuilder().makeTruthVal(false));
  766. C.addTransition(NullState, C.getNoteTag(
  767. [ThisRegion](PathSensitiveBugReport &BR,
  768. llvm::raw_ostream &OS) {
  769. OS << "Assuming smart pointer";
  770. checkAndPrettyPrintRegion(OS, ThisRegion);
  771. OS << " is null";
  772. },
  773. /*IsPrunable=*/true));
  774. NotNullState =
  775. NotNullState->BindExpr(CallExpr, C.getLocationContext(),
  776. C.getSValBuilder().makeTruthVal(true));
  777. C.addTransition(
  778. NotNullState,
  779. C.getNoteTag(
  780. [ThisRegion](PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
  781. OS << "Assuming smart pointer";
  782. checkAndPrettyPrintRegion(OS, ThisRegion);
  783. OS << " is non-null";
  784. },
  785. /*IsPrunable=*/true));
  786. return;
  787. }
  788. }
  789. void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
  790. auto *Checker = Mgr.registerChecker<SmartPtrModeling>();
  791. Checker->ModelSmartPtrDereference =
  792. Mgr.getAnalyzerOptions().getCheckerBooleanOption(
  793. Checker, "ModelSmartPtrDereference");
  794. }
  795. bool ento::shouldRegisterSmartPtrModeling(const CheckerManager &mgr) {
  796. const LangOptions &LO = mgr.getLangOpts();
  797. return LO.CPlusPlus;
  798. }