Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp +++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp @@ -225,7 +225,6 @@ // Note that we don't have a method for arrays -- the elements of an array are // often left uninitialized intentionally even when it is of a C++ record // type, so we'll assume that an array is always initialized. - // TODO: Add a support for nonloc::LocAsInteger. }; } // end of anonymous namespace @@ -268,6 +267,12 @@ /// even if Field is a captured lambda variable. static StringRef getVariableName(const FieldDecl *Field); +/// Returns with "reinterpret_cast" if Field is an integer (meaning that it is a +/// nonloc::LocAsInteger), or with "static_cast" otherwise. +/// +/// This function doesn't check whether Field really needs to be casted back. +static StringRef getCastTypeAsString(const FieldDecl *Field); + //===----------------------------------------------------------------------===// // Methods for UninitializedObjectChecker. //===----------------------------------------------------------------------===// @@ -425,15 +430,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, FR})) ContainsUninitField = true; @@ -485,12 +491,23 @@ 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 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 = false; + + if (auto LocAsInt = V.getAs()) { + NeedsCastBack = true; + V = LocAsInt->getLoc(); + } + if (V.isUnknown() || V.getAs()) { IsAnyFieldInitialized = true; return false; @@ -521,9 +538,7 @@ } QualType DynT = DynTInfo.getType(); - // If the static type of the field is a void pointer, we need to cast it back - // to the dynamic type before dereferencing. - bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType()); + NeedsCastBack = (NeedsCastBack || isVoidPointer(FR->getDecl()->getType())); if (isVoidPointer(DynT)) { IsAnyFieldInitialized = true; @@ -565,7 +580,8 @@ if (DynT->getPointeeType()->isStructureOrClassType()) { if (NeedsCastBack) - return isNonUnionUninit(R, {LocalChain, FR, /*IsDereferenced */false, DynT}); + return isNonUnionUninit( + R, {LocalChain, FR, /*IsDereferenced */ false, DynT}); return isNonUnionUninit(R, {LocalChain, FR}); } @@ -635,7 +651,16 @@ bool FieldChainInfo::isPointer() const { assert(!Chain.isEmpty() && "Empty fieldchain!"); - return (*Chain.begin())->getDecl()->getType()->isPointerType(); + + const QualType &T = (*Chain.begin())->getDecl()->getType(); + + // If the field is a nonloc::LocAsInteger, we'll also return true. + if (const CastBacksListImpl *C = CastBacks.getInternalPointer()) { + if (Chain.getInternalPointer() == C->getHead().second && T->isIntegerType()) + return true; + } + + return T->isPointerType(); } bool FieldChainInfo::isDereferenced() const { @@ -679,8 +704,8 @@ // casted back. if (C && L == C->getHead().second) { printTail(Out, L->getTail(), C->getTail()); - Out << "static_cast<" << C->getHead().first.getAsString() << ">(" - << getVariableName(Field) << ')'; + Out << getCastTypeAsString(Field) << "<" << C->getHead().first.getAsString() + << ">(" << getVariableName(Field) << ')'; } else { printTail(Out, L->getTail(), C); Out << getVariableName(Field); @@ -701,10 +726,10 @@ printTail(Out, L->getTail(), C); const FieldDecl *Field = L->getHead()->getDecl(); - + if (C && L == C->getHead().second) - Out << "static_cast<" << C->getHead().first.getAsString() << ">(" - << getVariableName(Field) << ')'; + Out << getCastTypeAsString(Field) << "<" << C->getHead().first.getAsString() + << ">(" << getVariableName(Field) << ')'; else Out << getVariableName(Field); Out << (Field->getType()->isPointerType() ? "->" : "."); @@ -780,6 +805,10 @@ return Field->getName(); } +static StringRef getCastTypeAsString(const FieldDecl *Field) { + return Field->getType()->isIntegerType() ? "reinterpret_cast" : "static_cast"; +} + void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) { auto Chk = Mgr.registerChecker(); Chk->IsPedantic = Mgr.getAnalyzerOptions().getBooleanOption( 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 @@ -17,6 +17,24 @@ } //===----------------------------------------------------------------------===// +// nonloc::LocAsInteger tests. +//===----------------------------------------------------------------------===// + +using intptr_t = long; + +struct LocAsIntegerTest { + intptr_t ptr; // expected-note{{uninitialized pointee 'this->reinterpret_cast(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. //===----------------------------------------------------------------------===// @@ -327,7 +345,7 @@ NestedNonVoidDynTypedVoidPointerTest(void *vptr, void *c) : vptr(vptr) { static_cast(vptr)->vptr = c; // expected-warning{{3 uninitialized fields}} - } + } }; void fNestedNonVoidDynTypedVoidPointerTest() {