A proposed fix for the {% embed %} error line number bug from fabpot/Twig#958

I've spent some time staring at the order of invocation when {% embed %} is
involved, the state of the call stack, and the compiler output. This commit
changes guessTemplateInfo based on the following rationale.

Given a call stack looking like this:

    #0  Twig_Error->guessTemplateInfo() called at [/Users/h2s/src/Twig/lib/Twig/Error.php:71]
    #1  Twig_Error->__construct() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:317]
    #2  Twig_Template->getContext() called at [/Users/h2s/src/Twig/lib/Twig/Environment.php(320) : eval()'d code:74]
    #3  __TwigTemplate_aee336d6e9d8c7d63204036df7919fc1_2059451906->block_c1()
    #4  call_user_func() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:133]
    #5  Twig_Template->displayBlock() called at [/Users/h2s/src/Twig/lib/Twig/Environment.php(320) : eval()'d code:20]
    #6  __TwigTemplate_c5df0c3d9cd7a9fd242778fcd97bc691->doDisplay() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:264]
    #7  Twig_Template->displayWithErrorHandling() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:238]
    #8  Twig_Template->display() called at [/Users/h2s/src/Twig/lib/Twig/Environment.php(320) : eval()'d code:66]
    #9  __TwigTemplate_aee336d6e9d8c7d63204036df7919fc1_2059451906->doDisplay() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:264]
    #10 Twig_Template->displayWithErrorHandling() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:238]
    #11 Twig_Template->display() called at [/Users/h2s/src/Twig/lib/Twig/Environment.php(320) : eval()'d code:22]
    #12 __TwigTemplate_aee336d6e9d8c7d63204036df7919fc1->doDisplay() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:264]
    #13 Twig_Template->displayWithErrorHandling() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:238]
    #14 Twig_Template->display() called at [/Users/h2s/src/Twig/lib/Twig/Template.php:249]
    #15 Twig_Template->render() called at [/Users/h2s/src/Twig/lib/Twig/Environment.php:288]

The fact that __TwigTemplate_aee336d6e9d8c7d63204036df7919fc1_2059451906 is
higher than __TwigTemplate_aee336d6e9d8c7d63204036df7919fc1 means that the error
occurred in the embedded block template. However, both of these templates return
the same value when $trace['object']->getTemplateName() is called. This means
that the "if" statement modified by this commit was returning true, allowing
$this->template to be overwritten incorrectly with the instance of
__TwigTemplate_aee336d6e9d8c7d63204036df7919fc1 despite already containing the
correct __TwigTemplate_aee336d6e9d8c7d63204036df7919fc1_2059451906 instance from
higher in the stack.

So my fix for this bug is to reject any candiate templates - even if their
templateName is a match - if their class name is a strict prefix of an
already-selected template from higher up in the call stack.
This commit is contained in:
Henry Smith
2013-07-17 07:51:52 +01:00
parent e225f8e2dd
commit 12cc0a0d0c
+7 -1
View File
@@ -186,6 +186,7 @@ class Twig_Error extends Exception
protected function guessTemplateInfo()
{
$template = null;
$templateClass = null;
if (version_compare(phpversion(), '5.3.6', '>=')) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
@@ -195,8 +196,13 @@ class Twig_Error extends Exception
foreach ($backtrace as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
if (null === $this->filename || $this->filename == $trace['object']->getTemplateName()) {
$currentClass = get_class($trace['object']);
$classNameIsPrefix = strpos($templateClass, $currentClass) === 0;
$classNameIsShorter = strlen($currentClass) < strlen($templateClass);
$isEmbedContainer = $classNameIsPrefix && $classNameIsShorter;
if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
$template = $trace['object'];
$templateClass = get_class($trace['object']);
}
}
}