Skip to content

Fix GH-22256: Preserve frameless argument order#22766

Open
prateekbhujel wants to merge 1 commit into
php:PHP-8.4from
prateekbhujel:prateek/fix-gh-22256-frameless-arg-order
Open

Fix GH-22256: Preserve frameless argument order#22766
prateekbhujel wants to merge 1 commit into
php:PHP-8.4from
prateekbhujel:prateek/fix-gh-22256-frameless-arg-order

Conversation

@prateekbhujel

@prateekbhujel prateekbhujel commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Frameless calls keep CV arguments in their original slots until the handler runs. If a later argument changes one of those CVs, the handler sees the new value instead of the value from when the earlier argument was evaluated.

Copy earlier CV arguments before compiling a later expression that may have side effects. The common variable, literal, and constant argument paths remain unchanged.

This happens before the frameless opcode runs, so the __toString() re-entry protection proposed in #21815 does not cover it.

Includes tests for assignment, increment, and mutation through a nested call.

Fixes GH-22256

@ndossche

Copy link
Copy Markdown
Member

I'm fairly certain that we consider the evaluation order of arguments to be undefined, just like languages like C etc.

@prateekbhujel

Copy link
Copy Markdown
Contributor Author

Argument evaluation order is undefined, but I think this case is slightly different. A regular call snapshots the earlier CV argument before the later assignment, while the frameless path keeps the CV live until the handler runs and therefore sees the mutated value. The result changes only because the call was optimized into a frameless call. Since frameless calls should be transparent to userland, I still think matching regular call behavior here is worth fixing.

@ndossche

Copy link
Copy Markdown
Member

That's at the cost of performance.
If we just adhere to the principle that the evaluation order is undefined than the behaviour is fine.

@prateekbhujel

Copy link
Copy Markdown
Contributor Author

I see the performance concern, but I checked the documented behavior and function arguments seem to be a specific exception here. The manual says arguments are evaluated from left to right, and the language spec says there is a sequence point after each argument:
https://www.php.net/manual/en/functions.arguments.php
https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#function-call-operator
That seems more specific than the general rule about undefined operand evaluation order. So unless those docs are considered wrong, the frameless path is changing documented function call behavior. The implementation cost should be kept as small as possible, but I do not think the behavior itself can be dismissed as undefined.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants