dotnet / dotnet/runtime

[wasm] R2R: 32-byte struct passed by value is corrupted (fields shifted by one word)

Open
#131,639 7 comments 0 reactions 2 assignees Claimed by @davidwrighton View on GitHub
arch-wasm area-CodeGen-coreclr
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Description

On `browser-wasm` (CoreCLR) with `PublishReadyToRun`, a 32-byte struct (four 8-byte fields) passed by value to a method is corrupted: the callee reads it shifted up by one 8-byte word, so each field takes the value of the next and the following argument bleeds in. 16- and 24-byte structs pass correctly.

### Repro

```csharp
using System;

struct S32 { public long A, B, C, D; }

class Program
{
static string E32(int x, S32 s, int y) => $"{x}|{s.A},{s.B},{s.C},{s.D}|{y}";

static void Main()
{
Console.WriteLine(E32(1, new S32 { A = 31, B = 32, C = 33, D = 34 }, 2));
}
}
```

`E32` must be ReadyToRun-compiled. Interpreted execution is correct.

### Expected

`1|31,32,33,34|2`

### Actual

`1|32,33,34,2|0`

`s.A` reads the input `B`, `s.B` reads `C`, `s.C` reads `D`, `s.D` reads the trailing `int y` (2), and `y` reads garbage (0) — i.e. the struct argument is read one 8-byte word too high.

### Notes

- 16-byte (`{ long, long }`) and 24-byte (`{ long, long, long }`) structs pass correctly; only the 32-byte (four-word) struct is affected.
- Reproduces with a direct call; reflection-invoking the same method corrupts it further.

### Configuration

- `-os browser -a wasm`, CoreCLR, `PublishReadyToRun` (crossgen2, `--obj-format:wasm`)
- Reproduces in Node and in the browser.

> [!NOTE]
> This issue was written with the assistance of GitHub Copilot.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.