From e5c7e0e4e81deea0ecbe4ca7fda8eb2b30067b1a Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 23 Oct 2026 00:02:28 +0200 Subject: [PATCH 1/4] JIT: Fix OP_DATA leak when ASSIGN_DIM fails Free OP_DATA when appending to a full array, and when converting a float or resource key throws, matching the VM. --- NEWS | 2 ++ ext/opcache/jit/zend_jit_helpers.c | 21 ++++++++------ ext/opcache/jit/zend_jit_ir.c | 1 + ext/opcache/tests/jit/assign_dim_018.phpt | 31 ++++++++++++++++++++ ext/opcache/tests/jit/assign_dim_019.phpt | 35 +++++++++++++++++++++++ ext/opcache/tests/jit/assign_dim_020.phpt | 35 +++++++++++++++++++++++ 6 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 ext/opcache/tests/jit/assign_dim_018.phpt create mode 100644 ext/opcache/tests/jit/assign_dim_019.phpt create mode 100644 ext/opcache/tests/jit/assign_dim_020.phpt diff --git a/NEWS b/NEWS index d79257caf334..eff773f9248e 100644 --- a/NEWS +++ b/NEWS @@ -230,6 +230,8 @@ PHP NEWS . Fixed bug GH-24988 (Incorrect opcode range check causes bugs with exceptions in function JIT). (ndossche, Jorg Sowa) . Fix opcache phar check. (ndossche) + . Fixed memory leak in JIT ASSIGN_DIM when the assignment fails. + (jorgsowa) - OpenSSL: . Fixed build and test compatibility with OpenSSL 4.0 and 4.1. diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 9504b5bf79ec..ca89771dfc69 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -922,11 +922,7 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim ZVAL_NULL(EX_VAR(opline->result.var)); } } - if (opline->opcode == ZEND_ASSIGN_DIM - && ((opline+1)->op1_type & (IS_VAR | IS_TMP_VAR))) { - zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); - } - return NULL; + goto free_op_data; } ZEND_FALLTHROUGH; case IS_NULL: @@ -954,13 +950,13 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim ZVAL_NULL(EX_VAR(opline->result.var)); } } - return NULL; + goto free_op_data; } if (EG(exception)) { if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); } - return NULL; + goto free_op_data; } } goto num_index; @@ -984,13 +980,13 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim ZVAL_NULL(EX_VAR(opline->result.var)); } } - return NULL; + goto free_op_data; } if (EG(exception)) { if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); } - return NULL; + goto free_op_data; } hval = Z_RES_HANDLE_P(dim); goto num_index; @@ -1013,6 +1009,13 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim return NULL; } +free_op_data: + if (opline->opcode == ZEND_ASSIGN_DIM + && ((opline+1)->op1_type & (IS_VAR | IS_TMP_VAR))) { + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + } + return NULL; + str_index: if (ZEND_HANDLE_NUMERIC(offset_key, hval)) { goto num_index; diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 53959a536a4a..b3b196593d14 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -13373,6 +13373,7 @@ static int zend_jit_assign_dim(zend_jit_ctx *jit, // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied"); jit_SET_EX_OPLINE(jit, opline); ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC)); + jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline); ir_END_list(end_inputs); diff --git a/ext/opcache/tests/jit/assign_dim_018.phpt b/ext/opcache/tests/jit/assign_dim_018.phpt new file mode 100644 index 000000000000..3fee8d5a70ac --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_018.phpt @@ -0,0 +1,31 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed when appending to a full array fails +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- + 1]; + $a[] = new D; +} + +try { + test(); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +dtor +Error: Cannot add element to the array as the next element is already occupied diff --git a/ext/opcache/tests/jit/assign_dim_019.phpt b/ext/opcache/tests/jit/assign_dim_019.phpt new file mode 100644 index 000000000000..2cdafe9ccdd2 --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_019.phpt @@ -0,0 +1,35 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed when a float key conversion throws +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +dtor +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/jit/assign_dim_020.phpt b/ext/opcache/tests/jit/assign_dim_020.phpt new file mode 100644 index 000000000000..e2688ef12b61 --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_020.phpt @@ -0,0 +1,35 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed when a resource key conversion throws +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +dtor +Exception: Resource ID#%d used as offset, casting to integer (%d) From 9e854fb147320def2f9618e010f3fc552e52bd6b Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 23 Oct 2026 11:55:21 +0200 Subject: [PATCH 2/4] Drop redundant array initialization from ASSIGN_DIM tests --- ext/opcache/tests/jit/assign_dim_019.phpt | 1 - ext/opcache/tests/jit/assign_dim_020.phpt | 1 - 2 files changed, 2 deletions(-) diff --git a/ext/opcache/tests/jit/assign_dim_019.phpt b/ext/opcache/tests/jit/assign_dim_019.phpt index 2cdafe9ccdd2..284757362a2d 100644 --- a/ext/opcache/tests/jit/assign_dim_019.phpt +++ b/ext/opcache/tests/jit/assign_dim_019.phpt @@ -20,7 +20,6 @@ set_error_handler(function ($errno, $errstr) { }); function test() { - $a = []; $a[1.5] = new D; } diff --git a/ext/opcache/tests/jit/assign_dim_020.phpt b/ext/opcache/tests/jit/assign_dim_020.phpt index e2688ef12b61..98f5f9842809 100644 --- a/ext/opcache/tests/jit/assign_dim_020.phpt +++ b/ext/opcache/tests/jit/assign_dim_020.phpt @@ -20,7 +20,6 @@ set_error_handler(function ($errno, $errstr) { }); function test() { - $a = []; $a[STDIN] = new D; } From ab3cef092a29186d5b84a78654860d8763aa7f42 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 23 Oct 2026 17:20:26 +0200 Subject: [PATCH 3/4] JIT: Keep ASSIGN_DIM OP_DATA ownership with the caller zend_jit_fetch_dim_w_helper() no longer frees OP_DATA, which zend_jit_assign_dim_helper() frees again after converting false to an array. The generated ASSIGN_DIM path selects dedicated fetch and append-failure helpers at compile time that free OP_DATA, so generated code size is unchanged. --- ext/opcache/jit/zend_jit_helpers.c | 49 ++++++++++++++--------- ext/opcache/jit/zend_jit_ir.c | 21 ++++++++-- ext/opcache/tests/jit/assign_dim_021.phpt | 34 ++++++++++++++++ ext/opcache/tests/jit/assign_dim_022.phpt | 34 ++++++++++++++++ 4 files changed, 116 insertions(+), 22 deletions(-) create mode 100644 ext/opcache/tests/jit/assign_dim_021.phpt create mode 100644 ext/opcache/tests/jit/assign_dim_022.phpt diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index ca89771dfc69..b317a1eac9bc 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -922,7 +922,7 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim ZVAL_NULL(EX_VAR(opline->result.var)); } } - goto free_op_data; + return NULL; } ZEND_FALLTHROUGH; case IS_NULL: @@ -950,13 +950,13 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim ZVAL_NULL(EX_VAR(opline->result.var)); } } - goto free_op_data; + return NULL; } if (EG(exception)) { if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); } - goto free_op_data; + return NULL; } } goto num_index; @@ -980,13 +980,13 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim ZVAL_NULL(EX_VAR(opline->result.var)); } } - goto free_op_data; + return NULL; } if (EG(exception)) { if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); } - goto free_op_data; + return NULL; } hval = Z_RES_HANDLE_P(dim); goto num_index; @@ -999,23 +999,9 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim default: zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), dim, BP_VAR_R); undef_result_after_exception(); - if (EG(opline_before_exception) - && (EG(opline_before_exception)+1)->opcode == ZEND_OP_DATA - && ((EG(opline_before_exception)+1)->op1_type & (IS_VAR|IS_TMP_VAR))) { - zend_execute_data *execute_data = EG(current_execute_data); - - zval_ptr_dtor_nogc(EX_VAR((EG(opline_before_exception)+1)->op1.var)); - } return NULL; } -free_op_data: - if (opline->opcode == ZEND_ASSIGN_DIM - && ((opline+1)->op1_type & (IS_VAR | IS_TMP_VAR))) { - zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); - } - return NULL; - str_index: if (ZEND_HANDLE_NUMERIC(offset_key, hval)) { goto num_index; @@ -1475,6 +1461,31 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_rw_helper(zval *object_ptr, zva // zend_jit_fetch_dim_obj_helper(object_ptr, dim, result, BP_VAR_UNSET); //} +static zval* ZEND_FASTCALL zend_jit_assign_dim_fetch_w_helper(zend_array *ht, zval *dim) +{ + zend_execute_data *execute_data = EG(current_execute_data); + /* EX(opline) points to HANDLE_EXCEPTION once the fetch throws */ + const zend_op *opline = EX(opline); + zval *retval = zend_jit_fetch_dim_w_helper(ht, dim); + + if (UNEXPECTED(!retval)) { + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + } + return retval; +} + +static ZEND_COLD void ZEND_FASTCALL zend_jit_assign_dim_cannot_add_element(void) +{ + zend_execute_data *execute_data = EG(current_execute_data); + const zend_op *opline = EX(opline); + + if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + zend_cannot_add_element(); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); +} + static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim, zval *value, zval *result) { if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index b3b196593d14..47c151b2a2b1 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -243,6 +243,7 @@ static size_t tsrm_tls_offset = 0; _(undefined_offset, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(undefined_key, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(cannot_add_element, IR_FUNCTION | IR_FASTCALL_FUNC) \ + _(assign_dim_cannot_add_element, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(assign_const, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(assign_tmp, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(assign_var, IR_FUNCTION | IR_FASTCALL_FUNC) \ @@ -2169,6 +2170,12 @@ static int zend_jit_invalid_this_stub(zend_jit_ctx *jit) return 1; } +static int zend_jit_assign_dim_cannot_add_element_stub(zend_jit_ctx *jit) +{ + ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_cannot_add_element)); + return 1; +} + static int zend_jit_undefined_function_stub(zend_jit_ctx *jit) { // JIT: load EX(opline) @@ -3139,6 +3146,7 @@ static void zend_jit_setup_disasm(void) REGISTER_HELPER(zend_jit_fetch_dim_isset_helper); REGISTER_HELPER(zend_jit_fetch_dim_rw_helper); REGISTER_HELPER(zend_jit_fetch_dim_w_helper); + REGISTER_HELPER(zend_jit_assign_dim_fetch_w_helper); REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper); REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper); REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper); @@ -12437,7 +12445,11 @@ static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx *jit, ir_END_list(*end_inputs); break; case BP_VAR_W: - ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref); + if (opline->opcode == ZEND_ASSIGN_DIM && ((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))) { + ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_assign_dim_fetch_w_helper), ht_ref, ref); + } else { + ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref); + } if_found = ir_IF(ref); ir_IF_TRUE(if_found); ir_refs_add(found_inputs, ir_END()); @@ -13372,8 +13384,11 @@ static int zend_jit_assign_dim(zend_jit_ctx *jit, // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied"); jit_SET_EX_OPLINE(jit, opline); - ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC)); - jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline); + if ((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR)) { + ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_dim_cannot_add_element, IR_FASTCALL_FUNC)); + } else { + ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC)); + } ir_END_list(end_inputs); diff --git a/ext/opcache/tests/jit/assign_dim_021.phpt b/ext/opcache/tests/jit/assign_dim_021.phpt new file mode 100644 index 000000000000..6965ea6979bc --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_021.phpt @@ -0,0 +1,34 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed once when a float key conversion throws on a false container +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/jit/assign_dim_022.phpt b/ext/opcache/tests/jit/assign_dim_022.phpt new file mode 100644 index 000000000000..3557466ba879 --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_022.phpt @@ -0,0 +1,34 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed once when a resource key conversion throws on a false container +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +Exception: Resource ID#%d used as offset, casting to integer (%d) From 34810d56146d2250984ad2d0c85578ca00f91e00 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Tue, 3 Nov 2026 18:40:58 +0100 Subject: [PATCH 4/4] JIT: Free ASSIGN_DIM OP_DATA inline on append failure Drop the cannot-add-element stub and helper in favour of jit_FREE_OP, only load opline in the fetch helper's failure path, and add tests for the remaining OP_DATA failure paths. --- ext/opcache/jit/zend_jit_helpers.c | 19 +++---------- ext/opcache/jit/zend_jit_ir.c | 14 ++-------- ext/opcache/tests/jit/assign_dim_021.phpt | 10 ++++++- ext/opcache/tests/jit/assign_dim_022.phpt | 10 ++++++- ext/opcache/tests/jit/assign_dim_023.phpt | 30 ++++++++++++++++++++ ext/opcache/tests/jit/assign_dim_024.phpt | 34 +++++++++++++++++++++++ ext/opcache/tests/jit/assign_dim_025.phpt | 34 +++++++++++++++++++++++ ext/opcache/tests/jit/assign_dim_026.phpt | 34 +++++++++++++++++++++++ ext/opcache/tests/jit/assign_dim_027.phpt | 32 +++++++++++++++++++++ 9 files changed, 188 insertions(+), 29 deletions(-) create mode 100644 ext/opcache/tests/jit/assign_dim_023.phpt create mode 100644 ext/opcache/tests/jit/assign_dim_024.phpt create mode 100644 ext/opcache/tests/jit/assign_dim_025.phpt create mode 100644 ext/opcache/tests/jit/assign_dim_026.phpt create mode 100644 ext/opcache/tests/jit/assign_dim_027.phpt diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index b317a1eac9bc..b52f2cc83636 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1463,29 +1463,18 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_rw_helper(zval *object_ptr, zva static zval* ZEND_FASTCALL zend_jit_assign_dim_fetch_w_helper(zend_array *ht, zval *dim) { - zend_execute_data *execute_data = EG(current_execute_data); - /* EX(opline) points to HANDLE_EXCEPTION once the fetch throws */ - const zend_op *opline = EX(opline); zval *retval = zend_jit_fetch_dim_w_helper(ht, dim); if (UNEXPECTED(!retval)) { + zend_execute_data *execute_data = EG(current_execute_data); + /* Throwing replaces EX(opline) with HANDLE_EXCEPTION */ + const zend_op *opline = EG(exception) ? EG(opline_before_exception) : EX(opline); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } return retval; } -static ZEND_COLD void ZEND_FASTCALL zend_jit_assign_dim_cannot_add_element(void) -{ - zend_execute_data *execute_data = EG(current_execute_data); - const zend_op *opline = EX(opline); - - if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - } - zend_cannot_add_element(); - zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); -} - static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim, zval *value, zval *result) { if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 47c151b2a2b1..351f6d601a1a 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -243,7 +243,6 @@ static size_t tsrm_tls_offset = 0; _(undefined_offset, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(undefined_key, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(cannot_add_element, IR_FUNCTION | IR_FASTCALL_FUNC) \ - _(assign_dim_cannot_add_element, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(assign_const, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(assign_tmp, IR_FUNCTION | IR_FASTCALL_FUNC) \ _(assign_var, IR_FUNCTION | IR_FASTCALL_FUNC) \ @@ -2170,12 +2169,6 @@ static int zend_jit_invalid_this_stub(zend_jit_ctx *jit) return 1; } -static int zend_jit_assign_dim_cannot_add_element_stub(zend_jit_ctx *jit) -{ - ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_cannot_add_element)); - return 1; -} - static int zend_jit_undefined_function_stub(zend_jit_ctx *jit) { // JIT: load EX(opline) @@ -13384,11 +13377,8 @@ static int zend_jit_assign_dim(zend_jit_ctx *jit, // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied"); jit_SET_EX_OPLINE(jit, opline); - if ((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR)) { - ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_dim_cannot_add_element, IR_FASTCALL_FUNC)); - } else { - ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC)); - } + ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC)); + jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL); ir_END_list(end_inputs); diff --git a/ext/opcache/tests/jit/assign_dim_021.phpt b/ext/opcache/tests/jit/assign_dim_021.phpt index 6965ea6979bc..2d3c89c67079 100644 --- a/ext/opcache/tests/jit/assign_dim_021.phpt +++ b/ext/opcache/tests/jit/assign_dim_021.phpt @@ -5,10 +5,17 @@ opcache.enable=1 opcache.enable_cli=1 opcache.file_update_protection=0 opcache.jit=function +zend.exception_ignore_args=1 --EXTENSIONS-- opcache --FILE-- getMessage(), "\n"; } ?> --EXPECT-- +dtor Exception: Implicit conversion from float 1.5 to int loses precision diff --git a/ext/opcache/tests/jit/assign_dim_022.phpt b/ext/opcache/tests/jit/assign_dim_022.phpt index 3557466ba879..de263bcb00c9 100644 --- a/ext/opcache/tests/jit/assign_dim_022.phpt +++ b/ext/opcache/tests/jit/assign_dim_022.phpt @@ -5,10 +5,17 @@ opcache.enable=1 opcache.enable_cli=1 opcache.file_update_protection=0 opcache.jit=function +zend.exception_ignore_args=1 --EXTENSIONS-- opcache --FILE-- getMessage(), "\n"; } ?> --EXPECTF-- +dtor Exception: Resource ID#%d used as offset, casting to integer (%d) diff --git a/ext/opcache/tests/jit/assign_dim_023.phpt b/ext/opcache/tests/jit/assign_dim_023.phpt new file mode 100644 index 000000000000..a398ba9f4872 --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_023.phpt @@ -0,0 +1,30 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed when the key is an illegal offset +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +dtor +TypeError: Cannot access offset of type array on array diff --git a/ext/opcache/tests/jit/assign_dim_024.phpt b/ext/opcache/tests/jit/assign_dim_024.phpt new file mode 100644 index 000000000000..2111a2d2dcec --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_024.phpt @@ -0,0 +1,34 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed when an undefined key warning throws +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +dtor +Exception: Undefined variable $k diff --git a/ext/opcache/tests/jit/assign_dim_025.phpt b/ext/opcache/tests/jit/assign_dim_025.phpt new file mode 100644 index 000000000000..0b5a48c1684c --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_025.phpt @@ -0,0 +1,34 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed when the array is destroyed by a float key notice +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECT-- +dtor +NULL diff --git a/ext/opcache/tests/jit/assign_dim_026.phpt b/ext/opcache/tests/jit/assign_dim_026.phpt new file mode 100644 index 000000000000..005fd427d36f --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_026.phpt @@ -0,0 +1,34 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed when the array is destroyed by an undefined key warning +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECT-- +dtor +NULL diff --git a/ext/opcache/tests/jit/assign_dim_027.phpt b/ext/opcache/tests/jit/assign_dim_027.phpt new file mode 100644 index 000000000000..b516b431e4a8 --- /dev/null +++ b/ext/opcache/tests/jit/assign_dim_027.phpt @@ -0,0 +1,32 @@ +--TEST-- +JIT ASSIGN_DIM: OP_DATA is freed when appending to a full array fails and the result is used +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit=function +--EXTENSIONS-- +opcache +--FILE-- + 1]; + $x = ($a[] = new D); + var_dump($x); +} + +try { + test(); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +dtor +Error: Cannot add element to the array as the next element is already occupied