Without this patch, Bash can hand out user-visible timestamps that are out of order, because on GNU/Linux the 'time' function uses a different clock than file timestamps and the 'gettimeofday' function. The out-of-order timestamps can lead to user-confusion. https://sourceware.org/bugzilla/show_bug.cgi?id=30200
This fixes a bug reported against Bash in 2020 by felix https://lists.gnu.org/archive/html/bug-bash/2020-04/msg00072.html * include/posixtime.h (getnow): New function. All calls to 'time' changed to use this function. * support/man2html.c (print_sig): Prefer gettimeofday if available. --- general.h | 2 +- include/posixtime.h | 10 ++++++++++ lib/readline/history.c | 4 +++- parse.y | 6 +++--- support/man2html.c | 8 +++++++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/general.h b/general.h index fa57251a..2232fabd 100644 --- a/general.h +++ b/general.h @@ -242,7 +242,7 @@ typedef int sh_builtin_func_t (WORD_LIST *); /* sh_wlist_func_t */ #endif /* SH_FUNCTION_TYPEDEF */ -#define NOW ((time_t) time ((time_t *) 0)) +#define NOW getnow () #define GETTIME(tv) gettimeofday(&(tv), NULL) /* Some defines for calling file status functions. */ diff --git a/include/posixtime.h b/include/posixtime.h index 319cb168..7b0fc035 100644 --- a/include/posixtime.h +++ b/include/posixtime.h @@ -52,6 +52,16 @@ struct timeval extern int gettimeofday (struct timeval * restrict, void * restrict); #endif +static inline time_t +getnow (void) +{ + /* Avoid time (NULL), which can disagree with gettimeofday and with + filesystem timestamps. */ + struct timeval now; + gettimeofday (&now, 0); + return now.tv_sec; +} + /* These exist on BSD systems, at least. */ #if !defined (timerclear) # define timerclear(tvp) do { (tvp)->tv_sec = 0; (tvp)->tv_usec = 0; } while (0) diff --git a/lib/readline/history.c b/lib/readline/history.c index 42580301..9dc90147 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -48,6 +48,7 @@ #include "history.h" #include "histlib.h" +#include "posixtime.h" #include "xmalloc.h" #if !defined (errno) @@ -261,7 +262,8 @@ hist_inittime (void) time_t t; char ts[64], *ret; - t = (time_t) time ((time_t *)0); + t = getnow (); + #if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */ snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t); #else diff --git a/parse.y b/parse.y index b758756a..2a61eb8c 100644 --- a/parse.y +++ b/parse.y @@ -85,7 +85,7 @@ typedef void *alias_t; # ifndef _MINIX # include <sys/param.h> # endif -# include <time.h> +# include "posixtime.h" # if defined (TM_IN_SYS_TIME) # include <sys/types.h> # include <sys/time.h> @@ -5976,7 +5976,7 @@ decode_prompt_string (char *string) case '@': case 'A': /* Make the current time/date into a string. */ - (void) time (&the_time); + the_time = getnow (); #if defined (HAVE_TZSET) sv_tz ("TZ"); /* XXX -- just make sure */ #endif @@ -6010,7 +6010,7 @@ decode_prompt_string (char *string) if (string[1] != '{') /* } */ goto not_escape; - (void) time (&the_time); + the_time = getnow (); tm = localtime (&the_time); string += 2; /* skip { */ t = string; diff --git a/support/man2html.c b/support/man2html.c index 58165796..61f05f10 100644 --- a/support/man2html.c +++ b/support/man2html.c @@ -452,8 +452,14 @@ print_sig(void) struct tm *timetm; time_t clock; - datbuf[0] = '\0'; +#if HAVE_GETTIMEOFDAY + struct timeval tv; + gettimeofday (&tv, NULL); + clock = tv.tv_sec; +#else clock = time(NULL); +#endif + datbuf[0] = '\0'; timetm = localtime(&clock); if (timetm) strftime(datbuf, MED_STR_MAX, TIMEFORMAT, timetm); -- 2.39.2