Skip to content

Commit 0586702

Browse files
committed
Mark first call frames of stack segment with ZEND_CALL_ALLOCATED flag to simplify checks on stack deallocation.
1 parent 653e8c5 commit 0586702

File tree

5 files changed

+55
-51
lines changed

5 files changed

+55
-51
lines changed

Zend/zend_compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ struct _zend_execute_data {
455455
#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4)
456456
#define ZEND_CALL_CLOSURE (1 << 5)
457457
#define ZEND_CALL_RELEASE_THIS (1 << 6)
458+
#define ZEND_CALL_ALLOCATED (1 << 7)
458459

459460
#define ZEND_CALL_INFO(call) \
460461
(Z_TYPE_INFO((call)->This) >> 24)

Zend/zend_execute.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2077,7 +2077,7 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data
20772077
EG(vm_stack_top) = EG(vm_stack)->top;
20782078
EG(vm_stack_end) = EG(vm_stack)->end;
20792079

2080-
call_info = ZEND_CALL_TOP_FUNCTION | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS));
2080+
call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS));
20812081
if (Z_OBJ(call->This)) {
20822082
call_info |= ZEND_CALL_RELEASE_THIS;
20832083
}

Zend/zend_execute.h

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -153,24 +153,19 @@ ZEND_API void zend_vm_stack_init(void);
153153
ZEND_API void zend_vm_stack_destroy(void);
154154
ZEND_API void* zend_vm_stack_extend(size_t size);
155155

156-
static zend_always_inline zval* zend_vm_stack_alloc(size_t size)
157-
{
158-
char *top = (char*)EG(vm_stack_top);
159-
160-
if (UNEXPECTED(size > (size_t)(((char*)EG(vm_stack_end)) - top))) {
161-
return (zval*)zend_vm_stack_extend(size);
162-
}
163-
EG(vm_stack_top) = (zval*)(top + size);
164-
return (zval*)top;
165-
}
166-
167156
static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
168157
{
169-
zend_execute_data *call = (zend_execute_data*)zend_vm_stack_alloc(used_stack);
158+
zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top);
170159

160+
if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
161+
call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
162+
ZEND_SET_CALL_INFO(call, call_info | ZEND_CALL_ALLOCATED);
163+
} else {
164+
EG(vm_stack_top) = (zval*)((char*)call + used_stack);
165+
ZEND_SET_CALL_INFO(call, call_info);
166+
}
171167
call->func = func;
172168
Z_OBJ(call->This) = object;
173-
ZEND_SET_CALL_INFO(call, call_info);
174169
ZEND_CALL_NUM_ARGS(call) = num_args;
175170
call->called_scope = called_scope;
176171
return call;
@@ -240,10 +235,11 @@ static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call)
240235
}
241236
}
242237

243-
static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call)
238+
static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_info, zend_execute_data *call)
244239
{
245-
zend_vm_stack p = EG(vm_stack);
246-
if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(p) == (zval*)call)) {
240+
if (UNEXPECTED(call_info & ZEND_CALL_ALLOCATED)) {
241+
zend_vm_stack p = EG(vm_stack);
242+
247243
zend_vm_stack prev = p->prev;
248244

249245
EG(vm_stack_top) = prev->top;
@@ -255,6 +251,11 @@ static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *
255251
}
256252
}
257253

254+
static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call)
255+
{
256+
zend_vm_stack_free_call_frame_ex(ZEND_CALL_INFO(call), call);
257+
}
258+
258259
/* services */
259260
ZEND_API const char *get_active_class_name(const char **space);
260261
ZEND_API const char *get_active_function_name(void);

Zend/zend_vm_def.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2395,7 +2395,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
23952395
if (UNEXPECTED(EX(symbol_table) != NULL)) {
23962396
zend_clean_and_cache_symbol_table(EX(symbol_table));
23972397
}
2398-
zend_vm_stack_free_extra_args(execute_data);
2398+
zend_vm_stack_free_extra_args_ex(call_info, execute_data);
23992399
old_execute_data = execute_data;
24002400
execute_data = EG(current_execute_data) = EX(prev_execute_data);
24012401
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
@@ -2420,7 +2420,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
24202420
}
24212421
EG(scope) = EX(func)->op_array.scope;
24222422

2423-
zend_vm_stack_free_call_frame(old_execute_data);
2423+
zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
24242424

