[PATCH] templater: add recursive template detection (issue4758)

Kostia Balytskyi ikostia at fb.com
Fri Jan 22 10:49:19 CST 2016


This is currently implemented using global variable and I'm aware that it's not the nicest option, but it feels like in order to store this state in some proper way, the templater would have to go through a significant refactoring. If I'm missing some easy way to fix this bug, please tell me.


On 1/22/16, 4:45 PM, "Kostia Balytskyi" <ikostia at fb.com> wrote:

># HG changeset patch
># User Kostia Balytskyi <ikostia at fb.com>
># Date 1453481091 0
>#      Fri Jan 22 16:44:51 2016 +0000
># Node ID bf244ba18a2ff50783a17fecf134118921892020
># Parent  d73a5ab18015f61ac61e6e77256512fd82b03818
>templater: add recursive template detection (issue4758)
>
>When mercurial is given a recursive template it currently fails with
>'maximum recursion depth' exception. To avoid that we need to
>introduce a set of symbols currenly in resolution which would be added to
>as we go deeper in call start and removed from when we move out, just
>like the actual call stack. However, since we want to completely prohibit
>recursion, on every addition to this set we need to check whether
>it already contains the same value, in which case we have to abort.
>
>diff --git a/mercurial/templater.py b/mercurial/templater.py
>--- a/mercurial/templater.py
>+++ b/mercurial/templater.py
>@@ -760,8 +760,15 @@
> 
> stringify = templatefilters.stringify
> 
>-def _flatten(thing):
>+namesinresolution = set([])
>+def _flatten(thing, key=''):
>     '''yield a single stream from a possibly nested set of iterators'''
>+    if key and key in namesinresolution:
>+        raise error.Abort("recursive template definition")
>+
>+    if key:
>+        namesinresolution.add(key)
>+
>     if isinstance(thing, str):
>         yield thing
>     elif not util.safehasattr(thing, '__iter__'):
>@@ -778,6 +785,9 @@
>                 for j in _flatten(i):
>                     yield j
> 
>+    if key:
>+        namesinresolution.remove(key)
>+
> def unquotestring(s):
>     '''unwrap quotes'''
>     if len(s) < 2 or s[0] != s[-1]:
>@@ -824,7 +834,7 @@
>         '''Perform expansion. t is name of map element to expand.
>         mapping contains added elements for use during expansion. Is a
>         generator.'''
>-        return _flatten(runtemplate(self, mapping, self._load(t)))
>+        return _flatten(runtemplate(self, mapping, self._load(t)), t)
> 
> engines = {'default': engine}
> 
>diff --git a/tests/test-template-engine.t b/tests/test-template-engine.t
>--- a/tests/test-template-engine.t
>+++ b/tests/test-template-engine.t
>@@ -44,6 +44,10 @@
>   0 97e5f848f0936960273bbf75be6388cd0350a32b -1 0000000000000000000000000000000000000000
>   -1 0000000000000000000000000000000000000000 -1 0000000000000000000000000000000000000000
> 
>+  $ hg log -l 1 --template "{changeset}"
>+  abort: recursive template definition
>+  [255]
>+
> Fuzzing the unicode escaper to ensure it produces valid data
> 
> #if hypothesis


More information about the Mercurial-devel mailing list