1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
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/DynamicTypeMap.h" |
22 | |
23 | using namespace clang; |
24 | using namespace clang::ento; |
25 | |
26 | namespace { |
27 | |
28 | |
29 | class LocField final : public FieldNode { |
30 | |
31 | const bool IsDereferenced; |
32 | |
33 | public: |
34 | LocField(const FieldRegion *FR, const bool IsDereferenced = true) |
35 | : FieldNode(FR), IsDereferenced(IsDereferenced) {} |
36 | |
37 | virtual void printNoteMsg(llvm::raw_ostream &Out) const override { |
38 | if (IsDereferenced) |
39 | Out << "uninitialized pointee "; |
40 | else |
41 | Out << "uninitialized pointer "; |
42 | } |
43 | |
44 | virtual void printPrefix(llvm::raw_ostream &Out) const override {} |
45 | |
46 | virtual void printNode(llvm::raw_ostream &Out) const override { |
47 | Out << getVariableName(getDecl()); |
48 | } |
49 | |
50 | virtual void printSeparator(llvm::raw_ostream &Out) const override { |
51 | if (getDecl()->getType()->isPointerType()) |
52 | Out << "->"; |
53 | else |
54 | Out << '.'; |
55 | } |
56 | }; |
57 | |
58 | |
59 | |
60 | class NeedsCastLocField final : public FieldNode { |
61 | QualType CastBackType; |
62 | |
63 | public: |
64 | NeedsCastLocField(const FieldRegion *FR, const QualType &T) |
65 | : FieldNode(FR), CastBackType(T) {} |
66 | |
67 | virtual void printNoteMsg(llvm::raw_ostream &Out) const override { |
68 | Out << "uninitialized pointee "; |
69 | } |
70 | |
71 | virtual void printPrefix(llvm::raw_ostream &Out) const override { |
72 | |
73 | if (getDecl()->getType()->isIntegerType()) |
74 | Out << "reinterpret_cast"; |
75 | |
76 | else |
77 | Out << "static_cast"; |
78 | Out << '<' << CastBackType.getAsString() << ">("; |
79 | } |
80 | |
81 | virtual void printNode(llvm::raw_ostream &Out) const override { |
82 | Out << getVariableName(getDecl()) << ')'; |
83 | } |
84 | |
85 | virtual void printSeparator(llvm::raw_ostream &Out) const override { |
86 | Out << "->"; |
87 | } |
88 | }; |
89 | |
90 | |
91 | class CyclicLocField final : public FieldNode { |
92 | |
93 | public: |
94 | CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {} |
95 | |
96 | virtual void printNoteMsg(llvm::raw_ostream &Out) const override { |
97 | Out << "object references itself "; |
98 | } |
99 | |
100 | virtual void printPrefix(llvm::raw_ostream &Out) const override {} |
101 | |
102 | virtual void printNode(llvm::raw_ostream &Out) const override { |
103 | Out << getVariableName(getDecl()); |
104 | } |
105 | |
106 | virtual void printSeparator(llvm::raw_ostream &Out) const override { |
107 | llvm_unreachable("CyclicLocField objects must be the last node of the " |
108 | "fieldchain!"); |
109 | } |
110 | }; |
111 | |
112 | } |
113 | |
114 | |
115 | |
116 | struct DereferenceInfo { |
117 | const TypedValueRegion *R; |
118 | const bool NeedsCastBack; |
119 | const bool IsCyclic; |
120 | DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC) |
121 | : R(R), NeedsCastBack(NCB), IsCyclic(IC) {} |
122 | }; |
123 | |
124 | |
125 | |
126 | |
127 | static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, |
128 | const FieldRegion *FR); |
129 | |
130 | |
131 | |
132 | static bool isVoidPointer(QualType T); |
133 | |
134 | |
135 | |
136 | |
137 | |
138 | bool FindUninitializedFields::isDereferencableUninit( |
139 | const FieldRegion *FR, FieldChainInfo LocalChain) { |
140 | |
141 | SVal V = State->getSVal(FR); |
142 | |
143 | (0) . __assert_fail ("(isDereferencableType(FR->getDecl()->getType()) || V.getAs()) && \"This method only checks dereferenceable objects!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp", 145, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert((isDereferencableType(FR->getDecl()->getType()) || |
144 | (0) . __assert_fail ("(isDereferencableType(FR->getDecl()->getType()) || V.getAs()) && \"This method only checks dereferenceable objects!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp", 145, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true"> V.getAs<nonloc::LocAsInteger>()) && |
145 | (0) . __assert_fail ("(isDereferencableType(FR->getDecl()->getType()) || V.getAs()) && \"This method only checks dereferenceable objects!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp", 145, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true"> "This method only checks dereferenceable objects!"); |
146 | |
147 | if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) { |
148 | IsAnyFieldInitialized = true; |
149 | return false; |
150 | } |
151 | |
152 | if (V.isUndef()) { |
153 | return addFieldToUninits( |
154 | LocalChain.add(LocField(FR, false)), FR); |
155 | } |
156 | |
157 | if (!Opts.CheckPointeeInitialization) { |
158 | IsAnyFieldInitialized = true; |
159 | return false; |
160 | } |
161 | |
162 | |
163 | |
164 | llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR); |
165 | if (!DerefInfo) { |
166 | IsAnyFieldInitialized = true; |
167 | return false; |
168 | } |
169 | |
170 | if (DerefInfo->IsCyclic) |
171 | return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR); |
172 | |
173 | const TypedValueRegion *R = DerefInfo->R; |
174 | const bool NeedsCastBack = DerefInfo->NeedsCastBack; |
175 | |
176 | QualType DynT = R->getLocationType(); |
177 | QualType PointeeT = DynT->getPointeeType(); |
178 | |
179 | if (PointeeT->isStructureOrClassType()) { |
180 | if (NeedsCastBack) |
181 | return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT))); |
182 | return isNonUnionUninit(R, LocalChain.add(LocField(FR))); |
183 | } |
184 | |
185 | if (PointeeT->isUnionType()) { |
186 | if (isUnionUninit(R)) { |
187 | if (NeedsCastBack) |
188 | return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), |
189 | R); |
190 | return addFieldToUninits(LocalChain.add(LocField(FR)), R); |
191 | } else { |
192 | IsAnyFieldInitialized = true; |
193 | return false; |
194 | } |
195 | } |
196 | |
197 | if (PointeeT->isArrayType()) { |
198 | IsAnyFieldInitialized = true; |
199 | return false; |
200 | } |
201 | |
202 | (0) . __assert_fail ("(isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && \"At this point FR must either have a primitive dynamic type, or it \" \"must be a null, undefined, unknown or concrete pointer!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp", 204, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && |
203 | (0) . __assert_fail ("(isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && \"At this point FR must either have a primitive dynamic type, or it \" \"must be a null, undefined, unknown or concrete pointer!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp", 204, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true"> "At this point FR must either have a primitive dynamic type, or it " |
204 | (0) . __assert_fail ("(isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) && \"At this point FR must either have a primitive dynamic type, or it \" \"must be a null, undefined, unknown or concrete pointer!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp", 204, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true"> "must be a null, undefined, unknown or concrete pointer!"); |
205 | |
206 | SVal PointeeV = State->getSVal(R); |
207 | |
208 | if (isPrimitiveUninit(PointeeV)) { |
209 | if (NeedsCastBack) |
210 | return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R); |
211 | return addFieldToUninits(LocalChain.add(LocField(FR)), R); |
212 | } |
213 | |
214 | IsAnyFieldInitialized = true; |
215 | return false; |
216 | } |
217 | |
218 | |
219 | |
220 | |
221 | |
222 | static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State, |
223 | const FieldRegion *FR) { |
224 | |
225 | llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions; |
226 | |
227 | SVal V = State->getSVal(FR); |
228 | (0) . __assert_fail ("V.getAsRegion() && \"V must have an underlying region!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp", 228, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert(V.getAsRegion() && "V must have an underlying region!"); |
229 | |
230 | |
231 | |
232 | |
233 | bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) || |
234 | V.getAs<nonloc::LocAsInteger>(); |
235 | |
236 | |
237 | const auto *R = V.getAsRegion()->getAs<TypedValueRegion>(); |
238 | if (!R) |
239 | return None; |
240 | |
241 | VisitedRegions.insert(R); |
242 | |
243 | |
244 | QualType DynT = R->getLocationType(); |
245 | |
246 | while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) { |
247 | |
248 | R = Tmp->getAs<TypedValueRegion>(); |
249 | if (!R) |
250 | return None; |
251 | |
252 | |
253 | if (!VisitedRegions.insert(R).second) |
254 | return DereferenceInfo{R, NeedsCastBack, true}; |
255 | |
256 | DynT = R->getLocationType(); |
257 | |
258 | |
259 | if (isDereferencableType(DynT->getPointeeType())) |
260 | break; |
261 | } |
262 | |
263 | while (R->getAs<CXXBaseObjectRegion>()) { |
264 | NeedsCastBack = true; |
265 | |
266 | if (!isa<TypedValueRegion>(R->getSuperRegion())) |
267 | break; |
268 | R = R->getSuperRegion()->getAs<TypedValueRegion>(); |
269 | } |
270 | |
271 | return DereferenceInfo{R, NeedsCastBack, false}; |
272 | } |
273 | |
274 | static bool isVoidPointer(QualType T) { |
275 | while (!T.isNull()) { |
276 | if (T->isVoidPointerType()) |
277 | return true; |
278 | T = T->getPointeeType(); |
279 | } |
280 | return false; |
281 | } |
282 | |