Skip to content

fix(scanner): reject invalid regexes at compile time - #27

Merged
gwillem merged 2 commits into
mainfrom
fix/reject-invalid-regex
Sep 28, 2026
Merged

gwillem merged 2 commits into
mainfrom
fix/reject-invalid-regex

Conversation

@gwillem

@gwillem gwillem commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Lazy regex compilation (9dd9581) dropped the compile-time error for invalid regexes. A pattern RE2 rejects, such as a repetition above 1000, now compiles without error and silently never matches, and SkipInvalidRegex no longer does what its doc says.

compileRegex now calls checkRegex on the final pattern, which covers the {,N} rewrite and hex strings:

  1. Parse with regexp/syntax (fast path, RE2 syntax including the repetition limit).
  2. Only if that fails, compile with the configured RegexCompiler and report its error. Go syntax is stricter than RE2 in Latin-1 mode (raw bytes 0x80-0xFF, \C), and a custom compiler may accept more, so the real compiler has the final say.

The go-re2 compile for valid patterns stays lazy.

Performance

Compile on the ecomscan-signatures ruleset (26,739 rules, 1,150 regex patterns), 10 interleaved runs each, benchstat:

main this PR delta
sec/op 1.444 ±6% 1.378 ±8% ~ (p=0.684)
B/op 331.9 MiB 334.4 MiB +0.76%
allocs/op 5.022M 5.059M +0.74%
  • Parsing all 1,150 patterns takes ~4 ms, vs ~250 ms for an eager go-re2 compile. That is below the run-to-run noise of Compile.
  • None of the 1,150 patterns reaches the compiler fallback.
  • The extra allocations are the discarded parse trees; retained memory is unchanged.
  • The scan path is untouched.
  • With SkipInvalidRegex, an invalid regex is no longer registered, so its atoms stay out of the Aho-Corasick automaton.

Out of scope

extractAtoms reads \C as a literal C (atom abcdCfgh for abcd\Cfgh), so such a regex compiles but can never match. This is unchanged from main; the test only asserts that it compiles.

Lazy regex compilation (9dd9581) dropped the compile-time error for
invalid regexes. A pattern RE2 rejects, such as a repetition above
1000, now compiles without error and silently never matches, and
SkipInvalidRegex no longer does what its doc says.

Check the final RE2 pattern with regexp/syntax in compileRegex. It
covers the {,N} rewrite and hex strings, costs ~4ms for 1,140
regexes (vs ~250ms for a go-re2 compile), and keeps the go-re2
compile lazy.
regexp/syntax is stricter than RE2 in Latin-1 mode: it rejects raw
bytes 0x80-0xFF and \C, and ignores a custom RegexCompiler. Such
patterns compiled and matched before and would now fail Compile, or
be silently dropped under SkipInvalidRegex. Keep the parse as the
fast path and confirm any rejection with the configured compiler.

@danslo danslo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@gwillem
gwillem merged commit f23835c into main Sep 28, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants