diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs index e8b28825888e4..4b24b1912e89a 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArrayInfo.cs @@ -13,7 +13,7 @@ namespace System.Formats.Nrbf; /// /// ArrayInfo structures are described in [MS-NRBF] 2.4.2.1. /// -[DebuggerDisplay("Length={Length}, {ArrayType}, rank={Rank}")] +[DebuggerDisplay("{ArrayType}, rank={Rank}")] internal readonly struct ArrayInfo { internal const int MaxArrayLength = 2147483591; // Array.MaxLength diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs index 5b3b974639468..46693c344bc84 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySinglePrimitiveRecord.cs @@ -41,17 +41,9 @@ internal ArraySinglePrimitiveRecord(ArrayInfo arrayInfo, IReadOnlyList values public override T[] GetArray(bool allowNulls = true) => (T[])(_arrayNullsNotAllowed ??= (Values is T[] array ? array : Values.ToArray())); - internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetAllowedRecordType() - { - Debug.Fail("GetAllowedRecordType should never be called on ArraySinglePrimitiveRecord"); - throw new InvalidOperationException(); - } + internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetAllowedRecordType() => throw new InvalidOperationException(); - private protected override void AddValue(object value) - { - Debug.Fail("AddValue should never be called on ArraySinglePrimitiveRecord"); - throw new InvalidOperationException(); - } + private protected override void AddValue(object value) => throw new InvalidOperationException(); internal static IReadOnlyList DecodePrimitiveTypes(BinaryReader reader, int count) { @@ -94,7 +86,7 @@ internal static IReadOnlyList DecodePrimitiveTypes(BinaryReader reader, int c #if NET reader.BaseStream.ReadExactly(resultAsBytes); #else - byte[] bytes = ArrayPool.Shared.Rent(Math.Min(count * Unsafe.SizeOf(), 256_000)); + byte[] bytes = ArrayPool.Shared.Rent((int)Math.Min(requiredBytes, 256_000)); while (!resultAsBytes.IsEmpty) { @@ -159,31 +151,10 @@ internal static IReadOnlyList DecodePrimitiveTypes(BinaryReader reader, int c private static List DecodeDecimals(BinaryReader reader, int count) { List values = new(); -#if NET - Span buffer = stackalloc byte[256]; - for (int i = 0; i < count; i++) - { - int stringLength = reader.Read7BitEncodedInt(); - if (!(stringLength > 0 && stringLength <= buffer.Length)) - { - ThrowHelper.ThrowInvalidValue(stringLength); - } - - reader.BaseStream.ReadExactly(buffer.Slice(0, stringLength)); - - if (!decimal.TryParse(buffer.Slice(0, stringLength), NumberStyles.Number, CultureInfo.InvariantCulture, out decimal value)) - { - ThrowHelper.ThrowInvalidFormat(); - } - - values.Add(value); - } -#else for (int i = 0; i < count; i++) { values.Add(reader.ParseDecimal()); } -#endif return values; } @@ -244,12 +215,14 @@ private static List DecodeFromNonSeekableStream(BinaryReader reader, int coun { values.Add((T)(object)Utils.BinaryReaderExtensions.CreateDateTimeFromData(reader.ReadUInt64())); } - else + else if (typeof(T) == typeof(TimeSpan)) { - Debug.Assert(typeof(T) == typeof(TimeSpan)); - values.Add((T)(object)new TimeSpan(reader.ReadInt64())); } + else + { + throw new InvalidOperationException(); + } } return values; diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs index de248bcef7675..7fed2a494b9b0 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/ArraySingleStringRecord.cs @@ -21,7 +21,7 @@ internal sealed class ArraySingleStringRecord : SZArrayRecord public override SerializationRecordType RecordType => SerializationRecordType.ArraySingleString; /// - public override TypeName TypeName => TypeNameHelpers.GetPrimitiveSZArrayTypeName(PrimitiveType.String); + public override TypeName TypeName => TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.StringPrimitiveType); private List Records { get; } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs index 0c7e04e840a48..5aa4878016d9f 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryArrayRecord.cs @@ -138,7 +138,7 @@ internal static ArrayRecord Decode(BinaryReader reader, RecordMap recordMap, Pay lengths[i] = ArrayInfo.ParseValidArrayLength(reader); totalElementCount *= lengths[i]; - if (totalElementCount > uint.MaxValue) + if (totalElementCount > ArrayInfo.MaxArrayLength) { ThrowHelper.ThrowInvalidValue(lengths[i]); // max array size exceeded } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs index ccd39922e23fb..7318052610e1b 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/BinaryLibraryRecord.cs @@ -30,14 +30,7 @@ private BinaryLibraryRecord(SerializationRecordId libraryId, AssemblyNameInfo li public override SerializationRecordType RecordType => SerializationRecordType.BinaryLibrary; - public override TypeName TypeName - { - get - { - Debug.Fail("TypeName should never be called on BinaryLibraryRecord"); - return TypeName.Parse(nameof(BinaryLibraryRecord).AsSpan()); - } - } + public override TypeName TypeName => TypeName.Parse(nameof(BinaryLibraryRecord).AsSpan()); internal string? RawLibraryName { get; } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs index 9843a0b71f04c..2e4b7e1399be2 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MemberTypeInfo.cs @@ -53,10 +53,14 @@ internal static MemberTypeInfo Decode(BinaryReader reader, int count, PayloadOpt case BinaryType.Class: info[i] = (type, ClassTypeInfo.Decode(reader, options, recordMap)); break; - default: - // Other types have no additional data. - Debug.Assert(type is BinaryType.String or BinaryType.ObjectArray or BinaryType.StringArray or BinaryType.Object); + case BinaryType.String: + case BinaryType.StringArray: + case BinaryType.Object: + case BinaryType.ObjectArray: + // These types have no additional data. break; + default: + throw new InvalidOperationException(); } } @@ -97,7 +101,8 @@ internal static MemberTypeInfo Decode(BinaryReader reader, int count, PayloadOpt BinaryType.PrimitiveArray => (PrimitiveArray, default), BinaryType.Class => (NonSystemClass, default), BinaryType.SystemClass => (SystemClass, default), - _ => (ObjectArray, default) + BinaryType.ObjectArray => (ObjectArray, default), + _ => throw new InvalidOperationException() }; } @@ -144,15 +149,15 @@ internal TypeName GetArrayTypeName(ArrayInfo arrayInfo) TypeName elementTypeName = binaryType switch { - BinaryType.String => TypeNameHelpers.GetPrimitiveTypeName(PrimitiveType.String), - BinaryType.StringArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName(PrimitiveType.String), + BinaryType.String => TypeNameHelpers.GetPrimitiveTypeName(TypeNameHelpers.StringPrimitiveType), + BinaryType.StringArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.StringPrimitiveType), BinaryType.Primitive => TypeNameHelpers.GetPrimitiveTypeName((PrimitiveType)additionalInfo!), BinaryType.PrimitiveArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName((PrimitiveType)additionalInfo!), BinaryType.Object => TypeNameHelpers.GetPrimitiveTypeName(TypeNameHelpers.ObjectPrimitiveType), BinaryType.ObjectArray => TypeNameHelpers.GetPrimitiveSZArrayTypeName(TypeNameHelpers.ObjectPrimitiveType), BinaryType.SystemClass => (TypeName)additionalInfo!, BinaryType.Class => ((ClassTypeInfo)additionalInfo!).TypeName, - _ => throw new ArgumentOutOfRangeException(paramName: nameof(binaryType), actualValue: binaryType, message: null) + _ => throw new InvalidOperationException() }; // In general, arrayRank == 1 may have two different meanings: diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs index 7cb28224a890e..62c7d57b3fa37 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/MessageEndRecord.cs @@ -24,12 +24,5 @@ private MessageEndRecord() public override SerializationRecordId Id => SerializationRecordId.NoId; - public override TypeName TypeName - { - get - { - Debug.Fail("TypeName should never be called on MessageEndRecord"); - return TypeName.Parse(nameof(MessageEndRecord).AsSpan()); - } - } + public override TypeName TypeName => TypeName.Parse(nameof(MessageEndRecord).AsSpan()); } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs index de4b24b6e46e1..fc03409bd2eec 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs @@ -69,28 +69,22 @@ public static bool StartsWithPayloadHeader(Stream stream) return false; } - try + byte[] buffer = new byte[SerializedStreamHeaderRecord.Size]; + int offset = 0; + while (offset < buffer.Length) { -#if NET - Span buffer = stackalloc byte[SerializedStreamHeaderRecord.Size]; - stream.ReadExactly(buffer); -#else - byte[] buffer = new byte[SerializedStreamHeaderRecord.Size]; - int offset = 0; - while (offset < buffer.Length) + int read = stream.Read(buffer, offset, buffer.Length - offset); + if (read == 0) { - int read = stream.Read(buffer, offset, buffer.Length - offset); - if (read == 0) - throw new EndOfStreamException(); - offset += read; + stream.Position = beginning; + return false; } -#endif - return StartsWithPayloadHeader(buffer); - } - finally - { - stream.Position = beginning; + offset += read; } + + bool result = StartsWithPayloadHeader(buffer); + stream.Position = beginning; + return result; } /// @@ -241,7 +235,8 @@ private static SerializationRecord DecodeNext(BinaryReader reader, RecordMap rec SerializationRecordType.ObjectNullMultiple => ObjectNullMultipleRecord.Decode(reader), SerializationRecordType.ObjectNullMultiple256 => ObjectNullMultiple256Record.Decode(reader), SerializationRecordType.SerializedStreamHeader => SerializedStreamHeaderRecord.Decode(reader), - _ => SystemClassWithMembersAndTypesRecord.Decode(reader, recordMap, options), + SerializationRecordType.SystemClassWithMembersAndTypes => SystemClassWithMembersAndTypesRecord.Decode(reader, recordMap, options), + _ => throw new InvalidOperationException() }; recordMap.Add(record); @@ -269,8 +264,8 @@ private static SerializationRecord DecodeMemberPrimitiveTypedRecord(BinaryReader PrimitiveType.Double => new MemberPrimitiveTypedRecord(reader.ReadDouble()), PrimitiveType.Decimal => new MemberPrimitiveTypedRecord(reader.ParseDecimal()), PrimitiveType.DateTime => new MemberPrimitiveTypedRecord(Utils.BinaryReaderExtensions.CreateDateTimeFromData(reader.ReadUInt64())), - // String is handled with a record, never on it's own - _ => new MemberPrimitiveTypedRecord(new TimeSpan(reader.ReadInt64())), + PrimitiveType.TimeSpan => new MemberPrimitiveTypedRecord(new TimeSpan(reader.ReadInt64())), + _ => throw new InvalidOperationException() }; } @@ -295,7 +290,8 @@ private static SerializationRecord DecodeArraySinglePrimitiveRecord(BinaryReader PrimitiveType.Double => Decode(info, reader), PrimitiveType.Decimal => Decode(info, reader), PrimitiveType.DateTime => Decode(info, reader), - _ => Decode(info, reader), + PrimitiveType.TimeSpan => Decode(info, reader), + _ => throw new InvalidOperationException() }; static SerializationRecord Decode(ArrayInfo info, BinaryReader reader) where T : unmanaged diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs index d3d859c193a9c..9c11db4307ced 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NullsRecord.cs @@ -12,12 +12,5 @@ internal abstract class NullsRecord : SerializationRecord public override SerializationRecordId Id => SerializationRecordId.NoId; - public override TypeName TypeName - { - get - { - Debug.Fail($"TypeName should never be called on {GetType().Name}"); - return TypeName.Parse(GetType().Name.AsSpan()); - } - } + public override TypeName TypeName => TypeName.Parse(GetType().Name.AsSpan()); } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs index 9ddb9179518fa..f2e696e6a90e9 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/PrimitiveType.cs @@ -11,10 +11,6 @@ namespace System.Formats.Nrbf; /// internal enum PrimitiveType : byte { - /// - /// Used internally to express no value - /// - None = 0, Boolean = 1, Byte = 2, Char = 3, @@ -30,7 +26,19 @@ internal enum PrimitiveType : byte DateTime = 13, UInt16 = 14, UInt32 = 15, - UInt64 = 16, - Null = 17, - String = 18 + UInt64 = 16 + // This internal enum no longer contains Null and String as they were always illegal: + // - In case of BinaryArray (NRBF 2.4.3.1): + // "If the BinaryTypeEnum value is Primitive, the PrimitiveTypeEnumeration + // value in AdditionalTypeInfo MUST NOT be Null (17) or String (18)." + // - In case of MemberPrimitiveTyped (NRBF 2.5.1): + // "PrimitiveTypeEnum (1 byte): A PrimitiveTypeEnumeration + // value that specifies the Primitive Type of data that is being transmitted. + // This field MUST NOT contain a value of 17 (Null) or 18 (String)." + // - In case of ArraySinglePrimitive (NRBF 2.4.3.3): + // "A PrimitiveTypeEnumeration value that identifies the Primitive Type + // of the items of the Array. The value MUST NOT be 17 (Null) or 18 (String)." + // - In case of MemberTypeInfo (NRBF 2.3.1.2): + // "When the BinaryTypeEnum value is Primitive, the PrimitiveTypeEnumeration + // value in AdditionalInfo MUST NOT be Null (17) or String (18)." } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs index 04a4d0e085048..eafcbf93249c5 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RecordMap.cs @@ -56,7 +56,7 @@ internal void Add(SerializationRecord record) return; } #endif - throw new SerializationException(SR.Format(SR.Serialization_DuplicateSerializationRecordId, record.Id)); + throw new SerializationException(SR.Format(SR.Serialization_DuplicateSerializationRecordId, record.Id._id)); } } } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs index de3c6d671850a..bc286e56ee5c2 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/RectangularArrayRecord.cs @@ -14,7 +14,7 @@ namespace System.Formats.Nrbf; internal sealed class RectangularArrayRecord : ArrayRecord { private readonly int[] _lengths; - private readonly ICollection _values; + private readonly List _values; private TypeName? _typeName; private RectangularArrayRecord(Type elementType, ArrayInfo arrayInfo, @@ -24,18 +24,8 @@ private RectangularArrayRecord(Type elementType, ArrayInfo arrayInfo, MemberTypeInfo = memberTypeInfo; _lengths = lengths; - // A List can hold as many objects as an array, so for multi-dimensional arrays - // with more elements than Array.MaxLength we use LinkedList. - // Testing that many elements takes a LOT of time, so to ensure that both code paths are tested, - // we always use LinkedList code path for Debug builds. -#if DEBUG - _values = new LinkedList(); -#else - _values = arrayInfo.TotalElementsCount <= ArrayInfo.MaxArrayLength - ? new List(canPreAllocate ? arrayInfo.GetSZArrayLength() : Math.Min(4, arrayInfo.GetSZArrayLength())) - : new LinkedList(); -#endif - + // ArrayInfo.GetSZArrayLength ensures to return a value <= Array.MaxLength + _values = new List(canPreAllocate ? arrayInfo.GetSZArrayLength() : Math.Min(4, arrayInfo.GetSZArrayLength())); } public override SerializationRecordType RecordType => SerializationRecordType.BinaryArray; @@ -108,6 +98,7 @@ private protected override Array Deserialize(Type arrayType, bool allowNulls) else if (ElementType == typeof(TimeSpan)) CopyTo(_values, result); else if (ElementType == typeof(DateTime)) CopyTo(_values, result); else if (ElementType == typeof(decimal)) CopyTo(_values, result); + else throw new InvalidOperationException(); } else { @@ -116,7 +107,7 @@ private protected override Array Deserialize(Type arrayType, bool allowNulls) return result; - static void CopyTo(ICollection list, Array array) + static void CopyTo(List list, Array array) { ref byte arrayDataRef = ref MemoryMarshal.GetArrayDataReference(array); ref T firstElementRef = ref Unsafe.As(ref arrayDataRef); @@ -176,7 +167,10 @@ internal static RectangularArrayRecord Create(BinaryReader reader, ArrayInfo arr PrimitiveType.Int64 => sizeof(long), PrimitiveType.UInt64 => sizeof(ulong), PrimitiveType.Double => sizeof(double), - _ => -1 + PrimitiveType.TimeSpan => sizeof(ulong), + PrimitiveType.DateTime => sizeof(ulong), + PrimitiveType.Decimal => -1, // represented as variable-length string + _ => throw new InvalidOperationException() }; if (sizeOfSingleValue > 0) @@ -215,7 +209,8 @@ private static Type MapPrimitive(PrimitiveType primitiveType) PrimitiveType.DateTime => typeof(DateTime), PrimitiveType.UInt16 => typeof(ushort), PrimitiveType.UInt32 => typeof(uint), - _ => typeof(ulong) + PrimitiveType.UInt64 => typeof(ulong), + _ => throw new InvalidOperationException() }; private static Type MapPrimitiveArray(PrimitiveType primitiveType) @@ -235,7 +230,8 @@ private static Type MapPrimitiveArray(PrimitiveType primitiveType) PrimitiveType.DateTime => typeof(DateTime[]), PrimitiveType.UInt16 => typeof(ushort[]), PrimitiveType.UInt32 => typeof(uint[]), - _ => typeof(ulong[]), + PrimitiveType.UInt64 => typeof(ulong[]), + _ => throw new InvalidOperationException() }; private static object? GetActualValue(object value) diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs index 531ff87cd894e..09af5ff0a4ed3 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecord.cs @@ -114,8 +114,8 @@ private static bool Matches(Type type, TypeName typeName) internal virtual object? GetValue() => this; internal virtual void HandleNextRecord(SerializationRecord nextRecord, NextInfo info) - => Debug.Fail($"HandleNextRecord should not have been called for '{GetType().Name}'"); + => throw new InvalidOperationException(); internal virtual void HandleNextValue(object value, NextInfo info) - => Debug.Fail($"HandleNextValue should not have been called for '{GetType().Name}'"); + => throw new InvalidOperationException(); } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs index 7f51525e6e113..a7478f5e3ffe0 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializationRecordId.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Formats.Nrbf.Utils; using System.IO; using System.Linq; @@ -15,6 +16,7 @@ namespace System.Formats.Nrbf; /// /// The ID of . /// +[DebuggerDisplay("{_id}")] public readonly struct SerializationRecordId : IEquatable { #pragma warning disable CS0649 // the default value is used on purpose diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs index 4757958fcb777..b21ff8ca23732 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SerializedStreamHeaderRecord.cs @@ -24,14 +24,8 @@ internal sealed class SerializedStreamHeaderRecord : SerializationRecord public override SerializationRecordType RecordType => SerializationRecordType.SerializedStreamHeader; - public override TypeName TypeName - { - get - { - Debug.Fail("TypeName should never be called on SerializedStreamHeaderRecord"); - return TypeName.Parse(nameof(SerializedStreamHeaderRecord).AsSpan()); - } - } + public override TypeName TypeName => TypeName.Parse(nameof(SerializedStreamHeaderRecord).AsSpan()); + public override SerializationRecordId Id => SerializationRecordId.NoId; internal SerializationRecordId RootId { get; } diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs index ff422c29401a1..a174d11dfffbe 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/BinaryReaderExtensions.cs @@ -60,8 +60,8 @@ internal static BinaryType ReadBinaryType(this BinaryReader reader) internal static PrimitiveType ReadPrimitiveType(this BinaryReader reader) { byte primitiveType = reader.ReadByte(); - // String is the last defined value, 4 is not used at all. - if (primitiveType is 0 or 4 or (byte)PrimitiveType.Null or > (byte)PrimitiveType.String) + // Boolean is the first valid value (1), UInt64 (16) is the last one. 4 is not used at all. + if (primitiveType is 4 or < (byte)PrimitiveType.Boolean or > (byte)PrimitiveType.UInt64) { ThrowHelper.ThrowInvalidValue(primitiveType); } @@ -88,7 +88,8 @@ internal static object ReadPrimitiveValue(this BinaryReader reader, PrimitiveTyp PrimitiveType.Double => reader.ReadDouble(), PrimitiveType.Decimal => reader.ParseDecimal(), PrimitiveType.DateTime => CreateDateTimeFromData(reader.ReadUInt64()), - _ => new TimeSpan(reader.ReadInt64()), + PrimitiveType.TimeSpan => new TimeSpan(reader.ReadInt64()), + _ => throw new InvalidOperationException(), }; // BinaryFormatter serializes decimals as strings and we can't BinaryReader.ReadDecimal. @@ -117,14 +118,22 @@ internal static char ParseChar(this BinaryReader reader) internal static char[] ParseChars(this BinaryReader reader, int count) { + char[]? result; try { - return reader.ReadChars(count); + result = reader.ReadChars(count); } catch (ArgumentException) // A surrogate character was read. { throw new SerializationException(SR.Serialization_SurrogateCharacter); } + + if (result.Length != count) + { + ThrowHelper.ThrowEndOfStreamException(); + } + + return result; } /// diff --git a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameHelpers.cs b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameHelpers.cs index 97c3b4e42f68b..1c08a5c24eca5 100644 --- a/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameHelpers.cs +++ b/src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/Utils/TypeNameHelpers.cs @@ -12,7 +12,8 @@ namespace System.Formats.Nrbf.Utils; internal static class TypeNameHelpers { - // PrimitiveType does not define Object, IntPtr or UIntPtr + // PrimitiveType does not define Object, IntPtr or UIntPtr. + internal const PrimitiveType StringPrimitiveType = (PrimitiveType)18; internal const PrimitiveType ObjectPrimitiveType = (PrimitiveType)19; internal const PrimitiveType IntPtrPrimitiveType = (PrimitiveType)20; internal const PrimitiveType UIntPtrPrimitiveType = (PrimitiveType)21; @@ -22,8 +23,6 @@ internal static class TypeNameHelpers internal static TypeName GetPrimitiveTypeName(PrimitiveType primitiveType) { - Debug.Assert(primitiveType is not (PrimitiveType.None or PrimitiveType.Null)); - TypeName? typeName = s_primitiveTypeNames[(int)primitiveType]; if (typeName is null) { @@ -44,11 +43,11 @@ internal static TypeName GetPrimitiveTypeName(PrimitiveType primitiveType) PrimitiveType.Decimal => "System.Decimal", PrimitiveType.TimeSpan => "System.TimeSpan", PrimitiveType.DateTime => "System.DateTime", - PrimitiveType.String => "System.String", + StringPrimitiveType => "System.String", ObjectPrimitiveType => "System.Object", IntPtrPrimitiveType => "System.IntPtr", UIntPtrPrimitiveType => "System.UIntPtr", - _ => throw new ArgumentOutOfRangeException(paramName: nameof(primitiveType), actualValue: primitiveType, message: null) + _ => throw new InvalidOperationException() }; s_primitiveTypeNames[(int)primitiveType] = typeName = TypeName.Parse(fullName.AsSpan()).WithCoreLibAssemblyName(); @@ -99,7 +98,7 @@ internal static PrimitiveType GetPrimitiveType() else if (typeof(T) == typeof(TimeSpan)) return PrimitiveType.TimeSpan; else if (typeof(T) == typeof(string)) - return PrimitiveType.String; + return StringPrimitiveType; else if (typeof(T) == typeof(IntPtr)) return IntPtrPrimitiveType; else if (typeof(T) == typeof(UIntPtr))