# HG changeset patch # User Yuya Nishihara # Date 1437575381 -32400 # Node ID 7ed3a3c0cef18f11b57aa9fcd38e30dc8ffc6c88 # Parent cabac7dfc6214e915908912678ff8e84f5dc7488 templater: abort if infinite recursion detected while evaluation (issue4758) It would be nice if we could detect recursion at the parsing phase, but we can't because a template can refer to a keyword of the same name. For example, "rev = {rev}" is valid if rev is a keyword, and we don't know if rev is a keyword or a template while parsing. diff -r cabac7dfc621 -r 7ed3a3c0cef1 mercurial/templater.py --- a/mercurial/templater.py Fri Jan 22 16:31:50 2016 -0800 +++ b/mercurial/templater.py Wed Jul 22 23:29:41 2015 +0900 @@ -226,13 +226,22 @@ def runstring(context, mapping, data): return data +def _recursivesymbolblocker(key): + def showrecursion(**args): + raise error.Abort(_("recursive reference '%s' in template") % key) + return showrecursion + def runsymbol(context, mapping, key): v = mapping.get(key) if v is None: v = context._defaults.get(key) if v is None: + # put poison to cut recursion. we can't move this to parsing phase + # because "x = {x}" is allowed if "x" is a keyword. (issue4758) + safemapping = mapping.copy() + safemapping[key] = _recursivesymbolblocker(key) try: - v = context.process(key, mapping) + v = context.process(key, safemapping) except TemplateNotFound: v = '' if callable(v): diff -r cabac7dfc621 -r 7ed3a3c0cef1 tests/test-command-template.t --- a/tests/test-command-template.t Fri Jan 22 16:31:50 2016 -0800 +++ b/tests/test-command-template.t Wed Jul 22 23:29:41 2015 +0900 @@ -1035,6 +1035,33 @@ 1 0 +Check that recursive reference does not fall into RuntimeError (issue4758): + + common mistake: + + $ hg log -T '{changeset}\n' + abort: recursive reference 'changeset' in template + [255] + + circular reference: + + $ cat << EOF > issue4758 + > changeset = '{foo}' + > foo = '{changeset}' + > EOF + $ hg log --style ./issue4758 + abort: recursive reference 'foo' in template + [255] + + not a recursion if a keyword of the same name exists: + + $ cat << EOF > issue4758 + > changeset = '{tags % rev}' + > rev = '{rev} {tag}\n' + > EOF + $ hg log --style ./issue4758 -r tip + 8 tip + Check that {phase} works correctly on parents: $ cat << EOF > parentphase