Commit Graph
3 Commits
Author SHA1 Message Date
kbeandClaude Opus 4.8 cb437ef9b5 Fix x64 stub ABI and marshal-path sizing; dedupe RPM readers
x64 call stub was ABI-broken: fixed 0x20 frame left rsp misaligned at the
inner call (callee entry rsp ≡ 0, ABI requires ≡ 8) and, for 5+ args, wrote
stack args over the return address. Compute frame K ≡ 8 (mod 16), K ≥
0x20 + 8*stackArgs, so the callee sees a 16-aligned stack and stack args land
above the shadow window. Load register args as full 64-bit imm64 (was imm32,
which truncated pointers > 4 GiB). BuildCallStub now takes nuint[]; x86 range-
checks each arg against uint.MaxValue instead of silently truncating.

MarshalCache conflated managed and unmanaged width in one Size field: the
blittable path needs Unsafe.SizeOf<T> (bool = 1) while the marshal path needs
Marshal.SizeOf<T> (inline ByValTStr/ByValArray expand past the managed
pointer). Add MarshalSize; MemoryBase picks per TypeRequiresMarshal at all four
IO sites. Prevents PtrToStructure/StructureToPtr from over-reading/overwriting
the pinned scratch buffer (heap corruption on write).

Extract shared RPM/WPM into RpmHelper: honor partial reads (dead Array.Resize
removed), consistent write-return semantics; InProcessReader now guards
MainModule like ExternalReader.

Tests: x64 frame-alignment property + inline-marshal round-trip added (both
fail against the pre-fix code); existing x64 byte-expectation tests updated to
the new frame. Build clean, 100/100 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 21:53:22 +02:00
kbeandClaude Opus 4.8 7c5e72e0e0 Harden memory layer: fix char sizing, ref structs, count guards, ReadString advance
Second-review fixes, each covered by a regression test in MemoryHardeningTests:

- MarshalCache: special-case char (Size=2; Marshal.SizeOf reports 1/ANSI but the
  blittable path reads a 2-byte UTF-16 unit). TypeRequiresMarshal now also trips on
  RuntimeHelpers.IsReferenceOrContainsReferences<T>() so reference-carrying structs
  route to the marshal path instead of throwing in MemoryMarshal.Read. Document that
  the MarshalAs scan is top-level only.
- MemoryBase.Read<T>(count): reject negative count (ArgumentOutOfRangeException) and
  guard elementSize*count overflow. Same overflow guard on Write<T>(values).
- MemoryBase.ReadString: advance by bytes actually read, not the requested amount, so
  a partial read no longer skips the unread tail of the window.
- ExternalReader: default to a minimal access set (not AllAccess, which over-requests
  and fails on protected processes); wrap Process.MainModule in try/catch so a
  bitness-mismatched or protected target yields ImageBase=Zero instead of throwing.
- NativeMethods: WaitForSingleObject and CreateRemoteThread's threadId are DWORD (uint),
  not int — the signatures no longer sign-flip.

Deferred: hoisting the identical ExternalReader/InProcessReader byte-IO into MemoryBase
(cosmetic; skipped to avoid colliding with concurrent Phase 3 edits).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 19:47:24 +02:00
kbe ccde012e45 task 2.1-2.2: implement MarshalCache<T> with tests
Add MarshalCache<T> static class that computes Size, SizeU,
TypeRequiresMarshal, IsIntPtr, TypeCode, and RealType once per type
in the static constructor. Handles bool (size=1), enums (underlying
type), and MarshalAs-attributed fields (TypeRequiresMarshal).

12 new tests covering: blittable sizes, bool size, enum size, struct
size, marshal-required flag, IsIntPtr, computed-once caching.
All passing.
2026-07-21 17:03:23 +02:00