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 indicate an error by returning a pointer to a "struct tm" with all fields set to zero. Let's also recognize this and convert it to a NULL (with this patch, t4212 should pass on FreeBSD). Reported-by: René Scharfe <l.s.r@xxxxxx> Signed-off-by: Jeff King <peff@xxxxxxxx> --- There are actually a few callers to gmtime and gmtime_r, so I pushed this fix up into a compat wrapper rather than in time_to_tm to get them all. It's possible that localtime() would want to receive the same treatment, too. It's not strictly necessary to make the wrapper conditional, but it was easy to do so. We could also just run this code all the time. I don't have a FreeBSD VM handy to test this, so confirmation that it passes the test would be nice. Makefile | 8 ++++++++ compat/gmtime.c | 26 ++++++++++++++++++++++++++ config.mak.uname | 1 + git-compat-util.h | 7 +++++++ 4 files changed, 42 insertions(+) create mode 100644 compat/gmtime.c diff --git a/Makefile b/Makefile index 3646391..2f3758c 100644 --- a/Makefile +++ b/Makefile @@ -338,6 +338,9 @@ all:: # Define TEST_GIT_INDEX_VERSION to 2, 3 or 4 to run the test suite # with a different indexfile format version. If it isn't set the index # file format used is index-v[23]. +# +# 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 @@ -1489,6 +1492,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 0000000..ffcabf4 --- /dev/null +++ b/compat/gmtime.c @@ -0,0 +1,26 @@ +#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; + + ret = gmtime_r(timep, result); + + /* + * Rather than NULL, FreeBSD gmtime will return a "struct tm" with all + * fields zeroed. Since "mday" cannot otherwise be zero, we can test + * this very quickly. + */ + if (ret && !ret->tm_mday) + ret = NULL; + + return ret; +} diff --git a/config.mak.uname b/config.mak.uname index 6069a44..0e22ac0 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -187,6 +187,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 892032b..5191866 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -716,4 +716,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 -- 1.9.1.656.ge8a0637 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html