Skip to content

Commit

Permalink
Fix TIMEFORMATted output for time_t != int (re: 70fc1da, c5820aa)
Browse files Browse the repository at this point in the history
Reproducer on NetBSD i386:

$ arch/netbsd.i386/bin/ksh -c 'TIMEFORMAT=%1U; time sleep 0'
0_0000000000000000000000000000000000000000000001
...where the _ is actually a 0 byte.

The format is similarly corrupted for other values of TIMEFORMAT.

The cause is on xec.c line 299, where the sfprintf statement passes
tvp->tv_sec to sfprintf with the %d modifier -- assuming it is a
regular int type. tv_sec is of type time_t, but on NetBSD, time_t
is defined as long, which on i386 is twice the size of an int.
Hence the corrupted output of sfprintf. Arguments *must* match the
type length of the formatters exactly.

POSIX only says that time_t is "an integer type", so we cannot
assume its size. It is thus unsafe to pass directly to *printf as
there is always a chance the formatter will mismatch with the type.

src/cmd/ksh93/sh/xec.c:
- Assign tvp->tv_sec to a local variable of type 'long' (which does
  an implicit typecast if necessary) before passing it to sfprintf
  using the %ld formatter.
  • Loading branch information
McDutchie committed Feb 9, 2024
1 parent 414a7c3 commit b35b1c8
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 2 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library.
- Fixed an init-time crash that may occur if standard error is on a terminal,
but the path to its tty device can't be found (e.g., in a chroot situation).

- Fixed corrupted output of the 'time' keyword as formatted via TIMEFORMAT on
systems where sizeof(time_t) != sizeof(int). Bug introduced on 2020-07-13.

2024-02-06:

- Fixed a regression introduced on 2023-03-04 that caused ksh to lock up
Expand Down
5 changes: 3 additions & 2 deletions src/cmd/ksh93/sh/xec.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,14 @@ static void p_time(Sfio_t *out, const char *format, clock_t *tm)
else
{
/* scale fraction from micro to milli, centi, or deci second according to precision */
long sec = tvp->tv_sec;
int n, frac = tvp->tv_usec;
for(n = 3 + (3 - precision); n > 0; --n)
frac /= 10;
if(precision)
sfprintf(sh.stk, "%d%c%0*d", tvp->tv_sec, sh.radixpoint, precision, frac);
sfprintf(sh.stk, "%ld%c%0*d", sec, sh.radixpoint, precision, frac);
else
sfprintf(sh.stk, "%d", tvp->tv_sec);
sfprintf(sh.stk, "%ld", sec);
}
#else
if(c=='R')
Expand Down

0 comments on commit b35b1c8

Please sign in to comment.