UninitializedObjectChecker.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. //===----- UninitializedObjectChecker.cpp ------------------------*- C++ -*-==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file defines a checker that reports uninitialized fields in objects
  11. // created after a constructor call.
  12. //
  13. // To read about command line options and how the checker works, refer to the
  14. // top of the file and inline comments in UninitializedObject.h.
  15. //
  16. // Some of the logic is implemented in UninitializedPointee.cpp, to reduce the
  17. // complexity of this file.
  18. //
  19. //===----------------------------------------------------------------------===//
  20. #include "../ClangSACheckers.h"
  21. #include "UninitializedObject.h"
  22. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  23. #include "clang/StaticAnalyzer/Core/Checker.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  25. #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
  26. using namespace clang;
  27. using namespace clang::ento;
  28. /// We'll mark fields (and pointee of fields) that are confirmed to be
  29. /// uninitialized as already analyzed.
  30. REGISTER_SET_WITH_PROGRAMSTATE(AnalyzedRegions, const MemRegion *)
  31. namespace {
  32. class UninitializedObjectChecker
  33. : public Checker<check::EndFunction, check::DeadSymbols> {
  34. std::unique_ptr<BuiltinBug> BT_uninitField;
  35. public:
  36. // The fields of this struct will be initialized when registering the checker.
  37. UninitObjCheckerOptions Opts;
  38. UninitializedObjectChecker()
  39. : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
  40. void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
  41. void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
  42. };
  43. /// A basic field type, that is not a pointer or a reference, it's dynamic and
  44. /// static type is the same.
  45. class RegularField final : public FieldNode {
  46. public:
  47. RegularField(const FieldRegion *FR) : FieldNode(FR) {}
  48. virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
  49. Out << "uninitialized field ";
  50. }
  51. virtual void printPrefix(llvm::raw_ostream &Out) const override {}
  52. virtual void printNode(llvm::raw_ostream &Out) const override {
  53. Out << getVariableName(getDecl());
  54. }
  55. virtual void printSeparator(llvm::raw_ostream &Out) const override {
  56. Out << '.';
  57. }
  58. };
  59. /// Represents that the FieldNode that comes after this is declared in a base
  60. /// of the previous FieldNode. As such, this descendant doesn't wrap a
  61. /// FieldRegion, and is purely a tool to describe a relation between two other
  62. /// FieldRegion wrapping descendants.
  63. class BaseClass final : public FieldNode {
  64. const QualType BaseClassT;
  65. public:
  66. BaseClass(const QualType &T) : FieldNode(nullptr), BaseClassT(T) {
  67. assert(!T.isNull());
  68. assert(T->getAsCXXRecordDecl());
  69. }
  70. virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
  71. llvm_unreachable("This node can never be the final node in the "
  72. "fieldchain!");
  73. }
  74. virtual void printPrefix(llvm::raw_ostream &Out) const override {}
  75. virtual void printNode(llvm::raw_ostream &Out) const override {
  76. Out << BaseClassT->getAsCXXRecordDecl()->getName() << "::";
  77. }
  78. virtual void printSeparator(llvm::raw_ostream &Out) const override {}
  79. virtual bool isBase() const override { return true; }
  80. };
  81. } // end of anonymous namespace
  82. // Utility function declarations.
  83. /// Returns the region that was constructed by CtorDecl, or nullptr if that
  84. /// isn't possible.
  85. static const TypedValueRegion *
  86. getConstructedRegion(const CXXConstructorDecl *CtorDecl,
  87. CheckerContext &Context);
  88. /// Checks whether the object constructed by \p Ctor will be analyzed later
  89. /// (e.g. if the object is a field of another object, in which case we'd check
  90. /// it multiple times).
  91. static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
  92. CheckerContext &Context);
  93. /// Checks whether RD contains a field with a name or type name that matches
  94. /// \p Pattern.
  95. static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern);
  96. //===----------------------------------------------------------------------===//
  97. // Methods for UninitializedObjectChecker.
  98. //===----------------------------------------------------------------------===//
  99. void UninitializedObjectChecker::checkEndFunction(
  100. const ReturnStmt *RS, CheckerContext &Context) const {
  101. const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
  102. Context.getLocationContext()->getDecl());
  103. if (!CtorDecl)
  104. return;
  105. if (!CtorDecl->isUserProvided())
  106. return;
  107. if (CtorDecl->getParent()->isUnion())
  108. return;
  109. // This avoids essentially the same error being reported multiple times.
  110. if (willObjectBeAnalyzedLater(CtorDecl, Context))
  111. return;
  112. const TypedValueRegion *R = getConstructedRegion(CtorDecl, Context);
  113. if (!R)
  114. return;
  115. FindUninitializedFields F(Context.getState(), R, Opts);
  116. std::pair<ProgramStateRef, const UninitFieldMap &> UninitInfo =
  117. F.getResults();
  118. ProgramStateRef UpdatedState = UninitInfo.first;
  119. const UninitFieldMap &UninitFields = UninitInfo.second;
  120. if (UninitFields.empty()) {
  121. Context.addTransition(UpdatedState);
  122. return;
  123. }
  124. // There are uninitialized fields in the record.
  125. ExplodedNode *Node = Context.generateNonFatalErrorNode(UpdatedState);
  126. if (!Node)
  127. return;
  128. PathDiagnosticLocation LocUsedForUniqueing;
  129. const Stmt *CallSite = Context.getStackFrame()->getCallSite();
  130. if (CallSite)
  131. LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
  132. CallSite, Context.getSourceManager(), Node->getLocationContext());
  133. // For Plist consumers that don't support notes just yet, we'll convert notes
  134. // to warnings.
  135. if (Opts.ShouldConvertNotesToWarnings) {
  136. for (const auto &Pair : UninitFields) {
  137. auto Report = llvm::make_unique<BugReport>(
  138. *BT_uninitField, Pair.second, Node, LocUsedForUniqueing,
  139. Node->getLocationContext()->getDecl());
  140. Context.emitReport(std::move(Report));
  141. }
  142. return;
  143. }
  144. SmallString<100> WarningBuf;
  145. llvm::raw_svector_ostream WarningOS(WarningBuf);
  146. WarningOS << UninitFields.size() << " uninitialized field"
  147. << (UninitFields.size() == 1 ? "" : "s")
  148. << " at the end of the constructor call";
  149. auto Report = llvm::make_unique<BugReport>(
  150. *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
  151. Node->getLocationContext()->getDecl());
  152. for (const auto &Pair : UninitFields) {
  153. Report->addNote(Pair.second,
  154. PathDiagnosticLocation::create(Pair.first->getDecl(),
  155. Context.getSourceManager()));
  156. }
  157. Context.emitReport(std::move(Report));
  158. }
  159. void UninitializedObjectChecker::checkDeadSymbols(SymbolReaper &SR,
  160. CheckerContext &C) const {
  161. ProgramStateRef State = C.getState();
  162. for (const MemRegion *R : State->get<AnalyzedRegions>()) {
  163. if (!SR.isLiveRegion(R))
  164. State = State->remove<AnalyzedRegions>(R);
  165. }
  166. }
  167. //===----------------------------------------------------------------------===//
  168. // Methods for FindUninitializedFields.
  169. //===----------------------------------------------------------------------===//
  170. FindUninitializedFields::FindUninitializedFields(
  171. ProgramStateRef State, const TypedValueRegion *const R,
  172. const UninitObjCheckerOptions &Opts)
  173. : State(State), ObjectR(R), Opts(Opts) {
  174. isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory));
  175. // In non-pedantic mode, if ObjectR doesn't contain a single initialized
  176. // field, we'll assume that Object was intentionally left uninitialized.
  177. if (!Opts.IsPedantic && !isAnyFieldInitialized())
  178. UninitFields.clear();
  179. }
  180. bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain,
  181. const MemRegion *PointeeR) {
  182. const FieldRegion *FR = Chain.getUninitRegion();
  183. assert((PointeeR || !isDereferencableType(FR->getDecl()->getType())) &&
  184. "One must also pass the pointee region as a parameter for "
  185. "dereferencable fields!");
  186. if (State->contains<AnalyzedRegions>(FR))
  187. return false;
  188. if (PointeeR) {
  189. if (State->contains<AnalyzedRegions>(PointeeR)) {
  190. return false;
  191. }
  192. State = State->add<AnalyzedRegions>(PointeeR);
  193. }
  194. State = State->add<AnalyzedRegions>(FR);
  195. if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
  196. FR->getDecl()->getLocation()))
  197. return false;
  198. UninitFieldMap::mapped_type NoteMsgBuf;
  199. llvm::raw_svector_ostream OS(NoteMsgBuf);
  200. Chain.printNoteMsg(OS);
  201. return UninitFields.insert({FR, std::move(NoteMsgBuf)}).second;
  202. }
  203. bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
  204. FieldChainInfo LocalChain) {
  205. assert(R->getValueType()->isRecordType() &&
  206. !R->getValueType()->isUnionType() &&
  207. "This method only checks non-union record objects!");
  208. const RecordDecl *RD = R->getValueType()->getAsRecordDecl()->getDefinition();
  209. if (!RD) {
  210. IsAnyFieldInitialized = true;
  211. return true;
  212. }
  213. if (!Opts.IgnoredRecordsWithFieldPattern.empty() &&
  214. shouldIgnoreRecord(RD, Opts.IgnoredRecordsWithFieldPattern)) {
  215. IsAnyFieldInitialized = true;
  216. return false;
  217. }
  218. bool ContainsUninitField = false;
  219. // Are all of this non-union's fields initialized?
  220. for (const FieldDecl *I : RD->fields()) {
  221. const auto FieldVal =
  222. State->getLValue(I, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
  223. const auto *FR = FieldVal.getRegionAs<FieldRegion>();
  224. QualType T = I->getType();
  225. // If LocalChain already contains FR, then we encountered a cyclic
  226. // reference. In this case, region FR is already under checking at an
  227. // earlier node in the directed tree.
  228. if (LocalChain.contains(FR))
  229. return false;
  230. if (T->isStructureOrClassType()) {
  231. if (isNonUnionUninit(FR, LocalChain.add(RegularField(FR))))
  232. ContainsUninitField = true;
  233. continue;
  234. }
  235. if (T->isUnionType()) {
  236. if (isUnionUninit(FR)) {
  237. if (addFieldToUninits(LocalChain.add(RegularField(FR))))
  238. ContainsUninitField = true;
  239. } else
  240. IsAnyFieldInitialized = true;
  241. continue;
  242. }
  243. if (T->isArrayType()) {
  244. IsAnyFieldInitialized = true;
  245. continue;
  246. }
  247. SVal V = State->getSVal(FieldVal);
  248. if (isDereferencableType(T) || V.getAs<nonloc::LocAsInteger>()) {
  249. if (isDereferencableUninit(FR, LocalChain))
  250. ContainsUninitField = true;
  251. continue;
  252. }
  253. if (isPrimitiveType(T)) {
  254. if (isPrimitiveUninit(V)) {
  255. if (addFieldToUninits(LocalChain.add(RegularField(FR))))
  256. ContainsUninitField = true;
  257. }
  258. continue;
  259. }
  260. llvm_unreachable("All cases are handled!");
  261. }
  262. // Checking bases. The checker will regard inherited data members as direct
  263. // fields.
  264. const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
  265. if (!CXXRD)
  266. return ContainsUninitField;
  267. for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {
  268. const auto *BaseRegion = State->getLValue(BaseSpec, R)
  269. .castAs<loc::MemRegionVal>()
  270. .getRegionAs<TypedValueRegion>();
  271. // If the head of the list is also a BaseClass, we'll overwrite it to avoid
  272. // note messages like 'this->A::B::x'.
  273. if (!LocalChain.isEmpty() && LocalChain.getHead().isBase()) {
  274. if (isNonUnionUninit(BaseRegion, LocalChain.replaceHead(
  275. BaseClass(BaseSpec.getType()))))
  276. ContainsUninitField = true;
  277. } else {
  278. if (isNonUnionUninit(BaseRegion,
  279. LocalChain.add(BaseClass(BaseSpec.getType()))))
  280. ContainsUninitField = true;
  281. }
  282. }
  283. return ContainsUninitField;
  284. }
  285. bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
  286. assert(R->getValueType()->isUnionType() &&
  287. "This method only checks union objects!");
  288. // TODO: Implement support for union fields.
  289. return false;
  290. }
  291. bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
  292. if (V.isUndef())
  293. return true;
  294. IsAnyFieldInitialized = true;
  295. return false;
  296. }
  297. //===----------------------------------------------------------------------===//
  298. // Methods for FieldChainInfo.
  299. //===----------------------------------------------------------------------===//
  300. bool FieldChainInfo::contains(const FieldRegion *FR) const {
  301. for (const FieldNode &Node : Chain) {
  302. if (Node.isSameRegion(FR))
  303. return true;
  304. }
  305. return false;
  306. }
  307. /// Prints every element except the last to `Out`. Since ImmutableLists store
  308. /// elements in reverse order, and have no reverse iterators, we use a
  309. /// recursive function to print the fieldchain correctly. The last element in
  310. /// the chain is to be printed by `FieldChainInfo::print`.
  311. static void printTail(llvm::raw_ostream &Out,
  312. const FieldChainInfo::FieldChain L);
  313. // FIXME: This function constructs an incorrect string in the following case:
  314. //
  315. // struct Base { int x; };
  316. // struct D1 : Base {}; struct D2 : Base {};
  317. //
  318. // struct MostDerived : D1, D2 {
  319. // MostDerived() {}
  320. // }
  321. //
  322. // A call to MostDerived::MostDerived() will cause two notes that say
  323. // "uninitialized field 'this->x'", but we can't refer to 'x' directly,
  324. // we need an explicit namespace resolution whether the uninit field was
  325. // 'D1::x' or 'D2::x'.
  326. void FieldChainInfo::printNoteMsg(llvm::raw_ostream &Out) const {
  327. if (Chain.isEmpty())
  328. return;
  329. const FieldNode &LastField = getHead();
  330. LastField.printNoteMsg(Out);
  331. Out << '\'';
  332. for (const FieldNode &Node : Chain)
  333. Node.printPrefix(Out);
  334. Out << "this->";
  335. printTail(Out, Chain.getTail());
  336. LastField.printNode(Out);
  337. Out << '\'';
  338. }
  339. static void printTail(llvm::raw_ostream &Out,
  340. const FieldChainInfo::FieldChain L) {
  341. if (L.isEmpty())
  342. return;
  343. printTail(Out, L.getTail());
  344. L.getHead().printNode(Out);
  345. L.getHead().printSeparator(Out);
  346. }
  347. //===----------------------------------------------------------------------===//
  348. // Utility functions.
  349. //===----------------------------------------------------------------------===//
  350. static const TypedValueRegion *
  351. getConstructedRegion(const CXXConstructorDecl *CtorDecl,
  352. CheckerContext &Context) {
  353. Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl,
  354. Context.getStackFrame());
  355. SVal ObjectV = Context.getState()->getSVal(ThisLoc);
  356. auto *R = ObjectV.getAsRegion()->getAs<TypedValueRegion>();
  357. if (R && !R->getValueType()->getAsCXXRecordDecl())
  358. return nullptr;
  359. return R;
  360. }
  361. static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
  362. CheckerContext &Context) {
  363. const TypedValueRegion *CurrRegion = getConstructedRegion(Ctor, Context);
  364. if (!CurrRegion)
  365. return false;
  366. const LocationContext *LC = Context.getLocationContext();
  367. while ((LC = LC->getParent())) {
  368. // If \p Ctor was called by another constructor.
  369. const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(LC->getDecl());
  370. if (!OtherCtor)
  371. continue;
  372. const TypedValueRegion *OtherRegion =
  373. getConstructedRegion(OtherCtor, Context);
  374. if (!OtherRegion)
  375. continue;
  376. // If the CurrRegion is a subregion of OtherRegion, it will be analyzed
  377. // during the analysis of OtherRegion.
  378. if (CurrRegion->isSubRegionOf(OtherRegion))
  379. return true;
  380. }
  381. return false;
  382. }
  383. static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) {
  384. llvm::Regex R(Pattern);
  385. for (const FieldDecl *FD : RD->fields()) {
  386. if (R.match(FD->getType().getAsString()))
  387. return true;
  388. if (R.match(FD->getName()))
  389. return true;
  390. }
  391. return false;
  392. }
  393. std::string clang::ento::getVariableName(const FieldDecl *Field) {
  394. // If Field is a captured lambda variable, Field->getName() will return with
  395. // an empty string. We can however acquire it's name from the lambda's
  396. // captures.
  397. const auto *CXXParent = dyn_cast<CXXRecordDecl>(Field->getParent());
  398. if (CXXParent && CXXParent->isLambda()) {
  399. assert(CXXParent->captures_begin());
  400. auto It = CXXParent->captures_begin() + Field->getFieldIndex();
  401. if (It->capturesVariable())
  402. return llvm::Twine("/*captured variable*/" +
  403. It->getCapturedVar()->getName())
  404. .str();
  405. if (It->capturesThis())
  406. return "/*'this' capture*/";
  407. llvm_unreachable("No other capture type is expected!");
  408. }
  409. return Field->getName();
  410. }
  411. void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
  412. auto Chk = Mgr.registerChecker<UninitializedObjectChecker>();
  413. AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
  414. UninitObjCheckerOptions &ChOpts = Chk->Opts;
  415. ChOpts.IsPedantic =
  416. AnOpts.getCheckerBooleanOption("Pedantic", /*DefaultVal*/ false, Chk);
  417. ChOpts.ShouldConvertNotesToWarnings =
  418. AnOpts.getCheckerBooleanOption("NotesAsWarnings", /*DefaultVal*/ false, Chk);
  419. ChOpts.CheckPointeeInitialization = AnOpts.getCheckerBooleanOption(
  420. "CheckPointeeInitialization", /*DefaultVal*/ false, Chk);
  421. ChOpts.IgnoredRecordsWithFieldPattern =
  422. AnOpts.getCheckerStringOption("IgnoreRecordsWithField",
  423. /*DefaultVal*/ "", Chk);
  424. }