Untrusted data can lead to DoS attack in MessagePack for C# and Unity
Description
Untrusted MessagePack data can cause denial of service via hash collisions or stack overflow in MessagePack-CSharp before 1.9.11 and 2.1.90.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Untrusted MessagePack data can cause denial of service via hash collisions or stack overflow in MessagePack-CSharp before 1.9.11 and 2.1.90.
CVE-2020-5234 is a denial of service vulnerability in MessagePack-CSharp, a fast MessagePack serializer for .NET, .NET Core, Unity, and Xamarin [1]. The flaw arises when untrusted MessagePack data is deserialized by vulnerable versions prior to 1.9.11 and 2.1.90, allowing an attacker to trigger either excessive CPU consumption through hash collisions or a process crash via stack overflow [3].
Attackers can exploit this remotely without authentication by sending specially crafted requests to an application that deserializes MessagePack data [2]. For example, ASP.NET Core applications using SignalR with the MessagePack Hub Protocol are affected, as the MessagePack package is used as a dependency [2]. No special privileges or network position are required beyond the ability to send malicious payloads to the deserializer.
Successful exploitation results in denial of service, rendering the application unresponsive or crashing it [2]. The impact is limited to availability; no data integrity or confidentiality is compromised.
To mitigate, users must upgrade to MessagePack 1.9.11 or 2.1.90 and enable the defensive UntrustedData mode via the MessagePackSecurity class [3]. Custom IMessagePackFormatter implementations and AOT-generated formatters must also be updated to include hash collision resistance. Microsoft advises updating to secure versions as detailed in their security advisory [2].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
MessagePackNuGet | < 1.9.11 | 1.9.11 |
MessagePackNuGet | >= 2.0.0, < 2.1.90 | 2.1.90 |
MessagePack.ImmutableCollectionNuGet | < 1.9.11 | 1.9.11 |
MessagePack.ImmutableCollectionNuGet | >= 2.0.0, < 2.1.90 | 2.1.90 |
MessagePack.ReactivePropertyNuGet | < 1.9.11 | 1.9.11 |
MessagePack.ReactivePropertyNuGet | >= 2.0.0, < 2.1.90 | 2.1.90 |
MessagePack.UnityShimsNuGet | < 1.9.11 | 1.9.11 |
MessagePack.UnityShimsNuGet | >= 2.0.0, < 2.1.90 | 2.1.90 |
MessagePack.UnityNuGet | < 1.9.11 | 1.9.11 |
MessagePack.UnityNuGet | >= 2.0.0, < 2.1.90 | 2.1.90 |
Affected products
6- ghsa-coords5 versionspkg:nuget/messagepackpkg:nuget/messagepack.immutablecollectionpkg:nuget/messagepack.reactivepropertypkg:nuget/messagepack.unitypkg:nuget/messagepack.unityshims
< 1.9.11+ 4 more
- (no CPE)range: < 1.9.11
- (no CPE)range: < 1.9.11
- (no CPE)range: < 1.9.11
- (no CPE)range: < 1.9.11
- (no CPE)range: < 1.9.11
- Range: < 1.9.11
Patches
2f88684078698Merge pull request #811 from AArnott/fixNullHasher
2 files changed · +8 −0
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSecurity.cs+1 −0 modified@@ -44,6 +44,7 @@ private MessagePackSecurity() /// </summary> /// <param name="copyFrom">The template to copy from.</param> protected MessagePackSecurity(MessagePackSecurity copyFrom) + : this() { if (copyFrom is null) {
src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs+7 −0 modified@@ -125,6 +125,13 @@ public void EqualityComparer_ObjectFallback() Assert.NotEqual(eq.GetHashCode(o), eq.GetHashCode(new object())); } + [Fact] + public void EqualityComparer_ObjectFallback_AfterCopyCtor() + { + var security = MessagePackSecurity.UntrustedData.WithMaximumObjectGraphDepth(15); + Assert.NotNull(security.GetEqualityComparer<object>()); + } + /// <summary> /// Verifies that arbitrary other types not known to be hash safe will be rejected. /// </summary>
56fa86219d01Merge security fixes in for v2.1
38 files changed · +2605 −438
README.md+32 −2 modified@@ -527,6 +527,27 @@ MessagePack.Formatters.TypelessFormatter.BindToType = typeName => }; ``` +## <a name="security"></a>Security + +Deserializing data from an untrusted source can introduce security vulnerabilities to your application. +Depending on the settings used during deserialization, untrusted data may be able to execute arbitrary code or a denial of service attack. +Untrusted data might come from over the Internet over an unauthenticated connection, from the local disk if it may have been tampered with, or many other sources. + +When deserializing untrusted data, put MessagePack into a more secure mode by configuring your `MessagePackSerializerOptions.Security` property: + +```cs +var options = MessagePackSerializerOptions.Standard + .WithSecurity(MessagePackSecurity.UntrustedData); + +// Pass the options explicitly for the greatest control. +T object = MessagePackSerializer.Deserialize<T>(data, options); + +// Or set the security level as the default. +MessagePackSerializer.DefaultOptions = options; +``` + +You should also avoid the Typeless serializer/formatters/resolvers for untrusted data as that opens the door for the untrusted data to potentially deserialize unanticipated types that can compromise security. + ## Performance Benchmarks comparing to other serializers run on `Windows 10 Pro x64 Intel Core i7-6700K 4.00GHz, 32GB RAM`. Benchmark code is [here](https://github.com/neuecc/ZeroFormatter/tree/master/sandbox/PerformanceComparison) - and there [version info](https://github.com/neuecc/ZeroFormatter/blob/bc63cb925d/sandbox/PerformanceComparison/packages.config), ZeroFormatter and [FlatBuffers](https://google.github.io/flatbuffers/) has infinitely fast deserializer so ignore deserialize performance. @@ -950,13 +971,22 @@ public class FileInfoFormatter<T> : IMessagePackFormatter<FileInfo> return null; } + options.Security.DepthStep(ref reader); + var path = reader.ReadString(); + + reader.Depth--; return new FileInfo(path); } } ``` -Your custom formatters must be discoverable via some `IFormatterResolver`. Learn more in our [resolvers](#resolvers). +The `DepthStep` and `Depth--` statements provide a level of security while deserializing untrusted data +that might otherwise be able to execute a denial of service attack by sending messagepack data that would +deserialize into a very deep object graph leading to a `StackOverflowException` that would crash the process. +This pair of statements should surround the bulk of any `IMessagePackFormatter<T>.Deserialize` method. + +Your custom formatters must be discoverable via some `IFormatterResolver`. Learn more in our [resolvers](#resolvers) section. You can see many other samples from [builtin formatters](https://github.com/neuecc/MessagePack-CSharp/tree/master/src/MessagePack/Formatters). @@ -1300,7 +1330,7 @@ Because strict-AOT environments such as Xamarin and Unity IL2CPP forbid runtime If you want to avoid the upfront dynamic generation cost or you need to run on Xamarin or Unity, you need AOT code generation. `mpc` (MessagePackCompiler) is the code generator of MessagePack for C#. mpc uses [Roslyn](https://github.com/dotnet/roslyn) to analyze source code. -In the first, mpc requires [.NET Core 3 Runtime](https://dotnet.microsoft.com/download), the easiest way to acquire and run mpc is as a dotnet tool. +In the first, mpc requires [.NET Core 3 Runtime](https://dotnet.microsoft.com/download), the easiest way to acquire and run mpc is as a dotnet tool. ``` dotnet tool install --global MessagePack.Generator
sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj+12 −0 modified@@ -30,6 +30,9 @@ <Compile Include="..\..\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\Internal\AutomataDictionary.cs"> <Link>Code\AutomataDictionary.cs</Link> </Compile> + <Compile Include="..\..\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\Internal\ThreadsafeTypeKeyHashTable.cs"> + <Link>Code\ThreadsafeTypeKeyHashTable.cs</Link> + </Compile> <Compile Include="..\..\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\Internal\ByteArrayStringHashTable.cs"> <Link>Code\ByteArrayStringHashTable.cs</Link> </Compile> @@ -66,6 +69,15 @@ <Compile Include="..\..\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\MessagePackSerializerOptions.cs"> <Link>Code\MessagePackSerializerOptions.cs</Link> </Compile> + <Compile Include="..\..\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\MessagePackSecurity.cs"> + <Link>Code\MessagePackSecurity.cs</Link> + </Compile> + <Compile Include="..\..\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\HashCode.cs"> + <Link>Code\HashCode.cs</Link> + </Compile> + <Compile Include="..\..\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\BitOperations.cs"> + <Link>Code\BitOperations.cs</Link> + </Compile> <Compile Include="..\..\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\MessagePackCompression.cs"> <Link>Code\MessagePackCompression.cs</Link> </Compile>
sandbox/Sandbox/Generated.cs+110 −0 modified@@ -378,6 +378,7 @@ public void Serialize(ref MessagePackWriter writer, global::IMessageBody value, throw new InvalidOperationException("Invalid Union data was detected. Type:global::IMessageBody"); } + options.Security.DepthStep(ref reader); var key = reader.ReadInt32(); if (!this.keyToJumpMap.TryGetValue(key, out key)) @@ -402,6 +403,7 @@ public void Serialize(ref MessagePackWriter writer, global::IMessageBody value, break; } + reader.Depth--; return result; } } @@ -489,6 +491,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.IIVersion throw new InvalidOperationException("Invalid Union data was detected. Type:global::SharedData.IIVersioningUnion"); } + options.Security.DepthStep(ref reader); var key = reader.ReadInt32(); if (!this.keyToJumpMap.TryGetValue(key, out key)) @@ -507,6 +510,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.IIVersion break; } + reader.Depth--; return result; } } @@ -577,6 +581,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.IUnionChe throw new InvalidOperationException("Invalid Union data was detected. Type:global::SharedData.IUnionChecker"); } + options.Security.DepthStep(ref reader); var key = reader.ReadInt32(); if (!this.keyToJumpMap.TryGetValue(key, out key)) @@ -604,6 +609,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.IUnionChe break; } + reader.Depth--; return result; } } @@ -674,6 +680,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.IUnionChe throw new InvalidOperationException("Invalid Union data was detected. Type:global::SharedData.IUnionChecker2"); } + options.Security.DepthStep(ref reader); var key = reader.ReadInt32(); if (!this.keyToJumpMap.TryGetValue(key, out key)) @@ -701,6 +708,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.IUnionChe break; } + reader.Depth--; return result; } } @@ -761,6 +769,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.IUnionSam throw new InvalidOperationException("Invalid Union data was detected. Type:global::SharedData.IUnionSample"); } + options.Security.DepthStep(ref reader); var key = reader.ReadInt32(); if (!this.keyToJumpMap.TryGetValue(key, out key)) @@ -782,6 +791,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.IUnionSam break; } + reader.Depth--; return result; } } @@ -842,6 +852,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.RootUnion throw new InvalidOperationException("Invalid Union data was detected. Type:global::SharedData.RootUnionType"); } + options.Security.DepthStep(ref reader); var key = reader.ReadInt32(); if (!this.keyToJumpMap.TryGetValue(key, out key)) @@ -863,6 +874,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.RootUnion break; } + reader.Depth--; return result; } } @@ -926,6 +938,7 @@ public void Serialize(ref MessagePackWriter writer, global::Abcdefg.Efcdigjl.Ate return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty__ = default(int); @@ -947,6 +960,7 @@ public void Serialize(ref MessagePackWriter writer, global::Abcdefg.Efcdigjl.Ate var ____result = new global::Abcdefg.Efcdigjl.Ateatatea.Hgfagfafgad.TnonodsfarnoiuAtatqaga(); ____result.MyProperty = __MyProperty__; + reader.Depth--; return ____result; } } @@ -1016,6 +1030,7 @@ public void Serialize(ref MessagePackWriter writer, global::ArrayTestTest value, return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty0__ = default(int[]); @@ -1067,6 +1082,7 @@ public void Serialize(ref MessagePackWriter writer, global::ArrayTestTest value, ____result.MyProperty4 = __MyProperty4__; ____result.MyProperty5 = __MyProperty5__; ____result.MyProperty6 = __MyProperty6__; + reader.Depth--; return ____result; } } @@ -1132,6 +1148,7 @@ public void Serialize(ref MessagePackWriter writer, global::ComplexModel value, return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); var __AdditionalProperty__ = default(global::System.Collections.Generic.IDictionary<string, string>); @@ -1182,6 +1199,7 @@ public void Serialize(ref MessagePackWriter writer, global::ComplexModel value, ____result.Id = __Id__; ____result.Name = __Name__; ____result.UpdatedOn = __UpdatedOn__; + reader.Depth--; return ____result; } } @@ -1210,6 +1228,7 @@ public void Serialize(ref MessagePackWriter writer, global::GlobalMan value, glo return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty__ = default(int); @@ -1231,6 +1250,7 @@ public void Serialize(ref MessagePackWriter writer, global::GlobalMan value, glo var ____result = new global::GlobalMan(); ____result.MyProperty = __MyProperty__; + reader.Depth--; return ____result; } } @@ -1262,6 +1282,7 @@ public void Serialize(ref MessagePackWriter writer, global::Message value, globa return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __UserId__ = default(int); @@ -1298,6 +1319,7 @@ public void Serialize(ref MessagePackWriter writer, global::Message value, globa ____result.RoomId = __RoomId__; ____result.PostTime = __PostTime__; ____result.Body = __Body__; + reader.Depth--; return ____result; } } @@ -1327,6 +1349,7 @@ public void Serialize(ref MessagePackWriter writer, global::QuestMessageBody val return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __QuestId__ = default(int); @@ -1353,6 +1376,7 @@ public void Serialize(ref MessagePackWriter writer, global::QuestMessageBody val var ____result = new global::QuestMessageBody(); ____result.QuestId = __QuestId__; ____result.Text = __Text__; + reader.Depth--; return ____result; } } @@ -1418,6 +1442,7 @@ public void Serialize(ref MessagePackWriter writer, global::SimpleModel value, g return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); var __Id__ = default(int); @@ -1469,6 +1494,7 @@ public void Serialize(ref MessagePackWriter writer, global::SimpleModel value, g ____result.CreatedOn = __CreatedOn__; ____result.Precision = __Precision__; ____result.Money = __Money__; + reader.Depth--; return ____result; } } @@ -1497,6 +1523,7 @@ public void Serialize(ref MessagePackWriter writer, global::StampMessageBody val return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __StampId__ = default(int); @@ -1518,6 +1545,7 @@ public void Serialize(ref MessagePackWriter writer, global::StampMessageBody val var ____result = new global::StampMessageBody(); ____result.StampId = __StampId__; + reader.Depth--; return ____result; } } @@ -1546,6 +1574,7 @@ public void Serialize(ref MessagePackWriter writer, global::TextMessageBody valu return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __Text__ = default(string); @@ -1567,6 +1596,7 @@ public void Serialize(ref MessagePackWriter writer, global::TextMessageBody valu var ____result = new global::TextMessageBody(); ____result.Text = __Text__; + reader.Depth--; return ____result; } } @@ -1679,6 +1709,7 @@ public void Serialize(ref MessagePackWriter writer, global::PerfBenchmarkDotNet. return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); var __MyProperty1__ = default(int); @@ -1746,6 +1777,7 @@ public void Serialize(ref MessagePackWriter writer, global::PerfBenchmarkDotNet. ____result.MyProperty7 = __MyProperty7__; ____result.MyProperty8 = __MyProperty8__; ____result.MyProperty9 = __MyProperty9__; + reader.Depth--; return ____result; } } @@ -1824,6 +1856,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.ArrayOpti return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty0__ = default(int); @@ -1920,6 +1953,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.ArrayOpti ____result.MyPropevrty13 = __MyPropevrty13__; ____result.MyProperty14 = __MyProperty14__; ____result.MyProperty15 = __MyProperty15__; + reader.Depth--; return ____result; } } @@ -1948,6 +1982,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.BarClass return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __OPQ__ = default(string); @@ -1969,6 +2004,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.BarClass var ____result = new global::SharedData.BarClass(); ____result.OPQ = __OPQ__; + reader.Depth--; return ____result; } } @@ -1998,6 +2034,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Callback1 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __X__ = default(int); @@ -2020,6 +2057,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Callback1 var ____result = new global::SharedData.Callback1(__X__); ____result.X = __X__; ____result.OnAfterDeserialize(); + reader.Depth--; return ____result; } } @@ -2049,6 +2087,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Callback1 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __X__ = default(int); @@ -2071,6 +2110,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Callback1 var ____result = new global::SharedData.Callback1_2(__X__); ____result.X = __X__; ((IMessagePackSerializationCallbackReceiver)____result).OnAfterDeserialize(); + reader.Depth--; return ____result; } } @@ -2111,6 +2151,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Callback2 throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); var __X__ = default(int); @@ -2139,6 +2180,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Callback2 var ____result = new global::SharedData.Callback2(__X__); ____result.X = __X__; ____result.OnAfterDeserialize(); + reader.Depth--; return ____result; } } @@ -2179,6 +2221,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Callback2 throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); var __X__ = default(int); @@ -2207,6 +2250,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Callback2 var ____result = new global::SharedData.Callback2_2(__X__); ____result.X = __X__; ((IMessagePackSerializationCallbackReceiver)____result).OnAfterDeserialize(); + reader.Depth--; return ____result; } } @@ -2234,6 +2278,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Empty1 va return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); @@ -2250,6 +2295,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Empty1 va } var ____result = new global::SharedData.Empty1(); + reader.Depth--; return ____result; } } @@ -2291,6 +2337,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Empty2 va return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); @@ -2313,6 +2360,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Empty2 va } var ____result = new global::SharedData.Empty2(); + reader.Depth--; return ____result; } } @@ -2340,6 +2388,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.EmptyClas return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); @@ -2356,6 +2405,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.EmptyClas } var ____result = new global::SharedData.EmptyClass(); + reader.Depth--; return ____result; } } @@ -2377,6 +2427,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.EmptyStru throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); @@ -2393,6 +2444,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.EmptyStru } var ____result = new global::SharedData.EmptyStruct(); + reader.Depth--; return ____result; } } @@ -2423,6 +2475,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.FirstSimp return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __Prop1__ = default(int); @@ -2454,6 +2507,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.FirstSimp ____result.Prop1 = __Prop1__; ____result.Prop2 = __Prop2__; ____result.Prop3 = __Prop3__; + reader.Depth--; return ____result; } } @@ -2482,6 +2536,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.FooClass return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __XYZ__ = default(int); @@ -2503,6 +2558,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.FooClass var ____result = new global::SharedData.FooClass(); ____result.XYZ = __XYZ__; + reader.Depth--; return ____result; } } @@ -2532,6 +2588,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.HolderV0 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty1__ = default(global::SharedData.Version0); @@ -2558,6 +2615,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.HolderV0 var ____result = new global::SharedData.HolderV0(); ____result.MyProperty1 = __MyProperty1__; ____result.After = __After__; + reader.Depth--; return ____result; } } @@ -2587,6 +2645,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.HolderV1 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty1__ = default(global::SharedData.Version1); @@ -2613,6 +2672,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.HolderV1 var ____result = new global::SharedData.HolderV1(); ____result.MyProperty1 = __MyProperty1__; ____result.After = __After__; + reader.Depth--; return ____result; } } @@ -2642,6 +2702,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.HolderV2 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty1__ = default(global::SharedData.Version2); @@ -2668,6 +2729,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.HolderV2 var ____result = new global::SharedData.HolderV2(); ____result.MyProperty1 = __MyProperty1__; ____result.After = __After__; + reader.Depth--; return ____result; } } @@ -2698,6 +2760,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MyClass v return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty1__ = default(int); @@ -2729,6 +2792,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MyClass v ____result.MyProperty1 = __MyProperty1__; ____result.MyProperty2 = __MyProperty2__; ____result.MyProperty3 = __MyProperty3__; + reader.Depth--; return ____result; } } @@ -2760,6 +2824,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MySubUnio return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __One__ = default(int); @@ -2781,6 +2846,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MySubUnio var ____result = new global::SharedData.MySubUnion1(); ____result.One = __One__; + reader.Depth--; return ____result; } } @@ -2808,6 +2874,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MySubUnio throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __Two__ = default(int); @@ -2829,6 +2896,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MySubUnio var ____result = new global::SharedData.MySubUnion2(); ____result.Two = __Two__; + reader.Depth--; return ____result; } } @@ -2859,6 +2927,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MySubUnio return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __Three__ = default(int); @@ -2880,6 +2949,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MySubUnio var ____result = new global::SharedData.MySubUnion3(); ____result.Three = __Three__; + reader.Depth--; return ____result; } } @@ -2909,6 +2979,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MySubUnio throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __Four__ = default(int); @@ -2930,6 +3001,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.MySubUnio var ____result = new global::SharedData.MySubUnion4(); ____result.Four = __Four__; + reader.Depth--; return ____result; } } @@ -2958,6 +3030,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.NestParen return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty__ = default(int); @@ -2979,6 +3052,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.NestParen var ____result = new global::SharedData.NestParent.NestContract(); ____result.MyProperty = __MyProperty__; + reader.Depth--; return ____result; } } @@ -3007,6 +3081,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.NonEmpty1 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty__ = default(int); @@ -3028,6 +3103,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.NonEmpty1 var ____result = new global::SharedData.NonEmpty1(); ____result.MyProperty = __MyProperty__; + reader.Depth--; return ____result; } } @@ -3073,6 +3149,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.NonEmpty2 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); var __MyProperty__ = default(int); @@ -3100,6 +3177,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.NonEmpty2 var ____result = new global::SharedData.NonEmpty2(); ____result.MyProperty = __MyProperty__; + reader.Depth--; return ____result; } } @@ -3134,6 +3212,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SimpleInt return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __Prop1__ = default(int); @@ -3185,6 +3264,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SimpleInt ____result.Prop5 = __Prop5__; ____result.Prop6 = __Prop6__; ____result.BytesSpecial = __BytesSpecial__; + reader.Depth--; return ____result; } } @@ -3238,6 +3318,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SimpleStr return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); var __Prop1__ = default(int); @@ -3275,6 +3356,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SimpleStr ____result.Prop1 = __Prop1__; ____result.Prop2 = __Prop2__; ____result.Prop3 = __Prop3__; + reader.Depth--; return ____result; } } @@ -3299,6 +3381,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SimpleStr throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __X__ = default(int); @@ -3330,6 +3413,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SimpleStr ____result.X = __X__; ____result.Y = __Y__; ____result.BytesSpecial = __BytesSpecial__; + reader.Depth--; return ____result; } } @@ -3373,6 +3457,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SimpleStr throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadMapHeader(); var __X__ = default(int); @@ -3405,6 +3490,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SimpleStr var ____result = new global::SharedData.SimpleStructStringKeyData(); ____result.X = __X__; ____result.Y = __Y__; + reader.Depth--; return ____result; } } @@ -3434,6 +3520,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SubUnionT return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty1__ = default(int); @@ -3460,6 +3547,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SubUnionT var ____result = new global::SharedData.SubUnionType1(); ____result.MyProperty1 = __MyProperty1__; ____result.MyProperty = __MyProperty__; + reader.Depth--; return ____result; } } @@ -3489,6 +3577,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SubUnionT return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty2__ = default(int); @@ -3515,6 +3604,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.SubUnionT var ____result = new global::SharedData.SubUnionType2(); ____result.MyProperty2 = __MyProperty2__; ____result.MyProperty = __MyProperty__; + reader.Depth--; return ____result; } } @@ -3545,6 +3635,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.UnVersion return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty__ = default(int); @@ -3571,6 +3662,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.UnVersion var ____result = new global::SharedData.UnVersionBlockTest(); ____result.MyProperty = __MyProperty__; ____result.MyProperty2 = __MyProperty2__; + reader.Depth--; return ____result; } } @@ -3594,6 +3686,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Vector2 v throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __X__ = default(float); @@ -3618,6 +3711,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Vector2 v } var ____result = new global::SharedData.Vector2(__X__, __Y__); + reader.Depth--; return ____result; } } @@ -3642,6 +3736,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Vector3Li throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __x__ = default(float); @@ -3673,6 +3768,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Vector3Li ____result.x = __x__; ____result.y = __y__; ____result.z = __z__; + reader.Depth--; return ____result; } } @@ -3696,6 +3792,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.VectorLik throw new InvalidOperationException("typecode is null, struct not supported"); } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __x__ = default(float); @@ -3722,6 +3819,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.VectorLik var ____result = new global::SharedData.VectorLike2(__x__, __y__); ____result.x = __x__; ____result.y = __y__; + reader.Depth--; return ____result; } } @@ -3753,6 +3851,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Version0 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty1__ = default(int); @@ -3774,6 +3873,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Version0 var ____result = new global::SharedData.Version0(); ____result.MyProperty1 = __MyProperty1__; + reader.Depth--; return ____result; } } @@ -3807,6 +3907,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Version1 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty1__ = default(int); @@ -3838,6 +3939,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Version1 ____result.MyProperty1 = __MyProperty1__; ____result.MyProperty2 = __MyProperty2__; ____result.MyProperty3 = __MyProperty3__; + reader.Depth--; return ____result; } } @@ -3873,6 +3975,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Version2 return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty1__ = default(int); @@ -3909,6 +4012,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Version2 ____result.MyProperty2 = __MyProperty2__; ____result.MyProperty3 = __MyProperty3__; ____result.MyProperty5 = __MyProperty5__; + reader.Depth--; return ____result; } } @@ -3939,6 +4043,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.VersionBl return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __MyProperty__ = default(int); @@ -3970,6 +4075,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.VersionBl ____result.MyProperty = __MyProperty__; ____result.UnknownBlock = __UnknownBlock__; ____result.MyProperty2 = __MyProperty2__; + reader.Depth--; return ____result; } } @@ -4005,6 +4111,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Versionin return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __FV__ = default(int); @@ -4026,6 +4133,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.Versionin var ____result = new global::SharedData.VersioningUnion(); ____result.FV = __FV__; + reader.Depth--; return ____result; } } @@ -4055,6 +4163,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.WithIndex return null; } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; var length = reader.ReadArrayHeader(); var __Data1__ = default(int); @@ -4081,6 +4190,7 @@ public void Serialize(ref MessagePackWriter writer, global::SharedData.WithIndex var ____result = new global::SharedData.WithIndexer(); ____result.Data1 = __Data1__; ____result.Data2 = __Data2__; + reader.Depth--; return ____result; } }
src/MessagePack/Formatters/ForceSizePrimitiveFormatter.cs+70 −14 modified@@ -97,9 +97,17 @@ public Int16[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOp { var len = reader.ReadArrayHeader(); var array = new Int16[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try { - array[i] = reader.ReadInt16(); + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadInt16(); + } + } + finally + { + reader.Depth--; } return array; @@ -193,9 +201,17 @@ public Int32[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOp { var len = reader.ReadArrayHeader(); var array = new Int32[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadInt32(); + } + } + finally { - array[i] = reader.ReadInt32(); + reader.Depth--; } return array; @@ -289,9 +305,17 @@ public Int64[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOp { var len = reader.ReadArrayHeader(); var array = new Int64[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try { - array[i] = reader.ReadInt64(); + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadInt64(); + } + } + finally + { + reader.Depth--; } return array; @@ -385,9 +409,17 @@ public UInt16[] Deserialize(ref MessagePackReader reader, MessagePackSerializerO { var len = reader.ReadArrayHeader(); var array = new UInt16[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadUInt16(); + } + } + finally { - array[i] = reader.ReadUInt16(); + reader.Depth--; } return array; @@ -481,9 +513,17 @@ public UInt32[] Deserialize(ref MessagePackReader reader, MessagePackSerializerO { var len = reader.ReadArrayHeader(); var array = new UInt32[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadUInt32(); + } + } + finally { - array[i] = reader.ReadUInt32(); + reader.Depth--; } return array; @@ -577,9 +617,17 @@ public UInt64[] Deserialize(ref MessagePackReader reader, MessagePackSerializerO { var len = reader.ReadArrayHeader(); var array = new UInt64[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try { - array[i] = reader.ReadUInt64(); + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadUInt64(); + } + } + finally + { + reader.Depth--; } return array; @@ -725,9 +773,17 @@ public SByte[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOp { var len = reader.ReadArrayHeader(); var array = new SByte[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadSByte(); + } + } + finally { - array[i] = reader.ReadSByte(); + reader.Depth--; } return array;
src/MessagePack/Formatters/ForceSizePrimitiveFormatter.tt+10 −2 modified@@ -123,9 +123,17 @@ namespace MessagePack.Formatters { var len = reader.ReadArrayHeader(); var array = new <#= t.Name #>[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try { - array[i] = reader.Read<#= t.Name #>(); + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.Read<#= t.Name #>(); + } + } + finally + { + reader.Depth--; } return array;
src/MessagePack/Formatters/TupleFormatter.cs+111 −47 modified@@ -43,9 +43,17 @@ public Tuple<T1> Deserialize(ref MessagePackReader reader, MessagePackSerializer } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - return new Tuple<T1>(item1); + return new Tuple<T1>(item1); + } + finally + { + reader.Depth--; + } } } } @@ -83,10 +91,18 @@ public Tuple<T1, T2> Deserialize(ref MessagePackReader reader, MessagePackSerial } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - return new Tuple<T1, T2>(item1, item2); + return new Tuple<T1, T2>(item1, item2); + } + finally + { + reader.Depth--; + } } } } @@ -125,11 +141,19 @@ public Tuple<T1, T2, T3> Deserialize(ref MessagePackReader reader, MessagePackSe } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - return new Tuple<T1, T2, T3>(item1, item2, item3); + return new Tuple<T1, T2, T3>(item1, item2, item3); + } + finally + { + reader.Depth--; + } } } } @@ -169,12 +193,20 @@ public Tuple<T1, T2, T3, T4> Deserialize(ref MessagePackReader reader, MessagePa } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4); + return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4); + } + finally + { + reader.Depth--; + } } } } @@ -215,13 +247,21 @@ public Tuple<T1, T2, T3, T4, T5> Deserialize(ref MessagePackReader reader, Messa } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); + return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); + } + finally + { + reader.Depth--; + } } } } @@ -263,14 +303,22 @@ public Tuple<T1, T2, T3, T4, T5, T6> Deserialize(ref MessagePackReader reader, M } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - - return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + + return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); + } + finally + { + reader.Depth--; + } } } } @@ -313,15 +361,23 @@ public Tuple<T1, T2, T3, T4, T5, T6, T7> Deserialize(ref MessagePackReader reade } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); - - return new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); + + return new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); + } + finally + { + reader.Depth--; + } } } } @@ -365,16 +421,24 @@ public Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> Deserialize(ref MessagePackReade } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); - TRest item8 = resolver.GetFormatterWithVerify<TRest>().Deserialize(ref reader, options); - - return new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, item8); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); + TRest item8 = resolver.GetFormatterWithVerify<TRest>().Deserialize(ref reader, options); + + return new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, item8); + } + finally + { + reader.Depth--; + } } } }
src/MessagePack/Formatters/TupleFormatter.tt+10 −2 modified@@ -57,11 +57,19 @@ namespace MessagePack.Formatters } IFormatterResolver resolver = options.Resolver; + options.Security.DepthStep(ref reader); + try + { <# for(var j = 1; j <= i; j++) { #> - <#= toT(j) #> item<#= j #> = resolver.GetFormatterWithVerify<<#= toT(j) #>>().Deserialize(ref reader, options); + <#= toT(j) #> item<#= j #> = resolver.GetFormatterWithVerify<<#= toT(j) #>>().Deserialize(ref reader, options); <# } #> - return new Tuple<<#= ts #>>(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => "item" + x)) #>); + return new Tuple<<#= ts #>>(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => "item" + x)) #>); + } + finally + { + reader.Depth--; + } } } }
src/MessagePack/Formatters/ValueTupleFormatter.cs+111 −47 modified@@ -36,9 +36,17 @@ public ValueTuple<T1> Deserialize(ref MessagePackReader reader, MessagePackSeria } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - return new ValueTuple<T1>(item1); + return new ValueTuple<T1>(item1); + } + finally + { + reader.Depth--; + } } } } @@ -69,10 +77,18 @@ public ValueTuple<T1, T2> Deserialize(ref MessagePackReader reader, MessagePackS } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - return new ValueTuple<T1, T2>(item1, item2); + return new ValueTuple<T1, T2>(item1, item2); + } + finally + { + reader.Depth--; + } } } } @@ -104,11 +120,19 @@ public ValueTuple<T1, T2, T3> Deserialize(ref MessagePackReader reader, MessageP } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - return new ValueTuple<T1, T2, T3>(item1, item2, item3); + return new ValueTuple<T1, T2, T3>(item1, item2, item3); + } + finally + { + reader.Depth--; + } } } } @@ -141,12 +165,20 @@ public ValueTuple<T1, T2, T3, T4> Deserialize(ref MessagePackReader reader, Mess } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - return new ValueTuple<T1, T2, T3, T4>(item1, item2, item3, item4); + return new ValueTuple<T1, T2, T3, T4>(item1, item2, item3, item4); + } + finally + { + reader.Depth--; + } } } } @@ -180,13 +212,21 @@ public ValueTuple<T1, T2, T3, T4, T5> Deserialize(ref MessagePackReader reader, } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - return new ValueTuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); + return new ValueTuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); + } + finally + { + reader.Depth--; + } } } } @@ -221,14 +261,22 @@ public ValueTuple<T1, T2, T3, T4, T5, T6> Deserialize(ref MessagePackReader read } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - - return new ValueTuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + + return new ValueTuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); + } + finally + { + reader.Depth--; + } } } } @@ -264,15 +312,23 @@ public ValueTuple<T1, T2, T3, T4, T5, T6, T7> Deserialize(ref MessagePackReader } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); - - return new ValueTuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); + + return new ValueTuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); + } + finally + { + reader.Depth--; + } } } } @@ -310,16 +366,24 @@ public ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> Deserialize(ref MessagePack } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); - TRest item8 = resolver.GetFormatterWithVerify<TRest>().Deserialize(ref reader, options); - - return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, item8); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); + TRest item8 = resolver.GetFormatterWithVerify<TRest>().Deserialize(ref reader, options); + + return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, item8); + } + finally + { + reader.Depth--; + } } } }
src/MessagePack/Formatters/ValueTupleFormatter.tt+10 −2 modified@@ -51,11 +51,19 @@ namespace MessagePack.Formatters } IFormatterResolver resolver = options.Resolver; + options.Security.DepthStep(ref reader); + try + { <# for(var j = 1; j <= i; j++) { #> - <#= toT(j) #> item<#= j #> = resolver.GetFormatterWithVerify<<#= toT(j) #>>().Deserialize(ref reader, options); + <#= toT(j) #> item<#= j #> = resolver.GetFormatterWithVerify<<#= toT(j) #>>().Deserialize(ref reader, options); <# } #> - return new ValueTuple<<#= ts #>>(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => "item" + x)) #>); + return new ValueTuple<<#= ts #>>(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => "item" + x)) #>); + } + finally + { + reader.Depth--; + } } } }
src/MessagePack.GeneratorCore/Generator/FormatterTemplate.cs+7 −7 modified@@ -1,10 +1,10 @@ // ------------------------------------------------------------------------------ // <auto-generated> -// このコードはツールによって生成されました。 -// ランタイム バージョン: 16.0.0.0 +// This code was generated by a tool. +// Runtime Version: 16.0.0.0 // -// このファイルへの変更は、正しくない動作の原因になる可能性があり、 -// コードが再生成されると失われます。 +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // </auto-generated> // ------------------------------------------------------------------------------ namespace MessagePackCompiler.Generator @@ -136,8 +136,8 @@ namespace "); this.Write(" throw new InvalidOperationException(\"typecode is null, struct not" + " supported\");\r\n"); } - this.Write(" }\r\n\r\n IFormatterResolver formatterResolver = options.Resol" + - "ver;\r\n"); + this.Write(" }\r\n\r\n options.Security.DepthStep(ref reader);\r\n " + + " IFormatterResolver formatterResolver = options.Resolver;\r\n"); if(objInfo.IsStringKey) { this.Write(" var length = reader.ReadMapHeader();\r\n"); } else { @@ -191,7 +191,7 @@ namespace "); } else if(objInfo.HasIMessagePackSerializationCallbackReceiver) { this.Write(" ____result.OnAfterDeserialize();\r\n"); } - this.Write(" return ____result;\r\n }\r\n }\r\n"); + this.Write(" reader.Depth--;\r\n return ____result;\r\n }\r\n }\r\n"); } this.Write(@"}
src/MessagePack.GeneratorCore/Generator/FormatterTemplate.tt+2 −0 modified@@ -102,6 +102,7 @@ namespace <#= Namespace #> <# } #> } + options.Security.DepthStep(ref reader); IFormatterResolver formatterResolver = options.Resolver; <# if(objInfo.IsStringKey) { #> var length = reader.ReadMapHeader(); @@ -148,6 +149,7 @@ namespace <#= Namespace #> <# } else if(objInfo.HasIMessagePackSerializationCallbackReceiver) { #> ____result.OnAfterDeserialize(); <# } #> + reader.Depth--; return ____result; } }
src/MessagePack.GeneratorCore/Generator/UnionTemplate.cs+10 −8 modified@@ -1,10 +1,10 @@ // ------------------------------------------------------------------------------ // <auto-generated> -// このコードはツールによって生成されました。 -// ランタイム バージョン: 16.0.0.0 +// This code was generated by a tool. +// Runtime Version: 16.0.0.0 // -// このファイルへの変更は、正しくない動作の原因になる可能性があり、 -// コードが再生成されると失われます。 +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // </auto-generated> // ------------------------------------------------------------------------------ namespace MessagePackCompiler.Generator @@ -112,9 +112,10 @@ namespace "); { throw new InvalidOperationException(""Invalid Union data was detected. Type:"); this.Write(this.ToStringHelper.ToStringWithCulture(info.FullName)); - this.Write("\");\r\n }\r\n\r\n var key = reader.ReadInt32();\r\n\r\n if" + - " (!this.keyToJumpMap.TryGetValue(key, out key))\r\n {\r\n " + - "key = -1;\r\n }\r\n\r\n "); + this.Write("\");\r\n }\r\n\r\n options.Security.DepthStep(ref reader);\r\n " + + " var key = reader.ReadInt32();\r\n\r\n if (!this.keyToJumpMap.TryGet" + + "Value(key, out key))\r\n {\r\n key = -1;\r\n }\r\n\r" + + "\n "); this.Write(this.ToStringHelper.ToStringWithCulture(info.FullName)); this.Write(" result = null;\r\n switch (key)\r\n {\r\n"); for(var i = 0; i < info.SubTypes.Length; i++) { var item = info.SubTypes[i]; @@ -127,7 +128,8 @@ namespace "); this.Write(">().Deserialize(ref reader, options);\r\n break;\r\n"); } this.Write(" default:\r\n reader.Skip();\r\n " + - " break;\r\n }\r\n\r\n return result;\r\n }\r\n }\r\n\r\n"); + " break;\r\n }\r\n\r\n reader.Depth--;\r\n return result" + + ";\r\n }\r\n }\r\n\r\n"); } this.Write(@" }
src/MessagePack.GeneratorCore/Generator/UnionTemplate.tt+2 −0 modified@@ -81,6 +81,7 @@ namespace <#= Namespace #> throw new InvalidOperationException("Invalid Union data was detected. Type:<#= info.FullName #>"); } + options.Security.DepthStep(ref reader); var key = reader.ReadInt32(); if (!this.keyToJumpMap.TryGetValue(key, out key)) @@ -101,6 +102,7 @@ namespace <#= Namespace #> break; } + reader.Depth--; return result; } }
src/MessagePack.ImmutableCollection/Formatters.cs+14 −6 modified@@ -45,9 +45,17 @@ public ImmutableArray<T> Deserialize(ref MessagePackReader reader, MessagePackSe var len = reader.ReadArrayHeader(); ImmutableArray<T>.Builder builder = ImmutableArray.CreateBuilder<T>(len); - for (int i = 0; i < len; i++) + options.Security.DepthStep(ref reader); + try { - builder.Add(formatter.Deserialize(ref reader, options)); + for (int i = 0; i < len; i++) + { + builder.Add(formatter.Deserialize(ref reader, options)); + } + } + finally + { + reader.Depth--; } return builder.ToImmutable(); @@ -92,7 +100,7 @@ protected override ImmutableDictionary<TKey, TValue> Complete(ImmutableDictionar protected override ImmutableDictionary<TKey, TValue>.Builder Create(int count, MessagePackSerializerOptions options) { - return ImmutableDictionary.CreateBuilder<TKey, TValue>(); + return ImmutableDictionary.CreateBuilder<TKey, TValue>(options.Security.GetEqualityComparer<TKey>()); } protected override ImmutableDictionary<TKey, TValue>.Enumerator GetSourceEnumerator(ImmutableDictionary<TKey, TValue> source) @@ -115,7 +123,7 @@ protected override ImmutableHashSet<T> Complete(ImmutableHashSet<T>.Builder inte protected override ImmutableHashSet<T>.Builder Create(int count, MessagePackSerializerOptions options) { - return ImmutableHashSet.CreateBuilder<T>(); + return ImmutableHashSet.CreateBuilder<T>(options.Security.GetEqualityComparer<T>()); } protected override ImmutableHashSet<T>.Enumerator GetSourceEnumerator(ImmutableHashSet<T> source) @@ -240,7 +248,7 @@ protected override IImmutableDictionary<TKey, TValue> Complete(ImmutableDictiona protected override ImmutableDictionary<TKey, TValue>.Builder Create(int count, MessagePackSerializerOptions options) { - return ImmutableDictionary.CreateBuilder<TKey, TValue>(); + return ImmutableDictionary.CreateBuilder<TKey, TValue>(options.Security.GetEqualityComparer<TKey>()); } } @@ -258,7 +266,7 @@ protected override IImmutableSet<T> Complete(ImmutableHashSet<T>.Builder interme protected override ImmutableHashSet<T>.Builder Create(int count, MessagePackSerializerOptions options) { - return ImmutableHashSet.CreateBuilder<T>(); + return ImmutableHashSet.CreateBuilder<T>(options.Security.GetEqualityComparer<T>()); } }
src/MessagePack/PublicAPI.Unshipped.txt+19 −1 modified@@ -3,12 +3,30 @@ MessagePack.Formatters.InterfaceCollectionFormatter2<T> MessagePack.Formatters.InterfaceCollectionFormatter2<T>.InterfaceCollectionFormatter2() -> void MessagePack.Formatters.InterfaceListFormatter2<T> MessagePack.Formatters.InterfaceListFormatter2<T>.InterfaceListFormatter2() -> void +MessagePack.MessagePackReader.Depth.get -> int +MessagePack.MessagePackReader.Depth.set -> void MessagePack.MessagePackReader.ReadDateTime(MessagePack.ExtensionHeader header) -> System.DateTime MessagePack.MessagePackReader.TryReadArrayHeader(out int count) -> bool MessagePack.MessagePackReader.TryReadExtensionFormatHeader(out MessagePack.ExtensionHeader extensionHeader) -> bool MessagePack.MessagePackReader.TryReadMapHeader(out int count) -> bool +MessagePack.MessagePackSecurity +MessagePack.MessagePackSecurity.DepthStep(ref MessagePack.MessagePackReader reader) -> void +MessagePack.MessagePackSecurity.GetEqualityComparer() -> System.Collections.IEqualityComparer +MessagePack.MessagePackSecurity.GetEqualityComparer<T>() -> System.Collections.Generic.IEqualityComparer<T> +MessagePack.MessagePackSecurity.HashCollisionResistant.get -> bool +MessagePack.MessagePackSecurity.MaximumObjectGraphDepth.get -> int +MessagePack.MessagePackSecurity.MessagePackSecurity(MessagePack.MessagePackSecurity copyFrom) -> void +MessagePack.MessagePackSecurity.WithHashCollisionResistant(bool hashCollisionResistant) -> MessagePack.MessagePackSecurity +MessagePack.MessagePackSecurity.WithMaximumObjectGraphDepth(int maximumObjectGraphDepth) -> MessagePack.MessagePackSecurity +MessagePack.MessagePackSerializerOptions.Security.get -> MessagePack.MessagePackSecurity +MessagePack.MessagePackSerializerOptions.WithSecurity(MessagePack.MessagePackSecurity security) -> MessagePack.MessagePackSerializerOptions MessagePack.MessagePackStreamReader.DiscardBufferedData() -> void MessagePack.MessagePackStreamReader.MessagePackStreamReader(System.IO.Stream stream, bool leaveOpen) -> void MessagePack.MessagePackStreamReader.ReadArrayAsync(System.Threading.CancellationToken cancellationToken) -> System.Collections.Generic.IAsyncEnumerable<System.Buffers.ReadOnlySequence<byte>> MessagePack.MessagePackWriter.WriteBinHeader(int length) -> void -MessagePack.MessagePackWriter.WriteStringHeader(int byteCount) -> void \ No newline at end of file +MessagePack.MessagePackWriter.WriteStringHeader(int byteCount) -> void +static readonly MessagePack.MessagePackSecurity.TrustedData -> MessagePack.MessagePackSecurity +static readonly MessagePack.MessagePackSecurity.UntrustedData -> MessagePack.MessagePackSecurity +virtual MessagePack.MessagePackSecurity.Clone() -> MessagePack.MessagePackSecurity +virtual MessagePack.MessagePackSecurity.GetHashCollisionResistantEqualityComparer() -> System.Collections.IEqualityComparer +virtual MessagePack.MessagePackSecurity.GetHashCollisionResistantEqualityComparer<T>() -> System.Collections.Generic.IEqualityComparer<T>
src/MessagePack.ReactiveProperty/Formatters.cs+51 −19 modified@@ -147,9 +147,17 @@ public ReactiveProperty<T> Deserialize(ref MessagePackReader reader, MessagePack IScheduler scheduler = ReactivePropertySchedulerMapper.GetScheduler(schedulerId); - T v = options.Resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T v = options.Resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options); - return new ReactiveProperty<T>(scheduler, v, mode); + return new ReactiveProperty<T>(scheduler, v, mode); + } + finally + { + reader.Depth--; + } } } } @@ -186,14 +194,22 @@ public IReactiveProperty<T> Deserialize(ref MessagePackReader reader, MessagePac { var length = reader.ReadArrayHeader(); - switch (length) + options.Security.DepthStep(ref reader); + try { - case 2: - return ReactivePropertyResolver.Instance.GetFormatterWithVerify<ReactivePropertySlim<T>>().Deserialize(ref reader, options); - case 3: - return ReactivePropertyResolver.Instance.GetFormatterWithVerify<ReactiveProperty<T>>().Deserialize(ref reader, options); - default: - throw new InvalidOperationException("Invalid ReactiveProperty or ReactivePropertySlim data."); + switch (length) + { + case 2: + return ReactivePropertyResolver.Instance.GetFormatterWithVerify<ReactivePropertySlim<T>>().Deserialize(ref reader, options); + case 3: + return ReactivePropertyResolver.Instance.GetFormatterWithVerify<ReactiveProperty<T>>().Deserialize(ref reader, options); + default: + throw new InvalidOperationException("Invalid ReactiveProperty or ReactivePropertySlim data."); + } + } + finally + { + reader.Depth--; } } } @@ -230,14 +246,22 @@ public IReadOnlyReactiveProperty<T> Deserialize(ref MessagePackReader reader, Me { var length = reader.ReadArrayHeader(); - switch (length) + options.Security.DepthStep(ref reader); + try { - case 2: - return ReactivePropertyResolver.Instance.GetFormatterWithVerify<ReactivePropertySlim<T>>().Deserialize(ref reader, options); - case 3: - return ReactivePropertyResolver.Instance.GetFormatterWithVerify<ReactiveProperty<T>>().Deserialize(ref reader, options); - default: - throw new InvalidOperationException("Invalid ReactiveProperty or ReactivePropertySlim data."); + switch (length) + { + case 2: + return ReactivePropertyResolver.Instance.GetFormatterWithVerify<ReactivePropertySlim<T>>().Deserialize(ref reader, options); + case 3: + return ReactivePropertyResolver.Instance.GetFormatterWithVerify<ReactiveProperty<T>>().Deserialize(ref reader, options); + default: + throw new InvalidOperationException("Invalid ReactiveProperty or ReactivePropertySlim data."); + } + } + finally + { + reader.Depth--; } } } @@ -339,11 +363,19 @@ public ReactivePropertySlim<T> Deserialize(ref MessagePackReader reader, Message throw new InvalidOperationException("Invalid ReactivePropertySlim data."); } - var mode = (ReactivePropertyMode)reader.ReadInt32(); + options.Security.DepthStep(ref reader); + try + { + var mode = (ReactivePropertyMode)reader.ReadInt32(); - T v = options.Resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options); + T v = options.Resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options); - return new ReactivePropertySlim<T>(v, mode); + return new ReactivePropertySlim<T>(v, mode); + } + finally + { + reader.Depth--; + } } } }
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/BitOperations.cs+36 −0 added@@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// <auto-generated /> + +#if !NETCOREAPP + +using System.Runtime.CompilerServices; + +// Some routines inspired by the Stanford Bit Twiddling Hacks by Sean Eron Anderson: +// http://graphics.stanford.edu/~seander/bithacks.html + +namespace System.Numerics +{ + /// <summary> + /// Utility methods for intrinsic bit-twiddling operations. + /// The methods use hardware intrinsics when available on the underlying platform, + /// otherwise they use optimized software fallbacks. + /// </summary> + internal static class BitOperations + { + /// <summary> + /// Rotates the specified value left by the specified number of bits. + /// Similar in behavior to the x86 instruction ROL. + /// </summary> + /// <param name="value">The value to rotate.</param> + /// <param name="offset">The number of bits to rotate by. + /// Any value outside the range [0..31] is treated as congruent mod 32.</param> + /// <returns>The rotated value.</returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) + => (value << offset) | (value >> (32 - offset)); + } +} + +#endif
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/CollectionFormatter.cs+96 −32 modified@@ -49,10 +49,18 @@ public T[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOption var len = reader.ReadArrayHeader(); var array = new T[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - array[i] = formatter.Deserialize(ref reader, options); + for (int i = 0; i < array.Length; i++) + { + reader.CancellationToken.ThrowIfCancellationRequested(); + array[i] = formatter.Deserialize(ref reader, options); + } + } + finally + { + reader.Depth--; } return array; @@ -160,10 +168,18 @@ public List<T> Deserialize(ref MessagePackReader reader, MessagePackSerializerOp var len = reader.ReadArrayHeader(); var list = new List<T>((int)len); - for (int i = 0; i < len; i++) + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - list.Add(formatter.Deserialize(ref reader, options)); + for (int i = 0; i < len; i++) + { + reader.CancellationToken.ThrowIfCancellationRequested(); + list.Add(formatter.Deserialize(ref reader, options)); + } + } + finally + { + reader.Depth--; } return list; @@ -253,10 +269,18 @@ public TCollection Deserialize(ref MessagePackReader reader, MessagePackSerializ var len = reader.ReadArrayHeader(); TIntermediate list = this.Create(len, options); - for (int i = 0; i < len; i++) + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - this.Add(list, i, formatter.Deserialize(ref reader, options), options); + for (int i = 0; i < len; i++) + { + reader.CancellationToken.ThrowIfCancellationRequested(); + this.Add(list, i, formatter.Deserialize(ref reader, options), options); + } + } + finally + { + reader.Depth--; } return this.Complete(list); @@ -426,7 +450,7 @@ protected override HashSet<T> Complete(HashSet<T> intermediateCollection) protected override HashSet<T> Create(int count, MessagePackSerializerOptions options) { - return new HashSet<T>(); + return new HashSet<T>(options.Security.GetEqualityComparer<T>()); } protected override HashSet<T>.Enumerator GetSourceEnumerator(HashSet<T> source) @@ -577,9 +601,17 @@ public IGrouping<TKey, TElement> Deserialize(ref MessagePackReader reader, Messa throw new MessagePackSerializationException("Invalid Grouping format."); } - TKey key = options.Resolver.GetFormatterWithVerify<TKey>().Deserialize(ref reader, options); - IEnumerable<TElement> value = options.Resolver.GetFormatterWithVerify<IEnumerable<TElement>>().Deserialize(ref reader, options); - return new Grouping<TKey, TElement>(key, value); + options.Security.DepthStep(ref reader); + try + { + TKey key = options.Resolver.GetFormatterWithVerify<TKey>().Deserialize(ref reader, options); + IEnumerable<TElement> value = options.Resolver.GetFormatterWithVerify<IEnumerable<TElement>>().Deserialize(ref reader, options); + return new Grouping<TKey, TElement>(key, value); + } + finally + { + reader.Depth--; + } } } } @@ -708,10 +740,18 @@ public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions var count = reader.ReadArrayHeader(); var list = new T(); - for (int i = 0; i < count; i++) + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - list.Add(formatter.Deserialize(ref reader, options)); + for (int i = 0; i < count; i++) + { + reader.CancellationToken.ThrowIfCancellationRequested(); + list.Add(formatter.Deserialize(ref reader, options)); + } + } + finally + { + reader.Depth--; } return list; @@ -756,10 +796,18 @@ public IList Deserialize(ref MessagePackReader reader, MessagePackSerializerOpti var count = reader.ReadArrayHeader(); var list = new object[count]; - for (int i = 0; i < count; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < count; i++) + { + reader.CancellationToken.ThrowIfCancellationRequested(); + list[i] = formatter.Deserialize(ref reader, options); + } + } + finally { - reader.CancellationToken.ThrowIfCancellationRequested(); - list[i] = formatter.Deserialize(ref reader, options); + reader.Depth--; } return list; @@ -799,13 +847,21 @@ public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions var count = reader.ReadMapHeader(); - var dict = new T(); - for (int i = 0; i < count; i++) + var dict = CollectionHelpers<T, IEqualityComparer>.CreateHashCollection(count, options.Security.GetEqualityComparer()); + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - var key = formatter.Deserialize(ref reader, options); - var value = formatter.Deserialize(ref reader, options); - dict.Add(key, value); + for (int i = 0; i < count; i++) + { + reader.CancellationToken.ThrowIfCancellationRequested(); + var key = formatter.Deserialize(ref reader, options); + var value = formatter.Deserialize(ref reader, options); + dict.Add(key, value); + } + } + finally + { + reader.Depth--; } return dict; @@ -850,13 +906,21 @@ public IDictionary Deserialize(ref MessagePackReader reader, MessagePackSerializ var count = reader.ReadMapHeader(); - var dict = new Dictionary<object, object>(count); - for (int i = 0; i < count; i++) + var dict = new Dictionary<object, object>(count, options.Security.GetEqualityComparer<object>()); + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < count; i++) + { + reader.CancellationToken.ThrowIfCancellationRequested(); + var key = formatter.Deserialize(ref reader, options); + var value = formatter.Deserialize(ref reader, options); + dict.Add(key, value); + } + } + finally { - reader.CancellationToken.ThrowIfCancellationRequested(); - var key = formatter.Deserialize(ref reader, options); - var value = formatter.Deserialize(ref reader, options); - dict.Add(key, value); + reader.Depth--; } return dict; @@ -944,7 +1008,7 @@ protected override ISet<T> Complete(HashSet<T> intermediateCollection) protected override HashSet<T> Create(int count, MessagePackSerializerOptions options) { - return new HashSet<T>(); + return new HashSet<T>(options.Security.GetEqualityComparer<T>()); } }
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/CollectionHelpers`2.cs+52 −0 added@@ -0,0 +1,52 @@ +// Copyright (c) All contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Linq.Expressions; + +namespace MessagePack.Formatters +{ + /// <summary> + /// Provides general helpers for creating collections (including dictionaries). + /// </summary> + /// <typeparam name="TCollection">The concrete type of collection to create.</typeparam> + /// <typeparam name="TEqualityComparer">The type of equality comparer that we would hope to pass into the collection's constructor.</typeparam> + internal static class CollectionHelpers<TCollection, TEqualityComparer> + where TCollection : new() + { + /// <summary> + /// The delegate that will create the collection, if the typical (int count, IEqualityComparer{T} equalityComparer) constructor was found. + /// </summary> + private static Func<int, TEqualityComparer, TCollection> collectionCreator; + + /// <summary> + /// Initializes static members of the <see cref="CollectionHelpers{TCollection, TEqualityComparer}"/> class. + /// </summary> + /// <remarks> + /// Initializes a delegate that is optimized to create a collection of a given size and using the given equality comparer, if possible. + /// </remarks> + static CollectionHelpers() + { + var ctor = typeof(TCollection).GetConstructor(new Type[] { typeof(int), typeof(TEqualityComparer) }); + if (ctor != null) + { + ParameterExpression param1 = Expression.Parameter(typeof(int), "count"); + ParameterExpression param2 = Expression.Parameter(typeof(TEqualityComparer), "equalityComparer"); + NewExpression body = Expression.New(ctor, param1, param2); + collectionCreator = Expression.Lambda<Func<int, TEqualityComparer, TCollection>>(body, param1, param2).Compile(); + } + } + + /// <summary> + /// Initializes a new instance of the <typeparamref name="TCollection"/> collection. + /// </summary> + /// <param name="count">The number of elements the collection should be prepared to receive.</param> + /// <param name="equalityComparer">The equality comparer to initialize the collection with.</param> + /// <returns>The newly initialized collection.</returns> + /// <remarks> + /// Use of the <paramref name="count"/> and <paramref name="equalityComparer"/> are a best effort. + /// If we can't find a constructor on the collection in the expected shape, we'll just instantiate the collection with its default constructor. + /// </remarks> + internal static TCollection CreateHashCollection(int count, TEqualityComparer equalityComparer) => collectionCreator != null ? collectionCreator.Invoke(count, equalityComparer) : new TCollection(); + } +}
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/DictionaryFormatter.cs+20 −11 modified@@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Reflection; #pragma warning disable SA1649 // File name should match first type name @@ -83,14 +84,22 @@ public TDictionary Deserialize(ref MessagePackReader reader, MessagePackSerializ var len = reader.ReadMapHeader(); TIntermediate dict = this.Create(len, options); - for (int i = 0; i < len; i++) + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - TKey key = keyFormatter.Deserialize(ref reader, options); + for (int i = 0; i < len; i++) + { + reader.CancellationToken.ThrowIfCancellationRequested(); + TKey key = keyFormatter.Deserialize(ref reader, options); - TValue value = valueFormatter.Deserialize(ref reader, options); + TValue value = valueFormatter.Deserialize(ref reader, options); - this.Add(dict, i, key, value, options); + this.Add(dict, i, key, value, options); + } + } + finally + { + reader.Depth--; } return this.Complete(dict); @@ -142,7 +151,7 @@ protected override Dictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> in protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options) { - return new Dictionary<TKey, TValue>(count); + return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>()); } protected override Dictionary<TKey, TValue>.Enumerator GetSourceEnumerator(Dictionary<TKey, TValue> source) @@ -161,7 +170,7 @@ protected override void Add(TDictionary collection, int index, TKey key, TValue protected override TDictionary Create(int count, MessagePackSerializerOptions options) { - return new TDictionary(); + return CollectionHelpers<TDictionary, IEqualityComparer<TKey>>.CreateHashCollection(count, options.Security.GetEqualityComparer<TKey>()); } } @@ -174,7 +183,7 @@ protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options) { - return new Dictionary<TKey, TValue>(count); + return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>()); } protected override IDictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection) @@ -233,7 +242,7 @@ protected override ReadOnlyDictionary<TKey, TValue> Complete(Dictionary<TKey, TV protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options) { - return new Dictionary<TKey, TValue>(count); + return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>()); } } @@ -251,7 +260,7 @@ protected override IReadOnlyDictionary<TKey, TValue> Complete(Dictionary<TKey, T protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options) { - return new Dictionary<TKey, TValue>(count); + return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>()); } } @@ -265,7 +274,7 @@ protected override void Add(ConcurrentDictionary<TKey, TValue> collection, int i protected override ConcurrentDictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options) { // concurrent dictionary can't access defaultConcurrecyLevel so does not use count overload. - return new ConcurrentDictionary<TKey, TValue>(); + return new ConcurrentDictionary<TKey, TValue>(options.Security.GetEqualityComparer<TKey>()); } } }
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/MultiDimensionalArrayFormatter.cs+76 −52 modified@@ -66,20 +66,28 @@ public void Serialize(ref MessagePackWriter writer, T[,] value, MessagePackSeria var i = 0; var j = -1; - for (int loop = 0; loop < maxLen; loop++) + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - if (j < jLength - 1) + for (int loop = 0; loop < maxLen; loop++) { - j++; + reader.CancellationToken.ThrowIfCancellationRequested(); + if (j < jLength - 1) + { + j++; + } + else + { + j = 0; + i++; + } + + array[i, j] = formatter.Deserialize(ref reader, options); } - else - { - j = 0; - i++; - } - - array[i, j] = formatter.Deserialize(ref reader, options); + } + finally + { + reader.Depth--; } return array; @@ -145,26 +153,34 @@ public void Serialize(ref MessagePackWriter writer, T[,,] value, MessagePackSeri var i = 0; var j = 0; var k = -1; - for (int loop = 0; loop < maxLen; loop++) + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - if (k < kLength - 1) + for (int loop = 0; loop < maxLen; loop++) { - k++; + reader.CancellationToken.ThrowIfCancellationRequested(); + if (k < kLength - 1) + { + k++; + } + else if (j < jLength - 1) + { + k = 0; + j++; + } + else + { + k = 0; + j = 0; + i++; + } + + array[i, j, k] = formatter.Deserialize(ref reader, options); } - else if (j < jLength - 1) - { - k = 0; - j++; - } - else - { - k = 0; - j = 0; - i++; - } - - array[i, j, k] = formatter.Deserialize(ref reader, options); + } + finally + { + reader.Depth--; } return array; @@ -233,33 +249,41 @@ public void Serialize(ref MessagePackWriter writer, T[,,,] value, MessagePackSer var j = 0; var k = 0; var l = -1; - for (int loop = 0; loop < maxLen; loop++) + options.Security.DepthStep(ref reader); + try { - reader.CancellationToken.ThrowIfCancellationRequested(); - if (l < lLength - 1) - { - l++; - } - else if (k < kLength - 1) - { - l = 0; - k++; - } - else if (j < jLength - 1) + for (int loop = 0; loop < maxLen; loop++) { - l = 0; - k = 0; - j++; + reader.CancellationToken.ThrowIfCancellationRequested(); + if (l < lLength - 1) + { + l++; + } + else if (k < kLength - 1) + { + l = 0; + k++; + } + else if (j < jLength - 1) + { + l = 0; + k = 0; + j++; + } + else + { + l = 0; + k = 0; + j = 0; + i++; + } + + array[i, j, k, l] = formatter.Deserialize(ref reader, options); } - else - { - l = 0; - k = 0; - j = 0; - i++; - } - - array[i, j, k, l] = formatter.Deserialize(ref reader, options); + } + finally + { + reader.Depth--; } return array;
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/PrimitiveObjectFormatter.cs+24 −7 modified@@ -14,6 +14,7 @@ public sealed class PrimitiveObjectFormatter : IMessagePackFormatter<object> private static readonly Dictionary<Type, int> TypeToJumpCode = new Dictionary<Type, int>() { + // When adding types whose size exceeds 32-bits, add support in MessagePackSecurity.GetHashCollisionResistantEqualityComparer<T>() { typeof(Boolean), 0 }, { typeof(Char), 1 }, { typeof(SByte), 2 }, @@ -283,9 +284,17 @@ public object Deserialize(ref MessagePackReader reader, MessagePackSerializerOpt IMessagePackFormatter<object> objectFormatter = resolver.GetFormatter<object>(); var array = new object[length]; - for (int i = 0; i < length; i++) + options.Security.DepthStep(ref reader); + try { - array[i] = objectFormatter.Deserialize(ref reader, options); + for (int i = 0; i < length; i++) + { + array[i] = objectFormatter.Deserialize(ref reader, options); + } + } + finally + { + reader.Depth--; } return array; @@ -296,14 +305,22 @@ public object Deserialize(ref MessagePackReader reader, MessagePackSerializerOpt var length = reader.ReadMapHeader(); IMessagePackFormatter<object> objectFormatter = resolver.GetFormatter<object>(); - var hash = new Dictionary<object, object>(length); - for (int i = 0; i < length; i++) + var hash = new Dictionary<object, object>(length, options.Security.GetEqualityComparer<object>()); + options.Security.DepthStep(ref reader); + try { - var key = objectFormatter.Deserialize(ref reader, options); + for (int i = 0; i < length; i++) + { + var key = objectFormatter.Deserialize(ref reader, options); - var value = objectFormatter.Deserialize(ref reader, options); + var value = objectFormatter.Deserialize(ref reader, options); - hash.Add(key, value); + hash.Add(key, value); + } + } + finally + { + reader.Depth--; } return hash;
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs+23 −7 modified@@ -368,9 +368,17 @@ public KeyValuePair<TKey, TValue> Deserialize(ref MessagePackReader reader, Mess } IFormatterResolver resolver = options.Resolver; - TKey key = resolver.GetFormatterWithVerify<TKey>().Deserialize(ref reader, options); - TValue value = resolver.GetFormatterWithVerify<TValue>().Deserialize(ref reader, options); - return new KeyValuePair<TKey, TValue>(key, value); + options.Security.DepthStep(ref reader); + try + { + TKey key = resolver.GetFormatterWithVerify<TKey>().Deserialize(ref reader, options); + TValue value = resolver.GetFormatterWithVerify<TValue>().Deserialize(ref reader, options); + return new KeyValuePair<TKey, TValue>(key, value); + } + finally + { + reader.Depth--; + } } } @@ -573,10 +581,18 @@ public Lazy<T> Deserialize(ref MessagePackReader reader, MessagePackSerializerOp } else { - // deserialize immediately(no delay, because capture byte[] causes memory leak) - IFormatterResolver resolver = options.Resolver; - T v = resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options); - return new Lazy<T>(() => v); + options.Security.DepthStep(ref reader); + try + { + // deserialize immediately(no delay, because capture byte[] causes memory leak) + IFormatterResolver resolver = options.Resolver; + T v = resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options); + return new Lazy<T>(() => v); + } + finally + { + reader.Depth--; + } } } }
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/HashCode.cs+481 −0 added@@ -0,0 +1,481 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// <auto-generated /> + +/* + +The xxHash32 implementation is based on the code published by Yann Collet: +https://raw.githubusercontent.com/Cyan4973/xxHash/5c174cfa4e45a42f94082dc0d4539b39696afea1/xxhash.c + + xxHash - Fast Hash algorithm + Copyright (C) 2012-2016, Yann Collet + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - xxHash homepage: http://www.xxhash.com + - xxHash source repository : https://github.com/Cyan4973/xxHash + +*/ + +#if !NETCOREAPP + +using System.Collections.Generic; +using System.ComponentModel; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; + +namespace System +{ + // xxHash32 is used for the hash code. + // https://github.com/Cyan4973/xxHash + + internal struct HashCode + { + private static readonly uint s_seed = GenerateGlobalSeed(); + + private const uint Prime1 = 2654435761U; + private const uint Prime2 = 2246822519U; + private const uint Prime3 = 3266489917U; + private const uint Prime4 = 668265263U; + private const uint Prime5 = 374761393U; + + private uint _v1, _v2, _v3, _v4; + private uint _queue1, _queue2, _queue3; + private uint _length; + + private static uint GenerateGlobalSeed() + { + var bytes = new byte[4]; + using (var rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(bytes); + } + + return BitConverter.ToUInt32(bytes, 0); + } + + public static int Combine<T1>(T1 value1) + { + unchecked + { + // Provide a way of diffusing bits from something with a limited + // input hash space. For example, many enums only have a few + // possible hashes, only using the bottom few bits of the code. Some + // collections are built on the assumption that hashes are spread + // over a larger space, so diffusing the bits may help the + // collection work more efficiently. + + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + + uint hash = MixEmptyState(); + hash += 4; + + hash = QueueRound(hash, hc1); + + hash = MixFinal(hash); + return (int)hash; + } + } + + public static int Combine<T1, T2>(T1 value1, T2 value2) + { + unchecked + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + + uint hash = MixEmptyState(); + hash += 8; + + hash = QueueRound(hash, hc1); + hash = QueueRound(hash, hc2); + + hash = MixFinal(hash); + return (int)hash; + } + } + + public static int Combine<T1, T2, T3>(T1 value1, T2 value2, T3 value3) + { + unchecked + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + + uint hash = MixEmptyState(); + hash += 12; + + hash = QueueRound(hash, hc1); + hash = QueueRound(hash, hc2); + hash = QueueRound(hash, hc3); + + hash = MixFinal(hash); + return (int)hash; + } + } + + public static int Combine<T1, T2, T3, T4>(T1 value1, T2 value2, T3 value3, T4 value4) + { + unchecked + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + uint hash = MixState(v1, v2, v3, v4); + hash += 16; + + hash = MixFinal(hash); + return (int)hash; + } + } + + public static int Combine<T1, T2, T3, T4, T5>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5) + { + unchecked + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + uint hc5 = (uint)(value5?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + uint hash = MixState(v1, v2, v3, v4); + hash += 20; + + hash = QueueRound(hash, hc5); + + hash = MixFinal(hash); + return (int)hash; + } + } + + public static int Combine<T1, T2, T3, T4, T5, T6>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6) + { + unchecked + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + uint hc5 = (uint)(value5?.GetHashCode() ?? 0); + uint hc6 = (uint)(value6?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + uint hash = MixState(v1, v2, v3, v4); + hash += 24; + + hash = QueueRound(hash, hc5); + hash = QueueRound(hash, hc6); + + hash = MixFinal(hash); + return (int)hash; + } + } + + public static int Combine<T1, T2, T3, T4, T5, T6, T7>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7) + { + unchecked + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + uint hc5 = (uint)(value5?.GetHashCode() ?? 0); + uint hc6 = (uint)(value6?.GetHashCode() ?? 0); + uint hc7 = (uint)(value7?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + uint hash = MixState(v1, v2, v3, v4); + hash += 28; + + hash = QueueRound(hash, hc5); + hash = QueueRound(hash, hc6); + hash = QueueRound(hash, hc7); + + hash = MixFinal(hash); + return (int)hash; + } + } + + public static int Combine<T1, T2, T3, T4, T5, T6, T7, T8>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8) + { + unchecked + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + uint hc5 = (uint)(value5?.GetHashCode() ?? 0); + uint hc6 = (uint)(value6?.GetHashCode() ?? 0); + uint hc7 = (uint)(value7?.GetHashCode() ?? 0); + uint hc8 = (uint)(value8?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + v1 = Round(v1, hc5); + v2 = Round(v2, hc6); + v3 = Round(v3, hc7); + v4 = Round(v4, hc8); + + uint hash = MixState(v1, v2, v3, v4); + hash += 32; + + hash = MixFinal(hash); + return (int)hash; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4) + { + unchecked + { + v1 = s_seed + Prime1 + Prime2; + v2 = s_seed + Prime2; + v3 = s_seed; + v4 = s_seed - Prime1; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Round(uint hash, uint input) + { + unchecked + { + return BitOperations.RotateLeft(hash + input * Prime2, 13) * Prime1; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint QueueRound(uint hash, uint queuedValue) + { + unchecked + { + return BitOperations.RotateLeft(hash + queuedValue * Prime3, 17) * Prime4; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint MixState(uint v1, uint v2, uint v3, uint v4) + { + unchecked + { + return BitOperations.RotateLeft(v1, 1) + BitOperations.RotateLeft(v2, 7) + BitOperations.RotateLeft(v3, 12) + BitOperations.RotateLeft(v4, 18); + } + } + + private static uint MixEmptyState() + { + unchecked + { + return s_seed + Prime5; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint MixFinal(uint hash) + { + unchecked + { + hash ^= hash >> 15; + hash *= Prime2; + hash ^= hash >> 13; + hash *= Prime3; + hash ^= hash >> 16; + return hash; + } + } + + public void Add<T>(T value) + { + Add(value?.GetHashCode() ?? 0); + } + + public void Add<T>(T value, IEqualityComparer<T> comparer) + { + Add(comparer != null ? comparer.GetHashCode(value) : (value?.GetHashCode() ?? 0)); + } + + private void Add(int value) + { + unchecked + { + // The original xxHash works as follows: + // 0. Initialize immediately. We can't do this in a struct (no + // default ctor). + // 1. Accumulate blocks of length 16 (4 uints) into 4 accumulators. + // 2. Accumulate remaining blocks of length 4 (1 uint) into the + // hash. + // 3. Accumulate remaining blocks of length 1 into the hash. + + // There is no need for #3 as this type only accepts ints. _queue1, + // _queue2 and _queue3 are basically a buffer so that when + // ToHashCode is called we can execute #2 correctly. + + // We need to initialize the xxHash32 state (_v1 to _v4) lazily (see + // #0) nd the last place that can be done if you look at the + // original code is just before the first block of 16 bytes is mixed + // in. The xxHash32 state is never used for streams containing fewer + // than 16 bytes. + + // To see what's really going on here, have a look at the Combine + // methods. + + uint val = (uint)value; + + // Storing the value of _length locally shaves of quite a few bytes + // in the resulting machine code. + uint previousLength = _length++; + uint position = previousLength % 4; + + // Switch can't be inlined. + + if (position == 0) + _queue1 = val; + else if (position == 1) + _queue2 = val; + else if (position == 2) + _queue3 = val; + else // position == 3 + { + if (previousLength == 3) + Initialize(out _v1, out _v2, out _v3, out _v4); + + _v1 = Round(_v1, _queue1); + _v2 = Round(_v2, _queue2); + _v3 = Round(_v3, _queue3); + _v4 = Round(_v4, val); + } + } + } + + public int ToHashCode() + { + unchecked + { + // Storing the value of _length locally shaves of quite a few bytes + // in the resulting machine code. + uint length = _length; + + // position refers to the *next* queue position in this method, so + // position == 1 means that _queue1 is populated; _queue2 would have + // been populated on the next call to Add. + uint position = length % 4; + + // If the length is less than 4, _v1 to _v4 don't contain anything + // yet. xxHash32 treats this differently. + + uint hash = length < 4 ? MixEmptyState() : MixState(_v1, _v2, _v3, _v4); + + // _length is incremented once per Add(Int32) and is therefore 4 + // times too small (xxHash length is in bytes, not ints). + + hash += length * 4; + + // Mix what remains in the queue + + // Switch can't be inlined right now, so use as few branches as + // possible by manually excluding impossible scenarios (position > 1 + // is always false if position is not > 0). + if (position > 0) + { + hash = QueueRound(hash, _queue1); + if (position > 1) + { + hash = QueueRound(hash, _queue2); + if (position > 2) + hash = QueueRound(hash, _queue3); + } + } + + hash = MixFinal(hash); + return (int)hash; + } + } + +#pragma warning disable 0809 + // Obsolete member 'memberA' overrides non-obsolete member 'memberB'. + // Disallowing GetHashCode and Equals is by design + + // * We decided to not override GetHashCode() to produce the hash code + // as this would be weird, both naming-wise as well as from a + // behavioral standpoint (GetHashCode() should return the object's + // hash code, not the one being computed). + + // * Even though ToHashCode() can be called safely multiple times on + // this implementation, it is not part of the contract. If the + // implementation has to change in the future we don't want to worry + // about people who might have incorrectly used this type. + + [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code.", error: true)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => throw new NotSupportedException(); + + [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", error: true)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => throw new NotSupportedException(); +#pragma warning restore 0809 + } +} + +#endif
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs+8 −0 modified@@ -38,6 +38,7 @@ ref partial struct MessagePackReader public MessagePackReader(ReadOnlyMemory<byte> memory) { this.reader = new SequenceReader<byte>(memory); + this.Depth = 0; } /// <summary> @@ -47,13 +48,19 @@ public MessagePackReader(ReadOnlyMemory<byte> memory) public MessagePackReader(in ReadOnlySequence<byte> readOnlySequence) { this.reader = new SequenceReader<byte>(readOnlySequence); + this.Depth = 0; } /// <summary> /// Gets or sets the cancellation token for this deserialization operation. /// </summary> public CancellationToken CancellationToken { get; set; } + /// <summary> + /// Gets or sets the present depth of the object graph being deserialized. + /// </summary> + public int Depth { get; set; } + /// <summary> /// Gets the <see cref="ReadOnlySequence{T}"/> originally supplied to the constructor. /// </summary> @@ -110,6 +117,7 @@ public byte NextCode public MessagePackReader Clone(in ReadOnlySequence<byte> readOnlySequence) => new MessagePackReader(readOnlySequence) { CancellationToken = this.CancellationToken, + Depth = this.Depth, }; /// <summary>
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSecurity.cs+399 −0 added@@ -0,0 +1,399 @@ +// Copyright (c) All contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.ExceptionServices; +using MessagePack.Formatters; +using MessagePack.Internal; + +namespace MessagePack +{ + /// <summary> + /// Settings related to security, particularly relevant when deserializing data from untrusted sources. + /// </summary> + public class MessagePackSecurity + { + /// <summary> + /// Gets an instance preconfigured with settings that omit all protections. Useful for deserializing fully-trusted and valid msgpack sequences. + /// </summary> + public static readonly MessagePackSecurity TrustedData = new MessagePackSecurity(); + + /// <summary> + /// Gets an instance preconfigured with protections applied with reasonable settings for deserializing untrusted msgpack sequences. + /// </summary> + public static readonly MessagePackSecurity UntrustedData = new MessagePackSecurity + { + HashCollisionResistant = true, + MaximumObjectGraphDepth = 500, + }; + + private readonly ObjectFallbackEqualityComparer objectFallbackEqualityComparer; + + private MessagePackSecurity() + { + this.objectFallbackEqualityComparer = new ObjectFallbackEqualityComparer(this); + } + + /// <summary> + /// Initializes a new instance of the <see cref="MessagePackSecurity"/> class + /// with properties copied from a provided template. + /// </summary> + /// <param name="copyFrom">The template to copy from.</param> + protected MessagePackSecurity(MessagePackSecurity copyFrom) + { + if (copyFrom is null) + { + throw new ArgumentNullException(nameof(copyFrom)); + } + + this.HashCollisionResistant = copyFrom.HashCollisionResistant; + this.MaximumObjectGraphDepth = copyFrom.MaximumObjectGraphDepth; + } + + /// <summary> + /// Gets a value indicating whether data to be deserialized is untrusted and thus should not be allowed to create + /// dictionaries or other hash-based collections unless the hashed type has a hash collision resistant implementation available. + /// This can mitigate some denial of service attacks when deserializing untrusted code. + /// </summary> + /// <value> + /// The value is <c>false</c> for <see cref="TrustedData"/> and <c>true</c> for <see cref="UntrustedData"/>. + /// </value> + public bool HashCollisionResistant { get; private set; } + + /// <summary> + /// Gets the maximum depth of an object graph that may be deserialized. + /// </summary> + /// <remarks> + /// <para> + /// This value can be reduced to avoid a stack overflow that would crash the process when deserializing a msgpack sequence designed to cause deep recursion. + /// A very short callstack on a thread with 1MB of total stack space might deserialize ~2000 nested arrays before crashing due to a stack overflow. + /// Since stack space occupied may vary by the kind of object deserialized, a conservative value for this property to defend against stack overflow attacks might be 500. + /// </para> + /// </remarks> + public int MaximumObjectGraphDepth { get; private set; } = int.MaxValue; + + /// <summary> + /// Gets a copy of these options with the <see cref="MaximumObjectGraphDepth"/> property set to a new value. + /// </summary> + /// <param name="maximumObjectGraphDepth">The new value for the <see cref="MaximumObjectGraphDepth"/> property.</param> + /// <returns>The new instance; or the original if the value is unchanged.</returns> + public MessagePackSecurity WithMaximumObjectGraphDepth(int maximumObjectGraphDepth) + { + if (this.MaximumObjectGraphDepth == maximumObjectGraphDepth) + { + return this; + } + + var clone = this.Clone(); + clone.MaximumObjectGraphDepth = maximumObjectGraphDepth; + return clone; + } + + /// <summary> + /// Gets a copy of these options with the <see cref="HashCollisionResistant"/> property set to a new value. + /// </summary> + /// <param name="hashCollisionResistant">The new value for the <see cref="HashCollisionResistant"/> property.</param> + /// <returns>The new instance; or the original if the value is unchanged.</returns> + public MessagePackSecurity WithHashCollisionResistant(bool hashCollisionResistant) + { + if (this.HashCollisionResistant == hashCollisionResistant) + { + return this; + } + + var clone = this.Clone(); + clone.HashCollisionResistant = hashCollisionResistant; + return clone; + } + + /// <summary> + /// Gets an <see cref="IEqualityComparer{T}"/> that is suitable to use with a hash-based collection. + /// </summary> + /// <typeparam name="T">The type of key that will be hashed in the collection.</typeparam> + /// <returns>The <see cref="IEqualityComparer{T}"/> to use.</returns> + /// <remarks> + /// When <see cref="HashCollisionResistant"/> is active, this will be a collision resistant instance which may reject certain key types. + /// When <see cref="HashCollisionResistant"/> is not active, this will be <see cref="EqualityComparer{T}.Default"/>. + /// </remarks> + public IEqualityComparer<T> GetEqualityComparer<T>() + { + return this.HashCollisionResistant ? GetHashCollisionResistantEqualityComparer<T>() : EqualityComparer<T>.Default; + } + + /// <summary> + /// Gets an <see cref="IEqualityComparer"/> that is suitable to use with a hash-based collection. + /// </summary> + /// <returns>The <see cref="IEqualityComparer"/> to use.</returns> + /// <remarks> + /// When <see cref="HashCollisionResistant"/> is active, this will be a collision resistant instance which may reject certain key types. + /// When <see cref="HashCollisionResistant"/> is not active, this will be <see cref="EqualityComparer{T}.Default"/>. + /// </remarks> + public IEqualityComparer GetEqualityComparer() + { + return this.HashCollisionResistant ? GetHashCollisionResistantEqualityComparer() : EqualityComparer<object>.Default; + } + + /// <summary> + /// Returns a hash collision resistant equality comparer. + /// </summary> + /// <typeparam name="T">The type of key that will be hashed in the collection.</typeparam> + /// <returns>A hash collision resistant equality comparer.</returns> + protected virtual IEqualityComparer<T> GetHashCollisionResistantEqualityComparer<T>() + { + // For anything 32-bits and under, our fallback base secure hasher is usually adequate since it makes the hash unpredictable. + // We should have special implementations for any value that is larger than 32-bits in order to make sure + // that all the data gets hashed securely rather than trivially and predictably compressed into 32-bits before being hashed. + // We also have to specially handle some 32-bit types (e.g. float) where multiple in-memory representations should hash to the same value. + // Any type supported by the PrimitiveObjectFormatter should be added here if supporting it as a key in a collection makes sense. + return + // 32-bits or smaller: + typeof(T) == typeof(bool) ? CollisionResistantHasher<T>.Instance : + typeof(T) == typeof(char) ? CollisionResistantHasher<T>.Instance : + typeof(T) == typeof(sbyte) ? CollisionResistantHasher<T>.Instance : + typeof(T) == typeof(byte) ? CollisionResistantHasher<T>.Instance : + typeof(T) == typeof(short) ? CollisionResistantHasher<T>.Instance : + typeof(T) == typeof(ushort) ? CollisionResistantHasher<T>.Instance : + typeof(T) == typeof(int) ? CollisionResistantHasher<T>.Instance : + typeof(T) == typeof(uint) ? CollisionResistantHasher<T>.Instance : + + // Larger than 32-bits (or otherwise require special handling): + typeof(T) == typeof(long) ? (IEqualityComparer<T>)Int64EqualityComparer.Instance : + typeof(T) == typeof(ulong) ? (IEqualityComparer<T>)UInt64EqualityComparer.Instance : + typeof(T) == typeof(float) ? (IEqualityComparer<T>)SingleEqualityComparer.Instance : + typeof(T) == typeof(double) ? (IEqualityComparer<T>)DoubleEqualityComparer.Instance : + typeof(T) == typeof(string) ? (IEqualityComparer<T>)StringEqualityComparer.Instance : + typeof(T) == typeof(Guid) ? (IEqualityComparer<T>)GuidEqualityComparer.Instance : + typeof(T) == typeof(DateTime) ? (IEqualityComparer<T>)DateTimeEqualityComparer.Instance : + typeof(T) == typeof(DateTimeOffset) ? (IEqualityComparer<T>)DateTimeOffsetEqualityComparer.Instance : + typeof(T) == typeof(object) ? (IEqualityComparer<T>)this.objectFallbackEqualityComparer : + + // Any type we don't explicitly whitelist here shouldn't be allowed to use as the key in a hash-based collection since it isn't known to be hash resistant. + // This method can of course be overridden to add more hash collision resistant type support, or the deserializing party can indicate that the data is Trusted + // so that this method doesn't even get called. + throw new TypeAccessException($"No hash-resistant equality comparer available for type: {typeof(T)}"); + } + + /// <summary> + /// Checks the depth of the deserializing graph and increments it by 1. + /// </summary> + /// <param name="reader">The reader that is involved in deserialization.</param> + /// <remarks> + /// Callers should decrement <see cref="MessagePackReader.Depth"/> after exiting that edge in the graph. + /// </remarks> + /// <exception cref="InsufficientExecutionStackException">Thrown if <see cref="MessagePackReader.Depth"/> is already at or exceeds <see cref="MaximumObjectGraphDepth"/>.</exception> + /// <remarks> + /// Rather than wrap the body of every <see cref="IMessagePackFormatter{T}.Deserialize"/> method, + /// this should wrap *calls* to these methods. They need not appear in pure "thunk" methods that simply delegate the deserialization to another formatter. + /// In this way, we can avoid repeatedly incrementing and decrementing the counter when deserializing each element of a collection. + /// </remarks> + public void DepthStep(ref MessagePackReader reader) + { + if (reader.Depth >= this.MaximumObjectGraphDepth) + { + throw new InsufficientExecutionStackException($"This msgpack sequence has an object graph that exceeds the maximum depth allowed of {MaximumObjectGraphDepth}."); + } + + reader.Depth++; + } + + /// <summary> + /// Returns a hash collision resistant equality comparer. + /// </summary> + /// <returns>A hash collision resistant equality comparer.</returns> + protected virtual IEqualityComparer GetHashCollisionResistantEqualityComparer() => (IEqualityComparer)this.GetHashCollisionResistantEqualityComparer<object>(); + + /// <summary> + /// Creates a new instance that is a copy of this one. + /// </summary> + /// <remarks> + /// Derived types should override this method to instantiate their own derived type. + /// </remarks> + protected virtual MessagePackSecurity Clone() => new MessagePackSecurity(this); + + /// <summary> + /// A hash collision resistant implementation of <see cref="IEqualityComparer{T}"/>. + /// </summary> + /// <typeparam name="T">The type of key that will be hashed.</typeparam> + private class CollisionResistantHasher<T> : IEqualityComparer<T>, IEqualityComparer + { + internal static readonly CollisionResistantHasher<T> Instance = new CollisionResistantHasher<T>(); + + public bool Equals(T x, T y) => EqualityComparer<T>.Default.Equals(x, y); + + bool IEqualityComparer.Equals(object x, object y) => ((IEqualityComparer)EqualityComparer<T>.Default).Equals(x, y); + + public int GetHashCode(object obj) => this.GetHashCode((T)obj); + + public virtual int GetHashCode(T value) => HashCode.Combine(value); + } + + /// <summary> + /// A special hash-resistent equality comparer that defers picking the actual implementation + /// till it can check the runtime type of each value to be hashed. + /// </summary> + private class ObjectFallbackEqualityComparer : IEqualityComparer<object>, IEqualityComparer + { + private static readonly MethodInfo GetHashCollisionResistantEqualityComparerOpenGenericMethod = typeof(MessagePackSecurity).GetTypeInfo().DeclaredMethods.Single(m => m.Name == nameof(MessagePackSecurity.GetHashCollisionResistantEqualityComparer) && m.IsGenericMethod); + private readonly MessagePackSecurity security; + private readonly ThreadsafeTypeKeyHashTable<IEqualityComparer> equalityComparerCache = new ThreadsafeTypeKeyHashTable<IEqualityComparer>(); + + internal ObjectFallbackEqualityComparer(MessagePackSecurity security) + { + this.security = security ?? throw new ArgumentNullException(nameof(security)); + } + + bool IEqualityComparer<object>.Equals(object x, object y) => EqualityComparer<object>.Default.Equals(x, y); + + bool IEqualityComparer.Equals(object x, object y) => ((IEqualityComparer)EqualityComparer<object>.Default).Equals(x, y); + + public int GetHashCode(object value) + { + if (value is null) + { + return 0; + } + + Type valueType = value.GetType(); + + // Take care to avoid recursion. + if (valueType == typeof(object)) + { + // We can trust object.GetHashCode() to be collision resistant. + return value.GetHashCode(); + } + + if (!equalityComparerCache.TryGetValue(valueType, out IEqualityComparer equalityComparer)) + { + try + { + equalityComparer = (IEqualityComparer)GetHashCollisionResistantEqualityComparerOpenGenericMethod.MakeGenericMethod(valueType).Invoke(this.security, Array.Empty<object>()); + } + catch (TargetInvocationException ex) + { + ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + } + + equalityComparerCache.TryAdd(valueType, equalityComparer); + } + + return equalityComparer.GetHashCode(value); + } + } + + private class UInt64EqualityComparer : CollisionResistantHasher<ulong> + { + internal static new readonly UInt64EqualityComparer Instance = new UInt64EqualityComparer(); + + public override int GetHashCode(ulong value) => HashCode.Combine((uint)(value >> 32), unchecked((uint)value)); + } + + private class Int64EqualityComparer : CollisionResistantHasher<long> + { + internal static new readonly Int64EqualityComparer Instance = new Int64EqualityComparer(); + + public override int GetHashCode(long value) => HashCode.Combine((int)(value >> 32), unchecked((int)value)); + } + + private class SingleEqualityComparer : CollisionResistantHasher<float> + { + internal static new readonly SingleEqualityComparer Instance = new SingleEqualityComparer(); + + public override unsafe int GetHashCode(float value) + { + // Special check for 0.0 so that the hash of 0.0 and -0.0 will equal. + if (value == 0.0f) + { + return HashCode.Combine(0); + } + + // Standardize on the binary representation of NaN prior to hashing. + if (float.IsNaN(value)) + { + value = float.NaN; + } + + long l = *(long*)&value; + return HashCode.Combine((int)(l >> 32), unchecked((int)l)); + } + } + + private class DoubleEqualityComparer : CollisionResistantHasher<double> + { + internal static new readonly DoubleEqualityComparer Instance = new DoubleEqualityComparer(); + + public override unsafe int GetHashCode(double value) + { + // Special check for 0.0 so that the hash of 0.0 and -0.0 will equal. + if (value == 0.0) + { + return HashCode.Combine(0); + } + + // Standardize on the binary representation of NaN prior to hashing. + if (double.IsNaN(value)) + { + value = double.NaN; + } + + long l = *(long*)&value; + return HashCode.Combine((int)(l >> 32), unchecked((int)l)); + } + } + + private class GuidEqualityComparer : CollisionResistantHasher<Guid> + { + internal static new readonly GuidEqualityComparer Instance = new GuidEqualityComparer(); + + public override unsafe int GetHashCode(Guid value) + { + var hash = default(HashCode); + int* pGuid = (int*)&value; + for (int i = 0; i < sizeof(Guid) / sizeof(int); i++) + { + hash.Add(pGuid[i]); + } + + return hash.ToHashCode(); + } + } + + private class StringEqualityComparer : CollisionResistantHasher<string> + { + internal static new readonly StringEqualityComparer Instance = new StringEqualityComparer(); + + public override int GetHashCode(string value) + { +#if NETCOREAPP + // .NET Core already has a secure string hashing function. Just use it. + return value?.GetHashCode() ?? 0; +#else + var hash = default(HashCode); + for (int i = 0; i < value.Length; i++) + { + hash.Add(value[i]); + } + + return hash.ToHashCode(); +#endif + } + } + + private class DateTimeEqualityComparer : CollisionResistantHasher<DateTime> + { + internal static new readonly DateTimeEqualityComparer Instance = new DateTimeEqualityComparer(); + + public override unsafe int GetHashCode(DateTime value) => HashCode.Combine((int)(value.Ticks >> 32), unchecked((int)value.Ticks), value.Kind); + } + + private class DateTimeOffsetEqualityComparer : CollisionResistantHasher<DateTimeOffset> + { + internal static new readonly DateTimeOffsetEqualityComparer Instance = new DateTimeOffsetEqualityComparer(); + + public override unsafe int GetHashCode(DateTimeOffset value) => HashCode.Combine((int)(value.UtcTicks >> 32), unchecked((int)value.UtcTicks)); + } + } +}
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.Json.cs+52 −35 modified@@ -98,17 +98,17 @@ public static void ConvertToJson(ref MessagePackReader reader, TextWriter jsonWr return; } - ToJsonCore(ref scratchReader, jsonWriter); + ToJsonCore(ref scratchReader, jsonWriter, options); } else { - ToJsonCore(ref reader, jsonWriter); + ToJsonCore(ref reader, jsonWriter, options); } } } else { - ToJsonCore(ref reader, jsonWriter); + ToJsonCore(ref reader, jsonWriter, options); } } catch (Exception ex) @@ -265,7 +265,7 @@ private static uint FromJsonCore(TinyJsonReader jr, ref MessagePackWriter writer return count; } - private static void ToJsonCore(ref MessagePackReader reader, TextWriter writer) + private static void ToJsonCore(ref MessagePackReader reader, TextWriter writer, MessagePackSerializerOptions options) { MessagePackType type = reader.NextMessagePackType; switch (type) @@ -305,56 +305,73 @@ private static void ToJsonCore(ref MessagePackReader reader, TextWriter writer) case MessagePackType.Array: { int length = reader.ReadArrayHeader(); - writer.Write("["); - for (int i = 0; i < length; i++) + options.Security.DepthStep(ref reader); + try { - ToJsonCore(ref reader, writer); - - if (i != length - 1) + writer.Write("["); + for (int i = 0; i < length; i++) { - writer.Write(","); + ToJsonCore(ref reader, writer, options); + + if (i != length - 1) + { + writer.Write(","); + } } + + writer.Write("]"); + } + finally + { + reader.Depth--; } - writer.Write("]"); return; } case MessagePackType.Map: { int length = reader.ReadMapHeader(); - writer.Write("{"); - for (int i = 0; i < length; i++) + options.Security.DepthStep(ref reader); + try { - // write key + writer.Write("{"); + for (int i = 0; i < length; i++) { - MessagePackType keyType = reader.NextMessagePackType; - if (keyType == MessagePackType.String || keyType == MessagePackType.Binary) + // write key { - ToJsonCore(ref reader, writer); + MessagePackType keyType = reader.NextMessagePackType; + if (keyType == MessagePackType.String || keyType == MessagePackType.Binary) + { + ToJsonCore(ref reader, writer, options); + } + else + { + writer.Write("\""); + ToJsonCore(ref reader, writer, options); + writer.Write("\""); + } } - else + + writer.Write(":"); + + // write body { - writer.Write("\""); - ToJsonCore(ref reader, writer); - writer.Write("\""); + ToJsonCore(ref reader, writer, options); } - } - - writer.Write(":"); - // write body - { - ToJsonCore(ref reader, writer); + if (i != length - 1) + { + writer.Write(","); + } } - if (i != length - 1) - { - writer.Write(","); - } + writer.Write("}"); + } + finally + { + reader.Depth--; } - - writer.Write("}"); return; } @@ -375,7 +392,7 @@ private static void ToJsonCore(ref MessagePackReader reader, TextWriter writer) var privateBuilder = new StringBuilder(); var typeNameTokenBuilder = new StringBuilder(); SequencePosition positionBeforeTypeNameRead = reader.Position; - ToJsonCore(ref reader, new StringWriter(typeNameTokenBuilder)); + ToJsonCore(ref reader, new StringWriter(typeNameTokenBuilder), options); int typeNameReadSize = (int)reader.Sequence.Slice(positionBeforeTypeNameRead, reader.Position).Length; if (extHeader.Length > typeNameReadSize) { @@ -386,7 +403,7 @@ private static void ToJsonCore(ref MessagePackReader reader, TextWriter writer) privateBuilder.Append("{"); } - ToJsonCore(ref reader, new StringWriter(privateBuilder)); + ToJsonCore(ref reader, new StringWriter(privateBuilder), options); // insert type name token to start of object map or array if (typeInside != MessagePackType.Array)
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializerOptions.cs+31 −0 modified@@ -59,6 +59,7 @@ protected MessagePackSerializerOptions(MessagePackSerializerOptions copyFrom) this.OldSpec = copyFrom.OldSpec; this.OmitAssemblyVersion = copyFrom.OmitAssemblyVersion; this.AllowAssemblyVersionMismatch = copyFrom.AllowAssemblyVersionMismatch; + this.Security = copyFrom.Security; } /// <summary> @@ -104,6 +105,14 @@ protected MessagePackSerializerOptions(MessagePackSerializerOptions copyFrom) /// <value>The default value is <c>false</c>.</value> public bool AllowAssemblyVersionMismatch { get; private set; } + /// <summary> + /// Gets the security-related options for deserializing messagepack sequences. + /// </summary> + /// <value> + /// The default value is to use <see cref="MessagePackSecurity.TrustedData"/>. + /// </value> + public MessagePackSecurity Security { get; private set; } = MessagePackSecurity.TrustedData; + /// <summary> /// Gets a type given a string representation of the type. /// </summary> @@ -228,6 +237,28 @@ public MessagePackSerializerOptions WithAllowAssemblyVersionMismatch(bool allowA return result; } + /// <summary> + /// Gets a copy of these options with the <see cref="Security"/> property set to a new value. + /// </summary> + /// <param name="security">The new value for the <see cref="Security"/> property.</param> + /// <returns>The new instance; or the original if the value is unchanged.</returns> + public MessagePackSerializerOptions WithSecurity(MessagePackSecurity security) + { + if (security is null) + { + throw new ArgumentNullException(nameof(security)); + } + + if (this.Security == security) + { + return this; + } + + var result = this.Clone(); + result.Security = security; + return result; + } + /// <summary> /// Creates a clone of this instance with the same properties set. /// </summary>
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs+22 −4 modified@@ -849,7 +849,7 @@ private static void EmitSerializeValue(ILGenerator il, TypeInfo type, ObjectSeri private static void BuildDeserialize(Type type, ObjectSerializationInfo info, ILGenerator il, Func<int, ObjectSerializationInfo.EmittableMember, Action> tryEmitLoadCustomFormatter, int firstArgIndex) { var reader = new ArgumentField(il, firstArgIndex, @ref: true); - var argResolver = new ArgumentField(il, firstArgIndex + 1); + var argOptions = new ArgumentField(il, firstArgIndex + 1); // if(reader.TryReadNil()) { return null; } Label falseLabel = il.DefineLabel(); @@ -870,6 +870,12 @@ private static void BuildDeserialize(Type type, ObjectSerializationInfo info, IL il.MarkLabel(falseLabel); + // options.Security.DepthStep(ref reader); + argOptions.EmitLoad(); + il.EmitCall(getSecurityFromOptions); + reader.EmitLdarg(); + il.EmitCall(securityDepthStep); + // var length = ReadMapHeader(ref byteSequence); LocalBuilder length = il.DeclareLocal(typeof(int)); // [loc:1] reader.EmitLdarg(); @@ -939,7 +945,7 @@ private static void BuildDeserialize(Type type, ObjectSerializationInfo info, IL // IFormatterResolver resolver = options.Resolver; LocalBuilder localResolver = il.DeclareLocal(typeof(IFormatterResolver)); - argResolver.EmitLoad(); + argOptions.EmitLoad(); il.EmitCall(getResolverFromOptions); il.EmitStloc(localResolver); @@ -975,7 +981,7 @@ private static void BuildDeserialize(Type type, ObjectSerializationInfo info, IL var i = x.Value; if (infoList[i].MemberInfo != null) { - EmitDeserializeValue(il, infoList[i], i, tryEmitLoadCustomFormatter, reader, argResolver, localResolver); + EmitDeserializeValue(il, infoList[i], i, tryEmitLoadCustomFormatter, reader, argOptions, localResolver); il.Emit(OpCodes.Br, loopEnd); } else @@ -1031,7 +1037,7 @@ private static void BuildDeserialize(Type type, ObjectSerializationInfo info, IL if (item.MemberInfo != null) { il.MarkLabel(item.SwitchLabel); - EmitDeserializeValue(il, item, i++, tryEmitLoadCustomFormatter, reader, argResolver, localResolver); + EmitDeserializeValue(il, item, i++, tryEmitLoadCustomFormatter, reader, argOptions, localResolver); il.Emit(OpCodes.Br, loopEnd); } } @@ -1077,6 +1083,14 @@ private static void BuildDeserialize(Type type, ObjectSerializationInfo info, IL } } + // reader.Depth--; + reader.EmitLdarg(); + il.Emit(OpCodes.Dup); + il.EmitCall(readerDepthGet); + il.Emit(OpCodes.Ldc_I4_1); + il.Emit(OpCodes.Sub_Ovf); + il.EmitCall(readerDepthSet); + if (info.IsStruct) { il.Emit(OpCodes.Ldloc, structLocal); @@ -1226,6 +1240,10 @@ private static bool IsOptimizeTargetType(Type type) private static readonly MethodInfo getFormatterWithVerify = typeof(FormatterResolverExtensions).GetRuntimeMethods().First(x => x.Name == nameof(FormatterResolverExtensions.GetFormatterWithVerify)); private static readonly MethodInfo getResolverFromOptions = typeof(MessagePackSerializerOptions).GetRuntimeProperty(nameof(MessagePackSerializerOptions.Resolver)).GetMethod; + private static readonly MethodInfo getSecurityFromOptions = typeof(MessagePackSerializerOptions).GetRuntimeProperty(nameof(MessagePackSerializerOptions.Security)).GetMethod; + private static readonly MethodInfo securityDepthStep = typeof(MessagePackSecurity).GetRuntimeMethod(nameof(MessagePackSecurity.DepthStep), new[] { typeof(MessagePackReader).MakeByRefType() }); + private static readonly MethodInfo readerDepthGet = typeof(MessagePackReader).GetRuntimeProperty(nameof(MessagePackReader.Depth)).GetMethod; + private static readonly MethodInfo readerDepthSet = typeof(MessagePackReader).GetRuntimeProperty(nameof(MessagePackReader.Depth)).SetMethod; private static readonly Func<Type, MethodInfo> getSerialize = t => typeof(IMessagePackFormatter<>).MakeGenericType(t).GetRuntimeMethod(nameof(IMessagePackFormatter<int>.Serialize), new[] { typeof(MessagePackWriter).MakeByRefType(), t, typeof(MessagePackSerializerOptions) }); private static readonly Func<Type, MethodInfo> getDeserialize = t => typeof(IMessagePackFormatter<>).MakeGenericType(t).GetRuntimeMethod(nameof(IMessagePackFormatter<int>.Deserialize), new[] { refMessagePackReader, typeof(MessagePackSerializerOptions) }); //// static readonly ConstructorInfo dictionaryConstructor = typeof(ByteArrayStringHashTable).GetTypeInfo().DeclaredConstructors.First(x => { var p = x.GetParameters(); return p.Length == 1 && p[0].ParameterType == typeof(int); });
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/T4/ForceSizePrimitiveFormatter.cs+70 −14 modified@@ -97,9 +97,17 @@ public Int16[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOp { var len = reader.ReadArrayHeader(); var array = new Int16[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try { - array[i] = reader.ReadInt16(); + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadInt16(); + } + } + finally + { + reader.Depth--; } return array; @@ -193,9 +201,17 @@ public Int32[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOp { var len = reader.ReadArrayHeader(); var array = new Int32[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadInt32(); + } + } + finally { - array[i] = reader.ReadInt32(); + reader.Depth--; } return array; @@ -289,9 +305,17 @@ public Int64[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOp { var len = reader.ReadArrayHeader(); var array = new Int64[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try { - array[i] = reader.ReadInt64(); + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadInt64(); + } + } + finally + { + reader.Depth--; } return array; @@ -385,9 +409,17 @@ public UInt16[] Deserialize(ref MessagePackReader reader, MessagePackSerializerO { var len = reader.ReadArrayHeader(); var array = new UInt16[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadUInt16(); + } + } + finally { - array[i] = reader.ReadUInt16(); + reader.Depth--; } return array; @@ -481,9 +513,17 @@ public UInt32[] Deserialize(ref MessagePackReader reader, MessagePackSerializerO { var len = reader.ReadArrayHeader(); var array = new UInt32[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadUInt32(); + } + } + finally { - array[i] = reader.ReadUInt32(); + reader.Depth--; } return array; @@ -577,9 +617,17 @@ public UInt64[] Deserialize(ref MessagePackReader reader, MessagePackSerializerO { var len = reader.ReadArrayHeader(); var array = new UInt64[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try { - array[i] = reader.ReadUInt64(); + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadUInt64(); + } + } + finally + { + reader.Depth--; } return array; @@ -725,9 +773,17 @@ public SByte[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOp { var len = reader.ReadArrayHeader(); var array = new SByte[len]; - for (int i = 0; i < array.Length; i++) + options.Security.DepthStep(ref reader); + try + { + for (int i = 0; i < array.Length; i++) + { + array[i] = reader.ReadSByte(); + } + } + finally { - array[i] = reader.ReadSByte(); + reader.Depth--; } return array;
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/T4/TupleFormatter.cs+111 −47 modified@@ -43,9 +43,17 @@ public Tuple<T1> Deserialize(ref MessagePackReader reader, MessagePackSerializer } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - return new Tuple<T1>(item1); + return new Tuple<T1>(item1); + } + finally + { + reader.Depth--; + } } } } @@ -83,10 +91,18 @@ public Tuple<T1, T2> Deserialize(ref MessagePackReader reader, MessagePackSerial } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - return new Tuple<T1, T2>(item1, item2); + return new Tuple<T1, T2>(item1, item2); + } + finally + { + reader.Depth--; + } } } } @@ -125,11 +141,19 @@ public Tuple<T1, T2, T3> Deserialize(ref MessagePackReader reader, MessagePackSe } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - return new Tuple<T1, T2, T3>(item1, item2, item3); + return new Tuple<T1, T2, T3>(item1, item2, item3); + } + finally + { + reader.Depth--; + } } } } @@ -169,12 +193,20 @@ public Tuple<T1, T2, T3, T4> Deserialize(ref MessagePackReader reader, MessagePa } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4); + return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4); + } + finally + { + reader.Depth--; + } } } } @@ -215,13 +247,21 @@ public Tuple<T1, T2, T3, T4, T5> Deserialize(ref MessagePackReader reader, Messa } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); + return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); + } + finally + { + reader.Depth--; + } } } } @@ -263,14 +303,22 @@ public Tuple<T1, T2, T3, T4, T5, T6> Deserialize(ref MessagePackReader reader, M } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - - return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + + return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); + } + finally + { + reader.Depth--; + } } } } @@ -313,15 +361,23 @@ public Tuple<T1, T2, T3, T4, T5, T6, T7> Deserialize(ref MessagePackReader reade } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); - - return new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); + + return new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); + } + finally + { + reader.Depth--; + } } } } @@ -365,16 +421,24 @@ public Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> Deserialize(ref MessagePackReade } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); - TRest item8 = resolver.GetFormatterWithVerify<TRest>().Deserialize(ref reader, options); - - return new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, item8); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); + TRest item8 = resolver.GetFormatterWithVerify<TRest>().Deserialize(ref reader, options); + + return new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, item8); + } + finally + { + reader.Depth--; + } } } }
src/MessagePack.UnityClient/Assets/Scripts/MessagePack/T4/ValueTupleFormatter.cs+111 −47 modified@@ -36,9 +36,17 @@ public ValueTuple<T1> Deserialize(ref MessagePackReader reader, MessagePackSeria } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - return new ValueTuple<T1>(item1); + return new ValueTuple<T1>(item1); + } + finally + { + reader.Depth--; + } } } } @@ -69,10 +77,18 @@ public ValueTuple<T1, T2> Deserialize(ref MessagePackReader reader, MessagePackS } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - return new ValueTuple<T1, T2>(item1, item2); + return new ValueTuple<T1, T2>(item1, item2); + } + finally + { + reader.Depth--; + } } } } @@ -104,11 +120,19 @@ public ValueTuple<T1, T2, T3> Deserialize(ref MessagePackReader reader, MessageP } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - return new ValueTuple<T1, T2, T3>(item1, item2, item3); + return new ValueTuple<T1, T2, T3>(item1, item2, item3); + } + finally + { + reader.Depth--; + } } } } @@ -141,12 +165,20 @@ public ValueTuple<T1, T2, T3, T4> Deserialize(ref MessagePackReader reader, Mess } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - return new ValueTuple<T1, T2, T3, T4>(item1, item2, item3, item4); + return new ValueTuple<T1, T2, T3, T4>(item1, item2, item3, item4); + } + finally + { + reader.Depth--; + } } } } @@ -180,13 +212,21 @@ public ValueTuple<T1, T2, T3, T4, T5> Deserialize(ref MessagePackReader reader, } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - return new ValueTuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); + return new ValueTuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5); + } + finally + { + reader.Depth--; + } } } } @@ -221,14 +261,22 @@ public ValueTuple<T1, T2, T3, T4, T5, T6> Deserialize(ref MessagePackReader read } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - - return new ValueTuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + + return new ValueTuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6); + } + finally + { + reader.Depth--; + } } } } @@ -264,15 +312,23 @@ public ValueTuple<T1, T2, T3, T4, T5, T6, T7> Deserialize(ref MessagePackReader } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); - - return new ValueTuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); + + return new ValueTuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7); + } + finally + { + reader.Depth--; + } } } } @@ -310,16 +366,24 @@ public ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> Deserialize(ref MessagePack } IFormatterResolver resolver = options.Resolver; - T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); - T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); - T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); - T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); - T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); - T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); - T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); - TRest item8 = resolver.GetFormatterWithVerify<TRest>().Deserialize(ref reader, options); - - return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, item8); + options.Security.DepthStep(ref reader); + try + { + T1 item1 = resolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options); + T2 item2 = resolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options); + T3 item3 = resolver.GetFormatterWithVerify<T3>().Deserialize(ref reader, options); + T4 item4 = resolver.GetFormatterWithVerify<T4>().Deserialize(ref reader, options); + T5 item5 = resolver.GetFormatterWithVerify<T5>().Deserialize(ref reader, options); + T6 item6 = resolver.GetFormatterWithVerify<T6>().Deserialize(ref reader, options); + T7 item7 = resolver.GetFormatterWithVerify<T7>().Deserialize(ref reader, options); + TRest item8 = resolver.GetFormatterWithVerify<TRest>().Deserialize(ref reader, options); + + return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>(item1, item2, item3, item4, item5, item6, item7, item8); + } + finally + { + reader.Depth--; + } } } }
src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackReaderTests.cs+11 −0 modified@@ -252,6 +252,17 @@ public void ReadRaw() Assert.True(reader.End); } + [Fact] + public void Depth() + { + var reader = new MessagePackReader(Encode((ref MessagePackWriter w) => w.Write(1.23))); + Assert.Equal(0, reader.Depth); + reader.Depth++; + Assert.Equal(1, reader.Depth); + reader.Depth--; + Assert.Equal(0, reader.Depth); + } + [Fact] public void Read_CheckOperations_WithNoBytesLeft() {
src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs+178 −0 added@@ -0,0 +1,178 @@ +// Copyright (c) All contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using MessagePack; +using Xunit; +using Xunit.Abstractions; + +public class MessagePackSecurityTests +{ + public MessagePackSecurityTests(ITestOutputHelper logger) + { + Logger = logger; + } + + public ITestOutputHelper Logger { get; } + + [Fact] + public void Untrusted() + { + Assert.True(MessagePackSecurity.UntrustedData.HashCollisionResistant); + } + + [Fact] + public void Trusted() + { + Assert.False(MessagePackSecurity.TrustedData.HashCollisionResistant); + } + + [Fact] + public void WithHashCollisionResistant() + { + Assert.Same(MessagePackSecurity.TrustedData, MessagePackSecurity.TrustedData.WithHashCollisionResistant(false)); + Assert.True(MessagePackSecurity.TrustedData.WithHashCollisionResistant(true).HashCollisionResistant); + } + + [Fact] + public void EqualityComparer_CollisionResistance_Int64() + { + const long value1 = 0x100000001; + const long value2 = 0x200000002; + var eq = MessagePackSecurity.UntrustedData.GetEqualityComparer<long>(); + Assert.Equal(EqualityComparer<long>.Default.GetHashCode(value1), EqualityComparer<long>.Default.GetHashCode(value2)); // demonstrate insecurity + Assert.NotEqual(eq.GetHashCode(value1), eq.GetHashCode(value2)); + } + + [Fact] + public void EqualityComparer_CollisionResistance_Guid() + { + Guid value1 = new Guid(new byte[] { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }); + Guid value2 = new Guid(new byte[] { 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2 }); + var eq = MessagePackSecurity.UntrustedData.GetEqualityComparer<Guid>(); +#if NETCOREAPP // We contrived the two GUIDs to force a collision on .NET Core. NETFx's algorithm is slightly different. + Assert.Equal(EqualityComparer<Guid>.Default.GetHashCode(value1), EqualityComparer<Guid>.Default.GetHashCode(value2)); // demonstrate insecurity +#endif + Assert.NotEqual(eq.GetHashCode(value1), eq.GetHashCode(value2)); + } + + [Fact] + public unsafe void EqualityComparer_Single() + { + var eq = MessagePackSecurity.UntrustedData.GetEqualityComparer<float>(); + Assert.Equal(eq.GetHashCode(0.0f), eq.GetHashCode(-0.0f)); + + // Try multiple forms of NaN + float nan1, nan2; + *(uint*)&nan1 = 0xFFC00001; + *(uint*)&nan2 = 0xFF800001; + + Assert.True(float.IsNaN(nan1)); + Assert.True(float.IsNaN(nan2)); +#if NETCOREAPP // .NET Framework had a bug where these would not be equal + Assert.Equal(nan1.GetHashCode(), nan2.GetHashCode()); +#endif + Assert.Equal(eq.GetHashCode(nan1), eq.GetHashCode(nan2)); + Assert.Equal(eq.GetHashCode(float.NaN), eq.GetHashCode(-float.NaN)); + + // Try various other clearly different numbers + Assert.NotEqual(eq.GetHashCode(1.0f), eq.GetHashCode(-1.0f)); + Assert.NotEqual(eq.GetHashCode(1.0f), eq.GetHashCode(2.0f)); + } + + [Fact] + public unsafe void EqualityComparer_Double() + { + var eq = MessagePackSecurity.UntrustedData.GetEqualityComparer<double>(); + Assert.Equal(eq.GetHashCode(0.0), eq.GetHashCode(-0.0)); + + // Try multiple forms of NaN + double nan1, nan2; + *(ulong*)&nan1 = 0xFFF8000000000001; + *(ulong*)&nan2 = 0xFFF8000000000002; + + Assert.True(double.IsNaN(nan1)); + Assert.True(double.IsNaN(nan2)); +#if NETCOREAPP // .NET Framework had a bug where these would not be equal + Assert.Equal(nan1.GetHashCode(), nan2.GetHashCode()); +#endif + Assert.Equal(eq.GetHashCode(nan1), eq.GetHashCode(nan2)); + Assert.Equal(eq.GetHashCode(double.NaN), eq.GetHashCode(-double.NaN)); + + // Try various other clearly different numbers + Assert.NotEqual(eq.GetHashCode(1.0), eq.GetHashCode(-1.0)); + Assert.NotEqual(eq.GetHashCode(1.0), eq.GetHashCode(2.0)); + } + + [Fact] + public void EqualityComparer_ObjectFallback() + { + var eq = MessagePackSecurity.UntrustedData.GetEqualityComparer<object>(); + + Assert.Equal(eq.GetHashCode(null), eq.GetHashCode(null)); + Assert.NotEqual(eq.GetHashCode(null), eq.GetHashCode(new object())); + + Assert.Equal(eq.GetHashCode("hi"), eq.GetHashCode("hi")); + Assert.NotEqual(eq.GetHashCode("hi"), eq.GetHashCode("bye")); + + Assert.Equal(eq.GetHashCode(true), eq.GetHashCode(true)); + Assert.NotEqual(eq.GetHashCode(true), eq.GetHashCode(false)); + + var o = new object(); + Assert.Equal(eq.GetHashCode(o), eq.GetHashCode(o)); + Assert.NotEqual(eq.GetHashCode(o), eq.GetHashCode(new object())); + } + + /// <summary> + /// Verifies that arbitrary other types not known to be hash safe will be rejected. + /// </summary> + [Fact] + public void EqualityComparer_ObjectFallback_UnsupportedType() + { + var eq = MessagePackSecurity.UntrustedData.GetEqualityComparer<object>(); + var ex = Assert.Throws<TypeAccessException>(() => eq.GetHashCode(new AggregateException())); + this.Logger.WriteLine(ex.ToString()); + } + + [Fact] + public void TypelessFormatterWithUntrustedData_SafeKeys() + { + var data = new + { + A = (byte)3, + B = new Dictionary<object, byte> + { + { "C", 15 }, + }, + D = new string[] { "E", "F" }, + }; + byte[] msgpack = MessagePackSerializer.Serialize(data); + var deserialized = (IDictionary<object, object>)MessagePackSerializer.Deserialize<object>(msgpack, MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData)); + Assert.Equal(data.A, deserialized["A"]); + Assert.Equal(data.B["C"], ((Dictionary<object, object>)deserialized["B"])["C"]); + Assert.Equal(data.D, deserialized["D"]); + } + + [Fact] + public void TypelessFormatterWithUntrustedData_UnsafeKeys() + { + var data = new + { + B = new Dictionary<object, byte> + { + { new ArbitraryType(), 15 }, + }, + }; + byte[] msgpack = MessagePackSerializer.Serialize(data); + var ex = Assert.Throws<MessagePackSerializationException>(() => MessagePackSerializer.Deserialize<object>(msgpack, MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData))); + Assert.IsType<TypeAccessException>(ex.InnerException); + this.Logger.WriteLine(ex.ToString()); + } + + [DataContract] + public class ArbitraryType + { + } +}
src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerOptionsTests.cs+42 −7 modified@@ -12,7 +12,8 @@ public class MessagePackSerializerOptionsTests .WithAllowAssemblyVersionMismatch(true) .WithOmitAssemblyVersion(true) .WithResolver(BuiltinResolver.Instance) - .WithOldSpec(false); + .WithOldSpec(false) + .WithSecurity(MySecurityOptions.Instance); [Fact] public void AllowAssemblyVersionMismatch() @@ -45,10 +46,17 @@ public void OldSpec() [Fact] public void Resolver() { - Assert.Same((object)StandardResolver.Instance, (object)MessagePackSerializerOptions.Standard.Resolver); + Assert.Same(StandardResolver.Instance, MessagePackSerializerOptions.Standard.Resolver); Assert.Same(BuiltinResolver.Instance, MessagePackSerializerOptions.Standard.WithResolver(BuiltinResolver.Instance).Resolver); } + [Fact] + public void Security() + { + Assert.Same(MessagePackSecurity.TrustedData, MessagePackSerializerOptions.Standard.Security); + Assert.Same(MessagePackSecurity.UntrustedData, MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData).Security); + } + [Fact] public void WithOldSpec_PreservesOtherProperties() { @@ -57,7 +65,8 @@ public void WithOldSpec_PreservesOtherProperties() Assert.Equal(NonDefaultOptions.Compression, mutated.Compression); Assert.Equal(NonDefaultOptions.AllowAssemblyVersionMismatch, mutated.AllowAssemblyVersionMismatch); Assert.Equal(NonDefaultOptions.OmitAssemblyVersion, mutated.OmitAssemblyVersion); - Assert.Same((object)NonDefaultOptions.Resolver, (object)mutated.Resolver); + Assert.Same(NonDefaultOptions.Resolver, mutated.Resolver); + Assert.Same(MySecurityOptions.Instance, mutated.Security); } [Fact] @@ -68,7 +77,8 @@ public void WithLZ4Compression_PreservesOtherProperties() Assert.Equal(NonDefaultOptions.OldSpec, mutated.OldSpec); Assert.Equal(NonDefaultOptions.AllowAssemblyVersionMismatch, mutated.AllowAssemblyVersionMismatch); Assert.Equal(NonDefaultOptions.OmitAssemblyVersion, mutated.OmitAssemblyVersion); - Assert.Same((object)NonDefaultOptions.Resolver, (object)mutated.Resolver); + Assert.Same(NonDefaultOptions.Resolver, mutated.Resolver); + Assert.Same(MySecurityOptions.Instance, mutated.Security); } [Fact] @@ -79,7 +89,8 @@ public void WithAllowAssemblyVersionMismatch_PreservesOtherProperties() Assert.Equal(NonDefaultOptions.Compression, mutated.Compression); Assert.Equal(NonDefaultOptions.OldSpec, mutated.OldSpec); Assert.Equal(NonDefaultOptions.OmitAssemblyVersion, mutated.OmitAssemblyVersion); - Assert.Same((object)NonDefaultOptions.Resolver, (object)mutated.Resolver); + Assert.Same(NonDefaultOptions.Resolver, mutated.Resolver); + Assert.Same(MySecurityOptions.Instance, mutated.Security); } [Fact] @@ -90,17 +101,41 @@ public void WithOmitAssemblyVersion_PreservesOtherProperties() Assert.Equal(NonDefaultOptions.Compression, mutated.Compression); Assert.Equal(NonDefaultOptions.OldSpec, mutated.OldSpec); Assert.Equal(NonDefaultOptions.AllowAssemblyVersionMismatch, mutated.AllowAssemblyVersionMismatch); - Assert.Same((object)NonDefaultOptions.Resolver, (object)mutated.Resolver); + Assert.Same(NonDefaultOptions.Resolver, mutated.Resolver); + Assert.Same(MySecurityOptions.Instance, mutated.Security); } [Fact] public void WithResolver_PreservesOtherProperties() { var mutated = NonDefaultOptions.WithResolver(ContractlessStandardResolver.Instance); - Assert.Same((object)ContractlessStandardResolver.Instance, (object)mutated.Resolver); + Assert.Same(ContractlessStandardResolver.Instance, mutated.Resolver); + Assert.Equal(NonDefaultOptions.Compression, mutated.Compression); + Assert.Equal(NonDefaultOptions.OldSpec, mutated.OldSpec); + Assert.Equal(NonDefaultOptions.AllowAssemblyVersionMismatch, mutated.AllowAssemblyVersionMismatch); + Assert.Equal(NonDefaultOptions.OmitAssemblyVersion, mutated.OmitAssemblyVersion); + Assert.Same(MySecurityOptions.Instance, mutated.Security); + } + + [Fact] + public void WithSecurity_PreservesOtherProperties() + { + var mutated = NonDefaultOptions.WithSecurity(MessagePackSecurity.TrustedData); + Assert.Same(MessagePackSecurity.TrustedData, mutated.Security); + Assert.Same(NonDefaultOptions.Resolver, mutated.Resolver); Assert.Equal(NonDefaultOptions.Compression, mutated.Compression); Assert.Equal(NonDefaultOptions.OldSpec, mutated.OldSpec); Assert.Equal(NonDefaultOptions.AllowAssemblyVersionMismatch, mutated.AllowAssemblyVersionMismatch); Assert.Equal(NonDefaultOptions.OmitAssemblyVersion, mutated.OmitAssemblyVersion); } + + private class MySecurityOptions : MessagePackSecurity + { + internal static readonly MySecurityOptions Instance = new MySecurityOptions(); + + private MySecurityOptions() + : base(TrustedData) + { + } + } }
src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs+122 −0 modified@@ -2,13 +2,17 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Buffers; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using MessagePack.Resolvers; using Microsoft; +using MsgPack.Serialization; using Nerdbank.Streams; using SharedData; using Xunit; @@ -200,6 +204,124 @@ public async Task SerializeAndDeserializeAsync_MultipleValues_SeekableStream(boo Assert.Equal(2, await MessagePackSerializer.DeserializeAsync<int>(stream)); Assert.Equal(3, await MessagePackSerializer.DeserializeAsync<int>(stream)); } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void StackDepthCheck_Arrays(bool convertToJson) + { + var (sequence, options) = StackDepthCheck_Helper((ref MessagePackWriter writer) => writer.WriteArrayHeader(1)); + if (convertToJson) + { + AssertConvertToJsonRecursionCheckThrows(sequence, options); + } + else + { + AssertDeserializationRecursionCheckThrows(sequence, options); + } + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void StackDepthCheck_Maps(bool convertToJson) + { + var (sequence, options) = StackDepthCheck_Helper((ref MessagePackWriter writer) => + { + writer.WriteMapHeader(1); + writer.Write(1); + }); + if (convertToJson) + { + AssertConvertToJsonRecursionCheckThrows(sequence, options); + } + else + { + AssertDeserializationRecursionCheckThrows(sequence, options); + } + } + + [Fact] + public void StackDepthCheck_DynamicObjectResolver() + { + var graph = new RecursiveObjectGraph + { + Child1 = new RecursiveObjectGraph + { + Child1 = new RecursiveObjectGraph { }, + }, + Child2 = new RecursiveObjectGraph + { + Child1 = new RecursiveObjectGraph { }, + }, + Child3 = new RecursiveObjectGraph + { + Child1 = new RecursiveObjectGraph { }, + }, + }; + byte[] msgpack = MessagePackSerializer.Serialize(graph, MessagePackSerializerOptions.Standard); + + var options = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumObjectGraphDepth(3)); + MessagePackSerializer.Deserialize<RecursiveObjectGraph>(msgpack, options); + + options = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumObjectGraphDepth(2)); + var ex = Assert.Throws<MessagePackSerializationException>(() => MessagePackSerializer.Deserialize<RecursiveObjectGraph>(msgpack, options)); + Assert.IsType<InsufficientExecutionStackException>(ex.InnerException); + } + + private delegate void WriterHelper(ref MessagePackWriter writer); + + private static (ReadOnlySequence<byte> Sequence, MessagePackSerializerOptions Options) StackDepthCheck_Helper(WriterHelper recursiveWriteOperation) + { + const int maxDepth = 3; + var options = MessagePackSerializerOptions.Standard + .WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumObjectGraphDepth(maxDepth)); + + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); + for (int i = 0; i <= maxDepth; i++) + { + recursiveWriteOperation(ref writer); + } + + writer.Write(1); + writer.Flush(); + + return (sequence.AsReadOnlySequence, options); + } + + private static void AssertDeserializationRecursionCheckThrows(ReadOnlySequence<byte> sequence, MessagePackSerializerOptions options) + { + var ex = Assert.Throws<MessagePackSerializationException>(() => + { + var reader = new MessagePackReader(sequence); + return MessagePackSerializer.Deserialize<object>(ref reader, options); + }); + Assert.IsType<InsufficientExecutionStackException>(ex.InnerException); + } + + private static void AssertConvertToJsonRecursionCheckThrows(ReadOnlySequence<byte> sequence, MessagePackSerializerOptions options) + { + var ex = Assert.Throws<MessagePackSerializationException>(() => + { + var reader = new MessagePackReader(sequence); + MessagePackSerializer.ConvertToJson(ref reader, new StringWriter(), options); + }); + Assert.IsType<InsufficientExecutionStackException>(ex.InnerException); + } + + [DataContract] + public class RecursiveObjectGraph + { + [DataMember] + public RecursiveObjectGraph Child1 { get; set; } + + [DataMember] + public RecursiveObjectGraph Child2 { get; set; } + + [DataMember] + public RecursiveObjectGraph Child3 { get; set; } + } } internal class StreamWrapper : Stream
tests/MessagePack.Tests/ExtensionTests/ImmutableCollectionTest.cs+19 −18 modified@@ -1,15 +1,8 @@ // Copyright (c) All contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using MessagePack.Formatters; -using MessagePack.ImmutableCollection; -using MessagePack.Resolvers; using Xunit; namespace MessagePack.Tests.ExtensionTests @@ -24,20 +17,28 @@ private T Convert<T>(T value) public static object[][] CollectionTestData = new object[][] { - new object[] { ImmutableList<int>.Empty.AddRange(new[] { 1, 10, 100 }), null }, - new object[] { ImmutableDictionary<int, int>.Empty.AddRange(new Dictionary<int, int> { { 1, 10 }, { 2, 10 }, { 3, 100 } }), null }, - new object[] { ImmutableHashSet<int>.Empty.Add(1).Add(10).Add(100), null }, - new object[] { ImmutableSortedDictionary<int, int>.Empty.AddRange(new Dictionary<int, int> { { 1, 10 }, { 2, 10 }, { 3, 100 } }), null }, - new object[] { ImmutableSortedSet<int>.Empty.Add(1).Add(10).Add(100), null }, - new object[] { ImmutableQueue<int>.Empty.Enqueue(1).Enqueue(10).Enqueue(100), null }, - new object[] { ImmutableStack<int>.Empty.Push(1).Push(10).Push(100), null }, + new object[] { true, ImmutableList<int>.Empty.AddRange(new[] { 1, 10, 100 }), null }, + new object[] { false, ImmutableDictionary<int, int>.Empty.AddRange(new Dictionary<int, int> { { 1, 10 }, { 2, 10 }, { 3, 100 } }), null }, + new object[] { false, ImmutableHashSet<int>.Empty.Add(1).Add(10).Add(100), null }, + new object[] { true, ImmutableSortedDictionary<int, int>.Empty.AddRange(new Dictionary<int, int> { { 1, 10 }, { 2, 10 }, { 3, 100 } }), null }, + new object[] { true, ImmutableSortedSet<int>.Empty.Add(1).Add(10).Add(100), null }, + new object[] { true, ImmutableQueue<int>.Empty.Enqueue(1).Enqueue(10).Enqueue(100), null }, + new object[] { true, ImmutableStack<int>.Empty.Push(1).Push(10).Push(100), null }, }; [Theory] [MemberData(nameof(CollectionTestData))] - public void ConcreteCollectionTest<T>(T x, T y) + public void ConcreteCollectionTest<T>(bool ordered, T x, T y) { - this.Convert(x).IsStructuralEqual(x); + if (ordered) + { + this.Convert(x).IsStructuralEqual(x); + } + else + { + this.Convert(x).IsStructuralEqualIgnoreCollectionOrder(x); + } + this.Convert(y).IsStructuralEqual(y); } @@ -51,8 +52,8 @@ public void InterfaceCollectionTest() IImmutableStack<int> e = ImmutableStack<int>.Empty.Push(1).Push(10).Push(100); this.Convert(a).IsStructuralEqual(a); - this.Convert(b).IsStructuralEqual(b); - this.Convert(c).IsStructuralEqual(c); + this.Convert(b).IsStructuralEqualIgnoreCollectionOrder(b); + this.Convert(c).IsStructuralEqualIgnoreCollectionOrder(c); this.Convert(d).IsStructuralEqual(d); this.Convert(e).IsStructuralEqual(e);
tests/MessagePack.Tests/Utils/ChainingAssertion.Xunit.cs+40 −0 modified@@ -366,6 +366,46 @@ public ReflectAccessor(T target, string name) #region StructuralEqual + public static void IsStructuralEqualIgnoreCollectionOrder(this object actual, object expected) + { + if (object.ReferenceEquals(actual, expected)) + { + return; + } + + if (actual == null) + { + throw new AssertException("actual is null"); + } + + if (expected == null) + { + throw new AssertException("actual is not null"); + } + + Assert.Equal(expected.GetType(), actual.GetType()); + + var actualCollection = (ICollection)actual; + var expectedCollection = (ICollection)expected; + + Assert.Equal(expectedCollection.Count, actualCollection.Count); + var names = new[] { actual.GetType().Name }; + foreach (var expectedEntry in expectedCollection) + { + bool matchFound = false; + foreach (var actualEntry in actualCollection) + { + if (StructuralEqual(actualEntry, expectedEntry, names).IsEquals) + { + matchFound = true; + break; + } + } + + Assert.True(matchFound); + } + } + /// <summary>Assert by deep recursive value equality compare.</summary> public static void IsStructuralEqual(this object actual, object expected, string message = "") {
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-7q36-4xx7-xcxfghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-5234ghsaADVISORY
- github.com/MessagePack-CSharp/MessagePack-CSharp/security/advisories/GHSA-7q36-4xx7-xcxfghsaWEB
- github.com/aspnet/Announcements/issues/405ghsaWEB
- github.com/neuecc/MessagePack-CSharp/commit/56fa86219d01d0a183babbbbcb34abbdea588a02ghsax_refsource_MISCWEB
- github.com/neuecc/MessagePack-CSharp/commit/f88684078698386df02204f13faeff098a61f007ghsax_refsource_MISCWEB
- github.com/neuecc/MessagePack-CSharp/issues/810ghsax_refsource_MISCWEB
- github.com/neuecc/MessagePack-CSharp/security/advisories/GHSA-7q36-4xx7-xcxfghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.