From b35b1c84cb9ce87193f9e06fbc6f85a26a61b0a7 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Fri, 9 Feb 2024 01:31:09 +0000 Subject: [PATCH] Fix TIMEFORMATted output for time_t != int (re: 70fc1da7, c5820aab) 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. --- NEWS | 3 +++ src/cmd/ksh93/sh/xec.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 9ffb9e4f762b..9ae47d2fe0ed 100644 --- a/NEWS +++ b/NEWS @@ -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 diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index 685c379204ae..b32c86c3dda4 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -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')