Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h =================================================================== --- /dev/null +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h @@ -0,0 +1,30 @@ +//===- 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" + +namespace clang { +namespace ento { + +/// Get the stored dynamic size for the region \p MR. +DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR); + +} // namespace ento +} // namespace clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICSIZE_H Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -56,6 +56,7 @@ class MemSpaceRegion; class SValBuilder; class SymbolicRegion; +class SymbolManager; class VarRegion; /// Represent a region's offset within the top level base region. @@ -112,7 +113,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 +199,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 +223,7 @@ class CodeSpaceRegion : public MemSpaceRegion { friend class MemRegionManager; - CodeSpaceRegion(MemRegionManager *mgr) + CodeSpaceRegion(MemRegionManager &mgr) : MemSpaceRegion(mgr, CodeSpaceRegionKind) {} public: @@ -238,7 +238,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 +259,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 +286,7 @@ void anchor() override; protected: - NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k) + NonStaticGlobalSpaceRegion(MemRegionManager &mgr, Kind k) : GlobalsSpaceRegion(mgr, k) { assert(classof(this)); } @@ -304,7 +304,7 @@ class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion { friend class MemRegionManager; - GlobalSystemSpaceRegion(MemRegionManager *mgr) + GlobalSystemSpaceRegion(MemRegionManager &mgr) : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {} public: @@ -323,7 +323,7 @@ class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion { friend class MemRegionManager; - GlobalImmutableSpaceRegion(MemRegionManager *mgr) + GlobalImmutableSpaceRegion(MemRegionManager &mgr) : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {} public: @@ -340,7 +340,7 @@ class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion { friend class MemRegionManager; - GlobalInternalSpaceRegion(MemRegionManager *mgr) + GlobalInternalSpaceRegion(MemRegionManager &mgr) : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {} public: @@ -354,7 +354,7 @@ class HeapSpaceRegion : public MemSpaceRegion { friend class MemRegionManager; - HeapSpaceRegion(MemRegionManager *mgr) + HeapSpaceRegion(MemRegionManager &mgr) : MemSpaceRegion(mgr, HeapSpaceRegionKind) {} public: @@ -368,7 +368,7 @@ class UnknownSpaceRegion : public MemSpaceRegion { friend class MemRegionManager; - UnknownSpaceRegion(MemRegionManager *mgr) + UnknownSpaceRegion(MemRegionManager &mgr) : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} public: @@ -385,7 +385,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 +405,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 +420,7 @@ private: friend class MemRegionManager; - StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + StackArgumentsSpaceRegion(MemRegionManager &mgr, const StackFrameContext *sfc) : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} public: @@ -449,12 +449,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 +486,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 +545,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 +773,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 +806,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 +1008,6 @@ return getDecl()->getType(); } - DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; - void dumpToStream(raw_ostream &os) const override; bool canPrintPretty() const override; @@ -1242,8 +1227,11 @@ //===----------------------------------------------------------------------===// class MemRegionManager { - ASTContext &C; + ASTContext &Ctx; llvm::BumpPtrAllocator& A; + SValBuilder &SVB; + SymbolManager &SymMgr; + llvm::FoldingSet Regions; GlobalInternalSpaceRegion *InternalGlobals = nullptr; @@ -1262,13 +1250,23 @@ CodeSpaceRegion *code = nullptr; public: - MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) : C(c), A(a) {} + MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a, SValBuilder &SVB, + SymbolManager &SymMgr) + : Ctx(c), A(a), SVB(SVB), SymMgr(SymMgr) {} ~MemRegionManager(); - ASTContext &getContext() { return C; } + ASTContext &getContext() { return Ctx; } llvm::BumpPtrAllocator &getAllocator() { return A; } + SValBuilder &getSValBuilder() { return SVB; } + + SymbolManager &getSymbolManager() { return SymMgr; } + + /// \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) const; + /// getStackLocalsRegion - Retrieve the memory region associated with the /// specified stack frame. const StackLocalsSpaceRegion * @@ -1434,7 +1432,7 @@ //===----------------------------------------------------------------------===// inline ASTContext &MemRegion::getContext() const { - return getMemRegionManager()->getContext(); + return getMemRegionManager().getContext(); } //===----------------------------------------------------------------------===// Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -84,8 +84,9 @@ SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, ProgramStateManager &stateMgr) : Context(context), BasicVals(context, alloc), - SymMgr(context, BasicVals, alloc), MemMgr(context, alloc), - StateMgr(stateMgr), ArrayIndexTy(context.LongLongTy), + SymMgr(context, BasicVals, alloc), + MemMgr(context, alloc, *this, SymMgr), StateMgr(stateMgr), + ArrayIndexTy(context.LongLongTy), ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {} virtual ~SValBuilder() = default; Index: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ 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); + 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(); Index: clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ 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,12 @@ 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); + + 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))); Index: clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ 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" @@ -329,10 +330,7 @@ // 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); // Get the index of the accessed element. DefinedOrUnknownSVal Idx = ER->getIndex().castAs(); @@ -937,14 +935,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); // 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); } @@ -1070,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); 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. Index: clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ 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); + 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. Index: clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ 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); + + State = State->BindExpr(CE, C.getLocationContext(), Size); C.addTransition(State); } Index: clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp +++ 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()); Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ 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); + // 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; } @@ -1539,12 +1541,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); + + DefinedOrUnknownSVal DynSizeMatchesSize = + svalBuilder.evalEQ(State, DynSize, *DefinedSize); - State = State->assume(extentMatchesSize, true); + State = State->assume(DynSizeMatchesSize, true); assert(State); } Index: clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ 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)); + 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. Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ 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) {} Index: clang/lib/StaticAnalyzer/Core/CMakeLists.txt =================================================================== --- clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ clang/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -16,6 +16,7 @@ CommonBugCategories.cpp ConstraintManager.cpp CoreEngine.cpp + DynamicSize.cpp DynamicType.cpp Environment.cpp ExplodedGraph.cpp Index: clang/lib/StaticAnalyzer/Core/DynamicSize.cpp =================================================================== --- /dev/null +++ clang/lib/StaticAnalyzer/Core/DynamicSize.cpp @@ -0,0 +1,36 @@ +//===- 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" + +REGISTER_MAP_WITH_PROGRAMSTATE(DynamicSizeMap, const clang::ento::MemRegion *, + clang::ento::DefinedOrUnknownSVal) + +namespace clang { +namespace ento { + +DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, + const MemRegion *MR) { + if (const DefinedOrUnknownSVal *Size = State->get(MR)) + return *Size; + + return MR->getMemRegionManager().getStaticSize(MR); +} + +} // namespace ento +} // namespace clang Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ 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,76 @@ // 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) const { + const auto *SR = cast(MR); + + 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::BlockDataRegionKind: + case MemRegion::BlockCodeRegionKind: + case MemRegion::FunctionCodeRegionKind: { + QualType Ty = cast(SR)->getDesugaredLocationType(Ctx); + return getTypeSize(Ty, Ctx, SVB); + } + 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; + } + 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 +761,7 @@ return R; R = A.Allocate(); - new (R) StackLocalsSpaceRegion(this, STC); + new (R) StackLocalsSpaceRegion(*this, STC); return R; } @@ -759,7 +774,7 @@ return R; R = A.Allocate(); - new (R) StackArgumentsSpaceRegion(this, STC); + new (R) StackArgumentsSpaceRegion(*this, STC); return R; } @@ -781,7 +796,7 @@ return R; R = A.Allocate(); - new (R) StaticGlobalSpaceRegion(this, CR); + new (R) StaticGlobalSpaceRegion(*this, CR); return R; } @@ -850,7 +865,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 +929,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 +1491,7 @@ std::pair BlockDataRegion::getCaptureRegions(const VarDecl *VD) { - MemRegionManager &MemMgr = *getMemRegionManager(); + MemRegionManager &MemMgr = getMemRegionManager(); const VarRegion *VR = nullptr; const VarRegion *OriginalVR = nullptr; @@ -1511,7 +1526,7 @@ return; } - MemRegionManager &MemMgr = *getMemRegionManager(); + MemRegionManager &MemMgr = getMemRegionManager(); llvm::BumpPtrAllocator &A = MemMgr.getAllocator(); BumpVectorContext BC(A); Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ 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); 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); const llvm::APSInt *SizeInt = svalBuilder.getKnownValue(state, Size); if (!SizeInt) return UnknownVal(); Index: clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -155,7 +155,7 @@ // FIXME: Currently we are using an extent symbol here, // because there are no generic region address metadata // symbols to use, only content metadata. - return nonloc::SymbolVal(SymMgr.getExtentSymbol(FTR)); + return FTR->getMemRegionManager().getStaticSize(FTR); if (const SymbolicRegion *SymR = R->getSymbolicBase()) return makeNonLoc(SymR->getSymbol(), BO_NE, Index: clang/lib/StaticAnalyzer/Core/SymbolManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ 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(); } Index: clang/test/Analysis/weak-functions.c =================================================================== --- clang/test/Analysis/weak-functions.c +++ clang/test/Analysis/weak-functions.c @@ -7,9 +7,9 @@ void testWeakFuncIsNull() { clang_analyzer_eval(myFunc == NULL); // expected-warning{{FALSE}} - clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} if (myWeakFunc == NULL) { - clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}} + clang_analyzer_eval(myWeakFunc == NULL); // no-warning } else { clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} } @@ -17,9 +17,9 @@ void testWeakFuncIsNot() { - clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} if (!myWeakFunc) { - clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}} + clang_analyzer_eval(myWeakFunc == NULL); // no-warning } else { clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} } @@ -27,11 +27,11 @@ void testWeakFuncIsTrue() { - clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} if (myWeakFunc) { clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{FALSE}} } else { - clang_analyzer_eval(myWeakFunc == NULL); // expected-warning{{TRUE}} + clang_analyzer_eval(myWeakFunc == NULL); // no-warning } }