EditorConfigLanguage icon indicating copy to clipboard operation
EditorConfigLanguage copied to clipboard

Catastrophic Backtracking (100% CPU + VS hang) in EditorConfigDocument.ParseAsync's _suppress Regex, caused by comma in input

Open daiplusplus opened this issue 4 years ago • 0 comments

Installed product versions

  • Visual Studio: Visual Studio 2019 v16.10.0
  • This extension: 1.17.288

Description

  • I started typing a command into an .editorconfig file and as soon as I typed a comma "," devenv.exe suddenly started using 100% CPU on all of my processor cores.
  • I attached a CLRv4 debugger and saw a load of worker threads were stuck in System.Text.RegularExpressions.RegexInterpreter.Go via EditorConfig.EditorConfigDocument.ParseAsync.

(Updated) Steps to recreate

After some digging, I found out the _suppress regex can get stuck on certain inputs. Here's a reliable repro I've made in Linqpad 6:

// Copied from https://github.com/madskristensen/EditorConfigLanguage/blob/ebec9b5d3069c9c6a0adbdcf2e642ef2d9d8317f/src/Parser/EditorConfigDocumentParser.cs
Regex suppressRegex = new Regex(@"^(?<comment>#\s*suppress\s*):?\s*(?<errors>(\w{0,5}\s*)+)$", RegexOptions.IgnoreCase);

String goodLine = @"# Suppressed because we do use antiforgery tokens as configured in Startup.cs";
Match goodMatch = suppressRegex.Match( goodLine ); // Works fine
goodMatch.Dump();

String badLine = @"# Suppressed because we do use antiforgery tokens, as configured in Startup.cs";
Match badMatch = suppressRegex.Match( badLine ); // <-- Program will get stuck here.
badMatch.Dump();

I tried it on Regex101.com on the same input data and it reported a Catastrophic Backtracking error.

(Real-life) Steps to recreate

  1. Have an editor config like this:

    root = true
    
    # All files 
    [*]
    indent_style = tab
    
    [*.csproj]
    indent_style = space
    indent_size = 2
    
    # Code files
    [*.cs]
    indent_size = 4
    insert_final_newline = true
    charset = utf-8
    
    
    # CA1055: URI return values should not be strings
    dotnet_diagnostic.CA1055.severity = silent
    # CA1056: URI properties should not be strings
    dotnet_diagnostic.CA1056.severity = silent
    
    # CA5395: Action method needs to specify the HTTP request kind explictly
    # https://github.com/dotnet/aspnetcore/issues/33102
    dotnet_diagnostic.CA5395.severity = none
    
    # CA1707: Identifiers should not contain underscores
    dotnet_diagnostic.CA1707.severity = none
    
    # CA5391: Use antiforgery tokens in ASP.NET Core MVC controllers
    dotnet_code_quality.CA5391.exclude_aspnet_core_mvc_controllerbase = true
    
  2. Manually type a new comment line underneath the # CA5391 line (and before dotnet_code_quality.CA5391):

    # Suppressed because we do use antiforgery tokens as configured in Startup.cs
    
  3. Insert a comma after "tokens" and before "as configured":

    # Suppressed because we do use antiforgery tokens, as configured in Startup.cs
    
  4. devenv.exe will now hog your CPU.

Stack traces

image

>	System.dll!System.Text.RegularExpressions.RegexInterpreter.Go()	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.RegexRunner.Scan(System.Text.RegularExpressions.Regex regex, string text, int textbeg, int textend, int textstart, int prevlen, bool quick = false, System.TimeSpan timeout)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.Regex.Run(bool quick, int prevlen, string input, int beginning, int length, int startat)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.Regex.Match(string input, int startat)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.Regex.Match(string input)	Unknown	Non-user code. Skipped loading symbols.
 	EditorConfig.dll!EditorConfig.EditorConfigDocument.ParseAsync.AnonymousMethod__26_0()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.Execute()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot = Id = 1189516, Status = Running, Method = Inspecting the state of an object in the debuggee of type System.Delegate is not supported in this context.)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()	Unknown	Non-user code. Skipped loading symbols.

and

>	System.dll!System.Text.RegularExpressions.RegexCharClass.CharInCategoryGroup(char ch, System.Globalization.UnicodeCategory chcategory = LowercaseLetter, string category = "\0\0\n\0\u0002\u0004\u0005\u0003\u0001\u0006\t\u0013\0", ref int i = 7)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.RegexCharClass.CharInCategory(char ch, string set = "\0\0\n\0\u0002\u0004\u0005\u0003\u0001\u0006\t\u0013\0", int start, int mySetLength, int myCategoryLength)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.RegexCharClass.CharInClassInternal(char ch, string set, int start, int mySetLength, int myCategoryLength)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.RegexCharClass.CharInClassRecursive(char ch, string set, int start)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.RegexCharClass.CharInClass(char ch, string set)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.RegexInterpreter.Go()	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.RegexRunner.Scan(System.Text.RegularExpressions.Regex regex, string text, int textbeg, int textend, int textstart, int prevlen, bool quick = false, System.TimeSpan timeout)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.Regex.Run(bool quick, int prevlen, string input, int beginning, int length, int startat)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.Regex.Match(string input, int startat)	Unknown	Non-user code. Skipped loading symbols.
 	System.dll!System.Text.RegularExpressions.Regex.Match(string input)	Unknown	Non-user code. Skipped loading symbols.
 	EditorConfig.dll!EditorConfig.EditorConfigDocument.ParseAsync.AnonymousMethod__26_0()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.Execute()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot = Id = 1189518, Status = Running, Method = "Void <ParseAsync>b__26_0()")	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution)	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()	Unknown	Non-user code. Skipped loading symbols.
 	mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()	Unknown	Non-user code. Skipped loading symbols.

daiplusplus avatar Jun 01 '21 05:06 daiplusplus