Skip to content

[interp] Pop memory.copy/table.copy length using the minimum index type#2800

Merged
sbc100 merged 1 commit into
WebAssembly:mainfrom
aizu-m:copy-length-index-type
Jul 20, 2026
Merged

[interp] Pop memory.copy/table.copy length using the minimum index type#2800
sbc100 merged 1 commit into
WebAssembly:mainfrom
aizu-m:copy-length-index-type

Conversation

@aizu-m

@aizu-m aizu-m commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

A valid module doing a mixed-width table.copy aborts wasm-interp in a debug build:

$ wasm-interp --enable-memory64 --enable-multi-memory --run-all-exports t.wasm
Assertion failed: (t == type || type == ValueType::Any), function CheckType, file interp.h, line 596.

The module copies from an i64-indexed table into an i32-indexed one (table.copy $t32 $t64). Found it running the memory64 tests under --run-all-exports.

DoTableCopy/DoMemoryCopy pop the length operand with the source's index type (PopPtr(table_src)/PopPtr(mem_src)). But the length's type is the minimum of the two index types, not the source's, so for a 64-bit source into a 32-bit destination the length is i32 while the interpreter reads it as i64. TypeChecker::OnMemoryCopy/OnTableCopy already spell out the min rule; the runtime side just didn't follow it.

Debug builds trip the type assertion. In release the read only gives the right answer because the Value union happens to be zero-initialised.

Pop the length as u64 only when both memories/tables are 64-bit. Same-width copies are byte-identical. Regression test added under test/interp.

@sbc100 sbc100 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe another case where the upstream spec tests are missing some coverage?

@sbc100 sbc100 changed the title Pop memory.copy/table.copy length using the minimum index type [interp] Pop memory.copy/table.copy length using the minimum index type Jul 20, 2026
@sbc100
sbc100 enabled auto-merge (squash) July 20, 2026 16:59
@sbc100
sbc100 merged commit 0ef5bd9 into WebAssembly:main Jul 20, 2026
17 checks passed
@aizu-m

aizu-m commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Looks like it. table_copy_mixed.wast defines test_64to32 but never invokes it, so only the validator sees the mixed case. Same on the memory side, the memory64 memory_copy.wast never executes a mixed-width copy. I only hit the runtime path by running the exports directly with --run-all-exports. An assert_return on test_64to32 upstream would have caught this. Thanks for merging.

@aizu-m

aizu-m commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Yes, looks that way. table_copy_mixed.wast defines test_64to32 and test_32to64 but never invokes them, so the mixed path only ever gets validated, never executed. I only tripped it because --run-all-exports calls everything. For memory.copy the proposal suite has no mixed execution test at all, just assert_invalid cases. Worth raising upstream. Thanks for merging this.

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