From 1ac29b094646572b1b21fff17a61fef1942bc819 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Fri, 11 Mar 2022 11:08:50 -0800 Subject: [PATCH 1/2] Ensure serializer reflection-dependency sentinel is accurate --- .../Serialization/JsonSerializerOptions.Converters.cs | 8 ++++++-- .../Text/Json/Serialization/JsonSerializerOptions.cs | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs index 91264247bc9539..0fc63c3a1e4c40 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs @@ -9,6 +9,7 @@ using System.Text.Json.Serialization; using System.Text.Json.Serialization.Converters; using System.Text.Json.Serialization.Metadata; +using System.Threading; namespace System.Text.Json { @@ -29,11 +30,14 @@ public sealed partial class JsonSerializerOptions [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] private static void RootReflectionSerializerDependencies() { - if (s_defaultSimpleConverters is null) + // s_typeInfoCreationFunc is the last field assigned. + // Use it as the sentinel to ensure that all dependencies are initialized. + if (s_typeInfoCreationFunc is null) { s_defaultSimpleConverters = GetDefaultSimpleConverters(); s_defaultFactoryConverters = GetDefaultFactoryConverters(); - s_typeInfoCreationFunc = CreateJsonTypeInfo; + // Explicitly ensure that the previous fields are initialized along with this one. + Volatile.Write(ref s_typeInfoCreationFunc, CreateJsonTypeInfo); } [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 95199d7ead9c54..12b77387a1c653 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -610,7 +610,9 @@ private JsonTypeInfo GetJsonTypeInfoFromContextOrCreate(Type type) return null!; } - Debug.Assert(s_typeInfoCreationFunc != null); + Debug.Assert( + s_typeInfoCreationFunc != null, + "Reflection-based JsonTypeInfo creator should be initialized if IsInitializedForReflectionSerializer is true."); return s_typeInfoCreationFunc(type, this); } From 8547ab394ef08b1576bfa9a3e7b45bcc57b70e51 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Mon, 14 Mar 2022 11:54:01 -0700 Subject: [PATCH 2/2] Address feedback --- .../Json/Serialization/JsonSerializerOptions.Converters.cs | 2 +- .../System/Text/Json/Serialization/JsonSerializerOptions.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs index 0fc63c3a1e4c40..478029174db339 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs @@ -32,7 +32,7 @@ private static void RootReflectionSerializerDependencies() { // s_typeInfoCreationFunc is the last field assigned. // Use it as the sentinel to ensure that all dependencies are initialized. - if (s_typeInfoCreationFunc is null) + if (Volatile.Read(ref s_typeInfoCreationFunc) is null) { s_defaultSimpleConverters = GetDefaultSimpleConverters(); s_defaultFactoryConverters = GetDefaultFactoryConverters(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 12b77387a1c653..8837b55dcf5da5 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -9,6 +9,7 @@ using System.Text.Json.Nodes; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; +using System.Threading; namespace System.Text.Json { @@ -579,7 +580,7 @@ internal MemberAccessor MemberAccessorStrategy /// /// Whether the options instance has been primed for reflection-based serialization. /// - internal bool IsInitializedForReflectionSerializer { get; private set; } + internal bool IsInitializedForReflectionSerializer; /// /// Initializes the converters for the reflection-based serializer. @@ -589,7 +590,7 @@ internal MemberAccessor MemberAccessorStrategy internal void InitializeForReflectionSerializer() { RootReflectionSerializerDependencies(); - IsInitializedForReflectionSerializer = true; + Volatile.Write(ref IsInitializedForReflectionSerializer, true); if (_cachingContext != null) { _cachingContext.Options.IsInitializedForReflectionSerializer = true;