]> Cypherpunks repositories - gostls13.git/commit
regexp: fix repeat of preferred empty match
authorRuss Cox <rsc@golang.org>
Tue, 11 May 2021 14:52:44 +0000 (10:52 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 13 May 2021 14:52:20 +0000 (14:52 +0000)
commit2a61b3c59088115245d084d5ae07dd4be5fbe1b0
treeedebf0990b16428f7da90f36c007b87e627fd16f
parentfd4631e24f53cf836a67b00e82e2159854ec31d0
regexp: fix repeat of preferred empty match

In Perl mode, (|a)* should match an empty string at the start of the
input. Instead it matches as many a's as possible.
Because (|a)+ is handled correctly, matching only an empty string,
this leads to the paradox that e* can match more text than e+
(for e = (|a)) and that e+ is sometimes different from ee*.

This is a very old bug that ultimately derives from the picture I drew
for e* in https://swtch.com/~rsc/regexp/regexp1.html. The picture is
correct for longest-match (POSIX) regexps but subtly wrong for
preferred-match (Perl) regexps in the case where e has a preferred
empty match. Pointed out by Andrew Gallant in private mail.

The current code treats e* and e+ as the same structure, with
different entry points. In the case of e* the preference list ends up
not quite in the right order, in part because the “before e” and
“after e” states are the same state. Splitting them apart fixes the
preference list, and that can be done by compiling e* as if it were
(e+)?.

Like with any bug fix, there is a very low chance of breaking a
program that accidentally depends on the buggy behavior.

RE2, Go, and Rust all have this bug, and we've all agreed to fix it,
to keep the implementations in sync.

Fixes #46123.

Change-Id: I70e742e71e0a23b626593b16ddef3c1e73b413b0
Reviewed-on: https://go-review.googlesource.com/c/go/+/318750
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
src/regexp/find_test.go
src/regexp/onepass_test.go
src/regexp/syntax/compile.go
src/regexp/syntax/prog_test.go
src/regexp/testdata/basic.dat
src/regexp/testdata/nullsubexpr.dat
src/regexp/testdata/re2-exhaustive.txt.bz2
src/regexp/testdata/re2-search.txt