From 259891a99855470401e89c89b7305e46610e6706 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Mon, 29 Jun 2026 17:31:58 -0500 Subject: [PATCH 01/14] fix This fixes an edge case scenario with string reading where if user code has caused the character count to have been already read prior to attempting to read a string value (safely or unsafely) and then reading the string can result in the signed integer size to roll over to a negative value and thus causing the reader to attempt to read into restricted memory outside of the application domain which results in the editor crashing. The fix catches this scenario and throws an overflow exception prior to attempting to read into negative memory space relative to the application domain. --- .../Runtime/Serialization/FastBufferReader.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index d420ccd28e..8df4acbade 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -572,6 +572,11 @@ public void ReadNetworkSerializableInPlace(ref T value) where T : INetworkSer public unsafe void ReadValue(out string s, bool oneByteChars = false) { ReadLength(out int length); + var readSize = oneByteChars ? length : length * sizeof(char); + if (int.MaxValue < (uint)readSize) + { + throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from reading the same serialized value more than once causing the position to be improperly offset."); + } s = "".PadRight(length); int target = s.Length; fixed (char* native = s) @@ -617,6 +622,12 @@ public unsafe void ReadValueSafe(out string s, bool oneByteChars = false) ReadLength(out int length); + var readSize = oneByteChars ? length : length * sizeof(char); + if (int.MaxValue < (uint)readSize) + { + throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from reading the same serialized value more than once causing the position to be improperly offset."); + } + if (!TryBeginReadInternal(length * (oneByteChars ? 1 : sizeof(char)))) { throw new OverflowException("Reading past the end of the buffer"); From 6133d41fced58fe3da4f980fb671d77a476e753b Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Mon, 29 Jun 2026 17:32:11 -0500 Subject: [PATCH 02/14] test This test validates the fix. --- .../Serialization/FastBufferReaderTests.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs index 85aabbb52e..ff53c76acf 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs @@ -924,6 +924,40 @@ public void GivenFastBufferWriterContainingValue_WhenReadingString_ValueMatchesW } } + /// + /// This validates that catches a potential + /// scenario where the string's character count value has already been read + /// due to an error within user script and the resultant character count + /// multiplied times 2 (when using 2 bytes vs 1) causes the length to roll over + /// to a negative value which, in turn, causes the reader to attempt to read + /// into restricted memory and causes the editor to crash. + /// + [Test] + public void ReadingStringAfterStringLengthHasAlreadyBeenRead() + { + // This was an issue uncovered in UUM-145752 that resulted + // in the below text to result in a length that when using + // 2 bytes per character would cause the skewed size to roll + // over into a negative value causing the editor to crash + // when it attempted to read a large negative offset value. + string valueToTest = "true"; + + var serializedValueSize = FastBufferWriter.GetWriteSize(valueToTest); + + using var writer = new FastBufferWriter(serializedValueSize + 3, Allocator.Temp); + writer.WriteValueSafe(valueToTest); + + using var reader = new FastBufferReader(writer, Allocator.Temp); + + // Read the value of the character count before trying to read the string + // This mocks user code having read too far into a stream causing the position to be skewed such that + // the string reader reads the some of the bytes for the actual text as the length. + reader.ReadByteSafe(out byte count); + Assert.True(count == valueToTest.Length, $"Count ({count}) is not the expected size of {valueToTest.Length}!"); + + // This should throw an overflow exception but should not crash the editor. + Assert.Throws(() => reader.ReadValueSafe(out string valueRead)); + } [TestCase(1, 0)] [TestCase(2, 0)] From 5184e54878f9570c79b0bdd7ad556c3b831405db Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Mon, 29 Jun 2026 17:43:53 -0500 Subject: [PATCH 03/14] update Adding changelog entry. --- com.unity.netcode.gameobjects/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 3f6df83f11..0c5e47d1a0 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -21,6 +21,8 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed + +- Issue when FastBufferReader is attempting to read a string and all or a portion of the character count has already been read by user script, it could read a character length that results in a negative byte length which could result in an editor crash. (#4052) - Issue where NetworkRigidbodyBase was not applying rotation correctly when using Rigidbody2D. (#4012) - Issue where NetworkRigidbodyBase was always checking the 3D rigid body's interpolation mode when determining if it is kinematic and needs to put the rigid body to sleep and then switch to interpolation. (#4012) From 41660e82aa4dc53ca2840728f83e8316321f8f1a Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Mon, 29 Jun 2026 17:46:52 -0500 Subject: [PATCH 04/14] update Making the reader use the already calculated readSize. --- .../Runtime/Serialization/FastBufferReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index 8df4acbade..48ad2fa2a0 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -577,7 +577,7 @@ public unsafe void ReadValue(out string s, bool oneByteChars = false) { throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from reading the same serialized value more than once causing the position to be improperly offset."); } - s = "".PadRight(length); + s = "".PadRight(readSize); int target = s.Length; fixed (char* native = s) { @@ -628,7 +628,7 @@ public unsafe void ReadValueSafe(out string s, bool oneByteChars = false) throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from reading the same serialized value more than once causing the position to be improperly offset."); } - if (!TryBeginReadInternal(length * (oneByteChars ? 1 : sizeof(char)))) + if (!TryBeginReadInternal(readSize)) { throw new OverflowException("Reading past the end of the buffer"); } From 4aed486a62cf2ca9b7673d12bfbefdeab03b431f Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Mon, 29 Jun 2026 17:57:08 -0500 Subject: [PATCH 05/14] test Updating test to unsafely read a string under the same condition. --- .../Serialization/FastBufferReaderTests.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs index ff53c76acf..f87a8226b7 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs @@ -933,7 +933,7 @@ public void GivenFastBufferWriterContainingValue_WhenReadingString_ValueMatchesW /// into restricted memory and causes the editor to crash. /// [Test] - public void ReadingStringAfterStringLengthHasAlreadyBeenRead() + public void ReadingStringAfterStringLengthHasAlreadyBeenRead([Values] bool isSafeRead) { // This was an issue uncovered in UUM-145752 that resulted // in the below text to result in a length that when using @@ -954,9 +954,19 @@ public void ReadingStringAfterStringLengthHasAlreadyBeenRead() // the string reader reads the some of the bytes for the actual text as the length. reader.ReadByteSafe(out byte count); Assert.True(count == valueToTest.Length, $"Count ({count}) is not the expected size of {valueToTest.Length}!"); + if (isSafeRead) + { + // This should throw an overflow exception but should not crash the editor. + Assert.Throws(() => reader.ReadValueSafe(out string valueRead)); + } + else + { + // Assume user does a pre-calculation of the size to be read: + Assert.IsTrue(reader.TryBeginRead(count), "Reader denied read permission"); - // This should throw an overflow exception but should not crash the editor. - Assert.Throws(() => reader.ReadValueSafe(out string valueRead)); + // This should throw an overflow exception but should not crash the editor. + Assert.Throws(() => reader.ReadValue(out string valueRead)); + } } [TestCase(1, 0)] From b5e946462cd88824467f3a6e9367861a3235c112 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 10:52:34 -0500 Subject: [PATCH 06/14] fix Fixing an issue where the unsafe string read needs to create an empty string based on the character count and not the byte count. --- .../Runtime/Serialization/FastBufferReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index 48ad2fa2a0..83be4f7790 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -577,7 +577,7 @@ public unsafe void ReadValue(out string s, bool oneByteChars = false) { throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from reading the same serialized value more than once causing the position to be improperly offset."); } - s = "".PadRight(readSize); + s = "".PadRight(length); int target = s.Length; fixed (char* native = s) { From b719aacf896e2dc50aadb10296b246085022c7ed Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 11:04:39 -0500 Subject: [PATCH 07/14] refactor Based on Paolo's suggestion on combining the string size, in bytes, validation script to a single in-lined method shared between the safe and unsafe string read methods. Also combined the actual reading of the string data into a single in-lined method. --- .../Runtime/Serialization/FastBufferReader.cs | 65 ++++++++++--------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index 83be4f7790..63b3c5d9b8 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -3,6 +3,7 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; +using UnityEngine.UIElements; namespace Unity.Netcode { @@ -563,20 +564,20 @@ public void ReadNetworkSerializableInPlace(ref T value) where T : INetworkSer value.NetworkSerialize(bufferSerializer); } - /// - /// Reads a string - /// NOTE: ALLOCATES - /// - /// Stores the read string - /// Whether or not to use one byte per character. This will only allow ASCII - public unsafe void ReadValue(out string s, bool oneByteChars = false) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int CheckIfValidStringLength(int length, bool oneByteChars) { - ReadLength(out int length); var readSize = oneByteChars ? length : length * sizeof(char); if (int.MaxValue < (uint)readSize) { throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from reading the same serialized value more than once causing the position to be improperly offset."); } + return readSize; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe void ReadString(out string s, int length, bool oneByteChars) + { s = "".PadRight(length); int target = s.Length; fixed (char* native = s) @@ -596,6 +597,23 @@ public unsafe void ReadValue(out string s, bool oneByteChars = false) } } + /// + /// Reads a string + /// NOTE: ALLOCATES + /// + /// Stores the read string + /// Whether or not to use one byte per character. This will only allow ASCII + public unsafe void ReadValue(out string s, bool oneByteChars = false) + { + ReadLength(out int length); + + // Validate the string length + CheckIfValidStringLength(length, oneByteChars); + + // Read the string + ReadString(out s, length, oneByteChars); + } + /// /// Reads a string. /// NOTE: ALLOCATES @@ -620,35 +638,18 @@ public unsafe void ReadValueSafe(out string s, bool oneByteChars = false) throw new OverflowException("Reading past the end of the buffer"); } - ReadLength(out int length); - var readSize = oneByteChars ? length : length * sizeof(char); - if (int.MaxValue < (uint)readSize) - { - throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from reading the same serialized value more than once causing the position to be improperly offset."); - } + ReadLength(out int length); - if (!TryBeginReadInternal(readSize)) + // Validate string length and if it is valid begin reading based on the returned + // byte count + if (!TryBeginReadInternal(CheckIfValidStringLength(length, oneByteChars))) { throw new OverflowException("Reading past the end of the buffer"); } - s = "".PadRight(length); - int target = s.Length; - fixed (char* native = s) - { - if (oneByteChars) - { - for (int i = 0; i < target; ++i) - { - ReadByte(out byte b); - native[i] = (char)b; - } - } - else - { - ReadBytes((byte*)native, target * sizeof(char)); - } - } + + // Read the string + ReadString(out s, length, oneByteChars); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 38a0f43d4fc48c83de54a216af6c692bcc527023 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 11:07:13 -0500 Subject: [PATCH 08/14] style Removing the auto-added (and not used) UnityEngine.UIElements using directive. --- .../Runtime/Serialization/FastBufferReader.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index 63b3c5d9b8..0d16492035 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -3,7 +3,6 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; -using UnityEngine.UIElements; namespace Unity.Netcode { From 944d8127a1c0ea587696ad3d35eecf6d8c152ba3 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 11:25:28 -0500 Subject: [PATCH 09/14] style updated comments and renamed CheckIfValidStringLength to ValidateStringByteCount. --- .../Runtime/Serialization/FastBufferReader.cs | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index 0d16492035..c95c5fd6e8 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -563,8 +563,19 @@ public void ReadNetworkSerializableInPlace(ref T value) where T : INetworkSer value.NetworkSerialize(bufferSerializer); } + /// + /// Validates the string's total byte count based on whether we are + /// using one or two byte characters. + /// + /// + /// Will throw an overflow exception if the size is greater than . + /// + /// Character count + /// If false(default) 2 byte characters and if true 1 byte characters + /// total size in bytes to read + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int CheckIfValidStringLength(int length, bool oneByteChars) + private int ValidateStringByteCount(int length, bool oneByteChars) { var readSize = oneByteChars ? length : length * sizeof(char); if (int.MaxValue < (uint)readSize) @@ -574,6 +585,12 @@ private int CheckIfValidStringLength(int length, bool oneByteChars) return readSize; } + /// + /// Commonly shared string read method between . + /// + /// The output of the string read. + /// The number of characters in the string. + /// If false(default) 2 byte characters and if true 1 byte characters. [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe void ReadString(out string s, int length, bool oneByteChars) { @@ -597,31 +614,36 @@ private unsafe void ReadString(out string s, int length, bool oneByteChars) } /// - /// Reads a string - /// NOTE: ALLOCATES + /// Reads a string without bounds checking. + /// NOTE: This mehtod ALLOCATES memory. /// + /// + /// This is the un-safe string read which requires invoking prior to invoking.
+ /// Using one byte characters only allows ASCII characters. + ///
/// Stores the read string - /// Whether or not to use one byte per character. This will only allow ASCII + /// If false(default) 2 byte characters and if true 1 byte characters. public unsafe void ReadValue(out string s, bool oneByteChars = false) { ReadLength(out int length); - // Validate the string length - CheckIfValidStringLength(length, oneByteChars); + // Validate the string's byte count based on the character count. + ValidateStringByteCount(length, oneByteChars); // Read the string ReadString(out s, length, oneByteChars); } /// - /// Reads a string. - /// NOTE: ALLOCATES - /// - /// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking - /// for multiple reads at once by calling TryBeginRead. + /// Reads a string after it performs bounds checking automatically. + /// NOTE: This mehtod ALLOCATES memory. /// - /// Stores the read string - /// Whether or not to use one byte per character. This will only allow ASCII + /// + /// This is the safe string read which invokes prior to invoking.
+ /// Using one byte characters only allows ASCII characters. + ///
+ /// The string re the read string + /// If false(default) 2 byte characters and if true 1 byte characters. public unsafe void ReadValueSafe(out string s, bool oneByteChars = false) { #if DEBUG @@ -640,9 +662,9 @@ public unsafe void ReadValueSafe(out string s, bool oneByteChars = false) ReadLength(out int length); - // Validate string length and if it is valid begin reading based on the returned - // byte count - if (!TryBeginReadInternal(CheckIfValidStringLength(length, oneByteChars))) + // Validate the string's byte count based on the character count and if it is valid begin reading based on the returned + // byte count. + if (!TryBeginReadInternal(ValidateStringByteCount(length, oneByteChars))) { throw new OverflowException("Reading past the end of the buffer"); } From f2463a92a87739f32f0a8629d64ad727e0e53bcc Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 11:29:52 -0500 Subject: [PATCH 10/14] test Removing the added 3 bytes used for earlier debugging purposes. --- .../Tests/Editor/Serialization/FastBufferReaderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs index f87a8226b7..d38c10e0a7 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs @@ -944,7 +944,7 @@ public void ReadingStringAfterStringLengthHasAlreadyBeenRead([Values] bool isSaf var serializedValueSize = FastBufferWriter.GetWriteSize(valueToTest); - using var writer = new FastBufferWriter(serializedValueSize + 3, Allocator.Temp); + using var writer = new FastBufferWriter(serializedValueSize, Allocator.Temp); writer.WriteValueSafe(valueToTest); using var reader = new FastBufferReader(writer, Allocator.Temp); From b645ff3c4451542e6ce0a3f0675aae433da84dcc Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 12:44:22 -0500 Subject: [PATCH 11/14] style spelling/typo fix. whitespace after sentence in comment fix. --- .../Runtime/Serialization/FastBufferReader.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index c95c5fd6e8..98d0ec3cb9 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -615,10 +615,10 @@ private unsafe void ReadString(out string s, int length, bool oneByteChars) /// /// Reads a string without bounds checking. - /// NOTE: This mehtod ALLOCATES memory. + /// NOTE: This method ALLOCATES memory. /// /// - /// This is the un-safe string read which requires invoking prior to invoking.
+ /// This is the un-safe string read which requires invoking prior to invoking this method.
/// Using one byte characters only allows ASCII characters. ///
/// Stores the read string @@ -636,10 +636,10 @@ public unsafe void ReadValue(out string s, bool oneByteChars = false) /// /// Reads a string after it performs bounds checking automatically. - /// NOTE: This mehtod ALLOCATES memory. + /// NOTE: This method ALLOCATES memory. /// /// - /// This is the safe string read which invokes prior to invoking.
+ /// This is the safe string read which invokes prior to reading the string.
/// Using one byte characters only allows ASCII characters. ///
/// The string re the read string From 0db2eb6ebf50d4ac60f6f2eec720d23df10d4cec Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 13:53:19 -0500 Subject: [PATCH 12/14] refactor Based on Emma's suggestion, removing the `SizeOfLengthField` method and `TryBeginReadInternal` check within the ReadValueSafe (string) method and replacing that with `ReadLengthSafe`. --- .../Runtime/Serialization/FastBufferReader.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index 98d0ec3cb9..0ca9dae551 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -654,13 +654,7 @@ public unsafe void ReadValueSafe(out string s, bool oneByteChars = false) } #endif - if (!TryBeginReadInternal(SizeOfLengthField())) - { - throw new OverflowException("Reading past the end of the buffer"); - } - - - ReadLength(out int length); + ReadLengthSafe(out int length); // Validate the string's byte count based on the character count and if it is valid begin reading based on the returned // byte count. @@ -673,9 +667,6 @@ public unsafe void ReadValueSafe(out string s, bool oneByteChars = false) ReadString(out s, length, oneByteChars); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int SizeOfLengthField() => sizeof(uint); - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ReadLengthSafe(out uint length) => ReadUnmanagedSafe(out length); From 68ca288ad9719254865f5fc9563ea289330867b7 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 13:56:41 -0500 Subject: [PATCH 13/14] Update com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs Co-authored-by: Emma --- .../Runtime/Serialization/FastBufferReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index 0ca9dae551..484bc3f446 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -580,7 +580,7 @@ private int ValidateStringByteCount(int length, bool oneByteChars) var readSize = oneByteChars ? length : length * sizeof(char); if (int.MaxValue < (uint)readSize) { - throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from reading the same serialized value more than once causing the position to be improperly offset."); + throw new OverflowException($"Invalid reader position detected when trying to read a string of size {(uint)readSize}! This can result from an error in the serialization. Ensure deserialization exactly matches what was serialized!"); } return readSize; } From 2c49f46de9b3e46eba59df097eb057a1f55b4fd5 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 30 Jun 2026 17:35:49 -0500 Subject: [PATCH 14/14] update Based on suggestion from Emma, removing InBitwiseContext check since this is done in both ReadLengthSafe and TryBeginReadInternal. --- .../Runtime/Serialization/FastBufferReader.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs index 0ca9dae551..e787d3816f 100644 --- a/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs +++ b/com.unity.netcode.gameobjects/Runtime/Serialization/FastBufferReader.cs @@ -646,14 +646,6 @@ public unsafe void ReadValue(out string s, bool oneByteChars = false) /// If false(default) 2 byte characters and if true 1 byte characters. public unsafe void ReadValueSafe(out string s, bool oneByteChars = false) { -#if DEBUG - if (Handle->InBitwiseContext) - { - throw new InvalidOperationException( - "Cannot use BufferReader in bytewise mode while in a bitwise context."); - } -#endif - ReadLengthSafe(out int length); // Validate the string's byte count based on the character count and if it is valid begin reading based on the returned