summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2016-05-01 11:44:51 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2016-05-01 17:27:02 -0700
commitb28c2cda0e90ccad85a99c48dded5624e39d28ac (patch)
treeefcd4824fbd894bb15b10c43bd20e2258ebc3870
parent6ed53f13bc39d9a0252549e98a2a59441fb2351f (diff)
downloadgnulib-b28c2cda0e90ccad85a99c48dded5624e39d28ac.tar.gz
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.
-rw-r--r--ChangeLog13
-rw-r--r--lib/mktime-internal.h35
-rw-r--r--lib/mktime.c12
-rw-r--r--lib/timegm.c6
-rw-r--r--m4/mktime.m422
5 files changed, 74 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 09c302cb9d..4b406cc283 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+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"
diff --git a/lib/mktime-internal.h b/lib/mktime-internal.h
index 4287acf4ac..0c9e204050 100644
--- a/lib/mktime-internal.h
+++ b/lib/mktime-internal.h
@@ -1,4 +1,37 @@
+/* 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 *);
diff --git a/lib/mktime.c b/lib/mktime.c
index 627b1a38d3..4f4f0bf34c 100644
--- a/lib/mktime.c
+++ b/lib/mktime.c
@@ -120,7 +120,9 @@ const unsigned short int __mon_yday[2][13] =
};
-#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.
@@ -296,7 +298,7 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
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;
@@ -518,11 +520,7 @@ __mktime_internal (struct tm *tp,
}
-/* 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
diff --git a/lib/timegm.c b/lib/timegm.c
index 1f567ec63d..ee9e497827 100644
--- a/lib/timegm.c
+++ b/lib/timegm.c
@@ -22,7 +22,9 @@
#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
@@ -32,7 +34,7 @@
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);
}
diff --git a/m4/mktime.m4 b/m4/mktime.m4
index 78f16ba66a..5a0f2d88ab 100644
--- a/m4/mktime.m4
+++ b/m4/mktime.m4
@@ -1,4 +1,4 @@
-# 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
@@ -7,9 +7,24 @@ dnl with or without modifications, as long as this notice is preserved.
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.
@@ -169,7 +184,6 @@ main ()
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.
@@ -179,11 +193,11 @@ main ()
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