diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-09-04 14:43:42 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-09-04 15:19:21 +0200 |
commit | b6f76aca54164bdef8d59f06560a087752cff20f (patch) | |
tree | 177390ff670cff664fc20b0257d30442673922fe | |
parent | 4bb7282742d4d1686044cc95d127f518be2e84aa (diff) | |
download | php-git-b6f76aca54164bdef8d59f06560a087752cff20f.tar.gz |
Improve exception handling for abstract/deprecated calls
Reuse existing arg freeing loop instead of duplicating it.
Additionally also handle deprecated in DO_FCALL_BY_NAME.
-rw-r--r-- | Zend/tests/call_to_abstract_method_args.phpt | 8 | ||||
-rw-r--r-- | Zend/tests/call_to_deprecated_function_args.phpt | 43 | ||||
-rw-r--r-- | Zend/zend_execute.c | 1 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 41 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 79 |
5 files changed, 119 insertions, 53 deletions
diff --git a/Zend/tests/call_to_abstract_method_args.phpt b/Zend/tests/call_to_abstract_method_args.phpt index 4f7f09e493..cbbc276d2c 100644 --- a/Zend/tests/call_to_abstract_method_args.phpt +++ b/Zend/tests/call_to_abstract_method_args.phpt @@ -13,6 +13,14 @@ try { echo $e->getMessage(), "\n"; } +$ret = new stdClass; +try { + $ret = Test::method(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + ?> --EXPECT-- Cannot call abstract method Test::method() +Cannot call abstract method Test::method() diff --git a/Zend/tests/call_to_deprecated_function_args.phpt b/Zend/tests/call_to_deprecated_function_args.phpt new file mode 100644 index 0000000000..5c3eb9ae16 --- /dev/null +++ b/Zend/tests/call_to_deprecated_function_args.phpt @@ -0,0 +1,43 @@ +--TEST-- +Check that arguments are freed when calling a deprecated function +--FILE-- +<?php + +set_error_handler(function($code, $msg) { + throw new Error($msg); +}); + +try { + ezmlm_hash(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$ret = new stdClass; +try { + $ret = ezmlm_hash(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + $fn = 'ezmlm_hash'; + $fn(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$ret = new stdClass; +try { + $fn = 'ezmlm_hash'; + $ret = $fn(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Function ezmlm_hash() is deprecated +Function ezmlm_hash() is deprecated +Function ezmlm_hash() is deprecated +Function ezmlm_hash() is deprecated diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index c831ef7ec7..70c4bdc8e9 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1132,7 +1132,6 @@ static zend_never_inline int zend_verify_internal_arg_types(zend_function *fbc, dummy_cache_slot = NULL; if (UNEXPECTED(!zend_verify_arg_type(fbc, i + 1, p, NULL, &dummy_cache_slot))) { EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); return 0; } p++; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1dec6a0a3f..428e2a12b4 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4075,8 +4075,12 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { zend_deprecated_function(fbc); if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + UNDEF_RESULT(); + if (!RETURN_VALUE_USED(opline)) { + ret = &retval; + ZVAL_UNDEF(ret); + } + ZEND_VM_C_GOTO(fcall_end); } } @@ -4085,10 +4089,12 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) { - zend_vm_stack_free_call_frame(call); - zend_rethrow_exception(execute_data); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + UNDEF_RESULT(); + if (!RETURN_VALUE_USED(opline)) { + ret = &retval; + ZVAL_UNDEF(ret); + } + ZEND_VM_C_GOTO(fcall_end); } ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; @@ -4106,6 +4112,8 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) #endif EG(current_execute_data) = execute_data; + +ZEND_VM_C_LABEL(fcall_end): zend_vm_stack_free_args(call); zend_vm_stack_free_call_frame(call); @@ -4128,6 +4136,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) zend_execute_data *call = EX(call); zend_function *fbc = call->func; zval *ret; + zval retval; SAVE_OPLINE(); EX(call) = call->prev_execute_data; @@ -4136,7 +4145,10 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) zend_abstract_method(fbc); ZEND_VM_C_LABEL(fcall_except): UNDEF_RESULT(); - zend_vm_stack_free_args(call); + if (!RETURN_VALUE_USED(opline)) { + ret = &retval; + ZVAL_UNDEF(ret); + } ZEND_VM_C_GOTO(fcall_end); } else { zend_deprecated_function(fbc); @@ -4167,15 +4179,12 @@ ZEND_VM_C_LABEL(fcall_except): zend_execute_ex(call); } } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { - zval retval; - call->prev_execute_data = execute_data; EG(current_execute_data) = call; if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) { - UNDEF_RESULT(); - ZEND_VM_C_GOTO(fcall_end); + ZEND_VM_C_GOTO(fcall_except); } ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; @@ -4198,15 +4207,13 @@ ZEND_VM_C_LABEL(fcall_except): #endif EG(current_execute_data) = execute_data; - zend_vm_stack_free_args(call); +ZEND_VM_C_LABEL(fcall_end): + zend_vm_stack_free_args(call); if (!RETURN_VALUE_USED(opline)) { i_zval_ptr_dtor(ret); } - } else { /* ZEND_OVERLOADED_FUNCTION */ - zval retval; - ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; call->prev_execute_data = execute_data; @@ -4221,7 +4228,6 @@ ZEND_VM_C_LABEL(fcall_except): } } -ZEND_VM_C_LABEL(fcall_end): if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) { OBJ_RELEASE(Z_OBJ(call->This)); } @@ -8291,14 +8297,13 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) EG(current_execute_data) = call->prev_execute_data; +ZEND_VM_C_LABEL(call_trampoline_end): zend_vm_stack_free_args(call); - if (ret == &retval) { zval_ptr_dtor(ret); } } -ZEND_VM_C_LABEL(call_trampoline_end): execute_data = EG(current_execute_data); if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3af0f5a0ef..47f7d1e15e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1413,8 +1413,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { zend_deprecated_function(fbc); if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + UNDEF_RESULT(); + if (!0) { + ret = &retval; + ZVAL_UNDEF(ret); + } + goto fcall_end; } } @@ -1423,10 +1427,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) { - zend_vm_stack_free_call_frame(call); - zend_rethrow_exception(execute_data); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + UNDEF_RESULT(); + if (!0) { + ret = &retval; + ZVAL_UNDEF(ret); + } + goto fcall_end; } ret = 0 ? EX_VAR(opline->result.var) : &retval; @@ -1444,6 +1450,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S #endif EG(current_execute_data) = execute_data; + +fcall_end: zend_vm_stack_free_args(call); zend_vm_stack_free_call_frame(call); @@ -1489,8 +1497,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { zend_deprecated_function(fbc); if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + UNDEF_RESULT(); + if (!1) { + ret = &retval; + ZVAL_UNDEF(ret); + } + goto fcall_end; } } @@ -1499,10 +1511,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) { - zend_vm_stack_free_call_frame(call); - zend_rethrow_exception(execute_data); - UNDEF_RESULT(); - HANDLE_EXCEPTION(); + UNDEF_RESULT(); + if (!1) { + ret = &retval; + ZVAL_UNDEF(ret); + } + goto fcall_end; } ret = 1 ? EX_VAR(opline->result.var) : &retval; @@ -1520,6 +1534,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S #endif EG(current_execute_data) = execute_data; + +fcall_end: zend_vm_stack_free_args(call); zend_vm_stack_free_call_frame(call); @@ -1542,6 +1558,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV zend_execute_data *call = EX(call); zend_function *fbc = call->func; zval *ret; + zval retval; SAVE_OPLINE(); EX(call) = call->prev_execute_data; @@ -1550,7 +1567,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV zend_abstract_method(fbc); fcall_except: UNDEF_RESULT(); - zend_vm_stack_free_args(call); + if (!0) { + ret = &retval; + ZVAL_UNDEF(ret); + } goto fcall_end; } else { zend_deprecated_function(fbc); @@ -1581,15 +1601,12 @@ fcall_except: zend_execute_ex(call); } } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { - zval retval; - call->prev_execute_data = execute_data; EG(current_execute_data) = call; if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) { - UNDEF_RESULT(); - goto fcall_end; + goto fcall_except; } ret = 0 ? EX_VAR(opline->result.var) : &retval; @@ -1612,15 +1629,13 @@ fcall_except: #endif EG(current_execute_data) = execute_data; - zend_vm_stack_free_args(call); +fcall_end: + zend_vm_stack_free_args(call); if (!0) { i_zval_ptr_dtor(ret); } - } else { /* ZEND_OVERLOADED_FUNCTION */ - zval retval; - ret = 0 ? EX_VAR(opline->result.var) : &retval; call->prev_execute_data = execute_data; @@ -1635,7 +1650,6 @@ fcall_except: } } -fcall_end: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) { OBJ_RELEASE(Z_OBJ(call->This)); } @@ -1656,6 +1670,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV zend_execute_data *call = EX(call); zend_function *fbc = call->func; zval *ret; + zval retval; SAVE_OPLINE(); EX(call) = call->prev_execute_data; @@ -1664,7 +1679,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV zend_abstract_method(fbc); fcall_except: UNDEF_RESULT(); - zend_vm_stack_free_args(call); + if (!1) { + ret = &retval; + ZVAL_UNDEF(ret); + } goto fcall_end; } else { zend_deprecated_function(fbc); @@ -1695,15 +1713,12 @@ fcall_except: zend_execute_ex(call); } } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { - zval retval; - call->prev_execute_data = execute_data; EG(current_execute_data) = call; if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) { - UNDEF_RESULT(); - goto fcall_end; + goto fcall_except; } ret = 1 ? EX_VAR(opline->result.var) : &retval; @@ -1726,15 +1741,13 @@ fcall_except: #endif EG(current_execute_data) = execute_data; - zend_vm_stack_free_args(call); +fcall_end: + zend_vm_stack_free_args(call); if (!1) { i_zval_ptr_dtor(ret); } - } else { /* ZEND_OVERLOADED_FUNCTION */ - zval retval; - ret = 1 ? EX_VAR(opline->result.var) : &retval; call->prev_execute_data = execute_data; @@ -1749,7 +1762,6 @@ fcall_except: } } -fcall_end: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) { OBJ_RELEASE(Z_OBJ(call->This)); } @@ -2810,14 +2822,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z EG(current_execute_data) = call->prev_execute_data; +call_trampoline_end: zend_vm_stack_free_args(call); - if (ret == &retval) { zval_ptr_dtor(ret); } } -call_trampoline_end: execute_data = EG(current_execute_data); if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { |