Skip to content

Skip the sandbox __toString check on arguments whose PHP parameter type cannot implicitly coerce to string#4823

Open
fabpot wants to merge 5 commits into
twigphp:3.xfrom
fabpot:sandbox-skip-tostring-walk-by-type
Open

Skip the sandbox __toString check on arguments whose PHP parameter type cannot implicitly coerce to string#4823
fabpot wants to merge 5 commits into
twigphp:3.xfrom
fabpot:sandbox-skip-tostring-walk-by-type

Conversation

@fabpot
Copy link
Copy Markdown
Contributor

@fabpot fabpot commented Jun 1, 2026

The sandbox visitor currently wraps every argument of every Twig callable with `CheckToStringNode.

As an optimization, we are now only wrapping when needed (based on the callable type hints). This is a conservative approach (untyped, mixed, string, array, iterable, object, Stringable, Traversable, self/static/parent and unknown class names all keep wrapping).

Here is a concrete before/after for template {{ demo(a, b) }} under the sandbox, with the following signature on the PHP side demo(int $a, string $b):

Before:

    yield $this->sandbox->ensureToStringAllowed(
       $this->env->getFunction('demo')->getCallable()(
           $this->sandbox->ensureToStringAllowed(($context["a"] ?? null), 1, $this->source),
           $this->sandbox->ensureToStringAllowed(($context["b"] ?? null), 1, $this->source),
       ),
       1, $this->source,
   );

After

   yield $this->sandbox->ensureToStringAllowed(
       $this->env->getFunction('demo')->getCallable()(
           ($context["a"] ?? null),                                                            // int: bare, skipped
           $this->sandbox->ensureToStringAllowed(($context["b"] ?? null), 1, $this->source),   // string: still wrapped
       ),
       1, $this->source,
   );

@fabpot fabpot changed the title Sandbox skip tostring walk by type Skip the sandbox __toString check on arguments whose PHP parameter type cannot implicitly coerce to string Jun 1, 2026
@fabpot fabpot force-pushed the sandbox-skip-tostring-walk-by-type branch 2 times, most recently from 9d29273 to 8458a85 Compare June 1, 2026 07:56
Comment thread src/Util/CallableParameters.php Outdated
Comment thread src/Util/CallableParameters.php Outdated
@fabpot fabpot force-pushed the sandbox-skip-tostring-walk-by-type branch from 8458a85 to ad1ac44 Compare June 1, 2026 11:14
Copy link
Copy Markdown
Member

@stof stof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For final classes implementing Stringable, would it make sense to try checking the policy at compile-time and mark it safe if we know that the policy allows casting them to string ?
This might help with the kind of logic currently done by Drupal to optimize the sandbox: #4820 (comment)

Comment thread src/Util/CallableParameters.php Outdated
Comment thread src/Util/CallableParameters.php Outdated
@fabpot
Copy link
Copy Markdown
Contributor Author

fabpot commented Jun 1, 2026

For final classes implementing Stringable, would it make sense to try checking the policy at compile-time and mark it safe if we know that the policy allows casting them to string ? This might help with the kind of logic currently done by Drupal to optimize the sandbox: #4820 (comment)

This is not possible as SecurityPolicy can be swapped, so we cannot make that decision at compile-time. The fact that security policies can be swapped is annoying for sure: 99a10384ff0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants