Regex: don't overflow the stack on long lines
libstdc++'s std::regex matcher recurses about once per matched character, so '.*', 'a+' or '(a|b)*' on a line of a few tens of thousands of characters (minified JS/JSON) overflowed the 8 MiB stack and crashed the editor from the regex search prompt or regex replace. Regex search and regex replace now run their matching on a worker thread with a 1 GiB reserved stack (RunWithLargeStack; the caller waits, so nothing is shared concurrently). Renderers skip regex match highlighting on lines over 10,000 bytes. Catastrophic backtracking (e.g. (a*)*b) is still possible: std::regex has no time limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
// RegexGuard.h - keep std::regex from overflowing the stack
|
||||
//
|
||||
// libstdc++'s std::regex matcher recurses roughly once per character of a
|
||||
// match, so a pattern such as ".*" or "a+" on a line of a few tens of
|
||||
// thousands of characters (minified JS/JSON) overflows a default 8 MiB
|
||||
// stack and crashes the editor.
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
namespace kte {
|
||||
// Renderers highlight regex matches only on lines up to this many bytes;
|
||||
// longer lines are drawn without match highlighting.
|
||||
constexpr std::size_t kRegexRenderLineLimit = 10000;
|
||||
|
||||
// Run fn to completion on a thread with a large stack (address space is
|
||||
// reserved, pages are committed only as used), so regex work over long lines
|
||||
// cannot overflow. If such a thread cannot be created, fn runs on the calling
|
||||
// thread. Exceptions thrown by fn are rethrown to the caller.
|
||||
void RunWithLargeStack(const std::function<void()> &fn);
|
||||
} // namespace kte
|
||||
Reference in New Issue
Block a user