| //===----- UninitializedPointer.cpp ------------------------------*- C++ -*-==// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines functions and methods for handling pointers and references |
| // to reduce the size and complexity of UninitializedObjectChecker.cpp. |
| // |
| // To read about command line options and a description what this checker does, |
| // refer to UninitializedObjectChecker.cpp. |
| // |
| // To read about how the checker works, refer to the comments in |
| // UninitializedObject.h. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "../ClangSACheckers.h" |
| #include "UninitializedObject.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/DynamicTypeMap.h" |
| |
| using namespace clang; |
| using namespace clang::ento; |
| |
| namespace { |
| |
| /// Represents a pointer or a reference field. |
| class LocField final : public FieldNode { |
| /// We'll store whether the pointee or the pointer itself is uninitialited. |
| const bool IsDereferenced; |
| |
| public: |
| LocField(const FieldRegion *FR, const bool IsDereferenced = true) |
| : FieldNode(FR), IsDereferenced(IsDereferenced) {} |
| |
| virtual void printNoteMsg(llvm::raw_ostream &Out) const override { |
| if (IsDereferenced) |
| Out << "uninitialized pointee "; |
| else |
| Out << "uninitialized pointer "; |
| } |
| |
| virtual void printPrefix(llvm::raw_ostream &Out) const override {} |
| |
| virtual void printNode(llvm::raw_ostream &Out) const override { |
| Out << getVariableName(getDecl()); |
| } |
| |
| virtual void printSeparator(llvm::raw_ostream &Out) const override { |
| if (getDecl()->getType()->isPointerType()) |
| Out << "->"; |
| else |
| Out << '.'; |
| } |
| }; |
| |
| /// Represents a void* field that needs to be casted back to its dynamic type |
| /// for a correct note message. |
| class NeedsCastLocField final : public FieldNode { |
| QualType CastBackType; |
| |
| public: |
| NeedsCastLocField(const FieldRegion *FR, const QualType &T) |
| : FieldNode(FR), CastBackType(T) {} |
| |
| virtual void printNoteMsg(llvm::raw_ostream &Out) const override { |
| Out << "uninitialized pointee "; |
| } |
| |
| virtual void printPrefix(llvm::raw_ostream &Out) const override { |
| Out << "static_cast" << '<' << CastBackType.getAsString() << ">("; |
| } |
| |
| virtual void printNode(llvm::raw_ostream &Out) const override { |
| Out << getVariableName(getDecl()) << ')'; |
| } |
| |
| virtual void printSeparator(llvm::raw_ostream &Out) const override { |
| Out << "->"; |
| } |
| }; |
| |
| } // end of anonymous namespace |
| |
| // Utility function declarations. |
| |
| /// Returns whether T can be (transitively) dereferenced to a void pointer type |
| /// (void*, void**, ...). The type of the region behind a void pointer isn't |
| /// known, and thus FD can not be analyzed. |
| static bool isVoidPointer(QualType T); |
| |
| //===----------------------------------------------------------------------===// |
| // Methods for FindUninitializedFields. |
| //===----------------------------------------------------------------------===// |
| |
| // Note that pointers/references don't contain fields themselves, so in this |
| // function we won't add anything to LocalChain. |
| bool FindUninitializedFields::isPointerOrReferenceUninit( |
| const FieldRegion *FR, FieldChainInfo LocalChain) { |
| |
| assert((FR->getDecl()->getType()->isAnyPointerType() || |
| FR->getDecl()->getType()->isReferenceType() || |
| FR->getDecl()->getType()->isBlockPointerType()) && |
| "This method only checks pointer/reference objects!"); |
| |
| SVal V = State->getSVal(FR); |
| |
| if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| if (V.isUndef()) { |
| return addFieldToUninits( |
| LocalChain.add(LocField(FR, /*IsDereferenced*/ false))); |
| } |
| |
| if (!CheckPointeeInitialization) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| assert(V.getAs<loc::MemRegionVal>() && |
| "At this point V must be loc::MemRegionVal!"); |
| auto L = V.castAs<loc::MemRegionVal>(); |
| |
| // We can't reason about symbolic regions, assume its initialized. |
| // Note that this also avoids a potential infinite recursion, because |
| // constructors for list-like classes are checked without being called, and |
| // the Static Analyzer will construct a symbolic region for Node *next; or |
| // similar code snippets. |
| if (L.getRegion()->getSymbolicBase()) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion()); |
| if (!DynTInfo.isValid()) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| QualType DynT = DynTInfo.getType(); |
| |
| // If the static type of the field is a void pointer, we need to cast it back |
| // to the dynamic type before dereferencing. |
| bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()); |
| |
| if (isVoidPointer(DynT)) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| // At this point the pointer itself is initialized and points to a valid |
| // location, we'll now check the pointee. |
| SVal DerefdV = State->getSVal(V.castAs<Loc>(), DynT); |
| |
| // If DerefdV is still a pointer value, we'll dereference it again (e.g.: |
| // int** -> int*). |
| while (auto Tmp = DerefdV.getAs<loc::MemRegionVal>()) { |
| if (Tmp->getRegion()->getSymbolicBase()) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion()); |
| if (!DynTInfo.isValid()) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| DynT = DynTInfo.getType(); |
| if (isVoidPointer(DynT)) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| DerefdV = State->getSVal(*Tmp, DynT); |
| } |
| |
| // If FR is a pointer pointing to a non-primitive type. |
| if (Optional<nonloc::LazyCompoundVal> RecordV = |
| DerefdV.getAs<nonloc::LazyCompoundVal>()) { |
| |
| const TypedValueRegion *R = RecordV->getRegion(); |
| |
| if (DynT->getPointeeType()->isStructureOrClassType()) { |
| if (NeedsCastBack) |
| return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT))); |
| return isNonUnionUninit(R, LocalChain.add(LocField(FR))); |
| } |
| |
| if (DynT->getPointeeType()->isUnionType()) { |
| if (isUnionUninit(R)) { |
| if (NeedsCastBack) |
| return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT))); |
| return addFieldToUninits(LocalChain.add(LocField(FR))); |
| } else { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| } |
| |
| if (DynT->getPointeeType()->isArrayType()) { |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| llvm_unreachable("All cases are handled!"); |
| } |
| |
| // Temporary variable to avoid warning from -Wunused-function. |
| bool IsPrimitive = isPrimitiveType(DynT->getPointeeType()); |
| assert((IsPrimitive || DynT->isAnyPointerType() || DynT->isReferenceType()) && |
| "At this point FR must either have a primitive dynamic type, or it " |
| "must be a null, undefined, unknown or concrete pointer!"); |
| (void)IsPrimitive; |
| |
| if (isPrimitiveUninit(DerefdV)) { |
| if (NeedsCastBack) |
| return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT))); |
| return addFieldToUninits(LocalChain.add(LocField(FR))); |
| } |
| |
| IsAnyFieldInitialized = true; |
| return false; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Utility functions. |
| //===----------------------------------------------------------------------===// |
| |
| static bool isVoidPointer(QualType T) { |
| while (!T.isNull()) { |
| if (T->isVoidPointerType()) |
| return true; |
| T = T->getPointeeType(); |
| } |
| return false; |
| } |