From d592c0557513f6083439eb18530333f36aebf7c4 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 2 Oct 2021 19:42:48 +0100 Subject: [PATCH 1/3] regex: patterns with no alternates are one-pass Check whether a regex has any 'alt' instructions before rejecting it. --- src/regexp/onepass.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/regexp/onepass.go b/src/regexp/onepass.go index 53cbd958394120..f0bfa0de7359a6 100644 --- a/src/regexp/onepass.go +++ b/src/regexp/onepass.go @@ -465,12 +465,19 @@ func compileOnePass(prog *syntax.Prog) (p *onePassProg) { syntax.EmptyOp(prog.Inst[prog.Start].Arg)&syntax.EmptyBeginText != syntax.EmptyBeginText { return nil } - // every instruction leading to InstMatch must be EmptyEndText + hasAlt := false + for _, inst := range prog.Inst { + if inst.Op == syntax.InstAlt || inst.Op == syntax.InstAltMatch { + hasAlt = true + } + } + // If we have alternates, every instruction leading to InstMatch must be EmptyEndText. + // Also, any match on empty text must be $. for _, inst := range prog.Inst { opOut := prog.Inst[inst.Out].Op switch inst.Op { default: - if opOut == syntax.InstMatch { + if opOut == syntax.InstMatch && hasAlt { return nil } case syntax.InstAlt, syntax.InstAltMatch: From 7310f43095ac1debf1a1ca6d2fc6bf1f86b1f4a4 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 9 Oct 2021 10:49:16 +0100 Subject: [PATCH 2/3] Early exit from loop --- src/regexp/onepass.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/regexp/onepass.go b/src/regexp/onepass.go index f0bfa0de7359a6..96e360661b9aa9 100644 --- a/src/regexp/onepass.go +++ b/src/regexp/onepass.go @@ -469,6 +469,7 @@ func compileOnePass(prog *syntax.Prog) (p *onePassProg) { for _, inst := range prog.Inst { if inst.Op == syntax.InstAlt || inst.Op == syntax.InstAltMatch { hasAlt = true + break } } // If we have alternates, every instruction leading to InstMatch must be EmptyEndText. From e9e0c29b7448c8ab7cb203c1ed58766dc5d91456 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 11 Oct 2021 21:20:40 +0100 Subject: [PATCH 3/3] Add test to check additional onepass regexps --- src/regexp/onepass_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/regexp/onepass_test.go b/src/regexp/onepass_test.go index 3f44dc7b150533..70eba1f577a9f8 100644 --- a/src/regexp/onepass_test.go +++ b/src/regexp/onepass_test.go @@ -142,6 +142,7 @@ var onePassTests = []struct { {`^(?:(a)|(?:a*))$`, false}, {`^(?:(?:(?:.(?:$))?))$`, true}, {`^abcd$`, true}, + {`^abcd`, true}, {`^(?:(?:a{0,})*?)$`, false}, {`^(?:(?:a+)*)$`, true}, {`^(?:(?:a|(?:aa)))$`, true}, @@ -154,6 +155,7 @@ var onePassTests = []struct { {`^(?:(?:aa)|a)$`, true}, {`^[a-c]*`, false}, {`^...$`, true}, + {`^...`, true}, {`^(?:a|(?:aa))$`, true}, {`^a((b))c$`, true}, {`^a.[l-nA-Cg-j]?e$`, true},