diff --git a/pm/pm.go b/pm/pm.go index e5c651f9..4b15d958 100644 --- a/pm/pm.go +++ b/pm/pm.go @@ -5,8 +5,11 @@ import ( "fmt" ) -const EOS = -1 -const _UNKNOWN = -2 +const ( + EOS = -1 + _UNKNOWN = -2 + maxRecursionLevel = 100000 +) /* Error {{{ */ @@ -524,7 +527,11 @@ func compilePattern(p pattern, ps ...*iptr) []inst { // Simple recursive virtual machine based on the // "Regular Expression Matching: the Virtual Machine Approach" (https://swtch.com/~rsc/regexp/regexp2.html) -func recursiveVM(src []byte, insts []inst, pc, sp int, ms ...*MatchData) (bool, int, *MatchData) { +func recursiveVM(src []byte, insts []inst, pc, sp, recLevel int, ms ...*MatchData) (bool, int, *MatchData) { + recLevel++ + if recLevel > maxRecursionLevel { + panic(newError(_UNKNOWN, "pattern/input too complex")) + } var m *MatchData if len(ms) == 0 { m = newMatchState() @@ -549,14 +556,14 @@ redo: pc = inst.Operand1 goto redo case opSplit: - if ok, nsp, _ := recursiveVM(src, insts, inst.Operand1, sp, m); ok { + if ok, nsp, _ := recursiveVM(src, insts, inst.Operand1, sp, recLevel, m); ok { return true, nsp, m } pc = inst.Operand2 goto redo case opSave: s := m.setCapture(inst.Operand1, sp) - if ok, nsp, _ := recursiveVM(src, insts, pc+1, sp, m); ok { + if ok, nsp, _ := recursiveVM(src, insts, pc+1, sp, recLevel, m); ok { return true, nsp, m } m.restoreCapture(inst.Operand1, s) @@ -620,7 +627,7 @@ func Find(p string, src []byte, offset, limit int) (matches []*MatchData, err er insts := compilePattern(pat) matches = []*MatchData{} for sp := offset; sp <= len(src); { - ok, nsp, ms := recursiveVM(src, insts, 0, sp) + ok, nsp, ms := recursiveVM(src, insts, 0, sp, 0) sp++ if ok { if sp < nsp {