[php-src] Issue #19155: zend_ast_tree_copy cannot copy closure with a default argument in zend_ast_process hook
| From: | KaseyJenkins | Date: | Thu, 17 Jul 2025 05:10:20 +0000 |
| Subject: | [php-src] Issue #19155: zend_ast_tree_copy cannot copy closure with a default argument in zend_ast_process hook | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-250447@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/19155
Author: KaseyJenkins
### Description
[zend_ast_copy](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.h#L340) seems to
be an API function to go when one wants to copy, let's say, function parameters.
Under the hood the function of interest is
[zend_ast_tree_copy](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.c#L1276).
We use the
zend_ast_process hook to modify the AST after it is parsed and created.
So far
[zend_ast_tree_copy](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.c#L1276)
seems to have behaved correctly in such cases, however, with the advent of PHP 8.5.0alpha1 in
general and '[Support for Closures in constant
expressions](https://wiki.php.net/rfc/closures_in_const_expr)' in particular it appears to no
longer properly copy AST nodes.
The culprit is ostensibly
[ZEND_AST_OP_ARRAY](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.h#L39), which
does not seem to exist at the time of the zend_ast_process hook and appears only after
zend_compile_const_expr -> zend_compile_const_expr_closure, which come later on:
```
zend_const_expr_to_zval (result=result@entry=0x7fffffff9d68, ast_ptr=ast_ptr@entry=0x7ffff448c1f0,
allow_dynamic=allow_dynamic@entry=true)
at php-src-php-8.5.0alpha1/Zend/zend_compile.c:11517
(gdb) p **ast_ptr
{kind = 69, attr = 0, lineno = 25, child = {0x1000000019}} // ZEND_AST_CLOSURE
zend_compile_const_expr(ast_ptr, &context);
p **ast_ptr
{kind = 66, attr = 0, lineno = 25, child = {0x7ffff4405320}} // ZEND_AST_OP_ARRAY
ZVAL_AST(&ast_zv, zend_ast_copy(*ast_ptr));
```
When one tries to use zend_ast_copy (or rather a function mimicking
[zend_ast_tree_copy](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.c#L1276)'s
functionality) on a function parameter that is a [Closure with a default
argument](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/tests/closures/closure_const_expr/default_args.phpt)
it seems to fail to copy the
[ZEND_AST_CLOSURE](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.h#L44) node
since
[zend_ast_get_num_children](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.c#L1330)
will detect it as
[zend_ast_is_special](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.h#L390) (or
it will just return 0 according to [ast->kind >>
ZEND_AST_NUM_CHILDREN_SHIFT](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.h#L392)),
hence no children will be copied (not to mention that the childless node created will be of
(zend_ast*) type and not (zend_ast_decl*).
How should one copy function parameters (especially [Closures with a default
argument](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/tests/closures/closure_const_expr/default_args.phpt))
when it comes to PHP 8.5 zend_ast_process hook? Should one no longer use zend_ast_copy
(or functions mimicking
[zend_ast_tree_copy](https://github.com/php/php-src/blob/php-8.5.0alpha1/Zend/zend_ast.c#L1276)'s
functionality) or it was never intended to be used in such a way?
Thanks..
### PHP Version
```plain
PHP 8.5.0alpha1 (cli) (built: Jul 4 2025 10:17:12) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.5.0-dev, Copyright (c) Zend Technologies
```
### Operating System
_No response_