mirror of
https://github.com/golang/go
synced 2024-11-23 20:00:04 -07:00
regexp/syntax: don't waste time checking for one pass algorithm
The code recurs very deeply in cases like (?:x{1,1000}){1,1000} Since if much time is spent checking whether one pass is possible, it's not worth doing at all, a simple fix is proposed: Stop if the check takes too long. To do this, we simply avoid machines with >1000 instructions. Benchmarks show a percent or less change either way, effectively zero. Fixes #7608. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/92290043
This commit is contained in:
parent
5bc1cef869
commit
f54f790a77
@ -473,6 +473,11 @@ func TestSplit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// This ran out of stack before issue 7608 was fixed.
|
||||
func TestOnePassCutoff(t *testing.T) {
|
||||
MustCompile(`^(?:x{1,1000}){1,1000}$`)
|
||||
}
|
||||
|
||||
func BenchmarkLiteral(b *testing.B) {
|
||||
x := strings.Repeat("x", 50) + "y"
|
||||
b.StopTimer()
|
||||
@ -588,6 +593,7 @@ func BenchmarkOnePassShortA(b *testing.B) {
|
||||
re.Match(x)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNotOnePassShortA(b *testing.B) {
|
||||
b.StopTimer()
|
||||
x := []byte("abcddddddeeeededd")
|
||||
@ -597,6 +603,7 @@ func BenchmarkNotOnePassShortA(b *testing.B) {
|
||||
re.Match(x)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOnePassShortB(b *testing.B) {
|
||||
b.StopTimer()
|
||||
x := []byte("abcddddddeeeededd")
|
||||
@ -606,6 +613,7 @@ func BenchmarkOnePassShortB(b *testing.B) {
|
||||
re.Match(x)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNotOnePassShortB(b *testing.B) {
|
||||
b.StopTimer()
|
||||
x := []byte("abcddddddeeeededd")
|
||||
@ -615,6 +623,7 @@ func BenchmarkNotOnePassShortB(b *testing.B) {
|
||||
re.Match(x)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOnePassLongPrefix(b *testing.B) {
|
||||
b.StopTimer()
|
||||
x := []byte("abcdefghijklmnopqrstuvwxyz")
|
||||
@ -624,6 +633,7 @@ func BenchmarkOnePassLongPrefix(b *testing.B) {
|
||||
re.Match(x)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOnePassLongNotPrefix(b *testing.B) {
|
||||
b.StopTimer()
|
||||
x := []byte("abcdefghijklmnopqrstuvwxyz")
|
||||
|
@ -600,6 +600,11 @@ func (p runeSlice) Sort() {
|
||||
// onepass Prog, the Prog syntax.NotOnePass is returned. makeOnePass is recursive
|
||||
// to the size of the Prog
|
||||
func (p *Prog) makeOnePass() *Prog {
|
||||
// If the machine is very long, it's not worth the time to check if we can use one pass.
|
||||
if len(p.Inst) >= 1000 {
|
||||
return NotOnePass
|
||||
}
|
||||
|
||||
var (
|
||||
instQueue = newQueue(len(p.Inst))
|
||||
visitQueue = newQueue(len(p.Inst))
|
||||
|
Loading…
Reference in New Issue
Block a user