Skip to content

Comments

Fix sign extension of i32 addresses in interpreter memory access#8348

Open
sumleo wants to merge 1 commit intoWebAssembly:mainfrom
sumleo:fix-interpreter-address-signext
Open

Fix sign extension of i32 addresses in interpreter memory access#8348
sumleo wants to merge 1 commit intoWebAssembly:mainfrom
sumleo:fix-interpreter-address-signext

Conversation

@sumleo
Copy link
Contributor

@sumleo sumleo commented Feb 20, 2026

Summary

  • Fix implicit sign extension of i32 addresses in getFinalAddress and getFinalAddressWithoutOffset in the interpreter
  • ptr.geti32() returns int32_t, which gets sign-extended to int64_t via C++ ternary promotion rules before being stored as uint64_t
  • For i32 addresses >= 0x80000000, this produces incorrect 64-bit values (e.g., 0xFFFFFFFF80000000 instead of 0x80000000), causing spurious out-of-bounds traps
  • Fix by casting through uint32_t first to zero-extend instead of sign-extend

Test plan

  • All 309 unit tests pass (binaryen-unittests)
  • Build succeeds with no warnings

size_t indexVal = index.getSingleValue().getUnsigned();
if (indexVal >= data->values.size()) {
trap("array oob");
}
Copy link
Member

Choose a reason for hiding this comment

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

This looks like a correct fix, but the title and description of the PR look unrelated?

if (indexVal >= data->values.size()) {
trap("array oob");
}
auto& field = data->values[indexVal];
Copy link
Member

Choose a reason for hiding this comment

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

@tlively is it possible the spec tests do not have bounds checks for this instruction, and ArrayCmpXChg?

Copy link
Member

Choose a reason for hiding this comment

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

We don't have real spec tests for GC atomics yet and it looks like we don't have our own interpreter tests or fuzzer support for them, either.

@sumleo sumleo force-pushed the fix-interpreter-address-signext branch from 73c73bb to 1aaf4f9 Compare February 21, 2026 02:24
@sumleo
Copy link
Contributor Author

sumleo commented Feb 21, 2026

Thanks for catching that! The branch previously contained the wrong change (an array bounds check that was already covered by #8351). I've force-pushed with the actual sign extension fix for getFinalAddress and getFinalAddressWithoutOffset — casting through uint32_t to zero-extend instead of sign-extend.

@sumleo sumleo force-pushed the fix-interpreter-address-signext branch from 1aaf4f9 to 88aba0f Compare February 21, 2026 02:36
ptr.geti32() returns int32_t, which gets sign-extended to int64_t via
C++ ternary promotion rules before being stored as uint64_t. For i32
addresses >= 0x80000000, this produces incorrect 64-bit addresses
(e.g., 0xFFFFFFFF80000000 instead of 0x80000000), causing spurious
out-of-bounds traps.

Fix by casting through uint32_t first to zero-extend instead of
sign-extend.
@sumleo sumleo force-pushed the fix-interpreter-address-signext branch from 88aba0f to 624d4c7 Compare February 21, 2026 04:13
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.

3 participants