Skip to content

Commit 82dc9a3

Browse files
Kharhamelnikic
authored andcommitted
Convert warnings to Errors in sprintf() functions
Closes phpGH-4837.
1 parent 9d48bf5 commit 82dc9a3

10 files changed

+171
-140
lines changed

ext/standard/formatted_print.c

+43-28
Original file line numberDiff line numberDiff line change
@@ -387,16 +387,20 @@ php_sprintf_getnumber(char **buffer, size_t *len)
387387
* "x" integer argument is printed as lowercase hexadecimal
388388
* "X" integer argument is printed as uppercase hexadecimal
389389
*
390+
* nb_additional_parameters is used for throwing errors:
391+
* - -1: ValueError is thrown (for vsprintf where args originates from an array)
392+
* - 0 or more: ArgumentCountError is thrown
390393
*/
391394
static zend_string *
392-
php_formatted_print(zval *z_format, zval *args, int argc)
395+
php_formatted_print(zval *z_format, zval *args, int argc, int nb_additional_parameters)
393396
{
394397
size_t size = 240, outpos = 0;
395398
int alignment, currarg, adjusting, argnum, width, precision;
396399
char *format, *temppos, padding;
397400
zend_string *result;
398401
int always_sign;
399402
size_t format_len;
403+
int bad_arg_number = 0;
400404

401405
if (!try_convert_to_string(z_format)) {
402406
return NULL;
@@ -407,6 +411,7 @@ php_formatted_print(zval *z_format, zval *args, int argc)
407411
result = zend_string_alloc(size, 0);
408412

409413
currarg = 0;
414+
argnum = 0;
410415

411416
while (format_len) {
412417
int expprec;
@@ -450,7 +455,7 @@ php_formatted_print(zval *z_format, zval *args, int argc)
450455

451456
if (argnum <= 0) {
452457
zend_string_efree(result);
453-
php_error_docref(NULL, E_WARNING, "Argument number must be greater than zero");
458+
zend_value_error("Argument number must be greater than zero");
454459
return NULL;
455460
}
456461
argnum--;
@@ -491,7 +496,7 @@ php_formatted_print(zval *z_format, zval *args, int argc)
491496
PRINTF_DEBUG(("sprintf: getting width\n"));
492497
if ((width = php_sprintf_getnumber(&format, &format_len)) < 0) {
493498
efree(result);
494-
php_error_docref(NULL, E_WARNING, "Width must be greater than zero and less than %d", INT_MAX);
499+
zend_value_error("Width must be greater than zero and less than %d", INT_MAX);
495500
return NULL;
496501
}
497502
adjusting |= ADJ_WIDTH;
@@ -508,7 +513,7 @@ php_formatted_print(zval *z_format, zval *args, int argc)
508513
if (isdigit((int)*format)) {
509514
if ((precision = php_sprintf_getnumber(&format, &format_len)) < 0) {
510515
efree(result);
511-
php_error_docref(NULL, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX);
516+
zend_value_error("Precision must be greater than zero and less than %d", INT_MAX);
512517
return NULL;
513518
}
514519
adjusting |= ADJ_PRECISION;
@@ -522,17 +527,17 @@ php_formatted_print(zval *z_format, zval *args, int argc)
522527
PRINTF_DEBUG(("sprintf: precision=%d\n", precision));
523528
}
524529

525-
if (argnum >= argc) {
526-
efree(result);
527-
php_error_docref(NULL, E_WARNING, "Too few arguments");
528-
return NULL;
529-
}
530-
531530
if (*format == 'l') {
532531
format++;
533532
format_len--;
534533
}
535534
PRINTF_DEBUG(("sprintf: format character='%c'\n", *format));
535+
536+
if (argnum >= argc) {
537+
bad_arg_number = 1;
538+
continue;
539+
}
540+
536541
/* now we expect to find a type specifier */
537542
tmp = &args[argnum];
538543
switch (*format) {
@@ -628,6 +633,16 @@ php_formatted_print(zval *z_format, zval *args, int argc)
628633
}
629634
}
630635

636+
if (bad_arg_number == 1) {
637+
efree(result);
638+
if (nb_additional_parameters == -1) {
639+
zend_value_error("The arguments array must contain %d items, %d given", argnum + 1, argc);
640+
} else {
641+
zend_argument_count_error("%d parameters are required, %d given", argnum + nb_additional_parameters + 1, argc + nb_additional_parameters);
642+
}
643+
return NULL;
644+
}
645+
631646
exit:
632647
/* possibly, we have to make sure we have room for the terminating null? */
633648
ZSTR_VAL(result)[outpos]=0;
@@ -660,7 +675,7 @@ php_formatted_print_get_array(zval *array, int *argc)
660675
}
661676
/* }}} */
662677

663-
/* {{{ proto string|false sprintf(string format [, mixed arg1 [, mixed ...]])
678+
/* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]])
664679
Return a formatted string */
665680
PHP_FUNCTION(user_sprintf)
666681
{
@@ -673,15 +688,15 @@ PHP_FUNCTION(user_sprintf)
673688
Z_PARAM_VARIADIC('*', args, argc)
674689
ZEND_PARSE_PARAMETERS_END();
675690

676-
result = php_formatted_print(format, args, argc);
691+
result = php_formatted_print(format, args, argc, 1);
677692
if (result == NULL) {
678-
RETURN_FALSE;
693+
return;
679694
}
680695
RETVAL_STR(result);
681696
}
682697
/* }}} */
683698

684-
/* {{{ proto string|false vsprintf(string format, array args)
699+
/* {{{ proto string vsprintf(string format, array args)
685700
Return a formatted string */
686701
PHP_FUNCTION(vsprintf)
687702
{
@@ -696,16 +711,16 @@ PHP_FUNCTION(vsprintf)
696711

697712
args = php_formatted_print_get_array(array, &argc);
698713

699-
result = php_formatted_print(format, args, argc);
714+
result = php_formatted_print(format, args, argc, -1);
700715
efree(args);
701716
if (result == NULL) {
702-
RETURN_FALSE;
717+
return;
703718
}
704719
RETVAL_STR(result);
705720
}
706721
/* }}} */
707722

708-
/* {{{ proto int|false printf(string format [, mixed arg1 [, mixed ...]])
723+
/* {{{ proto int printf(string format [, mixed arg1 [, mixed ...]])
709724
Output a formatted string */
710725
PHP_FUNCTION(user_printf)
711726
{
@@ -719,17 +734,17 @@ PHP_FUNCTION(user_printf)
719734
Z_PARAM_VARIADIC('*', args, argc)
720735
ZEND_PARSE_PARAMETERS_END();
721736

722-
result = php_formatted_print(format, args, argc);
737+
result = php_formatted_print(format, args, argc, 1);
723738
if (result == NULL) {
724-
RETURN_FALSE;
739+
return;
725740
}
726741
rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result));
727742
zend_string_efree(result);
728743
RETURN_LONG(rlen);
729744
}
730745
/* }}} */
731746

