Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h =================================================================== --- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h +++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h @@ -238,6 +238,19 @@ // type, so we'll assume that an array is always initialized. // TODO: Add a support for nonloc::LocAsInteger. + struct DereferenceInfo { + const TypedValueRegion *R; + const bool NeedsCastBack; + const bool IsCyclic; + DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC) + : R(R), NeedsCastBack(NCB), IsCyclic(IC) {} + }; + /// Dereferences \p FR and returns with the pointee's region, and whether it + /// needs to be casted back to it's location type. If for whatever reason + /// dereferencing fails, returns with None. + llvm::Optional dereference(ProgramStateRef State, + const FieldRegion *FR); + /// Processes LocalChain and attempts to insert it into UninitFields. Returns /// true on success. /// Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp +++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp @@ -86,6 +86,28 @@ } }; +/// Represents a Loc field that points to itself. +class CyclicLocField final : public FieldNode { + +public: + CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {} + + virtual void printNoteMsg(llvm::raw_ostream &Out) const override { + Out << "object references itself "; + } + + virtual void printPrefix(llvm::raw_ostream &Out) const override {} + + virtual void printNode(llvm::raw_ostream &Out) const override { + Out << getVariableName(getDecl()); + } + + virtual void printSeparator(llvm::raw_ostream &Out) const override { + llvm_unreachable("CyclicLocField objects must be the last node of the " + "fieldchain!"); + } +}; + } // end of anonymous namespace // Utility function declarations. @@ -95,14 +117,6 @@ /// known, and thus FD can not be analyzed. static bool isVoidPointer(QualType T); -using DereferenceInfo = std::pair; - -/// Dereferences \p FR and returns with the pointee's region, and whether it -/// needs to be casted back to it's location type. If for whatever reason -/// dereferencing fails, returns with None. -static llvm::Optional dereference(ProgramStateRef State, - const FieldRegion *FR); - //===----------------------------------------------------------------------===// // Methods for FindUninitializedFields. //===----------------------------------------------------------------------===// @@ -142,8 +156,11 @@ return false; } - const TypedValueRegion *R = DerefInfo->first; - const bool NeedsCastBack = DerefInfo->second; + if (DerefInfo->IsCyclic) + return addFieldToUninits(LocalChain.add(CyclicLocField(FR))); + + const TypedValueRegion *R = DerefInfo->R; + const bool NeedsCastBack = DerefInfo->NeedsCastBack; QualType DynT = R->getLocationType(); QualType PointeeT = DynT->getPointeeType(); @@ -186,21 +203,9 @@ return false; } -//===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -static bool isVoidPointer(QualType T) { - while (!T.isNull()) { - if (T->isVoidPointerType()) - return true; - T = T->getPointeeType(); - } - return false; -} - -static llvm::Optional dereference(ProgramStateRef State, - const FieldRegion *FR) { +llvm::Optional +FindUninitializedFields::dereference(ProgramStateRef State, + const FieldRegion *FR) { llvm::SmallSet VisitedRegions; @@ -224,14 +229,12 @@ while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) { R = Tmp->getAs(); - if (!R) return None; // We found a cyclic pointer, like int *ptr = (int *)&ptr. - // TODO: Report these fields too. if (!VisitedRegions.insert(R).second) - return None; + return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true}; DynT = R->getLocationType(); // In order to ensure that this loop terminates, we're also checking the @@ -245,5 +248,18 @@ R = R->getSuperRegion()->getAs(); } - return std::make_pair(R, NeedsCastBack); + return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false}; +} + +//===----------------------------------------------------------------------===// +// Utility functions. +//===----------------------------------------------------------------------===// + +static bool isVoidPointer(QualType T) { + while (!T.isNull()) { + if (T->isVoidPointerType()) + return true; + T = T->getPointeeType(); + } + return false; } Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp =================================================================== --- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp +++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp @@ -239,8 +239,10 @@ } struct CyclicPointerTest1 { - int *ptr; - CyclicPointerTest1() : ptr(reinterpret_cast(&ptr)) {} + int *ptr; // expected-note{{object references itself 'this->ptr'}} + int dontGetFilteredByNonPedanticMode = 0; + + CyclicPointerTest1() : ptr(reinterpret_cast(&ptr)) {} // expected-warning{{1 uninitialized field}} }; void fCyclicPointerTest1() { @@ -248,8 +250,10 @@ } struct CyclicPointerTest2 { - int **pptr; // no-crash - CyclicPointerTest2() : pptr(reinterpret_cast(&pptr)) {} + int **pptr; // expected-note{{object references itself 'this->pptr'}} + int dontGetFilteredByNonPedanticMode = 0; + + CyclicPointerTest2() : pptr(reinterpret_cast(&pptr)) {} // expected-warning{{1 uninitialized field}} }; void fCyclicPointerTest2() { @@ -335,9 +339,10 @@ } struct CyclicVoidPointerTest { - void *vptr; // no-crash + void *vptr; // expected-note{{object references itself 'this->vptr'}} + int dontGetFilteredByNonPedanticMode = 0; - CyclicVoidPointerTest() : vptr(&vptr) {} + CyclicVoidPointerTest() : vptr(&vptr) {} // expected-warning{{1 uninitialized field}} }; void fCyclicVoidPointerTest() {