24252425
if (UNEXPECTED(EG(exception) != NULL)) {
24262426
const zend_op *old_opline = EX(opline);
@@ -2440,7 +2440,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
24402440
efree_size(EX(func), sizeof(zend_op_array));
24412441
old_execute_data = execute_data;
24422442
execute_data = EG(current_execute_data) = EX(prev_execute_data);
2443-
zend_vm_stack_free_call_frame(old_execute_data);
2443+
zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
24442444

24452445
zend_attach_symbol_table(execute_data);
24462446
if (UNEXPECTED(EG(exception) != NULL)) {
@@ -2457,7 +2457,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
24572457
if (UNEXPECTED(EX(symbol_table) != NULL)) {
24582458
zend_clean_and_cache_symbol_table(EX(symbol_table));
24592459
}
2460-
zend_vm_stack_free_extra_args(execute_data);
2460+
zend_vm_stack_free_extra_args_ex(call_info, execute_data);
24612461
EG(current_execute_data) = EX(prev_execute_data);
24622462
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
24632463
OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
@@ -2478,7 +2478,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
24782478
}
24792479
EG(current_execute_data) = EX(prev_execute_data);
24802480
}
2481-
zend_vm_stack_free_call_frame(execute_data);
2481+
zend_vm_stack_free_call_frame_ex(call_info, execute_data);
24822482

24832483
ZEND_VM_RETURN();
24842484
}

Zend/zend_vm_execute.h

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
446446
if (UNEXPECTED(EX(symbol_table) != NULL)) {
447447
zend_clean_and_cache_symbol_table(EX(symbol_table));
448448
}
449-
zend_vm_stack_free_extra_args(execute_data);
449+
zend_vm_stack_free_extra_args_ex(call_info, execute_data);
450450
old_execute_data = execute_data;
451451
execute_data = EG(current_execute_data) = EX(prev_execute_data);
452452
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
@@ -471,7 +471,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
471471
}
472472
EG(scope) = EX(func)->op_array.scope;
473473

474-
zend_vm_stack_free_call_frame(old_execute_data);
474+
zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
475475

476476
if (UNEXPECTED(EG(exception) != NULL)) {
477477
const zend_op *old_opline = EX(opline);
@@ -491,7 +491,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
491491
efree_size(EX(func), sizeof(zend_op_array));
492492
old_execute_data = execute_data;
493493
execute_data = EG(current_execute_data) = EX(prev_execute_data);
494-
zend_vm_stack_free_call_frame(old_execute_data);
494+
zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
495495

496496
zend_attach_symbol_table(execute_data);
497497
if (UNEXPECTED(EG(exception) != NULL)) {
@@ -508,7 +508,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
508508
if (UNEXPECTED(EX(symbol_table) != NULL)) {
509509
zend_clean_and_cache_symbol_table(EX(symbol_table));
510510
}
511-
zend_vm_stack_free_extra_args(execute_data);
511+
zend_vm_stack_free_extra_args_ex(call_info, execute_data);
512512
EG(current_execute_data) = EX(prev_execute_data);
513513
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
514514
OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
@@ -529,7 +529,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
529529
}
530530
EG(current_execute_data) = EX(prev_execute_data);
531531
}
532-
zend_vm_stack_free_call_frame(execute_data);
532+
zend_vm_stack_free_call_frame_ex(call_info, execute_data);
533533

