diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index ca75c2a756a4a..51d76dc257ee9 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -494,6 +494,8 @@ class ProgramState : public llvm::FoldingSetNode { InvalidatedSymbols *IS, RegionAndSymbolInvalidationTraits *HTraits, const CallEvent *Call) const; + + SVal wrapSymbolicRegion(SVal Base) const; }; //===----------------------------------------------------------------------===// @@ -782,20 +784,6 @@ inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const { return getStateManager().StoreMgr->getLValueIvar(D, Base); } -inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const { - return getStateManager().StoreMgr->getLValueField(D, Base); -} - -inline SVal ProgramState::getLValue(const IndirectFieldDecl *D, - SVal Base) const { - StoreManager &SM = *getStateManager().StoreMgr; - for (const auto *I : D->chain()) { - Base = SM.getLValueField(cast(I), Base); - } - - return Base; -} - inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ if (std::optional N = Idx.getAs()) return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base); diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index f12f1a5ac970d..f82cd944750a3 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -226,6 +226,20 @@ ProgramStateRef ProgramState::killBinding(Loc LV) const { return makeWithStore(newStore); } +/// SymbolicRegions are expected to be wrapped by an ElementRegion as a +/// canonical representation. As a canonical representation, SymbolicRegions +/// should be wrapped by ElementRegions before getting a FieldRegion. +/// See f8643a9b31c4029942f67d4534c9139b45173504 why. +SVal ProgramState::wrapSymbolicRegion(SVal Val) const { + const auto *BaseReg = dyn_cast_or_null(Val.getAsRegion()); + if (!BaseReg) + return Val; + + StoreManager &SM = getStateManager().getStoreManager(); + QualType ElemTy = BaseReg->getPointeeStaticType(); + return loc::MemRegionVal{SM.GetElementZeroRegion(BaseReg, ElemTy)}; +} + ProgramStateRef ProgramState::enterStackFrame(const CallEvent &Call, const StackFrameContext *CalleeCtx) const { @@ -451,6 +465,24 @@ void ProgramState::setStore(const StoreRef &newStore) { store = newStoreStore; } +SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const { + Base = wrapSymbolicRegion(Base); + return getStateManager().StoreMgr->getLValueField(D, Base); +} + +SVal ProgramState::getLValue(const IndirectFieldDecl *D, SVal Base) const { + StoreManager &SM = *getStateManager().StoreMgr; + Base = wrapSymbolicRegion(Base); + + // FIXME: This should work with `SM.getLValueField(D->getAnonField(), Base)`, + // but that would break some tests. There is probably a bug somewhere that it + // would expose. + for (const auto *I : D->chain()) { + Base = SM.getLValueField(cast(I), Base); + } + return Base; +} + //===----------------------------------------------------------------------===// // State pretty-printing. //===----------------------------------------------------------------------===// diff --git a/clang/test/Analysis/inlining/false-positive-suppression.cpp b/clang/test/Analysis/inlining/false-positive-suppression.cpp index 56659b4a1941c..2f9ed7f78b3f0 100644 --- a/clang/test/Analysis/inlining/false-positive-suppression.cpp +++ b/clang/test/Analysis/inlining/false-positive-suppression.cpp @@ -210,3 +210,20 @@ namespace Cleanups { testArgumentHelper(NonTrivial().getNull()); } } + +class Bear *getNullBear() { return nullptr; } +class Bear { +public: + void brum() const; +}; +class Door { +public: + Door() : ptr(getNullBear()) { + ptr->brum(); +#ifndef SUPPRESSED + // expected-warning@-2 {{Called C++ object pointer is null}} +#endif + } +private: + Bear* ptr; +};