Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp +++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp @@ -259,15 +259,16 @@ continue; } - if (T->isPointerType() || T->isReferenceType()) { + SVal V = State->getSVal(FieldVal); + + if (T->isPointerType() || T->isReferenceType() || + V.getAs()) { if (isPointerOrReferenceUninit(FR, LocalChain)) ContainsUninitField = true; continue; } if (isPrimitiveType(T)) { - SVal V = State->getSVal(FieldVal); - if (isPrimitiveUninit(V)) { if (addFieldToUninits(LocalChain.add(RegularField(FR)))) ContainsUninitField = true; Index: lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp +++ lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp @@ -60,8 +60,8 @@ } }; -/// Represents a void* field that needs to be casted back to its dynamic type -/// for a correct note message. +/// Represents a nonloc::LocAsInteger or void* field, that point to objects, but +/// needs to be casted back to its dynamic type for a correct note message. class NeedsCastLocField : public FieldNode { QualType CastBackType; @@ -74,7 +74,13 @@ } virtual void printPrefix(llvm::raw_ostream &Out) const override { - Out << "static_cast" << '<' << CastBackType.getAsString() << ">("; + // If this object is a nonloc::LocAsInteger. + if (getDecl()->getType()->isIntegerType()) + Out << "reinterpret_cast"; + // If this pointer's dynamic type is different then it's static type. + else + Out << "static_cast"; + Out << '<' << CastBackType.getAsString() << ">("; } virtual void printNode(llvm::raw_ostream &Out) const { @@ -95,29 +101,29 @@ /// known, and thus FD can not be analyzed. static bool isVoidPointer(QualType T); -/// Dereferences V, stores the dereferenced value back into it, and stores it's -/// dynamic type in DynT. +/// Dereferences V, stores the dereferenced value back into it, it's dynamic +/// type in DynT, and whether it needs to be casted back in NeedsCastBack. /// /// V must be loc::MemRegionVal. /// /// If for whatever reason dereferencing fails, returns with false. -static bool dereference(ProgramStateRef State, SVal &V, QualType &DynT); +static bool dereference(ProgramStateRef State, SVal &V, QualType &DynT, + bool &NeedsCastBack); //===----------------------------------------------------------------------===// // Methods for FindUninitializedFields. //===----------------------------------------------------------------------===// -// Note that pointers/references don't contain fields themselves, so in this -// function we won't add anything to LocalChain. bool FindUninitializedFields::isPointerOrReferenceUninit( const FieldRegion *FR, FieldChainInfo LocalChain) { - assert((FR->getDecl()->getType()->isPointerType() || - FR->getDecl()->getType()->isReferenceType()) && - "This method only checks pointer/reference objects!"); - SVal V = State->getSVal(FR); + assert((FR->getDecl()->getType()->isPointerType() || + FR->getDecl()->getType()->isReferenceType() || + V.getAs()) && + "This method only checks pointer/reference or LocAsInteger objects!"); + if (V.isUnknown() || V.getAs()) { IsAnyFieldInitialized = true; return false; @@ -133,18 +139,16 @@ return false; } - assert(V.getAs() && - "At this point V must be loc::MemRegionVal!"); - - // If the static type of the field is a void pointer, we need to cast it back - // to the dynamic type before dereferencing. + // If the static type of the field is a void pointer or is a + // nonloc::LocAsInteger, we need to cast it back to the dynamic type before + // dereferencing. bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()); QualType DynT; // At this point the pointer itself is initialized and points to a valid // location, we'll now check the pointee. - if (!dereference(State, V, DynT)) { + if (!dereference(State, V, DynT, NeedsCastBack)) { IsAnyFieldInitialized = true; return false; } @@ -208,7 +212,13 @@ return false; } -static bool dereference(ProgramStateRef State, SVal &V, QualType &DynT) { +static bool dereference(ProgramStateRef State, SVal &V, QualType &DynT, + bool &NeedsCastBack) { + if (auto LocAsInt = V.getAs()) { + NeedsCastBack = true; + V = LocAsInt->getLoc(); + } + // If V is multiple pointer value, we'll dereference it again (e.g.: int** -> // int*). while (auto Tmp = V.getAs()) { @@ -233,6 +243,9 @@ } V = State->getSVal(*Tmp, DynT); + // TODO: Handle the case where V is nonloc::LocAsInteger, while avoiding + // infinite loops in the following sinister case: + // int *ptr = reinterpret_cast(ptr); } return true; } 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 @@ -22,6 +22,24 @@ } //===----------------------------------------------------------------------===// +// nonloc::LocAsInteger tests. +//===----------------------------------------------------------------------===// + +using intptr_t = long; + +struct LocAsIntegerTest { + intptr_t ptr; // expected-note{{uninitialized pointee 'reinterpret_cast(this->ptr)'}} + int dontGetFilteredByNonPedanticMode = 0; + + LocAsIntegerTest(void *ptr) : ptr(reinterpret_cast(ptr)) {} // expected-warning{{1 uninitialized field}} +}; + +void fLocAsIntegerTest() { + char c; + LocAsIntegerTest t(&c); +} + +//===----------------------------------------------------------------------===// // Null pointer tests. //===----------------------------------------------------------------------===//