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 /// Dereferences \p V and returns the value and dynamic type of the pointee, as
99 /// well as whether \p FR needs to be casted back to that type. If for whatever
100 /// reason dereferencing fails, returns with None.
101 static llvm::Optional<std::tuple<SVal, QualType, bool>>
102 dereference(ProgramStateRef State, const FieldRegion *FR);
103 
104 //===----------------------------------------------------------------------===//
105 //                   Methods for FindUninitializedFields.
106 //===----------------------------------------------------------------------===//
107 
108 // Note that pointers/references don't contain fields themselves, so in this
109 // function we won't add anything to LocalChain.
110 bool FindUninitializedFields::isPointerOrReferenceUninit(
111     const FieldRegion *FR, FieldChainInfo LocalChain) {
112 
113   assert((FR->getDecl()->getType()->isAnyPointerType() ||
114           FR->getDecl()->getType()->isReferenceType() ||
115           FR->getDecl()->getType()->isBlockPointerType()) &&
116          "This method only checks pointer/reference objects!");
117 
118   SVal V = State->getSVal(FR);
119 
120   if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
121     IsAnyFieldInitialized = true;
122     return false;
123   }
124 
125   if (V.isUndef()) {
126     return addFieldToUninits(
127         LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
128   }
129 
130   if (!CheckPointeeInitialization) {
131     IsAnyFieldInitialized = true;
132     return false;
133   }
134 
135   // At this point the pointer itself is initialized and points to a valid
136   // location, we'll now check the pointee.
137   llvm::Optional<std::tuple<SVal, QualType, bool>> DerefInfo =
138       dereference(State, FR);
139   if (!DerefInfo) {
140     IsAnyFieldInitialized = true;
141     return false;
142   }
143 
144   V = std::get<0>(*DerefInfo);
145   QualType DynT = std::get<1>(*DerefInfo);
146   bool NeedsCastBack = std::get<2>(*DerefInfo);
147 
148   // If FR is a pointer pointing to a non-primitive type.
149   if (Optional<nonloc::LazyCompoundVal> RecordV =
150           V.getAs<nonloc::LazyCompoundVal>()) {
151 
152     const TypedValueRegion *R = RecordV->getRegion();
153 
154     if (DynT->getPointeeType()->isStructureOrClassType()) {
155       if (NeedsCastBack)
156         return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
157       return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
158     }
159 
160     if (DynT->getPointeeType()->isUnionType()) {
161       if (isUnionUninit(R)) {
162         if (NeedsCastBack)
163           return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
164         return addFieldToUninits(LocalChain.add(LocField(FR)));
165       } else {
166         IsAnyFieldInitialized = true;
167         return false;
168       }
169     }
170 
171     if (DynT->getPointeeType()->isArrayType()) {
172       IsAnyFieldInitialized = true;
173       return false;
174     }
175 
176     llvm_unreachable("All cases are handled!");
177   }
178 
179   assert((isPrimitiveType(DynT->getPointeeType()) || DynT->isAnyPointerType() ||
180           DynT->isReferenceType()) &&
181          "At this point FR must either have a primitive dynamic type, or it "
182          "must be a null, undefined, unknown or concrete pointer!");
183 
184   if (isPrimitiveUninit(V)) {
185     if (NeedsCastBack)
186       return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
187     return addFieldToUninits(LocalChain.add(LocField(FR)));
188   }
189 
190   IsAnyFieldInitialized = true;
191   return false;
192 }
193 
194 //===----------------------------------------------------------------------===//
195 //                           Utility functions.
196 //===----------------------------------------------------------------------===//
197 
198 static bool isVoidPointer(QualType T) {
199   while (!T.isNull()) {
200     if (T->isVoidPointerType())
201       return true;
202     T = T->getPointeeType();
203   }
204   return false;
205 }
206 
207 static llvm::Optional<std::tuple<SVal, QualType, bool>>
208 dereference(ProgramStateRef State, const FieldRegion *FR) {
209 
210   DynamicTypeInfo DynTInfo;
211   QualType DynT;
212 
213   // If the static type of the field is a void pointer, we need to cast it back
214   // to the dynamic type before dereferencing.
215   bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
216 
217   SVal V = State->getSVal(FR);
218   assert(V.getAs<loc::MemRegionVal>() && "V must be loc::MemRegionVal!");
219 
220   // If V is multiple pointer value, we'll dereference it again (e.g.: int** ->
221   // int*).
222   // TODO: Dereference according to the dynamic type to avoid infinite loop for
223   // these kind of fields:
224   //   int **ptr = reinterpret_cast<int **>(&ptr);
225   while (auto Tmp = V.getAs<loc::MemRegionVal>()) {
226     // We can't reason about symbolic regions, assume its initialized.
227     // Note that this also avoids a potential infinite recursion, because
228     // constructors for list-like classes are checked without being called, and
229     // the Static Analyzer will construct a symbolic region for Node *next; or
230     // similar code snippets.
231     if (Tmp->getRegion()->getSymbolicBase()) {
232       return None;
233     }
234 
235     DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
236     if (!DynTInfo.isValid()) {
237       return None;
238     }
239 
240     DynT = DynTInfo.getType();
241 
242     if (isVoidPointer(DynT)) {
243       return None;
244     }
245 
246     V = State->getSVal(*Tmp, DynT);
247   }
248 
249   return std::make_tuple(V, DynT, NeedsCastBack);
250 }
251