732-
/* {{{ proto int|false vprintf(string format, array args)
747+
/* {{{ proto int vprintf(string format, array args)
733748
Output a formatted string */
734749
PHP_FUNCTION(vprintf)
735750
{
@@ -745,18 +760,18 @@ PHP_FUNCTION(vprintf)
745760

746761
args = php_formatted_print_get_array(array, &argc);
747762

748-
result = php_formatted_print(format, args, argc);
763+
result = php_formatted_print(format, args, argc, -1);
749764
efree(args);
750765
if (result == NULL) {
751-
RETURN_FALSE;
766+
return;
752767
}
753768
rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result));
754769
zend_string_efree(result);
755770
RETURN_LONG(rlen);
756771
}
757772
/* }}} */
758773

759-
/* {{{ proto int|false fprintf(resource stream, string format [, mixed arg1 [, mixed ...]])
774+
/* {{{ proto int fprintf(resource stream, string format [, mixed arg1 [, mixed ...]])
760775
Output a formatted string into a stream */
761776
PHP_FUNCTION(fprintf)
762777
{
@@ -777,9 +792,9 @@ PHP_FUNCTION(fprintf)
777792

778793
php_stream_from_zval(stream, arg1);
779794

780-
result = php_formatted_print(format, args, argc);
795+
result = php_formatted_print(format, args, argc, 2);
781796
if (result == NULL) {
782-
RETURN_FALSE;
797+
return;
783798
}
784799

785800
php_stream_write(stream, ZSTR_VAL(result), ZSTR_LEN(result));
@@ -789,7 +804,7 @@ PHP_FUNCTION(fprintf)
789804
}
790805
/* }}} */
791806

