]> Cypherpunks repositories - gostls13.git/commitdiff
regexp: set b.cap[0] and b.cap[1] only when captures requested
authorMichael Matloob <matloob@google.com>
Mon, 6 Apr 2015 20:33:47 +0000 (13:33 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Fri, 17 Apr 2015 17:10:07 +0000 (17:10 +0000)
Fixes #10319

Change-Id: I96015b0e1dff30a72de11fea3837638b5c672891
Reviewed-on: https://go-review.googlesource.com/8501
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>

src/regexp/all_test.go
src/regexp/backtrack.go

index 01ea3742a8b47bf0f09ed77cf17e27160651d262..d78ae6a4cdedc85dc9a46b10d89cc9dfaa066e2f 100644 (file)
@@ -489,6 +489,17 @@ func TestOnePassCutoff(t *testing.T) {
        }
 }
 
+// Check that the same machine can be used with the standard matcher
+// and then the backtracker when there are no captures.
+func TestSwitchBacktrack(t *testing.T) {
+       re := MustCompile(`a|b`)
+       long := make([]byte, maxBacktrackVector+1)
+
+       // The following sequence of Match calls used to panic. See issue #10319.
+       re.Match(long)     // triggers standard matcher
+       re.Match(long[:1]) // triggers backtracker
+}
+
 func BenchmarkLiteral(b *testing.B) {
        x := strings.Repeat("x", 50) + "y"
        b.StopTimer()
index a387fa66acf3cb694afe0e7c972021d921b30728..fd95604fe44a944b86d055f89830fe98e5be319e 100644 (file)
@@ -36,7 +36,6 @@ type bitState struct {
 
        end     int
        cap     []int
-       reqcap  bool // whether any captures are requested
        input   input
        jobs    []job
        visited []uint32
@@ -72,12 +71,10 @@ func shouldBacktrack(prog *syntax.Prog) bool {
 }
 
 // reset resets the state of the backtracker.
-// end is the end position in the input. ncap and reqcap are the number
-// of the machine's capture registers and the number of user-requested
-// captures respectively.
-func (b *bitState) reset(end int, ncap int, reqcap int) {
+// end is the end position in the input.
+// ncap is the number of captures.
+func (b *bitState) reset(end int, ncap int) {
        b.end = end
-       b.reqcap = reqcap > 0
 
        if cap(b.jobs) == 0 {
                b.jobs = make([]job, 0, 256)
@@ -95,8 +92,10 @@ func (b *bitState) reset(end int, ncap int, reqcap int) {
                }
        }
 
-       if len(b.cap) < ncap {
+       if cap(b.cap) < ncap {
                b.cap = make([]int, ncap)
+       } else {
+               b.cap = b.cap[:ncap]
        }
        for i := range b.cap {
                b.cap[i] = -1
@@ -271,7 +270,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
                case syntax.InstMatch:
                        // We found a match. If the caller doesn't care
                        // where the match is, no point going further.
-                       if !b.reqcap {
+                       if len(b.cap) == 0 {
                                m.matched = true
                                return m.matched
                        }
@@ -279,7 +278,9 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
                        // Record best match so far.
                        // Only need to check end point, because this entire
                        // call is only considering one start position.
-                       b.cap[1] = pos
+                       if len(b.cap) > 1 {
+                               b.cap[1] = pos
+                       }
                        if !m.matched || (longest && pos > 0 && pos > m.matchcap[1]) {
                                copy(m.matchcap, b.cap)
                        }
@@ -305,7 +306,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
 }
 
 // backtrack runs a backtracking search of prog on the input starting at pos.
-func (m *machine) backtrack(i input, pos int, end int, reqcap int) bool {
+func (m *machine) backtrack(i input, pos int, end int, ncap int) bool {
        if !i.canCheckPrefix() {
                panic("backtrack called for a RuneReader")
        }
@@ -320,15 +321,18 @@ func (m *machine) backtrack(i input, pos int, end int, reqcap int) bool {
        }
 
        b := m.b
-       b.reset(end, len(m.matchcap), reqcap)
+       b.reset(end, ncap)
 
+       m.matchcap = m.matchcap[:ncap]
        for i := range m.matchcap {
                m.matchcap[i] = -1
        }
 
        // Anchored search must start at the beginning of the input
        if startCond&syntax.EmptyBeginText != 0 {
-               b.cap[0] = pos
+               if len(b.cap) > 0 {
+                       b.cap[0] = pos
+               }
                return m.tryBacktrack(b, i, uint32(m.p.Start), pos)
        }
 
@@ -349,7 +353,9 @@ func (m *machine) backtrack(i input, pos int, end int, reqcap int) bool {
                        pos += advance
                }
 
-               b.cap[0] = pos
+               if len(b.cap) > 0 {
+                       b.cap[0] = pos
+               }
                if m.tryBacktrack(b, i, uint32(m.p.Start), pos) {
                        // Match must be leftmost; done.
                        return true