diff --git a/NEWS b/NEWS index efd0f9fc0c7cc..811eeb187dd6e 100644 --- a/NEWS +++ b/NEWS @@ -2,4 +2,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.4.0alpha1 +Core: + . Fixed bug GH-12073 (Segfault when freeing incompletely initialized + closures). (ilutov) + <<< NOTE: Insert NEWS from last stable release here prior to actual release! >>> diff --git a/Zend/tests/gh12073.phpt b/Zend/tests/gh12073.phpt new file mode 100644 index 0000000000000..ef115685ce7d4 --- /dev/null +++ b/Zend/tests/gh12073.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-12073: 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 2072eac72d712..07eeb7c550452 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -732,6 +732,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) { @@ -765,22 +770,17 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en if (func->common.scope != scope) { func->common.scope = scope; } - closure->func.op_array.fn_flags &= ~ZEND_ACC_HEAP_RT_CACHE; ptr = zend_arena_alloc(&CG(arena), func->op_array.cache_size); ZEND_MAP_PTR_SET(func->op_array.run_time_cache, ptr); + closure->func.op_array.fn_flags &= ~ZEND_ACC_HEAP_RT_CACHE; } else { /* Otherwise, we use a non-shared runtime cache */ - closure->func.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE; ptr = emalloc(func->op_array.cache_size); + closure->func.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE; } memset(ptr, 0, func->op_array.cache_size); } ZEND_MAP_PTR_INIT(closure->func.op_array.run_time_cache, ptr); - - 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;