792-
/* {{{ proto int|false vfprintf(resource stream, string format, array args)
807+
/* {{{ proto int vfprintf(resource stream, string format, array args)
793808
Output a formatted string into a stream */
794809
PHP_FUNCTION(vfprintf)
795810
{
@@ -812,10 +827,10 @@ PHP_FUNCTION(vfprintf)
812827

813828
args = php_formatted_print_get_array(array, &argc);
814829

815-
result = php_formatted_print(format, args, argc);
830+
result = php_formatted_print(format, args, argc, -1);
816831
efree(args);
817832
if (result == NULL) {
818-
RETURN_FALSE;
833+
return;
819834
}
820835

821836
php_stream_write(stream, ZSTR_VAL(result), ZSTR_LEN(result));

ext/standard/tests/file/fscanf_variation14.phpt

+6-2
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,12 @@ $counter = 1;
7676

7777
// writing to the file
7878
foreach($valid_strings as $string) {
79-
@fprintf($file_handle, $string);
80-
@fprintf($file_handle, "\n");
79+
try {
80+
fprintf($file_handle, $string);
81+
} catch (\ValueError $e) {
82+
} catch (\ArgumentCountError $e) {
83+
}
84+
fprintf($file_handle, "\n");
8185
}
8286
// closing the file
8387
fclose($file_handle);

ext/standard/tests/strings/printf_64bit.phpt

+6-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ echo "\n*** Output for insufficient number of arguments ***\n";
3939
$string = "dingy%sflem%dwombat";
4040
$nbr = 5;
4141
$name = "voudras";
42-
printf("%d $string %s", $nbr, $name);
42+
try {
43+
printf("%d $string %s", $nbr, $name);
44+
} catch (\ArgumentCountError $e) {
45+
print('Error found: '.$e->getMessage());
46+
}
4347

4448

4549
/* Scalar argument */
@@ -233,9 +237,7 @@ printf("%d", $tempstring);
233237
printf() expects at least 1 parameter, 0 given
234238

235239
*** Output for insufficient number of arguments ***
236-
237-
Warning: printf(): Too few arguments in %s on line %d
238-
240+
Error found: 5 parameters are required, 3 given
239241
*** Output for scalar argument ***
240242
3
241243
*** Output for NULL as argument ***

ext/standard/tests/strings/printf_error.phpt

+36-24
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,40 @@ $arg1 = 'one';
2525
$arg2 = 'two';
2626

2727
echo "\n-- Call printf with one argument less than expected --\n";
28-
var_dump( printf($format1) );
29-
var_dump( printf($format2,$arg1) );
30-
var_dump( printf($format3,$arg1,$arg2) );
28+
try {
29+
var_dump( printf($format1) );
30+
} catch (\ArgumentCountError $e) {
31+
echo $e->getMessage(), "\n";
32+
}
33+
try {
34+
var_dump( printf($format2,$arg1) );
35+
} catch (\ArgumentCountError $e) {
36+
echo $e->getMessage(), "\n";
37+
}
38+
try {
39+
var_dump( printf($format3,$arg1,$arg2) );
40+
} catch (\ArgumentCountError $e) {
41+
echo $e->getMessage(), "\n";
42+
}
3143

3244
echo "\n-- Call printf with two argument less than expected --\n";
33-
var_dump( printf($format2) );
34-
var_dump( printf($format3,$arg1) );
45+
try {
46+
var_dump( printf($format2) );
47+
} catch (\ArgumentCountError $e) {
48+
echo $e->getMessage(), "\n";
49+
}
50+
try {
51+
var_dump( printf($format3,$arg1) );
52+
} catch (\ArgumentCountError $e) {
53+
echo $e->getMessage(), "\n";
54+
}
3555

3656
echo "\n-- Call printf with three argument less than expected --\n";
37-
var_dump( printf($format3) );
57+
try {
58+
var_dump( printf($format3) );
59+
} catch (\ArgumentCountError $e) {
60+
echo $e->getMessage(), "\n";
61+
}
3862

3963
?>
4064
===DONE===
@@ -47,26 +71,14 @@ printf() expects at least 1 parameter, 0 given
4771
-- Testing printf() function with less than expected no. of arguments --
4872

4973
-- Call printf with one argument less than expected --
50-
51-
Warning: printf(): Too few arguments in %s on line %d
52-
bool(false)
53-
54-
Warning: printf(): Too few arguments in %s on line %d
55-
bool(false)
56-
57-
Warning: printf(): Too few arguments in %s on line %d
58-
bool(false)
74+
2 parameters are required, 1 given
75+
3 parameters are required, 2 given
76+
4 parameters are required, 3 given
5977

6078
-- Call printf with two argument less than expected --
61-
62-
Warning: printf(): Too few arguments in %s on line %d
63-
bool(false)
64-
65-
Warning: printf(): Too few arguments in %s on line %d
66-
bool(false)
79+
3 parameters are required, 1 given
80+
4 parameters are required, 2 given
6781

6882
-- Call printf with three argument less than expected --
69-
70-
Warning: printf(): Too few arguments in %s on line %d
71-
bool(false)
83+
4 parameters are required, 1 given
7284
===DONE===

0 commit comments

Comments
 (0)