Skip to content

Fix i32 sign extension in MemoryPacking pass#8368

Open
sumleo wants to merge 1 commit intoWebAssembly:mainfrom
sumleo:fix-memory-packing-sign-extension
Open

Fix i32 sign extension in MemoryPacking pass#8368
sumleo wants to merge 1 commit intoWebAssembly:mainfrom
sumleo:fix-memory-packing-sign-extension

Conversation

@sumleo
Copy link
Contributor

@sumleo sumleo commented Feb 24, 2026

Summary

  • Fix sign extension of geti32() results when assigned to uint64_t/size_t in MemoryPacking pass
  • In visitMemoryInit (line 465-466): offsetVal and sizeVal sign-extend for values >= 0x80000000, causing valid memory.init instructions to be incorrectly replaced with traps
  • In createSplitSegments (line 713-714): same pattern corrupts start/end range calculation for segment splitting

The fix casts through uint32_t before widening, consistent with the pattern already used at lines 458 and 461 in the same function.

Test plan

  • Build succeeds with no warnings
  • All 309 GTest unit tests pass
  • All wasm-opt tests pass (MemoryPacking pass is exercised there)

if (offset && size) {
uint64_t offsetVal(offset->value.geti32());
uint64_t sizeVal(size->value.geti32());
uint64_t offsetVal(uint32_t(offset->value.geti32()));
Copy link
Member

Choose a reason for hiding this comment

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

These can all be in the form auto x = value->getUnsigned(), which would be simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done — switched to getUnsigned() for all four occurrences. Also cleaned up the existing uint32_t() casts on lines 458/461 to use getUnsigned() consistently.

Use getUnsigned() to properly zero-extend i32 values when computing
memory.init offset and size. Previously, geti32() returned a signed
int32_t that sign-extended when stored as uint64_t, causing values
>= 0x80000000 to produce incorrect overflow detection and range
calculations.

Also clean up existing uint32_t() casts in the same function to
use getUnsigned() consistently.
@sumleo sumleo force-pushed the fix-memory-packing-sign-extension branch from 0a19127 to a3eb99c Compare February 25, 2026 01:14
Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

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

lgtm, thanks!

Though before landing, I have a question for @tlively - how did we not see crashes with running this pass on memory64? All the places that assume a segment offset is 32-bit were wrong, weren't they?

And we do run this pass on memory64, each time e.g. emscripten compiles memory64 code?

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