//===----- UninitializedObjectChecker.cpp ------------------------*- C++ -*-==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines a checker that reports uninitialized fields in objects // created after a constructor call. // // To read about command line options and how the checker works, refer to the // top of the file and inline comments in UninitializedObject.h. // // Some of the logic is implemented in UninitializedPointee.cpp, to reduce the // complexity of this file. // //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "UninitializedObject.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" usingnamespaceclang; usingnamespaceclang::ento; usingnamespaceclang::ast_matchers; /// We'll mark fields (and pointee of fields) that are confirmed to be /// uninitialized as already analyzed. REGISTER_SET_WITH_PROGRAMSTATE(…) … namespace { class UninitializedObjectChecker : public Checker<check::EndFunction, check::DeadSymbols> { … }; /// A basic field type, that is not a pointer or a reference, it's dynamic and /// static type is the same. class RegularField final : public FieldNode { … }; /// Represents that the FieldNode that comes after this is declared in a base /// of the previous FieldNode. As such, this descendant doesn't wrap a /// FieldRegion, and is purely a tool to describe a relation between two other /// FieldRegion wrapping descendants. class BaseClass final : public FieldNode { … }; } // end of anonymous namespace // Utility function declarations. /// Returns the region that was constructed by CtorDecl, or nullptr if that /// isn't possible. static const TypedValueRegion * getConstructedRegion(const CXXConstructorDecl *CtorDecl, CheckerContext &Context); /// Checks whether the object constructed by \p Ctor will be analyzed later /// (e.g. if the object is a field of another object, in which case we'd check /// it multiple times). static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor, CheckerContext &Context); /// Checks whether RD contains a field with a name or type name that matches /// \p Pattern. static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern); /// Checks _syntactically_ whether it is possible to access FD from the record /// that contains it without a preceding assert (even if that access happens /// inside a method). This is mainly used for records that act like unions, like /// having multiple bit fields, with only a fraction being properly initialized. /// If these fields are properly guarded with asserts, this method returns /// false. /// /// Since this check is done syntactically, this method could be inaccurate. static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State); //===----------------------------------------------------------------------===// // Methods for UninitializedObjectChecker. //===----------------------------------------------------------------------===// void UninitializedObjectChecker::checkEndFunction( const ReturnStmt *RS, CheckerContext &Context) const { … } void UninitializedObjectChecker::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { … } //===----------------------------------------------------------------------===// // Methods for FindUninitializedFields. //===----------------------------------------------------------------------===// FindUninitializedFields::FindUninitializedFields( ProgramStateRef State, const TypedValueRegion *const R, const UninitObjCheckerOptions &Opts) : … { … } bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain, const MemRegion *PointeeR) { … } bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R, FieldChainInfo LocalChain) { … } bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) { … } bool FindUninitializedFields::isPrimitiveUninit(SVal V) { … } //===----------------------------------------------------------------------===// // Methods for FieldChainInfo. //===----------------------------------------------------------------------===// bool FieldChainInfo::contains(const FieldRegion *FR) const { … } /// Prints every element except the last to `Out`. Since ImmutableLists store /// elements in reverse order, and have no reverse iterators, we use a /// recursive function to print the fieldchain correctly. The last element in /// the chain is to be printed by `FieldChainInfo::print`. static void printTail(llvm::raw_ostream &Out, const FieldChainInfo::FieldChain L); // FIXME: This function constructs an incorrect string in the following case: // // struct Base { int x; }; // struct D1 : Base {}; struct D2 : Base {}; // // struct MostDerived : D1, D2 { // MostDerived() {} // } // // A call to MostDerived::MostDerived() will cause two notes that say // "uninitialized field 'this->x'", but we can't refer to 'x' directly, // we need an explicit namespace resolution whether the uninit field was // 'D1::x' or 'D2::x'. void FieldChainInfo::printNoteMsg(llvm::raw_ostream &Out) const { … } static void printTail(llvm::raw_ostream &Out, const FieldChainInfo::FieldChain L) { … } //===----------------------------------------------------------------------===// // Utility functions. //===----------------------------------------------------------------------===// static const TypedValueRegion * getConstructedRegion(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) { … } static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor, CheckerContext &Context) { … } static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) { … } static const Stmt *getMethodBody(const CXXMethodDecl *M) { … } static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State) { … } std::string clang::ento::getVariableName(const FieldDecl *Field) { … } void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) { … } bool ento::shouldRegisterUninitializedObjectChecker(const CheckerManager &mgr) { … }