aboutsummaryrefslogtreecommitdiff
path: root/src/text/template/exec.go
diff options
context:
space:
mode:
authorAndrew Gerrand <adg@golang.org>2016-05-12 13:55:46 -0700
committerAndrew Gerrand <adg@golang.org>2016-05-12 22:32:30 +0000
commiteb69476c66339ca494f98e65a78d315da99a9c79 (patch)
tree900cb75a8839cff859de0844d86c2401dc87051d /src/text/template/exec.go
parent8f48efb31c7cdddeec7d4221174254466b0891dd (diff)
downloadgo-eb69476c66339ca494f98e65a78d315da99a9c79.tar.xz
text/template: detect pathologically recursive template invocations
Return an error message instead of eating memory and eventually triggering a stack overflow. Fixes #15618 Change-Id: I3dcf1d669104690a17847a20fbfeb6d7e39e8751 Reviewed-on: https://go-review.googlesource.com/23091 Reviewed-by: Rob Pike <r@golang.org>
Diffstat (limited to 'src/text/template/exec.go')
-rw-r--r--src/text/template/exec.go19
1 files changed, 15 insertions, 4 deletions
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index 22881c6852..8e5ad93ca6 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -15,14 +15,21 @@ import (
"text/template/parse"
)
+// maxExecDepth specifies the maximum stack depth of templates within
+// templates. This limit is only practically reached by accidentally
+// recursive template invocations. This limit allows us to return
+// an error instead of triggering a stack overflow.
+const maxExecDepth = 100000
+
// state represents the state of an execution. It's not part of the
// template so that multiple executions of the same template
// can execute in parallel.
type state struct {
- tmpl *Template
- wr io.Writer
- node parse.Node // current node, for errors
- vars []variable // push-down stack of variable values.
+ tmpl *Template
+ wr io.Writer
+ node parse.Node // current node, for errors
+ vars []variable // push-down stack of variable values.
+ depth int // the height of the stack of executing templates.
}
// variable holds the dynamic value of a variable such as $, $x etc.
@@ -363,9 +370,13 @@ func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
if tmpl == nil {
s.errorf("template %q not defined", t.Name)
}
+ if s.depth == maxExecDepth {
+ s.errorf("exceeded maximum template depth (%v)", maxExecDepth)
+ }
// Variables declared by the pipeline persist.
dot = s.evalPipeline(dot, t.Pipe)
newState := *s
+ newState.depth++
newState.tmpl = tmpl
// No dynamic scoping: template invocations inherit no variables.
newState.vars = []variable{{"$", dot}}