brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · d090748 Raw
278 lines · cpp
1//===----- UninitializedPointee.cpp ------------------------------*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines functions and methods for handling pointers and references10// to reduce the size and complexity of UninitializedObjectChecker.cpp.11//12// To read about command line options and documentation about how the checker13// works, refer to UninitializedObjectChecker.h.14//15//===----------------------------------------------------------------------===//16 17#include "UninitializedObject.h"18#include <optional>19 20using namespace clang;21using namespace clang::ento;22 23namespace {24 25/// Represents a pointer or a reference field.26class LocField final : public FieldNode {27  /// We'll store whether the pointee or the pointer itself is uninitialited.28  const bool IsDereferenced;29 30public:31  LocField(const FieldRegion *FR, const bool IsDereferenced = true)32      : FieldNode(FR), IsDereferenced(IsDereferenced) {}33 34  void printNoteMsg(llvm::raw_ostream &Out) const override {35    if (IsDereferenced)36      Out << "uninitialized pointee ";37    else38      Out << "uninitialized pointer ";39  }40 41  void printPrefix(llvm::raw_ostream &Out) const override {}42 43  void printNode(llvm::raw_ostream &Out) const override {44    Out << getVariableName(getDecl());45  }46 47  void printSeparator(llvm::raw_ostream &Out) const override {48    if (getDecl()->getType()->isPointerType())49      Out << "->";50    else51      Out << '.';52  }53};54 55/// Represents a nonloc::LocAsInteger or void* field, that point to objects, but56/// needs to be casted back to its dynamic type for a correct note message.57class NeedsCastLocField final : public FieldNode {58  QualType CastBackType;59 60public:61  NeedsCastLocField(const FieldRegion *FR, const QualType &T)62      : FieldNode(FR), CastBackType(T) {}63 64  void printNoteMsg(llvm::raw_ostream &Out) const override {65    Out << "uninitialized pointee ";66  }67 68  void printPrefix(llvm::raw_ostream &Out) const override {69    // If this object is a nonloc::LocAsInteger.70    if (getDecl()->getType()->isIntegerType())71      Out << "reinterpret_cast";72    // If this pointer's dynamic type is different then it's static type.73    else74      Out << "static_cast";75    Out << '<' << CastBackType.getAsString() << ">(";76  }77 78  void printNode(llvm::raw_ostream &Out) const override {79    Out << getVariableName(getDecl()) << ')';80  }81 82  void printSeparator(llvm::raw_ostream &Out) const override { Out << "->"; }83};84 85/// Represents a Loc field that points to itself.86class CyclicLocField final : public FieldNode {87 88public:89  CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}90 91  void printNoteMsg(llvm::raw_ostream &Out) const override {92    Out << "object references itself ";93  }94 95  void printPrefix(llvm::raw_ostream &Out) const override {}96 97  void printNode(llvm::raw_ostream &Out) const override {98    Out << getVariableName(getDecl());99  }100 101  void printSeparator(llvm::raw_ostream &Out) const override {102    llvm_unreachable("CyclicLocField objects must be the last node of the "103                     "fieldchain!");104  }105};106 107} // end of anonymous namespace108 109// Utility function declarations.110 111struct DereferenceInfo {112  const TypedValueRegion *R;113  const bool NeedsCastBack;114  const bool IsCyclic;115  DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)116      : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}117};118 119/// Dereferences \p FR and returns with the pointee's region, and whether it120/// needs to be casted back to it's location type. If for whatever reason121/// dereferencing fails, returns std::nullopt.122static std::optional<DereferenceInfo> dereference(ProgramStateRef State,123                                                  const FieldRegion *FR);124 125/// Returns whether \p T can be (transitively) dereferenced to a void pointer126/// type (void*, void**, ...).127static bool isVoidPointer(QualType T);128 129//===----------------------------------------------------------------------===//130//                   Methods for FindUninitializedFields.131//===----------------------------------------------------------------------===//132 133bool FindUninitializedFields::isDereferencableUninit(134    const FieldRegion *FR, FieldChainInfo LocalChain) {135 136  SVal V = State->getSVal(FR);137 138  assert((isDereferencableType(FR->getDecl()->getType()) ||139          isa<nonloc::LocAsInteger>(V)) &&140         "This method only checks dereferenceable objects!");141 142  if (V.isUnknown() || isa<loc::ConcreteInt>(V)) {143    IsAnyFieldInitialized = true;144    return false;145  }146 147  if (V.isUndef()) {148    return addFieldToUninits(149        LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);150  }151 152  if (!Opts.CheckPointeeInitialization) {153    IsAnyFieldInitialized = true;154    return false;155  }156 157  // At this point the pointer itself is initialized and points to a valid158  // location, we'll now check the pointee.159  std::optional<DereferenceInfo> DerefInfo = dereference(State, FR);160  if (!DerefInfo) {161    IsAnyFieldInitialized = true;162    return false;163  }164 165  if (DerefInfo->IsCyclic)166    return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);167 168  const TypedValueRegion *R = DerefInfo->R;169  const bool NeedsCastBack = DerefInfo->NeedsCastBack;170 171  QualType DynT = R->getLocationType();172  QualType PointeeT = DynT->getPointeeType();173 174  if (PointeeT->isStructureOrClassType()) {175    if (NeedsCastBack)176      return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));177    return isNonUnionUninit(R, LocalChain.add(LocField(FR)));178  }179 180  if (PointeeT->isUnionType()) {181    if (isUnionUninit(R)) {182      if (NeedsCastBack)183        return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),184                                 R);185      return addFieldToUninits(LocalChain.add(LocField(FR)), R);186    } else {187      IsAnyFieldInitialized = true;188      return false;189    }190  }191 192  if (PointeeT->isArrayType()) {193    IsAnyFieldInitialized = true;194    return false;195  }196 197  assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&198         "At this point FR must either have a primitive dynamic type, or it "199         "must be a null, undefined, unknown or concrete pointer!");200 201  SVal PointeeV = State->getSVal(R);202 203  if (isPrimitiveUninit(PointeeV)) {204    if (NeedsCastBack)205      return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);206    return addFieldToUninits(LocalChain.add(LocField(FR)), R);207  }208 209  IsAnyFieldInitialized = true;210  return false;211}212 213//===----------------------------------------------------------------------===//214//                           Utility functions.215//===----------------------------------------------------------------------===//216 217static std::optional<DereferenceInfo> dereference(ProgramStateRef State,218                                                  const FieldRegion *FR) {219 220  llvm::SmallPtrSet<const TypedValueRegion *, 5> VisitedRegions;221 222  SVal V = State->getSVal(FR);223  assert(V.getAsRegion() && "V must have an underlying region!");224 225  // If the static type of the field is a void pointer, or it is a226  // nonloc::LocAsInteger, we need to cast it back to the dynamic type before227  // dereferencing.228  bool NeedsCastBack =229      isVoidPointer(FR->getDecl()->getType()) || isa<nonloc::LocAsInteger>(V);230 231  // The region we'd like to acquire.232  const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();233  if (!R)234    return std::nullopt;235 236  VisitedRegions.insert(R);237 238  // We acquire the dynamic type of R,239  QualType DynT = R->getLocationType();240 241  while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {242 243    R = Tmp->getAs<TypedValueRegion>();244    if (!R)245      return std::nullopt;246 247    // We found a cyclic pointer, like int *ptr = (int *)&ptr.248    if (!VisitedRegions.insert(R).second)249      return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};250 251    DynT = R->getLocationType();252    // In order to ensure that this loop terminates, we're also checking the253    // dynamic type of R, since type hierarchy is finite.254    if (isDereferencableType(DynT->getPointeeType()))255      break;256  }257 258  while (isa<CXXBaseObjectRegion>(R)) {259    NeedsCastBack = true;260    const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());261    if (!SuperR)262      break;263 264    R = SuperR;265  }266 267  return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};268}269 270static bool isVoidPointer(QualType T) {271  while (!T.isNull()) {272    if (T->isVoidPointerType())273      return true;274    T = T->getPointeeType();275  }276  return false;277}278