diff options
| author | Andrew Gerrand <adg@golang.org> | 2016-05-12 13:55:46 -0700 |
|---|---|---|
| committer | Andrew Gerrand <adg@golang.org> | 2016-05-12 22:32:30 +0000 |
| commit | eb69476c66339ca494f98e65a78d315da99a9c79 (patch) | |
| tree | 900cb75a8839cff859de0844d86c2401dc87051d /src/text/template/exec.go | |
| parent | 8f48efb31c7cdddeec7d4221174254466b0891dd (diff) | |
| download | go-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.go | 19 |
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}} |
