Skip to content

Commit 28d83f6

Browse files
committed
Clean up frameless reentry copies after handler return
1 parent 9ce623c commit 28d83f6

6 files changed

Lines changed: 79 additions & 21 deletions

File tree

Zend/zend_execute.c

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,11 +1673,6 @@ ZEND_API bool zend_frameless_protect_args_for_reentry(void)
16731673
return true;
16741674
}
16751675

1676-
ZEND_API void zend_frameless_schedule_reentry_cleanup(void)
1677-
{
1678-
zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
1679-
}
1680-
16811676
static bool zend_frameless_reentry_copies_in_use(zend_frameless_reentry_copies *copies)
16821677
{
16831678
for (zend_execute_data *execute_data = EG(current_execute_data);
@@ -1691,31 +1686,48 @@ static bool zend_frameless_reentry_copies_in_use(zend_frameless_reentry_copies *
16911686
return false;
16921687
}
16931688

1694-
static void zend_frameless_cleanup_reentry_copies_ex(bool force)
1689+
static void zend_frameless_free_reentry_copies(zend_frameless_reentry_copies *copies)
1690+
{
1691+
for (uint32_t i = 0; i < 3; i++) {
1692+
if (copies->copied_args & (1u << i)) {
1693+
zval_ptr_dtor(&copies->args[i]);
1694+
}
1695+
}
1696+
1697+
efree(copies);
1698+
}
1699+
1700+
ZEND_API void zend_frameless_cleanup_reentry_copies_for_handler(zend_execute_data *execute_data, const zend_op *opline)
16951701
{
16961702
zend_frameless_reentry_copies **next = &EG(frameless_reentry_copies);
16971703

16981704
while (*next) {
16991705
zend_frameless_reentry_copies *copies = *next;
17001706

1701-
if (!force && zend_frameless_reentry_copies_in_use(copies)) {
1707+
if (copies->execute_data != execute_data || copies->opline != opline) {
17021708
next = &copies->prev;
17031709
continue;
17041710
}
17051711

17061712
*next = copies->prev;
1713+
zend_frameless_free_reentry_copies(copies);
1714+
}
1715+
}
17071716

1708-
for (uint32_t i = 0; i < 3; i++) {
1709-
if (copies->copied_args & (1u << i)) {
1710-
zval_ptr_dtor(&copies->args[i]);
1711-
}
1712-
}
1717+
static void zend_frameless_cleanup_reentry_copies_ex(bool force)
1718+
{
1719+
zend_frameless_reentry_copies **next = &EG(frameless_reentry_copies);
17131720

1714-
efree(copies);
1715-
}
1721+
while (*next) {
1722+
zend_frameless_reentry_copies *copies = *next;
17161723

1717-
if (EG(frameless_reentry_copies)) {
1718-
zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
1724+
if (!force && zend_frameless_reentry_copies_in_use(copies)) {
1725+
next = &copies->prev;
1726+
continue;
1727+
}
1728+
1729+
*next = copies->prev;
1730+
zend_frameless_free_reentry_copies(copies);
17191731
}
17201732
}
17211733

Zend/zend_execute.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(uint8_t opcode);
429429

430430
ZEND_API zval *zend_get_zval_ptr(const zend_op *opline, int op_type, const znode_op *node, const zend_execute_data *execute_data);
431431
ZEND_API bool zend_frameless_protect_args_for_reentry(void);
432-
ZEND_API void zend_frameless_schedule_reentry_cleanup(void);
432+
ZEND_API void zend_frameless_cleanup_reentry_copies_for_handler(zend_execute_data *execute_data, const zend_op *opline);
433433
ZEND_API void zend_frameless_cleanup_reentry_copies(void);
434434
ZEND_API void zend_frameless_cleanup_reentry_copies_force(void);
435435

Zend/zend_object_handlers.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,13 +2558,10 @@ ZEND_API zend_result zend_std_cast_object_tostring(zend_object *readobj, zval *w
25582558
zend_class_entry *ce = readobj->ce;
25592559
if (ce->__tostring) {
25602560
zval retval;
2561-
bool frameless_reentry = zend_frameless_protect_args_for_reentry();
2561+
zend_frameless_protect_args_for_reentry();
25622562
GC_ADDREF(readobj);
25632563
zend_call_known_instance_method_with_0_params(ce->__tostring, readobj, &retval);
25642564
zend_object_release(readobj);
2565-
if (frameless_reentry) {
2566-
zend_frameless_schedule_reentry_cleanup();
2567-
}
25682565
if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
25692566
ZVAL_COPY_VALUE(writeobj, &retval);
25702567
return SUCCESS;

Zend/zend_vm_def.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9690,6 +9690,9 @@ ZEND_VM_HANDLER(204, ZEND_FRAMELESS_ICALL_0, UNUSED, UNUSED, SPEC(OBSERVER))
96909690
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
96919691
function(EX_VAR(opline->result.var));
96929692
}
9693+
if (UNEXPECTED(EG(frameless_reentry_copies))) {
9694+
zend_frameless_cleanup_reentry_copies_for_handler(execute_data, opline);
9695+
}
96939696
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
96949697
}
96959698

@@ -9715,6 +9718,9 @@ ZEND_VM_HANDLER(205, ZEND_FRAMELESS_ICALL_1, ANY, UNUSED, SPEC(OBSERVER))
97159718
zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline);
97169719
function(result, arg1);
97179720
}
9721+
if (UNEXPECTED(EG(frameless_reentry_copies))) {
9722+
zend_frameless_cleanup_reentry_copies_for_handler(execute_data, opline);
9723+
}
97189724
FREE_OP1();
97199725
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
97209726
}
@@ -9743,6 +9749,9 @@ ZEND_VM_HANDLER(206, ZEND_FRAMELESS_ICALL_2, ANY, ANY, SPEC(OBSERVER))
97439749
zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline);
97449750
function(result, arg1, arg2);
97459751
}
9752+
if (UNEXPECTED(EG(frameless_reentry_copies))) {
9753+
zend_frameless_cleanup_reentry_copies_for_handler(execute_data, opline);
9754+
}
97469755

