Skip to content

fix[venom]: widen tuples by memory layout, not type equality - #5256

Open
harkal wants to merge 12 commits into
vyperlang:masterfrom
harkal:fix/venom/store-memory-tuple-widening
Open

harkal wants to merge 12 commits into
vyperlang:masterfrom
harkal:fix/venom/store-memory-tuple-widening

Conversation

@harkal

@harkal harkal commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

What I did

Venom-only miscompile: assigning a tuple to a tuple with wider members (e.g. x: (Bytes[10], uint256), y: (Bytes[40], uint256) = x) copied x as a flat block, so the second member of y sits at the wrong offset and is read back wrong. Same for storage/transient/immutable tuple writes and for internal returns of tuples that have unbounded members. Legacy codegen (make_setter) is correct.

Fixes the venom side of the tuple widening path that #5236 relies on.

How I did it

  • VenomCodegenContext.store_memory, Stmt._store_complex_type and Stmt._emit_dynamic_tuple_internal_return chose between a flat copy and the member-wise copy (_store_memory_typed) with src_typ != typ. TupleT.__eq__ compares members, which is never populated (_equality_attrs = ("members",)), so any two tuple types compare equal and the member-wise path never fired for tuples.
  • New same_memory_layout(src_typ, dst_typ) in codegen_venom/context.py = punnable(src_typ, dst_typ) and src_typ.memory_bytes_required == dst_typ.memory_bytes_required; the three sites gate on it. punnable alone (vyper/codegen/core.py, from fix[codegen]: widen ternary arms to the result type layout #5236) is not enough: it accepts a wider top-level DynArray capacity or bytestring bound in the destination (the data present has the same layout), but a flat copy of the destination size would read past the source. The size conjunct keeps every such case on the copy path it takes today (_copy_dynarray_memory_typed / the bytestring branch) and leaves all non-tuple codegen unchanged.
  • ensure_memory_layout now falls back to materialize_value (store_vyper_value -> store_memory) for bounded types; the comment that justified bypassing it was exactly this broken gate. The unbounded-sequence route added in feat[venom]: allow abi-dynamic elements in inf dynarrays #5240 is unchanged.
  • In _emit_dynamic_tuple_internal_return the type_contains_unbounded_sequence checks are evaluated before same_memory_layout, since unbounded members have no memory_bytes_required.
  • Left as is (identity checks, or unreachable for tuples): _copy_dynarray_memory_typed's fast path (elements are never tuples), _lower_dynarray_append, _lower_external_return's ret_src_typ != ret_typ (can_encode_from_src is True first for tuples), builtins/abi.py's wrapped_typ != output_typ.
  • Not changed: TupleT.__eq__ itself. Fixing it in semantics touches type-checker equality; separate PR if wanted.

How to verify it

Commit message

gate the flat-copy fast path in `store_memory`, `_store_complex_type`
and `_emit_dynamic_tuple_internal_return` on a new `same_memory_layout`
predicate (`punnable` plus equal `memory_bytes_required`) instead of
`src_typ != typ`, which is always False for tuples because
`TupleT.__eq__` compares the never-populated `members` dict. widened
tuple copies (e.g. `(Bytes[10], uint256)` into `(Bytes[40], uint256)`)
now take the member-wise path.

`ensure_memory_layout` falls back to `materialize_value` for bounded
types now that `store_memory` gates correctly. add runtime tests for
widened tuples through locals, returns, internal-call arguments, struct
members, nested tuples, DynArray members and state variables.

Description for the changelog

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Gas Changes

No changes detected.

Summary

  • Total tests measured: 560
  • Changed: 0
  • Regressions (gas up): 0
  • Improvements (gas down): 0
  • New tests: 0
  • Deleted tests: 0
  • Newly failing: 0
  • Newly passing: 0

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

📊 Bytecode Size Changes (venom)

No changes detected.

Full bytecode sizes

Contract legacy-O2 legacy-Os -O2 -O3 -Os
curvefi/legacy/CurveStableSwapMetaNG.vy 24952 23578 19769 19059 18523
curvefi/amm/stableswap/meta_implementation/meta_implementation_v_700.vy 23610 22805 19565 18627 18314
curvefi/amm/stableswap/implementation/implementation_v_700.vy 24962 23769 19188 18363 18019
curvefi/legacy/CurveStableSwapNG.vy 24473 23298 18749 17981 17636
curvefi/amm/tricryptoswap/implementation/implementation_v_200.vy 20724 19959 17250 16689 16325
curvefi/amm/twocryptoswap/implementation/implementation_v_210.vy 17634 16894 14958 14376 14027
yearnfi/VaultV3.vy 19972 19063 14739 13818 13269
curvefi/legacy/CurveCryptoSwap2.vy 18947 18382 14619 14129 13954
yearnfi/VaultV2.vy 16676 15763 13258 12466 12049
curvefi/amm/stableswap/factory/factory_v_100.vy 14558 13978 11852 10780 10880
curvefi/gauge/child_gauge/implementation/implementation_v_110.vy 12338 11561 9781 9184 8795
curvefi/amm/stableswap/views/views_v_120.vy 12784 12368 9705 9059 9294
curvefi/gauge/child_gauge/implementation/implementation_v_100.vy 12017 11249 9514 8924 8538
curvefi/amm/tricryptoswap/math/math_v_200.vy 11189 11126 9029 8144 8170
curvefi/legacy/CurveCryptoMathOptimized3.vy 11188 11125 9028 8144 8170
curvefi/gauge/child_gauge/implementation/implementation_v_020.vy 10665 9947 8626 8100 7714
curvefi/registries/metaregistry/metaregistry_v_110.vy 7590 6732 6491 5710 5603
curvefi/helpers/router/router_v_110.vy 6717 6717 6251 5733 6035
curvefi/amm/tricryptoswap/views/views_v_200.vy 7821 7776 6111 5896 6045
curvefi/helpers/stable_swap_meta_zap/stable_swap_meta_zap_v_100.vy 7302 7067 5877 5350 5610
curvefi/amm/twocryptoswap/views/views_v_200.vy 6991 6946 5680 5479 5614
curvefi/registries/metaregistry/registry_handlers/stableswap/handler_v_110.vy 6633 6259 5533 4695 5238
curvefi/amm/twocryptoswap/math/math_v_210.vy 6800 6800 5506 5012 5039
curvefi/amm/twocryptoswap/factory/factory_v_200.vy 5540 5252 4617 3917 4047
curvefi/amm/tricryptoswap/factory/factory_v_200.vy 5246 5021 4483 3890 4020
curvefi/gauge/child_gauge/factory/factory_v_201.vy 4844 4547 3901 3675 3511
curvefi/registries/metaregistry/registry_handlers/tricryptoswap/handler_v_110.vy 4241 3939 3718 3334 3429
curvefi/registries/metaregistry/registry_handlers/twocryptoswap/handler_v_110.vy 4186 3884 3671 3251 3329
curvefi/gauge/child_gauge/factory/factory_v_100.vy 4183 3914 3408 3144 2971
yearnfi/VaultFactory.vy 3765 3617 2936 2158 2461
curvefi/registries/address_provider/address_provider_v_201.vy 2973 2782 2613 2440 2353
curvefi/helpers/rate_provider/rate_provider_v_101.vy 3260 3260 2535 2263 2296
curvefi/amm/stableswap/math/math_v_100.vy 3067 3046 2458 2253 2310
curvefi/helpers/rate_provider/rate_provider_v_100.vy 2847 2841 2273 1954 1974
curvefi/helpers/deposit_and_stake_zap/deposit_and_stake_zap_v_100.vy 2322 2316 1782 1611 1670
curvefi/governance/relayer/taiko/relayer_v_001.vy 2068 2064 1731 1510 1558
curvefi/governance/relayer/polygon_cdk/relayer_v_101.vy 1556 1523 1530 1324 1347
curvefi/governance/relayer/arb_orbit/relayer_v_101.vy 1266 1262 1242 1066 1115
curvefi/governance/relayer/op_stack/relayer_v_101.vy 1186 1182 1183 1014 1056
curvefi/governance/relayer/not_rollup/relayer_v_100.vy 1168 1153 1174 1011 1037
curvefi/governance/vault/vault_v_100.vy 964 941 862 823 839
curvefi/governance/relayer/relayer_v_100.vy 496 496 593 490 503
curvefi/governance/agent/agent_v_100.vy 541 541 430 402 406
curvefi/governance/agent/agent_v_101.vy 541 541 430 402 406

Comment thread vyper/codegen_venom/context.py Outdated
@harkal
harkal marked this pull request as ready for review September 11, 2026 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants