From b576bb901ebeaf944c442629e122e26dbcb4bbc7 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Thu, 21 Jul 2022 13:20:24 +0200 Subject: [PATCH] Avoid using a stack allocated zend_function in Closure::call, to avoid prevent crashes on bailout Having a stack allocated zend_function may cause crashes if the stack is polluted between bailout and the actual unwinding in zend_observer_fcall_end_all. Signed-off-by: Bob Weinand --- Zend/zend_closures.c | 91 ++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 1dd7715e55b..3a2c3b11d38 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -121,7 +121,6 @@ ZEND_METHOD(Closure, call) zend_closure *closure; zend_fcall_info fci; zend_fcall_info_cache fci_cache; - zend_function my_function; zend_object *newobj; zend_class_entry *newclass; @@ -142,55 +141,71 @@ ZEND_METHOD(Closure, call) return; } - if (closure->func.common.fn_flags & ZEND_ACC_GENERATOR) { - zval new_closure; - zend_create_closure(&new_closure, &closure->func, newclass, closure->called_scope, newthis); - closure = (zend_closure *) Z_OBJ(new_closure); - fci_cache.function_handler = &closure->func; - } else { - memcpy(&my_function, &closure->func, closure->func.type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function)); - my_function.common.fn_flags &= ~ZEND_ACC_CLOSURE; - /* use scope of passed object */ - my_function.common.scope = newclass; - if (closure->func.type == ZEND_INTERNAL_FUNCTION) { - my_function.internal_function.handler = closure->orig_internal_handler; - } - fci_cache.function_handler = &my_function; - - /* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */ - if (ZEND_USER_CODE(my_function.type) - && (closure->func.common.scope != newclass - || (closure->func.common.fn_flags & ZEND_ACC_HEAP_RT_CACHE))) { - void *ptr; - - my_function.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE; - ptr = emalloc(my_function.op_array.cache_size); - ZEND_MAP_PTR_INIT(my_function.op_array.run_time_cache, ptr); - memset(ptr, 0, my_function.op_array.cache_size); - } - } - fci_cache.called_scope = newclass; fci_cache.object = fci.object = newobj; fci.size = sizeof(fci); ZVAL_OBJ(&fci.function_name, &closure->std); + ZVAL_UNDEF(&closure_result); fci.retval = &closure_result; - if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(closure_result) != IS_UNDEF) { + if (closure->func.common.fn_flags & ZEND_ACC_GENERATOR) { + zval new_closure; + zend_create_closure(&new_closure, &closure->func, newclass, closure->called_scope, newthis); + closure = (zend_closure *) Z_OBJ(new_closure); + fci_cache.function_handler = &closure->func; + + zend_call_function(&fci, &fci_cache); + + /* copied upon generator creation */ + GC_DELREF(&closure->std); + } else { + zend_function *my_function; + if (ZEND_USER_CODE(closure->func.type)) { + my_function = emalloc(sizeof(zend_op_array)); + memcpy(my_function, &closure->func, sizeof(zend_op_array)); + } else { + my_function = emalloc(sizeof(zend_internal_function)); + memcpy(my_function, &closure->func, sizeof(zend_internal_function)); + } + my_function->common.fn_flags &= ~ZEND_ACC_CLOSURE; + /* use scope of passed object */ + my_function->common.scope = newclass; + if (closure->func.type == ZEND_INTERNAL_FUNCTION) { + my_function->internal_function.handler = closure->orig_internal_handler; + } + fci_cache.function_handler = my_function; + + /* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */ + if (ZEND_USER_CODE(my_function->type) + && (closure->func.common.scope != newclass + || (closure->func.common.fn_flags & ZEND_ACC_HEAP_RT_CACHE))) { + void *ptr; + + my_function->op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE; + ptr = emalloc(my_function->op_array.cache_size); + ZEND_MAP_PTR_INIT(my_function->op_array.run_time_cache, ptr); + memset(ptr, 0, my_function->op_array.cache_size); + } + + zend_call_function(&fci, &fci_cache); + + if (ZEND_USER_CODE(my_function->type)) { + if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE) { + efree(ZEND_MAP_PTR(my_function->op_array.run_time_cache)); + } + efree_size(my_function, sizeof(zend_op_array)); + } else { + efree_size(my_function, sizeof(zend_internal_function)); + } + } + + if (Z_TYPE(closure_result) != IS_UNDEF) { if (Z_ISREF(closure_result)) { zend_unwrap_reference(&closure_result); } ZVAL_COPY_VALUE(return_value, &closure_result); } - - if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) { - /* copied upon generator creation */ - GC_DELREF(&closure->std); - } else if (ZEND_USER_CODE(my_function.type) - && (fci_cache.function_handler->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE)) { - efree(ZEND_MAP_PTR(my_function.op_array.run_time_cache)); - } } /* }}} */