123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- //===----- UninitializedPointee.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 functions and methods for handling pointers and references
- // to reduce the size and complexity of UninitializedObjectChecker.cpp.
- //
- // To read about command line options and documentation about how the checker
- // works, refer to UninitializedObjectChecker.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/DynamicType.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 nonloc::LocAsInteger or void* field, that point to objects, but
- /// 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 {
- // If this object is a nonloc::LocAsInteger.
- if (getDecl()->getType()->isIntegerType())
- Out << "reinterpret_cast";
- // If this pointer's dynamic type is different then it's static type.
- else
- Out << "static_cast";
- Out << '<' << CastBackType.getAsString() << ">(";
- }
- virtual void printNode(llvm::raw_ostream &Out) const override {
- Out << getVariableName(getDecl()) << ')';
- }
- virtual void printSeparator(llvm::raw_ostream &Out) const override {
- Out << "->";
- }
- };
- /// Represents a Loc field that points to itself.
- class CyclicLocField final : public FieldNode {
- public:
- CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
- virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
- Out << "object references itself ";
- }
- 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 {
- llvm_unreachable("CyclicLocField objects must be the last node of the "
- "fieldchain!");
- }
- };
- } // end of anonymous namespace
- // Utility function declarations.
- struct DereferenceInfo {
- const TypedValueRegion *R;
- const bool NeedsCastBack;
- const bool IsCyclic;
- DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
- : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
- };
- /// Dereferences \p FR and returns with the pointee's region, and whether it
- /// needs to be casted back to it's location type. If for whatever reason
- /// dereferencing fails, returns with None.
- static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
- const FieldRegion *FR);
- /// Returns whether \p T can be (transitively) dereferenced to a void pointer
- /// type (void*, void**, ...).
- static bool isVoidPointer(QualType T);
- //===----------------------------------------------------------------------===//
- // Methods for FindUninitializedFields.
- //===----------------------------------------------------------------------===//
- bool FindUninitializedFields::isDereferencableUninit(
- const FieldRegion *FR, FieldChainInfo LocalChain) {
- SVal V = State->getSVal(FR);
- assert((isDereferencableType(FR->getDecl()->getType()) ||
- V.getAs<nonloc::LocAsInteger>()) &&
- "This method only checks dereferenceable objects!");
- if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
- IsAnyFieldInitialized = true;
- return false;
- }
- if (V.isUndef()) {
- return addFieldToUninits(
- LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
- }
- if (!Opts.CheckPointeeInitialization) {
- IsAnyFieldInitialized = true;
- return false;
- }
- // At this point the pointer itself is initialized and points to a valid
- // location, we'll now check the pointee.
- llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
- if (!DerefInfo) {
- IsAnyFieldInitialized = true;
- return false;
- }
- if (DerefInfo->IsCyclic)
- return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
- const TypedValueRegion *R = DerefInfo->R;
- const bool NeedsCastBack = DerefInfo->NeedsCastBack;
- QualType DynT = R->getLocationType();
- QualType PointeeT = DynT->getPointeeType();
- if (PointeeT->isStructureOrClassType()) {
- if (NeedsCastBack)
- return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
- return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
- }
- if (PointeeT->isUnionType()) {
- if (isUnionUninit(R)) {
- if (NeedsCastBack)
- return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
- R);
- return addFieldToUninits(LocalChain.add(LocField(FR)), R);
- } else {
- IsAnyFieldInitialized = true;
- return false;
- }
- }
- if (PointeeT->isArrayType()) {
- IsAnyFieldInitialized = true;
- return false;
- }
- assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
- "At this point FR must either have a primitive dynamic type, or it "
- "must be a null, undefined, unknown or concrete pointer!");
- SVal PointeeV = State->getSVal(R);
- if (isPrimitiveUninit(PointeeV)) {
- if (NeedsCastBack)
- return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
- return addFieldToUninits(LocalChain.add(LocField(FR)), R);
- }
- IsAnyFieldInitialized = true;
- return false;
- }
- //===----------------------------------------------------------------------===//
- // Utility functions.
- //===----------------------------------------------------------------------===//
- static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
- const FieldRegion *FR) {
- llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
- SVal V = State->getSVal(FR);
- assert(V.getAsRegion() && "V must have an underlying region!");
- // If the static type of the field is a void pointer, or it is a
- // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
- // dereferencing.
- bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
- V.getAs<nonloc::LocAsInteger>();
- // The region we'd like to acquire.
- const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
- if (!R)
- return None;
- VisitedRegions.insert(R);
- // We acquire the dynamic type of R,
- QualType DynT = R->getLocationType();
- while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
- R = Tmp->getAs<TypedValueRegion>();
- if (!R)
- return None;
- // We found a cyclic pointer, like int *ptr = (int *)&ptr.
- if (!VisitedRegions.insert(R).second)
- return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
- DynT = R->getLocationType();
- // In order to ensure that this loop terminates, we're also checking the
- // dynamic type of R, since type hierarchy is finite.
- if (isDereferencableType(DynT->getPointeeType()))
- break;
- }
- while (isa<CXXBaseObjectRegion>(R)) {
- NeedsCastBack = true;
- const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
- if (!SuperR)
- break;
- R = SuperR;
- }
- return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
- }
- static bool isVoidPointer(QualType T) {
- while (!T.isNull()) {
- if (T->isVoidPointerType())
- return true;
- T = T->getPointeeType();
- }
- return false;
- }
|