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

Gregory Szorc gregory.szorc at gmail.com
Fri Jan 22 10:54:01 CST 2016



> On Jan 22, 2016, at 08:45, 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([])

Global variable can lead to false positives in multithreaded environments or when forks occur.

> +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
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> https://selenic.com/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list