Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/libraries/System.Text.Json/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -506,4 +506,7 @@
<data name="BufferMaximumSizeExceeded" xml:space="preserve">
<value>Cannot allocate a buffer of size {0}.</value>
</data>
<data name="SerializeTypeInstanceNotSupported" xml:space="preserve">
<value>Serialization and deserialization of 'System.Type' instances are not supported and should be avoided since they can lead to security issues.</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/libraries/System.Text.Json/src/System.Text.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
<Compile Include="System\Text\Json\Serialization\Converters\Value\SByteConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\SingleConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\StringConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\TypeConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\UInt16Converter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\UInt32Converter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\UInt64Converter.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.

namespace System.Text.Json.Serialization.Converters
{
internal sealed class TypeConverter : JsonConverter<Type>
{
public override Type Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotSupportedException(SR.SerializeTypeInstanceNotSupported);
}

public override void Write(Utf8JsonWriter writer, Type value, JsonSerializerOptions options)
{
throw new NotSupportedException(SR.SerializeTypeInstanceNotSupported);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public sealed partial class JsonSerializerOptions

private static Dictionary<Type, JsonConverter> GetDefaultSimpleConverters()
{
const int NumberOfSimpleConverters = 21;
const int NumberOfSimpleConverters = 22;
var converters = new Dictionary<Type, JsonConverter>(NumberOfSimpleConverters);

// Use a dictionary for simple converters.
Expand All @@ -59,6 +59,7 @@ private static Dictionary<Type, JsonConverter> GetDefaultSimpleConverters()
Add(new SByteConverter());
Add(new SingleConverter());
Add(new StringConverter());
Add(new TypeConverter());
Add(new UInt16Converter());
Add(new UInt32Converter());
Add(new UInt64Converter());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static void ThrowNotSupportedException_SerializationNotSupported(Type pro

[DoesNotReturn]
[MethodImpl(MethodImplOptions.NoInlining)]
public static NotSupportedException ThrowNotSupportedException_ConstructorMaxOf64Parameters(ConstructorInfo constructorInfo, Type type)
public static void ThrowNotSupportedException_ConstructorMaxOf64Parameters(ConstructorInfo constructorInfo, Type type)
{
throw new NotSupportedException(SR.Format(SR.ConstructorMaxOf64Parameters, constructorInfo, type));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,5 +526,58 @@ public static void UnsupportedTypeFromRoot()
// Root-level Types (not from a property) do not include the Path.
Assert.DoesNotContain("Path: $", ex.Message);
}

[Fact]
public static void DeserializeTypeInstance()
{
string json = @"""System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e""";

NotSupportedException ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<Type>(json));
string exAsStr = ex.ToString();
Assert.Contains("System.Type", exAsStr);
Assert.Contains("$", exAsStr);

json = $@"{{""Type"":{json}}}";

ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ClassWithType>(json));
exAsStr = ex.ToString();
Assert.Contains("System.Type", exAsStr);
Assert.Contains("$.Type", exAsStr);

// NSE is not thrown because the serializer handles null.
Assert.Null(JsonSerializer.Deserialize<Type>("null"));

ClassWithType obj = JsonSerializer.Deserialize<ClassWithType>(@"{""Type"":null}");
Assert.Null(obj.Type);
}

[Fact]
public static void SerializeTypeInstance()
{
Type type = typeof(int);

NotSupportedException ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(type));
string exAsStr = ex.ToString();
Assert.Contains("System.Type", exAsStr);
Assert.Contains("$", exAsStr);

type = null;
string serialized = JsonSerializer.Serialize(type);
Assert.Equal("null", serialized);

ClassWithType obj = new ClassWithType { Type = typeof(int) };

ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(obj));
exAsStr = ex.ToString();
Assert.Contains("System.Type", exAsStr);
Assert.Contains("$.Type", exAsStr);

obj.Type = null;
serialized = JsonSerializer.Serialize(obj);
Assert.Equal(@"{""Type"":null}", serialized);

serialized = JsonSerializer.Serialize(obj, new JsonSerializerOptions { IgnoreNullValues = true });
Assert.Equal(@"{}", serialized);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1853,4 +1853,9 @@ public void Verify()
MyData.Verify();
}
}

public class ClassWithType
{
public Type Type { get; set; }
}
}