Regex Engines: Backtracking vs. Finite Automata
A backtracking regex engine tries one path at a time, which can be fast but also exponentially slow. A finite-automata engine (like Go's) checks all paths at once, guaranteeing linear time. The footgun is using a backtracking engine on untrusted user input.
WHY IT EXISTS Regular expressions are powerful but can be dangerously slow. A seemingly simple pattern against a crafted input can cause some engines to run for seconds, minutes, or even hours, creating a denial-of-service vulnerability. This happens because the engine's strategy for finding a match can lead to an exponential number of steps.
THE MENTAL MODEL An engine's strategy determines its performance. A backtracking engine (like those in Python, Perl, and PCRE) is an optimist: it tries one possible match path, and if it fails, it "backtracks" to try another. A finite-automata engine (like Google's RE2, used in Go and Rust) is a pessimist: it considers all possible matches simultaneously in a single pass.
HOW IT WORKS The backtracking engine's optimism can make it fast for simple cases where the first path works. But for complex patterns with many alternatives or nested quantifiers, a malicious input can force it to explore an exponential number of paths. This is called "catastrophic backtracking." A finite-automata engine builds a state machine where each input character transitions it to a new set of possible states. Since it never backtracks, its runtime is guaranteed to be linear in the length of the input string, regardless of the pattern's complexity.
WHEN TO USE IT Use a finite-automata engine (like Go's default, or Rust's regex crate) whenever you're processing a regular expression from an untrusted source, like a user search query or a web form validation. Its primary guarantee is safety: the match time is predictable and won't crash your server. It is the correct choice for production systems prioritizing stability and security over niche features.
WHEN NOT TO USE IT Backtracking engines are not inherently bad; they represent a different trade-off. They often support advanced features like backreferences and lookarounds, which are difficult or impossible to implement in a pure finite-automata engine with linear-time guarantees. If you absolutely need those features and you completely control the regex pattern and its inputs, a backtracking engine may be suitable.
ONE CANONICAL EXAMPLE Google's RE2 library was designed explicitly to handle regexes from untrusted users safely. It guarantees linear time performance and has configurable memory limits, preventing Regular Expression Denial of Service (ReDoS) attacks. This philosophy is why languages like Go and Rust adopted this model for their standard regex libraries, prioritizing production safety over feature parity with older engines like PCRE.
Read the original → github.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.