From 6654754779d2a90af91a9c6b93d7e4e7ee16cfab Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 1 Apr 2014 17:28:42 -0400 Subject: [PATCH 1/2] date: recognize bogus FreeBSD gmtime output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most gmtime implementations return a NULL value when they encounter an error (and this behavior is specified by ANSI C and POSIX). FreeBSD's implementation, however, will simply leave the "struct tm" untouched. Let's also recognize this and convert it to a NULL (with this patch, t4212 should pass on FreeBSD). Reported-by: René Scharfe Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Makefile | 8 ++++++++ compat/gmtime.c | 29 +++++++++++++++++++++++++++++ config.mak.uname | 1 + git-compat-util.h | 7 +++++++ 4 files changed, 45 insertions(+) create mode 100644 compat/gmtime.c diff --git a/Makefile b/Makefile index 598d6313da..da7013b1bc 100644 --- a/Makefile +++ b/Makefile @@ -342,6 +342,9 @@ all:: # Define DEFAULT_HELP_FORMAT to "man", "info" or "html" # (defaults to "man") if you want to have a different default when # "git help" is called without a parameter specifying the format. +# +# Define GMTIME_UNRELIABLE_ERRORS if your gmtime() function does not +# return NULL when it receives a bogus time_t. GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -1464,6 +1467,11 @@ ifneq (,$(XDL_FAST_HASH)) BASIC_CFLAGS += -DXDL_FAST_HASH endif +ifdef GMTIME_UNRELIABLE_ERRORS + COMPAT_OBJS += compat/gmtime.o + BASIC_CFLAGS += -DGMTIME_UNRELIABLE_ERRORS +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK = NoThanks endif diff --git a/compat/gmtime.c b/compat/gmtime.c new file mode 100644 index 0000000000..e8362dd2b9 --- /dev/null +++ b/compat/gmtime.c @@ -0,0 +1,29 @@ +#include "../git-compat-util.h" +#undef gmtime +#undef gmtime_r + +struct tm *git_gmtime(const time_t *timep) +{ + static struct tm result; + return git_gmtime_r(timep, &result); +} + +struct tm *git_gmtime_r(const time_t *timep, struct tm *result) +{ + struct tm *ret; + + memset(result, 0, sizeof(*result)); + ret = gmtime_r(timep, result); + + /* + * Rather than NULL, FreeBSD gmtime simply leaves the "struct tm" + * untouched when it encounters overflow. Since "mday" cannot otherwise + * be zero, we can test this very quickly. + */ + if (ret && !ret->tm_mday) { + ret = NULL; + errno = EOVERFLOW; + } + + return ret; +} diff --git a/config.mak.uname b/config.mak.uname index e09af8fc13..94cc108b4a 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -189,6 +189,7 @@ ifeq ($(uname_S),FreeBSD) endif PYTHON_PATH = /usr/local/bin/python HAVE_PATHS_H = YesPlease + GMTIME_UNRELIABLE_ERRORS = UnfortunatelyYes endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease diff --git a/git-compat-util.h b/git-compat-util.h index ad4762499e..66728145b4 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -697,4 +697,11 @@ void warn_on_inaccessible(const char *path); /* Get the passwd entry for the UID of the current process. */ struct passwd *xgetpwuid_self(void); +#ifdef GMTIME_UNRELIABLE_ERRORS +struct tm *git_gmtime(const time_t *); +struct tm *git_gmtime_r(const time_t *, struct tm *); +#define gmtime git_gmtime +#define gmtime_r git_gmtime_r +#endif + #endif From f80d1f95f0adf9909f42eb9e74546963daa4b0c1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 1 Apr 2014 03:43:06 -0400 Subject: [PATCH 2/2] t4212: loosen far-in-future test for AIX One of the tests in t4212 checks our behavior when we feed gmtime a date so far in the future that it gives up and returns NULL. Some implementations, like AIX, may actually just provide us a bogus result instead. It's not worth it for us to come up with heuristics that guess whether the return value is sensible or not. On good platforms where gmtime reports the problem to us with NULL, we will print the epoch value. On bad platforms, we will print garbage. But our test should be written for the lowest common denominator so that it passes everywhere. Reported-by: Charles Bailey Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t4212-log-corrupt.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh index 85c6df4ec9..1863e7163c 100755 --- a/t/t4212-log-corrupt.sh +++ b/t/t4212-log-corrupt.sh @@ -77,11 +77,9 @@ test_expect_success 'date parser recognizes time_t overflow' ' ' # date is within 2^63-1, but enough to choke glibc's gmtime -test_expect_success 'absurdly far-in-future dates produce sentinel' ' +test_expect_success 'absurdly far-in-future date' ' commit=$(munge_author_date HEAD 999999999999999999) && - echo "Thu Jan 1 00:00:00 1970 +0000" >expect && - git log -1 --format=%ad $commit >actual && - test_cmp expect actual + git log -1 --format=%ad $commit ' test_done