changeset 39291:27f187a5e5d0

time_rz: work around Mac OS X 10.6 infloop * doc/posix-functions/localtime.texi: * doc/posix-functions/localtime_r.texi: Mention the bug. * lib/time_rz.c (localtime_rz): Work around the bug. It’d be better to fix localtime and localtime_r instead, but that would be more work and is not needed to fix the Emacs problem. * m4/time_rz.m4 (gl_TIME_RZ): Detect the bug.
author Paul Eggert <eggert@cs.ucla.edu>
date Mon, 26 Mar 2018 19:23:33 -0700
parents 6c3d7fccbe2d
children f3e5ba124466
files ChangeLog doc/posix-functions/localtime.texi doc/posix-functions/localtime_r.texi lib/time_rz.c m4/time_rz.m4
diffstat 5 files changed, 69 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Mar 24 09:48:47 2018 -0700
+++ b/ChangeLog	Mon Mar 26 19:23:33 2018 -0700
@@ -1,3 +1,13 @@
+2018-03-26  Paul Eggert  <eggert@cs.ucla.edu>
+
+	time_rz: work around Mac OS X 10.6 infloop
+	* doc/posix-functions/localtime.texi:
+	* doc/posix-functions/localtime_r.texi: Mention the bug.
+	* lib/time_rz.c (localtime_rz): Work around the bug.  It’d be
+	better to fix localtime and localtime_r instead, but that would be
+	more work and is not needed to fix the Emacs problem.
+	* m4/time_rz.m4 (gl_TIME_RZ): Detect the bug.
+
 2018-03-24  Jim Meyering  <meyering@fb.com>
 
 	test-version-etc.sh: don't use diff directly: use init.sh's compare
--- a/doc/posix-functions/localtime.texi	Sat Mar 24 09:48:47 2018 -0700
+++ b/doc/posix-functions/localtime.texi	Mon Mar 26 19:23:33 2018 -0700
@@ -16,6 +16,11 @@
 Portability problems not fixed by Gnulib:
 @itemize
 @item
+On some platforms, this function loops forever for values
+near extrema (such as the year @math{-2**31}):
+Mac OS X 10.6.
+You can use the @code{time_rz} module to work around the problem.
+@item
 On some platforms, this function returns nonsense values for
 unsupported arguments (like @math{2^56}), rather than failing:
 FreeBSD 10.
--- a/doc/posix-functions/localtime_r.texi	Sat Mar 24 09:48:47 2018 -0700
+++ b/doc/posix-functions/localtime_r.texi	Mon Mar 26 19:23:33 2018 -0700
@@ -22,7 +22,13 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item On some platforms, this function returns nonsense values for
+@item
+On some platforms, this function loops forever for values
+near extrema (such as the year @math{-2**31}):
+Mac OS X 10.6.
+You can use the @code{time_rz} module to work around the problem.
+@item
+On some platforms, this function returns nonsense values for
 unsupported arguments (like @math{2^56}), rather than failing:
 FreeBSD 10.
 @end itemize
--- a/lib/time_rz.c	Sat Mar 24 09:48:47 2018 -0700
+++ b/lib/time_rz.c	Mon Mar 26 19:23:33 2018 -0700
@@ -286,6 +286,21 @@
 struct tm *
 localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
 {
+#ifdef HAVE_LOCALTIME_INFLOOP_BUG
+  /* The -67768038400665599 comes from:
+     https://lists.gnu.org/r/bug-gnulib/2017-07/msg00142.html
+     On affected platforms the greatest POSIX-compatible time_t value
+     that could return nonnull is 67768036191766798 (when
+     TZ="XXX24:59:59" it resolves to the year 2**31 - 1 + 1900, on
+     12-31 at 23:59:59), so test for that too while we're in the
+     neighborhood.  */
+  if (! (-67768038400665599 <= *t && *t <= 67768036191766798))
+    {
+      errno = EOVERFLOW;
+      return NULL;
+    }
+#endif
+
   if (!tz)
     return gmtime_r (t, tm);
   else
--- a/m4/time_rz.m4	Sat Mar 24 09:48:47 2018 -0700
+++ b/m4/time_rz.m4	Mon Mar 26 19:23:33 2018 -0700
@@ -13,6 +13,38 @@
   AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
   AC_REQUIRE([AC_STRUCT_TIMEZONE])
 
+  # Mac OS X 10.6 loops forever with some time_t values less
+  # than -67768038400665599.  See Bug#27706, Bug#27736, and
+  # https://lists.gnu.org/r/bug-gnulib/2017-07/msg00142.html
+  AC_CACHE_CHECK([whether localtime loops forever near extrema],
+    [gl_cv_func_localtime_infloop_bug],
+    [gl_cv_func_localtime_infloop_bug=no
+     AC_RUN_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <stdlib.h>
+            #include <string.h>
+            #include <unistd.h>
+            #include <time.h>
+          ]], [[
+            time_t t = -67768038400665600;
+            struct tm *tm;
+            char *tz = getenv ("TZ");
+            if (! (tz && strcmp (tz, "QQQ0") == 0))
+              return 0;
+            alarm (2);
+            tm = localtime (&t);
+            /* Use TM and *TM to suppress over-optimization.  */
+            return tm && tm->tm_isdst;
+          ]])],
+       [TZ=QQQ0 ./conftest$EXEEXT || gl_cv_func_localtime_infloop_bug=yes],
+       [],
+       [gl_cv_func_localtime_infloop_bug="guessing no"])])
+  if test "$gl_cv_func_localtime_infloop_bug" = yes; then
+      AC_DEFINE([HAVE_LOCALTIME_INFLOOP_BUG], 1,
+        [Define if localtime-like functions can loop forever on
+         extreme arguments.])
+  fi
+
   AC_CHECK_TYPES([timezone_t], [], [], [[#include <time.h>]])
   if test "$ac_cv_type_timezone_t" = yes; then
     HAVE_TIMEZONE_T=1