From e9283c081970f350054d52891a1940fcbed21d51 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 24 Oct 2024 22:25:25 +0200 Subject: [PATCH] Fix GH-16574: Incorrect error "undefined method" messages The `get_method` object handler may change the object pointer. SPL does this in its iterator implementations. This causes the error message to change to another class which is confusing to the user. JIT handles this correctly. This patch aligns behaviour with JIT. Closes GH-16576. --- NEWS | 4 ++++ Zend/zend_vm_def.h | 2 +- Zend/zend_vm_execute.h | 24 ++++++++++++------------ ext/spl/tests/gh16574.phpt | 15 +++++++++++++++ 4 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 ext/spl/tests/gh16574.phpt diff --git a/NEWS b/NEWS index c2ec09c0051..d80da988e39 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.4.0RC4 +- Core: + . Fixed bug GH-16574 (Incorrect error "undefined method" messages). + (nielsdos) + - GD: . Fixed bug GH-16559 (UBSan abort in ext/gd/libgd/gd_interpolation.c:1007). (nielsdos) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7263c6eef6d..0eb81087856 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3625,7 +3625,7 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } FREE_OP2(); if ((OP1_TYPE & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f0ecc76bbbc..274f92456d2 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7209,7 +7209,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } if ((IS_CONST & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -9773,7 +9773,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if ((IS_CONST & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -12255,7 +12255,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } if ((IS_CONST & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -16648,7 +16648,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -18141,7 +18141,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -19548,7 +19548,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -34934,7 +34934,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_S fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } if ((IS_UNUSED & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -37103,7 +37103,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if ((IS_UNUSED & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -39748,7 +39748,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } if ((IS_UNUSED & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -44864,7 +44864,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_S fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } if ((IS_CV & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -48758,7 +48758,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if ((IS_CV & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { @@ -54353,7 +54353,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (RT_CONSTANT(opline, opline->op2) + 1) : NULL)); if (UNEXPECTED(fbc == NULL)) { if (EXPECTED(!EG(exception))) { - zend_undefined_method(obj->ce, Z_STR_P(function_name)); + zend_undefined_method(orig_obj->ce, Z_STR_P(function_name)); } if ((IS_CV & (IS_VAR|IS_TMP_VAR)) && GC_DELREF(orig_obj) == 0) { diff --git a/ext/spl/tests/gh16574.phpt b/ext/spl/tests/gh16574.phpt new file mode 100644 index 00000000000..0bcc6611a22 --- /dev/null +++ b/ext/spl/tests/gh16574.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-16574 (Incorrect error "undefined method" messages) +--CREDITS-- +YuanchengJiang +--FILE-- +doesnotexist("x"); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Call to undefined method CachingIterator::doesnotexist() in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d