From 3a5cf9906609322648dedf8c92e5e0f81ac6e3f3 Mon Sep 17 00:00:00 2001 From: DaveBlack Date: Tue, 29 Aug 2023 16:46:16 -0500 Subject: [PATCH 1/2] - fix race condition on static dictionaries, copy recent code from LitJson --- sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs | 135 +++++++++++------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs b/sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs index 56e50ff1..3a4afce6 100644 --- a/sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs +++ b/sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs @@ -101,33 +101,35 @@ public IDictionary Properties { public class JsonMapper { #region Fields - private static int max_nesting_depth; + private static readonly int max_nesting_depth; - private static IFormatProvider datetime_format; + private static readonly IFormatProvider datetime_format; - private static IDictionary base_exporters_table; - private static IDictionary custom_exporters_table; + private static readonly IDictionary base_exporters_table; + private static readonly IDictionary custom_exporters_table; + private static readonly object custom_exporters_table_lock = new Object(); - private static IDictionary> base_importers_table; - private static IDictionary> custom_importers_table; + private static readonly object custom_importers_table_lock = new Object(); - private static IDictionary array_metadata; + private static readonly IDictionary array_metadata; private static readonly object array_metadata_lock = new Object (); - private static IDictionary> conv_ops; private static readonly object conv_ops_lock = new Object (); - private static IDictionary object_metadata; + private static readonly IDictionary object_metadata; private static readonly object object_metadata_lock = new Object (); - private static IDictionary> type_properties; private static readonly object type_properties_lock = new Object (); - private static JsonWriter static_writer; + private static readonly JsonWriter static_writer; private static readonly object static_writer_lock = new Object (); #endregion @@ -337,25 +339,19 @@ private static object ReadValue (Type inst_type, JsonReader reader) return reader.Value; // If there's a custom importer that fits, use it - if (custom_importers_table.ContainsKey (json_type) && - custom_importers_table[json_type].ContainsKey ( - value_type)) { + lock (custom_importers_table_lock) { + if (custom_importers_table.TryGetValue(json_type, out IDictionary customImporterTablesValue) && + customImporterTablesValue.TryGetValue(value_type, out ImporterFunc customImporter)) { - ImporterFunc importer = - custom_importers_table[json_type][value_type]; - - return importer (reader.Value); + return customImporter(reader.Value); + } } // Maybe there's a base importer that works - if (base_importers_table.ContainsKey (json_type) && - base_importers_table[json_type].ContainsKey ( - value_type)) { + if (base_importers_table.TryGetValue(json_type, out IDictionary baseImporterTablesValue) && + baseImporterTablesValue.TryGetValue(value_type, out ImporterFunc baseImporter)) { - ImporterFunc importer = - base_importers_table[json_type][value_type]; - - return importer (reader.Value); + return baseImporter(reader.Value); } // Maybe it's an enum @@ -550,8 +546,10 @@ private static void ReadSkip (JsonReader reader) private static void RegisterBaseExporters () { + // This method is only called from the static initializer, + // so there is no need to explicitly lock any static members here base_exporters_table[typeof (byte)] = - delegate (object obj, JsonWriter writer) { + delegate (object obj, JsonWriter writer) { writer.Write (Convert.ToInt32 ((byte) obj)); }; @@ -595,10 +593,17 @@ private static void RegisterBaseExporters () delegate (object obj, JsonWriter writer) { writer.Write ((ulong) obj); }; + + base_exporters_table[typeof(DateTimeOffset)] = + delegate (object obj, JsonWriter writer) { + writer.Write(((DateTimeOffset)obj).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", datetime_format)); + }; } private static void RegisterBaseImporters () { + // This method is only called from the static initializer, + // so there is no need to explicitly lock any static members here ImporterFunc importer; importer = delegate (object input) { @@ -613,6 +618,12 @@ private static void RegisterBaseImporters () RegisterImporter (base_importers_table, typeof (int), typeof (ulong), importer); + importer = delegate (object input) { + return Convert.ToInt64((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(long), importer); + importer = delegate (object input) { return Convert.ToSByte ((int) input); }; @@ -655,6 +666,11 @@ private static void RegisterBaseImporters () RegisterImporter (base_importers_table, typeof (double), typeof (decimal), importer); + importer = delegate (object input) { + return Convert.ToSingle((double)input); + }; + RegisterImporter(base_importers_table, typeof(double), + typeof(float), importer); importer = delegate (object input) { return Convert.ToUInt32 ((long) input); @@ -673,6 +689,12 @@ private static void RegisterBaseImporters () }; RegisterImporter (base_importers_table, typeof (string), typeof (DateTime), importer); + + importer = delegate (object input) { + return DateTimeOffset.Parse((string)input, datetime_format); + }; + RegisterImporter(base_importers_table, typeof(string), + typeof(DateTimeOffset), importer); } private static void RegisterImporter ( @@ -719,6 +741,11 @@ private static void WriteValue (object obj, JsonWriter writer, return; } + if (obj is Single) { + writer.Write((float)obj); + return; + } + if (obj is Int32) { writer.Write ((int) obj); return; @@ -775,29 +802,17 @@ private static void WriteValue (object obj, JsonWriter writer, Type obj_type = obj.GetType (); // See if there's a custom exporter for the object - if (custom_exporters_table.ContainsKey (obj_type)) { - ExporterFunc exporter = custom_exporters_table[obj_type]; - exporter (obj, writer); - - return; - } - - // See if there's a custom exporter for the base class of the object - foreach (var type in custom_exporters_table.Keys) - { - if (obj_type.IsSubclassOf(type)) - { - ExporterFunc exporter = custom_exporters_table[type]; - exporter(obj, writer); + lock (custom_exporters_table_lock) { + if (custom_exporters_table.TryGetValue(obj_type, out ExporterFunc customExporter)) { + customExporter(obj, writer); return; } } // If not, maybe there's a base exporter - if (base_exporters_table.ContainsKey (obj_type)) { - ExporterFunc exporter = base_exporters_table[obj_type]; - exporter (obj, writer); + if (base_exporters_table.TryGetValue(obj_type, out ExporterFunc baseExporter)) { + baseExporter(obj, writer); return; } @@ -806,10 +821,20 @@ private static void WriteValue (object obj, JsonWriter writer, if (obj is Enum) { Type e_type = Enum.GetUnderlyingType (obj_type); - if (e_type == typeof (long) - || e_type == typeof (uint) - || e_type == typeof (ulong)) + if (e_type == typeof (long)) + writer.Write ((long) obj); + else if (e_type == typeof (uint)) + writer.Write ((uint) obj); + else if (e_type == typeof (ulong)) writer.Write ((ulong) obj); + else if (e_type == typeof(ushort)) + writer.Write ((ushort)obj); + else if (e_type == typeof(short)) + writer.Write ((short)obj); + else if (e_type == typeof(byte)) + writer.Write ((byte)obj); + else if (e_type == typeof(sbyte)) + writer.Write ((sbyte)obj); else writer.Write ((int) obj); @@ -919,7 +944,9 @@ public static void RegisterExporter (ExporterFunc exporter) exporter ((T) obj, writer); }; - custom_exporters_table[typeof (T)] = exporter_wrapper; + lock (custom_exporters_table_lock) { + custom_exporters_table[typeof (T)] = exporter_wrapper; + } } public static void RegisterImporter ( @@ -930,18 +957,24 @@ public static void RegisterImporter ( return importer ((TJson) input); }; - RegisterImporter (custom_importers_table, typeof (TJson), - typeof (TValue), importer_wrapper); + lock (custom_importers_table_lock) { + RegisterImporter (custom_importers_table, typeof (TJson), + typeof (TValue), importer_wrapper); + } } public static void UnregisterExporters () { - custom_exporters_table.Clear (); + lock (custom_exporters_table_lock) { + custom_exporters_table.Clear(); + } } public static void UnregisterImporters () { - custom_importers_table.Clear (); + lock (custom_importers_table_lock) { + custom_importers_table.Clear(); + } } } } From 8f269322b24809be0374b82b9774d52188162218 Mon Sep 17 00:00:00 2001 From: jjllee Date: Mon, 10 Jun 2024 17:58:09 -0700 Subject: [PATCH 2/2] revert some incomplete synced code, restore deleted code that checks custom exporter for base class of object --- sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs | 83 +++++++------------ 1 file changed, 30 insertions(+), 53 deletions(-) diff --git a/sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs b/sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs index 3a4afce6..3dd20b82 100644 --- a/sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs +++ b/sdk/src/Core/ThirdParty/LitJson/JsonMapper.cs @@ -101,35 +101,35 @@ public IDictionary Properties { public class JsonMapper { #region Fields - private static readonly int max_nesting_depth; + private static int max_nesting_depth; - private static readonly IFormatProvider datetime_format; + private static IFormatProvider datetime_format; - private static readonly IDictionary base_exporters_table; - private static readonly IDictionary custom_exporters_table; + private static IDictionary base_exporters_table; + private static IDictionary custom_exporters_table; private static readonly object custom_exporters_table_lock = new Object(); - private static readonly IDictionary> base_importers_table; - private static readonly IDictionary> custom_importers_table; private static readonly object custom_importers_table_lock = new Object(); - private static readonly IDictionary array_metadata; + private static IDictionary array_metadata; private static readonly object array_metadata_lock = new Object (); - private static readonly IDictionary> conv_ops; private static readonly object conv_ops_lock = new Object (); - private static readonly IDictionary object_metadata; + private static IDictionary object_metadata; private static readonly object object_metadata_lock = new Object (); - private static readonly IDictionary> type_properties; private static readonly object type_properties_lock = new Object (); - private static readonly JsonWriter static_writer; + private static JsonWriter static_writer; private static readonly object static_writer_lock = new Object (); #endregion @@ -549,7 +549,7 @@ private static void RegisterBaseExporters () // This method is only called from the static initializer, // so there is no need to explicitly lock any static members here base_exporters_table[typeof (byte)] = - delegate (object obj, JsonWriter writer) { + delegate (object obj, JsonWriter writer) { writer.Write (Convert.ToInt32 ((byte) obj)); }; @@ -593,11 +593,6 @@ private static void RegisterBaseExporters () delegate (object obj, JsonWriter writer) { writer.Write ((ulong) obj); }; - - base_exporters_table[typeof(DateTimeOffset)] = - delegate (object obj, JsonWriter writer) { - writer.Write(((DateTimeOffset)obj).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", datetime_format)); - }; } private static void RegisterBaseImporters () @@ -618,12 +613,6 @@ private static void RegisterBaseImporters () RegisterImporter (base_importers_table, typeof (int), typeof (ulong), importer); - importer = delegate (object input) { - return Convert.ToInt64((int)input); - }; - RegisterImporter(base_importers_table, typeof(int), - typeof(long), importer); - importer = delegate (object input) { return Convert.ToSByte ((int) input); }; @@ -666,11 +655,6 @@ private static void RegisterBaseImporters () RegisterImporter (base_importers_table, typeof (double), typeof (decimal), importer); - importer = delegate (object input) { - return Convert.ToSingle((double)input); - }; - RegisterImporter(base_importers_table, typeof(double), - typeof(float), importer); importer = delegate (object input) { return Convert.ToUInt32 ((long) input); @@ -689,12 +673,6 @@ private static void RegisterBaseImporters () }; RegisterImporter (base_importers_table, typeof (string), typeof (DateTime), importer); - - importer = delegate (object input) { - return DateTimeOffset.Parse((string)input, datetime_format); - }; - RegisterImporter(base_importers_table, typeof(string), - typeof(DateTimeOffset), importer); } private static void RegisterImporter ( @@ -741,11 +719,6 @@ private static void WriteValue (object obj, JsonWriter writer, return; } - if (obj is Single) { - writer.Write((float)obj); - return; - } - if (obj is Int32) { writer.Write ((int) obj); return; @@ -810,6 +783,20 @@ private static void WriteValue (object obj, JsonWriter writer, } } + // See if there's a custom exporter for the base class of the object + lock (custom_exporters_table_lock) { + foreach (var type in custom_exporters_table.Keys) + { + if (obj_type.IsSubclassOf(type)) + { + ExporterFunc exporter = custom_exporters_table[type]; + exporter(obj, writer); + + return; + } + } + } + // If not, maybe there's a base exporter if (base_exporters_table.TryGetValue(obj_type, out ExporterFunc baseExporter)) { baseExporter(obj, writer); @@ -821,20 +808,10 @@ private static void WriteValue (object obj, JsonWriter writer, if (obj is Enum) { Type e_type = Enum.GetUnderlyingType (obj_type); - if (e_type == typeof (long)) - writer.Write ((long) obj); - else if (e_type == typeof (uint)) - writer.Write ((uint) obj); - else if (e_type == typeof (ulong)) + if (e_type == typeof (long) + || e_type == typeof (uint) + || e_type == typeof (ulong)) writer.Write ((ulong) obj); - else if (e_type == typeof(ushort)) - writer.Write ((ushort)obj); - else if (e_type == typeof(short)) - writer.Write ((short)obj); - else if (e_type == typeof(byte)) - writer.Write ((byte)obj); - else if (e_type == typeof(sbyte)) - writer.Write ((sbyte)obj); else writer.Write ((int) obj); @@ -944,7 +921,7 @@ public static void RegisterExporter (ExporterFunc exporter) exporter ((T) obj, writer); }; - lock (custom_exporters_table_lock) { + lock (custom_exporters_table_lock) { custom_exporters_table[typeof (T)] = exporter_wrapper; } }