Skip to content

Commit 05ef633

Browse files
committed
Fix bug #81303 improve match errors
1 parent 6048481 commit 05ef633

18 files changed

+143
-69
lines changed

NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.1.0beta2
44

5+
- Core:
6+
. Fixed bug #81303 (match error message improvements). (krakjoe)
7+
58
- Mbstring:
69
. Fixed bug #81298 (mb_detect_encoding() segfaults when 7bit encoding is
710
specified). (Nikita)

Zend/tests/match/006.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ $x = match (true) {};
77

88
?>
99
--EXPECTF--
10-
Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type bool in %s
10+
Fatal error: Uncaught UnhandledMatchError: Unhandled match case true in %s:%d
1111
Stack trace:
1212
#0 {main}
1313
thrown in %s on line %d

Zend/tests/match/007.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ echo get_value(3) . "\n";
1919
1
2020
2
2121

22-
Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type int in %s
22+
Fatal error: Uncaught UnhandledMatchError: Unhandled match case 3 in %s:%d
2323
Stack trace:
2424
#0 %s: get_value(3)
2525
#1 {main}

Zend/tests/match/037.phpt

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ var_dump(match(3) {
5353

5454
?>
5555
--EXPECTF--
56-
string(%d) "UnhandledMatchError: Unhandled match value of type bool in %s037.php:4
56+
string(%d) "UnhandledMatchError: Unhandled match case true in %s:%d
5757
Stack trace:
5858
#0 {main}"
59-
string(%d) "UnhandledMatchError: Unhandled match value of type int in %s037.php:12
59+
string(%d) "UnhandledMatchError: Unhandled match case 6 in %s:%d
6060
Stack trace:
6161
#0 {main}"
62-
string(%d) "UnhandledMatchError: Unhandled match value of type string in %s037.php:20
62+
string(%d) "UnhandledMatchError: Unhandled match case '3' in %s:%d
6363
Stack trace:
6464
#0 {main}"
6565
string(3) "foo"

Zend/tests/match/043.phpt

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
Match expression error messages
3+
--FILE--
4+
<?php
5+
6+
class Beep {}
7+
8+
function test(mixed $var) {
9+
try {
10+
match($var) {};
11+
} catch (UnhandledMatchError $e) {
12+
print $e->getMessage() . PHP_EOL;
13+
}
14+
}
15+
16+
test(null);
17+
test(1);
18+
test(5.5);
19+
test(5.0);
20+
test("foo");
21+
test(true);
22+
test(false);
23+
test([1, 2, 3]);
24+
test(new Beep());
25+
// Testing long strings.
26+
test(str_repeat('e', 100));
27+
test(str_repeat("e\n", 100));
28+
?>
29+
--EXPECT--
30+
Unhandled match case NULL
31+
Unhandled match case 1
32+
Unhandled match case 5.5
33+
Unhandled match case 5.0
34+
Unhandled match case 'foo'
35+
Unhandled match case true
36+
Unhandled match case false
37+
Unhandled match case of type array
38+
Unhandled match case of type Beep
39+
Unhandled match case 'eeeeeeeeeeeeeee...'
40+
Unhandled match case 'e\ne\ne\ne\ne\ne\ne\ne...'

Zend/tests/type_declarations/explicit_weak_include_strict.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require 'weak_include_strict_2.inc';
1313
--EXPECTF--
1414
Fatal error: Uncaught TypeError: takes_int(): Argument #1 ($x) must be of type int, float given, called in %s:%d
1515
Stack trace:
16-
#0 %s(%d): takes_int(1)
16+
#0 %s(%d): takes_int(1.0)
1717
#1 %s(%d): require('%s')
1818
#2 {main}
1919
thrown in %sweak_include_strict_2.inc on line 5

Zend/tests/type_declarations/strict_call_weak.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ function_declared_in_weak_mode(1.0);
1515
--EXPECTF--
1616
Fatal error: Uncaught TypeError: function_declared_in_weak_mode(): Argument #1 ($x) must be of type int, float given, called in %s:%d
1717
Stack trace:
18-
#0 %s(%d): function_declared_in_weak_mode(1)
18+
#0 %s(%d): function_declared_in_weak_mode(1.0)
1919
#1 {main}
2020
thrown in %sstrict_call_weak_2.inc on line 5

Zend/tests/type_declarations/strict_call_weak_explicit.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ function_declared_in_weak_mode(1.0);
1515
--EXPECTF--
1616
Fatal error: Uncaught TypeError: function_declared_in_weak_mode(): Argument #1 ($x) must be of type int, float given, called in %s:%d
1717
Stack trace:
18-
#0 %s(%d): function_declared_in_weak_mode(1)
18+
#0 %s(%d): function_declared_in_weak_mode(1.0)
1919
#1 {main}
2020
thrown in %sstrict_call_weak_explicit_2.inc on line 5

Zend/tests/type_declarations/weak_include_strict.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require 'weak_include_strict_2.inc';
1313
--EXPECTF--
1414
Fatal error: Uncaught TypeError: takes_int(): Argument #1 ($x) must be of type int, float given, called in %s:%d
1515
Stack trace:
16-
#0 %s(%d): takes_int(1)
16+
#0 %s(%d): takes_int(1.0)
1717
#1 %s(%d): require('%s')
1818
#2 {main}
1919
thrown in %sweak_include_strict_2.inc on line 5

Zend/zend_exceptions.c

+21-42
Original file line numberDiff line numberDiff line change
@@ -491,49 +491,28 @@ static void _build_trace_args(zval *arg, smart_str *str) /* {{{ */
491491
*/
492492

493493
ZVAL_DEREF(arg);
494-
switch (Z_TYPE_P(arg)) {
495-
case IS_NULL:
496-
smart_str_appends(str, "NULL, ");
497-
break;
498-
case IS_STRING:
499-
smart_str_appendc(str, '\'');
500-
smart_str_append_escaped(str, Z_STRVAL_P(arg), MIN(Z_STRLEN_P(arg), EG(exception_string_param_max_len)));
501-
if (Z_STRLEN_P(arg) > EG(exception_string_param_max_len)) {
502-
smart_str_appends(str, "...', ");
503-
} else {
504-
smart_str_appends(str, "', ");
494+
495+
if (Z_TYPE_P(arg) <= IS_STRING) {
496+
smart_str_append_scalar(str, arg, EG(exception_string_param_max_len));
497+
smart_str_appends(str, ", ");
498+
} else {
499+
switch (Z_TYPE_P(arg)) {
500+
case IS_RESOURCE:
501+
smart_str_appends(str, "Resource id #");
502+
smart_str_append_long(str, Z_RES_HANDLE_P(arg));
503+
smart_str_appends(str, ", ");
504+
break;
505+
case IS_ARRAY:
506+
smart_str_appends(str, "Array, ");
507+
break;
508+
case IS_OBJECT: {
509+
zend_string *class_name = Z_OBJ_HANDLER_P(arg, get_class_name)(Z_OBJ_P(arg));
510+
smart_str_appends(str, "Object(");
511+
smart_str_appends(str, ZSTR_VAL(class_name));
512+
smart_str_appends(str, "), ");
513+
zend_string_release_ex(class_name, 0);
514+
break;
505515
}
506-
break;
507-
case IS_FALSE:
508-
smart_str_appends(str, "false, ");
509-
break;
510-
case IS_TRUE:
511-
smart_str_appends(str, "true, ");
512-
break;
513-
case IS_RESOURCE:
514-
smart_str_appends(str, "Resource id #");
515-
smart_str_append_long(str, Z_RES_HANDLE_P(arg));
516-
smart_str_appends(str, ", ");
517-
break;
518-
case IS_LONG:
519-
smart_str_append_long(str, Z_LVAL_P(arg));
520-
smart_str_appends(str, ", ");
521-
break;
522-
case IS_DOUBLE:
523-
smart_str_append_double(
524-
str, Z_DVAL_P(arg), (int) EG(precision), /* zero_fraction */ false);
525-
smart_str_appends(str, ", ");
526-
break;
527-
case IS_ARRAY:
528-
smart_str_appends(str, "Array, ");
529-
break;
530-
case IS_OBJECT: {
531-
zend_string *class_name = Z_OBJ_HANDLER_P(arg, get_class_name)(Z_OBJ_P(arg));
532-
smart_str_appends(str, "Object(");
533-
smart_str_appends(str, ZSTR_VAL(class_name));
534-
smart_str_appends(str, "), ");
535-
zend_string_release_ex(class_name, 0);
536-
break;
537516
}
538517
}
539518
}

Zend/zend_execute.c

+19
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,25 @@ ZEND_COLD zend_never_inline void zend_verify_property_type_error(zend_property_i
824824
zend_string_release(type_str);
825825
}
826826

827+
ZEND_COLD void zend_match_unhandled_error(zval *value)
828+
{
829+
smart_str msg = {0};
830+
831+
if (Z_TYPE_P(value) <= IS_STRING) {
832+
smart_str_append_scalar(&msg, value, EG(exception_string_param_max_len));
833+
} else {
834+
smart_str_appendl(&msg, "of type ", sizeof("of type ")-1);
835+
smart_str_appends(&msg, zend_zval_type_name(value));
836+
}
837+
838+
smart_str_0(&msg);
839+
840+
zend_throw_exception_ex(
841+
zend_ce_unhandled_match_error, 0, "Unhandled match case %s", ZSTR_VAL(msg.s));
842+
843+
smart_str_free(&msg);
844+
}
845+
827846
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(
828847
zend_property_info *info) {
829848
zend_throw_error(NULL, "Cannot modify readonly property %s::$%s",

Zend/zend_execute.h

+2
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,8 @@ ZEND_COLD void zend_verify_property_type_error(zend_property_info *info, zval *p
469469
} \
470470
} while (0)
471471

472+
ZEND_COLD void zend_match_unhandled_error(zval *value);
473+
472474
END_EXTERN_C()
473475

474476
#endif /* ZEND_EXECUTE_H */

Zend/zend_smart_str.c

+41
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,44 @@ ZEND_API void ZEND_FASTCALL _smart_string_alloc(smart_string *str, size_t len)
180180
str->c = erealloc2(str->c, str->a + 1, str->len);
181181
}
182182
}
183+
184+
ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, zend_string *value, size_t length)
185+
{
186+
smart_str_append_escaped(str, ZSTR_VAL(value), MIN(length, ZSTR_LEN(value)));
187+
188+
if (ZSTR_LEN(value) > length) {
189+
smart_str_appendl(str, "...", sizeof("...")-1);
190+
}
191+
}
192+
193+
ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *dest, zval *value, size_t truncate) {
194+
ZEND_ASSERT(Z_TYPE_P(value) <= IS_STRING);
195+
196+
switch (Z_TYPE_P(value)) {
197+
case IS_UNDEF:
198+
case IS_NULL:
199+
smart_str_appendl(dest, "NULL", sizeof("NULL")-1);
200+
break;
201+
202+
case IS_TRUE:
203+
case IS_FALSE:
204+
smart_str_appends(dest, Z_TYPE_P(value) == IS_TRUE ? "true" : "false");
205+
break;
206+
207+
case IS_DOUBLE:
208+
smart_str_append_double(dest, Z_DVAL_P(value), (int) EG(precision), true);
209+
break;
210+
211+
case IS_LONG:
212+
smart_str_append_long(dest, Z_LVAL_P(value));
213+
break;
214+
215+
case IS_STRING:
216+
smart_str_appendc(dest, '\'');
217+
smart_str_append_escaped_truncated(dest, Z_STR_P(value), truncate);
218+
smart_str_appendc(dest, '\'');
219+
break;
220+
221+
EMPTY_SWITCH_DEFAULT_CASE();
222+
}
223+
}

Zend/zend_smart_str.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ ZEND_API void ZEND_FASTCALL smart_str_append_double(
5555
smart_str *str, double num, int precision, bool zero_fraction);
5656
ZEND_API void smart_str_append_printf(smart_str *dest, const char *format, ...)
5757
ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
58-
58+
ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, zend_string *value, size_t length);
59+
ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *str, zval *value, size_t truncate);
5960
END_EXTERN_C()
6061

