@@ -608,6 +608,9 @@ class RegionStoreManager : public StoreManager {
608
608
return getBinding (getRegionBindings (S), L, T);
609
609
}
610
610
611
+ std::optional<SVal>
612
+ getUniqueDefaultBinding (nonloc::LazyCompoundVal LCV) const ;
613
+
611
614
std::optional<SVal> getDefaultBinding (Store S, const MemRegion *R) override {
612
615
RegionBindingsRef B = getRegionBindings (S);
613
616
// Default bindings are always applied over a base region so look up the
@@ -2605,9 +2608,43 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
2605
2608
return NewB;
2606
2609
}
2607
2610
2611
+ std::optional<SVal>
2612
+ RegionStoreManager::getUniqueDefaultBinding (nonloc::LazyCompoundVal LCV) const {
2613
+ const MemRegion *BaseR = LCV.getRegion ();
2614
+
2615
+ // We only handle base regions.
2616
+ if (BaseR != BaseR->getBaseRegion ())
2617
+ return std::nullopt;
2618
+
2619
+ const auto *Cluster = getRegionBindings (LCV.getStore ()).lookup (BaseR);
2620
+ if (!Cluster || !llvm::hasSingleElement (*Cluster))
2621
+ return std::nullopt;
2622
+
2623
+ const auto [Key, Value] = *Cluster->begin ();
2624
+ return Key.isDirect () ? std::optional<SVal>{} : Value;
2625
+ }
2626
+
2608
2627
std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallStruct (
2609
2628
RegionBindingsConstRef B, const TypedValueRegion *R, const RecordDecl *RD,
2610
2629
nonloc::LazyCompoundVal LCV) {
2630
+ // If we try to copy a Conjured value representing the value of the whole
2631
+ // struct, don't try to element-wise copy each field.
2632
+ // That would unnecessarily bind Derived symbols slicing off the subregion for
2633
+ // the field from the whole Conjured symbol.
2634
+ //
2635
+ // struct Window { int width; int height; };
2636
+ // Window getWindow(); <-- opaque fn.
2637
+ // Window w = getWindow(); <-- conjures a new Window.
2638
+ // Window w2 = w; <-- trivial copy "w", calling "tryBindSmallStruct"
2639
+ //
2640
+ // We should not end up with a new Store for "w2" like this:
2641
+ // Direct [ 0..31]: Derived{Conj{}, w.width}
2642
+ // Direct [32..63]: Derived{Conj{}, w.height}
2643
+ // Instead, we should just bind that Conjured value instead.
2644
+ if (std::optional<SVal> Val = getUniqueDefaultBinding (LCV)) {
2645
+ return B.addBinding (BindingKey::Make (R, BindingKey::Default), Val.value ());
2646
+ }
2647
+
2611
2648
FieldVector Fields;
2612
2649
2613
2650
if (const CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(RD))
0 commit comments