534534
ZEND_VM_RETURN();
535535
}
@@ -2058,32 +2058,32 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_H
20582058
try_function_name:
20592059
if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
20602060
const char *colon;
2061-
2061+
20622062
if ((colon = zend_memrchr(Z_STRVAL_P(function_name), ':', Z_STRLEN_P(function_name))) != NULL &&
20632063
colon > Z_STRVAL_P(function_name) &&
20642064
*(colon-1) == ':'
20652065
) {
20662066
zend_string *mname;
20672067
size_t cname_length = colon - Z_STRVAL_P(function_name) - 1;
20682068
size_t mname_length = Z_STRLEN_P(function_name) - cname_length - (sizeof("::") - 1);
2069-
2069+
20702070
if (!mname_length) {
20712071
zend_error(E_EXCEPTION | E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name));
20722072

20732073
HANDLE_EXCEPTION();
20742074
}
2075-
2075+
20762076
lcname = zend_string_init(Z_STRVAL_P(function_name), cname_length, 0);
2077-
2077+
20782078
called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
20792079
if (UNEXPECTED(called_scope == NULL)) {
20802080
zend_string_release(lcname);
20812081
CHECK_EXCEPTION();
20822082
ZEND_VM_NEXT_OPCODE();
20832083
}
2084-
2084+
20852085
mname = zend_string_init(Z_STRVAL_P(function_name) + (cname_length + sizeof("::") - 1), mname_length, 0);
2086-
2086+
20872087
if (called_scope->get_static_method) {
20882088
fbc = called_scope->get_static_method(called_scope, mname);
20892089
} else {
@@ -2098,10 +2098,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_H
20982098

20992099
HANDLE_EXCEPTION();
21002100
}
2101-
2101+
21022102
zend_string_release(lcname);
21032103
zend_string_release(mname);
2104-
2104+
21052105
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
21062106
if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
21072107
zend_error(E_DEPRECATED,
@@ -2135,6 +2135,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_H
21352135
called_scope = NULL;
21362136
object = NULL;
21372137
}
2138+
21382139
} else if (IS_CONST != IS_CONST &&
21392140
EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
21402141
Z_OBJ_HANDLER_P(function_name, get_closure) &&
@@ -2529,32 +2530,32 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HAND
25292530
try_function_name:
25302531
if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
25312532
const char *colon;
2532-
2533+
25332534
if ((colon = zend_memrchr(Z_STRVAL_P(function_name), ':', Z_STRLEN_P(function_name))) != NULL &&
25342535
colon > Z_STRVAL_P(function_name) &&
25352536
*(colon-1) == ':'
25362537
) {
25372538
zend_string *mname;
25382539
size_t cname_length = colon - Z_STRVAL_P(function_name) - 1;
25392540
size_t mname_length = Z_STRLEN_P(function_name) - cname_length - (sizeof("::") - 1);
2540-
2541+
25412542
if (!mname_length) {
25422543
zend_error(E_EXCEPTION | E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name));
25432544

25442545
HANDLE_EXCEPTION();
25452546
}
2546-
2547+
25472548
lcname = zend_string_init(Z_STRVAL_P(function_name), cname_length, 0);
2548-
2549+
25492550
called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
25502551
if (UNEXPECTED(called_scope == NULL)) {
25512552
zend_string_release(lcname);
25522553
CHECK_EXCEPTION();
25532554
ZEND_VM_NEXT_OPCODE();
25542555
}
2555-
2556+
25562557
mname = zend_string_init(Z_STRVAL_P(function_name) + (cname_length + sizeof("::") - 1), mname_length, 0);
2557-
2558+
25582559
if (called_scope->get_static_method) {
25592560
fbc = called_scope->get_static_method(called_scope, mname);
25602561
} else {
@@ -2569,10 +2570,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HAND
25692570

25702571
HANDLE_EXCEPTION();
25712572
}
2572-
2573+
25732574
zend_string_release(lcname);
25742575
zend_string_release(mname);
2575-
2576+
25762577
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
25772578
if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
25782579
zend_error(E_DEPRECATED,
@@ -2606,6 +2607,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HAND
26062607
called_scope = NULL;
26072608
object = NULL;
26082609
}
2610+
26092611
} else if (IS_CV != IS_CONST &&
26102612
EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
26112613
Z_OBJ_HANDLER_P(function_name, get_closure) &&
@@ -2781,32 +2783,32 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_
27812783
try_function_name:
27822784
if ((IS_TMP_VAR|IS_VAR) != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
27832785
const char *colon;
2784-
2786+
27852787
if ((colon = zend_memrchr(Z_STRVAL_P(function_name), ':', Z_STRLEN_P(function_name))) != NULL &&
27862788
colon > Z_STRVAL_P(function_name) &&
27872789
*(colon-1) == ':'
27882790
) {
27892791
zend_string *mname;
27902792
size_t cname_length = colon - Z_STRVAL_P(function_name) - 1;
27912793
size_t mname_length = Z_STRLEN_P(function_name) - cname_length - (sizeof("::") - 1);
2792-
2794+
27932795
if (!mname_length) {
27942796
zend_error(E_EXCEPTION | E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name));
27952797
zval_ptr_dtor_nogc(free_op2);
27962798
HANDLE_EXCEPTION();
27972799
}
2798-
2800+
27992801
lcname = zend_string_init(Z_STRVAL_P(function_name), cname_length, 0);
2800-
2802+
28012803
called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
28022804
if (UNEXPECTED(called_scope == NULL)) {
28032805
zend_string_release(lcname);
28042806
CHECK_EXCEPTION();
28052807
ZEND_VM_NEXT_OPCODE();
28062808
}
2807-
2809+
28082810
mname = zend_string_init(Z_STRVAL_P(function_name) + (cname_length + sizeof("::") - 1), mname_length, 0);
2809-
2811+
28102812
if (called_scope->get_static_method) {
28112813
fbc = called_scope->get_static_method(called_scope, mname);
28122814
} else {
@@ -2821,10 +2823,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_
28212823
zval_ptr_dtor_nogc(free_op2);
28222824
HANDLE_EXCEPTION();
28232825
}
2824-
2826+
28252827
zend_string_release(lcname);
28262828
zend_string_release(mname);
2827-
2829+
28282830
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
28292831
if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
28302832
zend_error(E_DEPRECATED,

0 commit comments

Comments
 (0)