Skip to content

Commit 781e157

Browse files
committed
Use ZEND_CLOSURE_OBJECT() macro to resolve closure op_array to closure object through address calculation, instead of op_array->prototype reuse.
1 parent 35e70af commit 781e157

8 files changed

+28
-31
lines changed

Zend/zend_closures.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ void zend_register_closure_ce(void) /* {{{ */
639639

640640
static ZEND_NAMED_FUNCTION(zend_closure_internal_handler) /* {{{ */
641641
{
642-
zend_closure *closure = (zend_closure*)EX(func)->common.prototype;
642+
zend_closure *closure = (zend_closure*)ZEND_CLOSURE_OBJECT(EX(func));
643643
closure->orig_internal_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
644644
OBJ_RELEASE((zend_object*)closure);
645645
EX(func) = NULL;
@@ -662,7 +662,6 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
662662

663663
if (func->type == ZEND_USER_FUNCTION) {
664664
memcpy(&closure->func, func, sizeof(zend_op_array));
665-
closure->func.common.prototype = (zend_function*)closure;
666665
closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;
667666
if (closure->func.op_array.static_variables) {
668667
closure->func.op_array.static_variables =
@@ -677,7 +676,6 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
677676
}
678677
} else {
679678
memcpy(&closure->func, func, sizeof(zend_internal_function));
680-
closure->func.common.prototype = (zend_function*)closure;
681679
closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;
682680
/* wrap internal function handler to avoid memory leak */
683681
if (UNEXPECTED(closure->func.internal_function.handler == zend_closure_internal_handler)) {

Zend/zend_closures.h

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424

2525
BEGIN_EXTERN_C()
2626

27+
/* This macro depends on zend_closure structure layout */
28+
#define ZEND_CLOSURE_OBJECT(op_array) \
29+
((zend_object*)((char*)(op_array) - sizeof(zend_object)))
30+
2731
void zend_register_closure_ce(void);
2832
void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var);
2933

Zend/zend_execute.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -2554,7 +2554,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
25542554
OBJ_RELEASE(Z_OBJ(call->This));
25552555
}
25562556
if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) {
2557-
zend_object_release((zend_object *) call->func->common.prototype);
2557+
zend_object_release(ZEND_CLOSURE_OBJECT(call->func));
25582558
} else if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
25592559
zend_string_release(call->func->common.function_name);
25602560
zend_free_trampoline(call->func);
@@ -2735,8 +2735,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval *
27352735

27362736
if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
27372737
/* Delay closure destruction until its invocation */
2738-
ZEND_ASSERT(GC_TYPE((zend_object*)fbc->common.prototype) == IS_OBJECT);
2739-
GC_ADDREF((zend_object*)fbc->common.prototype);
2738+
GC_ADDREF(ZEND_CLOSURE_OBJECT(fbc));
27402739
call_info |= ZEND_CALL_CLOSURE;
27412740
if (fbc->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
27422741
call_info |= ZEND_CALL_FAKE_CLOSURE;

Zend/zend_execute_API.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -776,8 +776,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
776776
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
777777
uint32_t call_info;
778778

779-
ZEND_ASSERT(GC_TYPE((zend_object*)func->op_array.prototype) == IS_OBJECT);
780-
GC_ADDREF((zend_object*)func->op_array.prototype);
779+
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
781780
call_info = ZEND_CALL_CLOSURE;
782781
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
783782
call_info |= ZEND_CALL_FAKE_CLOSURE;

Zend/zend_generators.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "zend_interfaces.h"
2525
#include "zend_exceptions.h"
2626
#include "zend_generators.h"
27+
#include "zend_closures.h"
2728

2829
ZEND_API zend_class_entry *zend_ce_generator;
2930
ZEND_API zend_class_entry *zend_ce_ClosedGeneratorException;
@@ -145,7 +146,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
145146

146147
/* Free closure object */
147148
if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
148-
OBJ_RELEASE((zend_object *) EX(func)->common.prototype);
149+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
149150
}
150151

151152
/* Free GC buffer. GC for closed generators doesn't need an allocated buffer */
@@ -335,7 +336,7 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {
335336
ZVAL_OBJ(gc_buffer++, Z_OBJ(execute_data->This));
336337
}
337338
if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
338-
ZVAL_OBJ(gc_buffer++, (zend_object *) EX(func)->common.prototype);
339+
ZVAL_OBJ(gc_buffer++, ZEND_CLOSURE_OBJECT(EX(func)));
339340
}
340341

341342
if (generator->node.children == 0) {

Zend/zend_vm_def.h

+6-7
Original file line numberDiff line numberDiff line change
@@ -2374,7 +2374,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
23742374
}
23752375
OBJ_RELEASE(object);
23762376
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
2377-
OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
2377+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
23782378
}
23792379
EG(vm_stack_top) = (zval*)execute_data;
23802380
execute_data = EX(prev_execute_data);
@@ -2405,7 +2405,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
24052405
}
24062406
OBJ_RELEASE(object);
24072407
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
2408-
OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
2408+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
24092409
}
24102410

