Skip to content

Commit

Permalink
Zend: Fix reference counting for Closures in const-expr
Browse files Browse the repository at this point in the history
Fixes php#17851
  • Loading branch information
TimWolla committed Feb 18, 2025
1 parent da38477 commit 04f5a7c
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

#[Attr(static function () { })]
#[Attr(static function (...$args) {
var_dump($args);
})]
class C {}

?>
57 changes: 57 additions & 0 deletions Zend/tests/closures/closure_const_expr/attributes_autoload.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--TEST--
GH-17851: Use-after-free when instantiating autoloaded class with attribute having a Closure parameter.
--EXTENSIONS--
reflection
--FILE--
<?php

spl_autoload_register(static function ($className) {
if ($className === 'C') {
require(__DIR__ . '/attributes_autoload.inc');
}
});

#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class Attr {
public function __construct(public Closure $value) {
$value('foo');
}
}

foreach ((new ReflectionClass(C::class))->getAttributes() as $reflectionAttribute) {
var_dump($reflectionAttribute->newInstance());
}

?>
--EXPECTF--
object(Attr)#%d (1) {
["value"]=>
object(Closure)#%d (3) {
["name"]=>
string(%d) "{closure:%s:%d}"
["file"]=>
string(%d) "%s"
["line"]=>
int(%d)
}
}
array(1) {
[0]=>
string(3) "foo"
}
object(Attr)#%d (1) {
["value"]=>
object(Closure)#%d (4) {
["name"]=>
string(%d) "{closure:%s:%d}"
["file"]=>
string(%d) "%s"
["line"]=>
int(%d)
["parameter"]=>
array(1) {
["$args"]=>
string(10) "<optional>"
}
}
}
4 changes: 3 additions & 1 deletion Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_op_array(zend_op_array *op_arr
ast->attr = 0;
ast->lineno = CG(zend_lineno);
ast->op_array = op_array;
function_add_ref((zend_function *)op_array);

return (zend_ast *) ast;
}
Expand Down Expand Up @@ -1226,7 +1227,8 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
} else if (EXPECTED(ast->kind == ZEND_AST_CONSTANT)) {
zend_string_release_ex(zend_ast_get_constant_name(ast), 0);
} else if (EXPECTED(ast->kind == ZEND_AST_OP_ARRAY)) {
/* Nothing to do. */
zend_ast_op_array *op_array = zend_ast_get_op_array(ast);
destroy_op_array(op_array->op_array);
} else if (EXPECTED(zend_ast_is_decl(ast))) {
zend_ast_decl *decl = (zend_ast_decl *) ast;

Expand Down

0 comments on commit 04f5a7c

Please sign in to comment.