From f75f2f3fcc0bf4becde65dc23297e081a8d35d1f Mon Sep 17 00:00:00 2001 From: Didier Spezia Date: Fri, 28 Aug 2015 17:36:35 +0000 Subject: [PATCH] regexp: fix slice bounds out of range panics Regular expressions involving a (x){0} term are simplified by removing this term from the expression, just before the expression is compiled. The number of subexpressions is evaluated before the simplification. The number of capture instructions in the compiled expressions is not necessarily in line with the number of subexpressions. When the ReplaceAll(String) methods are used, a number of capture slots (nmatch) is evaluated as 2*(s+1) (s being the number of subexpressions). In some case, it can be higher than the number of capture instructions evaluated at compile time, resulting in a panic when the internal slices of regexp.machine are resized to this value. Fixed by capping the number of capture slots to the number of capture instructions. I must say I do not really see the benefits of setting nmatch lower than re.prog.NumCap using this 2*(s+1) formula, so perhaps this can be further simplified. Fixes #11178 Fixes #11176 Change-Id: I21415e8ef2dd5f2721218e9a679f7f6bfb76ae9b Reviewed-on: https://go-review.googlesource.com/14013 Reviewed-by: Russ Cox --- src/regexp/all_test.go | 6 ++++++ src/regexp/regexp.go | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go index d78ae6a4cd..9448f60624 100644 --- a/src/regexp/all_test.go +++ b/src/regexp/all_test.go @@ -201,6 +201,12 @@ var replaceTests = []ReplaceTest{ // Substitution when subexpression isn't found {"(x)?", "$1", "123", "123"}, {"abc", "$1", "123", "123"}, + + // Substitutions involving a (x){0} + {"(a)(b){0}(c)", ".$1|$3.", "xacxacx", "x.a|c.x.a|c.x"}, + {"(a)(((b))){0}c", ".$1.", "xacxacx", "x.a.x.a.x"}, + {"((a(b){0}){3}){5}(h)", "y caramb$2", "say aaaaaaaaaaaaaaaah", "say ay caramba"}, + {"((a(b){0}){3}){5}h", "y caramb$2", "say aaaaaaaaaaaaaaaah", "say ay caramba"}, } var replaceLiteralTests = []ReplaceTest{ diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go index 4e4b41242a..85c070eaeb 100644 --- a/src/regexp/regexp.go +++ b/src/regexp/regexp.go @@ -482,6 +482,10 @@ func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst } else { endPos = len(src) } + if nmatch > re.prog.NumCap { + nmatch = re.prog.NumCap + } + for searchPos <= endPos { a := re.doExecute(nil, bsrc, src, searchPos, nmatch) if len(a) == 0 { -- 2.50.0