Live data from Hacker News

Python, Catastrophic Regular Expressions and the GIL (2013)

benfrederickson.com

31–39 of 39 posts

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#31

It really feels like they buried the lede here, as almost all discussions about catastrophic backtracking seem to do. Here's the second-to-last paragraph: > Alternatively you could switch to a regular expression engine that doesn’t exhibit this kind of behaviour. RE2 is an excellent library that uses a finite automata approach to avoid this type of catastrophic backtracking. Using this library on the same 32 characte…

> Nonetheless, every popular programming language (except Go[1])

... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1].

> So it's feasible for the engine to optimistically try to use an efficient implementation

Feasible, sure. But not easy or simple. If Python's re2 module uses RE2 by default and Python's regex engine when necessary, then it's very likely that the match offsets it reports are not coherent. RE2 aims to be mostly consistent with things like PCRE, but there are cases where it isn't.

The problem is, building a production grade FSM regex engine or a production grade backtracking regex engine are both huge engineering projects. And there are few, if any, people that know how to do both. They both have their own little specialties and there isn't a ton of crossover among implementors of regex engines.

It's one of those ideas that sounds so stupidly obvious in practice, but when you actually sit down to engineer the thing, it's quite a bit harder than you might imagine.

> (And if you are using them, then I'd argue you're shoving a bit too much logic into a regex, but that's beside the point).

This kind of ignores the fact that regexes are often the interface to something else. If you have a full blown programming language at your fingertips, it's usually not hard to work around the absence of look-around or backreferences by, say, using a second regex or something. But when all you have available to you is, say, a blacklist and you get to provide the regexes to that blacklist, then a more expressive regex syntax becomes a lot more useful. See for example people already running into problems with Discord's new feature: https://github.com/rust-lang/regex/issues/127#issuecomment-1...

Of course, as I noted, it would be very inappropriate for Discord to permit non-regular regexes here. It's borderline already by permitting any regexes at all, because even FSMs have their pathological cases, albeit, not exponential. But if it's a tool you run on your local system? Sure, look-arounds become much more useful.

To be clear, I am pro-FSM and agree with you that they should really be the default regex engine everywhere. But instead, reality is indeed inverted, with backtracking being the default (almost) everywhere. But I wanted to pipe up about a few points that I think you might have not quite captured precisely.

[1]: https://github.com/rust-lang/regex/

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#32

It really feels like they buried the lede here, as almost all discussions about catastrophic backtracking seem to do. Here's the second-to-last paragraph: > Alternatively you could switch to a regular expression engine that doesn’t exhibit this kind of behaviour. RE2 is an excellent library that uses a finite automata approach to avoid this type of catastrophic backtracking. Using this library on the same 32 characte…

> Nonetheless, every popular programming language (except Go[1]) ... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1]. > So it's feasible for the engine to optimistically try to use an efficient implementation Feasible, sure. But not easy or simple. If Python's re2 module uses RE2 by default and Python's regex engine when necessary, then it's…

> > Nonetheless, every popular programming language (except Go[1])

> ... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1].

... and Tcl (see my earlier post). You might argue that Tcl is not popular but it still has a significant following.

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#33

Earlier quoted context omitted.

> Nonetheless, every popular programming language (except Go[1]) ... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1]. > So it's feasible for the engine to optimistically try to use an efficient implementation Feasible, sure. But not easy or simple. If Python's re2 module uses RE2 by default and Python's regex engine when necessary, then it's…

> > Nonetheless, every popular programming language (except Go[1]) > ... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1]. ... and Tcl (see my earlier post). You might argue that Tcl is not popular but it still has a significant following.

... sure. I don't personally consider Tcl to be popular at present though.

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#34

The real problem is using multithreading in CPython for any set of tasks that has a nonzero chance to block one of the tasks due to a CPU-bound issue. The rule of thumb here - and I learned that the hard way - is to use async/await for anything I/O bound, and multiprocessing for anything CPU-bound.

Not really, the real problem is the exponential runtime of a badly-written regex. Multithreading in CPython is also a problem, but even if this was written in a performant language with robust multithreading support, this bug could still be amplified into a denial of service.

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#35

Earlier quoted context omitted.

