diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h @@ -0,0 +1,32 @@ +//===- DynamicSize.h - Dynamic size related APIs ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines APIs that track and query dynamic size information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICSIZE_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICSIZE_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" + +namespace clang { +namespace ento { + +/// Get the stored dynamic size for the region \p MR. +DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR, + SValBuilder &SVB); + +} // namespace ento +} // namespace clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICSIZE_H diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -112,7 +112,7 @@ virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; - virtual MemRegionManager* getMemRegionManager() const = 0; + virtual MemRegionManager &getMemRegionManager() const = 0; const MemSpaceRegion *getMemorySpace() const; @@ -198,14 +198,13 @@ /// for example, the set of global variables, the stack frame, etc. class MemSpaceRegion : public MemRegion { protected: - MemRegionManager *Mgr; + MemRegionManager &Mgr; - MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) { + MemSpaceRegion(MemRegionManager &mgr, Kind k) : MemRegion(k), Mgr(mgr) { assert(classof(this)); - assert(mgr); } - MemRegionManager* getMemRegionManager() const override { return Mgr; } + MemRegionManager &getMemRegionManager() const override { return Mgr; } public: bool isBoundable() const override { return false; } @@ -223,7 +222,7 @@ class CodeSpaceRegion : public MemSpaceRegion { friend class MemRegionManager; - CodeSpaceRegion(MemRegionManager *mgr) + CodeSpaceRegion(MemRegionManager &mgr) : MemSpaceRegion(mgr, CodeSpaceRegionKind) {} public: @@ -238,7 +237,7 @@ virtual void anchor(); protected: - GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) : MemSpaceRegion(mgr, k) { + GlobalsSpaceRegion(MemRegionManager &mgr, Kind k) : MemSpaceRegion(mgr, k) { assert(classof(this)); } @@ -259,7 +258,7 @@ const CodeTextRegion *CR; - StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr) + StaticGlobalSpaceRegion(MemRegionManager &mgr, const CodeTextRegion *cr) : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) { assert(cr); } @@ -286,7 +285,7 @@ void anchor() override; protected: - NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k) + NonStaticGlobalSpaceRegion(MemRegionManager &mgr, Kind k) : GlobalsSpaceRegion(mgr, k) { assert(classof(this)); } @@ -304,7 +303,7 @@ class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion { friend class MemRegionManager; - GlobalSystemSpaceRegion(MemRegionManager *mgr) + GlobalSystemSpaceRegion(MemRegionManager &mgr) : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {} public: @@ -323,7 +322,7 @@ class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion { friend class MemRegionManager; - GlobalImmutableSpaceRegion(MemRegionManager *mgr) + GlobalImmutableSpaceRegion(MemRegionManager &mgr) : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {} public: @@ -340,7 +339,7 @@ class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion { friend class MemRegionManager; - GlobalInternalSpaceRegion(MemRegionManager *mgr) + GlobalInternalSpaceRegion(MemRegionManager &mgr) : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {} public: @@ -354,7 +353,7 @@ class HeapSpaceRegion : public MemSpaceRegion { friend class MemRegionManager; - HeapSpaceRegion(MemRegionManager *mgr) + HeapSpaceRegion(MemRegionManager &mgr) : MemSpaceRegion(mgr, HeapSpaceRegionKind) {} public: @@ -368,7 +367,7 @@ class UnknownSpaceRegion : public MemSpaceRegion { friend class MemRegionManager; - UnknownSpaceRegion(MemRegionManager *mgr) + UnknownSpaceRegion(MemRegionManager &mgr) : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} public: @@ -385,7 +384,7 @@ const StackFrameContext *SFC; protected: - StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) + StackSpaceRegion(MemRegionManager &mgr, Kind k, const StackFrameContext *sfc) : MemSpaceRegion(mgr, k), SFC(sfc) { assert(classof(this)); assert(sfc); @@ -405,7 +404,7 @@ class StackLocalsSpaceRegion : public StackSpaceRegion { friend class MemRegionManager; - StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + StackLocalsSpaceRegion(MemRegionManager &mgr, const StackFrameContext *sfc) : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} public: @@ -420,7 +419,7 @@ private: friend class MemRegionManager; - StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + StackArgumentsSpaceRegion(MemRegionManager &mgr, const StackFrameContext *sfc) : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} public: @@ -449,12 +448,7 @@ return superRegion; } - /// getExtent - Returns the size of the region in bytes. - virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const { - return UnknownVal(); - } - - MemRegionManager* getMemRegionManager() const override; + MemRegionManager &getMemRegionManager() const override; bool isSubRegionOf(const MemRegion* R) const override; @@ -491,8 +485,6 @@ bool isBoundable() const override { return true; } - DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; - void Profile(llvm::FoldingSetNodeID& ID) const override; void dumpToStream(raw_ostream &os) const override; @@ -552,8 +544,6 @@ return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T; } - DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; - static bool classof(const MemRegion* R) { unsigned k = R->getKind(); return k >= BEGIN_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS; @@ -782,8 +772,6 @@ bool isBoundable() const override { return true; } - DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; - void Profile(llvm::FoldingSetNodeID& ID) const override; static void ProfileRegion(llvm::FoldingSetNodeID& ID, @@ -817,8 +805,6 @@ QualType getValueType() const override { return Str->getType(); } - DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; - bool isBoundable() const override { return false; } void Profile(llvm::FoldingSetNodeID& ID) const override { @@ -1021,8 +1007,6 @@ return getDecl()->getType(); } - DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; - void dumpToStream(raw_ostream &os) const override; bool canPrintPretty() const override; @@ -1242,8 +1226,9 @@ //===----------------------------------------------------------------------===// class MemRegionManager { - ASTContext &C; + ASTContext &Ctx; llvm::BumpPtrAllocator& A; + llvm::FoldingSet Regions; GlobalInternalSpaceRegion *InternalGlobals = nullptr; @@ -1262,13 +1247,18 @@ CodeSpaceRegion *code = nullptr; public: - MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) : C(c), A(a) {} + MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) : Ctx(c), A(a) {} ~MemRegionManager(); - ASTContext &getContext() { return C; } + ASTContext &getContext() { return Ctx; } llvm::BumpPtrAllocator &getAllocator() { return A; } + /// \returns The static size in bytes of the region \p MR. + /// \note The region \p MR must be a 'SubRegion'. + DefinedOrUnknownSVal getStaticSize(const MemRegion *MR, + SValBuilder &SVB) const; + /// getStackLocalsRegion - Retrieve the memory region associated with the /// specified stack frame. const StackLocalsSpaceRegion * @@ -1434,7 +1424,7 @@ //===----------------------------------------------------------------------===// inline ASTContext &MemRegion::getContext() const { - return getMemRegionManager()->getContext(); + return getMemRegionManager().getContext(); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -12,13 +12,14 @@ //===----------------------------------------------------------------------===// #include "Taint.h" -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/CharUnits.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.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" @@ -175,24 +176,23 @@ } do { - // CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)? If so, + // CHECK UPPER BOUND: Is byteOffset >= size(baseRegion)? If so, // we are doing a load/store after the last valid offset. - DefinedOrUnknownSVal extentVal = - rawOffset.getRegion()->getExtent(svalBuilder); - if (!extentVal.getAs()) + const MemRegion *MR = rawOffset.getRegion(); + DefinedOrUnknownSVal Size = getDynamicSize(state, MR, svalBuilder); + if (!Size.getAs()) break; - if (extentVal.getAs()) { + if (Size.getAs()) { std::pair simplifiedOffsets = getSimplifiedOffsets(rawOffset.getByteOffset(), - extentVal.castAs(), - svalBuilder); + Size.castAs(), svalBuilder); rawOffsetVal = simplifiedOffsets.first; - extentVal = simplifiedOffsets.second; + Size = simplifiedOffsets.second; } SVal upperbound = svalBuilder.evalBinOpNN(state, BO_GE, rawOffsetVal, - extentVal.castAs(), + Size.castAs(), svalBuilder.getConditionType()); Optional upperboundToCheck = upperbound.getAs(); diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -10,12 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/Basic/Builtins.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" using namespace clang; using namespace ento; @@ -90,10 +91,10 @@ return true; // Return true to model purity. SValBuilder& svalBuilder = C.getSValBuilder(); - DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder); - DefinedOrUnknownSVal extentMatchesSizeArg = - svalBuilder.evalEQ(state, Extent, Size.castAs()); - state = state->assume(extentMatchesSizeArg, true); + DefinedOrUnknownSVal DynSize = getDynamicSize(state, R, svalBuilder); + DefinedOrUnknownSVal DynSizeMatchesSizeArg = + svalBuilder.evalEQ(state, DynSize, Size.castAs()); + state = state->assume(DynSizeMatchesSizeArg, true); assert(state && "The region should not have any previous constraints"); C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R))); diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -11,14 +11,15 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "InterCheckerAPI.h" #include "clang/Basic/CharInfo.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" @@ -327,10 +328,8 @@ // Get the size of the array. const SubRegion *superReg = cast(ER->getSuperRegion()); - SValBuilder &svalBuilder = C.getSValBuilder(); - SVal Extent = - svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); - DefinedOrUnknownSVal Size = Extent.castAs(); + DefinedOrUnknownSVal Size = + getDynamicSize(state, superReg, C.getSValBuilder()); // Get the index of the accessed element. DefinedOrUnknownSVal Idx = ER->getIndex().castAs(); @@ -935,14 +934,12 @@ // Get the size of the array. const SubRegion *superReg = cast(ER->getSuperRegion()); - SVal Extent = - svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); - DefinedOrUnknownSVal ExtentSize = Extent.castAs(); + DefinedOrUnknownSVal SizeDV = getDynamicSize(state, superReg, svalBuilder); // Get the index of the accessed element. DefinedOrUnknownSVal Idx = ER->getIndex().castAs(); - ProgramStateRef StInBound = state->assumeInBound(Idx, ExtentSize, true); + ProgramStateRef StInBound = state->assumeInBound(Idx, SizeDV, true); return static_cast(StInBound); } @@ -1069,13 +1066,12 @@ // For now we can only handle the case of offset is 0 and concrete char value. if (Offset.isValid() && !Offset.hasSymbolicOffset() && Offset.getOffset() == 0) { - // Get the base region's extent. - auto *SubReg = cast(BR); - DefinedOrUnknownSVal Extent = SubReg->getExtent(svalBuilder); + // Get the base region's size. + DefinedOrUnknownSVal SizeDV = getDynamicSize(State, BR, svalBuilder); ProgramStateRef StateWholeReg, StateNotWholeReg; std::tie(StateWholeReg, StateNotWholeReg) = - State->assume(svalBuilder.evalEQ(State, Extent, *SizeNL)); + State->assume(svalBuilder.evalEQ(State, SizeDV, *SizeNL)); // With the semantic of 'memset()', we should convert the CharVal to // unsigned char. diff --git a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -10,12 +10,14 @@ // whether the size of the symbolic region is a multiple of the size of T. // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" + #include "clang/AST/CharUnits.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #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" using namespace clang; using namespace ento; @@ -109,12 +111,13 @@ return; SValBuilder &svalBuilder = C.getSValBuilder(); - SVal extent = SR->getExtent(svalBuilder); - const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent); - if (!extentInt) + + DefinedOrUnknownSVal Size = getDynamicSize(state, SR, svalBuilder); + const llvm::APSInt *SizeInt = svalBuilder.getKnownValue(state, Size); + if (!SizeInt) return; - CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue()); + CharUnits regionSize = CharUnits::fromQuantity(SizeInt->getZExtValue()); CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy); // Ignore void, and a few other un-sizeable types. diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp --- a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp @@ -1,6 +1,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "llvm/Support/FormatVariadic.h" using namespace clang; @@ -42,7 +43,7 @@ NonLoc OffsetInBytes = SvalBuilder.makeArrayIndex( Offset.getOffset() / C.getASTContext().getCharWidth()); DefinedOrUnknownSVal ExtentInBytes = - BaseRegion->castAs()->getExtent(SvalBuilder); + getDynamicSize(State, BaseRegion, SvalBuilder); return SvalBuilder.evalBinOp(State, BinaryOperator::Opcode::BO_Sub, ExtentInBytes, OffsetInBytes, diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -13,6 +13,7 @@ #include "clang/StaticAnalyzer/Core/IssueHash.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ScopedPrinter.h" @@ -234,8 +235,9 @@ } ProgramStateRef State = C.getState(); - State = State->BindExpr(CE, C.getLocationContext(), - MR->getExtent(C.getSValBuilder())); + DefinedOrUnknownSVal Size = getDynamicSize(State, MR, C.getSValBuilder()); + + State = State->BindExpr(CE, C.getLocationContext(), Size); C.addTransition(State); } 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 @@ -146,7 +146,7 @@ llvm::SmallVector &ReqRegions, const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const { - MemRegionManager *const RegionManager = MR->getMemRegionManager(); + MemRegionManager &RegionManager = MR->getMemRegionManager(); if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) { const SubRegion *SuperRegion{nullptr}; @@ -168,7 +168,7 @@ for (size_t i = 0; i < ArrSize; ++i) { const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i); - const ElementRegion *const ER = RegionManager->getElementRegion( + const ElementRegion *const ER = RegionManager.getElementRegion( CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion, Ctx.getASTContext()); diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -57,6 +57,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" @@ -1402,15 +1403,16 @@ CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType); if (ElementCount.getAs()) { - DefinedOrUnknownSVal Extent = Region->getExtent(svalBuilder); + DefinedOrUnknownSVal DynSize = getDynamicSize(State, Region, svalBuilder); + // size in Bytes = ElementCount*TypeSize SVal SizeInBytes = svalBuilder.evalBinOpNN( State, BO_Mul, ElementCount.castAs(), svalBuilder.makeArrayIndex(TypeSize.getQuantity()), svalBuilder.getArrayIndexType()); - DefinedOrUnknownSVal extentMatchesSize = svalBuilder.evalEQ( - State, Extent, SizeInBytes.castAs()); - State = State->assume(extentMatchesSize, true); + DefinedOrUnknownSVal DynSizeMatchesSize = svalBuilder.evalEQ( + State, DynSize, SizeInBytes.castAs()); + State = State->assume(DynSizeMatchesSize, true); } return State; } @@ -1542,12 +1544,12 @@ return nullptr; if (Optional DefinedSize = Size.getAs()) { - SValBuilder &svalBuilder = C.getSValBuilder(); - DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder); - DefinedOrUnknownSVal extentMatchesSize = - svalBuilder.evalEQ(State, Extent, *DefinedSize); + DefinedOrUnknownSVal DynSize = getDynamicSize(State, R, svalBuilder); + + DefinedOrUnknownSVal DynSizeMatchesSize = + svalBuilder.evalEQ(State, DynSize, *DefinedSize); - State = State->assume(extentMatchesSize, true); + State = State->assume(DynSizeMatchesSize, true); assert(State); } diff --git a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -14,12 +14,13 @@ //===----------------------------------------------------------------------===// #include "Taint.h" -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/CharUnits.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #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 "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" @@ -165,13 +166,14 @@ SVal ArraySizeVal = svalBuilder.evalBinOpNN( state, BO_Mul, ArrayLength, EleSizeVal.castAs(), SizeTy); - // Finally, assume that the array's extent matches the given size. + // Finally, assume that the array's size matches the given size. const LocationContext *LC = C.getLocationContext(); - DefinedOrUnknownSVal Extent = - state->getRegion(VD, LC)->getExtent(svalBuilder); + DefinedOrUnknownSVal DynSize = + getDynamicSize(state, state->getRegion(VD, LC), svalBuilder); + DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs(); DefinedOrUnknownSVal sizeIsKnown = - svalBuilder.evalEQ(state, Extent, ArraySize); + svalBuilder.evalEQ(state, DynSize, ArraySize); state = state->assume(sizeIsKnown, true); // Assume should not fail at this point. diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -358,7 +358,7 @@ public: NoStoreFuncVisitor(const SubRegion *R, bugreporter::TrackingKind TKind) - : RegionOfInterest(R), MmrMgr(*R->getMemRegionManager()), + : RegionOfInterest(R), MmrMgr(R->getMemRegionManager()), SM(MmrMgr.getContext().getSourceManager()), PP(MmrMgr.getContext().getPrintingPolicy()), TKind(TKind) {} diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt --- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -16,6 +16,7 @@ CommonBugCategories.cpp ConstraintManager.cpp CoreEngine.cpp + DynamicSize.cpp DynamicType.cpp Environment.cpp ExplodedGraph.cpp diff --git a/clang/lib/StaticAnalyzer/Core/DynamicSize.cpp b/clang/lib/StaticAnalyzer/Core/DynamicSize.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/DynamicSize.cpp @@ -0,0 +1,30 @@ +//===- DynamicSize.cpp - Dynamic size related APIs --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines APIs that track and query dynamic size information. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" + +namespace clang { +namespace ento { + +DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR, + SValBuilder &SVB) { + return MR->getMemRegionManager().getStaticSize(MR, SVB); +} + +} // namespace ento +} // namespace clang diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -142,7 +142,7 @@ return false; } -MemRegionManager* SubRegion::getMemRegionManager() const { +MemRegionManager &SubRegion::getMemRegionManager() const { const SubRegion* r = this; do { const MemRegion *superRegion = r->getSuperRegion(); @@ -159,56 +159,6 @@ return SSR ? SSR->getStackFrame() : nullptr; } -//===----------------------------------------------------------------------===// -// Region extents. -//===----------------------------------------------------------------------===// - -DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const { - ASTContext &Ctx = svalBuilder.getContext(); - QualType T = getDesugaredValueType(Ctx); - - if (isa(T)) - return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this)); - if (T->isIncompleteType()) - return UnknownVal(); - - CharUnits size = Ctx.getTypeSizeInChars(T); - QualType sizeTy = svalBuilder.getArrayIndexType(); - return svalBuilder.makeIntVal(size.getQuantity(), sizeTy); -} - -DefinedOrUnknownSVal FieldRegion::getExtent(SValBuilder &svalBuilder) const { - // Force callers to deal with bitfields explicitly. - if (getDecl()->isBitField()) - return UnknownVal(); - - DefinedOrUnknownSVal Extent = DeclRegion::getExtent(svalBuilder); - - // A zero-length array at the end of a struct often stands for dynamically- - // allocated extra memory. - if (Extent.isZeroConstant()) { - QualType T = getDesugaredValueType(svalBuilder.getContext()); - - if (isa(T)) - return UnknownVal(); - } - - return Extent; -} - -DefinedOrUnknownSVal AllocaRegion::getExtent(SValBuilder &svalBuilder) const { - return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this)); -} - -DefinedOrUnknownSVal SymbolicRegion::getExtent(SValBuilder &svalBuilder) const { - return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this)); -} - -DefinedOrUnknownSVal StringRegion::getExtent(SValBuilder &svalBuilder) const { - return svalBuilder.makeIntVal(getStringLiteral()->getByteLength()+1, - svalBuilder.getArrayIndexType()); -} - ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg) : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {} @@ -717,11 +667,78 @@ // MemRegionManager methods. //===----------------------------------------------------------------------===// +static DefinedOrUnknownSVal getTypeSize(QualType Ty, ASTContext &Ctx, + SValBuilder &SVB) { + CharUnits Size = Ctx.getTypeSizeInChars(Ty); + QualType SizeTy = SVB.getArrayIndexType(); + return SVB.makeIntVal(Size.getQuantity(), SizeTy); +} + +DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR, + SValBuilder &SVB) const { + const auto *SR = cast(MR); + SymbolManager &SymMgr = SVB.getSymbolManager(); + + switch (SR->getKind()) { + case MemRegion::AllocaRegionKind: + case MemRegion::SymbolicRegionKind: + return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR)); + case MemRegion::StringRegionKind: + return SVB.makeIntVal( + cast(SR)->getStringLiteral()->getByteLength() + 1, + SVB.getArrayIndexType()); + case MemRegion::CompoundLiteralRegionKind: + case MemRegion::CXXBaseObjectRegionKind: + case MemRegion::CXXDerivedObjectRegionKind: + case MemRegion::CXXTempObjectRegionKind: + case MemRegion::CXXThisRegionKind: + case MemRegion::ObjCIvarRegionKind: + case MemRegion::VarRegionKind: + case MemRegion::ElementRegionKind: + case MemRegion::ObjCStringRegionKind: { + QualType Ty = cast(SR)->getDesugaredValueType(Ctx); + if (isa(Ty)) + return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR)); + + if (Ty->isIncompleteType()) + return UnknownVal(); + + return getTypeSize(Ty, Ctx, SVB); + } + case MemRegion::FieldRegionKind: { + // Force callers to deal with bitfields explicitly. + if (cast(SR)->getDecl()->isBitField()) + return UnknownVal(); + + QualType Ty = cast(SR)->getDesugaredValueType(Ctx); + DefinedOrUnknownSVal Size = getTypeSize(Ty, Ctx, SVB); + + // A zero-length array at the end of a struct often stands for dynamically + // allocated extra memory. + if (Size.isZeroConstant()) { + if (isa(Ty)) + return UnknownVal(); + } + + return Size; + } + // FIXME: The following are being used in 'SimpleSValBuilder' and in + // 'ArrayBoundChecker::checkLocation' because there is no symbol to + // represent the regions more appropriately. + case MemRegion::BlockDataRegionKind: + case MemRegion::BlockCodeRegionKind: + case MemRegion::FunctionCodeRegionKind: + return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR)); + default: + llvm_unreachable("Unhandled region"); + } +} + template const REG *MemRegionManager::LazyAllocate(REG*& region) { if (!region) { region = A.Allocate(); - new (region) REG(this); + new (region) REG(*this); } return region; @@ -746,7 +763,7 @@ return R; R = A.Allocate(); - new (R) StackLocalsSpaceRegion(this, STC); + new (R) StackLocalsSpaceRegion(*this, STC); return R; } @@ -759,7 +776,7 @@ return R; R = A.Allocate(); - new (R) StackArgumentsSpaceRegion(this, STC); + new (R) StackArgumentsSpaceRegion(*this, STC); return R; } @@ -781,7 +798,7 @@ return R; R = A.Allocate(); - new (R) StaticGlobalSpaceRegion(this, CR); + new (R) StaticGlobalSpaceRegion(*this, CR); return R; } @@ -850,7 +867,7 @@ if (D->hasGlobalStorage() && !D->isStaticLocal()) { // First handle the globals defined in system headers. - if (C.getSourceManager().isInSystemHeader(D->getLocation())) { + if (Ctx.getSourceManager().isInSystemHeader(D->getLocation())) { // Whitelist the system globals which often DO GET modified, assume the // rest are immutable. if (D->getName().find("errno") != StringRef::npos) @@ -914,7 +931,7 @@ T = getContext().getBlockPointerType(T); const BlockCodeRegion *BTR = - getBlockCodeRegion(BD, C.getCanonicalType(T), + getBlockCodeRegion(BD, Ctx.getCanonicalType(T), STC->getAnalysisDeclContext()); sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, BTR); @@ -1476,7 +1493,7 @@ std::pair BlockDataRegion::getCaptureRegions(const VarDecl *VD) { - MemRegionManager &MemMgr = *getMemRegionManager(); + MemRegionManager &MemMgr = getMemRegionManager(); const VarRegion *VR = nullptr; const VarRegion *OriginalVR = nullptr; @@ -1511,7 +1528,7 @@ return; } - MemRegionManager &MemMgr = *getMemRegionManager(); + MemRegionManager &MemMgr = getMemRegionManager(); llvm::BumpPtrAllocator &A = MemMgr.getAllocator(); BumpVectorContext BC(A); 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 @@ -23,6 +23,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" @@ -876,7 +877,7 @@ // Find the length (in bits) of the region being invalidated. uint64_t Length = UINT64_MAX; - SVal Extent = Top->getExtent(SVB); + SVal Extent = Top->getMemRegionManager().getStaticSize(Top, SVB); if (Optional ExtentCI = Extent.getAs()) { const llvm::APSInt &ExtentInt = ExtentCI->getValue(); @@ -1394,7 +1395,7 @@ RegionStoreManager::getSizeInElements(ProgramStateRef state, const MemRegion *R, QualType EleTy) { - SVal Size = cast(R)->getExtent(svalBuilder); + DefinedOrUnknownSVal Size = getDynamicSize(state, R, svalBuilder); const llvm::APSInt *SizeInt = svalBuilder.getKnownValue(state, Size); if (!SizeInt) return UnknownVal(); diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -329,7 +329,7 @@ } QualType SymbolExtent::getType() const { - ASTContext &Ctx = R->getMemRegionManager()->getContext(); + ASTContext &Ctx = R->getMemRegionManager().getContext(); return Ctx.getSizeType(); }