From: Nikita Popov Date: Wed, 4 Sep 2019 10:34:20 +0000 (+0200) Subject: Fix handling of abstract/deprecated exception X-Git-Tag: php-7.4.0RC2~90 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4bb7282742d4d1686044cc95d127f518be2e84aa;p=php Fix handling of abstract/deprecated exception The exception mechanism assumes that exceptions from DO_FCALL are already happening after the function call. This means that we are currently leaking the passed arguments, and I think we can also corrupt the VM stack due to incorrect frame linking in some cases (there are assertion failures if the VM stack page size is reduced). Instead handle the stack frame freeing manually for this special case. --- diff --git a/Zend/tests/call_to_abstract_method_args.phpt b/Zend/tests/call_to_abstract_method_args.phpt new file mode 100644 index 0000000000..4f7f09e493 --- /dev/null +++ b/Zend/tests/call_to_abstract_method_args.phpt @@ -0,0 +1,18 @@ +--TEST-- +Check that arguments are freed when a call to an abstract method throws +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Cannot call abstract method Test::method() diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 556a8f8493..c831ef7ec7 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1537,6 +1537,12 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(c ZSTR_VAL(fbc->common.function_name)); } +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_abstract_method(const zend_function *fbc) +{ + zend_throw_error(NULL, "Cannot call abstract method %s::%s()", + ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); +} + static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC) { zend_uchar c; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index aa7a80c95c..1dec6a0a3f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1047,16 +1047,6 @@ ZEND_VM_COLD_HELPER(zend_this_not_in_object_context_helper, ANY, ANY) HANDLE_EXCEPTION(); } -ZEND_VM_COLD_HELPER(zend_abstract_method_helper, ANY, ANY, zend_function *func) -{ - USE_OPLINE - - SAVE_OPLINE(); - zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name)); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); -} - ZEND_VM_COLD_HELPER(zend_undefined_function_helper, ANY, ANY) { USE_OPLINE @@ -4143,12 +4133,15 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_abstract_method_helper, func, fbc); + zend_abstract_method(fbc); +ZEND_VM_C_LABEL(fcall_except): + UNDEF_RESULT(); + zend_vm_stack_free_args(call); + ZEND_VM_C_GOTO(fcall_end); } else { zend_deprecated_function(fbc); if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + ZEND_VM_C_GOTO(fcall_except); } } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 6bc3bb2e94..3af0f5a0ef 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -781,16 +781,6 @@ static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_th HANDLE_EXCEPTION(); } -static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_abstract_method_helper_SPEC(zend_function *func ZEND_OPCODE_HANDLER_ARGS_DC) -{ - USE_OPLINE - - SAVE_OPLINE(); - zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name)); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); -} - static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_undefined_function_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -1557,12 +1547,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - ZEND_VM_TAIL_CALL(zend_abstract_method_helper_SPEC(fbc ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + zend_abstract_method(fbc); +fcall_except: + UNDEF_RESULT(); + zend_vm_stack_free_args(call); + goto fcall_end; } else { zend_deprecated_function(fbc); if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + goto fcall_except; } } } @@ -1668,12 +1661,15 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - ZEND_VM_TAIL_CALL(zend_abstract_method_helper_SPEC(fbc ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + zend_abstract_method(fbc); +fcall_except: + UNDEF_RESULT(); + zend_vm_stack_free_args(call); + goto fcall_end; } else { zend_deprecated_function(fbc); if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + goto fcall_except; } } }