-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix output for user strings in R2RDump (#36935)
Quote user strings and escape control characters, unpaired surrogates, and other unsafe characters.
- Loading branch information
1 parent
8e6bd8c
commit cb59fba
Showing
4 changed files
with
123 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/StringExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// 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 System.Globalization; | ||
using System.Text; | ||
|
||
namespace ILCompiler.Reflection.ReadyToRun | ||
{ | ||
public static class StringBuilderExtensions | ||
{ | ||
/// <summary> | ||
/// Appends a C# string literal with the given value to the string builder. | ||
/// </summary> | ||
/// <remarks> | ||
/// This method closely follows the logic in <see cref="Microsoft.CodeAnalysis.CSharp.ObjectDisplay.FormatLiteral(string, ObjectDisplayOptions)"/> | ||
/// method in Roslyn .NET compiler; see its | ||
/// <a href="https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs">sources</a> for reference. | ||
/// </remarks> | ||
public static StringBuilder AppendEscapedString(this StringBuilder builder, string value) | ||
{ | ||
builder.Append('"'); | ||
|
||
for (int i = 0; i < value.Length; i++) | ||
{ | ||
char c = value[i]; | ||
UnicodeCategory category; | ||
|
||
// Fast check for printable ASCII characters | ||
if ((c <= 0x7e) && (c >= 0x20) || !NeedsEscaping(category = CharUnicodeInfo.GetUnicodeCategory(c))) | ||
{ | ||
if ((c == '"') || (c == '\\')) | ||
{ | ||
builder.Append(@"\"); | ||
} | ||
builder.Append(c); | ||
} | ||
else if (category == UnicodeCategory.Surrogate) | ||
{ | ||
// Check for a valid surrogate pair | ||
category = CharUnicodeInfo.GetUnicodeCategory(value, i); | ||
if (category == UnicodeCategory.Surrogate) | ||
{ | ||
// Escape an unpaired surrogate | ||
builder.Append(@"\u" + ((int)c).ToString("x4")); | ||
} | ||
else if (NeedsEscaping(category)) | ||
{ | ||
// A surrogate pair that needs to be escaped | ||
int codePoint = char.ConvertToUtf32(value, i); | ||
builder.Append(@"\U" + codePoint.ToString("x8")); | ||
i++; // Skip the already-encoded second surrogate of the pair | ||
} | ||
else | ||
{ | ||
// Copy a printable surrogate pair | ||
builder.Append(c); | ||
builder.Append(value[++i]); | ||
} | ||
} | ||
else | ||
{ | ||
string escaped = c switch | ||
{ | ||
'\0' => @"\0", | ||
'\a' => @"\a", | ||
'\b' => @"\b", | ||
'\f' => @"\f", | ||
'\n' => @"\n", | ||
'\r' => @"\r", | ||
'\t' => @"\t", | ||
'\v' => @"\v", | ||
_ => @"\u" + ((int)c).ToString("x4") | ||
}; | ||
builder.Append(escaped); | ||
} | ||
} | ||
|
||
builder.Append('"'); | ||
return builder; | ||
} | ||
|
||
/// <summary> | ||
/// Determines whether characters of the given <see cref="UnicodeCategory"/> will be represented with escape sequences. | ||
/// </summary> | ||
private static bool NeedsEscaping(UnicodeCategory category) | ||
{ | ||
switch (category) | ||
{ | ||
case UnicodeCategory.LineSeparator: | ||
case UnicodeCategory.ParagraphSeparator: | ||
case UnicodeCategory.Control: | ||
case UnicodeCategory.Surrogate: | ||
case UnicodeCategory.OtherNotAssigned: | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
public static class StringExtensions | ||
{ | ||
/// <summary> | ||
/// Returns a C# string literal with the given value. | ||
/// </summary> | ||
public static string ToEscapedString(this string value) | ||
{ | ||
return new StringBuilder(value.Length + 16).AppendEscapedString(value).ToString(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters