Skip to content

Commit c48cef0

Browse files
authored
Additional Hex parsing checks to ConnectionId and Identity (#3988)
# Description of Changes This PR fixes Release-only flakiness in C# runtime/property tests by making `ConnectionId` / `Identity` parsing and related low-level byte decoding strict about input length. Previously, length validation relied on `Debug.Assert`, which is compiled out in Release builds. That meant malformed inputs (wrong-length spans/strings) could slip through in Release and produce inconsistent behavior. Changes: * Updated `ConnectionId.FromHexString(string hex)` to throw when the input is not exactly 32 hex characters. * Updated `Identity.FromHexString(string hex)` to throw when the input is not exactly 64 hex characters. * Updated `Util.Read(ReadOnlySpan source, bool littleEndian)` to throw an `ArgumentException` when `source.Length != sizeof(T)` (instead of relying on `Debug.Assert`), preventing Release-mode “partial reads” from incorrectly-sized spans. # API and ABI breaking changes None. * No schema or wire-format changes. * Behavior change is limited to stricter validation of invalid/malformed inputs for `ConnectionId` / `Identity` parsing and internal runtime decoding. Valid inputs are unaffected. # Expected complexity level and risk 2 - Low * Changes are isolated to the C# BSATN runtime input validation paths. * No impact on valid serialization/normal runtime behavior; only affects invalid inputs and makes behavior consistent between Debug and Release. # Testing - [X] Ran C# BSATN runtime tests locally (Debug + Release) and verified they pass.
1 parent 952402d commit c48cef0

1 file changed

Lines changed: 31 additions & 7 deletions

File tree

crates/bindings-csharp/BSATN.Runtime/Builtins.cs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,13 @@ public static string ToHexBigEndian<T>(T val)
5353
public static T Read<T>(ReadOnlySpan<byte> source, bool littleEndian)
5454
where T : struct
5555
{
56-
Debug.Assert(
57-
source.Length == Marshal.SizeOf<T>(),
58-
$"Error while reading ${typeof(T).FullName}: expected source span to be {Marshal.SizeOf<T>()} bytes long, but was {source.Length} bytes."
59-
);
56+
var expectedSize = Marshal.SizeOf<T>();
57+
if (source.Length != expectedSize)
58+
{
59+
throw new ArgumentException(
60+
$"Error while reading {typeof(T).FullName}: expected source span to be {expectedSize} bytes long, but was {source.Length} bytes."
61+
);
62+
}
6063

6164
var result = MemoryMarshal.Read<T>(source);
6265

@@ -166,8 +169,18 @@ public readonly record struct ConnectionId
166169
/// </summary>
167170
/// <param name="hex"></param>
168171
/// <returns></returns>
169-
public static ConnectionId? FromHexString(string hex) =>
170-
FromBigEndian(Util.StringToByteArray(hex));
172+
public static ConnectionId? FromHexString(string hex)
173+
{
174+
if (hex.Length != 32)
175+
{
176+
throw new ArgumentException(
177+
$"Expected ConnectionId hex string to be 32 characters long, but was {hex.Length}.",
178+
nameof(hex)
179+
);
180+
}
181+
182+
return FromBigEndian(Util.StringToByteArray(hex));
183+
}
171184

172185
public static ConnectionId Random()
173186
{
@@ -268,7 +281,18 @@ public static Identity FromBigEndian(ReadOnlySpan<byte> bytes) =>
268281
/// </summary>
269282
/// <param name="hex"></param>
270283
/// <returns></returns>
271-
public static Identity FromHexString(string hex) => FromBigEndian(Util.StringToByteArray(hex));
284+
public static Identity FromHexString(string hex)
285+
{
286+
if (hex.Length != 64)
287+
{
288+
throw new ArgumentException(
289+
$"Expected Identity hex string to be 64 characters long, but was {hex.Length}.",
290+
nameof(hex)
291+
);
292+
}
293+
294+
return FromBigEndian(Util.StringToByteArray(hex));
295+
}
272296

273297
// --- auto-generated ---
274298
public readonly struct BSATN : IReadWrite<Identity>

0 commit comments

Comments
 (0)