diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0750a02db8b..c6d37e57a0d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3044,13 +3044,24 @@ ZEND_VM_HOT_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY) zval *var; USE_OPLINE - SAVE_OPLINE(); var = EX_VAR(opline->op1.var); - if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { - zend_hash_iterator_del(Z_FE_ITER_P(var)); + if (Z_TYPE_P(var) != IS_ARRAY) { + SAVE_OPLINE(); + if (Z_FE_ITER_P(var) != (uint32_t)-1) { + zend_hash_iterator_del(Z_FE_ITER_P(var)); + } + zval_ptr_dtor_nogc(var); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } - zval_ptr_dtor_nogc(var); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + + /* This is freeing an array. Use an inlined version of zval_ptr_dtor_nogc. */ + /* PHP only needs to save the opline and check for an exception if the last reference to the array was garbage collected (destructors of elements in the array could throw an exception) */ + if (Z_REFCOUNTED_P(var) && !Z_DELREF_P(var)) { + SAVE_OPLINE(); + rc_dtor_func(Z_COUNTED_P(var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + ZEND_VM_NEXT_OPCODE(); } ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index d1ef53128f6..7e173dc2f70 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -12882,13 +12882,24 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FREE_SPEC_TMPVA zval *var; USE_OPLINE - SAVE_OPLINE(); var = EX_VAR(opline->op1.var); - if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { - zend_hash_iterator_del(Z_FE_ITER_P(var)); + if (Z_TYPE_P(var) != IS_ARRAY) { + SAVE_OPLINE(); + if (Z_FE_ITER_P(var) != (uint32_t)-1) { + zend_hash_iterator_del(Z_FE_ITER_P(var)); + } + zval_ptr_dtor_nogc(var); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } - zval_ptr_dtor_nogc(var); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + + /* This is freeing an array. Use an inlined version of zval_ptr_dtor_nogc. */ + /* PHP only needs to save the opline and check for an exception if the last reference to the array was garbage collected (destructors of elements in the array could throw an exception) */ + if (Z_REFCOUNTED_P(var) && !Z_DELREF_P(var)) { + SAVE_OPLINE(); + rc_dtor_func(Z_COUNTED_P(var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + ZEND_VM_NEXT_OPCODE(); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)