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"
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 void printNoteMsg(llvm::raw_ostream
&Out
) const override
{
40 Out
<< "uninitialized pointee ";
42 Out
<< "uninitialized pointer ";
45 void printPrefix(llvm::raw_ostream
&Out
) const override
{}
47 void printNode(llvm::raw_ostream
&Out
) const override
{
48 Out
<< getVariableName(getDecl());
51 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 void printNoteMsg(llvm::raw_ostream
&Out
) const override
{
69 Out
<< "uninitialized pointee ";
72 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 void printNode(llvm::raw_ostream
&Out
) const override
{
83 Out
<< getVariableName(getDecl()) << ')';
86 void printSeparator(llvm::raw_ostream
&Out
) const override
{ Out
<< "->"; }
89 /// Represents a Loc field that points to itself.
90 class CyclicLocField final
: public FieldNode
{
93 CyclicLocField(const FieldRegion
*FR
) : FieldNode(FR
) {}
95 void printNoteMsg(llvm::raw_ostream
&Out
) const override
{
96 Out
<< "object references itself ";
99 void printPrefix(llvm::raw_ostream
&Out
) const override
{}
101 void printNode(llvm::raw_ostream
&Out
) const override
{
102 Out
<< getVariableName(getDecl());
105 void printSeparator(llvm::raw_ostream
&Out
) const override
{
106 llvm_unreachable("CyclicLocField objects must be the last node of the "
111 } // end of anonymous namespace
113 // Utility function declarations.
115 struct DereferenceInfo
{
116 const TypedValueRegion
*R
;
117 const bool NeedsCastBack
;
119 DereferenceInfo(const TypedValueRegion
*R
, bool NCB
, bool IC
)
120 : R(R
), NeedsCastBack(NCB
), IsCyclic(IC
) {}
123 /// Dereferences \p FR and returns with the pointee's region, and whether it
124 /// needs to be casted back to it's location type. If for whatever reason
125 /// dereferencing fails, returns std::nullopt.
126 static std::optional
<DereferenceInfo
> dereference(ProgramStateRef State
,
127 const FieldRegion
*FR
);
129 /// Returns whether \p T can be (transitively) dereferenced to a void pointer
130 /// type (void*, void**, ...).
131 static bool isVoidPointer(QualType T
);
133 //===----------------------------------------------------------------------===//
134 // Methods for FindUninitializedFields.
135 //===----------------------------------------------------------------------===//
137 bool FindUninitializedFields::isDereferencableUninit(
138 const FieldRegion
*FR
, FieldChainInfo LocalChain
) {
140 SVal V
= State
->getSVal(FR
);
142 assert((isDereferencableType(FR
->getDecl()->getType()) ||
143 isa
<nonloc::LocAsInteger
>(V
)) &&
144 "This method only checks dereferenceable objects!");
146 if (V
.isUnknown() || isa
<loc::ConcreteInt
>(V
)) {
147 IsAnyFieldInitialized
= true;
152 return addFieldToUninits(
153 LocalChain
.add(LocField(FR
, /*IsDereferenced*/ false)), FR
);
156 if (!Opts
.CheckPointeeInitialization
) {
157 IsAnyFieldInitialized
= true;
161 // At this point the pointer itself is initialized and points to a valid
162 // location, we'll now check the pointee.
163 std::optional
<DereferenceInfo
> DerefInfo
= dereference(State
, FR
);
165 IsAnyFieldInitialized
= true;
169 if (DerefInfo
->IsCyclic
)
170 return addFieldToUninits(LocalChain
.add(CyclicLocField(FR
)), FR
);
172 const TypedValueRegion
*R
= DerefInfo
->R
;
173 const bool NeedsCastBack
= DerefInfo
->NeedsCastBack
;
175 QualType DynT
= R
->getLocationType();
176 QualType PointeeT
= DynT
->getPointeeType();
178 if (PointeeT
->isStructureOrClassType()) {
180 return isNonUnionUninit(R
, LocalChain
.add(NeedsCastLocField(FR
, DynT
)));
181 return isNonUnionUninit(R
, LocalChain
.add(LocField(FR
)));
184 if (PointeeT
->isUnionType()) {
185 if (isUnionUninit(R
)) {
187 return addFieldToUninits(LocalChain
.add(NeedsCastLocField(FR
, DynT
)),
189 return addFieldToUninits(LocalChain
.add(LocField(FR
)), R
);
191 IsAnyFieldInitialized
= true;
196 if (PointeeT
->isArrayType()) {
197 IsAnyFieldInitialized
= true;
201 assert((isPrimitiveType(PointeeT
) || isDereferencableType(PointeeT
)) &&
202 "At this point FR must either have a primitive dynamic type, or it "
203 "must be a null, undefined, unknown or concrete pointer!");
205 SVal PointeeV
= State
->getSVal(R
);
207 if (isPrimitiveUninit(PointeeV
)) {
209 return addFieldToUninits(LocalChain
.add(NeedsCastLocField(FR
, DynT
)), R
);
210 return addFieldToUninits(LocalChain
.add(LocField(FR
)), R
);
213 IsAnyFieldInitialized
= true;
217 //===----------------------------------------------------------------------===//
218 // Utility functions.
219 //===----------------------------------------------------------------------===//
221 static std::optional
<DereferenceInfo
> dereference(ProgramStateRef State
,
222 const FieldRegion
*FR
) {
224 llvm::SmallSet
<const TypedValueRegion
*, 5> VisitedRegions
;
226 SVal V
= State
->getSVal(FR
);
227 assert(V
.getAsRegion() && "V must have an underlying region!");
229 // If the static type of the field is a void pointer, or it is a
230 // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
233 isVoidPointer(FR
->getDecl()->getType()) || isa
<nonloc::LocAsInteger
>(V
);
235 // The region we'd like to acquire.
236 const auto *R
= V
.getAsRegion()->getAs
<TypedValueRegion
>();
240 VisitedRegions
.insert(R
);
242 // We acquire the dynamic type of R,
243 QualType DynT
= R
->getLocationType();
245 while (const MemRegion
*Tmp
= State
->getSVal(R
, DynT
).getAsRegion()) {
247 R
= Tmp
->getAs
<TypedValueRegion
>();
251 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
252 if (!VisitedRegions
.insert(R
).second
)
253 return DereferenceInfo
{R
, NeedsCastBack
, /*IsCyclic*/ true};
255 DynT
= R
->getLocationType();
256 // In order to ensure that this loop terminates, we're also checking the
257 // dynamic type of R, since type hierarchy is finite.
258 if (isDereferencableType(DynT
->getPointeeType()))
262 while (isa
<CXXBaseObjectRegion
>(R
)) {
263 NeedsCastBack
= true;
264 const auto *SuperR
= dyn_cast
<TypedValueRegion
>(R
->getSuperRegion());
271 return DereferenceInfo
{R
, NeedsCastBack
, /*IsCyclic*/ false};
274 static bool isVoidPointer(QualType T
) {
275 while (!T
.isNull()) {
276 if (T
->isVoidPointerType())
278 T
= T
->getPointeeType();