From 6ba10a03e7b14089e2f53305dec9a6ec06a7eb64 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 11 Jan 2018 17:27:26 +0300 Subject: [PATCH] Revert "Use ZEND_CLOSURE_OBJECT() macro to resolve closure op_array to closure object through address calculation, instead of op_array->prototype reuse." (this patch is incomplete or wrong) This reverts commit 781e1573afdc7c336b3577ceabc9c65cafea17e8. --- Zend/zend_closures.c | 4 +++- Zend/zend_closures.h | 4 ---- Zend/zend_execute.c | 5 +++-- Zend/zend_execute_API.c | 3 ++- Zend/zend_generators.c | 5 ++--- Zend/zend_vm_def.h | 13 +++++++------ Zend/zend_vm_execute.h | 23 +++++++++++++---------- ext/reflection/php_reflection.c | 2 +- 8 files changed, 31 insertions(+), 28 deletions(-) diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index d471718783..b60107c9e5 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -639,7 +639,7 @@ void zend_register_closure_ce(void) /* {{{ */ static ZEND_NAMED_FUNCTION(zend_closure_internal_handler) /* {{{ */ { - zend_closure *closure = (zend_closure*)ZEND_CLOSURE_OBJECT(EX(func)); + zend_closure *closure = (zend_closure*)EX(func)->common.prototype; closure->orig_internal_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); OBJ_RELEASE((zend_object*)closure); EX(func) = NULL; @@ -662,6 +662,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent if (func->type == ZEND_USER_FUNCTION) { memcpy(&closure->func, func, sizeof(zend_op_array)); + closure->func.common.prototype = (zend_function*)closure; closure->func.common.fn_flags |= ZEND_ACC_CLOSURE; if (closure->func.op_array.static_variables) { closure->func.op_array.static_variables = @@ -676,6 +677,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent } } else { memcpy(&closure->func, func, sizeof(zend_internal_function)); + closure->func.common.prototype = (zend_function*)closure; closure->func.common.fn_flags |= ZEND_ACC_CLOSURE; /* wrap internal function handler to avoid memory leak */ if (UNEXPECTED(closure->func.internal_function.handler == zend_closure_internal_handler)) { diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h index c8b447e498..4c7c041da8 100644 --- a/Zend/zend_closures.h +++ b/Zend/zend_closures.h @@ -24,10 +24,6 @@ BEGIN_EXTERN_C() -/* This macro depends on zend_closure structure layout */ -#define ZEND_CLOSURE_OBJECT(op_array) \ - ((zend_object*)((char*)(op_array) - sizeof(zend_object))) - void zend_register_closure_ce(void); void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 4de6ba0c07..9b7cbf294d 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2554,7 +2554,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o OBJ_RELEASE(Z_OBJ(call->This)); } if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) { - zend_object_release(ZEND_CLOSURE_OBJECT(call->func)); + zend_object_release((zend_object *) call->func->common.prototype); } else if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { zend_string_release(call->func->common.function_name); zend_free_trampoline(call->func); @@ -2735,7 +2735,8 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval * if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - GC_ADDREF(ZEND_CLOSURE_OBJECT(fbc)); + ZEND_ASSERT(GC_TYPE((zend_object*)fbc->common.prototype) == IS_OBJECT); + GC_ADDREF((zend_object*)fbc->common.prototype); call_info |= ZEND_CALL_CLOSURE; if (fbc->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { call_info |= ZEND_CALL_FAKE_CLOSURE; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index f66bd66304..61d92914bb 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -776,7 +776,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) { uint32_t call_info; - GC_ADDREF(ZEND_CLOSURE_OBJECT(func)); + ZEND_ASSERT(GC_TYPE((zend_object*)func->op_array.prototype) == IS_OBJECT); + GC_ADDREF((zend_object*)func->op_array.prototype); call_info = ZEND_CALL_CLOSURE; if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { call_info |= ZEND_CALL_FAKE_CLOSURE; diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 6c2495d69d..755300f92b 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -24,7 +24,6 @@ #include "zend_interfaces.h" #include "zend_exceptions.h" #include "zend_generators.h" -#include "zend_closures.h" ZEND_API zend_class_entry *zend_ce_generator; ZEND_API zend_class_entry *zend_ce_ClosedGeneratorException; @@ -146,7 +145,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished /* Free closure object */ if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); + OBJ_RELEASE((zend_object *) EX(func)->common.prototype); } /* Free GC buffer. GC for closed generators doesn't need an allocated buffer */ @@ -336,7 +335,7 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* { ZVAL_OBJ(gc_buffer++, Z_OBJ(execute_data->This)); } if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) { - ZVAL_OBJ(gc_buffer++, ZEND_CLOSURE_OBJECT(EX(func))); + ZVAL_OBJ(gc_buffer++, (zend_object *) EX(func)->common.prototype); } if (generator->node.children == 0) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 9627c045d3..cd0a769f34 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2374,7 +2374,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } OBJ_RELEASE(object); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); + OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype); } EG(vm_stack_top) = (zval*)execute_data; execute_data = EX(prev_execute_data); @@ -2405,7 +2405,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } OBJ_RELEASE(object); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); + OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype); } zend_vm_stack_free_extra_args_ex(call_info, execute_data); @@ -2447,7 +2447,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); + OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype); } ZEND_VM_RETURN(); } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { @@ -3356,7 +3356,8 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) } if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - GC_ADDREF(ZEND_CLOSURE_OBJECT(func)); + ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT); + GC_ADDREF((zend_object*)func->common.prototype); call_info |= ZEND_CALL_CLOSURE; if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { call_info |= ZEND_CALL_FAKE_CLOSURE; @@ -3369,7 +3370,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) FREE_OP2(); if ((OP2_TYPE & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) { if (call_info & ZEND_CALL_CLOSURE) { - zend_object_release(ZEND_CLOSURE_OBJECT(func)); + zend_object_release((zend_object*)func->common.prototype); } if (call_info & ZEND_CALL_RELEASE_THIS) { zend_object_release(object); @@ -4531,7 +4532,7 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY, NUM) } zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(call)->func)); + OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); } if (Z_TYPE(EX(call)->This) == IS_OBJECT) { OBJ_RELEASE(Z_OBJ(EX(call)->This)); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3845f454da..8747a299e8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -457,7 +457,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ } OBJ_RELEASE(object); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); + OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype); } EG(vm_stack_top) = (zval*)execute_data; execute_data = EX(prev_execute_data); @@ -488,7 +488,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ } OBJ_RELEASE(object); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); + OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype); } zend_vm_stack_free_extra_args_ex(call_info, execute_data); @@ -530,7 +530,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ } EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); + OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype); } ZEND_VM_RETURN(); } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { @@ -1361,7 +1361,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O } zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(call)->func)); + OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); } if (Z_TYPE(EX(call)->This) == IS_OBJECT) { OBJ_RELEASE(Z_OBJ(EX(call)->This)); @@ -5585,7 +5585,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS } if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - GC_ADDREF(ZEND_CLOSURE_OBJECT(func)); + ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT); + GC_ADDREF((zend_object*)func->common.prototype); call_info |= ZEND_CALL_CLOSURE; if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { call_info |= ZEND_CALL_FAKE_CLOSURE; @@ -5597,7 +5598,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS if ((IS_CONST & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) { if (call_info & ZEND_CALL_CLOSURE) { - zend_object_release(ZEND_CLOSURE_OBJECT(func)); + zend_object_release((zend_object*)func->common.prototype); } if (call_info & ZEND_CALL_RELEASE_THIS) { zend_object_release(object); @@ -7795,7 +7796,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV } if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - GC_ADDREF(ZEND_CLOSURE_OBJECT(func)); + ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT); + GC_ADDREF((zend_object*)func->common.prototype); call_info |= ZEND_CALL_CLOSURE; if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { call_info |= ZEND_CALL_FAKE_CLOSURE; @@ -7808,7 +7810,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV zval_ptr_dtor_nogc(free_op2); if (((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) { if (call_info & ZEND_CALL_CLOSURE) { - zend_object_release(ZEND_CLOSURE_OBJECT(func)); + zend_object_release((zend_object*)func->common.prototype); } if (call_info & ZEND_CALL_RELEASE_THIS) { zend_object_release(object); @@ -10931,7 +10933,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H } if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - GC_ADDREF(ZEND_CLOSURE_OBJECT(func)); + ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT); + GC_ADDREF((zend_object*)func->common.prototype); call_info |= ZEND_CALL_CLOSURE; if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) { call_info |= ZEND_CALL_FAKE_CLOSURE; @@ -10943,7 +10946,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H if ((IS_CV & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) { if (call_info & ZEND_CALL_CLOSURE) { - zend_object_release(ZEND_CLOSURE_OBJECT(func)); + zend_object_release((zend_object*)func->common.prototype); } if (call_info & ZEND_CALL_RELEASE_THIS) { zend_object_release(object); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 6749003c46..458d5c2c06 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2218,7 +2218,7 @@ ZEND_METHOD(reflection_generator, getFunction) if (ex->func->common.fn_flags & ZEND_ACC_CLOSURE) { zval closure; - ZVAL_OBJ(&closure, ZEND_CLOSURE_OBJECT(ex->func)); + ZVAL_OBJ(&closure, (zend_object *) ex->func->common.prototype); reflection_function_factory(ex->func, &closure, return_value); } else if (ex->func->op_array.scope) { reflection_method_factory(ex->func->op_array.scope, ex->func, NULL, return_value); -- 2.40.0