fix(gateway): reject oversized sparse array total_length with InvalidArgument

Guard against proto uint32 total_length values that exceed Array.MaxLength
before casting; the previous checked cast threw OverflowException (gRPC
Internal) instead of the intended InvalidArgument. Adds tests for the new
guard, for the null-value ArgumentNullException path, and removes the
checked keyword (redundant after the guard).
This commit is contained in:
Joseph Doherty
2026-06-18 02:58:03 -04:00
parent 34a99c783b
commit 627c17fae1
2 changed files with 22 additions and 1 deletions
@@ -62,7 +62,13 @@ internal static class SparseArrayExpander
throw Invalid($"Sparse array element_data_type '{elementType}' is not a supported scalar element type.");
}
int length = checked((int)totalLength);
if (totalLength > (uint)Array.MaxLength)
{
throw Invalid(
$"Sparse array total_length {totalLength} exceeds the maximum supported array length {Array.MaxLength}.");
}
int length = (int)totalLength;
HashSet<uint> seenIndices = new();
foreach (MxSparseElement element in sparse.Elements)
@@ -192,4 +192,19 @@ public sealed class SparseArrayExpanderTests
Assert.Equal(MxValue.KindOneofCase.Int32Value, value.KindCase);
Assert.Equal(42, value.Int32Value);
}
[Fact]
public void Expand_NullValue_ThrowsArgumentNull()
{
Assert.Throws<ArgumentNullException>(() => SparseArrayExpander.Expand(null!));
}
[Fact]
public void Expand_TotalLengthExceedsMaxArrayLength_Throws()
{
MxValue value = SparseValue(MxDataType.Integer, 2_147_483_648u);
RpcException ex = Assert.Throws<RpcException>(() => SparseArrayExpander.Expand(value));
Assert.Equal(StatusCode.InvalidArgument, ex.StatusCode);
}
}