Compile a pattern that came from a user¶
Compile it through compile_bounded¶
use rtb_app::regex_util::compile_bounded;
let re = compile_bounded(pattern_from_config)?;
if re.is_match(line) {
// …
}
Any pattern that did not come from a string literal in your source goes through this function: config files, CLI flags, TUI input, HTTP payloads, message queues.
Know when you do not need it¶
A pattern that is a build-time literal in your own source is trusted, and
regex::Regex::new is fine — usually wrapped in a LazyLock or once_cell so it
compiles once:
static SEMVER: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^\d+\.\d+\.\d+$").expect("literal pattern"));
The distinction is where the pattern came from, not where the input came from. Matching untrusted text against a literal pattern is not a risk here.
Report the failure usefully¶
compile_bounded returns RegexCompileError, which is a miette::Diagnostic, so
propagating it with ? from a miette::Result gives a rendered diagnostic for free:
If you want to tell the user which problem they have, match on the variant:
match compile_bounded(&pattern) {
Ok(re) => { /* … */ }
Err(RegexCompileError::TooLong { len }) => {
eprintln!("that pattern is {len} bytes; the limit is 1024");
}
Err(RegexCompileError::Compile(source)) => {
eprintln!("that pattern will not compile: {source}");
}
}
Note the second arm covers two different problems: a syntax error and a pattern
whose compiled program would exceed the memory bounds. Both arrive as Compile. To
distinguish them you have to inspect the wrapped regex::Error — the enum variant
will not tell you, and the top-level message (regex failed to compile within memory
bounds) reads as a size problem even when the pattern was simply malformed.
Do not try to raise the limits¶
MAX_PATTERN_LEN, SIZE_LIMIT and DFA_SIZE_LIMIT are pub const and fixed at
1 KiB, 1 MiB and 8 MiB. There is no options struct, no builder and no per-call
override. A tool that genuinely needs different bounds has to construct its own
regex::RegexBuilder and takes on the denial-of-service surface that
compile_bounded exists to close.
The constants are public so you can quote them at the user:
use rtb_app::regex_util::MAX_PATTERN_LEN;
eprintln!("patterns are limited to {MAX_PATTERN_LEN} bytes");