+2016-05-01 Paul Eggert <eggert@cs.ucla.edu>
+
+ Port mktime_internal offset to unsigned time_t
+ This avoids some assumptions about wraparound arithmetic on
+ signed integer overflow.
+ * lib/mktime-internal.h (mktime_offset_t): New type.
+ (mktime_internal): Use it in decl.
+ * lib/mktime.c, lib/timegm.c (mktime_offset_t) [_LIBC]: New type.
+ * lib/mktime.c (__mktime_internal, localtime_offset):
+ * lib/timegm.c (timegm): Use it.
+ * m4/mktime.m4 (gl_TIME_T_IS_SIGNED): New macro.
+ (gl_FUNC_MKTIME): Require it.
+
2016-04-27 Paul Eggert <eggert@cs.ucla.edu>
xstrtol: prohibit monstrosities like "1bB"
+/* mktime variant that also uses an offset guess
+
+ Copyright 2016 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see
+ <http://www.gnu.org/licenses/>. */
+
#include <time.h>
+
+/* mktime_offset_t is a signed type wide enough to hold a UTC offset
+ in seconds, and used as part of the type of the offset-guess
+ argument to mktime_internal. Use time_t on platforms where time_t
+ is signed, to be compatible with platforms like BeOS that export
+ this implementation detail of mktime. On platforms where time_t is
+ unsigned, GNU and POSIX code can assume 'int' is at least 32 bits
+ which is wide enough for a UTC offset. */
+
+#if TIME_T_IS_SIGNED
+typedef time_t mktime_offset_t;
+#else
+typedef int mktime_offset_t;
+#endif
+
time_t mktime_internal (struct tm *,
struct tm * (*) (time_t const *, struct tm *),
- time_t *);
+ mktime_offset_t *);
};
-#ifndef _LIBC
+#ifdef _LIBC
+typedef time_t mktime_offset_t;
+#else
/* Portable standalone applications should supply a <time.h> that
declares a POSIX-compliant localtime_r, for the benefit of older
implementations that lack localtime_r or have a nonstandard one.
time_t
__mktime_internal (struct tm *tp,
struct tm *(*convert) (const time_t *, struct tm *),
- time_t *offset)
+ mktime_offset_t *offset)
{
time_t t, gt, t0, t1, t2;
struct tm tm;
}
-/* FIXME: This should use a signed type wide enough to hold any UTC
- offset in seconds. 'int' should be good enough for GNU code. We
- can't fix this unilaterally though, as other modules invoke
- __mktime_internal. */
-static time_t localtime_offset;
+static mktime_offset_t localtime_offset;
/* Convert *TP to a time_t value. */
time_t
#include <time.h>
-#ifndef _LIBC
+#ifdef _LIBC
+typedef time_t mktime_offset_t;
+#else
# undef __gmtime_r
# define __gmtime_r gmtime_r
# define __mktime_internal mktime_internal
time_t
timegm (struct tm *tmp)
{
- static time_t gmtime_offset;
+ static mktime_offset_t gmtime_offset;
tmp->tm_isdst = 0;
return __mktime_internal (tmp, __gmtime_r, &gmtime_offset);
}
-# serial 25
+# serial 26
dnl Copyright (C) 2002-2003, 2005-2007, 2009-2016 Free Software Foundation,
dnl Inc.
dnl This file is free software; the Free Software Foundation
dnl From Jim Meyering.
+AC_DEFUN([gl_TIME_T_IS_SIGNED],
+[
+ AC_CACHE_CHECK([whether time_t is signed],
+ [gl_cv_time_t_is_signed],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[#include <time.h>
+ char time_t_signed[(time_t) -1 < 0 ? 1 : -1];]])],
+ [gl_cv_time_t_is_signed=yes],
+ [gl_cv_time_t_is_signed=no])])
+ if test $gl_cv_time_t_is_signed = yes; then
+ AC_DEFINE([TIME_T_IS_SIGNED], [1], [Define to 1 if time_t is signed.])
+ fi
+])
+
AC_DEFUN([gl_FUNC_MKTIME],
[
AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
+ AC_REQUIRE([gl_TIME_T_IS_SIGNED])
dnl We don't use AC_FUNC_MKTIME any more, because it is no longer maintained
dnl in Autoconf and because it invokes AC_LIBOBJ.
time_t t, delta;
int i, j;
int time_t_signed_magnitude = (time_t) ~ (time_t) 0 < (time_t) -1;
- int time_t_signed = ! ((time_t) 0 < (time_t) -1);
#if HAVE_DECL_ALARM
/* This test makes some buggy mktime implementations loop.
alarm (60);
#endif
- time_t_max = (! time_t_signed
+ time_t_max = (! TIME_T_IS_SIGNED
? (time_t) -1
: ((((time_t) 1 << (sizeof (time_t) * CHAR_BIT - 2)) - 1)
* 2 + 1));
- time_t_min = (! time_t_signed
+ time_t_min = (! TIME_T_IS_SIGNED
? (time_t) 0
: time_t_signed_magnitude
? ~ (time_t) 0