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