Skip to content

Commit 485f348

Browse files
matloobbradfitz
authored andcommitted
regexp: set b.cap[0] and b.cap[1] only when captures requested
Fixes #10319 Change-Id: I96015b0e1dff30a72de11fea3837638b5c672891 Reviewed-on: https://go-review.googlesource.com/8501 Reviewed-by: Russ Cox <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]>
1 parent 92189a2 commit 485f348

File tree

2 files changed

+30
-13
lines changed

2 files changed

+30
-13
lines changed

src/regexp/all_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,17 @@ func TestOnePassCutoff(t *testing.T) {
489489
}
490490
}
491491

492+
// Check that the same machine can be used with the standard matcher
493+
// and then the backtracker when there are no captures.
494+
func TestSwitchBacktrack(t *testing.T) {
495+
re := MustCompile(`a|b`)
496+
long := make([]byte, maxBacktrackVector+1)
497+
498+
// The following sequence of Match calls used to panic. See issue #10319.
499+
re.Match(long) // triggers standard matcher
500+
re.Match(long[:1]) // triggers backtracker
501+
}
502+
492503
func BenchmarkLiteral(b *testing.B) {
493504
x := strings.Repeat("x", 50) + "y"
494505
b.StopTimer()

src/regexp/backtrack.go

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ type bitState struct {
3636

3737
end int
3838
cap []int
39-
reqcap bool // whether any captures are requested
4039
input input
4140
jobs []job
4241
visited []uint32
@@ -72,12 +71,10 @@ func shouldBacktrack(prog *syntax.Prog) bool {
7271
}
7372

7473
// reset resets the state of the backtracker.
75-
// end is the end position in the input. ncap and reqcap are the number
76-
// of the machine's capture registers and the number of user-requested
77-
// captures respectively.
78-
func (b *bitState) reset(end int, ncap int, reqcap int) {
74+
// end is the end position in the input.
75+
// ncap is the number of captures.
76+
func (b *bitState) reset(end int, ncap int) {
7977
b.end = end
80-
b.reqcap = reqcap > 0
8178

8279
if cap(b.jobs) == 0 {
8380
b.jobs = make([]job, 0, 256)
@@ -95,8 +92,10 @@ func (b *bitState) reset(end int, ncap int, reqcap int) {
9592
}
9693
}
9794

98-
if len(b.cap) < ncap {
95+
if cap(b.cap) < ncap {
9996
b.cap = make([]int, ncap)
97+
} else {
98+
b.cap = b.cap[:ncap]
10099
}
101100
for i := range b.cap {
102101
b.cap[i] = -1
@@ -271,15 +270,17 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
271270
case syntax.InstMatch:
272271
// We found a match. If the caller doesn't care
273272
// where the match is, no point going further.
274-
if !b.reqcap {
273+
if len(b.cap) == 0 {
275274
m.matched = true
276275
return m.matched
277276
}
278277

279278
// Record best match so far.
280279
// Only need to check end point, because this entire
281280
// call is only considering one start position.
282-
b.cap[1] = pos
281+
if len(b.cap) > 1 {
282+
b.cap[1] = pos
283+
}
283284
if !m.matched || (longest && pos > 0 && pos > m.matchcap[1]) {
284285
copy(m.matchcap, b.cap)
285286
}
@@ -305,7 +306,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
305306
}
306307

307308
// backtrack runs a backtracking search of prog on the input starting at pos.
308-
func (m *machine) backtrack(i input, pos int, end int, reqcap int) bool {
309+
func (m *machine) backtrack(i input, pos int, end int, ncap int) bool {
309310
if !i.canCheckPrefix() {
310311
panic("backtrack called for a RuneReader")
311312
}
@@ -320,15 +321,18 @@ func (m *machine) backtrack(i input, pos int, end int, reqcap int) bool {
320321
}
321322

322323
b := m.b
323-
b.reset(end, len(m.matchcap), reqcap)
324+
b.reset(end, ncap)
324325

326+
m.matchcap = m.matchcap[:ncap]
325327
for i := range m.matchcap {
326328
m.matchcap[i] = -1
327329
}
328330

329331
// Anchored search must start at the beginning of the input
330332
if startCond&syntax.EmptyBeginText != 0 {
331-
b.cap[0] = pos
333+
if len(b.cap) > 0 {
334+
b.cap[0] = pos
335+
}
332336
return m.tryBacktrack(b, i, uint32(m.p.Start), pos)
333337
}
334338

@@ -349,7 +353,9 @@ func (m *machine) backtrack(i input, pos int, end int, reqcap int) bool {
349353
pos += advance
350354
}
351355

352-
b.cap[0] = pos
356+
if len(b.cap) > 0 {
357+
b.cap[0] = pos
358+
}
353359
if m.tryBacktrack(b, i, uint32(m.p.Start), pos) {
354360
// Match must be leftmost; done.
355361
return true

0 commit comments

Comments
 (0)