From: Paul Eggert Date: Tue, 19 Nov 2024 02:19:54 +0000 (-0800) Subject: printf: diagnose empty args correctly X-Git-Tag: v9.6~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=91e95f1f86977a66ac0d6165f6db554eff174128;p=thirdparty%2Fcoreutils.git printf: diagnose empty args correctly Also, port better to macOS. * src/printf.c (verify_numeric): Don’t assume that when s == end then errno is zero; it is EINVAL on macOS, and POSIX allows this. (print_direc): Treat missing arg as zero for numeric conversions, and as an empty string for the others. (print_formatted): Use null pointer, not an empty string, to represent missing arg. * tests/printf/printf.sh: Test empty and space widths and precisions. --- diff --git a/src/printf.c b/src/printf.c index 488e8e006a..d7730ae6cf 100644 --- a/src/printf.c +++ b/src/printf.c @@ -104,17 +104,19 @@ ARGUMENTs converted to proper type first. Variable widths are handled.\n\ static void verify_numeric (char const *s, char const *end) { - if (errno) + if (s == end) + { + error (0, 0, _("%s: expected a numeric value"), quote (s)); + exit_status = EXIT_FAILURE; + } + else if (errno) { error (0, errno, "%s", quote (s)); exit_status = EXIT_FAILURE; } else if (*end) { - if (s == end) - error (0, 0, _("%s: expected a numeric value"), quote (s)); - else - error (0, 0, _("%s: value not completely converted"), quote (s)); + error (0, 0, _("%s: value not completely converted"), quote (s)); exit_status = EXIT_FAILURE; } } @@ -344,7 +346,7 @@ print_direc (char const *start, char conversion, case 'd': case 'i': { - intmax_t arg = vstrtoimax (argument); + intmax_t arg = argument ? vstrtoimax (argument) : 0; if (!have_field_width) { if (!have_precision) @@ -367,7 +369,7 @@ print_direc (char const *start, char conversion, case 'x': case 'X': { - uintmax_t arg = vstrtoumax (argument); + uintmax_t arg = argument ? vstrtoumax (argument) : 0; if (!have_field_width) { if (!have_precision) @@ -394,7 +396,7 @@ print_direc (char const *start, char conversion, case 'g': case 'G': { - long double arg = vstrtold (argument); + long double arg = argument ? vstrtold (argument) : 0; if (!have_field_width) { if (!have_precision) @@ -413,13 +415,18 @@ print_direc (char const *start, char conversion, break; case 'c': - if (!have_field_width) - xprintf (p, *argument); - else - xprintf (p, field_width, *argument); + { + char c = argument ? *argument : '\0'; + if (!have_field_width) + xprintf (p, c); + else + xprintf (p, field_width, c); + } break; case 's': + if (!argument) + argument = ""; if (!have_field_width) { if (!have_precision) @@ -662,7 +669,7 @@ print_formatted (char const *format, int argc, char **argv) print_direc (direc, *ac.f, have_field_width, field_width, have_precision, precision, - argc <= ac.curr_arg ? "" : argv[ac.curr_arg]); + ac.curr_arg < argc ? argv[ac.curr_arg] : nullptr); break; diff --git a/tests/printf/printf.sh b/tests/printf/printf.sh index 7e489161e7..a411b9d9f2 100755 --- a/tests/printf/printf.sh +++ b/tests/printf/printf.sh @@ -73,6 +73,11 @@ returns_ 1 $prog '%.*dx\n' $INT_OFLOW 0 >>out 2> /dev/null || fail=1 $prog '11 %*c\n' 2 x >>out || fail=1 +returns_ 1 $prog '12 %*s\n' '' 'empty width' >>out 2>/dev/null || fail=1 +returns_ 1 $prog '13 %*s\n' ' ' 'space width' >>out 2>/dev/null || fail=1 +returns_ 1 $prog '14 %.*sx\n' '' 'empty precision' >>out 2>/dev/null || fail=1 +returns_ 1 $prog '15 %.*sx\n' ' ' 'space precision' >>out 2>/dev/null || fail=1 + returns_ 1 $prog '%#d\n' 0 >>out 2> /dev/null || fail=1 returns_ 1 $prog '%0s\n' 0 >>out 2> /dev/null || fail=1 @@ -93,6 +98,10 @@ cat <<\EOF > exp 9 0 x 10 0x 11 x +12 empty width +13 space width +14 x +15 x EOF compare exp out || fail=1