1
0
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:
Joe Watkins
2021-07-30 00:19:47 +02:00
parent 604848188b
commit 05ef6334cd
18 changed files with 143 additions and 69 deletions

3
NEWS
View File

@@ -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)

View File

@@ -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

View File

@@ -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}

View File

@@ -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
View 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...'

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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",

View File

@@ -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 */

View File

@@ -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();
}
}

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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 {