Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h @@ -22,16 +22,20 @@ namespace clang { namespace ento { -/// Get the stored dynamic size for the region \p MR. +/// \returns The stored dynamic size for the region \p MR. DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB); -/// Get the stored element count of the region \p MR. +/// \return The stored element count of the region \p MR. DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB, QualType ElementTy); +/// Set the dynamic size \p Size of the region \p MR. +ProgramStateRef setDynamicSize(ProgramStateRef State, const MemRegion *MR, + DefinedOrUnknownSVal Size); + } // namespace ento } // namespace clang Index: clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -90,12 +90,7 @@ if (Size.isUndef()) return true; // Return true to model purity. - SValBuilder& svalBuilder = C.getSValBuilder(); - 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"); + state = setDynamicSize(state, R, Size.castAs()); C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R))); return true; Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1403,16 +1403,14 @@ CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType); if (ElementCount.getAs()) { - 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 DynSizeMatchesSize = svalBuilder.evalEQ( - State, DynSize, SizeInBytes.castAs()); - State = State->assume(DynSizeMatchesSize, true); + + State = setDynamicSize(State, Region, + SizeInBytes.castAs()); } return State; } @@ -1537,21 +1535,9 @@ // Fill the region with the initialization value. State = State->bindDefaultInitial(RetVal, Init, LCtx); - // Set the region's extent equal to the Size parameter. - const SymbolicRegion *R = - dyn_cast_or_null(RetVal.getAsRegion()); - if (!R) - return nullptr; - if (Optional DefinedSize = - Size.getAs()) { - DefinedOrUnknownSVal DynSize = getDynamicSize(State, R, svalBuilder); - - DefinedOrUnknownSVal DynSizeMatchesSize = - svalBuilder.evalEQ(State, DynSize, *DefinedSize); - - State = State->assume(DynSizeMatchesSize, true); - assert(State); - } + // Set the region's size. + State = setDynamicSize(State, RetVal.getAsRegion(), + Size.castAs()); return MallocUpdateRefState(C, CE, State, Family); } Index: clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -166,18 +166,9 @@ SVal ArraySizeVal = svalBuilder.evalBinOpNN( state, BO_Mul, ArrayLength, EleSizeVal.castAs(), SizeTy); - // Finally, assume that the array's size matches the given size. - const LocationContext *LC = C.getLocationContext(); - DefinedOrUnknownSVal DynSize = - getDynamicSize(state, state->getRegion(VD, LC), svalBuilder); - - DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs(); - DefinedOrUnknownSVal sizeIsKnown = - svalBuilder.evalEQ(state, DynSize, ArraySize); - state = state->assume(sizeIsKnown, true); - - // Assume should not fail at this point. - assert(state); + // Finally, set the size. + state = setDynamicSize(state, state->getRegion(VD, C.getLocationContext()), + ArraySizeVal.castAs()); // Remember our assumptions! C.addTransition(state); Index: clang/lib/StaticAnalyzer/Core/DynamicSize.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/DynamicSize.cpp +++ clang/lib/StaticAnalyzer/Core/DynamicSize.cpp @@ -19,11 +19,24 @@ #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 { +ProgramStateRef setDynamicSize(ProgramStateRef State, const MemRegion *MR, + DefinedOrUnknownSVal Size) { + if (Size.isUnknown()) + return State; + return State->set(MR, Size); +} + DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB) { + if (const DefinedOrUnknownSVal *Size = State->get(MR)) + return *Size; + return MR->getMemRegionManager().getStaticSize(MR, SVB); } Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -10,15 +10,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/Analysis/ConstructionContext.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/StmtCXX.h" #include "clang/AST/ParentMap.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Analysis/ConstructionContext.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/StaticAnalyzer/Core/CheckerManager.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/ExprEngine.h" using namespace clang; using namespace ento; @@ -761,11 +762,17 @@ // heap. We realize this is an approximation that might not correctly model // a custom global allocator. if (symVal.isUnknown()) { - if (IsStandardGlobalOpNewFunction) + if (IsStandardGlobalOpNewFunction) { + DefinedOrUnknownSVal Size = UnknownVal(); + if (const Expr *SizeExpr = CNE->getArraySize().getValueOr(nullptr)) + Size = State->getSVal(SizeExpr, LCtx).castAs(); + symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); - else + State = setDynamicSize(State, symVal.getAsRegion(), Size); + } else { symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), blockCount); + } } CallEventManager &CEMgr = getStateManager().getCallEventManager(); Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -10,15 +10,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/Decl.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/ConstructionContext.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/SaveAndRestore.h" @@ -690,16 +691,18 @@ // See if we need to conjure a heap pointer instead of // a regular unknown pointer. - bool IsHeapPointer = false; - if (const auto *CNE = dyn_cast(E)) - if (CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) { - // FIXME: Delegate this to evalCall in MallocChecker? - IsHeapPointer = true; - } - - R = IsHeapPointer ? svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count) - : svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, - Count); + const auto *CNE = dyn_cast(E); + if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) { + // FIXME: Delegate this to evalCall in MallocChecker? + DefinedOrUnknownSVal Size = UnknownVal(); + if (const Expr *SizeExpr = CNE->getArraySize().getValueOr(nullptr)) + Size = State->getSVal(SizeExpr, LCtx).castAs(); + + R = svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count); + State = setDynamicSize(State, R.getAsRegion(), Size); + } else { + R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count); + } } return State->BindExpr(E, LCtx, R); }