Mercurial > hg-stable
changeset 27940:cfe7da66f555 stable
templater: abort if infinite recursion detected while compiling
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')]
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Thu, 23 Jul 2015 23:41:29 +0900 |
parents | 7ed3a3c0cef1 |
children | 75fa75d31495 |
files | mercurial/templater.py tests/test-command-template.t |
diffstat | 2 files changed, 16 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/templater.py Wed Jul 22 23:29:41 2015 +0900 +++ b/mercurial/templater.py Thu Jul 23 23:41:29 2015 +0900 @@ -231,6 +231,9 @@ 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 @@ 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):
--- a/tests/test-command-template.t Wed Jul 22 23:29:41 2015 +0900 +++ b/tests/test-command-template.t Thu Jul 23 23:41:29 2015 +0900 @@ -1053,6 +1053,12 @@ 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