UninitializedPointee.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. //===----- UninitializedPointee.cpp ------------------------------*- C++ -*-==//
  2. //
  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
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defines functions and methods for handling pointers and references
  10. // to reduce the size and complexity of UninitializedObjectChecker.cpp.
  11. //
  12. // To read about command line options and documentation about how the checker
  13. // works, refer to UninitializedObjectChecker.h.
  14. //
  15. //===----------------------------------------------------------------------===//
  16. #include "UninitializedObject.h"
  17. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  18. #include "clang/StaticAnalyzer/Core/Checker.h"
  19. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  20. #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
  21. using namespace clang;
  22. using namespace clang::ento;
  23. namespace {
  24. /// Represents a pointer or a reference field.
  25. class LocField final : public FieldNode {
  26. /// We'll store whether the pointee or the pointer itself is uninitialited.
  27. const bool IsDereferenced;
  28. public:
  29. LocField(const FieldRegion *FR, const bool IsDereferenced = true)
  30. : FieldNode(FR), IsDereferenced(IsDereferenced) {}
  31. virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
  32. if (IsDereferenced)
  33. Out << "uninitialized pointee ";
  34. else
  35. Out << "uninitialized pointer ";
  36. }
  37. virtual void printPrefix(llvm::raw_ostream &Out) const override {}
  38. virtual void printNode(llvm::raw_ostream &Out) const override {
  39. Out << getVariableName(getDecl());
  40. }
  41. virtual void printSeparator(llvm::raw_ostream &Out) const override {
  42. if (getDecl()->getType()->isPointerType())
  43. Out << "->";
  44. else
  45. Out << '.';
  46. }
  47. };
  48. /// Represents a nonloc::LocAsInteger or void* field, that point to objects, but
  49. /// needs to be casted back to its dynamic type for a correct note message.
  50. class NeedsCastLocField final : public FieldNode {
  51. QualType CastBackType;
  52. public:
  53. NeedsCastLocField(const FieldRegion *FR, const QualType &T)
  54. : FieldNode(FR), CastBackType(T) {}
  55. virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
  56. Out << "uninitialized pointee ";
  57. }
  58. virtual void printPrefix(llvm::raw_ostream &Out) const override {
  59. // If this object is a nonloc::LocAsInteger.
  60. if (getDecl()->getType()->isIntegerType())
  61. Out << "reinterpret_cast";
  62. // If this pointer's dynamic type is different then it's static type.
  63. else
  64. Out << "static_cast";
  65. Out << '<' << CastBackType.getAsString() << ">(";
  66. }
  67. virtual void printNode(llvm::raw_ostream &Out) const override {
  68. Out << getVariableName(getDecl()) << ')';
  69. }
  70. virtual void printSeparator(llvm::raw_ostream &Out) const override {
  71. Out << "->";
  72. }
  73. };
  74. /// Represents a Loc field that points to itself.
  75. class CyclicLocField final : public FieldNode {
  76. public:
  77. CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
  78. virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
  79. Out << "object references itself ";
  80. }
  81. virtual void printPrefix(llvm::raw_ostream &Out) const override {}
  82. virtual void printNode(llvm::raw_ostream &Out) const override {
  83. Out << getVariableName(getDecl());
  84. }
  85. virtual void printSeparator(llvm::raw_ostream &Out) const override {
  86. llvm_unreachable("CyclicLocField objects must be the last node of the "
  87. "fieldchain!");
  88. }
  89. };
  90. } // end of anonymous namespace
  91. // Utility function declarations.
  92. struct DereferenceInfo {
  93. const TypedValueRegion *R;
  94. const bool NeedsCastBack;
  95. const bool IsCyclic;
  96. DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
  97. : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
  98. };
  99. /// Dereferences \p FR and returns with the pointee's region, and whether it
  100. /// needs to be casted back to it's location type. If for whatever reason
  101. /// dereferencing fails, returns with None.
  102. static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
  103. const FieldRegion *FR);
  104. /// Returns whether \p T can be (transitively) dereferenced to a void pointer
  105. /// type (void*, void**, ...).
  106. static bool isVoidPointer(QualType T);
  107. //===----------------------------------------------------------------------===//
  108. // Methods for FindUninitializedFields.
  109. //===----------------------------------------------------------------------===//
  110. bool FindUninitializedFields::isDereferencableUninit(
  111. const FieldRegion *FR, FieldChainInfo LocalChain) {
  112. SVal V = State->getSVal(FR);
  113. assert((isDereferencableType(FR->getDecl()->getType()) ||
  114. V.getAs<nonloc::LocAsInteger>()) &&
  115. "This method only checks dereferenceable objects!");
  116. if (V.isUnknown() || V.getAs<loc::ConcreteInt>()) {
  117. IsAnyFieldInitialized = true;
  118. return false;
  119. }
  120. if (V.isUndef()) {
  121. return addFieldToUninits(
  122. LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
  123. }
  124. if (!Opts.CheckPointeeInitialization) {
  125. IsAnyFieldInitialized = true;
  126. return false;
  127. }
  128. // At this point the pointer itself is initialized and points to a valid
  129. // location, we'll now check the pointee.
  130. llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
  131. if (!DerefInfo) {
  132. IsAnyFieldInitialized = true;
  133. return false;
  134. }
  135. if (DerefInfo->IsCyclic)
  136. return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
  137. const TypedValueRegion *R = DerefInfo->R;
  138. const bool NeedsCastBack = DerefInfo->NeedsCastBack;
  139. QualType DynT = R->getLocationType();
  140. QualType PointeeT = DynT->getPointeeType();
  141. if (PointeeT->isStructureOrClassType()) {
  142. if (NeedsCastBack)
  143. return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
  144. return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
  145. }
  146. if (PointeeT->isUnionType()) {
  147. if (isUnionUninit(R)) {
  148. if (NeedsCastBack)
  149. return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
  150. R);
  151. return addFieldToUninits(LocalChain.add(LocField(FR)), R);
  152. } else {
  153. IsAnyFieldInitialized = true;
  154. return false;
  155. }
  156. }
  157. if (PointeeT->isArrayType()) {
  158. IsAnyFieldInitialized = true;
  159. return false;
  160. }
  161. assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
  162. "At this point FR must either have a primitive dynamic type, or it "
  163. "must be a null, undefined, unknown or concrete pointer!");
  164. SVal PointeeV = State->getSVal(R);
  165. if (isPrimitiveUninit(PointeeV)) {
  166. if (NeedsCastBack)
  167. return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
  168. return addFieldToUninits(LocalChain.add(LocField(FR)), R);
  169. }
  170. IsAnyFieldInitialized = true;
  171. return false;
  172. }
  173. //===----------------------------------------------------------------------===//
  174. // Utility functions.
  175. //===----------------------------------------------------------------------===//
  176. static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
  177. const FieldRegion *FR) {
  178. llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
  179. SVal V = State->getSVal(FR);
  180. assert(V.getAsRegion() && "V must have an underlying region!");
  181. // If the static type of the field is a void pointer, or it is a
  182. // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
  183. // dereferencing.
  184. bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()) ||
  185. V.getAs<nonloc::LocAsInteger>();
  186. // The region we'd like to acquire.
  187. const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
  188. if (!R)
  189. return None;
  190. VisitedRegions.insert(R);
  191. // We acquire the dynamic type of R,
  192. QualType DynT = R->getLocationType();
  193. while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
  194. R = Tmp->getAs<TypedValueRegion>();
  195. if (!R)
  196. return None;
  197. // We found a cyclic pointer, like int *ptr = (int *)&ptr.
  198. if (!VisitedRegions.insert(R).second)
  199. return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
  200. DynT = R->getLocationType();
  201. // In order to ensure that this loop terminates, we're also checking the
  202. // dynamic type of R, since type hierarchy is finite.
  203. if (isDereferencableType(DynT->getPointeeType()))
  204. break;
  205. }
  206. while (isa<CXXBaseObjectRegion>(R)) {
  207. NeedsCastBack = true;
  208. const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
  209. if (!SuperR)
  210. break;
  211. R = SuperR;
  212. }
  213. return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
  214. }
  215. static bool isVoidPointer(QualType T) {
  216. while (!T.isNull()) {
  217. if (T->isVoidPointerType())
  218. return true;
  219. T = T->getPointeeType();
  220. }
  221. return false;
  222. }