Prevent concurrent use of YAML serializer / deserializer (#1544)

YamlDotNet ISerializer and IDeserializer are not thread-safe
This commit is contained in:
Alex Mitchell
2024-04-06 16:37:27 +10:30
committed by GitHub
parent d523291d1a
commit 7dad2f31a8

View File

@@ -12,6 +12,9 @@ namespace k8s
/// </summary> /// </summary>
public static class KubernetesYaml public static class KubernetesYaml
{ {
private static readonly object DeserializerLockObject = new object();
private static readonly object SerializerLockObject = new object();
private static DeserializerBuilder CommonDeserializerBuilder => private static DeserializerBuilder CommonDeserializerBuilder =>
new DeserializerBuilder() new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance) .WithNamingConvention(CamelCaseNamingConvention.Instance)
@@ -155,10 +158,13 @@ namespace k8s
var parser = new MergingParser(new Parser(new StringReader(content))); var parser = new MergingParser(new Parser(new StringReader(content)));
parser.Consume<StreamStart>(); parser.Consume<StreamStart>();
while (parser.Accept<DocumentStart>(out _)) while (parser.Accept<DocumentStart>(out _))
{
lock (DeserializerLockObject)
{ {
var dict = GetDeserializer(strict).Deserialize<Dictionary<object, object>>(parser); var dict = GetDeserializer(strict).Deserialize<Dictionary<object, object>>(parser);
types.Add(mergedTypeMap[dict["apiVersion"] + "/" + dict["kind"]]); types.Add(mergedTypeMap[dict["apiVersion"] + "/" + dict["kind"]]);
} }
}
parser = new MergingParser(new Parser(new StringReader(content))); parser = new MergingParser(new Parser(new StringReader(content)));
parser.Consume<StreamStart>(); parser.Consume<StreamStart>();
@@ -167,9 +173,12 @@ namespace k8s
while (parser.Accept<DocumentStart>(out _)) while (parser.Accept<DocumentStart>(out _))
{ {
var objType = types[ix++]; var objType = types[ix++];
lock (DeserializerLockObject)
{
var obj = GetDeserializer(strict).Deserialize(parser, objType); var obj = GetDeserializer(strict).Deserialize(parser, objType);
results.Add(obj); results.Add(obj);
} }
}
return results; return results;
} }
@@ -204,14 +213,20 @@ namespace k8s
public static TValue Deserialize<TValue>(string yaml, bool strict = false) public static TValue Deserialize<TValue>(string yaml, bool strict = false)
{ {
using var reader = new StringReader(yaml); using var reader = new StringReader(yaml);
lock (DeserializerLockObject)
{
return GetDeserializer(strict).Deserialize<TValue>(new MergingParser(new Parser(reader))); return GetDeserializer(strict).Deserialize<TValue>(new MergingParser(new Parser(reader)));
} }
}
public static TValue Deserialize<TValue>(Stream yaml, bool strict = false) public static TValue Deserialize<TValue>(Stream yaml, bool strict = false)
{ {
using var reader = new StreamReader(yaml); using var reader = new StreamReader(yaml);
lock (DeserializerLockObject)
{
return GetDeserializer(strict).Deserialize<TValue>(new MergingParser(new Parser(reader))); return GetDeserializer(strict).Deserialize<TValue>(new MergingParser(new Parser(reader)));
} }
}
public static string SerializeAll(IEnumerable<object> values) public static string SerializeAll(IEnumerable<object> values)
{ {
@@ -231,7 +246,11 @@ namespace k8s
if (value != null) if (value != null)
{ {
emitter.Emit(new DocumentStart()); emitter.Emit(new DocumentStart());
lock (SerializerLockObject)
{
Serializer.SerializeValue(emitter, value, value.GetType()); Serializer.SerializeValue(emitter, value, value.GetType());
}
emitter.Emit(new DocumentEnd(true)); emitter.Emit(new DocumentEnd(true));
} }
} }
@@ -252,7 +271,10 @@ namespace k8s
emitter.Emit(new StreamStart()); emitter.Emit(new StreamStart());
emitter.Emit(new DocumentStart()); emitter.Emit(new DocumentStart());
lock (SerializerLockObject)
{
Serializer.SerializeValue(emitter, value, value.GetType()); Serializer.SerializeValue(emitter, value, value.GetType());
}
return stringBuilder.ToString(); return stringBuilder.ToString();
} }