1ceb5f654SKristof Umann //===----- UninitializedPointee.cpp ------------------------------*- C++ -*-==//
256963aecSKristof Umann //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
656963aecSKristof Umann //
756963aecSKristof Umann //===----------------------------------------------------------------------===//
856963aecSKristof Umann //
956963aecSKristof Umann // This file defines functions and methods for handling pointers and references
1056963aecSKristof Umann // to reduce the size and complexity of UninitializedObjectChecker.cpp.
1156963aecSKristof Umann //
126cec6c46SKristof Umann // To read about command line options and documentation about how the checker
136cec6c46SKristof Umann // works, refer to UninitializedObjectChecker.h.
1456963aecSKristof Umann //
1556963aecSKristof Umann //===----------------------------------------------------------------------===//
1656963aecSKristof Umann 
17a37bba47SKristof Umann #include "UninitializedObject.h"
1856963aecSKristof Umann #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1956963aecSKristof Umann #include "clang/StaticAnalyzer/Core/Checker.h"
2056963aecSKristof Umann #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21e4bf456fSCsaba Dabis #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
2256963aecSKristof Umann 
2356963aecSKristof Umann using namespace clang;
2456963aecSKristof Umann using namespace clang::ento;
2556963aecSKristof Umann 
26015b0595SKristof Umann namespace {
27015b0595SKristof Umann 
28015b0595SKristof Umann /// Represents a pointer or a reference field.
29651d683eSRichard Smith class LocField final : public FieldNode {
30015b0595SKristof Umann   /// We'll store whether the pointee or the pointer itself is uninitialited.
31015b0595SKristof Umann   const bool IsDereferenced;
32015b0595SKristof Umann 
33015b0595SKristof Umann public:
LocField(const FieldRegion * FR,const bool IsDereferenced=true)34015b0595SKristof Umann   LocField(const FieldRegion *FR, const bool IsDereferenced = true)
35015b0595SKristof Umann       : FieldNode(FR), IsDereferenced(IsDereferenced) {}
36015b0595SKristof Umann 
printNoteMsg(llvm::raw_ostream & Out) const37*a210f404SKazu Hirata   void printNoteMsg(llvm::raw_ostream &Out) const override {
38015b0595SKristof Umann     if (IsDereferenced)
39015b0595SKristof Umann       Out << "uninitialized pointee ";
40015b0595SKristof Umann     else
41015b0595SKristof Umann       Out << "uninitialized pointer ";
42015b0595SKristof Umann   }
43015b0595SKristof Umann 
printPrefix(llvm::raw_ostream & Out) const44*a210f404SKazu Hirata   void printPrefix(llvm::raw_ostream &Out) const override {}
45015b0595SKristof Umann 
printNode(llvm::raw_ostream & Out) const46*a210f404SKazu Hirata   void printNode(llvm::raw_ostream &Out) const override {
47015b0595SKristof Umann     Out << getVariableName(getDecl());
48015b0595SKristof Umann   }
49015b0595SKristof Umann 
printSeparator(llvm::raw_ostream & Out) const50*a210f404SKazu Hirata   void printSeparator(llvm::raw_ostream &Out) const override {
51015b0595SKristof Umann     if (getDecl()->getType()->isPointerType())
52015b0595SKristof Umann       Out << "->";
53015b0595SKristof Umann     else
54015b0595SKristof Umann       Out << '.';
55015b0595SKristof Umann   }
56015b0595SKristof Umann };
57015b0595SKristof Umann 
58f051379fSKristof Umann /// Represents a nonloc::LocAsInteger or void* field, that point to objects, but
59f051379fSKristof Umann /// needs to be casted back to its dynamic type for a correct note message.
6088ad9cf7SIlya Biryukov class NeedsCastLocField final : public FieldNode {
615a42441dSKristof Umann   QualType CastBackType;
625a42441dSKristof Umann 
635a42441dSKristof Umann public:
NeedsCastLocField(const FieldRegion * FR,const QualType & T)645a42441dSKristof Umann   NeedsCastLocField(const FieldRegion *FR, const QualType &T)
655a42441dSKristof Umann       : FieldNode(FR), CastBackType(T) {}
665a42441dSKristof Umann 
printNoteMsg(llvm::raw_ostream & Out) const67*a210f404SKazu Hirata   void printNoteMsg(llvm::raw_ostream &Out) const override {
685a42441dSKristof Umann     Out << "uninitialized pointee ";
695a42441dSKristof Umann   }
705a42441dSKristof Umann 
printPrefix(llvm::raw_ostream & Out) const71*a210f404SKazu Hirata   void printPrefix(llvm::raw_ostream &Out) const override {
72f051379fSKristof Umann     // If this object is a nonloc::LocAsInteger.
73f051379fSKristof Umann     if (getDecl()->getType()->isIntegerType())
74f051379fSKristof Umann       Out << "reinterpret_cast";
75f051379fSKristof Umann     // If this pointer's dynamic type is different then it's static type.
76f051379fSKristof Umann     else
77f051379fSKristof Umann       Out << "static_cast";
78f051379fSKristof Umann     Out << '<' << CastBackType.getAsString() << ">(";
795a42441dSKristof Umann   }
805a42441dSKristof Umann 
printNode(llvm::raw_ostream & Out) const81*a210f404SKazu Hirata   void printNode(llvm::raw_ostream &Out) const override {
825a42441dSKristof Umann     Out << getVariableName(getDecl()) << ')';
835a42441dSKristof Umann   }
845a42441dSKristof Umann 
printSeparator(llvm::raw_ostream & Out) const85*a210f404SKazu Hirata   void printSeparator(llvm::raw_ostream &Out) const override { Out << "->"; }
865a42441dSKristof Umann };
875a42441dSKristof Umann 
888e5328b6SKristof Umann /// Represents a Loc field that points to itself.
898e5328b6SKristof Umann class CyclicLocField final : public FieldNode {
908e5328b6SKristof Umann 
918e5328b6SKristof Umann public:
CyclicLocField(const FieldRegion * FR)928e5328b6SKristof Umann   CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
938e5328b6SKristof Umann 
printNoteMsg(llvm::raw_ostream & Out) const94*a210f404SKazu Hirata   void printNoteMsg(llvm::raw_ostream &Out) const override {
958e5328b6SKristof Umann     Out << "object references itself ";
968e5328b6SKristof Umann   }
978e5328b6SKristof Umann 
printPrefix(llvm::raw_ostream & Out) const98*a210f404SKazu Hirata   void printPrefix(llvm::raw_ostream &Out) const override {}
998e5328b6SKristof Umann 
printNode(llvm::raw_ostream & Out) const100*a210f404SKazu Hirata   void printNode(llvm::raw_ostream &Out) const override {
1018e5328b6SKristof Umann     Out << getVariableName(getDecl());
1028e5328b6SKristof Umann   }
1038e5328b6SKristof Umann 
printSeparator(llvm::raw_ostream & Out) const104*a210f404SKazu Hirata   void printSeparator(llvm::raw_ostream &Out) const override {
1058e5328b6SKristof Umann     llvm_unreachable("CyclicLocField objects must be the last node of the "
1068e5328b6SKristof Umann                      "fieldchain!");
1078e5328b6SKristof Umann   }
1088e5328b6SKristof Umann };
1098e5328b6SKristof Umann 
110015b0595SKristof Umann } // end of anonymous namespace
111015b0595SKristof Umann 
11256963aecSKristof Umann // Utility function declarations.
11356963aecSKristof Umann 
1148e5328b6SKristof Umann struct DereferenceInfo {
1158e5328b6SKristof Umann   const TypedValueRegion *R;
1168e5328b6SKristof Umann   const bool NeedsCastBack;
1178e5328b6SKristof Umann   const bool IsCyclic;
DereferenceInfoDereferenceInfo1188e5328b6SKristof Umann   DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
1198e5328b6SKristof Umann       : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
1208e5328b6SKristof Umann };
121f0dd1016SKristof Umann 
122f0dd1016SKristof Umann /// Dereferences \p FR and returns with the pointee's region, and whether it
123f0dd1016SKristof Umann /// needs to be casted back to it's location type. If for whatever reason
124f0dd1016SKristof Umann /// dereferencing fails, returns with None.
125f0dd1016SKristof Umann static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
126f0dd1016SKristof Umann                                                    const FieldRegion *FR);
12764601965SKristof Umann 
1288e5328b6SKristof Umann /// Returns whether \p T can be (transitively) dereferenced to a void pointer
1298e5328b6SKristof Umann /// type (void*, void**, ...).
1308e5328b6SKristof Umann static bool isVoidPointer(QualType T);
1318e5328b6SKristof Umann 
13256963aecSKristof Umann //===----------------------------------------------------------------------===//
13356963aecSKristof Umann //                   Methods for FindUninitializedFields.
13456963aecSKristof Umann //===----------------------------------------------------------------------===//
13556963aecSKristof Umann 
isDereferencableUninit(const FieldRegion * FR,FieldChainInfo LocalChain)136ceb5f654SKristof Umann bool FindUninitializedFields::isDereferencableUninit(
13756963aecSKristof Umann     const FieldRegion *FR, FieldChainInfo LocalChain) {
13856963aecSKristof Umann 
13956963aecSKristof Umann   SVal V = State->getSVal(FR);
14056963aecSKristof Umann 
141f051379fSKristof Umann   assert((isDereferencableType(FR->getDecl()->getType()) ||
14296ccb690SBalazs Benics           isa<nonloc::LocAsInteger>(V)) &&
143b23ccecbSRaphael Isemann          "This method only checks dereferenceable objects!");
144f051379fSKristof Umann 
14596ccb690SBalazs Benics   if (V.isUnknown() || isa<loc::ConcreteInt>(V)) {
14656963aecSKristof Umann     IsAnyFieldInitialized = true;
14756963aecSKristof Umann     return false;
14856963aecSKristof Umann   }
14956963aecSKristof Umann 
15056963aecSKristof Umann   if (V.isUndef()) {
151015b0595SKristof Umann     return addFieldToUninits(
1524ff77699SKristof Umann         LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
15356963aecSKristof Umann   }
15456963aecSKristof Umann 
1556cec6c46SKristof Umann   if (!Opts.CheckPointeeInitialization) {
15656963aecSKristof Umann     IsAnyFieldInitialized = true;
15756963aecSKristof Umann     return false;
15856963aecSKristof Umann   }
15956963aecSKristof Umann 
16056963aecSKristof Umann   // At this point the pointer itself is initialized and points to a valid
16156963aecSKristof Umann   // location, we'll now check the pointee.
162f0dd1016SKristof Umann   llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
16364601965SKristof Umann   if (!DerefInfo) {
16456963aecSKristof Umann     IsAnyFieldInitialized = true;
16556963aecSKristof Umann     return false;
16656963aecSKristof Umann   }
16756963aecSKristof Umann 
1688e5328b6SKristof Umann   if (DerefInfo->IsCyclic)
1694ff77699SKristof Umann     return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
1708e5328b6SKristof Umann 
1718e5328b6SKristof Umann   const TypedValueRegion *R = DerefInfo->R;
1728e5328b6SKristof Umann   const bool NeedsCastBack = DerefInfo->NeedsCastBack;
17356963aecSKristof Umann 
174f0dd1016SKristof Umann   QualType DynT = R->getLocationType();
175f0dd1016SKristof Umann   QualType PointeeT = DynT->getPointeeType();
17656963aecSKristof Umann 
177f0dd1016SKristof Umann   if (PointeeT->isStructureOrClassType()) {
1785a42441dSKristof Umann     if (NeedsCastBack)
1795a42441dSKristof Umann       return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
180015b0595SKristof Umann     return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
1815a42441dSKristof Umann   }
18256963aecSKristof Umann 
183f0dd1016SKristof Umann   if (PointeeT->isUnionType()) {
18456963aecSKristof Umann     if (isUnionUninit(R)) {
1855a42441dSKristof Umann       if (NeedsCastBack)
1864ff77699SKristof Umann         return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
1874ff77699SKristof Umann                                  R);
1884ff77699SKristof Umann       return addFieldToUninits(LocalChain.add(LocField(FR)), R);
18956963aecSKristof Umann     } else {
19056963aecSKristof Umann       IsAnyFieldInitialized = true;
19156963aecSKristof Umann       return false;
19256963aecSKristof Umann     }
19356963aecSKristof Umann   }
19456963aecSKristof Umann 
195f0dd1016SKristof Umann   if (PointeeT->isArrayType()) {
19656963aecSKristof Umann     IsAnyFieldInitialized = true;
19756963aecSKristof Umann     return false;
19856963aecSKristof Umann   }
19956963aecSKristof Umann 
200f0dd1016SKristof Umann   assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
20156963aecSKristof Umann          "At this point FR must either have a primitive dynamic type, or it "
20256963aecSKristof Umann          "must be a null, undefined, unknown or concrete pointer!");
20356963aecSKristof Umann 
204f0dd1016SKristof Umann   SVal PointeeV = State->getSVal(R);
205f0dd1016SKristof Umann 
206f0dd1016SKristof Umann   if (isPrimitiveUninit(PointeeV)) {
2075a42441dSKristof Umann     if (NeedsCastBack)
2084ff77699SKristof Umann       return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
2094ff77699SKristof Umann     return addFieldToUninits(LocalChain.add(LocField(FR)), R);
2105a42441dSKristof Umann   }
21156963aecSKristof Umann 
21256963aecSKristof Umann   IsAnyFieldInitialized = true;
21356963aecSKristof Umann   return false;
21456963aecSKristof Umann }
21556963aecSKristof Umann 
21656963aecSKristof Umann //===----------------------------------------------------------------------===//
21756963aecSKristof Umann //                           Utility functions.
21856963aecSKristof Umann //===----------------------------------------------------------------------===//
21956963aecSKristof Umann 
dereference(ProgramStateRef State,const FieldRegion * FR)220f0dd1016SKristof Umann static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
221f0dd1016SKristof Umann                                                    const FieldRegion *FR) {
22264601965SKristof Umann 
223f0dd1016SKristof Umann   llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
22464601965SKristof Umann 
22564601965SKristof Umann   SVal V = State->getSVal(FR);
226f0dd1016SKristof Umann   assert(V.getAsRegion() && "V must have an underlying region!");
22764601965SKristof Umann 
228f051379fSKristof Umann   // If the static type of the field is a void pointer, or it is a
229f051379fSKristof Umann   // nonloc::LocAsInteger, we need to cast it back to the dynamic type before
230f051379fSKristof Umann   // dereferencing.
23196ccb690SBalazs Benics   bool NeedsCastBack =
23296ccb690SBalazs Benics       isVoidPointer(FR->getDecl()->getType()) || isa<nonloc::LocAsInteger>(V);
233f051379fSKristof Umann 
234f0dd1016SKristof Umann   // The region we'd like to acquire.
235f0dd1016SKristof Umann   const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
236f0dd1016SKristof Umann   if (!R)
23764601965SKristof Umann     return None;
23864601965SKristof Umann 
239f0dd1016SKristof Umann   VisitedRegions.insert(R);
240f0dd1016SKristof Umann 
241f0dd1016SKristof Umann   // We acquire the dynamic type of R,
242f0dd1016SKristof Umann   QualType DynT = R->getLocationType();
243f0dd1016SKristof Umann 
244f0dd1016SKristof Umann   while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
245f0dd1016SKristof Umann 
246f0dd1016SKristof Umann     R = Tmp->getAs<TypedValueRegion>();
247f0dd1016SKristof Umann     if (!R)
24864601965SKristof Umann       return None;
24964601965SKristof Umann 
250f0dd1016SKristof Umann     // We found a cyclic pointer, like int *ptr = (int *)&ptr.
251f0dd1016SKristof Umann     if (!VisitedRegions.insert(R).second)
2528e5328b6SKristof Umann       return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
253f0dd1016SKristof Umann 
254f0dd1016SKristof Umann     DynT = R->getLocationType();
255f0dd1016SKristof Umann     // In order to ensure that this loop terminates, we're also checking the
256f0dd1016SKristof Umann     // dynamic type of R, since type hierarchy is finite.
257f0dd1016SKristof Umann     if (isDereferencableType(DynT->getPointeeType()))
258f0dd1016SKristof Umann       break;
25964601965SKristof Umann   }
26064601965SKristof Umann 
261630f7dafSArtem Dergachev   while (isa<CXXBaseObjectRegion>(R)) {
2623ef3dd7cSKristof Umann     NeedsCastBack = true;
263630f7dafSArtem Dergachev     const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
264630f7dafSArtem Dergachev     if (!SuperR)
2653ef3dd7cSKristof Umann       break;
266630f7dafSArtem Dergachev 
267630f7dafSArtem Dergachev     R = SuperR;
2683ef3dd7cSKristof Umann   }
2693ef3dd7cSKristof Umann 
2708e5328b6SKristof Umann   return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
2718e5328b6SKristof Umann }
2728e5328b6SKristof Umann 
isVoidPointer(QualType T)2738e5328b6SKristof Umann static bool isVoidPointer(QualType T) {
2748e5328b6SKristof Umann   while (!T.isNull()) {
2758e5328b6SKristof Umann     if (T->isVoidPointerType())
2768e5328b6SKristof Umann       return true;
2778e5328b6SKristof Umann     T = T->getPointeeType();
2788e5328b6SKristof Umann   }
2798e5328b6SKristof Umann   return false;
28064601965SKristof Umann }
281