> Nonetheless, every popular programming language (except Go[1]) ... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1]. > So it's feasible for the engine to optimistically try to use an efficient implementation Feasible, sure. But not easy or simple. If Python's re2 module uses RE2 by default and Python's regex engine when necessary, then it's…

> > Nonetheless, every popular programming language (except Go[1]) > ... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1]. ... and Tcl (see my earlier post). You might argue that Tcl is not popular but it still has a significant following.

I'm not a Tcl expert, but now that I think about it, I'm not sure you're correct. My recollection is that Tcl is one of the few to have a true hybrid engine. So if you use look-around or backreferences, then Tcl could provide an exponential runtime. If that's true, then Tcl would be included in "Nonetheless, every popular programming language (except Go[1]) has included an exponential backtracking regex implementation in their standard library," with perhaps a caveat or special mention. But it's still a categorically different guarantee than what, say, RE2 provides.

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#36
post #15
post #10

Why Perl version of regexps returns near-instantly for same regexp ? I tested few other on regex101.com and none of them ran longer than a millisecond or two

The article explains that: >On my laptop it takes about 20ms to do the search above with 16 characters - but by doubling the input string size to 32 characters, it takes over 12 minutes to finish. Exponential running time really does suck. I checked with 32 characters on regex101, and it says "Match 1 halted after 119986 step(s)" when you click the debug icon (click the message above the regex input box).

I tried with PHP 7.4.6 on my PC and the results were nearly instantaneous, even with the input string more than doubled to >32 chars. What's up with that?

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#37

It really feels like they buried the lede here, as almost all discussions about catastrophic backtracking seem to do. Here's the second-to-last paragraph: > Alternatively you could switch to a regular expression engine that doesn’t exhibit this kind of behaviour. RE2 is an excellent library that uses a finite automata approach to avoid this type of catastrophic backtracking. Using this library on the same 32 characte…

> Nonetheless, every popular programming language (except Go[1]) ... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1]. > So it's feasible for the engine to optimistically try to use an efficient implementation Feasible, sure. But not easy or simple. If Python's re2 module uses RE2 by default and Python's regex engine when necessary, then it's…

Thanks! All good clarifications. You're definitely right on all counts, and it was more than a bit naive of me to suggest that language/library authors "simply" have two production grade regex implementations :)

>> (And if you are using them, then I'd argue you're shoving a bit too much logic into a regex, but that's beside the point).

> This kind of ignores the fact that regexes are often the interface to something else.

I will definitely admit to using the occasional assertion or backreference in grep or sed from time to time, so you make a good point about local tools too. I suppose I was thinking more in terms of programming APIs when I said this, and so keeping the standard library FSM-based would still apply here. I'd imagine that special-purpose text munging tools which care that much, will likely have their own engines anyway.

Thanks also for your work on the regex crate. I'm still dipping my toes into Rust but I'm glad to know there's an FSM-based default regex library!

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#38
Why is the run time exponential in the length of the string of a's? It seems like it should be at most O(n^3).

2^n is the number of subsets of the string of a's with no contiguity requirements. Nothing like this number of possible matches should need to be checked. What am I missing?

Re: Python, Catastrophic Regular Expressions and the GIL (2013)

#39

Earlier quoted context omitted.

> Nonetheless, every popular programming language (except Go[1]) ... and Rust. Although Rust doesn't have a regex library in std, the official regex crate (I am its author) descends from RE2[1]. > So it's feasible for the engine to optimistically try to use an efficient implementation Feasible, sure. But not easy or simple. If Python's re2 module uses RE2 by default and Python's regex engine when necessary, then it's…

Thanks! All good clarifications. You're definitely right on all counts, and it was more than a bit naive of me to suggest that language/library authors "simply" have two production grade regex implementations :) >> (And if you are using them, then I'd argue you're shoving a bit too much logic into a regex, but that's beside the point). > This kind of ignores the fact that regexes are often the interface to something…

Indeed. It doesn't take long before look-around inside of a grep command ends up being quite convenient, sometimes even saving yourself from a much longer shell pipeline. It's why I ultimately relented and added -P/--pcre2 to ripgrep. (Its default regex engine is the Rust regex crate.)
Post reply on HN