Skip to content

Commit a513088

Browse files
mattybbradfitz
authored andcommitted
regexp: skip backtracker for long programs
This update makes maxBacktrackLen return 0 if len(prog.Inst) > maxBacktrackProg. This prevents an attempt to backtrack against a nil bitstate. Fixes #10319 Change-Id: Icdbeb2392782ccf66f9d0a70ea57af22fb93f01b Reviewed-on: https://go-review.googlesource.com/8473 Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 957255f commit a513088

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

src/regexp/backtrack.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,30 @@ var notBacktrack *bitState = nil
4747
// maxBitStateLen returns the maximum length of a string to search with
4848
// the backtracker using prog.
4949
func maxBitStateLen(prog *syntax.Prog) int {
50+
if !shouldBacktrack(prog) {
51+
return 0
52+
}
5053
return maxBacktrackVector / len(prog.Inst)
5154
}
5255

5356
// newBitState returns a new bitState for the given prog,
5457
// or notBacktrack if the size of the prog exceeds the maximum size that
5558
// the backtracker will be run for.
5659
func newBitState(prog *syntax.Prog) *bitState {
57-
if len(prog.Inst) > maxBacktrackProg {
60+
if !shouldBacktrack(prog) {
5861
return notBacktrack
5962
}
6063
return &bitState{
6164
prog: prog,
6265
}
6366
}
6467

68+
// shouldBacktrack reports whether the program is too
69+
// long for the backtracker to run.
70+
func shouldBacktrack(prog *syntax.Prog) bool {
71+
return len(prog.Inst) <= maxBacktrackProg
72+
}
73+
6574
// reset resets the state of the backtracker.
6675
// end is the end position in the input. ncap and reqcap are the number
6776
// of the machine's capture registers and the number of user-requested

src/regexp/exec_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,3 +713,15 @@ func TestLongest(t *testing.T) {
713713
t.Errorf("longest match was %q, want %q", g, w)
714714
}
715715
}
716+
717+
// TestProgramTooLongForBacktrace tests that a regex which is too long
718+
// for the backtracker still executes properly.
719+
func TestProgramTooLongForBacktrack(t *testing.T) {
720+
longRegex := MustCompile(`(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|twentyone|twentytwo|twentythree|twentyfour|twentyfive|twentysix|twentyseven|twentyeight|twentynine|thirty|thirtyone|thirtytwo|thirtythree|thirtyfour|thirtyfive|thirtysix|thirtyseven|thirtyeight|thirtynine|forty|fortyone|fortytwo|fortythree|fortyfour|fortyfive|fortysix|fortyseven|fortyeight|fortynine|fifty|fiftyone|fiftytwo|fiftythree|fiftyfour|fiftyfive|fiftysix|fiftyseven|fiftyeight|fiftynine|sixty|sixtyone|sixtytwo|sixtythree|sixtyfour|sixtyfive|sixtysix|sixtyseven|sixtyeight|sixtynine|seventy|seventyone|seventytwo|seventythree|seventyfour|seventyfive|seventysix|seventyseven|seventyeight|seventynine|eighty|eightyone|eightytwo|eightythree|eightyfour|eightyfive|eightysix|eightyseven|eightyeight|eightynine|ninety|ninetyone|ninetytwo|ninetythree|ninetyfour|ninetyfive|ninetysix|ninetyseven|ninetyeight|ninetynine|onehundred)`)
721+
if !longRegex.MatchString("two") {
722+
t.Errorf("longRegex.MatchString(\"two\") was false, want true")
723+
}
724+
if longRegex.MatchString("xxx") {
725+
t.Errorf("longRegex.MatchString(\"xxx\") was true, want false")
726+
}
727+
}

0 commit comments

Comments
 (0)