-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Zend: Fix reference counting for Closures in const-expr #17853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Ah, this doesn't actually fix the issue: It's only reproducible without OPcache. |
04f5a7c
to
3c8493a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index bf0b3d19881..87b55454b84 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -190,6 +190,9 @@ static zend_ast *zend_persist_ast(zend_ast *ast)
node = (zend_ast *) copy;
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
zend_ast_op_array *copy = zend_shared_memdup(ast, sizeof(zend_ast_op_array));
+ /* We're holding a separate reference to the op_array in the AST. Release it
+ * early because zend_persist_op_array() is destructive. */
+ destroy_op_array(copy->op_array);
zval z;
ZVAL_PTR(&z, copy->op_array);
zend_persist_op_array(&z);
diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c
index 0c53923354c..5381f8f6e1c 100644
--- a/ext/opcache/zend_persist_calc.c
+++ b/ext/opcache/zend_persist_calc.c
@@ -91,6 +91,14 @@ static void zend_persist_ast_calc(zend_ast *ast)
zval z;
ZVAL_PTR(&z, zend_ast_get_op_array(ast)->op_array);
zend_persist_op_array_calc(&z);
+
+ /* If op_array is shared, the function name refcount is still incremented for each use,
+ * so we need to release it here. We remembered the original function name in xlat. */
+ zend_string *old_function_name =
+ zend_shared_alloc_get_xlat_entry(&zend_ast_get_op_array(ast)->op_array->function_name);
+ if (old_function_name) {
+ zend_string_release_ex(old_function_name, 0);
+ }
} else if (zend_ast_is_decl(ast)) {
/* Not implemented. */
ZEND_UNREACHABLE();
This should fix the issue. It's not pretty but it works.
Zend/tests/closures/closure_const_expr/attributes_autoload.phpt
Outdated
Show resolved
Hide resolved
ffd97c7
to
9a7cd28
Compare
48c418e
to
bb252e4
Compare
@TimWolla This example seems to leak: const Closure = static function () {
static $x = str_repeat('a', 10);
echo "called", PHP_EOL;
};
var_dump(Closure);
(Closure)(); It might be because Lines 641 to 645 in da1e254
However, for |
712fb01
to
f54c7ce
Compare
323e899
to
2365ff7
Compare
Fixes #17851