xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp (revision 56963aec8b8b1d0defe486dc576a9721866c609d)
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 "UninitializedObject.h"
22 #include "ClangSACheckers.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 // Utility function declarations.
32 
33 /// Returns whether T can be (transitively) dereferenced to a void pointer type
34 /// (void*, void**, ...). The type of the region behind a void pointer isn't
35 /// known, and thus FD can not be analyzed.
36 static bool isVoidPointer(QualType T);
37 
38 //===----------------------------------------------------------------------===//
39 //                   Methods for FindUninitializedFields.
40 //===----------------------------------------------------------------------===//
41 
42 // Note that pointers/references don't contain fields themselves, so in this
43 // function we won't add anything to LocalChain.
44 bool FindUninitializedFields::isPointerOrReferenceUninit(
45     const FieldRegion *FR, FieldChainInfo LocalChain) {
46 
47   assert((FR->getDecl()->getType()->isPointerType() ||
48           FR->getDecl()->getType()->isReferenceType() ||
49           FR->getDecl()->getType()->isBlockPointerType()) &&
50          "This method only checks pointer/reference objects!");
51 
52   SVal V = State->getSVal(FR);
53 
54   if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
55     IsAnyFieldInitialized = true;
56     return false;
57   }
58 
59   if (V.isUndef()) {
60     return addFieldToUninits({LocalChain, FR});
61   }
62 
63   if (!CheckPointeeInitialization) {
64     IsAnyFieldInitialized = true;
65     return false;
66   }
67 
68   assert(V.getAs<loc::MemRegionVal>() &&
69          "At this point V must be loc::MemRegionVal!");
70   auto L = V.castAs<loc::MemRegionVal>();
71 
72   // We can't reason about symbolic regions, assume its initialized.
73   // Note that this also avoids a potential infinite recursion, because
74   // constructors for list-like classes are checked without being called, and
75   // the Static Analyzer will construct a symbolic region for Node *next; or
76   // similar code snippets.
77   if (L.getRegion()->getSymbolicBase()) {
78     IsAnyFieldInitialized = true;
79     return false;
80   }
81 
82   DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
83   if (!DynTInfo.isValid()) {
84     IsAnyFieldInitialized = true;
85     return false;
86   }
87 
88   QualType DynT = DynTInfo.getType();
89 
90   if (isVoidPointer(DynT)) {
91     IsAnyFieldInitialized = true;
92     return false;
93   }
94 
95   // At this point the pointer itself is initialized and points to a valid
96   // location, we'll now check the pointee.
97   SVal DerefdV = State->getSVal(V.castAs<Loc>(), DynT);
98 
99   // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
100   // int** -> int*).
101   while (auto Tmp = DerefdV.getAs<loc::MemRegionVal>()) {
102     if (Tmp->getRegion()->getSymbolicBase()) {
103       IsAnyFieldInitialized = true;
104       return false;
105     }
106 
107     DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
108     if (!DynTInfo.isValid()) {
109       IsAnyFieldInitialized = true;
110       return false;
111     }
112 
113     DynT = DynTInfo.getType();
114     if (isVoidPointer(DynT)) {
115       IsAnyFieldInitialized = true;
116       return false;
117     }
118 
119     DerefdV = State->getSVal(*Tmp, DynT);
120   }
121 
122   // If FR is a pointer pointing to a non-primitive type.
123   if (Optional<nonloc::LazyCompoundVal> RecordV =
124           DerefdV.getAs<nonloc::LazyCompoundVal>()) {
125 
126     const TypedValueRegion *R = RecordV->getRegion();
127 
128     if (DynT->getPointeeType()->isStructureOrClassType())
129       return isNonUnionUninit(R, {LocalChain, FR});
130 
131     if (DynT->getPointeeType()->isUnionType()) {
132       if (isUnionUninit(R)) {
133         return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
134       } else {
135         IsAnyFieldInitialized = true;
136         return false;
137       }
138     }
139 
140     if (DynT->getPointeeType()->isArrayType()) {
141       IsAnyFieldInitialized = true;
142       return false;
143     }
144 
145     llvm_unreachable("All cases are handled!");
146   }
147 
148   assert((isPrimitiveType(DynT->getPointeeType()) || DynT->isPointerType() ||
149           DynT->isReferenceType()) &&
150          "At this point FR must either have a primitive dynamic type, or it "
151          "must be a null, undefined, unknown or concrete pointer!");
152 
153   if (isPrimitiveUninit(DerefdV))
154     return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
155 
156   IsAnyFieldInitialized = true;
157   return false;
158 }
159 
160 //===----------------------------------------------------------------------===//
161 //                           Utility functions.
162 //===----------------------------------------------------------------------===//
163 
164 static bool isVoidPointer(QualType T) {
165   while (!T.isNull()) {
166     if (T->isVoidPointerType())
167       return true;
168     T = T->getPointeeType();
169   }
170   return false;
171 }
172