6162
static zend_always_inline size_t smart_str_alloc(smart_str *str, size_t len, bool persistent) {

Zend/zend_vm_def.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -8921,7 +8921,7 @@ ZEND_VM_COLD_CONST_HANDLER(197, ZEND_MATCH_ERROR, CONST|TMPVARCV, UNUSED)
89218921

89228922
SAVE_OPLINE();
89238923
op = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
8924-
zend_throw_exception_ex(zend_ce_unhandled_match_error, 0, "Unhandled match value of type %s", zend_zval_type_name(op));
8924+
zend_match_unhandled_error(op);
89258925
HANDLE_EXCEPTION();
89268926
}
89278927

Zend/zend_vm_execute.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -10493,7 +10493,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MATCH_ERROR_SPEC_
1049310493

1049410494
SAVE_OPLINE();
1049510495
op = RT_CONSTANT(opline, opline->op1);
10496-
zend_throw_exception_ex(zend_ce_unhandled_match_error, 0, "Unhandled match value of type %s", zend_zval_type_name(op));
10496+
zend_match_unhandled_error(op);
1049710497
HANDLE_EXCEPTION();
1049810498
}
1049910499

@@ -14019,7 +14019,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MATCH_ERROR_SPEC_TMPVARCV_UNUS
1401914019