97479756
FREE_OP1();
97489757
/* Set OP1 to UNDEF in case FREE_OP2() throws. */
@@ -9779,6 +9788,9 @@ ZEND_VM_HANDLER(207, ZEND_FRAMELESS_ICALL_3, ANY, ANY, SPEC(OBSERVER))
97799788
zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline);
97809789
function(result, arg1, arg2, arg3);
97819790
}
9791+
if (UNEXPECTED(EG(frameless_reentry_copies))) {
9792+
zend_frameless_cleanup_reentry_copies_for_handler(execute_data, opline);
9793+
}
97829794

97839795
FREE_OP1();
97849796
/* Set to UNDEF in case FREE_OP2() throws. */

Zend/zend_vm_execute.h

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/opcache/jit/zend_jit_ir.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17513,6 +17513,15 @@ static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
1751317513
return skip;
1751417514
}
1751517515

17516+
static void jit_frameless_cleanup_reentry_copies(zend_jit_ctx *jit, const zend_op *opline)
17517+
{
17518+
ir_ref if_copies = ir_IF(ir_LOAD_A(jit_EG(frameless_reentry_copies)));
17519+
ir_IF_TRUE_cold(if_copies);
17520+
ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)zend_frameless_cleanup_reentry_copies_for_handler),
17521+
jit_FP(jit), ir_CONST_ADDR((size_t)opline));
17522+
ir_MERGE_WITH_EMPTY_FALSE(if_copies);
17523+
}
17524+
1751617525
static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
1751717526
{
1751817527
jit_SET_EX_OPLINE(jit, opline);
@@ -17533,6 +17542,7 @@ static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
1753317542
ir_MERGE_WITH(skip_observer);
1753417543
}
1753517544

17545+
jit_frameless_cleanup_reentry_copies(jit, opline);
1753617546
zend_jit_check_exception(jit);
1753717547
}
1753817548

@@ -17572,6 +17582,7 @@ static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint3
1757217582
ir_MERGE_WITH(skip_observer);
1757317583
}
1757417584

17585+
jit_frameless_cleanup_reentry_copies(jit, opline);
1757517586
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
1757617587
zend_jit_check_exception(jit);
1757717588
}
@@ -17626,6 +17637,7 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint3
1762617637
ir_MERGE_WITH(skip_observer);
1762717638
}
1762817639

17640+
jit_frameless_cleanup_reentry_copies(jit, opline);
1762917641
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
1763017642
/* Set OP1 to UNDEF in case FREE_OP2() throws. */
1763117643
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0
@@ -17707,6 +17719,7 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint3
1770717719
ir_MERGE_WITH(skip_observer);
1770817720
}
1770917721

17722+
jit_frameless_cleanup_reentry_copies(jit, opline);
1771017723
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
1771117724
/* Set OP1 to UNDEF in case FREE_OP2() throws. */
1771217725
bool op1_undef = false;

0 commit comments

Comments
 (0)