Skip to content

Commit b1b510e

Browse files
committed
Improve error message with argument name and full type
1 parent 41fe3bf commit b1b510e

File tree

10 files changed

+137
-113
lines changed

10 files changed

+137
-113
lines changed

Zend/tests/bug43201.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,37 @@ Warning: Undefined variable $ref in %s on line %d
3030

3131
Warning: Undefined variable $undef in %s on line %d
3232

33-
Deprecated: chop(): Passing null to parameter of type string is deprecated in %s on line %d
33+
Deprecated: chop(): Passing null to parameter #1 ($string) of type string is deprecated in %s on line %d
3434

3535
Notice: Indirect modification of overloaded property Foo::$arr has no effect in %sbug43201.php on line 17
3636

3737
Warning: Undefined variable $undef in %s on line %d
3838

39-
Deprecated: chop(): Passing null to parameter of type string is deprecated in %s on line %d
39+
Deprecated: chop(): Passing null to parameter #1 ($string) of type string is deprecated in %s on line %d
4040

4141
Notice: Indirect modification of overloaded property Foo::$arr has no effect in %sbug43201.php on line 17
4242

4343
Warning: Undefined variable $undef in %s on line %d
4444

45-
Deprecated: chop(): Passing null to parameter of type string is deprecated in %s on line %d
45+
Deprecated: chop(): Passing null to parameter #1 ($string) of type string is deprecated in %s on line %d
4646

4747
Notice: Indirect modification of overloaded property Foo::$arr has no effect in %sbug43201.php on line 17
4848

4949
Warning: Undefined variable $undef in %s on line %d
5050

51-
Deprecated: chop(): Passing null to parameter of type string is deprecated in %s on line %d
51+
Deprecated: chop(): Passing null to parameter #1 ($string) of type string is deprecated in %s on line %d
5252

5353
Notice: Indirect modification of overloaded property Foo::$arr has no effect in %sbug43201.php on line 17
5454

5555
Warning: Undefined variable $undef in %s on line %d
5656

57-
Deprecated: chop(): Passing null to parameter of type string is deprecated in %s on line %d
57+
Deprecated: chop(): Passing null to parameter #1 ($string) of type string is deprecated in %s on line %d
5858

5959
Notice: Indirect modification of overloaded property Foo::$arr has no effect in %sbug43201.php on line 17
6060

6161
Warning: Undefined variable $undef in %s on line %d
6262

63-
Deprecated: chop(): Passing null to parameter of type string is deprecated in %s on line %d
63+
Deprecated: chop(): Passing null to parameter #1 ($string) of type string is deprecated in %s on line %d
6464

6565
Notice: Indirect modification of overloaded property Foo::$arr has no effect in %sbug43201.php on line 17
6666
ok

Zend/tests/nullsafe_operator/013.phpt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@ dump_error(fn() => array_key_exists('foo', $foo?->foo()));
3838

3939
?>
4040
--EXPECTF--
41-
Deprecated: strlen(): Passing null to parameter of type string is deprecated in %s on line %d
41+
Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated in %s on line %d
4242
int(0)
4343
bool(true)
4444
bool(false)
4545
bool(false)
4646
bool(false)
4747
bool(false)
4848

49-
Deprecated: defined(): Passing null to parameter of type string is deprecated in %s on line %d
49+
Deprecated: defined(): Passing null to parameter #1 ($constant_name) of type string is deprecated in %s on line %d
5050
bool(false)
5151

52-
Deprecated: chr(): Passing null to parameter of type int is deprecated in %s on line %d
52+
Deprecated: chr(): Passing null to parameter #1 ($codepoint) of type int is deprecated in %s on line %d
5353
string(1) "%s"
5454

