Add runtime x64 stack-alignment regression test

A non-faulting probe payload returns (rsp+8)&15 from the callee, which is 0
only when the stub delivers callee entry rsp ≡ 8 (mod 16) per the Microsoft
x64 ABI. Proves the stub frame alignment end-to-end through CreateRemoteThread
without risking a #GP that would crash the in-process test host. Verified to
fail against the old fixed-0x20 frame.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
kbe
2026-07-22 01:13:45 +02:00
co-authored by Claude Opus 4.8
parent fa0b5b5013
commit 77736698ab
@@ -56,6 +56,15 @@ public sealed class RemoteThreadExecutorTests
// ret
private static readonly byte[] PointSumPayload = [0x8B, 0x01, 0x03, 0x41, 0x04, 0xC3];
// Measures the callee's entry stack alignment without faulting.
// mov eax, esp
// add eax, 8
// and eax, 0x0F
// ret
// Returns (rsp + 8) & 15, which is 0 iff callee entry rsp ≡ 8 (mod 16) — the
// Microsoft x64 ABI guarantee the stub must deliver.
private static readonly byte[] AlignProbePayload = [0x89, 0xE0, 0x83, 0xC0, 0x08, 0x83, 0xE0, 0x0F, 0xC3];
[StructLayout(LayoutKind.Sequential)]
private struct Point
{
@@ -87,6 +96,20 @@ public sealed class RemoteThreadExecutorTests
Assert.Equal(15, result);
}
[Fact]
public void Execute_delivers_16byte_aligned_stack_to_callee()
{
if (!Environment.Is64BitProcess)
{
return;
}
// Stub entry rsp ≡ 8 → sub rsp, K (K ≡ 8) → rsp ≡ 0 → call → callee entry rsp ≡ 8.
// So (rsp + 8) & 15 == 0 when the frame math is right; a bad K (e.g. 0x20) yields 8.
int misalign = RunPayload(AlignProbePayload, CallConvention.Cdecl);
Assert.Equal(0, misalign);
}
[Fact]
public void Execute_marshals_string_as_utf8_pointer()
{