From 7ca36d9398a85e7974d04f8fbd2c6adb088290e1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 24 Feb 2014 02:39:45 -0500 Subject: date: check date overflow against time_t When we check whether a timestamp has overflowed, we check only against ULONG_MAX, meaning that strtoul has overflowed. However, we also feed these timestamps to system functions like gmtime, which expect a time_t. On many systems, time_t is actually smaller than "unsigned long" (e.g., because it is signed), and we would overflow when using these functions. We don't know the actual size or signedness of time_t, but we can easily check for truncation with a simple assignment. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- date.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'date.c') diff --git a/date.c b/date.c index 57331ed406..2dae471dd1 100644 --- a/date.c +++ b/date.c @@ -1085,3 +1085,20 @@ unsigned long approxidate_careful(const char *date, int *error_ret) gettimeofday(&tv, NULL); return approxidate_str(date, &tv, error_ret); } + +int date_overflows(unsigned long t) +{ + time_t sys; + + /* If we overflowed our unsigned long, that's bad... */ + if (t == ULONG_MAX) + return 1; + + /* + * ...but we also are going to feed the result to system + * functions that expect time_t, which is often "signed long". + * Make sure that we fit into time_t, as well. + */ + sys = t; + return t != sys || (t < 1) != (sys < 1); +} -- cgit v1.2.3 From 2b15846dbfb31df10a69a4d56ae944a01563bc07 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 24 Feb 2014 02:49:05 -0500 Subject: log: do not segfault on gmtime errors Many code paths assume that show_date and show_ident_date cannot return NULL. For the most part, we handle missing or corrupt timestamps by showing the epoch time t=0. However, we might still return NULL if gmtime rejects the time_t we feed it, resulting in a segfault. Let's catch this case and just format t=0. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- date.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'date.c') diff --git a/date.c b/date.c index 2dae471dd1..f64bbeb823 100644 --- a/date.c +++ b/date.c @@ -184,8 +184,10 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode) tz = local_tzoffset(time); tm = time_to_tm(time, tz); - if (!tm) - return NULL; + if (!tm) { + tm = time_to_tm(0, 0); + tz = 0; + } strbuf_reset(&timebuf); if (mode == DATE_SHORT) -- cgit v1.2.3