RE2 rejects backreferences and lookaround, and grep fell back to
std::regex for those patterns. std::regex backtracks with no limit, so
a pattern like (x+x+)+y\1 runs in exponential time (2 s at 24 chars on
grim, 4x per 2 more) and libstdc++ recursion can overflow the stack on
long lines. A daemon grep request could pin a worker indefinitely.
Use Boost.Regex (header-only, already a dependency) for the fallback.
It is non-recursive and abandons a search after
max(N*S^2, min(N^2, cap)) + 1e5 states; the cap is 1e7 here. An
abandoned line counts as no match, and grep reports the count as
searchStats.regex_budget_exceeded. The fallback also gains lookbehind.
findNext now passes the preceding bytes as context to both engines, so
^ and \b no longer match at a resumed offset ("^a" on "aa" counted 2).
Signed-off-by: trvon <me@trevon.dev>