@@ -608,6 +608,9 @@ class RegionStoreManager : public StoreManager {
608608 return getBinding (getRegionBindings (S), L, T);
609609 }
610610
611+ std::optional<SVal>
612+ getUniqueDefaultBinding (nonloc::LazyCompoundVal LCV) const ;
613+
611614 std::optional<SVal> getDefaultBinding (Store S, const MemRegion *R) override {
612615 RegionBindingsRef B = getRegionBindings (S);
613616 // Default bindings are always applied over a base region so look up the
@@ -2605,9 +2608,43 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
26052608 return NewB;
26062609}
26072610
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+
26082627std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallStruct (
26092628 RegionBindingsConstRef B, const TypedValueRegion *R, const RecordDecl *RD,
26102629 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+
26112648 FieldVector Fields;
26122649
26132650 if (const CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(RD))
0 commit comments