1 //===----- UninitializedPointee.cpp ------------------------------*- C++ -*-==//
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-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines functions and methods for handling pointers and references
10 // to reduce the size and complexity of UninitializedObjectChecker.cpp.
12 // To read about command line options and documentation about how the checker
13 // works, refer to UninitializedObjectChecker.h.
15 //===----------------------------------------------------------------------===//
17 #include "UninitializedObject.h"
18 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19 #include "clang/StaticAnalyzer/Core/Checker.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
23 using namespace clang;
24 using namespace clang::ento;
28 /// Represents a pointer or a reference field.
29 class LocField final : public FieldNode {
30 /// We'll store whether the pointee or the pointer itself is uninitialited.
31 const bool IsDereferenced;
34 LocField(const FieldRegion *FR, const bool IsDereferenced = true)
35 : FieldNode(FR), IsDereferenced(IsDereferenced) {}
37 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
39 Out << "uninitialized pointee ";
41 Out << "uninitialized pointer ";
44 virtual void printPrefix(llvm::raw_ostream &Out) const override {}
46 virtual void printNode(llvm::raw_ostream &Out) const override {
47 Out << getVariableName(getDecl());
50 virtual void printSeparator(llvm::raw_ostream &Out) const override {
51 if (getDecl()->getType()->isPointerType())
58 /// Represents a nonloc::LocAsInteger or void* field, that point to objects, but
59 /// needs to be casted back to its dynamic type for a correct note message.
60 class NeedsCastLocField final : public FieldNode {
61 QualType CastBackType;
64 NeedsCastLocField(const FieldRegion *FR, const QualType &T)
65 : FieldNode(FR), CastBackType(T) {}
67 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
68 Out << "uninitialized pointee ";
71 virtual void printPrefix(llvm::raw_ostream &Out) const override {
72 // If this object is a nonloc::LocAsInteger.
73 if (getDecl()->getType()->isIntegerType())
74 Out << "reinterpret_cast";
75 // If this pointer's dynamic type is different then it's static type.
78 Out << '<' << CastBackType.getAsString() << ">(";
81 virtual void printNode(llvm::raw_ostream &Out) const override {
82 Out << getVariableName(getDecl()) << ')';
85 virtual void printSeparator(llvm::raw_ostream &Out) const override {
90 /// Represents a Loc field that points to itself.
91 class CyclicLocField final : public FieldNode {
94 CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
96 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
97 Out << "object references itself ";
100 virtual void printPrefix(llvm::raw_ostream &Out) const override {}
102 virtual void printNode(llvm::raw_ostream &Out) const override {
103 Out << getVariableName(getDecl());
106 virtual void printSeparator(llvm::raw_ostream &Out) const override {
107 llvm_unreachable("CyclicLocField objects must be the last node of the "
112 } // end of anonymous namespace
114 // Utility function declarations.
116 struct DereferenceInfo {
117 const TypedValueRegion *R;
118 const bool NeedsCastBack;
120 DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
121 : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
124 /// Dereferences \p FR and returns with the pointee's region, and whether it
125 /// needs to be casted back to it's location type. If for whatever reason
126 /// dereferencing fails, returns with None.
127 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
128 const FieldRegion *FR);
130 /// Returns whether \p T can be (transitively) dereferenced to a void pointer
131 /// type (void*, void**, ...).
132 static bool isVoidPointer(QualType T);
134 //===----------------------------------------------------------------------===//
135 // Methods for FindUninitializedFields.
136 //===----------------------------------------------------------------------===//
138 bool FindUninitializedFields::isDereferencableUninit(
139 const FieldRegion *FR, FieldChainInfo LocalChain) {
141 SVal V = State->getSVal(FR);
143 assert((isDereferencableType(FR->getDecl()->getType()) ||
144 V.getAs<nonloc::LocAsInteger>()) &&
145 "This method only checks dereferenceable objects!");
147 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
148 IsAnyFieldInitialized = true;
153 return addFieldToUninits(
154 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
157 if (!Opts.CheckPointeeInitialization) {
158 IsAnyFieldInitialized = true;
162 // At this point the pointer itself is initialized and points to a valid
163 // location, we'll now check the pointee.
164 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
166 IsAnyFieldInitialized = true;
170 if (DerefInfo->IsCyclic)
171 return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
173 const TypedValueRegion *R = DerefInfo->R;
174 const bool NeedsCastBack = DerefInfo->NeedsCastBack;
176 QualType DynT = R->getLocationType();
177 QualType PointeeT = DynT->getPointeeType();
179 if (PointeeT->isStructureOrClassType()) {
181 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
182 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
185 if (PointeeT->isUnionType()) {
186 if (isUnionUninit(R)) {
188 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
190 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
192 IsAnyFieldInitialized = true;
197 if (PointeeT->isArrayType()) {
198 IsAnyFieldInitialized = true;
202 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
203 "At this point FR must either have a primitive dynamic type, or it "
204 "must be a null, undefined, unknown or concrete pointer!");
206 SVal PointeeV = State->getSVal(R);
208 if (isPrimitiveUninit(PointeeV)) {
210 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
211 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
214 IsAnyFieldInitialized = true;
218 //===----------------------------------------------------------------------===//
219 // Utility functions.
220 //===----------------------------------------------------------------------===//
222 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
223 const FieldRegion *FR) {
225 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
227 SVal V = State->getSVal(FR);
228 assert(V.getAsRegion() && "V must have an underlying region!");
230 // If the static type of the field is a void pointer, or it is a
231 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
233 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
234 V.getAs<nonloc::LocAsInteger>();
236 // The region we'd like to acquire.
237 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
241 VisitedRegions.insert(R);
243 // We acquire the dynamic type of R,
244 QualType DynT = R->getLocationType();
246 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
248 R = Tmp->getAs<TypedValueRegion>();
252 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
253 if (!VisitedRegions.insert(R).second)
254 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
256 DynT = R->getLocationType();
257 // In order to ensure that this loop terminates, we're also checking the
258 // dynamic type of R, since type hierarchy is finite.
259 if (isDereferencableType(DynT->getPointeeType()))
263 while (isa<CXXBaseObjectRegion>(R)) {
264 NeedsCastBack = true;
265 const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
272 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
275 static bool isVoidPointer(QualType T) {
276 while (!T.isNull()) {
277 if (T->isVoidPointerType())
279 T = T->getPointeeType();