55-
Deprecated: ord(): Passing null to parameter of type string is deprecated in %s on line %d
55+
Deprecated: ord(): Passing null to parameter #1 ($character) of type string is deprecated in %s on line %d
5656
int(0)
5757
string(98) "call_user_func_array(): Argument #1 ($function) must be a valid callback, no array or string given"
5858
string(77) "call_user_func_array(): Argument #2 ($args) must be of type array, null given"
@@ -63,7 +63,7 @@ string(52) "func_num_args() expects exactly 0 arguments, 1 given"
6363
string(52) "func_get_args() expects exactly 0 arguments, 1 given"
6464
string(69) "array_slice(): Argument #1 ($array) must be of type array, null given"
6565

66-
Deprecated: array_slice(): Passing null to parameter of type int is deprecated in %s on line %d
66+
Deprecated: array_slice(): Passing null to parameter #2 ($offset) of type int is deprecated in %s on line %d
6767
array(1) {
6868
[0]=>
6969
string(3) "foo"

Zend/tests/str_or_obj_of_class_zpp.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ try {
5555
string(6) "string"
5656
string(1) "1"
5757

58-
Deprecated: zend_string_or_stdclass(): Passing null to parameter of type string is deprecated in %s on line %d
58+
Deprecated: zend_string_or_stdclass(): Passing null to parameter #1 ($param) of type string is deprecated in %s on line %d
5959
string(0) ""
6060
object(stdClass)#1 (0) {
6161
}

Zend/tests/str_or_obj_zpp.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ try {
3838
string(6) "string"
3939
string(1) "1"
4040

41-
Deprecated: zend_string_or_object(): Passing null to parameter of type string is deprecated in %s on line %d
41+
Deprecated: zend_string_or_object(): Passing null to parameter #1 ($param) of type object|string is deprecated in %s on line %d
4242
string(0) ""
4343
object(stdClass)#1 (0) {
4444
}

Zend/zend_API.c

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -426,18 +426,39 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **p
426426
}
427427
/* }}} */
428428

429-
static ZEND_COLD bool zend_null_arg_deprecated(const char *type) {
429+
static ZEND_COLD bool zend_null_arg_deprecated(const char *fallback_type, uint32_t arg_num) {
430+
zend_function *func = EG(current_execute_data)->func;
431+
ZEND_ASSERT(arg_num > 0);
432+
uint32_t arg_offset = arg_num - 1;
433+
if (arg_offset >= func->common.num_args) {
434+
ZEND_ASSERT(func->common.fn_flags & ZEND_ACC_VARIADIC);
435+
arg_offset = func->common.num_args;
436+
}
437+
438+
zend_arg_info *arg_info = &func->common.arg_info[arg_offset];
430439
zend_string *func_name = get_active_function_or_method_name();
431-
zend_error(E_DEPRECATED, "%s(): Passing null to parameter of type %s is deprecated",
432-
ZSTR_VAL(func_name), type);
440+
const char *arg_name = get_active_function_arg_name(arg_num);
441+
442+
/* If no type is specified in arginfo, use the specified fallback_type determined through
443+
* zend_parse_parameters instead. */
444+
zend_string *type_str = zend_type_to_string(arg_info->type);
445+
const char *type = type_str ? ZSTR_VAL(type_str) : fallback_type;
446+
zend_error(E_DEPRECATED,
447+
"%s(): Passing null to parameter #%" PRIu32 "%s%s%s of type %s is deprecated",
448+
ZSTR_VAL(func_name), arg_num,
449+
arg_name ? " ($" : "", arg_name ? arg_name : "", arg_name ? ")" : "",
450+
type);
433451
zend_string_release(func_name);
452+
if (type_str) {
453+
zend_string_release(type_str);
454+
}
434455
return !EG(exception);
435456
}
436457

437-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest) /* {{{ */
458+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest, uint32_t arg_num) /* {{{ */
438459
{
439460
if (EXPECTED(Z_TYPE_P(arg) <= IS_STRING)) {
440-
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("bool")) {
461+
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("bool", arg_num)) {
441462
return 0;
442463
}
443464
*dest = zend_is_true(arg);
@@ -448,16 +469,16 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest) /* {
448469
}
449470
/* }}} */
450471

