Guard BuildCallStub against argument-count overflow

The x64 frame math (0x20 + 8*stackArgs) and x86 arg buffer size grow with the
argument count. An absurdly large count could overflow int and produce a bogus
or negative frame. Add a MaxArguments (256) bound checked at the public entry —
far above any real calling convention — so the arithmetic stays in range. Add a
test asserting the cap is inclusive and count+1 throws.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
kbe
2026-07-21 22:10:33 +02:00
co-authored by Claude Opus 4.8
parent cb437ef9b5
commit b06a034072
2 changed files with 30 additions and 2 deletions
+16 -2
View File
@@ -13,6 +13,13 @@ namespace WhiteMagic.Assembly;
/// </remarks>
public sealed class StubAssembler : IAssembler
{
/// <summary>
/// The maximum number of call arguments a single stub may pass. Far above any real
/// calling convention; exists only to keep frame-size and stack-offset math from
/// overflowing <see cref="int"/>.
/// </summary>
public const int MaxArguments = 256;
/// <inheritdoc />
public byte[] Assemble(string assemblyText, ulong origin = 0)
{
@@ -51,11 +58,18 @@ public sealed class StubAssembler : IAssembler
/// <param name="pointerSize">4 (x86) or 8 (x64).</param>
/// <param name="convention">Calling convention (ignored on x64; Windows has a single ABI).</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="pointerSize"/> is not 4 or 8,
/// or <paramref name="convention"/> is not known, or the distance between stub and target
/// exceeds the E8 rel32 range.</exception>
/// or <paramref name="convention"/> is not known, or <paramref name="arguments"/> exceeds
/// <see cref="MaxArguments"/>, or the distance between stub and target exceeds the E8 rel32
/// range.</exception>
public byte[] BuildCallStub(IntPtr stubAddress, IntPtr targetAddress,
nuint[] arguments, int pointerSize, CallConvention convention)
{
ArgumentNullException.ThrowIfNull(arguments);
// Bound the argument count. No real calling convention passes anywhere near this
// many; the cap keeps the frame-size and stack-offset arithmetic (0x20 + 8*stackArgs)
// well inside int range, so it can never overflow into a bogus/negative frame.
ArgumentOutOfRangeException.ThrowIfGreaterThan(arguments.Length, MaxArguments, nameof(arguments));
var buffer = new List<byte>(96);
if (pointerSize == 4)