1402014020
SAVE_OPLINE();
1402114021
op = EX_VAR(opline->op1.var);
14022-
zend_throw_exception_ex(zend_ce_unhandled_match_error, 0, "Unhandled match value of type %s", zend_zval_type_name(op));
14022+
zend_match_unhandled_error(op);
1402314023
HANDLE_EXCEPTION();
1402414024
}
1402514025

ext/intl/tests/timezone_getOffset_error.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ bool(false)
2424

2525
Fatal error: Uncaught TypeError: intltz_get_offset(): Argument #1 ($timezone) must be of type IntlTimeZone, null given in %s:%d
2626
Stack trace:
27-
#0 %s(%d): intltz_get_offset(NULL, %d, false, NULL, NULL)
27+
#0 %s(%d): intltz_get_offset(NULL, %f, false, NULL, NULL)
2828
#1 {main}
2929
thrown in %s on line %d

ext/reflection/php_reflection.c

+2-13
Original file line numberDiff line numberDiff line change
@@ -617,19 +617,8 @@ static int format_default_value(smart_str *str, zval *value, zend_class_entry *s
617617
return FAILURE;
618618
}
619619

620-
if (Z_TYPE(zv) == IS_TRUE) {
621-
smart_str_appends(str, "true");
622-
} else if (Z_TYPE(zv) == IS_FALSE) {
623-
smart_str_appends(str, "false");
624-
} else if (Z_TYPE(zv) == IS_NULL) {
625-
smart_str_appends(str, "NULL");
626-
} else if (Z_TYPE(zv) == IS_STRING) {
627-
smart_str_appendc(str, '\'');
628-
smart_str_appendl(str, Z_STRVAL(zv), MIN(Z_STRLEN(zv), 15));
629-
if (Z_STRLEN(zv) > 15) {
630-
smart_str_appends(str, "...");
631-
}
632-
smart_str_appendc(str, '\'');
620+
if (Z_TYPE(zv) <= IS_STRING) {
621+
smart_str_append_scalar(str, &zv, 15);
633622
} else if (Z_TYPE(zv) == IS_ARRAY) {
634623
smart_str_appends(str, "Array");
635624
} else {

0 commit comments

Comments
 (0)