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