mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix bug #81303 improve match errors
This commit is contained in:
3
NEWS
3
NEWS
@@ -2,6 +2,9 @@ PHP NEWS
|
||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
?? ??? ????, PHP 8.1.0beta2
|
||||
|
||||
- Core:
|
||||
. Fixed bug #81303 (match error message improvements). (krakjoe)
|
||||
|
||||
- Mbstring:
|
||||
. Fixed bug #81298 (mb_detect_encoding() segfaults when 7bit encoding is
|
||||
specified). (Nikita)
|
||||
|
||||
@@ -7,7 +7,7 @@ $x = match (true) {};
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type bool in %s
|
||||
Fatal error: Uncaught UnhandledMatchError: Unhandled match case true in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
||||
|
||||
@@ -19,7 +19,7 @@ echo get_value(3) . "\n";
|
||||
1
|
||||
2
|
||||
|
||||
Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type int in %s
|
||||
Fatal error: Uncaught UnhandledMatchError: Unhandled match case 3 in %s:%d
|
||||
Stack trace:
|
||||
#0 %s: get_value(3)
|
||||
#1 {main}
|
||||
|
||||
@@ -53,13 +53,13 @@ var_dump(match(3) {
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(%d) "UnhandledMatchError: Unhandled match value of type bool in %s037.php:4
|
||||
string(%d) "UnhandledMatchError: Unhandled match case true in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}"
|
||||
string(%d) "UnhandledMatchError: Unhandled match value of type int in %s037.php:12
|
||||
string(%d) "UnhandledMatchError: Unhandled match case 6 in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}"
|
||||
string(%d) "UnhandledMatchError: Unhandled match value of type string in %s037.php:20
|
||||
string(%d) "UnhandledMatchError: Unhandled match case '3' in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}"
|
||||
string(3) "foo"
|
||||
|
||||
40
Zend/tests/match/043.phpt
Normal file
40
Zend/tests/match/043.phpt
Normal file
@@ -0,0 +1,40 @@
|
||||
--TEST--
|
||||
Match expression error messages
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Beep {}
|
||||
|
||||
function test(mixed $var) {
|
||||
try {
|
||||
match($var) {};
|
||||
} catch (UnhandledMatchError $e) {
|
||||
print $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
test(null);
|
||||
test(1);
|
||||
test(5.5);
|
||||
test(5.0);
|
||||
test("foo");
|
||||
test(true);
|
||||
test(false);
|
||||
test([1, 2, 3]);
|
||||
test(new Beep());
|
||||
// Testing long strings.
|
||||
test(str_repeat('e', 100));
|
||||
test(str_repeat("e\n", 100));
|
||||
?>
|
||||
--EXPECT--
|
||||
Unhandled match case NULL
|
||||
Unhandled match case 1
|
||||
Unhandled match case 5.5
|
||||
Unhandled match case 5.0
|
||||
Unhandled match case 'foo'
|
||||
Unhandled match case true
|
||||
Unhandled match case false
|
||||
Unhandled match case of type array
|
||||
Unhandled match case of type Beep
|
||||
Unhandled match case 'eeeeeeeeeeeeeee...'
|
||||
Unhandled match case 'e\ne\ne\ne\ne\ne\ne\ne...'
|
||||
@@ -13,7 +13,7 @@ require 'weak_include_strict_2.inc';
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: takes_int(): Argument #1 ($x) must be of type int, float given, called in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): takes_int(1)
|
||||
#0 %s(%d): takes_int(1.0)
|
||||
#1 %s(%d): require('%s')
|
||||
#2 {main}
|
||||
thrown in %sweak_include_strict_2.inc on line 5
|
||||
|
||||
@@ -15,6 +15,6 @@ function_declared_in_weak_mode(1.0);
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: function_declared_in_weak_mode(): Argument #1 ($x) must be of type int, float given, called in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): function_declared_in_weak_mode(1)
|
||||
#0 %s(%d): function_declared_in_weak_mode(1.0)
|
||||
#1 {main}
|
||||
thrown in %sstrict_call_weak_2.inc on line 5
|
||||
|
||||
@@ -15,6 +15,6 @@ function_declared_in_weak_mode(1.0);
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: function_declared_in_weak_mode(): Argument #1 ($x) must be of type int, float given, called in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): function_declared_in_weak_mode(1)
|
||||
#0 %s(%d): function_declared_in_weak_mode(1.0)
|
||||
#1 {main}
|
||||
thrown in %sstrict_call_weak_explicit_2.inc on line 5
|
||||
|
||||
@@ -13,7 +13,7 @@ require 'weak_include_strict_2.inc';
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: takes_int(): Argument #1 ($x) must be of type int, float given, called in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): takes_int(1)
|
||||
#0 %s(%d): takes_int(1.0)
|
||||
#1 %s(%d): require('%s')
|
||||
#2 {main}
|
||||
thrown in %sweak_include_strict_2.inc on line 5
|
||||
|
||||
@@ -491,49 +491,28 @@ static void _build_trace_args(zval *arg, smart_str *str) /* {{{ */
|
||||
*/
|
||||
|
||||
ZVAL_DEREF(arg);
|
||||
switch (Z_TYPE_P(arg)) {
|
||||
case IS_NULL:
|
||||
smart_str_appends(str, "NULL, ");
|
||||
break;
|
||||
case IS_STRING:
|
||||
smart_str_appendc(str, '\'');
|
||||
smart_str_append_escaped(str, Z_STRVAL_P(arg), MIN(Z_STRLEN_P(arg), EG(exception_string_param_max_len)));
|
||||
if (Z_STRLEN_P(arg) > EG(exception_string_param_max_len)) {
|
||||
smart_str_appends(str, "...', ");
|
||||
} else {
|
||||
smart_str_appends(str, "', ");
|
||||
|
||||
if (Z_TYPE_P(arg) <= IS_STRING) {
|
||||
smart_str_append_scalar(str, arg, EG(exception_string_param_max_len));
|
||||
smart_str_appends(str, ", ");
|
||||
} else {
|
||||
switch (Z_TYPE_P(arg)) {
|
||||
case IS_RESOURCE:
|
||||
smart_str_appends(str, "Resource id #");
|
||||
smart_str_append_long(str, Z_RES_HANDLE_P(arg));
|
||||
smart_str_appends(str, ", ");
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
smart_str_appends(str, "Array, ");
|
||||
break;
|
||||
case IS_OBJECT: {
|
||||
zend_string *class_name = Z_OBJ_HANDLER_P(arg, get_class_name)(Z_OBJ_P(arg));
|
||||
smart_str_appends(str, "Object(");
|
||||
smart_str_appends(str, ZSTR_VAL(class_name));
|
||||
smart_str_appends(str, "), ");
|
||||
zend_string_release_ex(class_name, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IS_FALSE:
|
||||
smart_str_appends(str, "false, ");
|
||||
break;
|
||||
case IS_TRUE:
|
||||
smart_str_appends(str, "true, ");
|
||||
break;
|
||||
case IS_RESOURCE:
|
||||
smart_str_appends(str, "Resource id #");
|
||||
smart_str_append_long(str, Z_RES_HANDLE_P(arg));
|
||||
smart_str_appends(str, ", ");
|
||||
break;
|
||||
case IS_LONG:
|
||||
smart_str_append_long(str, Z_LVAL_P(arg));
|
||||
smart_str_appends(str, ", ");
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
smart_str_append_double(
|
||||
str, Z_DVAL_P(arg), (int) EG(precision), /* zero_fraction */ false);
|
||||
smart_str_appends(str, ", ");
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
smart_str_appends(str, "Array, ");
|
||||
break;
|
||||
case IS_OBJECT: {
|
||||
zend_string *class_name = Z_OBJ_HANDLER_P(arg, get_class_name)(Z_OBJ_P(arg));
|
||||
smart_str_appends(str, "Object(");
|
||||
smart_str_appends(str, ZSTR_VAL(class_name));
|
||||
smart_str_appends(str, "), ");
|
||||
zend_string_release_ex(class_name, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,6 +824,25 @@ ZEND_COLD zend_never_inline void zend_verify_property_type_error(zend_property_i
|
||||
zend_string_release(type_str);
|
||||
}
|
||||
|
||||
ZEND_COLD void zend_match_unhandled_error(zval *value)
|
||||
{
|
||||
smart_str msg = {0};
|
||||
|
||||
if (Z_TYPE_P(value) <= IS_STRING) {
|
||||
smart_str_append_scalar(&msg, value, EG(exception_string_param_max_len));
|
||||
} else {
|
||||
smart_str_appendl(&msg, "of type ", sizeof("of type ")-1);
|
||||
smart_str_appends(&msg, zend_zval_type_name(value));
|
||||
}
|
||||
|
||||
smart_str_0(&msg);
|
||||
|
||||
zend_throw_exception_ex(
|
||||
zend_ce_unhandled_match_error, 0, "Unhandled match case %s", ZSTR_VAL(msg.s));
|
||||
|
||||
smart_str_free(&msg);
|
||||
}
|
||||
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(
|
||||
zend_property_info *info) {
|
||||
zend_throw_error(NULL, "Cannot modify readonly property %s::$%s",
|
||||
|
||||
@@ -469,6 +469,8 @@ ZEND_COLD void zend_verify_property_type_error(zend_property_info *info, zval *p
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
ZEND_COLD void zend_match_unhandled_error(zval *value);
|
||||
|
||||
END_EXTERN_C()
|
||||
|
||||
#endif /* ZEND_EXECUTE_H */
|
||||
|
||||
@@ -180,3 +180,44 @@ ZEND_API void ZEND_FASTCALL _smart_string_alloc(smart_string *str, size_t len)
|
||||
str->c = erealloc2(str->c, str->a + 1, str->len);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, zend_string *value, size_t length)
|
||||
{
|
||||
smart_str_append_escaped(str, ZSTR_VAL(value), MIN(length, ZSTR_LEN(value)));
|
||||
|
||||
if (ZSTR_LEN(value) > length) {
|
||||
smart_str_appendl(str, "...", sizeof("...")-1);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *dest, zval *value, size_t truncate) {
|
||||
ZEND_ASSERT(Z_TYPE_P(value) <= IS_STRING);
|
||||
|
||||
switch (Z_TYPE_P(value)) {
|
||||
case IS_UNDEF:
|
||||
case IS_NULL:
|
||||
smart_str_appendl(dest, "NULL", sizeof("NULL")-1);
|
||||
break;
|
||||
|
||||
case IS_TRUE:
|
||||
case IS_FALSE:
|
||||
smart_str_appends(dest, Z_TYPE_P(value) == IS_TRUE ? "true" : "false");
|
||||
break;
|
||||
|
||||
case IS_DOUBLE:
|
||||
smart_str_append_double(dest, Z_DVAL_P(value), (int) EG(precision), true);
|
||||
break;
|
||||
|
||||
case IS_LONG:
|
||||
smart_str_append_long(dest, Z_LVAL_P(value));
|
||||
break;
|
||||
|
||||
case IS_STRING:
|
||||
smart_str_appendc(dest, '\'');
|
||||
smart_str_append_escaped_truncated(dest, Z_STR_P(value), truncate);
|
||||
smart_str_appendc(dest, '\'');
|
||||
break;
|
||||
|
||||
EMPTY_SWITCH_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,8 @@ ZEND_API void ZEND_FASTCALL smart_str_append_double(
|
||||
smart_str *str, double num, int precision, bool zero_fraction);
|
||||
ZEND_API void smart_str_append_printf(smart_str *dest, const char *format, ...)
|
||||
ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
|
||||
|
||||
ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, zend_string *value, size_t length);
|
||||
ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *str, zval *value, size_t truncate);
|
||||
END_EXTERN_C()
|
||||
|
||||
static zend_always_inline size_t smart_str_alloc(smart_str *str, size_t len, bool persistent) {
|
||||
|
||||
@@ -8921,7 +8921,7 @@ ZEND_VM_COLD_CONST_HANDLER(197, ZEND_MATCH_ERROR, CONST|TMPVARCV, UNUSED)
|
||||
|
||||
SAVE_OPLINE();
|
||||
op = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
|
||||
zend_throw_exception_ex(zend_ce_unhandled_match_error, 0, "Unhandled match value of type %s", zend_zval_type_name(op));
|
||||
zend_match_unhandled_error(op);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
|
||||
@@ -10493,7 +10493,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MATCH_ERROR_SPEC_
|
||||
|
||||
SAVE_OPLINE();
|
||||
op = RT_CONSTANT(opline, opline->op1);
|
||||
zend_throw_exception_ex(zend_ce_unhandled_match_error, 0, "Unhandled match value of type %s", zend_zval_type_name(op));
|
||||
zend_match_unhandled_error(op);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
@@ -14019,7 +14019,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MATCH_ERROR_SPEC_TMPVARCV_UNUS
|
||||
|
||||
SAVE_OPLINE();
|
||||
op = EX_VAR(opline->op1.var);
|
||||
zend_throw_exception_ex(zend_ce_unhandled_match_error, 0, "Unhandled match value of type %s", zend_zval_type_name(op));
|
||||
zend_match_unhandled_error(op);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,6 @@ bool(false)
|
||||
|
||||
Fatal error: Uncaught TypeError: intltz_get_offset(): Argument #1 ($timezone) must be of type IntlTimeZone, null given in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): intltz_get_offset(NULL, %d, false, NULL, NULL)
|
||||
#0 %s(%d): intltz_get_offset(NULL, %f, false, NULL, NULL)
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
||||
|
||||
@@ -617,19 +617,8 @@ static int format_default_value(smart_str *str, zval *value, zend_class_entry *s
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (Z_TYPE(zv) == IS_TRUE) {
|
||||
smart_str_appends(str, "true");
|
||||
} else if (Z_TYPE(zv) == IS_FALSE) {
|
||||
smart_str_appends(str, "false");
|
||||
} else if (Z_TYPE(zv) == IS_NULL) {
|
||||
smart_str_appends(str, "NULL");
|
||||
} else if (Z_TYPE(zv) == IS_STRING) {
|
||||
smart_str_appendc(str, '\'');
|
||||
smart_str_appendl(str, Z_STRVAL(zv), MIN(Z_STRLEN(zv), 15));
|
||||
if (Z_STRLEN(zv) > 15) {
|
||||
smart_str_appends(str, "...");
|
||||
}
|
||||
smart_str_appendc(str, '\'');
|
||||
if (Z_TYPE(zv) <= IS_STRING) {
|
||||
smart_str_append_scalar(str, &zv, 15);
|
||||
} else if (Z_TYPE(zv) == IS_ARRAY) {
|
||||
smart_str_appends(str, "Array");
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user