1343173Sdim//===----- UninitializedPointee.cpp ------------------------------*- C++ -*-==// 2343173Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343173Sdim// 7343173Sdim//===----------------------------------------------------------------------===// 8343173Sdim// 9343173Sdim// This file defines functions and methods for handling pointers and references 10343173Sdim// to reduce the size and complexity of UninitializedObjectChecker.cpp. 11343173Sdim// 12343173Sdim// To read about command line options and documentation about how the checker 13343173Sdim// works, refer to UninitializedObjectChecker.h. 14343173Sdim// 15343173Sdim//===----------------------------------------------------------------------===// 16343173Sdim 17343173Sdim#include "UninitializedObject.h" 18343173Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 19343173Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 20343173Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 21360784Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" 22343173Sdim 23343173Sdimusing namespace clang; 24343173Sdimusing namespace clang::ento; 25343173Sdim 26343173Sdimnamespace { 27343173Sdim 28343173Sdim/// Represents a pointer or a reference field. 29343173Sdimclass LocField final : public FieldNode { 30343173Sdim /// We'll store whether the pointee or the pointer itself is uninitialited. 31343173Sdim const bool IsDereferenced; 32343173Sdim 33343173Sdimpublic: 34343173Sdim LocField(const FieldRegion *FR, const bool IsDereferenced = true) 35343173Sdim : FieldNode(FR), IsDereferenced(IsDereferenced) {} 36343173Sdim 37343173Sdim virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 38343173Sdim if (IsDereferenced) 39343173Sdim Out << "uninitialized pointee "; 40343173Sdim else 41343173Sdim Out << "uninitialized pointer "; 42343173Sdim } 43343173Sdim 44343173Sdim virtual void printPrefix(llvm::raw_ostream &Out) const override {} 45343173Sdim 46343173Sdim virtual void printNode(llvm::raw_ostream &Out) const override { 47343173Sdim Out << getVariableName(getDecl()); 48343173Sdim } 49343173Sdim 50343173Sdim virtual void printSeparator(llvm::raw_ostream &Out) const override { 51343173Sdim if (getDecl()->getType()->isPointerType()) 52343173Sdim Out << "->"; 53343173Sdim else 54343173Sdim Out << '.'; 55343173Sdim } 56343173Sdim}; 57343173Sdim 58343173Sdim/// Represents a nonloc::LocAsInteger or void* field, that point to objects, but 59343173Sdim/// needs to be casted back to its dynamic type for a correct note message. 60343173Sdimclass NeedsCastLocField final : public FieldNode { 61343173Sdim QualType CastBackType; 62343173Sdim 63343173Sdimpublic: 64343173Sdim NeedsCastLocField(const FieldRegion *FR, const QualType &T) 65343173Sdim : FieldNode(FR), CastBackType(T) {} 66343173Sdim 67343173Sdim virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 68343173Sdim Out << "uninitialized pointee "; 69343173Sdim } 70343173Sdim 71343173Sdim virtual void printPrefix(llvm::raw_ostream &Out) const override { 72343173Sdim // If this object is a nonloc::LocAsInteger. 73343173Sdim if (getDecl()->getType()->isIntegerType()) 74343173Sdim Out << "reinterpret_cast"; 75343173Sdim // If this pointer's dynamic type is different then it's static type. 76343173Sdim else 77343173Sdim Out << "static_cast"; 78343173Sdim Out << '<' << CastBackType.getAsString() << ">("; 79343173Sdim } 80343173Sdim 81343173Sdim virtual void printNode(llvm::raw_ostream &Out) const override { 82343173Sdim Out << getVariableName(getDecl()) << ')'; 83343173Sdim } 84343173Sdim 85343173Sdim virtual void printSeparator(llvm::raw_ostream &Out) const override { 86343173Sdim Out << "->"; 87343173Sdim } 88343173Sdim}; 89343173Sdim 90343173Sdim/// Represents a Loc field that points to itself. 91343173Sdimclass CyclicLocField final : public FieldNode { 92343173Sdim 93343173Sdimpublic: 94343173Sdim CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {} 95343173Sdim 96343173Sdim virtual void printNoteMsg(llvm::raw_ostream &Out) const override { 97343173Sdim Out << "object references itself "; 98343173Sdim } 99343173Sdim 100343173Sdim virtual void printPrefix(llvm::raw_ostream &Out) const override {} 101343173Sdim 102343173Sdim virtual void printNode(llvm::raw_ostream &Out) const override { 103343173Sdim Out << getVariableName(getDecl()); 104343173Sdim } 105343173Sdim 106343173Sdim virtual void printSeparator(llvm::raw_ostream &Out) const override { 107343173Sdim llvm_unreachable("CyclicLocField objects must be the last node of the " 108343173Sdim "fieldchain!"); 109343173Sdim } 110343173Sdim}; 111343173Sdim 112343173Sdim} // end of anonymous namespace 113343173Sdim 114343173Sdim// Utility function declarations. 115343173Sdim 116343173Sdimstruct DereferenceInfo { 117343173Sdim const TypedValueRegion *R; 118343173Sdim const bool NeedsCastBack; 119343173Sdim const bool IsCyclic; 120343173Sdim DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC) 121343173Sdim : R(R), NeedsCastBack(NCB), IsCyclic(IC) {} 122343173Sdim}; 123343173Sdim 124343173Sdim/// Dereferences \p FR and returns with the pointee's region, and whether it 125343173Sdim/// needs to be casted back to it's location type. If for whatever reason 126343173Sdim/// dereferencing fails, returns with None. 127343173Sdimstatic llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 128343173Sdim const FieldRegion *FR); 129343173Sdim 130343173Sdim/// Returns whether \p T can be (transitively) dereferenced to a void pointer 131343173Sdim/// type (void*, void**, ...). 132343173Sdimstatic bool isVoidPointer(QualType T); 133343173Sdim 134343173Sdim//===----------------------------------------------------------------------===// 135343173Sdim// Methods for FindUninitializedFields. 136343173Sdim//===----------------------------------------------------------------------===// 137343173Sdim 138343173Sdimbool FindUninitializedFields::isDereferencableUninit( 139343173Sdim const FieldRegion *FR, FieldChainInfo LocalChain) { 140343173Sdim 141343173Sdim SVal V = State->getSVal(FR); 142343173Sdim 143343173Sdim assert((isDereferencableType(FR->getDecl()->getType()) || 144343173Sdim V.getAs<nonloc::LocAsInteger>()) && 145343173Sdim "This method only checks dereferenceable objects!"); 146343173Sdim 147343173Sdim if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) { 148343173Sdim IsAnyFieldInitialized = true; 149343173Sdim return false; 150343173Sdim } 151343173Sdim 152343173Sdim if (V.isUndef()) { 153343173Sdim return addFieldToUninits( 154343173Sdim LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR); 155343173Sdim } 156343173Sdim 157343173Sdim if (!Opts.CheckPointeeInitialization) { 158343173Sdim IsAnyFieldInitialized = true; 159343173Sdim return false; 160343173Sdim } 161343173Sdim 162343173Sdim // At this point the pointer itself is initialized and points to a valid 163343173Sdim // location, we'll now check the pointee. 164343173Sdim llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR); 165343173Sdim if (!DerefInfo) { 166343173Sdim IsAnyFieldInitialized = true; 167343173Sdim return false; 168343173Sdim } 169343173Sdim 170343173Sdim if (DerefInfo->IsCyclic) 171343173Sdim return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR); 172343173Sdim 173343173Sdim const TypedValueRegion *R = DerefInfo->R; 174343173Sdim const bool NeedsCastBack = DerefInfo->NeedsCastBack; 175343173Sdim 176343173Sdim QualType DynT = R->getLocationType(); 177343173Sdim QualType PointeeT = DynT->getPointeeType(); 178343173Sdim 179343173Sdim if (PointeeT->isStructureOrClassType()) { 180343173Sdim if (NeedsCastBack) 181343173Sdim return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT))); 182343173Sdim return isNonUnionUninit(R, LocalChain.add(LocField(FR))); 183343173Sdim } 184343173Sdim 185343173Sdim if (PointeeT->isUnionType()) { 186343173Sdim if (isUnionUninit(R)) { 187343173Sdim if (NeedsCastBack) 188343173Sdim return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), 189343173Sdim R); 190343173Sdim return addFieldToUninits(LocalChain.add(LocField(FR)), R); 191343173Sdim } else { 192343173Sdim IsAnyFieldInitialized = true; 193343173Sdim return false; 194343173Sdim } 195343173Sdim } 196343173Sdim 197343173Sdim if (PointeeT->isArrayType()) { 198343173Sdim IsAnyFieldInitialized = true; 199343173Sdim return false; 200343173Sdim } 201343173Sdim 202343173Sdim assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && 203343173Sdim "At this point FR must either have a primitive dynamic type, or it " 204343173Sdim "must be a null, undefined, unknown or concrete pointer!"); 205343173Sdim 206343173Sdim SVal PointeeV = State->getSVal(R); 207343173Sdim 208343173Sdim if (isPrimitiveUninit(PointeeV)) { 209343173Sdim if (NeedsCastBack) 210343173Sdim return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R); 211343173Sdim return addFieldToUninits(LocalChain.add(LocField(FR)), R); 212343173Sdim } 213343173Sdim 214343173Sdim IsAnyFieldInitialized = true; 215343173Sdim return false; 216343173Sdim} 217343173Sdim 218343173Sdim//===----------------------------------------------------------------------===// 219343173Sdim// Utility functions. 220343173Sdim//===----------------------------------------------------------------------===// 221343173Sdim 222343173Sdimstatic llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, 223343173Sdim const FieldRegion *FR) { 224343173Sdim 225343173Sdim llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions; 226343173Sdim 227343173Sdim SVal V = State->getSVal(FR); 228343173Sdim assert(V.getAsRegion() && "V must have an underlying region!"); 229343173Sdim 230343173Sdim // If the static type of the field is a void pointer, or it is a 231343173Sdim // nonloc::LocAsInteger, we need to cast it back to the dynamic type before 232343173Sdim // dereferencing. 233343173Sdim bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) || 234343173Sdim V.getAs<nonloc::LocAsInteger>(); 235343173Sdim 236343173Sdim // The region we'd like to acquire. 237343173Sdim const auto *R = V.getAsRegion()->getAs<TypedValueRegion>(); 238343173Sdim if (!R) 239343173Sdim return None; 240343173Sdim 241343173Sdim VisitedRegions.insert(R); 242343173Sdim 243343173Sdim // We acquire the dynamic type of R, 244343173Sdim QualType DynT = R->getLocationType(); 245343173Sdim 246343173Sdim while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) { 247343173Sdim 248343173Sdim R = Tmp->getAs<TypedValueRegion>(); 249343173Sdim if (!R) 250343173Sdim return None; 251343173Sdim 252343173Sdim // We found a cyclic pointer, like int *ptr = (int *)&ptr. 253343173Sdim if (!VisitedRegions.insert(R).second) 254343173Sdim return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true}; 255343173Sdim 256343173Sdim DynT = R->getLocationType(); 257343173Sdim // In order to ensure that this loop terminates, we're also checking the 258343173Sdim // dynamic type of R, since type hierarchy is finite. 259343173Sdim if (isDereferencableType(DynT->getPointeeType())) 260343173Sdim break; 261343173Sdim } 262343173Sdim 263360784Sdim while (isa<CXXBaseObjectRegion>(R)) { 264343173Sdim NeedsCastBack = true; 265360784Sdim const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion()); 266360784Sdim if (!SuperR) 267360784Sdim break; 268343173Sdim 269360784Sdim R = SuperR; 270343173Sdim } 271343173Sdim 272343173Sdim return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false}; 273343173Sdim} 274343173Sdim 275343173Sdimstatic bool isVoidPointer(QualType T) { 276343173Sdim while (!T.isNull()) { 277343173Sdim if (T->isVoidPointerType()) 278343173Sdim return true; 279343173Sdim T = T->getPointeeType(); 280343173Sdim } 281343173Sdim return false; 282343173Sdim} 283