You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Glob filter *-*-*-*-*-*-*x takes ~6 s per item against an 80-dash line (56 s with one more *-): glob matching is exponential and, unlike regex, has no timeout #131
IsGlobMatch (TextFilter/TextFilter.cs ~line 415 at c4eec7b) hands every text token to DotNet.Glob's glob.IsMatch. It is called from DoesMatchGlob for the excluded, optional and required tokens (~lines 341, 352, 363). DotNet.Glob backtracks recursively over *, so a pattern with several *s that fails near the end costs exponential time in the number of *s.
The regex path is protected by RegexMatchTimeout (~line 124), so that "a caller-supplied pattern cannot hang the calling thread". The glob path has no equivalent limit.
Reproduction (observed on net10.0, default ByWordAny)
Against a token of 40 as, the pattern "*a"×10 + "*b" took 12,071 ms, and ×12 took 84,563 ms.
Expected: a few milliseconds. A wildcard match with only * and ? can run in O(n·m), or linear with the standard two-pointer star-backtrack.
Why it matters
An 80-dash line is an ordinary markdown or log separator. Filter() pays this cost for every item and every word, typically on the UI thread and on every keystroke as the user types. A filter box over log lines can freeze the app for minutes from a pattern a user could plausibly type.
Suggested fix / acceptance criteria
Collapse consecutive *s, and evaluate globs with a non-recursive wildcard matcher (two-pointer, backtracking only to the last *). Alternatively, translate the glob to a Regex compiled with RegexOptions.NonBacktracking, or with the existing RegexMatchTimeout.
The patterns above against an 80-character dash token complete in well under 100 ms.
What's wrong
IsGlobMatch(TextFilter/TextFilter.cs~line 415 at c4eec7b) hands every text token to DotNet.Glob'sglob.IsMatch. It is called fromDoesMatchGlobfor the excluded, optional and required tokens (~lines 341, 352, 363). DotNet.Glob backtracks recursively over*, so a pattern with several*s that fails near the end costs exponential time in the number of*s.The regex path is protected by
RegexMatchTimeout(~line 124), so that "a caller-supplied pattern cannot hang the calling thread". The glob path has no equivalent limit.Reproduction (observed on net10.0, default ByWordAny)
TextFilter.IsMatch(new string('-', 80), pattern, TextFilterType.Glob):*-*-*-*-*-*x*-*-*-*-*-*-*x*-*-*-*-*-*-*-*xAgainst a token of 40
as, the pattern"*a"×10 + "*b"took 12,071 ms, and×12took 84,563 ms.Expected: a few milliseconds. A wildcard match with only
*and?can run in O(n·m), or linear with the standard two-pointer star-backtrack.Why it matters
An 80-dash line is an ordinary markdown or log separator.
Filter()pays this cost for every item and every word, typically on the UI thread and on every keystroke as the user types. A filter box over log lines can freeze the app for minutes from a pattern a user could plausibly type.Suggested fix / acceptance criteria
*s, and evaluate globs with a non-recursive wildcard matcher (two-pointer, backtracking only to the last*). Alternatively, translate the glob to aRegexcompiled withRegexOptions.NonBacktracking, or with the existingRegexMatchTimeout.*and?never match across/or\, so any item containing a slash is filtered out #114).