UninitializedPointee.cpp 8.7 KB

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