From 217b24253133651410dff60acc64d285cc0b3739 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Mon, 8 Mar 2021 15:25:39 -0800 Subject: [PATCH 01/19] Prohibit BF unless the app opts in --- docs/workflow/trimming/feature-switches.md | 1 + .../src/ILLink/ILLink.Substitutions.xml | 7 + .../src/ILLink/ILLink.Suppressions.xml | 12 ++ .../src/Resources/Strings.resx | 3 + ...System.ComponentModel.TypeConverter.csproj | 3 + .../DesigntimeLicenseContextSerializer.cs | 185 ++++++++++++++++-- ...DesigntimeLicenseContextSerializerTests.cs | 115 +++++++++++ ....ComponentModel.TypeConverter.Tests.csproj | 1 + 8 files changed, 316 insertions(+), 11 deletions(-) create mode 100644 src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Substitutions.xml create mode 100644 src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs diff --git a/docs/workflow/trimming/feature-switches.md b/docs/workflow/trimming/feature-switches.md index 40971d1fdb9df5..36ac156f4f86be 100644 --- a/docs/workflow/trimming/feature-switches.md +++ b/docs/workflow/trimming/feature-switches.md @@ -19,6 +19,7 @@ configurations but their defaults might vary as any SDK can set the defaults dif | StartupHookSupport | System.StartupHookProvider.IsSupported | Startup hooks are disabled when set to false. Startup hook related functionality can be trimmed. | | TBD | System.Threading.ThreadPool.EnableDispatchAutoreleasePool | When set to true, creates an NSAutoreleasePool around each thread pool work item on applicable platforms. | | CustomResourceTypesSupport | System.Resources.ResourceManager.AllowCustomResourceTypes | Use of custom resource types is disabled when set to false. ResourceManager code paths that use reflection for custom types can be trimmed. | +| EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization | System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization | BinaryFormatter serialization support is trimmed when set to false. | Any feature-switch which defines property can be set in csproj file or on the command line as any other MSBuild property. Those without predefined property name diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Substitutions.xml b/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Substitutions.xml new file mode 100644 index 00000000000000..d5df6acfa1cbc4 --- /dev/null +++ b/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Substitutions.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.xml index 9a250687a3b2ac..cddfb1ce1a8f56 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.xml +++ b/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.xml @@ -19,5 +19,17 @@ member M:System.ComponentModel.MaskedTextProvider.Clone + + ILLink + IL2026 + member + M:System.ComponentModel.Design.DesigntimeLicenseContextSerializer.SerializeWithBinaryFormatter(System.IO.Stream,System.String,System.ComponentModel.Design.DesigntimeLicenseContext) + + + ILLink + IL2026 + member + M:System.ComponentModel.Design.DesigntimeLicenseContextSerializer.DeserializeUsingBinaryFormatter(System.ComponentModel.Design.DesigntimeLicenseContextSerializer.StreamWrapper,System.String,System.ComponentModel.Design.RuntimeLicenseContext) + diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx b/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx index 7de9810d591ed2..42938cccdd3ff2 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx +++ b/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx @@ -250,4 +250,7 @@ Relationships between {0}.{1} and {2}.{3} are not supported. + + Enable {0} as an AppContextSwitch to use BinaryFormatter to deserealize a stream + \ No newline at end of file diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj b/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj index 7319c74b19b825..a93c8e4aadc9da 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj @@ -4,6 +4,9 @@ true $(NetCoreAppCurrent) + + + diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs index c4e7c24165e779..941d93aef49afe 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs @@ -5,7 +5,7 @@ using System.Runtime.Serialization; using System.Collections; using System.IO; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; namespace System.ComponentModel.Design { @@ -14,6 +14,19 @@ namespace System.ComponentModel.Design /// public class DesigntimeLicenseContextSerializer { + internal const string s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = "System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization"; + private const string s_enableBinaryFormatter = "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization"; + + private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization + { + get => AppContext.TryGetSwitch(s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, out bool isEnabled) ? isEnabled : false; + } + + private static bool BinaryFormatterSerializationEnabled + { + get => AppContext.TryGetSwitch(s_enableBinaryFormatter, out bool isEnabled) ? isEnabled : false; + } + // Not creatable. private DesigntimeLicenseContextSerializer() { @@ -25,25 +38,175 @@ private DesigntimeLicenseContextSerializer() /// public static void Serialize(Stream o, string cryptoKey, DesigntimeLicenseContext context) { - IFormatter formatter = new BinaryFormatter(); -#pragma warning disable SYSLIB0011 // Issue https://github.com/dotnet/runtime/issues/39293 tracks finding an alternative to BinaryFormatter - formatter.Serialize(o, new object[] { cryptoKey, context._savedLicenseKeys }); + if (EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization) + { + SerializeWithBinaryFormatter(o, cryptoKey, context); + } + else + { + using (BinaryWriter writer = new BinaryWriter(o, encoding: Text.Encoding.UTF8, leaveOpen: true)) + { + writer.Write((sbyte)-1); // flag to identify BinaryWriter + writer.Write(cryptoKey); + writer.Write(context._savedLicenseKeys.Count); + foreach (DictionaryEntry keyAndValue in context._savedLicenseKeys) + { + writer.Write(keyAndValue.Key.ToString()); + writer.Write(keyAndValue.Value.ToString()); + } + } + } + } + + private static void SerializeWithBinaryFormatter(Stream o, string cryptoKey, DesigntimeLicenseContext context) + { + try + { + IFormatter formatter = new BinaryFormatter(); +#pragma warning disable SYSLIB0011 + formatter.Serialize(o, new object[] { cryptoKey, context._savedLicenseKeys }); #pragma warning restore SYSLIB0011 + } + catch (NotSupportedException exception) + { + if (!BinaryFormatterSerializationEnabled) + { + throw new NotSupportedException(exception.Message + " Turn on the EnableUnsafeBinaryFormatterSerialization flag to continue using BinaryFormatter"); + } + else + { + throw; + } + } } - internal static void Deserialize(Stream o, string cryptoKey, RuntimeLicenseContext context) + internal class StreamWrapper : Stream { -#pragma warning disable SYSLIB0011 // Issue https://github.com/dotnet/runtime/issues/39293 tracks finding an alternative to BinaryFormatter - IFormatter formatter = new BinaryFormatter(); + private Stream _stream; + internal bool readFirstByte; + internal byte firstByte; + public StreamWrapper(Stream stream) + { + _stream = stream; + readFirstByte = false; + firstByte = 0; + } - object obj = formatter.Deserialize(o); + public override bool CanRead => _stream.CanRead; + + public override bool CanSeek => _stream.CanSeek; + + public override bool CanWrite => _stream.CanWrite; + + public override long Length => _stream.Length; + + public override long Position { get => _stream.Position; set => _stream.Position = value; } + + public override void Flush() => _stream.Flush(); + + public override int Read(byte[] buffer, int offset, int count) + { + Debug.Assert(_stream.Position != 0, "Expected the first byte to be read first"); + if (_stream.Position == 1) + { + Debug.Assert(readFirstByte == true); + // Add the first byte read by ReadByte into buffer here + buffer[0] = firstByte; + return _stream.Read(buffer, offset + 1, count - 1) + 1; + } + return _stream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) => _stream.Seek(offset, origin); + + public override void SetLength(long value) => _stream.SetLength(value); + + public override void Write(byte[] buffer, int offset, int count) => _stream.Write(buffer, offset, count); + + public override int ReadByte() + { + byte read = (byte)_stream.ReadByte(); + firstByte = read; + readFirstByte = true; + return read; + } + } + + /// + /// During deserialization, the stream passed in may be binary formatted or may have used binary writer. This is quick test to discern between them. + /// + internal static bool StreamIsBinaryFormatted(StreamWrapper stream) + { + // For binary formatter, the first byte is the SerializationHeaderRecord and has a value 0 + int firstByte = stream.ReadByte(); + if (firstByte != 0) + { + return false; + } + + return true; + } + + private static void DeserializeUsingBinaryFormatter(StreamWrapper wrappedStream, string cryptoKey, RuntimeLicenseContext context) + { + if (EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization) + { + try + { +#pragma warning disable SYSLIB0011 + IFormatter formatter = new BinaryFormatter(); + + object obj = formatter.Deserialize(wrappedStream); #pragma warning restore SYSLIB0011 - if (obj is object[] value) + if (obj is object[] value) + { + if (value[0] is string && (string)value[0] == cryptoKey) + { + context._savedLicenseKeys = (Hashtable)value[1]; + } + } + } + catch (NotSupportedException exception) + { + if (!BinaryFormatterSerializationEnabled) + { + throw new NotSupportedException(exception.Message + " Turn on the EnableUnsafeBinaryFormatterSerialization flag to continue using BinaryFormatter"); + } + else + { + throw; + } + } + } + else + { + throw new NotSupportedException(SR.Format(SR.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization)); + } + } + + internal static void Deserialize(Stream o, string cryptoKey, RuntimeLicenseContext context) + { + StreamWrapper wrappedStream = new StreamWrapper(o); + if (StreamIsBinaryFormatted(wrappedStream)) + { + DeserializeUsingBinaryFormatter(wrappedStream, cryptoKey, context); + } + else { - if (value[0] is string && (string)value[0] == cryptoKey) + using (BinaryReader reader = new BinaryReader(wrappedStream, encoding: Text.Encoding.UTF8, leaveOpen: true)) { - context._savedLicenseKeys = (Hashtable)value[1]; + sbyte binaryWriterIdentifer = (sbyte)wrappedStream.firstByte; + Debug.Assert(binaryWriterIdentifer == -1, "Expected the first sbyte to be -1"); + string streamCryptoKey = reader.ReadString(); + int numEntries = reader.ReadInt32(); + if (streamCryptoKey == cryptoKey) + { + for (int i = 0; i < numEntries; i++) + { + context._savedLicenseKeys.Add(reader.ReadString(), reader.ReadString()); + } + } } } } diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs new file mode 100644 index 00000000000000..ec87d0658c6f8a --- /dev/null +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs @@ -0,0 +1,115 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.IO; +using System.Reflection; +using Microsoft.DotNet.RemoteExecutor; +using Xunit; + +namespace System.ComponentModel.Design.Tests +{ + public static class DesigntimeLicenseContextSerializerTests + { + private static string enableBinaryFormatterInTypeConverter = "System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization"; + private static string enableBinaryFormatter = "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization"; + + public static bool AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform => PlatformDetection.IsBinaryFormatterSupported && RemoteExecutor.IsSupported; + + [ConditionalFact(nameof(AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform))] + public static void SerializeAndDeserialize() + { + RemoteExecutor.Invoke(() => + { + foreach (var (useBinaryFormatter, key) in new System.Collections.Generic.List>() { + new Tuple(false, "key" ), + new Tuple(true, "key" ), + new Tuple(false, "" ), + new Tuple(true, "" ), + }) + { + { + AppContext.SetSwitch("TestSwitch.LocalAppContext.DisableCaching", true); + if (!useBinaryFormatter) + { + AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, false); + } + else + { + AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, true); + } + var context = new DesigntimeLicenseContext(); + context.SetSavedLicenseKey(typeof(int), key); + var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; + Type runtimeLicenseContextType = assembly.GetType("System.ComponentModel.Design.RuntimeLicenseContext"); + Assert.NotNull(runtimeLicenseContextType); + object runtimeLicenseContext = Activator.CreateInstance(runtimeLicenseContextType); + FieldInfo _savedLicenseKeys = runtimeLicenseContextType.GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(_savedLicenseKeys); + _savedLicenseKeys.SetValue(runtimeLicenseContext, new Hashtable()); + Assert.NotNull(runtimeLicenseContext); + + Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); + Assert.NotNull(designtimeLicenseContextSerializer); + Reflection.MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Static); + + using (MemoryStream stream = new MemoryStream()) + { + long position = stream.Position; + System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Serialize(stream, key, context); + stream.Seek(position, SeekOrigin.Begin); + deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext }); + Hashtable savedLicenseKeys = runtimeLicenseContext.GetType().GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(runtimeLicenseContext) as Hashtable; + Assert.NotNull(savedLicenseKeys); + var value = savedLicenseKeys[typeof(int).AssemblyQualifiedName]; + Assert.True(value is string); + Assert.Equal(key, value); + } + } + } + }).Dispose(); + } + + [ConditionalFact(nameof(AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform))] + public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter() + { + RemoteExecutor.Invoke(() => + { + foreach (var key in new System.Collections.Generic.List() { "key", "" }) + { + AppContext.SetSwitch("TestSwitch.LocalAppContext.DisableCaching", true); + AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, true); + AppContext.SetSwitch(enableBinaryFormatter, true); + var context = new DesigntimeLicenseContext(); + context.SetSavedLicenseKey(typeof(int), key); + var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; + Type runtimeLicenseContextType = assembly.GetType("System.ComponentModel.Design.RuntimeLicenseContext"); + Assert.NotNull(runtimeLicenseContextType); + object runtimeLicenseContext = Activator.CreateInstance(runtimeLicenseContextType); + Assert.NotNull(runtimeLicenseContext); + + Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); + Assert.NotNull(designtimeLicenseContextSerializer); + + using (MemoryStream stream = new MemoryStream()) + { + long position = stream.Position; + System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Serialize(stream, key, context); + AppContext.SetSwitch(enableBinaryFormatter, false); + Reflection.MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Static); + stream.Seek(position, SeekOrigin.Begin); + try + { + deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext }); + } + catch (System.Reflection.TargetInvocationException exception) + { + var baseException = exception.GetBaseException(); + Assert.IsType(baseException); + } + } + } + }).Dispose(); + } + } +} diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj b/src/libraries/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj index 49f136f0c0b974..645e898ea5150c 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj @@ -74,6 +74,7 @@ + From 0c28c37ab45a1eaab7e794841f8a6d23c7cc4749 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Tue, 23 Mar 2021 11:50:26 -0700 Subject: [PATCH 02/19] Address feedback --- .../src/Resources/Strings.resx | 4 +- .../DesigntimeLicenseContextSerializer.cs | 78 ++++++------------- ...DesigntimeLicenseContextSerializerTests.cs | 4 +- 3 files changed, 25 insertions(+), 61 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx b/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx index 42938cccdd3ff2..e9dd12b50616dd 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx +++ b/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx @@ -250,7 +250,7 @@ Relationships between {0}.{1} and {2}.{3} are not supported. - - Enable {0} as an AppContextSwitch to use BinaryFormatter to deserealize a stream + + BinaryFormatter serialization is obsolete and should not be used. See https://aka.ms/binaryformatter for more information. \ No newline at end of file diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs index 941d93aef49afe..a61afb25b5e03c 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs @@ -14,18 +14,10 @@ namespace System.ComponentModel.Design /// public class DesigntimeLicenseContextSerializer { - internal const string s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = "System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization"; - private const string s_enableBinaryFormatter = "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization"; + internal const byte BinaryWriterMagic = 255; - private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization - { - get => AppContext.TryGetSwitch(s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, out bool isEnabled) ? isEnabled : false; - } - - private static bool BinaryFormatterSerializationEnabled - { - get => AppContext.TryGetSwitch(s_enableBinaryFormatter, out bool isEnabled) ? isEnabled : false; - } + private const string s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = "System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization"; + private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization { get; } = AppContext.TryGetSwitch(s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, out bool isEnabled) ? isEnabled : false; // Not creatable. private DesigntimeLicenseContextSerializer() @@ -46,7 +38,7 @@ public static void Serialize(Stream o, string cryptoKey, DesigntimeLicenseContex { using (BinaryWriter writer = new BinaryWriter(o, encoding: Text.Encoding.UTF8, leaveOpen: true)) { - writer.Write((sbyte)-1); // flag to identify BinaryWriter + writer.Write(BinaryWriterMagic); // flag to identify BinaryWriter writer.Write(cryptoKey); writer.Write(context._savedLicenseKeys.Count); foreach (DictionaryEntry keyAndValue in context._savedLicenseKeys) @@ -60,35 +52,21 @@ public static void Serialize(Stream o, string cryptoKey, DesigntimeLicenseContex private static void SerializeWithBinaryFormatter(Stream o, string cryptoKey, DesigntimeLicenseContext context) { - try - { - IFormatter formatter = new BinaryFormatter(); + IFormatter formatter = new BinaryFormatter(); #pragma warning disable SYSLIB0011 - formatter.Serialize(o, new object[] { cryptoKey, context._savedLicenseKeys }); + formatter.Serialize(o, new object[] { cryptoKey, context._savedLicenseKeys }); #pragma warning restore SYSLIB0011 - } - catch (NotSupportedException exception) - { - if (!BinaryFormatterSerializationEnabled) - { - throw new NotSupportedException(exception.Message + " Turn on the EnableUnsafeBinaryFormatterSerialization flag to continue using BinaryFormatter"); - } - else - { - throw; - } - } } internal class StreamWrapper : Stream { private Stream _stream; - internal bool readFirstByte; + private bool _readFirstByte; internal byte firstByte; public StreamWrapper(Stream stream) { _stream = stream; - readFirstByte = false; + _readFirstByte = false; firstByte = 0; } @@ -109,7 +87,7 @@ public override int Read(byte[] buffer, int offset, int count) Debug.Assert(_stream.Position != 0, "Expected the first byte to be read first"); if (_stream.Position == 1) { - Debug.Assert(readFirstByte == true); + Debug.Assert(_readFirstByte == true); // Add the first byte read by ReadByte into buffer here buffer[0] = firstByte; return _stream.Read(buffer, offset + 1, count - 1) + 1; @@ -127,13 +105,13 @@ public override int ReadByte() { byte read = (byte)_stream.ReadByte(); firstByte = read; - readFirstByte = true; + _readFirstByte = true; return read; } } /// - /// During deserialization, the stream passed in may be binary formatted or may have used binary writer. This is quick test to discern between them. + /// During deserialization, the stream passed in may be binary formatted or may have used binary writer. This is a quick test to discern between them. /// internal static bool StreamIsBinaryFormatted(StreamWrapper stream) { @@ -151,37 +129,23 @@ private static void DeserializeUsingBinaryFormatter(StreamWrapper wrappedStream, { if (EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization) { - try - { #pragma warning disable SYSLIB0011 - IFormatter formatter = new BinaryFormatter(); + IFormatter formatter = new BinaryFormatter(); - object obj = formatter.Deserialize(wrappedStream); + object obj = formatter.Deserialize(wrappedStream); #pragma warning restore SYSLIB0011 - if (obj is object[] value) - { - if (value[0] is string && (string)value[0] == cryptoKey) - { - context._savedLicenseKeys = (Hashtable)value[1]; - } - } - } - catch (NotSupportedException exception) + if (obj is object[] value) { - if (!BinaryFormatterSerializationEnabled) - { - throw new NotSupportedException(exception.Message + " Turn on the EnableUnsafeBinaryFormatterSerialization flag to continue using BinaryFormatter"); - } - else + if (value[0] is string && (string)value[0] == cryptoKey) { - throw; + context._savedLicenseKeys = (Hashtable)value[1]; } } } else { - throw new NotSupportedException(SR.Format(SR.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization)); + throw new NotSupportedException(SR.BinaryFormatterMessage); } } @@ -196,15 +160,17 @@ internal static void Deserialize(Stream o, string cryptoKey, RuntimeLicenseConte { using (BinaryReader reader = new BinaryReader(wrappedStream, encoding: Text.Encoding.UTF8, leaveOpen: true)) { - sbyte binaryWriterIdentifer = (sbyte)wrappedStream.firstByte; - Debug.Assert(binaryWriterIdentifer == -1, "Expected the first sbyte to be -1"); + byte binaryWriterIdentifer = wrappedStream.firstByte; + Debug.Assert(binaryWriterIdentifer == BinaryWriterMagic, $"Expected the first byte to be {BinaryWriterMagic}"); string streamCryptoKey = reader.ReadString(); int numEntries = reader.ReadInt32(); if (streamCryptoKey == cryptoKey) { for (int i = 0; i < numEntries; i++) { - context._savedLicenseKeys.Add(reader.ReadString(), reader.ReadString()); + string key = reader.ReadString(); + string value = reader.ReadString(); + context._savedLicenseKeys.Add(key, value); } } } diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs index ec87d0658c6f8a..0ca8546d23bb85 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs @@ -26,10 +26,9 @@ public static void SerializeAndDeserialize() new Tuple(true, "key" ), new Tuple(false, "" ), new Tuple(true, "" ), - }) + }) { { - AppContext.SetSwitch("TestSwitch.LocalAppContext.DisableCaching", true); if (!useBinaryFormatter) { AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, false); @@ -77,7 +76,6 @@ public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter() { foreach (var key in new System.Collections.Generic.List() { "key", "" }) { - AppContext.SetSwitch("TestSwitch.LocalAppContext.DisableCaching", true); AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, true); AppContext.SetSwitch(enableBinaryFormatter, true); var context = new DesigntimeLicenseContext(); From 046372f0891a6aa8d6bd07750b6847e3c62c69d4 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Wed, 24 Mar 2021 11:26:00 -0700 Subject: [PATCH 03/19] First unit test --- ...DesigntimeLicenseContextSerializerTests.cs | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs index 0ca8546d23bb85..10cd978cc3b1f9 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; +using System.Diagnostics; using System.IO; using System.Reflection; +using System.Text; using Microsoft.DotNet.RemoteExecutor; using Xunit; @@ -16,27 +18,45 @@ public static class DesigntimeLicenseContextSerializerTests public static bool AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform => PlatformDetection.IsBinaryFormatterSupported && RemoteExecutor.IsSupported; - [ConditionalFact(nameof(AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform))] - public static void SerializeAndDeserialize() + private static void VerifyStreamFormatting(Stream stream) { - RemoteExecutor.Invoke(() => + AppContext.TryGetSwitch(enableBinaryFormatterInTypeConverter, out bool binaryFormatterUsageInTypeConverterIsEnabled); + long position = stream.Position; + int firstByte = stream.ReadByte(); + if (binaryFormatterUsageInTypeConverterIsEnabled) + { + if (firstByte != 0) + { + Assert.False(true, "Expected this stream to have used BinaryFormatter"); + } + } + else { - foreach (var (useBinaryFormatter, key) in new System.Collections.Generic.List>() { - new Tuple(false, "key" ), - new Tuple(true, "key" ), - new Tuple(false, "" ), - new Tuple(true, "" ), - }) + if (firstByte != 255) { + Assert.False(true, "Expected this stream to have used BinaryWriter"); + } + } + stream.Seek(position, SeekOrigin.Begin); + } + + [ConditionalTheory(nameof(AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform))] + [InlineData(false, "key")] + [InlineData(true, "key")] + [InlineData(false, "")] + [InlineData(true, "")] + public static void SerializeAndDeserialize(bool useBinaryFormatter, string key) + { + { + RemoteInvokeOptions options = new RemoteInvokeOptions(); + if (useBinaryFormatter) + { + options.RuntimeConfigurationOptions.Add(enableBinaryFormatterInTypeConverter, bool.TrueString); + } + RemoteExecutor.Invoke((key) => + { + Debugger.Launch(); { - if (!useBinaryFormatter) - { - AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, false); - } - else - { - AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, true); - } var context = new DesigntimeLicenseContext(); context.SetSavedLicenseKey(typeof(int), key); var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; @@ -57,6 +77,7 @@ public static void SerializeAndDeserialize() long position = stream.Position; System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Serialize(stream, key, context); stream.Seek(position, SeekOrigin.Begin); + VerifyStreamFormatting(stream); deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext }); Hashtable savedLicenseKeys = runtimeLicenseContext.GetType().GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(runtimeLicenseContext) as Hashtable; Assert.NotNull(savedLicenseKeys); @@ -65,8 +86,8 @@ public static void SerializeAndDeserialize() Assert.Equal(key, value); } } - } - }).Dispose(); + }, key, options).Dispose(); + } } [ConditionalFact(nameof(AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform))] From 7fdaf7e6e1207e942482cf2934f7b1eb9b760d58 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Wed, 24 Mar 2021 11:26:25 -0700 Subject: [PATCH 04/19] 2nd unit test. Checkpoint --- .../DesigntimeLicenseContextSerializerTests.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs index 10cd978cc3b1f9..69a0271c9fcf20 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs @@ -106,16 +106,22 @@ public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter() Assert.NotNull(runtimeLicenseContextType); object runtimeLicenseContext = Activator.CreateInstance(runtimeLicenseContextType); Assert.NotNull(runtimeLicenseContext); - - Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); - Assert.NotNull(designtimeLicenseContextSerializer); + FieldInfo _savedLicenseKeys = runtimeLicenseContextType.GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(_savedLicenseKeys); + _savedLicenseKeys.SetValue(runtimeLicenseContext, new Hashtable()); using (MemoryStream stream = new MemoryStream()) { long position = stream.Position; System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Serialize(stream, key, context); AppContext.SetSwitch(enableBinaryFormatter, false); + Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); + Assert.NotNull(designtimeLicenseContextSerializer); + var enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = designtimeLicenseContextSerializer.GetField("_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization", BindingFlags.Static | BindingFlags.NonPublic); + Assert.NotNull(enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization); + enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization.SetValue(designtimeLicenseContextSerializer, false); Reflection.MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Static); + Assert.NotNull(deserializeMethod); stream.Seek(position, SeekOrigin.Begin); try { @@ -123,7 +129,8 @@ public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter() } catch (System.Reflection.TargetInvocationException exception) { - var baseException = exception.GetBaseException(); + Exception baseException = exception.GetBaseException(); + var baseExceptionType = baseException.GetType(); Assert.IsType(baseException); } } From 7002e821e3ddb6c10b371b772c770dc32d37d6b7 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Wed, 24 Mar 2021 11:43:40 -0700 Subject: [PATCH 05/19] sq --- .../DesigntimeLicenseContextSerializer.cs | 7 +- ...DesigntimeLicenseContextSerializerTests.cs | 86 ++++++++++--------- 2 files changed, 50 insertions(+), 43 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs index a61afb25b5e03c..75cf70595b900a 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs @@ -17,8 +17,13 @@ public class DesigntimeLicenseContextSerializer internal const byte BinaryWriterMagic = 255; private const string s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = "System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization"; - private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization { get; } = AppContext.TryGetSwitch(s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, out bool isEnabled) ? isEnabled : false; + private static bool _enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = AppContext.TryGetSwitch(s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, out bool isEnabled) ? isEnabled : false; + private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization + { + get => _enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization; + set => _enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = value; + } // Not creatable. private DesigntimeLicenseContextSerializer() { diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs index 69a0271c9fcf20..5f15adf602a768 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.IO; using System.Reflection; -using System.Text; using Microsoft.DotNet.RemoteExecutor; using Xunit; @@ -70,12 +69,12 @@ public static void SerializeAndDeserialize(bool useBinaryFormatter, string key) Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); Assert.NotNull(designtimeLicenseContextSerializer); - Reflection.MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Static); + MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static); using (MemoryStream stream = new MemoryStream()) { long position = stream.Position; - System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Serialize(stream, key, context); + DesigntimeLicenseContextSerializer.Serialize(stream, key, context); stream.Seek(position, SeekOrigin.Begin); VerifyStreamFormatting(stream); deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext }); @@ -90,52 +89,55 @@ public static void SerializeAndDeserialize(bool useBinaryFormatter, string key) } } - [ConditionalFact(nameof(AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform))] - public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter() + [ConditionalTheory(nameof(AreBinaryFormatterAndRemoteExecutorSupportedOnThisPlatform))] + [InlineData("key")] + [InlineData("")] + public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter(string key) { - RemoteExecutor.Invoke(() => + RemoteInvokeOptions options = new RemoteInvokeOptions(); + options.RuntimeConfigurationOptions.Add(enableBinaryFormatterInTypeConverter, bool.TrueString); + options.RuntimeConfigurationOptions.Add(enableBinaryFormatter, bool.TrueString); + RemoteExecutor.Invoke((key) => { - foreach (var key in new System.Collections.Generic.List() { "key", "" }) + var context = new DesigntimeLicenseContext(); + context.SetSavedLicenseKey(typeof(int), key); + var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; + Type runtimeLicenseContextType = assembly.GetType("System.ComponentModel.Design.RuntimeLicenseContext"); + Assert.NotNull(runtimeLicenseContextType); + object runtimeLicenseContext = Activator.CreateInstance(runtimeLicenseContextType); + Assert.NotNull(runtimeLicenseContext); + FieldInfo _savedLicenseKeys = runtimeLicenseContextType.GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(_savedLicenseKeys); + _savedLicenseKeys.SetValue(runtimeLicenseContext, new Hashtable()); + + using (MemoryStream stream = new MemoryStream()) { - AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, true); - AppContext.SetSwitch(enableBinaryFormatter, true); - var context = new DesigntimeLicenseContext(); - context.SetSavedLicenseKey(typeof(int), key); - var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; - Type runtimeLicenseContextType = assembly.GetType("System.ComponentModel.Design.RuntimeLicenseContext"); - Assert.NotNull(runtimeLicenseContextType); - object runtimeLicenseContext = Activator.CreateInstance(runtimeLicenseContextType); - Assert.NotNull(runtimeLicenseContext); - FieldInfo _savedLicenseKeys = runtimeLicenseContextType.GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(_savedLicenseKeys); - _savedLicenseKeys.SetValue(runtimeLicenseContext, new Hashtable()); + long position = stream.Position; + DesigntimeLicenseContextSerializer.Serialize(stream, key, context); + stream.Seek(position, SeekOrigin.Begin); + VerifyStreamFormatting(stream); + + Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); + Assert.NotNull(designtimeLicenseContextSerializer); + // Simulate deserializing a BinaryFormatted stream with enableBinaryFormatterInTypeConverter turned off. + var enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = designtimeLicenseContextSerializer.GetField("_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization", BindingFlags.Static | BindingFlags.NonPublic); + Assert.NotNull(enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization); + enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization.SetValue(designtimeLicenseContextSerializer, false); + MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static); + Assert.NotNull(deserializeMethod); - using (MemoryStream stream = new MemoryStream()) + stream.Seek(position, SeekOrigin.Begin); + try { - long position = stream.Position; - System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Serialize(stream, key, context); - AppContext.SetSwitch(enableBinaryFormatter, false); - Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); - Assert.NotNull(designtimeLicenseContextSerializer); - var enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = designtimeLicenseContextSerializer.GetField("_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization", BindingFlags.Static | BindingFlags.NonPublic); - Assert.NotNull(enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization); - enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization.SetValue(designtimeLicenseContextSerializer, false); - Reflection.MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Static); - Assert.NotNull(deserializeMethod); - stream.Seek(position, SeekOrigin.Begin); - try - { - deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext }); - } - catch (System.Reflection.TargetInvocationException exception) - { - Exception baseException = exception.GetBaseException(); - var baseExceptionType = baseException.GetType(); - Assert.IsType(baseException); - } + deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext }); + } + catch (TargetInvocationException exception) + { + Exception baseException = exception.GetBaseException(); + Assert.IsType(baseException); } } - }).Dispose(); + }, key, options).Dispose(); } } } From 4c4bb958dea13d425cd714723af700b72fe3d258 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Wed, 24 Mar 2021 14:22:11 -0700 Subject: [PATCH 06/19] sq --- .../DesigntimeLicenseContextSerializer.cs | 1 - ...DesigntimeLicenseContextSerializerTests.cs | 51 +++++++++++-------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs index 75cf70595b900a..f1a42451b2c310 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs @@ -22,7 +22,6 @@ public class DesigntimeLicenseContextSerializer private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization { get => _enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization; - set => _enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = value; } // Not creatable. private DesigntimeLicenseContextSerializer() diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs index 5f15adf602a768..38ab37cf3d285b 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs @@ -94,13 +94,28 @@ public static void SerializeAndDeserialize(bool useBinaryFormatter, string key) [InlineData("")] public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter(string key) { - RemoteInvokeOptions options = new RemoteInvokeOptions(); - options.RuntimeConfigurationOptions.Add(enableBinaryFormatterInTypeConverter, bool.TrueString); - options.RuntimeConfigurationOptions.Add(enableBinaryFormatter, bool.TrueString); + AppContext.SetSwitch(enableBinaryFormatter, true); + AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, true); + var context = new DesigntimeLicenseContext(); + context.SetSavedLicenseKey(typeof(int), key); + var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; + using (MemoryStream stream = new MemoryStream()) + { + long position = stream.Position; + DesigntimeLicenseContextSerializer.Serialize(stream, key, context); + stream.Seek(position, SeekOrigin.Begin); + VerifyStreamFormatting(stream); + + string tempPath = Path.GetTempPath(); + using (FileStream outStream = File.Create(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter"))) + { + stream.Seek(position, SeekOrigin.Begin); + stream.CopyTo(outStream); + } + } + RemoteExecutor.Invoke((key) => { - var context = new DesigntimeLicenseContext(); - context.SetSavedLicenseKey(typeof(int), key); var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; Type runtimeLicenseContextType = assembly.GetType("System.ComponentModel.Design.RuntimeLicenseContext"); Assert.NotNull(runtimeLicenseContextType); @@ -110,23 +125,14 @@ public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter(stri Assert.NotNull(_savedLicenseKeys); _savedLicenseKeys.SetValue(runtimeLicenseContext, new Hashtable()); - using (MemoryStream stream = new MemoryStream()) - { - long position = stream.Position; - DesigntimeLicenseContextSerializer.Serialize(stream, key, context); - stream.Seek(position, SeekOrigin.Begin); - VerifyStreamFormatting(stream); - - Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); - Assert.NotNull(designtimeLicenseContextSerializer); - // Simulate deserializing a BinaryFormatted stream with enableBinaryFormatterInTypeConverter turned off. - var enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = designtimeLicenseContextSerializer.GetField("_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization", BindingFlags.Static | BindingFlags.NonPublic); - Assert.NotNull(enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization); - enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization.SetValue(designtimeLicenseContextSerializer, false); - MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static); - Assert.NotNull(deserializeMethod); + Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); + Assert.NotNull(designtimeLicenseContextSerializer); + MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static); + Assert.NotNull(deserializeMethod); - stream.Seek(position, SeekOrigin.Begin); + string tempPath = Path.GetTempPath(); + using (FileStream stream = File.Open(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter"), FileMode.Open)) + { try { deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext }); @@ -137,7 +143,8 @@ public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter(stri Assert.IsType(baseException); } } - }, key, options).Dispose(); + File.Delete(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter")); + }, key).Dispose(); } } } From 570a875a1fc3aaef0bf416a7ae68eaefcd8a8e2a Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Wed, 24 Mar 2021 14:25:53 -0700 Subject: [PATCH 07/19] sq --- .../Design/DesigntimeLicenseContextSerializer.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs index f1a42451b2c310..2c7e72efdd3c88 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs @@ -18,11 +18,8 @@ public class DesigntimeLicenseContextSerializer private const string s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = "System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization"; - private static bool _enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = AppContext.TryGetSwitch(s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, out bool isEnabled) ? isEnabled : false; - private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization - { - get => _enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization; - } + private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization { get; } = AppContext.TryGetSwitch(s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, out bool isEnabled) ? isEnabled : false; + // Not creatable. private DesigntimeLicenseContextSerializer() { From 773bb774357ca3e1dc898e7504aa5473cb31e0e1 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Thu, 25 Mar 2021 09:43:15 -0700 Subject: [PATCH 08/19] Address Levi's feedback --- .../Design/DesigntimeLicenseContextSerializer.cs | 3 ++- .../tests/Design/DesigntimeLicenseContextSerializerTests.cs | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs index 2c7e72efdd3c88..d03ffe4771742b 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs @@ -90,7 +90,7 @@ public override int Read(byte[] buffer, int offset, int count) { Debug.Assert(_readFirstByte == true); // Add the first byte read by ReadByte into buffer here - buffer[0] = firstByte; + buffer[offset] = firstByte; return _stream.Read(buffer, offset + 1, count - 1) + 1; } return _stream.Read(buffer, offset, count); @@ -104,6 +104,7 @@ public override int Read(byte[] buffer, int offset, int count) public override int ReadByte() { + Debug.Assert(_readFirstByte == false); byte read = (byte)_stream.ReadByte(); firstByte = read; _readFirstByte = true; diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs index 38ab37cf3d285b..8007784c01039d 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; -using System.Diagnostics; using System.IO; using System.Reflection; using Microsoft.DotNet.RemoteExecutor; @@ -54,7 +53,6 @@ public static void SerializeAndDeserialize(bool useBinaryFormatter, string key) } RemoteExecutor.Invoke((key) => { - Debugger.Launch(); { var context = new DesigntimeLicenseContext(); context.SetSavedLicenseKey(typeof(int), key); From 9f78bcbf8f7a1e003b8ffb209e251379ff1a6bcf Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Thu, 25 Mar 2021 10:19:19 -0700 Subject: [PATCH 09/19] sq --- .../src/ILLink/ILLink.Suppressions.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.xml index cddfb1ce1a8f56..da654041e4bb77 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.xml +++ b/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.xml @@ -1,18 +1,6 @@  - - ILLink - IL2026 - member - M:System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Deserialize(System.IO.Stream,System.String,System.ComponentModel.Design.RuntimeLicenseContext) - - - ILLink - IL2026 - member - M:System.ComponentModel.Design.DesigntimeLicenseContextSerializer.Serialize(System.IO.Stream,System.String,System.ComponentModel.Design.DesigntimeLicenseContext) - ILLink IL2072 From 78a3c7640f81a92343401fcf03eb08b73faa3b46 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Thu, 25 Mar 2021 11:13:25 -0700 Subject: [PATCH 10/19] Address nits --- .../Design/DesigntimeLicenseContextSerializer.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs index d03ffe4771742b..6c15e6968a2289 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesigntimeLicenseContextSerializer.cs @@ -16,9 +16,7 @@ public class DesigntimeLicenseContextSerializer { internal const byte BinaryWriterMagic = 255; - private const string s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization = "System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization"; - - private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization { get; } = AppContext.TryGetSwitch(s_enableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization, out bool isEnabled) ? isEnabled : false; + private static bool EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization { get; } = AppContext.TryGetSwitch("System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization", out bool isEnabled) ? isEnabled : false; // Not creatable. private DesigntimeLicenseContextSerializer() @@ -63,12 +61,12 @@ internal class StreamWrapper : Stream { private Stream _stream; private bool _readFirstByte; - internal byte firstByte; + internal byte _firstByte; public StreamWrapper(Stream stream) { _stream = stream; _readFirstByte = false; - firstByte = 0; + _firstByte = 0; } public override bool CanRead => _stream.CanRead; @@ -90,7 +88,7 @@ public override int Read(byte[] buffer, int offset, int count) { Debug.Assert(_readFirstByte == true); // Add the first byte read by ReadByte into buffer here - buffer[offset] = firstByte; + buffer[offset] = _firstByte; return _stream.Read(buffer, offset + 1, count - 1) + 1; } return _stream.Read(buffer, offset, count); @@ -106,7 +104,7 @@ public override int ReadByte() { Debug.Assert(_readFirstByte == false); byte read = (byte)_stream.ReadByte(); - firstByte = read; + _firstByte = read; _readFirstByte = true; return read; } @@ -162,7 +160,7 @@ internal static void Deserialize(Stream o, string cryptoKey, RuntimeLicenseConte { using (BinaryReader reader = new BinaryReader(wrappedStream, encoding: Text.Encoding.UTF8, leaveOpen: true)) { - byte binaryWriterIdentifer = wrappedStream.firstByte; + byte binaryWriterIdentifer = wrappedStream._firstByte; Debug.Assert(binaryWriterIdentifer == BinaryWriterMagic, $"Expected the first byte to be {BinaryWriterMagic}"); string streamCryptoKey = reader.ReadString(); int numEntries = reader.ReadInt32(); From 3d080422318317c930dd2a36da43ee0e9466e71b Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Thu, 25 Mar 2021 18:01:10 -0500 Subject: [PATCH 11/19] Linker changes and tests --- eng/testing/linker/project.csproj.template | 1 + eng/testing/linker/trimmingTests.targets | 6 +++ .../src/ILLink/ILLink.Suppressions.xml | 12 ----- .../DesigntimeLicenseContextSerializer.cs | 7 ++- ...LicenseContextSerialization_Deserialize.cs | 34 ++++++++++++++ ...meLicenseContextSerialization_Serialize.cs | 45 +++++++++++++++++++ .../tests/TrimmingTests/SampleStream.cs | 19 ++++++++ ...nentModel.TypeConverter.TrimmingTests.proj | 15 +++++++ 8 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 src/libraries/System.ComponentModel.TypeConverter/tests/TrimmingTests/DesigntimeLicenseContextSerialization_Deserialize.cs create mode 100644 src/libraries/System.ComponentModel.TypeConverter/tests/TrimmingTests/DesigntimeLicenseContextSerialization_Serialize.cs create mode 100644 src/libraries/System.ComponentModel.TypeConverter/tests/TrimmingTests/SampleStream.cs diff --git a/eng/testing/linker/project.csproj.template b/eng/testing/linker/project.csproj.template index 7ac21cbcb5b5f0..53576a8cc2163d 100644 --- a/eng/testing/linker/project.csproj.template +++ b/eng/testing/linker/project.csproj.template @@ -29,6 +29,7 @@ {AdditionalProjectReferences} + {TrimmerRootAssemblies} + browser-wasm --feature System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization true DesigntimeLicenseContextSerialization_Stream.cs + + browser-wasm From 8dfe20a8ac63f7e0c6210155365fc8334b3954e4 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Tue, 30 Mar 2021 09:29:02 -0700 Subject: [PATCH 19/19] sq --- ...DesigntimeLicenseContextSerializerTests.cs | 81 +++++++++---------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs index dfad16059928f3..131d6f73c4e28a 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesigntimeLicenseContextSerializerTests.cs @@ -86,62 +86,55 @@ public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter(stri AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, true); var context = new DesigntimeLicenseContext(); context.SetSavedLicenseKey(typeof(int), key); - var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; string tempPath = Path.GetTempPath(); - using (MemoryStream stream = new MemoryStream()) + try { - long position = stream.Position; - DesigntimeLicenseContextSerializer.Serialize(stream, key, context); - stream.Seek(position, SeekOrigin.Begin); - VerifyStreamFormatting(stream); - using (FileStream outStream = File.Create(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter"))) + using (MemoryStream stream = new MemoryStream()) { + long position = stream.Position; + DesigntimeLicenseContextSerializer.Serialize(stream, key, context); stream.Seek(position, SeekOrigin.Begin); - stream.CopyTo(outStream); + VerifyStreamFormatting(stream); + + using (FileStream outStream = File.Create(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter"))) + { + stream.Seek(position, SeekOrigin.Begin); + stream.CopyTo(outStream); + } } - } - RemoteInvokeHandle handle = RemoteExecutor.Invoke((key) => - { - var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; - Type runtimeLicenseContextType = assembly.GetType("System.ComponentModel.Design.RuntimeLicenseContext"); - Assert.NotNull(runtimeLicenseContextType); - object runtimeLicenseContext = Activator.CreateInstance(runtimeLicenseContextType); - Assert.NotNull(runtimeLicenseContext); - FieldInfo _savedLicenseKeys = runtimeLicenseContextType.GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(_savedLicenseKeys); - _savedLicenseKeys.SetValue(runtimeLicenseContext, new Hashtable()); + RemoteInvokeHandle handle = RemoteExecutor.Invoke((key) => + { + var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; + Type runtimeLicenseContextType = assembly.GetType("System.ComponentModel.Design.RuntimeLicenseContext"); + Assert.NotNull(runtimeLicenseContextType); + object runtimeLicenseContext = Activator.CreateInstance(runtimeLicenseContextType); + Assert.NotNull(runtimeLicenseContext); + FieldInfo _savedLicenseKeys = runtimeLicenseContextType.GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(_savedLicenseKeys); + _savedLicenseKeys.SetValue(runtimeLicenseContext, new Hashtable()); - Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); - Assert.NotNull(designtimeLicenseContextSerializer); - MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static); - Assert.NotNull(deserializeMethod); + Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); + Assert.NotNull(designtimeLicenseContextSerializer); + MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static); + Assert.NotNull(deserializeMethod); - string tempPath = Path.GetTempPath(); - using (FileStream stream = File.Open(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter"), FileMode.Open)) - { - try + string tempPath = Path.GetTempPath(); + using (FileStream stream = File.Open(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter"), FileMode.Open)) { - deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext }); + TargetInvocationException exception = Assert.Throws(() => deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext })); + Assert.IsType(exception.InnerException); } - catch (TargetInvocationException exception) - { - Exception baseException = exception.GetBaseException(); - Assert.IsType(baseException); - return; - } - catch - { - throw; - } - throw new Exception("Expected to throw a TargetInvocationException"); - } - }, key); + }, key); - handle.Process.WaitForExit(); - handle.Dispose(); - File.Delete(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter")); + handle.Process.WaitForExit(); + handle.Dispose(); + } + finally + { + File.Delete(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter")); + } } } }