1 //===----- UninitializedPointee.cpp ------------------------------*- C++ -*-==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines functions and methods for handling pointers and references
11 // to reduce the size and complexity of UninitializedObjectChecker.cpp.
13 // To read about command line options and documentation about how the checker
14 // works, refer to UninitializedObjectChecker.h.
16 //===----------------------------------------------------------------------===//
18 #include "UninitializedObject.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20 #include "clang/StaticAnalyzer/Core/Checker.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
24 using namespace clang;
25 using namespace clang::ento;
29 /// Represents a pointer or a reference field.
30 class LocField final : public FieldNode {
31 /// We'll store whether the pointee or the pointer itself is uninitialited.
32 const bool IsDereferenced;
35 LocField(const FieldRegion *FR, const bool IsDereferenced = true)
36 : FieldNode(FR), IsDereferenced(IsDereferenced) {}
38 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
40 Out << "uninitialized pointee ";
42 Out << "uninitialized pointer ";
45 virtual void printPrefix(llvm::raw_ostream &Out) const override {}
47 virtual void printNode(llvm::raw_ostream &Out) const override {
48 Out << getVariableName(getDecl());
51 virtual void printSeparator(llvm::raw_ostream &Out) const override {
52 if (getDecl()->getType()->isPointerType())
59 /// Represents a nonloc::LocAsInteger or void* field, that point to objects, but
60 /// needs to be casted back to its dynamic type for a correct note message.
61 class NeedsCastLocField final : public FieldNode {
62 QualType CastBackType;
65 NeedsCastLocField(const FieldRegion *FR, const QualType &T)
66 : FieldNode(FR), CastBackType(T) {}
68 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
69 Out << "uninitialized pointee ";
72 virtual void printPrefix(llvm::raw_ostream &Out) const override {
73 // If this object is a nonloc::LocAsInteger.
74 if (getDecl()->getType()->isIntegerType())
75 Out << "reinterpret_cast";
76 // If this pointer's dynamic type is different then it's static type.
79 Out << '<' << CastBackType.getAsString() << ">(";
82 virtual void printNode(llvm::raw_ostream &Out) const override {
83 Out << getVariableName(getDecl()) << ')';
86 virtual void printSeparator(llvm::raw_ostream &Out) const override {
91 /// Represents a Loc field that points to itself.
92 class CyclicLocField final : public FieldNode {
95 CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
97 virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
98 Out << "object references itself ";
101 virtual void printPrefix(llvm::raw_ostream &Out) const override {}
103 virtual void printNode(llvm::raw_ostream &Out) const override {
104 Out << getVariableName(getDecl());
107 virtual void printSeparator(llvm::raw_ostream &Out) const override {
108 llvm_unreachable("CyclicLocField objects must be the last node of the "
113 } // end of anonymous namespace
115 // Utility function declarations.
117 struct DereferenceInfo {
118 const TypedValueRegion *R;
119 const bool NeedsCastBack;
121 DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
122 : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
125 /// Dereferences \p FR and returns with the pointee's region, and whether it
126 /// needs to be casted back to it's location type. If for whatever reason
127 /// dereferencing fails, returns with None.
128 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
129 const FieldRegion *FR);
131 /// Returns whether \p T can be (transitively) dereferenced to a void pointer
132 /// type (void*, void**, ...).
133 static bool isVoidPointer(QualType T);
135 //===----------------------------------------------------------------------===//
136 // Methods for FindUninitializedFields.
137 //===----------------------------------------------------------------------===//
139 bool FindUninitializedFields::isDereferencableUninit(
140 const FieldRegion *FR, FieldChainInfo LocalChain) {
142 SVal V = State->getSVal(FR);
144 assert((isDereferencableType(FR->getDecl()->getType()) ||
145 V.getAs<nonloc::LocAsInteger>()) &&
146 "This method only checks dereferenceable objects!");
148 if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
149 IsAnyFieldInitialized = true;
154 return addFieldToUninits(
155 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
158 if (!Opts.CheckPointeeInitialization) {
159 IsAnyFieldInitialized = true;
163 // At this point the pointer itself is initialized and points to a valid
164 // location, we'll now check the pointee.
165 llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
167 IsAnyFieldInitialized = true;
171 if (DerefInfo->IsCyclic)
172 return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
174 const TypedValueRegion *R = DerefInfo->R;
175 const bool NeedsCastBack = DerefInfo->NeedsCastBack;
177 QualType DynT = R->getLocationType();
178 QualType PointeeT = DynT->getPointeeType();
180 if (PointeeT->isStructureOrClassType()) {
182 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
183 return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
186 if (PointeeT->isUnionType()) {
187 if (isUnionUninit(R)) {
189 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
191 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
193 IsAnyFieldInitialized = true;
198 if (PointeeT->isArrayType()) {
199 IsAnyFieldInitialized = true;
203 assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
204 "At this point FR must either have a primitive dynamic type, or it "
205 "must be a null, undefined, unknown or concrete pointer!");
207 SVal PointeeV = State->getSVal(R);
209 if (isPrimitiveUninit(PointeeV)) {
211 return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
212 return addFieldToUninits(LocalChain.add(LocField(FR)), R);
215 IsAnyFieldInitialized = true;
219 //===----------------------------------------------------------------------===//
220 // Utility functions.
221 //===----------------------------------------------------------------------===//
223 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
224 const FieldRegion *FR) {
226 llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
228 SVal V = State->getSVal(FR);
229 assert(V.getAsRegion() && "V must have an underlying region!");
231 // If the static type of the field is a void pointer, or it is a
232 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
234 bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
235 V.getAs<nonloc::LocAsInteger>();
237 // The region we'd like to acquire.
238 const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
242 VisitedRegions.insert(R);
244 // We acquire the dynamic type of R,
245 QualType DynT = R->getLocationType();
247 while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
249 R = Tmp->getAs<TypedValueRegion>();
253 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
254 if (!VisitedRegions.insert(R).second)
255 return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
257 DynT = R->getLocationType();
258 // In order to ensure that this loop terminates, we're also checking the
259 // dynamic type of R, since type hierarchy is finite.
260 if (isDereferencableType(DynT->getPointeeType()))
264 while (R->getAs<CXXBaseObjectRegion>()) {
265 NeedsCastBack = true;
267 if (!isa<TypedValueRegion>(R->getSuperRegion()))
269 R = R->getSuperRegion()->getAs<TypedValueRegion>();
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();