diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h @@ -26,6 +26,12 @@ DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB); +/// Get the stored element count of the region \p MR. +DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State, + const MemRegion *MR, + SValBuilder &SVB, + QualType ElementTy); + } // namespace ento } // namespace clang diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -148,14 +148,6 @@ virtual SVal getLValueElement(QualType elementType, NonLoc offset, SVal Base); - // FIXME: This should soon be eliminated altogether; clients should deal with - // region extents directly. - virtual DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, - const MemRegion *region, - QualType EleTy) { - return UnknownVal(); - } - /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit /// conversions between arrays and pointers. virtual SVal ArrayToPointer(Loc Array, QualType ElementTy) = 0; diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" using namespace clang; @@ -54,12 +55,11 @@ ProgramStateRef state = C.getState(); // Get the size of the array. - DefinedOrUnknownSVal NumElements - = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), - ER->getValueType()); + DefinedOrUnknownSVal ElementCount = getDynamicElementCount( + state, ER->getSuperRegion(), C.getSValBuilder(), ER->getValueType()); - ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); - ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); + ProgramStateRef StInBound = state->assumeInBound(Idx, ElementCount, true); + ProgramStateRef StOutBound = state->assumeInBound(Idx, ElementCount, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateErrorNode(StOutBound); if (!N) diff --git a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp @@ -16,6 +16,7 @@ #include "MPIChecker.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" namespace clang { namespace ento { @@ -160,10 +161,11 @@ return; } - const auto &Size = Ctx.getStoreManager().getSizeInElements( - Ctx.getState(), SuperRegion, + DefinedOrUnknownSVal ElementCount = getDynamicElementCount( + Ctx.getState(), SuperRegion, Ctx.getSValBuilder(), CE.getArgExpr(1)->getType()->getPointeeType()); - const llvm::APSInt &ArrSize = Size.getAs()->getValue(); + const llvm::APSInt &ArrSize = + ElementCount.getAs()->getValue(); for (size_t i = 0; i < ArrSize; ++i) { const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i); diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" using namespace clang; @@ -51,15 +52,14 @@ // pointer casts. if (Idx.isZeroConstant()) return; + // FIXME: All of this out-of-bounds checking should eventually be refactored // into a common place. + DefinedOrUnknownSVal ElementCount = getDynamicElementCount( + state, ER->getSuperRegion(), C.getSValBuilder(), ER->getValueType()); - DefinedOrUnknownSVal NumElements - = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), - ER->getValueType()); - - ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); - ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); + ProgramStateRef StInBound = state->assumeInBound(Idx, ElementCount, true); + ProgramStateRef StOutBound = state->assumeInBound(Idx, ElementCount, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateErrorNode(StOutBound); diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" @@ -50,10 +51,10 @@ return false; DefinedOrUnknownSVal Idx = ER->getIndex().castAs(); - DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements( - state, ER->getSuperRegion(), ER->getValueType()); - ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); - ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); + DefinedOrUnknownSVal ElementCount = getDynamicElementCount( + state, ER->getSuperRegion(), C.getSValBuilder(), ER->getValueType()); + ProgramStateRef StInBound = state->assumeInBound(Idx, ElementCount, true); + ProgramStateRef StOutBound = state->assumeInBound(Idx, ElementCount, false); return StOutBound && !StInBound; } diff --git a/clang/lib/StaticAnalyzer/Core/DynamicSize.cpp b/clang/lib/StaticAnalyzer/Core/DynamicSize.cpp --- a/clang/lib/StaticAnalyzer/Core/DynamicSize.cpp +++ b/clang/lib/StaticAnalyzer/Core/DynamicSize.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" +#include "clang/AST/Expr.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" @@ -26,5 +27,22 @@ return MR->getMemRegionManager().getStaticSize(MR, SVB); } +DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State, + const MemRegion *MR, + SValBuilder &SVB, + QualType ElementTy) { + MemRegionManager &MemMgr = MR->getMemRegionManager(); + ASTContext &Ctx = MemMgr.getContext(); + + DefinedOrUnknownSVal Size = getDynamicSize(State, MR, SVB); + SVal ElementSizeV = SVB.makeIntVal( + Ctx.getTypeSizeInChars(ElementTy).getQuantity(), SVB.getArrayIndexType()); + + SVal DivisionV = + SVB.evalBinOp(State, BO_Div, Size, ElementSizeV, SVB.getArrayIndexType()); + + return DivisionV.castAs(); +} + } // namespace ento } // namespace clang diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -623,15 +623,6 @@ SymbolReaper& SymReaper) override; //===------------------------------------------------------------------===// - // Region "extents". - //===------------------------------------------------------------------===// - - // FIXME: This method will soon be eliminated; see the note in Store.h. - DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, - const MemRegion* R, - QualType EleTy) override; - - //===------------------------------------------------------------------===// // Utility methods. //===------------------------------------------------------------------===// @@ -1388,37 +1379,6 @@ } //===----------------------------------------------------------------------===// -// Extents for regions. -//===----------------------------------------------------------------------===// - -DefinedOrUnknownSVal -RegionStoreManager::getSizeInElements(ProgramStateRef state, - const MemRegion *R, - QualType EleTy) { - DefinedOrUnknownSVal Size = getDynamicSize(state, R, svalBuilder); - const llvm::APSInt *SizeInt = svalBuilder.getKnownValue(state, Size); - if (!SizeInt) - return UnknownVal(); - - CharUnits RegionSize = CharUnits::fromQuantity(SizeInt->getSExtValue()); - - if (Ctx.getAsVariableArrayType(EleTy)) { - // FIXME: We need to track extra state to properly record the size - // of VLAs. Returning UnknownVal here, however, is a stop-gap so that - // we don't have a divide-by-zero below. - return UnknownVal(); - } - - CharUnits EleSize = Ctx.getTypeSizeInChars(EleTy); - - // If a variable is reinterpreted as a type that doesn't fit into a larger - // type evenly, round it down. - // This is a signed value, since it's used in arithmetic with signed indices. - return svalBuilder.makeIntVal(RegionSize / EleSize, - svalBuilder.getArrayIndexType()); -} - -//===----------------------------------------------------------------------===// // Location and region casting. //===----------------------------------------------------------------------===//