diff --git a/Zend/tests/gh12073.phpt b/Zend/tests/gh12073.phpt new file mode 100644 index 0000000000000..7ad23e5c0ff0b --- /dev/null +++ b/Zend/tests/gh12073.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-12073: Fix freeing of non-ZMM pointer of incompletely allocated closure +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 0dab5537a3752..73991806080f0 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -689,6 +689,11 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en closure->func.common.fn_flags |= ZEND_ACC_CLOSURE; closure->func.common.fn_flags &= ~ZEND_ACC_IMMUTABLE; + zend_string_addref(closure->func.op_array.function_name); + if (closure->func.op_array.refcount) { + (*closure->func.op_array.refcount)++; + } + /* For fake closures, we want to reuse the static variables of the original function. */ if (!is_fake) { if (closure->func.op_array.static_variables) { @@ -736,10 +741,6 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en } memset(ptr, 0, func->op_array.cache_size); } - zend_string_addref(closure->func.op_array.function_name); - if (closure->func.op_array.refcount) { - (*closure->func.op_array.refcount)++; - } } else { memcpy(&closure->func, func, sizeof(zend_internal_function)); closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;