Skip to content

Commit

Permalink
Fixes microsoft#485. Added a timeout to NegatableTypeOrMemberReferenc…
Browse files Browse the repository at this point in the history
…eRegex and MemberReferenceRegex to prevent CPU hang when given input that can cause expensive regex backtracking.
  • Loading branch information
bluetarpmedia committed Jun 28, 2021
1 parent a0ab9d8 commit 15fb735
Showing 1 changed file with 24 additions and 6 deletions.
30 changes: 24 additions & 6 deletions src/Microsoft.VisualStudio.Threading.Analyzers/CommonInterest.cs
Expand Up @@ -63,9 +63,11 @@ internal static class CommonInterest

private const RegexOptions FileNamePatternRegexOptions = RegexOptions.IgnoreCase | RegexOptions.Singleline;

private static readonly Regex NegatableTypeOrMemberReferenceRegex = new Regex(@"^(?<negated>!)?\[(?<typeName>[^\[\]\:]+)+\](?:\:\:(?<memberName>\S+))?\s*$", RegexOptions.Singleline | RegexOptions.CultureInvariant);
private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromMilliseconds(100); // Prevent expensive CPU hang in Regex.Match if backtracking occurs due to pathological input (see #485).

private static readonly Regex MemberReferenceRegex = new Regex(@"^\[(?<typeName>[^\[\]\:]+)+\]::(?<memberName>\S+)\s*$", RegexOptions.Singleline | RegexOptions.CultureInvariant);
private static readonly Regex NegatableTypeOrMemberReferenceRegex = new Regex(@"^(?<negated>!)?\[(?<typeName>[^\[\]\:]+)+\](?:\:\:(?<memberName>\S+))?\s*$", RegexOptions.Singleline | RegexOptions.CultureInvariant, RegexMatchTimeout);

private static readonly Regex MemberReferenceRegex = new Regex(@"^\[(?<typeName>[^\[\]\:]+)+\]::(?<memberName>\S+)\s*$", RegexOptions.Singleline | RegexOptions.CultureInvariant, RegexMatchTimeout);

/// <summary>
/// An array with '.' as its only element.
Expand All @@ -84,8 +86,16 @@ internal static IEnumerable<TypeMatchSpec> ReadTypesAndMembers(AnalyzerOptions a
{
foreach (string line in ReadAdditionalFiles(analyzerOptions, fileNamePattern, cancellationToken))
{
Match match = NegatableTypeOrMemberReferenceRegex.Match(line);
if (!match.Success)
Match? match = null;
try
{
match = NegatableTypeOrMemberReferenceRegex.Match(line);
}
catch (RegexMatchTimeoutException)
{
}

if (match == null || !match.Success)
{
throw new InvalidOperationException($"Parsing error on line: {line}");
}
Expand Down Expand Up @@ -175,8 +185,16 @@ internal static IEnumerable<string> ReadLinesFromAdditionalFile(SourceText text)

internal static QualifiedMember ParseAdditionalFileMethodLine(string line)
{
Match match = MemberReferenceRegex.Match(line);
if (!match.Success)
Match? match = null;
try
{
match = MemberReferenceRegex.Match(line);
}
catch (RegexMatchTimeoutException)
{
}

if (match == null || !match.Success)
{
throw new InvalidOperationException($"Parsing error on line: {line}");
}
Expand Down

0 comments on commit 15fb735

Please sign in to comment.