mirror of
https://github.com/twigphp/Twig.git
synced 2026-10-02 01:47:10 +00:00
Stop the escaping safe analysis from retaining every analyzed node
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# 3.30.0 (2026-XX-XX)
|
||||
|
||||
* Fix the escaping safe analysis retaining every compiled template node for the lifetime of the environment
|
||||
* Fix `IntlExtension` letting the pattern derived from a date formatter prototype override an explicit locale
|
||||
* Fix `IntlExtension` not honoring the locale of a date formatter prototype configured with no date and time styles
|
||||
* Speed up macro calls
|
||||
|
||||
@@ -29,9 +29,17 @@ use Twig\Node\Node;
|
||||
*/
|
||||
final class SafeAnalysisNodeVisitor implements NodeVisitorInterface
|
||||
{
|
||||
private $data = [];
|
||||
/**
|
||||
* @var \WeakMap<Node, array>
|
||||
*/
|
||||
private \WeakMap $data;
|
||||
private $safeVars = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->data = new \WeakMap();
|
||||
}
|
||||
|
||||
public function setSafeVars(array $safeVars): void
|
||||
{
|
||||
$this->safeVars = $safeVars;
|
||||
@@ -42,47 +50,23 @@ final class SafeAnalysisNodeVisitor implements NodeVisitorInterface
|
||||
*/
|
||||
public function getSafe(Node $node)
|
||||
{
|
||||
$hash = spl_object_id($node);
|
||||
if (!isset($this->data[$hash])) {
|
||||
return [];
|
||||
$safe = $this->data[$node] ?? [];
|
||||
|
||||
if (\in_array('html_attr', $safe, true)) {
|
||||
$safe[] = 'html';
|
||||
$safe[] = 'html_attr_relaxed';
|
||||
}
|
||||
|
||||
foreach ($this->data[$hash] as $bucket) {
|
||||
if ($bucket['key'] !== $node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (\in_array('html_attr', $bucket['value'], true)) {
|
||||
$bucket['value'][] = 'html';
|
||||
$bucket['value'][] = 'html_attr_relaxed';
|
||||
}
|
||||
|
||||
if (\in_array('html_attr_relaxed', $bucket['value'], true)) {
|
||||
$bucket['value'][] = 'html';
|
||||
}
|
||||
|
||||
return $bucket['value'];
|
||||
if (\in_array('html_attr_relaxed', $safe, true)) {
|
||||
$safe[] = 'html';
|
||||
}
|
||||
|
||||
return [];
|
||||
return $safe;
|
||||
}
|
||||
|
||||
private function setSafe(Node $node, array $safe): void
|
||||
{
|
||||
$hash = spl_object_id($node);
|
||||
if (isset($this->data[$hash])) {
|
||||
foreach ($this->data[$hash] as &$bucket) {
|
||||
if ($bucket['key'] === $node) {
|
||||
$bucket['value'] = $safe;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->data[$hash][] = [
|
||||
'key' => $node,
|
||||
'value' => $safe,
|
||||
];
|
||||
$this->data[$node] = $safe;
|
||||
}
|
||||
|
||||
public function enterNode(Node $node, Environment $env): Node
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Tests\NodeVisitor;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
use Twig\Node\Node;
|
||||
use Twig\Source;
|
||||
|
||||
class SafeAnalysisTest extends TestCase
|
||||
{
|
||||
public function testCompilingDoesNotRetainTheAst()
|
||||
{
|
||||
$env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => 'html']);
|
||||
$source = new Source('{{ "a"|upper }}{{ foo.bar }}{{ [1, 2]|join("-") }}{{ b ? "y" : "n" }}', 'index');
|
||||
|
||||
$ast = $env->parse($env->tokenize($source));
|
||||
|
||||
$refs = [];
|
||||
$collect = static function (Node $node) use (&$collect, &$refs) {
|
||||
$refs[] = \WeakReference::create($node);
|
||||
foreach ($node as $child) {
|
||||
$collect($child);
|
||||
}
|
||||
};
|
||||
$collect($ast);
|
||||
$this->assertNotEmpty($refs);
|
||||
|
||||
unset($ast, $collect);
|
||||
gc_collect_cycles();
|
||||
|
||||
$retained = 0;
|
||||
foreach ($refs as $ref) {
|
||||
if (null !== $ref->get()) {
|
||||
++$retained;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertSame(0, $retained, \sprintf('%d of %d AST nodes are still referenced after compilation.', $retained, \count($refs)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user