451-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, bool *dest) /* {{{ */
472+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, bool *dest, uint32_t arg_num) /* {{{ */
452473
{
453474
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
454475
return 0;
455476
}
456-
return zend_parse_arg_bool_weak(arg, dest);
477+
return zend_parse_arg_bool_weak(arg, dest, arg_num);
457478
}
458479
/* }}} */
459480

460-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest) /* {{{ */
481+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */
461482
{
462483
if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) {
463484
if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) {
@@ -490,7 +511,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest)
490511
return 0;
491512
}
492513
} else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
493-
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("int")) {
514+
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("int", arg_num)) {
494515
return 0;
495516
}
496517
*dest = 0;
@@ -503,16 +524,16 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest)
503524
}
504525
/* }}} */
505526

506-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest) /* {{{ */
527+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */
507528
{
508529
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
509530
return 0;
510531
}
511-
return zend_parse_arg_long_weak(arg, dest);
532+
return zend_parse_arg_long_weak(arg, dest, arg_num);
512533
}
513534
/* }}} */
514535

515-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest) /* {{{ */
536+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest, uint32_t arg_num) /* {{{ */
516537
{
517538
if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
518539
*dest = (double)Z_LVAL_P(arg);
@@ -531,7 +552,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest)
531552
return 0;
532553
}
533554
} else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
534-
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("float")) {
555+
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("float", arg_num)) {
535556
return 0;
536557
}
537558
*dest = 0.0;
@@ -544,19 +565,19 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest)
544565
}
545566
/* }}} */
546567

547-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest) /* {{{ */
568+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest, uint32_t arg_num) /* {{{ */
548569
{
549570
if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
550571
/* SSTH Exception: IS_LONG may be accepted instead as IS_DOUBLE */
551572
*dest = (double)Z_LVAL_P(arg);
552573
} else if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
553574
return 0;
554575
}
555-
return zend_parse_arg_double_weak(arg, dest);
576+
return zend_parse_arg_double_weak(arg, dest, arg_num);
556577
}
557578
/* }}} */
558579

559-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest) /* {{{ */
580+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest, uint32_t arg_num) /* {{{ */
560581
{
561582
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
562583
return 0;
@@ -575,6 +596,9 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest) /
575596
}
576597
zend_string_release(str);
577598
} else if (Z_TYPE_P(arg) < IS_TRUE) {
599+
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("int|float", arg_num)) {
600+
return 0;
601+
}
578602
ZVAL_LONG(arg, 0);
579603
} else if (Z_TYPE_P(arg) == IS_TRUE) {
580604
ZVAL_LONG(arg, 1);
@@ -586,10 +610,10 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest) /
586610
}
587611
/* }}} */
588612

589-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest) /* {{{ */
613+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest, uint32_t arg_num) /* {{{ */
590614
{
591615
if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) {
592-
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("string")) {
616+
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("string", arg_num)) {
593617
return 0;
594618
}
595619
convert_to_string(arg);
@@ -611,24 +635,24 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **des
611635
}
612636
/* }}} */
613637

614-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest) /* {{{ */
638+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest, uint32_t arg_num) /* {{{ */
615639
{
616640
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
617641
return 0;
618642
}
619-
return zend_parse_arg_str_weak(arg, dest);
643+
return zend_parse_arg_str_weak(arg, dest, arg_num);
620644
}
621645
/* }}} */
622646

623-
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_string **dest_str, zend_long *dest_long) /* {{{ */
647+
ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_string **dest_str, zend_long *dest_long, uint32_t arg_num) /* {{{ */
624648
{
625649
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
626650
return 0;
627651
}
628-
if (zend_parse_arg_long_weak(arg, dest_long)) {
652+
if (zend_parse_arg_long_weak(arg, dest_long, arg_num)) {
629653
*dest_str = NULL;
630654
return 1;
631-
} else if (zend_parse_arg_str_weak(arg, dest_str)) {
655+
} else if (zend_parse_arg_str_weak(arg, dest_str, arg_num)) {
632656
*dest_long = 0;
633657
return 1;
634658
} else {
@@ -637,7 +661,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_stri
637661
}
638662
/* }}} */
639663

640-
static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec, char **error) /* {{{ */
664+
static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec, char **error, uint32_t arg_num) /* {{{ */
641665
{
642666
const char *spec_walk = *spec;
643667
char c = *spec_walk++;
@@ -670,7 +694,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
670694
is_null = va_arg(*va, bool *);
671695
}
672696

