From 627c17fae1ec5f4fbd58c25958b05ca63be6a410 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 18 Jun 2026 02:58:03 -0400 Subject: [PATCH] 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). --- .../Sessions/SparseArrayExpander.cs | 8 +++++++- .../Gateway/Sessions/SparseArrayExpanderTests.cs | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/ZB.MOM.WW.MxGateway.Server/Sessions/SparseArrayExpander.cs b/src/ZB.MOM.WW.MxGateway.Server/Sessions/SparseArrayExpander.cs index 890ff0b..c6d7c37 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/Sessions/SparseArrayExpander.cs +++ b/src/ZB.MOM.WW.MxGateway.Server/Sessions/SparseArrayExpander.cs @@ -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 seenIndices = new(); foreach (MxSparseElement element in sparse.Elements) diff --git a/src/ZB.MOM.WW.MxGateway.Tests/Gateway/Sessions/SparseArrayExpanderTests.cs b/src/ZB.MOM.WW.MxGateway.Tests/Gateway/Sessions/SparseArrayExpanderTests.cs index a329ad4..668230d 100644 --- a/src/ZB.MOM.WW.MxGateway.Tests/Gateway/Sessions/SparseArrayExpanderTests.cs +++ b/src/ZB.MOM.WW.MxGateway.Tests/Gateway/Sessions/SparseArrayExpanderTests.cs @@ -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(() => SparseArrayExpander.Expand(null!)); + } + + [Fact] + public void Expand_TotalLengthExceedsMaxArrayLength_Throws() + { + MxValue value = SparseValue(MxDataType.Integer, 2_147_483_648u); + + RpcException ex = Assert.Throws(() => SparseArrayExpander.Expand(value)); + Assert.Equal(StatusCode.InvalidArgument, ex.StatusCode); + } }