From 0057f56bdf1838a968adb4f317aca90be9cdca8e Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Fri, 5 Jun 2020 16:32:33 -0700 Subject: [PATCH 01/13] Obsolete Encoding.UTF7 property and UTF7Encoding ctors --- eng/CodeAnalysis.ruleset | 3 +- .../src/System/IO/Compression/ZipArchive.cs | 3 -- .../tests/SerialPort/Encoding.cs | 2 + .../tests/SerialPort/ReadTo.cs | 15 ++++++-- .../tests/SerialPort/Read_char_int_int.cs | 5 ++- .../UnitTests/TranscodingReadStreamTests.cs | 9 ----- .../UnitTests/TranscodingWriteStreamTests.cs | 8 ---- .../src/Resources/Strings.resx | 3 ++ .../System.Private.CoreLib.Shared.projitems | 1 + .../src/System/Obsoletions.cs | 14 +++++++ .../src/System/Text/Encoding.cs | 37 ++++++++++++++++++- .../src/System/Text/EncodingTable.cs | 14 +++++-- .../src/System/Text/UTF7Encoding.cs | 4 ++ .../System.Runtime/ref/System.Runtime.cs | 1 + .../tests/System.Runtime.Tests.csproj | 1 + .../tests/System/Text/EncodingTests.cs | 27 ++++++++++++++ .../tests/EncodingCodePages.cs | 7 +++- .../ref/System.Text.Encoding.Extensions.cs | 2 + .../tests/System.Text.Encoding.Tests.csproj | 5 +++ .../tests/runtimeconfig.template.json | 5 +++ 20 files changed, 133 insertions(+), 33 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs create mode 100644 src/libraries/System.Runtime/tests/System/Text/EncodingTests.cs create mode 100644 src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json diff --git a/eng/CodeAnalysis.ruleset b/eng/CodeAnalysis.ruleset index 66a6af943a1ef7..0a84dcdbdffd9b 100644 --- a/eng/CodeAnalysis.ruleset +++ b/eng/CodeAnalysis.ruleset @@ -126,7 +126,8 @@ - + + diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs index c6a91b550cf475..0738921b356b65 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs @@ -373,9 +373,6 @@ private set #if FEATURE_UTF32 || value.Equals(Encoding.UTF32) #endif // FEATURE_UTF32 -#if FEATURE_UTF7 - || value.Equals(Encoding.UTF7) -#endif // FEATURE_UTF7 )) { throw new ArgumentException(SR.EntryNameEncodingNotSupported, nameof(EntryNameEncoding)); diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs b/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs index 60b309a89b11ad..a6c49f245b8dfb 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs @@ -111,7 +111,9 @@ public void Encoding_ISCIIAssemese() public void Encoding_UTF7() { Debug.WriteLine("Verifying UTF7Encoding Encoding"); +#pragma warning disable BCL0001 // Encoding.UTF7 property is obsolete VerifyException(Encoding.UTF7, ThrowAt.Set, typeof(ArgumentException)); +#pragma warning restore BCL0001 } [ConditionalFact(nameof(HasOneSerialPort))] diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs b/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs index 4a63d75a1ebf49..3c8740f608a778 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs @@ -25,6 +25,9 @@ public class ReadTo : PortsTest private const int MIN_NUM_NEWLINE_CHARS = 1; private const int MAX_NUM_NEWLINE_CHARS = 5; + // The web name of Encoding.UTF7 + private const string UTF7_WEBNAME = "utf-7"; + private enum ReadDataFromEnum { NonBuffered, Buffered, BufferedAndNonBuffered }; #region Test Cases @@ -691,7 +694,7 @@ private void PerformReadOnCom1FromCom2(SerialPort com1, SerialPort com2, string int totalCharsRead; int lastIndexOfNewLine = -newLineStringLength; string expectedString; - bool isUTF7Encoding = com1.Encoding.EncodingName == Encoding.UTF7.EncodingName; + bool isUTF7Encoding = com1.Encoding.WebName == UTF7_WEBNAME; char[] charsToWrite = strToWrite.ToCharArray(); byte[] bytesToWrite = com1.Encoding.GetBytes(charsToWrite); @@ -805,7 +808,7 @@ private void VerifyReadToWithWriteLine(Encoding encoding, string newLine) Random rndGen = new Random(-55); StringBuilder strBldrToWrite; string strExpected; - bool isUTF7Encoding = encoding.EncodingName == Encoding.UTF7.EncodingName; + bool isUTF7Encoding = encoding.WebName == UTF7_WEBNAME; Debug.WriteLine("Verifying ReadTo with WriteLine encoding={0}, newLine={1}", encoding, newLine); @@ -861,10 +864,14 @@ private string GenRandomNewLine(bool validAscii) private int GetUTF7EncodingBytes(char[] chars, int index, int count) { - byte[] bytes = Encoding.UTF7.GetBytes(chars, index, count); +#pragma warning disable BCL0001 // Encoding.UTF7 property is obsolete + Encoding utf7Encoding = Encoding.UTF7; +#pragma warning restore BCL0001 + + byte[] bytes = utf7Encoding.GetBytes(chars, index, count); int byteCount = bytes.Length; - while (Encoding.UTF7.GetCharCount(bytes, 0, byteCount) == count) + while (utf7Encoding.GetCharCount(bytes, 0, byteCount) == count) { --byteCount; } diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs b/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs index 30561e194a90ba..eb360920bafcf8 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs @@ -34,6 +34,9 @@ public class Read_char_int_int : PortsTest //The maximum buffer size when an exception is not expected private const int maxBufferSize = 8; + // The web name of Encoding.UTF7 + private const string utf7WebName = "utf-7"; + public enum ReadDataFromEnum { NonBuffered, Buffered, BufferedAndNonBuffered }; #region Test Cases @@ -950,7 +953,7 @@ private void VerifyBytesFollowedByChars(Encoding encoding) Fail("ERROR!!!: Expected to read {0} chars actually read {1}", xmitCharBuffer.Length, numRead); } - if (encoding.EncodingName == Encoding.UTF7.EncodingName) + if (encoding.WebName == utf7WebName) { //If UTF7Encoding is being used we might leave a - in the stream if (com1.BytesToRead == xmitByteBuffer.Length + 1) diff --git a/src/libraries/System.Net.Http.Json/tests/UnitTests/TranscodingReadStreamTests.cs b/src/libraries/System.Net.Http.Json/tests/UnitTests/TranscodingReadStreamTests.cs index 3a8ee5840f7dfc..ef8904bf72fd22 100644 --- a/src/libraries/System.Net.Http.Json/tests/UnitTests/TranscodingReadStreamTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/UnitTests/TranscodingReadStreamTests.cs @@ -232,15 +232,6 @@ public Task ReadAsync_Works_WhenInputIs_Unicode(string message) return ReadAsyncTest(sourceEncoding, message); } - [Theory] - [MemberData(nameof(ReadAsyncInputLatin), "utf-7")] - [MemberData(nameof(ReadAsyncInputUnicode), "utf-7")] - public Task ReadAsync_Works_WhenInputIs_UTF7(string message) - { - Encoding sourceEncoding = Encoding.UTF7; - return ReadAsyncTest(sourceEncoding, message); - } - [Theory] [MemberData(nameof(ReadAsyncInputLatin), "iso-8859-1")] public Task ReadAsync_Works_WhenInputIs_WesternEuropeanEncoding(string message) diff --git a/src/libraries/System.Net.Http.Json/tests/UnitTests/TranscodingWriteStreamTests.cs b/src/libraries/System.Net.Http.Json/tests/UnitTests/TranscodingWriteStreamTests.cs index 546f666c7c1133..909f174e125bb8 100644 --- a/src/libraries/System.Net.Http.Json/tests/UnitTests/TranscodingWriteStreamTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/UnitTests/TranscodingWriteStreamTests.cs @@ -42,14 +42,6 @@ public Task WriteAsync_Works_WhenOutputIs_Unicode(string message) return WriteAsyncTest(targetEncoding, message); } - [Theory] - [MemberData(nameof(WriteAsyncInputLatin))] - public Task WriteAsync_Works_WhenOutputIs_UTF7(string message) - { - Encoding targetEncoding = Encoding.UTF7; - return WriteAsyncTest(targetEncoding, message); - } - [Theory] [MemberData(nameof(WriteAsyncInputLatin))] public Task WriteAsync_Works_WhenOutputIs_WesternEuropeanEncoding(string message) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index c5c6a8603e8dff..2e50c18b785c00 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3739,4 +3739,7 @@ Unmatched value was {0}. + + Support for UTF-7 has been disabled. See {0} for more information. + diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 6f2855c237f967..f63601eae09348 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -436,6 +436,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs b/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs new file mode 100644 index 00000000000000..36fc980c2f3638 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs @@ -0,0 +1,14 @@ +// 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 +{ + internal static class Obsoletions + { + internal const string SHARED_URL_FORMAT = "https://aka.ms/dotnet-warnings/{0}"; + + internal const string SYSTEM_TEXT_ENCODING_UTF7_MESSAGE = "The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead."; + internal const string SYSTEM_TEXT_ENCODING_UTF7_DIAGID = "BCL0001"; + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs index 3f0d0350610bad..0d19a74b417d98 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization; @@ -75,6 +76,8 @@ namespace System.Text public abstract partial class Encoding : ICloneable { + private const string ENABLEUTF7_APPCONTEXT_SWITCH_NAME = "System.Text.Encoding.EnableUnsafeUTF7Encoding"; + // For netcore we use UTF8 as default encoding since ANSI isn't available private static readonly UTF8Encoding.UTF8EncodingSealed s_defaultEncoding = new UTF8Encoding.UTF8EncodingSealed(encoderShouldEmitUTF8Identifier: false); @@ -104,7 +107,7 @@ public abstract partial class Encoding : ICloneable internal const int ISO_8859_1 = 28591; // Latin1 // Special code pages - private const int CodePageUTF7 = 65000; + internal const int CodePageUTF7 = 65000; private const int CodePageUTF8 = 65001; private const int CodePageUTF32 = 12000; private const int CodePageUTF32BE = 12001; @@ -224,7 +227,6 @@ public static Encoding GetEncoding(int codepage) case CodePageBigEndian: return BigEndianUnicode; // 1201 case CodePageUTF32: return UTF32; // 12000 case CodePageUTF32BE: return BigEndianUTF32; // 12001 - case CodePageUTF7: return UTF7; // 65000 case CodePageUTF8: return UTF8; // 65001 case CodePageASCII: return ASCII; // 20127 case ISO_8859_1: return Latin1; // 28591 @@ -235,6 +237,27 @@ public static Encoding GetEncoding(int codepage) case CodePageNoThread: // 3 CP_THREAD_ACP case CodePageNoSymbol: // 42 CP_SYMBOL throw new ArgumentException(SR.Format(SR.Argument_CodepageNotSupported, codepage), nameof(codepage)); + + case CodePageUTF7: // 65000 + { + // Support for UTF-7 is disabled by default. It can be re-enabled by registering a custom + // provider (which early-exits this method before the 'switch' statement) or by using + // AppContext. If support is not enabled, we'll provide a friendly error message stating + // how the developer can re-enable it in their application. + + if (IsUTF7EncodingEnabled) + { +#pragma warning disable BCL0001 // Encoding.UTF7 property getter is obsolete + return UTF7; +#pragma warning restore BCL0001 + } + else + { + string moreInfoUrl = string.Format(CultureInfo.InvariantCulture, Obsoletions.SHARED_URL_FORMAT, Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID); + string exceptionMessage = SR.Format(SR.Encoding_UTF7_Disabled, moreInfoUrl); + throw new NotSupportedException(exceptionMessage); // matches generic "unknown code page" exception type + } + } } if (codepage < 0 || codepage > 65535) @@ -1015,8 +1038,18 @@ public virtual string GetString(byte[] bytes, int index, int count) => // Returns an encoding for the UTF-7 format. The returned encoding will be // an instance of the UTF7Encoding class. + [Obsolete(Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_MESSAGE, DiagnosticId = Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID, UrlFormat = Obsoletions.SHARED_URL_FORMAT)] public static Encoding UTF7 => UTF7Encoding.s_default; + internal static bool IsUTF7EncodingEnabled + { + get + { + AppContext.TryGetSwitch(ENABLEUTF7_APPCONTEXT_SWITCH_NAME, out bool isEnabled); + return isEnabled; + } + } + // Returns an encoding for the UTF-8 format. The returned encoding will be // an instance of the UTF8Encoding class. diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs index cc69f793d6e8f7..be0f17e20f70f8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections; +using System.Collections.Generic; using System.Diagnostics; using System.Threading; @@ -105,18 +106,23 @@ private static int InternalGetCodePageFromName(string name) // Return a list of all EncodingInfo objects describing all of our encodings internal static EncodingInfo[] GetEncodings() { - EncodingInfo[] arrayEncodingInfo = new EncodingInfo[s_mappedCodePages.Length]; + List encodingInfos = new List(s_mappedCodePages.Length); for (int i = 0; i < s_mappedCodePages.Length; i++) { - arrayEncodingInfo[i] = new EncodingInfo( + if (s_mappedCodePages[i] == Encoding.CodePageUTF7 && !Encoding.IsUTF7EncodingEnabled) + { + continue; // skip this entry + } + + encodingInfos.Add(new EncodingInfo( s_mappedCodePages[i], s_webNames[s_webNameIndices[i]..s_webNameIndices[i + 1]], GetDisplayName(s_mappedCodePages[i], i) - ); + )); } - return arrayEncodingInfo; + return encodingInfos.ToArray(); } internal static CodePageDataItem? GetCodePageDataItem(int codePage) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs index feb7a3114c30f6..5d734dea7bee7a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs @@ -27,9 +27,11 @@ public class UTF7Encoding : Encoding private const string optionalChars = "!\"#$%&*;<=>@[]^_`{|}"; +#pragma warning disable BCL0001 // Used by Encoding.UTF7 for lazy initialization // The initialization code will not be run until a static member of the class is referenced internal static readonly UTF7Encoding s_default = new UTF7Encoding(); +#pragma warning restore BCL0001 // The set of base 64 characters. private byte[] _base64Bytes; @@ -46,11 +48,13 @@ public class UTF7Encoding : Encoding private const int UTF7_CODEPAGE = 65000; + [Obsolete(Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_MESSAGE, DiagnosticId = Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID, UrlFormat = Obsoletions.SHARED_URL_FORMAT)] public UTF7Encoding() : this(false) { } + [Obsolete(Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_MESSAGE, DiagnosticId = Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID, UrlFormat = Obsoletions.SHARED_URL_FORMAT)] public UTF7Encoding(bool allowOptionals) : base(UTF7_CODEPAGE) // Set the data item. { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 4c39802764aae4..72d97269e57658 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -10204,6 +10204,7 @@ protected Encoding(int codePage, System.Text.EncoderFallback? encoderFallback, S public virtual System.ReadOnlySpan Preamble { get { throw null; } } public static System.Text.Encoding Unicode { get { throw null; } } public static System.Text.Encoding UTF32 { get { throw null; } } + [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "BCL0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public static System.Text.Encoding UTF7 { get { throw null; } } public static System.Text.Encoding UTF8 { get { throw null; } } public virtual string WebName { get { throw null; } } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index 69f4de93591a8a..98756b4cca6e31 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -240,6 +240,7 @@ + diff --git a/src/libraries/System.Runtime/tests/System/Text/EncodingTests.cs b/src/libraries/System.Runtime/tests/System/Text/EncodingTests.cs new file mode 100644 index 00000000000000..753220843c9f43 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Text/EncodingTests.cs @@ -0,0 +1,27 @@ +// 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. + +using Xunit; + +namespace System.Text.Tests +{ + public class EncodingTests + { + [Theory] + [InlineData(65000)] // UTF-7 + public void GetEncoding_ByCodePage_WithDisallowedEncoding_Throws(int codePage) + { + Assert.Throws(() => Encoding.GetEncoding(codePage)); + Assert.Throws(() => Encoding.GetEncoding(codePage, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback)); + } + + [Theory] + [InlineData("utf-7")] + public void GetEncoding_ByName_WithDisallowedEncoding_Throws(string name) + { + Assert.Throws(() => Encoding.GetEncoding(name)); + Assert.Throws(() => Encoding.GetEncoding(name, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback)); + } + } +} diff --git a/src/libraries/System.Text.Encoding.CodePages/tests/EncodingCodePages.cs b/src/libraries/System.Text.Encoding.CodePages/tests/EncodingCodePages.cs index edd6e158fdfc7d..faca9b5a5f23cd 100644 --- a/src/libraries/System.Text.Encoding.CodePages/tests/EncodingCodePages.cs +++ b/src/libraries/System.Text.Encoding.CodePages/tests/EncodingCodePages.cs @@ -447,8 +447,13 @@ private static IEnumerable> CrossplatformDefaultEncodi yield return Map(1200, "utf-16"); yield return Map(12000, "utf-32"); yield return Map(20127, "us-ascii"); - yield return Map(65000, "utf-7"); yield return Map(65001, "utf-8"); + + if (!PlatformDetection.IsNetCore) + { + // Encoding.GetEncodings() doesn't include UTF-7 in the result set as of .NET 5.0 + yield return Map(65000, "utf-7"); + } } private static KeyValuePair Map(int codePage, string webName) diff --git a/src/libraries/System.Text.Encoding.Extensions/ref/System.Text.Encoding.Extensions.cs b/src/libraries/System.Text.Encoding.Extensions/ref/System.Text.Encoding.Extensions.cs index 3f32a97fc837ac..667045fb468691 100644 --- a/src/libraries/System.Text.Encoding.Extensions/ref/System.Text.Encoding.Extensions.cs +++ b/src/libraries/System.Text.Encoding.Extensions/ref/System.Text.Encoding.Extensions.cs @@ -96,7 +96,9 @@ public UTF32Encoding(bool bigEndian, bool byteOrderMark, bool throwOnInvalidChar } public partial class UTF7Encoding : System.Text.Encoding { + [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "BCL0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public UTF7Encoding() { } + [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "BCL0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public UTF7Encoding(bool allowOptionals) { } public override bool Equals(object? value) { throw null; } [System.CLSCompliantAttribute(false)] diff --git a/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj b/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj index 7b990f30a054cb..b28d3685ecb504 100644 --- a/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj +++ b/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj @@ -4,6 +4,8 @@ true true $(NetCoreAppCurrent) + + $(NoWarn),BCL0001 @@ -78,6 +80,9 @@ + + + diff --git a/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json b/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json new file mode 100644 index 00000000000000..f24ff824948f67 --- /dev/null +++ b/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json @@ -0,0 +1,5 @@ +{ + "configProperties": { + "System.Text.Encoding.EnableUnsafeUTF7Encoding": true + } +} From 93f90b397707eba1d84f313ddb66c6676210af5b Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 24 Jun 2020 12:02:14 -0700 Subject: [PATCH 02/13] PR feedback: Remove FEATURE_UTF32 --- .../src/System/IO/Compression/ZipArchive.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs index 0738921b356b65..ed170eb696d4f9 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs @@ -369,11 +369,7 @@ private set if (value != null && (value.Equals(Encoding.BigEndianUnicode) - || value.Equals(Encoding.Unicode) -#if FEATURE_UTF32 - || value.Equals(Encoding.UTF32) -#endif // FEATURE_UTF32 - )) + || value.Equals(Encoding.Unicode))) { throw new ArgumentException(SR.EntryNameEncodingNotSupported, nameof(EntryNameEncoding)); } From cb96b40926098f9af6f72a177fcbc4ee0ba8ac22 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 24 Jun 2020 14:15:02 -0700 Subject: [PATCH 03/13] GetEncodings shouldn't return UTF-7 by default --- .../src/System/Text/EncodingTable.cs | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs index 40904f1cbc2c38..d9f107ddb98f68 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs @@ -106,20 +106,31 @@ private static int InternalGetCodePageFromName(string name) // Return a list of all EncodingInfo objects describing all of our encodings internal static EncodingInfo[] GetEncodings() { + // If UTF-7 encoding is not enabled, we adjust the return array length by -1 + // to account for the skipped EncodingInfo element. + ushort[] mappedCodePages = s_mappedCodePages; - EncodingInfo[] arrayEncodingInfo = new EncodingInfo[mappedCodePages.Length]; + EncodingInfo[] arrayEncodingInfo = new EncodingInfo[(Encoding.IsUTF7EncodingEnabled) ? mappedCodePages.Length : (mappedCodePages.Length - 1)]; string webNames = s_webNames; int[] webNameIndices = s_webNameIndices; + int arrayEncodingInfoIdx = 0; for (int i = 0; i < mappedCodePages.Length; i++) { - arrayEncodingInfo[i] = new EncodingInfo( - mappedCodePages[i], + int codePage = mappedCodePages[i]; + if (codePage == Encoding.CodePageUTF7 && !Encoding.IsUTF7EncodingEnabled) + { + continue; // skip this entry; UTF-7 is disabled + } + + arrayEncodingInfo[arrayEncodingInfoIdx++] = new EncodingInfo( + codePage, webNames[webNameIndices[i]..webNameIndices[i + 1]], - GetDisplayName(mappedCodePages[i], i) + GetDisplayName(codePage, i) ); } + Debug.Assert(arrayEncodingInfoIdx == arrayEncodingInfo.Length); return arrayEncodingInfo; } @@ -132,10 +143,18 @@ internal static EncodingInfo[] GetEncodings(Dictionary encodi for (int i = 0; i < mappedCodePages.Length; i++) { - if (!encodingInfoList.ContainsKey(mappedCodePages[i])) + int codePage = mappedCodePages[i]; + if (!encodingInfoList.ContainsKey(codePage)) { - encodingInfoList[mappedCodePages[i]] = new EncodingInfo(mappedCodePages[i], webNames[webNameIndices[i]..webNameIndices[i + 1]], - GetDisplayName(mappedCodePages[i], i)); + // If UTF-7 encoding is not enabled, don't add it to the provided dictionary instance. + // Exception: If somebody already registered a custom UTF-7 provider, the dictionary + // will already contain an entry for the UTF-7 code page key, and we'll let it go through. + + if (codePage != Encoding.CodePageUTF7 || Encoding.IsUTF7EncodingEnabled) + { + encodingInfoList[codePage] = new EncodingInfo(codePage, webNames[webNameIndices[i]..webNameIndices[i + 1]], + GetDisplayName(codePage, i)); + } } } From 660dd150edddade672544f2674a5a1aaf0797323 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 24 Jun 2020 14:17:40 -0700 Subject: [PATCH 04/13] Use LocalAppContextSwitches cached info --- .../src/System/LocalAppContextSwitches.cs | 7 +++++++ .../src/System/Text/Encoding.cs | 13 +------------ .../src/System/Text/EncodingTable.cs | 6 +++--- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/LocalAppContextSwitches.cs b/src/libraries/System.Private.CoreLib/src/System/LocalAppContextSwitches.cs index a8c2b187d15ff7..79b999e9cdbea6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/LocalAppContextSwitches.cs +++ b/src/libraries/System.Private.CoreLib/src/System/LocalAppContextSwitches.cs @@ -8,6 +8,13 @@ namespace System { internal static partial class LocalAppContextSwitches { + private static int s_enableUnsafeUTF7Encoding; + public static bool EnableUnsafeUTF7Encoding + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetCachedSwitchValue("Switch.System.Text.Encoding.EnableUnsafeUTF7Encoding", ref s_enableUnsafeUTF7Encoding); + } + private static int s_enforceJapaneseEraYearRanges; public static bool EnforceJapaneseEraYearRanges { diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs index 7007ddca26eaf0..98817a7536679e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs @@ -77,8 +77,6 @@ namespace System.Text public abstract partial class Encoding : ICloneable { - private const string ENABLEUTF7_APPCONTEXT_SWITCH_NAME = "System.Text.Encoding.EnableUnsafeUTF7Encoding"; - // For netcore we use UTF8 as default encoding since ANSI isn't available private static readonly UTF8Encoding.UTF8EncodingSealed s_defaultEncoding = new UTF8Encoding.UTF8EncodingSealed(encoderShouldEmitUTF8Identifier: false); @@ -246,7 +244,7 @@ public static Encoding GetEncoding(int codepage) // AppContext. If support is not enabled, we'll provide a friendly error message stating // how the developer can re-enable it in their application. - if (IsUTF7EncodingEnabled) + if (LocalAppContextSwitches.EnableUnsafeUTF7Encoding) { #pragma warning disable BCL0001 // Encoding.UTF7 property getter is obsolete return UTF7; @@ -1046,15 +1044,6 @@ public virtual string GetString(byte[] bytes, int index, int count) => [Obsolete(Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_MESSAGE, DiagnosticId = Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID, UrlFormat = Obsoletions.SHARED_URL_FORMAT)] public static Encoding UTF7 => UTF7Encoding.s_default; - internal static bool IsUTF7EncodingEnabled - { - get - { - AppContext.TryGetSwitch(ENABLEUTF7_APPCONTEXT_SWITCH_NAME, out bool isEnabled); - return isEnabled; - } - } - // Returns an encoding for the UTF-8 format. The returned encoding will be // an instance of the UTF8Encoding class. diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs index d9f107ddb98f68..7e4b831fba0e96 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs @@ -110,7 +110,7 @@ internal static EncodingInfo[] GetEncodings() // to account for the skipped EncodingInfo element. ushort[] mappedCodePages = s_mappedCodePages; - EncodingInfo[] arrayEncodingInfo = new EncodingInfo[(Encoding.IsUTF7EncodingEnabled) ? mappedCodePages.Length : (mappedCodePages.Length - 1)]; + EncodingInfo[] arrayEncodingInfo = new EncodingInfo[(LocalAppContextSwitches.EnableUnsafeUTF7Encoding) ? mappedCodePages.Length : (mappedCodePages.Length - 1)]; string webNames = s_webNames; int[] webNameIndices = s_webNameIndices; int arrayEncodingInfoIdx = 0; @@ -118,7 +118,7 @@ internal static EncodingInfo[] GetEncodings() for (int i = 0; i < mappedCodePages.Length; i++) { int codePage = mappedCodePages[i]; - if (codePage == Encoding.CodePageUTF7 && !Encoding.IsUTF7EncodingEnabled) + if (codePage == Encoding.CodePageUTF7 && !LocalAppContextSwitches.EnableUnsafeUTF7Encoding) { continue; // skip this entry; UTF-7 is disabled } @@ -150,7 +150,7 @@ internal static EncodingInfo[] GetEncodings(Dictionary encodi // Exception: If somebody already registered a custom UTF-7 provider, the dictionary // will already contain an entry for the UTF-7 code page key, and we'll let it go through. - if (codePage != Encoding.CodePageUTF7 || Encoding.IsUTF7EncodingEnabled) + if (codePage != Encoding.CodePageUTF7 || LocalAppContextSwitches.EnableUnsafeUTF7Encoding) { encodingInfoList[codePage] = new EncodingInfo(codePage, webNames[webNameIndices[i]..webNameIndices[i + 1]], GetDisplayName(codePage, i)); From db7fa60f421a5f1b12569dee62e244b15ebb1264 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 24 Jun 2020 14:21:34 -0700 Subject: [PATCH 05/13] BCL0001 -> MSLIB0001 --- docs/project/list-of-obsoletions.md | 2 +- src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs | 4 ++-- src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs | 4 ++-- .../System.Private.CoreLib/src/System/Obsoletions.cs | 2 +- .../System.Private.CoreLib/src/System/Text/Encoding.cs | 4 ++-- .../System.Private.CoreLib/src/System/Text/UTF7Encoding.cs | 4 ++-- src/libraries/System.Runtime/ref/System.Runtime.cs | 2 +- .../ref/System.Text.Encoding.Extensions.cs | 4 ++-- .../tests/System.Text.Encoding.Tests.csproj | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/project/list-of-obsoletions.md b/docs/project/list-of-obsoletions.md index 5083069cb799de..40e833ae20f80b 100644 --- a/docs/project/list-of-obsoletions.md +++ b/docs/project/list-of-obsoletions.md @@ -13,5 +13,5 @@ Currently the identifiers `MSLIB0001` through `MSLIB0999` are carved out for obs | Diagnostic ID | Description | | :--------------- | :---------- | -| __`MSLIB0001`__ | (Reserved for `Encoding.UTF7`.) | +| __`MSLIB0001`__ | The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead. | | __`MSLIB0002`__ | `PrincipalPermissionAttribute` is not honored by the runtime and must not be used. | diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs b/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs index a6c49f245b8dfb..7cc301b8f950c2 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs @@ -111,9 +111,9 @@ public void Encoding_ISCIIAssemese() public void Encoding_UTF7() { Debug.WriteLine("Verifying UTF7Encoding Encoding"); -#pragma warning disable BCL0001 // Encoding.UTF7 property is obsolete +#pragma warning disable MSLIB0001 // Encoding.UTF7 property is obsolete VerifyException(Encoding.UTF7, ThrowAt.Set, typeof(ArgumentException)); -#pragma warning restore BCL0001 +#pragma warning restore MSLIB0001 } [ConditionalFact(nameof(HasOneSerialPort))] diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs b/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs index 3c8740f608a778..096e2a3401da43 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs @@ -864,9 +864,9 @@ private string GenRandomNewLine(bool validAscii) private int GetUTF7EncodingBytes(char[] chars, int index, int count) { -#pragma warning disable BCL0001 // Encoding.UTF7 property is obsolete +#pragma warning disable MSLIB0001 // Encoding.UTF7 property is obsolete Encoding utf7Encoding = Encoding.UTF7; -#pragma warning restore BCL0001 +#pragma warning restore MSLIB0001 byte[] bytes = utf7Encoding.GetBytes(chars, index, count); int byteCount = bytes.Length; diff --git a/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs b/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs index 36fc980c2f3638..1fadf6483f0e34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs @@ -9,6 +9,6 @@ internal static class Obsoletions internal const string SHARED_URL_FORMAT = "https://aka.ms/dotnet-warnings/{0}"; internal const string SYSTEM_TEXT_ENCODING_UTF7_MESSAGE = "The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead."; - internal const string SYSTEM_TEXT_ENCODING_UTF7_DIAGID = "BCL0001"; + internal const string SYSTEM_TEXT_ENCODING_UTF7_DIAGID = "MSLIB0001"; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs index 98817a7536679e..bbfbdc88630568 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs @@ -246,9 +246,9 @@ public static Encoding GetEncoding(int codepage) if (LocalAppContextSwitches.EnableUnsafeUTF7Encoding) { -#pragma warning disable BCL0001 // Encoding.UTF7 property getter is obsolete +#pragma warning disable MSLIB0001 // Encoding.UTF7 property getter is obsolete return UTF7; -#pragma warning restore BCL0001 +#pragma warning restore MSLIB0001 } else { diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs index 5d734dea7bee7a..3d80fd3ad17f7a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs @@ -27,11 +27,11 @@ public class UTF7Encoding : Encoding private const string optionalChars = "!\"#$%&*;<=>@[]^_`{|}"; -#pragma warning disable BCL0001 +#pragma warning disable MSLIB0001 // Used by Encoding.UTF7 for lazy initialization // The initialization code will not be run until a static member of the class is referenced internal static readonly UTF7Encoding s_default = new UTF7Encoding(); -#pragma warning restore BCL0001 +#pragma warning restore MSLIB0001 // The set of base 64 characters. private byte[] _base64Bytes; diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 5e8e48a1e3901c..428f0cf838e6f9 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -10379,7 +10379,7 @@ protected Encoding(int codePage, System.Text.EncoderFallback? encoderFallback, S public virtual System.ReadOnlySpan Preamble { get { throw null; } } public static System.Text.Encoding Unicode { get { throw null; } } public static System.Text.Encoding UTF32 { get { throw null; } } - [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "BCL0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "MSLIB0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public static System.Text.Encoding UTF7 { get { throw null; } } public static System.Text.Encoding UTF8 { get { throw null; } } public virtual string WebName { get { throw null; } } diff --git a/src/libraries/System.Text.Encoding.Extensions/ref/System.Text.Encoding.Extensions.cs b/src/libraries/System.Text.Encoding.Extensions/ref/System.Text.Encoding.Extensions.cs index 667045fb468691..67e741cc1dfae5 100644 --- a/src/libraries/System.Text.Encoding.Extensions/ref/System.Text.Encoding.Extensions.cs +++ b/src/libraries/System.Text.Encoding.Extensions/ref/System.Text.Encoding.Extensions.cs @@ -96,9 +96,9 @@ public UTF32Encoding(bool bigEndian, bool byteOrderMark, bool throwOnInvalidChar } public partial class UTF7Encoding : System.Text.Encoding { - [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "BCL0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "MSLIB0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public UTF7Encoding() { } - [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "BCL0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead.", DiagnosticId = "MSLIB0001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public UTF7Encoding(bool allowOptionals) { } public override bool Equals(object? value) { throw null; } [System.CLSCompliantAttribute(false)] diff --git a/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj b/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj index b28d3685ecb504..f4077aa49f2736 100644 --- a/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj +++ b/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj @@ -5,7 +5,7 @@ true $(NetCoreAppCurrent) - $(NoWarn),BCL0001 + $(NoWarn),MSLIB0001 From e8acb23a149e2e0e4272c4623079831039e6ab08 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 24 Jun 2020 16:10:09 -0700 Subject: [PATCH 06/13] Update compat switch name --- .../System.Text.Encoding/tests/runtimeconfig.template.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json b/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json index f24ff824948f67..4d9fba67a9ea9e 100644 --- a/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json +++ b/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json @@ -1,5 +1,5 @@ { "configProperties": { - "System.Text.Encoding.EnableUnsafeUTF7Encoding": true + "Switch.System.Text.Encoding.EnableUnsafeUTF7Encoding": true } } From d77c36b1492da4d37c992096668a6f9ec1c3fa27 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 24 Jun 2020 16:21:31 -0700 Subject: [PATCH 07/13] Update Ports tests --- .../System/Text/EncodingExtensions.cs | 20 +++++++++++++++++++ .../tests/TestUtilities/TestUtilities.csproj | 1 + .../tests/SerialPort/Encoding.cs | 4 +--- .../tests/SerialPort/ReadTo.cs | 15 ++++---------- .../tests/SerialPort/Read_char_int_int.cs | 16 ++------------- .../tests/Support/PortsTest.cs | 5 +++++ 6 files changed, 33 insertions(+), 28 deletions(-) create mode 100644 src/libraries/Common/tests/TestUtilities/System/Text/EncodingExtensions.cs diff --git a/src/libraries/Common/tests/TestUtilities/System/Text/EncodingExtensions.cs b/src/libraries/Common/tests/TestUtilities/System/Text/EncodingExtensions.cs new file mode 100644 index 00000000000000..b2f89d0fb4b1a6 --- /dev/null +++ b/src/libraries/Common/tests/TestUtilities/System/Text/EncodingExtensions.cs @@ -0,0 +1,20 @@ +// 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 +{ + public static class EncodingExtensions + { + /// + /// Returns a value stating whether is UTF-7. + /// + /// + /// This method checks only for the code page 65000. + /// + public static bool IsUTF7Encoding(this Encoding encoding) + { + return (encoding.CodePage == 65000); + } + } +} diff --git a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj index cc22d6724e6a98..b110ae7c39ce69 100644 --- a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj +++ b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj @@ -20,6 +20,7 @@ + diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs b/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs index 7cc301b8f950c2..5f1629c9687d11 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/Encoding.cs @@ -111,9 +111,7 @@ public void Encoding_ISCIIAssemese() public void Encoding_UTF7() { Debug.WriteLine("Verifying UTF7Encoding Encoding"); -#pragma warning disable MSLIB0001 // Encoding.UTF7 property is obsolete - VerifyException(Encoding.UTF7, ThrowAt.Set, typeof(ArgumentException)); -#pragma warning restore MSLIB0001 + VerifyException(LegacyUTF7Encoding, ThrowAt.Set, typeof(ArgumentException)); } [ConditionalFact(nameof(HasOneSerialPort))] diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs b/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs index 096e2a3401da43..a4ca92f8e75a68 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs @@ -25,9 +25,6 @@ public class ReadTo : PortsTest private const int MIN_NUM_NEWLINE_CHARS = 1; private const int MAX_NUM_NEWLINE_CHARS = 5; - // The web name of Encoding.UTF7 - private const string UTF7_WEBNAME = "utf-7"; - private enum ReadDataFromEnum { NonBuffered, Buffered, BufferedAndNonBuffered }; #region Test Cases @@ -694,7 +691,7 @@ private void PerformReadOnCom1FromCom2(SerialPort com1, SerialPort com2, string int totalCharsRead; int lastIndexOfNewLine = -newLineStringLength; string expectedString; - bool isUTF7Encoding = com1.Encoding.WebName == UTF7_WEBNAME; + bool isUTF7Encoding = com1.Encoding.IsUTF7Encoding(); char[] charsToWrite = strToWrite.ToCharArray(); byte[] bytesToWrite = com1.Encoding.GetBytes(charsToWrite); @@ -808,7 +805,7 @@ private void VerifyReadToWithWriteLine(Encoding encoding, string newLine) Random rndGen = new Random(-55); StringBuilder strBldrToWrite; string strExpected; - bool isUTF7Encoding = encoding.WebName == UTF7_WEBNAME; + bool isUTF7Encoding = encoding.IsUTF7Encoding(); Debug.WriteLine("Verifying ReadTo with WriteLine encoding={0}, newLine={1}", encoding, newLine); @@ -864,14 +861,10 @@ private string GenRandomNewLine(bool validAscii) private int GetUTF7EncodingBytes(char[] chars, int index, int count) { -#pragma warning disable MSLIB0001 // Encoding.UTF7 property is obsolete - Encoding utf7Encoding = Encoding.UTF7; -#pragma warning restore MSLIB0001 - - byte[] bytes = utf7Encoding.GetBytes(chars, index, count); + byte[] bytes = LegacyUTF7Encoding.GetBytes(chars, index, count); int byteCount = bytes.Length; - while (utf7Encoding.GetCharCount(bytes, 0, byteCount) == count) + while (LegacyUTF7Encoding.GetCharCount(bytes, 0, byteCount) == count) { --byteCount; } diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs b/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs index eb360920bafcf8..7eba0e5bdbd456 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs @@ -34,9 +34,6 @@ public class Read_char_int_int : PortsTest //The maximum buffer size when an exception is not expected private const int maxBufferSize = 8; - // The web name of Encoding.UTF7 - private const string utf7WebName = "utf-7"; - public enum ReadDataFromEnum { NonBuffered, Buffered, BufferedAndNonBuffered }; #region Test Cases @@ -953,18 +950,9 @@ private void VerifyBytesFollowedByChars(Encoding encoding) Fail("ERROR!!!: Expected to read {0} chars actually read {1}", xmitCharBuffer.Length, numRead); } - if (encoding.WebName == utf7WebName) + if (encoding.IsUTF7Encoding()) { - //If UTF7Encoding is being used we might leave a - in the stream - if (com1.BytesToRead == xmitByteBuffer.Length + 1) - { - int byteRead; - - if ('-' != (char)(byteRead = com1.ReadByte())) - { - Fail("Err_29282naie Expected '-' to be left in the stream with UTF7Encoding and read {0}", byteRead); - } - } + Fail("UTF-7 encoding not expected to be passed to this test."); } if (xmitByteBuffer.Length != (numRead = com1.Read(rcvByteBuffer, 0, rcvByteBuffer.Length))) diff --git a/src/libraries/System.IO.Ports/tests/Support/PortsTest.cs b/src/libraries/System.IO.Ports/tests/Support/PortsTest.cs index 74148b20a3250b..294cce60e1dbd4 100644 --- a/src/libraries/System.IO.Ports/tests/Support/PortsTest.cs +++ b/src/libraries/System.IO.Ports/tests/Support/PortsTest.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text; using System.IO; using Legacy.Support; using Xunit; @@ -36,5 +37,9 @@ public static void Fail(string format, params object[] args) { Assert.True(false, string.Format(format, args)); } + +#pragma warning disable MSLIB0001 // Encoding.UTF7 property is obsolete + protected static Encoding LegacyUTF7Encoding => Encoding.UTF7; +#pragma warning restore MSLIB0001 } } From d4179d1d0be16648d1697ac5e3155a1bd725a697 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 24 Jun 2020 16:34:42 -0700 Subject: [PATCH 08/13] Obsoletions consts -> camel case --- .../System.Private.CoreLib/src/System/Obsoletions.cs | 6 +++--- .../System.Private.CoreLib/src/System/Text/Encoding.cs | 4 ++-- .../System.Private.CoreLib/src/System/Text/UTF7Encoding.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs b/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs index 1fadf6483f0e34..549aa39bbad4df 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Obsoletions.cs @@ -6,9 +6,9 @@ namespace System { internal static class Obsoletions { - internal const string SHARED_URL_FORMAT = "https://aka.ms/dotnet-warnings/{0}"; + internal const string SharedUrlFormat = "https://aka.ms/dotnet-warnings/{0}"; - internal const string SYSTEM_TEXT_ENCODING_UTF7_MESSAGE = "The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead."; - internal const string SYSTEM_TEXT_ENCODING_UTF7_DIAGID = "MSLIB0001"; + internal const string SystemTextEncodingUTF7Message = "The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead."; + internal const string SystemTextEncodingUTF7DiagId = "MSLIB0001"; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs index bbfbdc88630568..9343fb47c0a36a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs @@ -252,7 +252,7 @@ public static Encoding GetEncoding(int codepage) } else { - string moreInfoUrl = string.Format(CultureInfo.InvariantCulture, Obsoletions.SHARED_URL_FORMAT, Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID); + string moreInfoUrl = string.Format(CultureInfo.InvariantCulture, Obsoletions.SharedUrlFormat, Obsoletions.SystemTextEncodingUTF7DiagId); string exceptionMessage = SR.Format(SR.Encoding_UTF7_Disabled, moreInfoUrl); throw new NotSupportedException(exceptionMessage); // matches generic "unknown code page" exception type } @@ -1041,7 +1041,7 @@ public virtual string GetString(byte[] bytes, int index, int count) => // Returns an encoding for the UTF-7 format. The returned encoding will be // an instance of the UTF7Encoding class. - [Obsolete(Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_MESSAGE, DiagnosticId = Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID, UrlFormat = Obsoletions.SHARED_URL_FORMAT)] + [Obsolete(Obsoletions.SystemTextEncodingUTF7Message, DiagnosticId = Obsoletions.SystemTextEncodingUTF7DiagId, UrlFormat = Obsoletions.SharedUrlFormat)] public static Encoding UTF7 => UTF7Encoding.s_default; // Returns an encoding for the UTF-8 format. The returned encoding will be diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs index 3d80fd3ad17f7a..1aaaa992273392 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs @@ -48,13 +48,13 @@ public class UTF7Encoding : Encoding private const int UTF7_CODEPAGE = 65000; - [Obsolete(Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_MESSAGE, DiagnosticId = Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID, UrlFormat = Obsoletions.SHARED_URL_FORMAT)] + [Obsolete(Obsoletions.SystemTextEncodingUTF7Message, DiagnosticId = Obsoletions.SystemTextEncodingUTF7DiagId, UrlFormat = Obsoletions.SharedUrlFormat)] public UTF7Encoding() : this(false) { } - [Obsolete(Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_MESSAGE, DiagnosticId = Obsoletions.SYSTEM_TEXT_ENCODING_UTF7_DIAGID, UrlFormat = Obsoletions.SHARED_URL_FORMAT)] + [Obsolete(Obsoletions.SystemTextEncodingUTF7Message, DiagnosticId = Obsoletions.SystemTextEncodingUTF7DiagId, UrlFormat = Obsoletions.SharedUrlFormat)] public UTF7Encoding(bool allowOptionals) : base(UTF7_CODEPAGE) // Set the data item. { From 908b106531b4bbf17ff9bda668ef540b52e44a40 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 24 Jun 2020 16:37:37 -0700 Subject: [PATCH 09/13] Back out conflicting EncodingExtensions shared file --- .../System/Text/EncodingExtensions.cs | 20 ------------------- .../tests/TestUtilities/TestUtilities.csproj | 1 - .../tests/SerialPort/ReadTo.cs | 4 ++-- .../tests/SerialPort/Read_char_int_int.cs | 2 +- .../tests/Support/PortsTest.cs | 11 ++++++++++ 5 files changed, 14 insertions(+), 24 deletions(-) delete mode 100644 src/libraries/Common/tests/TestUtilities/System/Text/EncodingExtensions.cs diff --git a/src/libraries/Common/tests/TestUtilities/System/Text/EncodingExtensions.cs b/src/libraries/Common/tests/TestUtilities/System/Text/EncodingExtensions.cs deleted file mode 100644 index b2f89d0fb4b1a6..00000000000000 --- a/src/libraries/Common/tests/TestUtilities/System/Text/EncodingExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// 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 -{ - public static class EncodingExtensions - { - /// - /// Returns a value stating whether is UTF-7. - /// - /// - /// This method checks only for the code page 65000. - /// - public static bool IsUTF7Encoding(this Encoding encoding) - { - return (encoding.CodePage == 65000); - } - } -} diff --git a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj index b110ae7c39ce69..cc22d6724e6a98 100644 --- a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj +++ b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj @@ -20,7 +20,6 @@ - diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs b/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs index a4ca92f8e75a68..6f05b6d7154247 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/ReadTo.cs @@ -691,7 +691,7 @@ private void PerformReadOnCom1FromCom2(SerialPort com1, SerialPort com2, string int totalCharsRead; int lastIndexOfNewLine = -newLineStringLength; string expectedString; - bool isUTF7Encoding = com1.Encoding.IsUTF7Encoding(); + bool isUTF7Encoding = IsUTF7Encoding(com1.Encoding); char[] charsToWrite = strToWrite.ToCharArray(); byte[] bytesToWrite = com1.Encoding.GetBytes(charsToWrite); @@ -805,7 +805,7 @@ private void VerifyReadToWithWriteLine(Encoding encoding, string newLine) Random rndGen = new Random(-55); StringBuilder strBldrToWrite; string strExpected; - bool isUTF7Encoding = encoding.IsUTF7Encoding(); + bool isUTF7Encoding = IsUTF7Encoding(encoding); Debug.WriteLine("Verifying ReadTo with WriteLine encoding={0}, newLine={1}", encoding, newLine); diff --git a/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs b/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs index 7eba0e5bdbd456..4c1ec55496660a 100644 --- a/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs +++ b/src/libraries/System.IO.Ports/tests/SerialPort/Read_char_int_int.cs @@ -950,7 +950,7 @@ private void VerifyBytesFollowedByChars(Encoding encoding) Fail("ERROR!!!: Expected to read {0} chars actually read {1}", xmitCharBuffer.Length, numRead); } - if (encoding.IsUTF7Encoding()) + if (IsUTF7Encoding(encoding)) { Fail("UTF-7 encoding not expected to be passed to this test."); } diff --git a/src/libraries/System.IO.Ports/tests/Support/PortsTest.cs b/src/libraries/System.IO.Ports/tests/Support/PortsTest.cs index 294cce60e1dbd4..ef10226595bca4 100644 --- a/src/libraries/System.IO.Ports/tests/Support/PortsTest.cs +++ b/src/libraries/System.IO.Ports/tests/Support/PortsTest.cs @@ -41,5 +41,16 @@ public static void Fail(string format, params object[] args) #pragma warning disable MSLIB0001 // Encoding.UTF7 property is obsolete protected static Encoding LegacyUTF7Encoding => Encoding.UTF7; #pragma warning restore MSLIB0001 + + /// + /// Returns a value stating whether is UTF-7. + /// + /// + /// This method checks only for the code page 65000. + /// + internal static bool IsUTF7Encoding(Encoding encoding) + { + return (encoding.CodePage == LegacyUTF7Encoding.CodePage); + } } } From 2dc4656d3bdd4afef075a20bdc5f652da4694f07 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Thu, 25 Jun 2020 11:06:37 -0700 Subject: [PATCH 10/13] PR feedback Drop switch prefix Disallow Encoding.GetEncoding from seeing an EncodingProvider-returned UTF-7 encoding --- .../src/Resources/Strings.resx | 2 +- .../src/System/LocalAppContextSwitches.cs | 2 +- .../src/System/Text/Encoding.cs | 22 ++- .../src/System/Text/EncodingTable.cs | 7 + .../tests/System.Runtime.Tests.csproj | 3 + .../tests/System/Text/EncodingTests.cs | 152 +++++++++++++++++- .../tests/runtimeconfig.template.json | 2 +- 7 files changed, 177 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 054e18356e79e7..759cfb1366c707 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3743,7 +3743,7 @@ Unmatched value was {0}. - Support for UTF-7 has been disabled. See {0} for more information. + Support for UTF-7 is disabled. See {0} for more information. Type '{0}' returned by IDynamicInterfaceCastable does not implement the requested interface '{1}'. diff --git a/src/libraries/System.Private.CoreLib/src/System/LocalAppContextSwitches.cs b/src/libraries/System.Private.CoreLib/src/System/LocalAppContextSwitches.cs index 79b999e9cdbea6..924504aa0f1a11 100644 --- a/src/libraries/System.Private.CoreLib/src/System/LocalAppContextSwitches.cs +++ b/src/libraries/System.Private.CoreLib/src/System/LocalAppContextSwitches.cs @@ -12,7 +12,7 @@ internal static partial class LocalAppContextSwitches public static bool EnableUnsafeUTF7Encoding { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetCachedSwitchValue("Switch.System.Text.Encoding.EnableUnsafeUTF7Encoding", ref s_enableUnsafeUTF7Encoding); + get => GetCachedSwitchValue("System.Text.Encoding.EnableUnsafeUTF7Encoding", ref s_enableUnsafeUTF7Encoding); } private static int s_enforceJapaneseEraYearRanges; diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs index 9343fb47c0a36a..f294256925983a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Encoding.cs @@ -215,7 +215,7 @@ public static void RegisterProvider(EncodingProvider provider) public static Encoding GetEncoding(int codepage) { - Encoding? result = EncodingProvider.GetEncodingFromProvider(codepage); + Encoding? result = FilterDisallowedEncodings(EncodingProvider.GetEncodingFromProvider(codepage)); if (result != null) return result; @@ -271,7 +271,7 @@ public static Encoding GetEncoding(int codepage) public static Encoding GetEncoding(int codepage, EncoderFallback encoderFallback, DecoderFallback decoderFallback) { - Encoding? baseEncoding = EncodingProvider.GetEncodingFromProvider(codepage, encoderFallback, decoderFallback); + Encoding? baseEncoding = FilterDisallowedEncodings(EncodingProvider.GetEncodingFromProvider(codepage, encoderFallback, decoderFallback)); if (baseEncoding != null) return baseEncoding; @@ -295,7 +295,7 @@ public static Encoding GetEncoding(string name) // add the corresponding item in EncodingTable. // Otherwise, the code below will throw exception when trying to call // EncodingTable.GetCodePageFromName(). - return EncodingProvider.GetEncodingFromProvider(name) ?? + return FilterDisallowedEncodings(EncodingProvider.GetEncodingFromProvider(name)) ?? GetEncoding(EncodingTable.GetCodePageFromName(name)); } @@ -308,10 +308,24 @@ public static Encoding GetEncoding(string name, // add the corresponding item in EncodingTable. // Otherwise, the code below will throw exception when trying to call // EncodingTable.GetCodePageFromName(). - return EncodingProvider.GetEncodingFromProvider(name, encoderFallback, decoderFallback) ?? + return FilterDisallowedEncodings(EncodingProvider.GetEncodingFromProvider(name, encoderFallback, decoderFallback)) ?? GetEncoding(EncodingTable.GetCodePageFromName(name), encoderFallback, decoderFallback); } + // If the input encoding is forbidden (currently, only UTF-7), returns null. + // Otherwise returns the input encoding unchanged. + private static Encoding? FilterDisallowedEncodings(Encoding? encoding) + { + if (LocalAppContextSwitches.EnableUnsafeUTF7Encoding) + { + return encoding; + } + else + { + return (encoding?.CodePage == CodePageUTF7) ? null : encoding; + } + } + /// /// Get the list from the runtime and all registered encoding providers /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs index 7e4b831fba0e96..5931474d9d6f69 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs @@ -158,6 +158,13 @@ internal static EncodingInfo[] GetEncodings(Dictionary encodi } } + // Just in case a provider registered UTF-7 without the application's consent + + if (!LocalAppContextSwitches.EnableUnsafeUTF7Encoding) + { + encodingInfoList.Remove(Encoding.CodePageUTF7); // won't throw if doesn't exist + } + var result = new EncodingInfo[encodingInfoList.Count]; int j = 0; foreach (KeyValuePair pair in encodingInfoList) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index 98756b4cca6e31..9438767ab467b1 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -273,4 +273,7 @@ + + + diff --git a/src/libraries/System.Runtime/tests/System/Text/EncodingTests.cs b/src/libraries/System.Runtime/tests/System/Text/EncodingTests.cs index 753220843c9f43..1e6dcbea93f457 100644 --- a/src/libraries/System.Runtime/tests/System/Text/EncodingTests.cs +++ b/src/libraries/System.Runtime/tests/System/Text/EncodingTests.cs @@ -2,26 +2,166 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; +using System.Linq; +using Moq; using Xunit; namespace System.Text.Tests { public class EncodingTests { +#pragma warning disable MSLIB0001 // UTF7Encoding is obsolete + private static UTF7Encoding _utf7Encoding = new UTF7Encoding(); +#pragma warning restore MSLIB0001 + + public static IEnumerable DisallowedEncodings() + { + yield return new object[] { "utf-7", 65000 }; + } + [Theory] - [InlineData(65000)] // UTF-7 - public void GetEncoding_ByCodePage_WithDisallowedEncoding_Throws(int codePage) + [MemberData(nameof(DisallowedEncodings))] +#pragma warning disable xUnit1026 // Theory methods should use all of their parameters + public void GetEncoding_BuiltIn_ByCodePage_WithDisallowedEncoding_Throws(string encodingName, int codePage) +#pragma warning restore xUnit1026 // Theory methods should use all of their parameters { Assert.Throws(() => Encoding.GetEncoding(codePage)); Assert.Throws(() => Encoding.GetEncoding(codePage, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback)); } [Theory] - [InlineData("utf-7")] - public void GetEncoding_ByName_WithDisallowedEncoding_Throws(string name) + [MemberData(nameof(DisallowedEncodings))] +#pragma warning disable xUnit1026 // Theory methods should use all of their parameters + public void GetEncoding_FromProvider_ByCodePage_WithDisallowedEncoding_Throws(string encodingName, int codePage) +#pragma warning restore xUnit1026 // Theory methods should use all of their parameters + { + Mock mockEncoding = new Mock(); + mockEncoding.Setup(o => o.CodePage).Returns(codePage); + + Mock mockProvider = new Mock(); + mockProvider.Setup(o => o.GetEncoding(codePage)).Returns(mockEncoding.Object); + mockProvider.Setup(o => o.GetEncoding(codePage, It.IsAny(), It.IsAny())).Returns(mockEncoding.Object); + + ThreadStaticEncodingProvider.WithEncodingProvider(mockProvider.Object, () => + { + Assert.Throws(() => Encoding.GetEncoding(codePage)); + Assert.Throws(() => Encoding.GetEncoding(codePage, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback)); + }); + } + + [Theory] + [MemberData(nameof(DisallowedEncodings))] +#pragma warning disable xUnit1026 // Theory methods should use all of their parameters + public void GetEncoding_BuiltIn_ByEncodingName_WithDisallowedEncoding_Throws(string encodingName, int codePage) +#pragma warning restore xUnit1026 // Theory methods should use all of their parameters + { + Assert.Throws(() => Encoding.GetEncoding(encodingName)); + Assert.Throws(() => Encoding.GetEncoding(encodingName, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback)); + } + + [Theory] + [MemberData(nameof(DisallowedEncodings))] + public void GetEncoding_FromProvider_ByEncodingName_WithDisallowedEncoding_Throws(string encodingName, int codePage) + { + Mock mockEncoding = new Mock(); + mockEncoding.Setup(o => o.CodePage).Returns(codePage); + + Mock mockProvider = new Mock(); + mockProvider.Setup(o => o.GetEncoding(encodingName)).Returns(mockEncoding.Object); + mockProvider.Setup(o => o.GetEncoding(encodingName, It.IsAny(), It.IsAny())).Returns(mockEncoding.Object); + + ThreadStaticEncodingProvider.WithEncodingProvider(mockProvider.Object, () => + { + Assert.Throws(() => Encoding.GetEncoding(encodingName)); + Assert.Throws(() => Encoding.GetEncoding(encodingName, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback)); + }); + } + + [Theory] + [MemberData(nameof(DisallowedEncodings))] + public void GetEncodings_BuiltIn_DoesNotContainDisallowedEncodings(string encodingName, int codePage) + { + foreach (EncodingInfo encodingInfo in Encoding.GetEncodings()) + { + Assert.NotEqual(encodingName, encodingInfo.Name, StringComparer.OrdinalIgnoreCase); + Assert.NotEqual(codePage, encodingInfo.CodePage); + } + } + + [Theory] + [MemberData(nameof(DisallowedEncodings))] + public void GetEncodings_FromProvider_DoesNotContainDisallowedEncodings(string encodingName, int codePage) { - Assert.Throws(() => Encoding.GetEncoding(name)); - Assert.Throws(() => Encoding.GetEncoding(name, EncoderFallback.ReplacementFallback, DecoderFallback.ReplacementFallback)); + Mock mockProvider = new Mock(MockBehavior.Strict); + mockProvider.Setup(o => o.GetEncodings()).Returns( + new[] { new EncodingInfo(mockProvider.Object, codePage, encodingName, "UTF-7") }); + + ThreadStaticEncodingProvider.WithEncodingProvider(mockProvider.Object, () => + { + foreach (EncodingInfo encodingInfo in Encoding.GetEncodings()) + { + Assert.NotEqual(encodingName, encodingInfo.Name, StringComparer.OrdinalIgnoreCase); + Assert.NotEqual(codePage, encodingInfo.CodePage); + } + }); + } + + private sealed class ThreadStaticEncodingProvider : EncodingProvider + { + private static readonly object _globalRegistrationLockObj = new object(); + private static bool _globalRegistrationCompleted; + + [ThreadStatic] + private static EncodingProvider _staticInstance; + + private ThreadStaticEncodingProvider() { } + + public static void WithEncodingProvider(EncodingProvider instance, Action action) + { + EnsureProviderRegistered(); + + EncodingProvider oldInstance = _staticInstance; + try + { + _staticInstance = instance; + action(); + } + finally + { + _staticInstance = oldInstance; + } + } + + private static void EnsureProviderRegistered() + { + if (!_globalRegistrationCompleted) + { + lock (_globalRegistrationLockObj) + { + if (!_globalRegistrationCompleted) + { + Encoding.RegisterProvider(new ThreadStaticEncodingProvider()); + _globalRegistrationCompleted = true; + } + } + } + } + + public override Encoding GetEncoding(int codepage) + => _staticInstance?.GetEncoding(codepage); + + public override Encoding GetEncoding(int codepage, EncoderFallback encoderFallback, DecoderFallback decoderFallback) + => _staticInstance?.GetEncoding(codepage, encoderFallback, decoderFallback); + + public override Encoding GetEncoding(string name) + => _staticInstance?.GetEncoding(name); + + public override Encoding GetEncoding(string name, EncoderFallback encoderFallback, DecoderFallback decoderFallback) + => _staticInstance?.GetEncoding(name, encoderFallback, decoderFallback); + + public override IEnumerable GetEncodings() + => _staticInstance?.GetEncodings() ?? Enumerable.Empty(); } } } diff --git a/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json b/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json index 4d9fba67a9ea9e..f24ff824948f67 100644 --- a/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json +++ b/src/libraries/System.Text.Encoding/tests/runtimeconfig.template.json @@ -1,5 +1,5 @@ { "configProperties": { - "Switch.System.Text.Encoding.EnableUnsafeUTF7Encoding": true + "System.Text.Encoding.EnableUnsafeUTF7Encoding": true } } From 9d6811c5753d0d627d608a4d5d932aee014f43e5 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Thu, 25 Jun 2020 15:11:09 -0700 Subject: [PATCH 11/13] Add UTF-7 linker trimming option --- .../src/ILLink/ILLink.Substitutions.Shared.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml index 3af7868a176f86..522cea0c61ca2b 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml @@ -3,5 +3,8 @@ + + + From 092119ddf69cadac1463d9734fe23acb5d16c298 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 29 Jun 2020 12:12:54 -0700 Subject: [PATCH 12/13] Fix IL linker trimming value --- .../src/ILLink/ILLink.Substitutions.Shared.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml index 522cea0c61ca2b..ba59103a5b5e5a 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml @@ -4,7 +4,7 @@ - + From e9245bff81aa2346d1419c24e2f285ac3d2ca07e Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 29 Jun 2020 12:10:39 -0700 Subject: [PATCH 13/13] Suppress failing wasm tests --- src/libraries/System.Text.Encoding/tests/Encoding/Encoding.cs | 2 ++ .../tests/Encoding/EncodingGetEncodingTests.cs | 3 +++ .../tests/UTF7Encoding/UTF7EncodingEncode.cs | 1 + .../tests/UTF7Encoding/UTF7EncodingTests.cs | 1 + 4 files changed, 7 insertions(+) diff --git a/src/libraries/System.Text.Encoding/tests/Encoding/Encoding.cs b/src/libraries/System.Text.Encoding/tests/Encoding/Encoding.cs index 0cacbaa18c7b8d..703d37788f783f 100644 --- a/src/libraries/System.Text.Encoding/tests/Encoding/Encoding.cs +++ b/src/libraries/System.Text.Encoding/tests/Encoding/Encoding.cs @@ -65,6 +65,7 @@ public static void GetEncodingsTest() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/38433", TestPlatforms.Browser)] // wasm doesn't honor runtimeconfig.json [Theory] [MemberData(nameof(Encoding_TestData))] public static void VerifyCodePageAttributes(int codepage, string name, string bodyName, string headerName, bool isBrowserDisplay, @@ -81,6 +82,7 @@ public static void VerifyCodePageAttributes(int codepage, string name, string bo Assert.Equal(windowsCodePage, encoding.WindowsCodePage); } + [ActiveIssue("https://github.com/dotnet/runtime/issues/38433", TestPlatforms.Browser)] // wasm doesn't honor runtimeconfig.json [Theory] [MemberData(nameof(Normalization_TestData))] public static void NormalizationTest(int codepage, bool normalized, bool normalizedC, bool normalizedD, bool normalizedKC, bool normalizedKD) diff --git a/src/libraries/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs b/src/libraries/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs index 69b2b3894ffd75..33b006c83ed648 100644 --- a/src/libraries/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs +++ b/src/libraries/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs @@ -89,6 +89,7 @@ public CodePageMapping(string name, int codepage) new CodePageMapping("x-unicode-2-0-utf-8", 65001) }; + [ActiveIssue("https://github.com/dotnet/runtime/issues/38433", TestPlatforms.Browser)] // wasm doesn't honor runtimeconfig.json [Fact] public void TestEncodingNameAndCopdepageNumber() { @@ -99,6 +100,7 @@ public void TestEncodingNameAndCopdepageNumber() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/38433", TestPlatforms.Browser)] // wasm doesn't honor runtimeconfig.json [Fact] public void GetEncoding_EncodingName() { @@ -118,6 +120,7 @@ public void GetEncoding_EncodingName() } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/38433", TestPlatforms.Browser)] // wasm doesn't honor runtimeconfig.json [Fact] public void GetEncoding_WebName() { diff --git a/src/libraries/System.Text.Encoding/tests/UTF7Encoding/UTF7EncodingEncode.cs b/src/libraries/System.Text.Encoding/tests/UTF7Encoding/UTF7EncodingEncode.cs index 2a9503cf5ba4c9..4d7c79317d4ba7 100644 --- a/src/libraries/System.Text.Encoding/tests/UTF7Encoding/UTF7EncodingEncode.cs +++ b/src/libraries/System.Text.Encoding/tests/UTF7Encoding/UTF7EncodingEncode.cs @@ -7,6 +7,7 @@ namespace System.Text.Tests { + [ActiveIssue("https://github.com/dotnet/runtime/issues/38433", TestPlatforms.Browser)] // wasm doesn't honor runtimeconfig.json public class UTF7EncodingEncode { public static IEnumerable Encode_Basic_TestData() diff --git a/src/libraries/System.Text.Encoding/tests/UTF7Encoding/UTF7EncodingTests.cs b/src/libraries/System.Text.Encoding/tests/UTF7Encoding/UTF7EncodingTests.cs index 0935ab36a9e5f6..e46722fbed546c 100644 --- a/src/libraries/System.Text.Encoding/tests/UTF7Encoding/UTF7EncodingTests.cs +++ b/src/libraries/System.Text.Encoding/tests/UTF7Encoding/UTF7EncodingTests.cs @@ -7,6 +7,7 @@ namespace System.Text.Tests { + [ActiveIssue("https://github.com/dotnet/runtime/issues/38433", TestPlatforms.Browser)] // wasm doesn't honor runtimeconfig.json public class UTF7EncodingTests { [Fact]