forked from OSchip/llvm-project
[Static Analyzer] Small array binding policy
If a lazyCompoundVal to a struct is bound to the store, there is a policy which decides whether a copy gets created instead. This patch introduces a similar policy for arrays, which is required to model structured binding to arrays without false negatives. Differential Revision: https://reviews.llvm.org/D128064
This commit is contained in:
parent
ad709a752d
commit
92bf652d40
|
@ -440,11 +440,19 @@ ANALYZER_OPTION(
|
|||
ANALYZER_OPTION(
|
||||
unsigned, RegionStoreSmallStructLimit, "region-store-small-struct-limit",
|
||||
"The largest number of fields a struct can have and still be considered "
|
||||
"small This is currently used to decide whether or not it is worth forcing "
|
||||
"small. This is currently used to decide whether or not it is worth forcing "
|
||||
"a LazyCompoundVal on bind. To disable all small-struct-dependent "
|
||||
"behavior, set the option to 0.",
|
||||
2)
|
||||
|
||||
ANALYZER_OPTION(
|
||||
unsigned, RegionStoreSmallArrayLimit, "region-store-small-array-limit",
|
||||
"The largest number of elements an array can have and still be considered "
|
||||
"small. This is currently used to decide whether or not it is worth forcing "
|
||||
"a LazyCompoundVal on bind. To disable all small-array-dependent "
|
||||
"behavior, set the option to 0.",
|
||||
5)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// String analyzer options.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -345,6 +345,16 @@ private:
|
|||
/// To disable all small-struct-dependent behavior, set the option to "0".
|
||||
unsigned SmallStructLimit;
|
||||
|
||||
/// The largest number of element an array can have and still be
|
||||
/// considered "small".
|
||||
///
|
||||
/// This is currently used to decide whether or not it is worth "forcing" a
|
||||
/// LazyCompoundVal on bind.
|
||||
///
|
||||
/// This is controlled by 'region-store-small-struct-limit' option.
|
||||
/// To disable all small-struct-dependent behavior, set the option to "0".
|
||||
unsigned SmallArrayLimit;
|
||||
|
||||
/// A helper used to populate the work list with the given set of
|
||||
/// regions.
|
||||
void populateWorkList(InvalidateRegionsWorker &W,
|
||||
|
@ -354,10 +364,11 @@ private:
|
|||
public:
|
||||
RegionStoreManager(ProgramStateManager &mgr)
|
||||
: StoreManager(mgr), RBFactory(mgr.getAllocator()),
|
||||
CBFactory(mgr.getAllocator()), SmallStructLimit(0) {
|
||||
CBFactory(mgr.getAllocator()), SmallStructLimit(0), SmallArrayLimit(0) {
|
||||
ExprEngine &Eng = StateMgr.getOwningEngine();
|
||||
AnalyzerOptions &Options = Eng.getAnalysisManager().options;
|
||||
SmallStructLimit = Options.RegionStoreSmallStructLimit;
|
||||
SmallArrayLimit = Options.RegionStoreSmallArrayLimit;
|
||||
}
|
||||
|
||||
/// setImplicitDefaultValue - Set the default binding for the provided
|
||||
|
@ -487,6 +498,11 @@ public: // Part of public interface to class.
|
|||
RegionBindingsRef bindVector(RegionBindingsConstRef B,
|
||||
const TypedValueRegion* R, SVal V);
|
||||
|
||||
Optional<RegionBindingsRef> tryBindSmallArray(RegionBindingsConstRef B,
|
||||
const TypedValueRegion *R,
|
||||
const ArrayType *AT,
|
||||
nonloc::LazyCompoundVal LCV);
|
||||
|
||||
RegionBindingsRef bindArray(RegionBindingsConstRef B,
|
||||
const TypedValueRegion* R,
|
||||
SVal V);
|
||||
|
@ -2392,6 +2408,40 @@ RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B,
|
|||
return B.addBinding(R, BindingKey::Default, V);
|
||||
}
|
||||
|
||||
Optional<RegionBindingsRef> RegionStoreManager::tryBindSmallArray(
|
||||
RegionBindingsConstRef B, const TypedValueRegion *R, const ArrayType *AT,
|
||||
nonloc::LazyCompoundVal LCV) {
|
||||
|
||||
auto CAT = dyn_cast<ConstantArrayType>(AT);
|
||||
|
||||
// If we don't know the size, create a lazyCompoundVal instead.
|
||||
if (!CAT)
|
||||
return None;
|
||||
|
||||
QualType Ty = CAT->getElementType();
|
||||
if (!(Ty->isScalarType() || Ty->isReferenceType()))
|
||||
return None;
|
||||
|
||||
// If the array is too big, create a LCV instead.
|
||||
uint64_t ArrSize = CAT->getSize().getLimitedValue();
|
||||
if (ArrSize > SmallArrayLimit)
|
||||
return None;
|
||||
|
||||
RegionBindingsRef NewB = B;
|
||||
|
||||
for (uint64_t i = 0; i < ArrSize; ++i) {
|
||||
auto Idx = svalBuilder.makeArrayIndex(i);
|
||||
const ElementRegion *SrcER =
|
||||
MRMgr.getElementRegion(Ty, Idx, LCV.getRegion(), Ctx);
|
||||
SVal V = getBindingForElement(getRegionBindings(LCV.getStore()), SrcER);
|
||||
|
||||
const ElementRegion *DstER = MRMgr.getElementRegion(Ty, Idx, R, Ctx);
|
||||
NewB = bind(NewB, loc::MemRegionVal(DstER), V);
|
||||
}
|
||||
|
||||
return NewB;
|
||||
}
|
||||
|
||||
RegionBindingsRef
|
||||
RegionStoreManager::bindArray(RegionBindingsConstRef B,
|
||||
const TypedValueRegion* R,
|
||||
|
@ -2413,8 +2463,13 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B,
|
|||
}
|
||||
|
||||
// Handle lazy compound values.
|
||||
if (isa<nonloc::LazyCompoundVal>(Init))
|
||||
if (Optional<nonloc::LazyCompoundVal> LCV =
|
||||
Init.getAs<nonloc::LazyCompoundVal>()) {
|
||||
if (Optional<RegionBindingsRef> NewB = tryBindSmallArray(B, R, AT, *LCV))
|
||||
return *NewB;
|
||||
|
||||
return bindAggregate(B, R, Init);
|
||||
}
|
||||
|
||||
if (Init.isUnknown())
|
||||
return bindAggregate(B, R, UnknownVal());
|
||||
|
|
|
@ -114,6 +114,7 @@
|
|||
// CHECK-NEXT: osx.NumberObjectConversion:Pedantic = false
|
||||
// CHECK-NEXT: osx.cocoa.RetainCount:TrackNSCFStartParam = false
|
||||
// CHECK-NEXT: prune-paths = true
|
||||
// CHECK-NEXT: region-store-small-array-limit = 5
|
||||
// CHECK-NEXT: region-store-small-struct-limit = 2
|
||||
// CHECK-NEXT: report-in-main-source-file = false
|
||||
// CHECK-NEXT: serialize-stats = false
|
||||
|
|
Loading…
Reference in New Issue