Handle "non well formed" exception during ZPP

Previously if the "non well formed" notice was converted into an
exception we'd still end up executing the function.

Also drop the now unnecessary EG(exception) checks in the engine.

Additionally remote a bogus exception in zend_is_callable: It
should only be writing to error, but not directly throwing.
This commit is contained in:
Nikita Popov 2019-10-08 16:53:23 +02:00
parent 68b26ff8cf
commit 21148679d1
7 changed files with 46 additions and 10 deletions

View File

@ -30,8 +30,7 @@ C::foo();
--EXPECTF--
Exception: Cannot call abstract method C::foo() in %sexception_017.php on line %d
Exception: Argument 1 passed to foo() must be callable, string given, called in %sexception_017.php on line %d
Exception: Cannot call abstract method C::foo()
Exception: Argument 1 passed to foo() must be callable, string given, called in %s on line %d
Fatal error: Uncaught Error: Cannot call abstract method C::foo() in %sexception_017.php:%d
Stack trace:

View File

@ -0,0 +1,22 @@
--TEST--
A "non well formed" notice converted to exception should result in a ZPP failure
--FILE--
<?php
set_error_handler(function($_, $msg) {
throw new Exception($msg);
}, E_NOTICE);
try {
wordwrap("foo", "123foo", "");
} catch (Exception $e) {
echo $e, "\n";
}
?>
--EXPECTF--
Exception: A non well formed numeric value encountered in %s:%d
Stack trace:
#0 [internal function]: {closure}(%s)
#1 %s(%d): wordwrap('foo', '123foo', '')
#2 {main}

View File

@ -438,6 +438,9 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest)
return 0;
}
}
if (UNEXPECTED(EG(exception))) {
return 0;
}
} else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
*dest = 0;
} else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
@ -479,6 +482,9 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_long_cap_weak(zval *arg, zend_long *de
return 0;
}
}
if (UNEXPECTED(EG(exception))) {
return 0;
}
} else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
*dest = 0;
} else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
@ -514,6 +520,9 @@ ZEND_API int ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest) /
return 0;
}
}
if (UNEXPECTED(EG(exception))) {
return 0;
}
} else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
*dest = 0.0;
} else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
@ -3163,12 +3172,9 @@ get_function_via_handler:
if (retval) {
if (fcc->calling_scope && !call_via_handler) {
if (fcc->function_handler->common.fn_flags & ZEND_ACC_ABSTRACT) {
retval = 0;
if (error) {
zend_spprintf(error, 0, "cannot call abstract method %s::%s()", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name));
retval = 0;
} else {
zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name));
retval = 0;
}
} else if (!fcc->object && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
int severity;

View File

@ -792,6 +792,12 @@ static ZEND_COLD void zend_verify_arg_error(
const char *fname, *fsep, *fclass;
const char *need_msg, *need_kind, *need_or_null, *given_msg, *given_kind;
if (EG(exception)) {
/* The type verification itself might have already thrown an exception
* through a promoted warning. */
return;
}
if (value) {
zend_verify_type_error_common(
zf, arg_info, ce, value,

View File

@ -3131,6 +3131,9 @@ process_double:
}
if (allow_errors == -1) {
zend_error(E_NOTICE, "A non well formed numeric value encountered");
if (EG(exception)) {
return 0;
}
}
}

View File

@ -5209,7 +5209,7 @@ ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED|CACHE_SLOT)
zval *param = EX_VAR(opline->result.var);
SAVE_OPLINE();
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) {
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)))) {
HANDLE_EXCEPTION();
}
}
@ -5257,7 +5257,7 @@ ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT)
zval *default_value = RT_CONSTANT(opline, opline->op2);
SAVE_OPLINE();
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)) || EG(exception))) {
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)))) {
HANDLE_EXCEPTION();
}
}

View File

@ -3060,7 +3060,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CON
zval *default_value = RT_CONSTANT(opline, opline->op2);
SAVE_OPLINE();
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)) || EG(exception))) {
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)))) {
HANDLE_EXCEPTION();
}
}
@ -3139,7 +3139,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_UNUSED_H
zval *param = EX_VAR(opline->result.var);
SAVE_OPLINE();
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) {
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)))) {
HANDLE_EXCEPTION();
}
}