summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-09-04 14:43:42 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-09-04 15:19:21 +0200
commitb6f76aca54164bdef8d59f06560a087752cff20f (patch)
tree177390ff670cff664fc20b0257d30442673922fe
parent4bb7282742d4d1686044cc95d127f518be2e84aa (diff)
downloadphp-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.phpt8
-rw-r--r--Zend/tests/call_to_deprecated_function_args.phpt43
-rw-r--r--Zend/zend_execute.c1
-rw-r--r--Zend/zend_vm_def.h41
-rw-r--r--Zend/zend_vm_execute.h79
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)) {