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,28 @@ 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. +/// \returns 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. +/// \returns The assumption of the current dynamic size equal to \p Size. +ProgramStateRef setDynamicSizeAssumption(ProgramStateRef State, + const MemRegion *MR, SValBuilder &SVB, + DefinedOrUnknownSVal Size); + +/// Set the dynamic size \p Size of the region \p MR. +/// \returns The dual assumption of the current dynamic size equal to \p Size. +std::pair +setDynamicSizeDualAssumption(ProgramStateRef State, const MemRegion *MR, + SValBuilder &SVB, 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 @@ -91,10 +91,8 @@ 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); + state = setDynamicSizeAssumption(state, R, svalBuilder, + Size.castAs()); 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 @@ -1067,12 +1067,9 @@ // 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 size. - DefinedOrUnknownSVal SizeDV = getDynamicSize(State, BR, svalBuilder); - ProgramStateRef StateWholeReg, StateNotWholeReg; std::tie(StateWholeReg, StateNotWholeReg) = - State->assume(svalBuilder.evalEQ(State, SizeDV, *SizeNL)); + setDynamicSizeDualAssumption(State, BR, svalBuilder, *SizeNL); // With the semantic of 'memset()', we should convert the CharVal to // unsigned char. 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 = setDynamicSizeAssumption( + State, Region, svalBuilder, SizeInBytes.castAs()); } return State; } @@ -1541,13 +1539,7 @@ 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); + State = setDynamicSizeAssumption(State, R, svalBuilder, *DefinedSize); } 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 @@ -168,13 +168,8 @@ // 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); + state = setDynamicSizeAssumption(state, state->getRegion(VD, LC), svalBuilder, + ArraySizeVal.castAs()); // Assume should not fail at this point. assert(state); Index: clang/lib/StaticAnalyzer/Core/DynamicSize.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/DynamicSize.cpp +++ clang/lib/StaticAnalyzer/Core/DynamicSize.cpp @@ -18,11 +18,17 @@ #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, SValBuilder &SVB) { + if (const DefinedOrUnknownSVal *Size = State->get(MR)) + return *Size; + return MR->getMemRegionManager().getStaticSize(MR, SVB); } @@ -47,5 +53,30 @@ return SVB.makeIntVal(RegionSize / ElementSize, SVB.getArrayIndexType()); } +ProgramStateRef setDynamicSizeAssumption(ProgramStateRef State, + const MemRegion *MR, SValBuilder &SVB, + DefinedOrUnknownSVal Size) { + DefinedOrUnknownSVal DynSize = getDynamicSize(State, MR, SVB); + + if ((State = State->assume(SVB.evalEQ(State, DynSize, Size), true))) + State = State->set(MR, Size); + + return State; +} + +std::pair +setDynamicSizeDualAssumption(ProgramStateRef State, const MemRegion *MR, + SValBuilder &SVB, DefinedOrUnknownSVal Size) { + DefinedOrUnknownSVal DynSize = getDynamicSize(State, MR, SVB); + + ProgramStateRef StateEQ, StateNE; + std::tie(StateEQ, StateNE) = State->assume(SVB.evalEQ(State, DynSize, Size)); + + if (StateEQ) + StateEQ = StateEQ->set(MR, Size); + + return {StateEQ, StateNE}; +} + } // namespace ento } // namespace clang