24112411
zend_vm_stack_free_extra_args_ex(call_info, execute_data);
@@ -2447,7 +2447,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
24472447
}
24482448
EG(current_execute_data) = EX(prev_execute_data);
24492449
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
2450-
OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
2450+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
24512451
}
24522452
ZEND_VM_RETURN();
24532453
} else /* if (call_kind == ZEND_CALL_TOP_CODE) */ {
@@ -3356,8 +3356,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
33563356
}
33573357
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
33583358
/* Delay closure destruction until its invocation */
3359-
ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT);
3360-
GC_ADDREF((zend_object*)func->common.prototype);
3359+
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
33613360
call_info |= ZEND_CALL_CLOSURE;
33623361
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
33633362
call_info |= ZEND_CALL_FAKE_CLOSURE;
@@ -3370,7 +3369,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
33703369
FREE_OP2();
33713370
if ((OP2_TYPE & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
33723371
if (call_info & ZEND_CALL_CLOSURE) {
3373-
zend_object_release((zend_object*)func->common.prototype);
3372+
zend_object_release(ZEND_CLOSURE_OBJECT(func));
33743373
}
33753374
if (call_info & ZEND_CALL_RELEASE_THIS) {
33763375
zend_object_release(object);
@@ -4532,7 +4531,7 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY, NUM)
45324531
}
45334532
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)));
45344533
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
4535-
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
4534+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(call)->func));
45364535
}
45374536
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
45384537
OBJ_RELEASE(Z_OBJ(EX(call)->This));

Zend/zend_vm_execute.h

+10-13
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
457457
}
458458
OBJ_RELEASE(object);
459459
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
460-
OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
460+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
461461
}
462462
EG(vm_stack_top) = (zval*)execute_data;
463463
execute_data = EX(prev_execute_data);
@@ -488,7 +488,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
488488
}
489489
OBJ_RELEASE(object);
490490
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
491-
OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
491+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
492492
}
493493

494494
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_
530530
}
531531
EG(current_execute_data) = EX(prev_execute_data);
532532
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
533-
OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
533+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
534534
}
535535
ZEND_VM_RETURN();
536536
} 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
13611361
}
13621362
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)));
13631363
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
1364-
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
1364+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(call)->func));
13651365
}
13661366
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
13671367
OBJ_RELEASE(Z_OBJ(EX(call)->This));
@@ -5585,8 +5585,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
55855585
}
55865586
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
55875587
/* Delay closure destruction until its invocation */
5588-
ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT);
5589-
GC_ADDREF((zend_object*)func->common.prototype);
5588+
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
55905589
call_info |= ZEND_CALL_CLOSURE;
55915590
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
55925591
call_info |= ZEND_CALL_FAKE_CLOSURE;
@@ -5598,7 +5597,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
55985597

55995598
if ((IS_CONST & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
56005599
if (call_info & ZEND_CALL_CLOSURE) {
5601-
zend_object_release((zend_object*)func->common.prototype);
5600+
zend_object_release(ZEND_CLOSURE_OBJECT(func));
56025601
}
56035602
if (call_info & ZEND_CALL_RELEASE_THIS) {
56045603
zend_object_release(object);
@@ -7796,8 +7795,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV
77967795
}
77977796
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
77987797
/* Delay closure destruction until its invocation */
7799-
ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT);
7800-
GC_ADDREF((zend_object*)func->common.prototype);
7798+
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
78017799
call_info |= ZEND_CALL_CLOSURE;
78027800
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
78037801
call_info |= ZEND_CALL_FAKE_CLOSURE;
@@ -7810,7 +7808,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV
78107808
zval_ptr_dtor_nogc(free_op2);
78117809
if (((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
78127810
if (call_info & ZEND_CALL_CLOSURE) {
7813-
zend_object_release((zend_object*)func->common.prototype);
7811+
zend_object_release(ZEND_CLOSURE_OBJECT(func));
78147812
}
78157813
if (call_info & ZEND_CALL_RELEASE_THIS) {
78167814
zend_object_release(object);
@@ -10933,8 +10931,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H
1093310931
}
1093410932
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
1093510933
/* Delay closure destruction until its invocation */
10936-
ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT);
10937-
GC_ADDREF((zend_object*)func->common.prototype);
10934+
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
1093810935
call_info |= ZEND_CALL_CLOSURE;
1093910936
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
1094010937
call_info |= ZEND_CALL_FAKE_CLOSURE;
@@ -10946,7 +10943,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H
1094610943

1094710944
if ((IS_CV & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
1094810945
if (call_info & ZEND_CALL_CLOSURE) {
10949-
zend_object_release((zend_object*)func->common.prototype);
10946+
zend_object_release(ZEND_CLOSURE_OBJECT(func));
1095010947
}
1095110948
if (call_info & ZEND_CALL_RELEASE_THIS) {
1095210949
zend_object_release(object);

ext/reflection/php_reflection.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2218,7 +2218,7 @@ ZEND_METHOD(reflection_generator, getFunction)
22182218

22192219
if (ex->func->common.fn_flags & ZEND_ACC_CLOSURE) {
22202220
zval closure;
2221-
ZVAL_OBJ(&closure, (zend_object *) ex->func->common.prototype);
2221+
ZVAL_OBJ(&closure, ZEND_CLOSURE_OBJECT(ex->func));
22222222
reflection_function_factory(ex->func, &closure, return_value);
22232223
} else if (ex->func->op_array.scope) {
22242224
reflection_method_factory(ex->func->op_array.scope, ex->func, NULL, return_value);

0 commit comments

Comments
 (0)