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?

@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 2 times, most recently from 88aba0f to 624d4c7 Compare February 21, 2026 04:13
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. Update expected test outputs that contained the old
sign-extended trap values.
@sumleo sumleo force-pushed the fix-interpreter-address-signext branch from 624d4c7 to c906298 Compare February 23, 2026 01:15
Address memorySizeBytes = memorySize * Memory::kPageSize;
uint64_t addr = ptr.type == Type::i32 ? ptr.geti32() : ptr.geti64();
uint64_t addr = ptr.type == Type::i32 ? (uint64_t)(uint32_t)ptr.geti32()
: (uint64_t)ptr.geti64();
Copy link
Member

Choose a reason for hiding this comment

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

Can this just be getUnsigned()? That returns uint64_t.

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