xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp (revision 3e3f7552eb5b400be026ce365e1abbfc7767022c)
1 //===----- UninitializedPointer.cpp ------------------------------*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines functions and methods for handling pointers and references
11 // to reduce the size and complexity of UninitializedObjectChecker.cpp.
12 //
13 // To read about command line options and a description what this checker does,
14 // refer to UninitializedObjectChecker.cpp.
15 //
16 // To read about how the checker works, refer to the comments in
17 // UninitializedObject.h.
18 //
19 //===----------------------------------------------------------------------===//
20 
21 #include "../ClangSACheckers.h"
22 #include "UninitializedObject.h"
23 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
24 #include "clang/StaticAnalyzer/Core/Checker.h"
25 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
26 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
27 
28 using namespace clang;
29 using namespace clang::ento;
30 
31 namespace {
32 
33 /// Represents a pointer or a reference field.
34 class LocField final : public FieldNode {
35   /// We'll store whether the pointee or the pointer itself is uninitialited.
36   const bool IsDereferenced;
37 
38 public:
39   LocField(const FieldRegion *FR, const bool IsDereferenced = true)
40       : FieldNode(FR), IsDereferenced(IsDereferenced) {}
41 
42   virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
43     if (IsDereferenced)
44       Out << "uninitialized pointee ";
45     else
46       Out << "uninitialized pointer ";
47   }
48 
49   virtual void printPrefix(llvm::raw_ostream &Out) const override {}
50 
51   virtual void printNode(llvm::raw_ostream &Out) const override {
52     Out << getVariableName(getDecl());
53   }
54 
55   virtual void printSeparator(llvm::raw_ostream &Out) const override {
56     if (getDecl()->getType()->isPointerType())
57       Out << "->";
58     else
59       Out << '.';
60   }
61 };
62 
63 /// Represents a void* field that needs to be casted back to its dynamic type
64 /// for a correct note message.
65 class NeedsCastLocField final : public FieldNode {
66   QualType CastBackType;
67 
68 public:
69   NeedsCastLocField(const FieldRegion *FR, const QualType &T)
70       : FieldNode(FR), CastBackType(T) {}
71 
72   virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
73     Out << "uninitialized pointee ";
74   }
75 
76   virtual void printPrefix(llvm::raw_ostream &Out) const override {
77     Out << "static_cast" << '<' << CastBackType.getAsString() << ">(";
78   }
79 
80   virtual void printNode(llvm::raw_ostream &Out) const override {
81     Out << getVariableName(getDecl()) << ')';
82   }
83 
84   virtual void printSeparator(llvm::raw_ostream &Out) const override {
85     Out << "->";
86   }
87 };
88 
89 } // end of anonymous namespace
90 
91 // Utility function declarations.
92 
93 /// Returns whether T can be (transitively) dereferenced to a void pointer type
94 /// (void*, void**, ...). The type of the region behind a void pointer isn't
95 /// known, and thus FD can not be analyzed.
96 static bool isVoidPointer(QualType T);
97 
98 //===----------------------------------------------------------------------===//
99 //                   Methods for FindUninitializedFields.
100 //===----------------------------------------------------------------------===//
101 
102 // Note that pointers/references don't contain fields themselves, so in this
103 // function we won't add anything to LocalChain.
104 bool FindUninitializedFields::isPointerOrReferenceUninit(
105     const FieldRegion *FR, FieldChainInfo LocalChain) {
106 
107   assert((FR->getDecl()->getType()->isAnyPointerType() ||
108           FR->getDecl()->getType()->isReferenceType() ||
109           FR->getDecl()->getType()->isBlockPointerType()) &&
110          "This method only checks pointer/reference objects!");
111 
112   SVal V = State->getSVal(FR);
113 
114   if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
115     IsAnyFieldInitialized = true;
116     return false;
117   }
118 
119   if (V.isUndef()) {
120     return addFieldToUninits(
121         LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
122   }
123 
124   if (!CheckPointeeInitialization) {
125     IsAnyFieldInitialized = true;
126     return false;
127   }
128 
129   assert(V.getAs<loc::MemRegionVal>() &&
130          "At this point V must be loc::MemRegionVal!");
131   auto L = V.castAs<loc::MemRegionVal>();
132 
133   // We can't reason about symbolic regions, assume its initialized.
134   // Note that this also avoids a potential infinite recursion, because
135   // constructors for list-like classes are checked without being called, and
136   // the Static Analyzer will construct a symbolic region for Node *next; or
137   // similar code snippets.
138   if (L.getRegion()->getSymbolicBase()) {
139     IsAnyFieldInitialized = true;
140     return false;
141   }
142 
143   DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
144   if (!DynTInfo.isValid()) {
145     IsAnyFieldInitialized = true;
146     return false;
147   }
148 
149   QualType DynT = DynTInfo.getType();
150 
151   // If the static type of the field is a void pointer, we need to cast it back
152   // to the dynamic type before dereferencing.
153   bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
154 
155   if (isVoidPointer(DynT)) {
156     IsAnyFieldInitialized = true;
157     return false;
158   }
159 
160   // At this point the pointer itself is initialized and points to a valid
161   // location, we'll now check the pointee.
162   SVal DerefdV = State->getSVal(V.castAs<Loc>(), DynT);
163 
164   // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
165   // int** -> int*).
166   while (auto Tmp = DerefdV.getAs<loc::MemRegionVal>()) {
167     if (Tmp->getRegion()->getSymbolicBase()) {
168       IsAnyFieldInitialized = true;
169       return false;
170     }
171 
172     DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
173     if (!DynTInfo.isValid()) {
174       IsAnyFieldInitialized = true;
175       return false;
176     }
177 
178     DynT = DynTInfo.getType();
179     if (isVoidPointer(DynT)) {
180       IsAnyFieldInitialized = true;
181       return false;
182     }
183 
184     DerefdV = State->getSVal(*Tmp, DynT);
185   }
186 
187   // If FR is a pointer pointing to a non-primitive type.
188   if (Optional<nonloc::LazyCompoundVal> RecordV =
189           DerefdV.getAs<nonloc::LazyCompoundVal>()) {
190 
191     const TypedValueRegion *R = RecordV->getRegion();
192 
193     if (DynT->getPointeeType()->isStructureOrClassType()) {
194       if (NeedsCastBack)
195         return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
196       return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
197     }
198 
199     if (DynT->getPointeeType()->isUnionType()) {
200       if (isUnionUninit(R)) {
201         if (NeedsCastBack)
202           return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
203         return addFieldToUninits(LocalChain.add(LocField(FR)));
204       } else {
205         IsAnyFieldInitialized = true;
206         return false;
207       }
208     }
209 
210     if (DynT->getPointeeType()->isArrayType()) {
211       IsAnyFieldInitialized = true;
212       return false;
213     }
214 
215     llvm_unreachable("All cases are handled!");
216   }
217 
218   // Temporary variable to avoid warning from -Wunused-function.
219   bool IsPrimitive = isPrimitiveType(DynT->getPointeeType());
220   assert((IsPrimitive || DynT->isAnyPointerType() || DynT->isReferenceType()) &&
221          "At this point FR must either have a primitive dynamic type, or it "
222          "must be a null, undefined, unknown or concrete pointer!");
223   (void)IsPrimitive;
224 
225   if (isPrimitiveUninit(DerefdV)) {
226     if (NeedsCastBack)
227       return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
228     return addFieldToUninits(LocalChain.add(LocField(FR)));
229   }
230 
231   IsAnyFieldInitialized = true;
232   return false;
233 }
234 
235 //===----------------------------------------------------------------------===//
236 //                           Utility functions.
237 //===----------------------------------------------------------------------===//
238 
239 static bool isVoidPointer(QualType T) {
240   while (!T.isNull()) {
241     if (T->isVoidPointerType())
242       return true;
243     T = T->getPointeeType();
244   }
245   return false;
246 }
247