[PATCH 2 of 2 STABLE] templater: abort if infinite recursion detected while compilation

Yuya Nishihara yuya at tcha.org
Sat Jan 23 01:45:53 CST 2016


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1437662489 -32400
#      Thu Jul 23 23:41:29 2015 +0900
# Branch stable
# Node ID 66fd78e17ad47d30f9c540b9e10dd5b00cd1c563
# Parent  a4b3e8ef3603d01d683012266bf0e4124011df56
templater: abort if infinite recursion detected while compilation

In this case, a template is parsed recursively with no thunk for lazy
evaluation. This patch prevents recursion by putting a dummy of the same name
into a cache that will be referenced while parsing if there's a recursion.

  changeset = {files % changeset}\n
                       ~~~~~~~~~
                        = [(_runrecursivesymbol, 'changeset')]

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -231,6 +231,9 @@ def _recursivesymbolblocker(key):
         raise error.Abort(_("recursive reference '%s' in template") % key)
     return showrecursion
 
+def _runrecursivesymbol(context, mapping, key):
+    raise error.Abort(_("recursive reference '%s' in template") % key)
+
 def runsymbol(context, mapping, key):
     v = mapping.get(key)
     if v is None:
@@ -826,7 +829,13 @@ class engine(object):
     def _load(self, t):
         '''load, parse, and cache a template'''
         if t not in self._cache:
-            self._cache[t] = compiletemplate(self._loader(t), self)
+            # put poison to cut recursion while compiling 't'
+            self._cache[t] = [(_runrecursivesymbol, t)]
+            try:
+                self._cache[t] = compiletemplate(self._loader(t), self)
+            except: # re-raises
+                del self._cache[t]
+                raise
         return self._cache[t]
 
     def process(self, t, mapping):
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -1053,6 +1053,12 @@ Check that recursive reference does not 
   abort: recursive reference 'foo' in template
   [255]
 
+ buildmap() -> gettemplate(), where no thunk was made:
+
+  $ hg log -T '{files % changeset}\n'
+  abort: recursive reference 'changeset' in template
+  [255]
+
  not a recursion if a keyword of the same name exists:
 
   $ cat << EOF > issue4758


More information about the Mercurial-devel mailing list