673-
if (!zend_parse_arg_long(arg, p, is_null, check_null)) {
697+
if (!zend_parse_arg_long(arg, p, is_null, check_null, arg_num)) {
674698
return check_null ? "?int" : "int";
675699
}
676700
}
@@ -685,7 +709,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
685709
is_null = va_arg(*va, bool *);
686710
}
687711

688-
if (!zend_parse_arg_double(arg, p, is_null, check_null)) {
712+
if (!zend_parse_arg_double(arg, p, is_null, check_null, arg_num)) {
689713
return check_null ? "?float" : "float";
690714
}
691715
}
@@ -695,7 +719,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
695719
{
696720
zval **p = va_arg(*va, zval **);
697721

698-
if (!zend_parse_arg_number(arg, p, check_null)) {
722+
if (!zend_parse_arg_number(arg, p, check_null, arg_num)) {
699723
return check_null ? "int|float|null" : "int|float";
700724
}
701725
}
@@ -705,7 +729,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
705729
{
706730
char **p = va_arg(*va, char **);
707731
size_t *pl = va_arg(*va, size_t *);
708-
if (!zend_parse_arg_string(arg, p, pl, check_null)) {
732+
if (!zend_parse_arg_string(arg, p, pl, check_null, arg_num)) {
709733
return check_null ? "?string" : "string";
710734
}
711735
}
@@ -715,7 +739,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
715739
{
716740
char **p = va_arg(*va, char **);
717741
size_t *pl = va_arg(*va, size_t *);
718-
if (!zend_parse_arg_path(arg, p, pl, check_null)) {
742+
if (!zend_parse_arg_path(arg, p, pl, check_null, arg_num)) {
719743
if (Z_TYPE_P(arg) == IS_STRING) {
720744
zend_spprintf(error, 0, "must not contain any null bytes");
721745
return "";
@@ -729,7 +753,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
729753
case 'P':
730754
{
731755
zend_string **str = va_arg(*va, zend_string **);
732-
if (!zend_parse_arg_path_str(arg, str, check_null)) {
756+
if (!zend_parse_arg_path_str(arg, str, check_null, arg_num)) {
733757
if (Z_TYPE_P(arg) == IS_STRING) {
734758
zend_spprintf(error, 0, "must not contain any null bytes");
735759
return "";
@@ -743,7 +767,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
743767
case 'S':
744768
{
745769
zend_string **str = va_arg(*va, zend_string **);
746-
if (!zend_parse_arg_str(arg, str, check_null)) {
770+
if (!zend_parse_arg_str(arg, str, check_null, arg_num)) {
747771
return check_null ? "?string" : "string";
748772
}
749773
}
@@ -758,7 +782,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
758782
is_null = va_arg(*va, bool *);
759783
}
760784

761-
if (!zend_parse_arg_bool(arg, p, is_null, check_null)) {
785+
if (!zend_parse_arg_bool(arg, p, is_null, check_null, arg_num)) {
762786
return check_null ? "?bool" : "bool";
763787
}
764788
}
@@ -919,7 +943,7 @@ static zend_result zend_parse_arg(uint32_t arg_num, zval *arg, va_list *va, cons
919943
const char *expected_type = NULL;
920944
char *error = NULL;
921945

922-
expected_type = zend_parse_arg_impl(arg, va, spec, &error);
946+
expected_type = zend_parse_arg_impl(arg, va, spec, &error, arg_num);
923947
if (expected_type) {
924948
if (EG(exception)) {
925949
return FAILURE;

0 commit comments

Comments
 (0)