aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2024-11-18 18:19:54 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2024-11-19 08:41:34 -0800
commit91e95f1f86977a66ac0d6165f6db554eff174128 (patch)
tree0dc32c079cb078f986086a0c14c223c1b1b7147b
parentprintf: do n$ overflow checking by hand (diff)
downloadcoreutils-91e95f1f86977a66ac0d6165f6db554eff174128.tar.gz
coreutils-91e95f1f86977a66ac0d6165f6db554eff174128.zip
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.
-rw-r--r--src/printf.c33
-rwxr-xr-xtests/printf/printf.sh9
2 files changed, 29 insertions, 13 deletions
diff --git a/src/printf.c b/src/printf.c
index 488e8e006..d7730ae6c 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 7e489161e..a411b9d9f 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