Package: coreutils;
Reported by: Jim Meyering <jim <at> meyering.net>
Date: Wed, 3 Nov 2010 18:56:02 UTC
Severity: normal
Done: Pádraig Brady <P <at> draigBrady.com>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Paul Eggert <eggert <at> cs.ucla.edu> To: Jim Meyering <jim <at> meyering.net> Cc: 7325 <at> debbugs.gnu.org, Eric Blake <eblake <at> redhat.com> Subject: bug#7325: new test failure due to non-portability of printf formats like %05.3s Date: Wed, 03 Nov 2010 15:58:25 -0700
The test-case part of that looks OK, but the change to stat.c can be simplified. Also, there's a similar problem with a format like %020X, which should be fixed too. While we're on the subject, there are other ways that stat invokers can exercise undefined behavior (in the C sense) by passing weird formats in. This really should get fixed at some point. The patch proposed below addresses just the immediate issue. From a24a9ce8f3711670a6413c60b5e9ebd3e51a4e06 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert <at> cs.ucla.edu> Date: Wed, 3 Nov 2010 15:49:50 -0700 Subject: [PATCH] stat: handle leading '0' when formatting secs and ns * src/stat.c (epoch_sec): Remove. All callers changed to use out_epoch_sec instead. (out_ns): Use numeric format, not string format, to output the nanoseconds count; this avoids unportable use of (e.g.) %05s in a printf format. (out_epoch_sec): New function. This also uses a numeric format, instead of a string format, to output a number. --- src/stat.c | 56 ++++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/stat.c b/src/stat.c index d05a93b..c1def13 100644 --- a/src/stat.c +++ b/src/stat.c @@ -463,15 +463,6 @@ human_time (struct timespec t) return str; } -/* Return a string representation (in static storage) - of the number of seconds in T since the epoch. */ -static char * ATTRIBUTE_WARN_UNUSED_RESULT -epoch_sec (struct timespec t) -{ - static char str[INT_BUFSIZE_BOUND (time_t)]; - return timetostr (t.tv_sec, str); -} - /* Output the number of nanoseconds, ARG.tv_nsec, honoring a WIDTH.PRECISION format modifier, where PRECISION specifies how many leading digits(on a field of 9) to print. */ @@ -491,13 +482,29 @@ out_ns (char *pformat, size_t prefix_len, struct timespec arg) on the default representation, i.e., a zero padded number of width 9. */ unsigned long int ns = arg.tv_nsec; + char *dot = memchr (pformat, '.', prefix_len); - if (memchr (pformat, '.', prefix_len)) /* precision specified. */ + if (dot) { - char tmp[INT_BUFSIZE_BOUND (uintmax_t)]; - snprintf (tmp, sizeof tmp, "%09lu", ns); - strcpy (pformat + prefix_len, "s"); - printf (pformat, tmp); + /* Precision specified. */ + size_t i; + int precision = 0; + for (i = dot - pformat + 1; i < prefix_len && ISDIGIT (pformat[i]); i++) + { + if (! precision) + precision = pformat[i] - '0'; + else + { + /* If more than 9 digits are asked for, just output 9. */ + precision = 9; + break; + } + } + if (! precision) + return; + for (; precision < 9; precision++) + ns /= 10; + strcpy (dot, "lu"); } else { @@ -505,8 +512,9 @@ out_ns (char *pformat, size_t prefix_len, struct timespec arg) /* Note that pformat is big enough, as %:X -> %09lu and two extra bytes are already allocated. */ strcpy (pformat + prefix_len, fmt); - printf (pformat, ns); } + + printf (pformat, ns); } static void @@ -539,6 +547,14 @@ out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg) strcpy (pformat + prefix_len, PRIxMAX); printf (pformat, arg); } +static void +out_epoch_sec (char *pformat, size_t prefix_len, struct timespec arg) +{ + if (TYPE_SIGNED (time_t)) + out_int (pformat, prefix_len, arg.tv_sec); + else + out_uint (pformat, prefix_len, arg.tv_sec); +} /* Print the context information of FILENAME, and return true iff the context could not be obtained. */ @@ -853,8 +869,8 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, } break; case 'W': - out_string (pformat, prefix_len, - epoch_sec (neg_to_zero (get_stat_birthtime (statbuf)))); + out_epoch_sec (pformat, prefix_len, + neg_to_zero (get_stat_birthtime (statbuf))); break; case 'W' + 256: out_ns (pformat, prefix_len, neg_to_zero (get_stat_birthtime (statbuf))); @@ -863,7 +879,7 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf))); break; case 'X': - out_string (pformat, prefix_len, epoch_sec (get_stat_atime (statbuf))); + out_epoch_sec (pformat, prefix_len, get_stat_atime (statbuf)); break; case 'X' + 256: out_ns (pformat, prefix_len, get_stat_atime (statbuf)); @@ -872,7 +888,7 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf))); break; case 'Y': - out_string (pformat, prefix_len, epoch_sec (get_stat_mtime (statbuf))); + out_epoch_sec (pformat, prefix_len, get_stat_mtime (statbuf)); break; case 'Y' + 256: out_ns (pformat, prefix_len, get_stat_mtime (statbuf)); @@ -881,7 +897,7 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf))); break; case 'Z': - out_string (pformat, prefix_len, epoch_sec (get_stat_ctime (statbuf))); + out_epoch_sec (pformat, prefix_len, get_stat_ctime (statbuf)); break; case 'Z' + 256: out_ns (pformat, prefix_len, get_stat_ctime (statbuf)); -- 1.7.2
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.