[v2,1/2] Y2038: Add 64-bit time for all architectures

Message ID 20180614135116.8767-2-albert.aribaud@3adev.fr
State New, archived
Headers

Commit Message

Albert ARIBAUD June 14, 2018, 1:51 p.m. UTC
  * Add macro __TIMESIZE equal to the bit size of time_t.
  It equals the architecture __WORDSIZE except for x32
  where it equals 64.

* Add type __time64_t which is always 64-bit. On 64-bit
  architectures and on x32, it is #defined as time_t.
  On other architectures, it has its own type.

* Replace all occurrences of internal_time_t with
  __time64_t.

The  __time64_t type is public so that the public time_t type
can be a typedef or #define of __time64_t when we switch the
public API to 64-bit time.

Also, provide a function (inline) to check if a __time64_t
value fits in a (possibly 32-bit) time_t. This is used when
a 32-bit-time wrapper calls a glibc function which returns
a __time64_t, so that the wrapper can detect times which
it cannot properly return to its caller, and can flag an
EOVERFLOW accordingly.
---
 bits/timesize.h                              | 23 ++++++++++++
 bits/timesizes.h                             | 37 ++++++++++++++++++++
 include/sys/types.h                          |  1 +
 include/time.h                               | 21 +++++++----
 posix/bits/types.h                           |  8 +++++
 stdlib/Makefile                              |  2 +-
 sysdeps/unix/sysv/linux/x86/bits/timesizes.h | 32 +++++++++++++++++
 sysdeps/x86/bits/timesize.h                  | 21 +++++++++++
 time/tzfile.c                                | 18 +++++-----
 9 files changed, 147 insertions(+), 16 deletions(-)
 create mode 100644 bits/timesize.h
 create mode 100644 bits/timesizes.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/bits/timesizes.h
 create mode 100644 sysdeps/x86/bits/timesize.h
  

Comments

Joseph Myers June 14, 2018, 1:57 p.m. UTC | #1
On Thu, 14 Jun 2018, Albert ARIBAUD (3ADEV) wrote:

> diff --git a/include/sys/types.h b/include/sys/types.h
> index 716732f4d4..107b0672ac 100644
> --- a/include/sys/types.h
> +++ b/include/sys/types.h
> @@ -1 +1,2 @@
>  #include <posix/sys/types.h>
> +#include <bits/timesizes.h>

include/ wrappers should include the installed header and do nothing more 
in the _ISOMAC case.  For this header you shouldn't need any !_ISOMAC case 
to include more, because sys/types.h includes bits/types.h and you've 
already put a bits/timesizes.h include in there.

So no change to include/sys/types.h should be needed at all.
  
Paul Eggert June 14, 2018, 4:56 p.m. UTC | #2
On 06/14/2018 06:51 AM, Albert ARIBAUD (3ADEV) wrote:
> +/* check whether a time64_t value fits in a time_t */
> +# if __TIMESIZE == 64
> +/* __time64_t is time_t, so it always fits_in_time_t */
> +#  define fits_in_time_t(x)	1
> +# else
> +/* Not all __time64_t values can fit; check by type-casting */
> +static inline bool
> +fits_in_time_t (__time64_t t)
> +{
> +  return t == (time_t) t;
> +}
> +# endif

Don't bother with the "#if". Just have the static function 
unconditionally. It should generate zero instructions if time_t is 64 bits.
  
Albert ARIBAUD June 14, 2018, 5:52 p.m. UTC | #3
Hi Paul,

On Thu, 14 Jun 2018 09:56:03 -0700, Paul Eggert <eggert@cs.ucla.edu>
wrote :

> On 06/14/2018 06:51 AM, Albert ARIBAUD (3ADEV) wrote:
> > +/* check whether a time64_t value fits in a time_t */
> > +# if __TIMESIZE == 64
> > +/* __time64_t is time_t, so it always fits_in_time_t */
> > +#  define fits_in_time_t(x)	1
> > +# else
> > +/* Not all __time64_t values can fit; check by type-casting */
> > +static inline bool
> > +fits_in_time_t (__time64_t t)
> > +{
> > +  return t == (time_t) t;
> > +}
> > +# endif  
> 
> Don't bother with the "#if". Just have the static function 
> unconditionally. It should generate zero instructions if time_t is 64 bits.

Done, thanks.

Cordialement,
Albert ARIBAUD
3ADEV
  
Albert ARIBAUD June 14, 2018, 6:51 p.m. UTC | #4
Hi Joseph,

On Thu, 14 Jun 2018 13:57:16 +0000, Joseph Myers
<joseph@codesourcery.com> wrote :

> On Thu, 14 Jun 2018, Albert ARIBAUD (3ADEV) wrote:
> 
> > diff --git a/include/sys/types.h b/include/sys/types.h
> > index 716732f4d4..107b0672ac 100644
> > --- a/include/sys/types.h
> > +++ b/include/sys/types.h
> > @@ -1 +1,2 @@
> >  #include <posix/sys/types.h>
> > +#include <bits/timesizes.h>  
> 
> include/ wrappers should include the installed header and do nothing more 
> in the _ISOMAC case.  For this header you shouldn't need any !_ISOMAC case 
> to include more, because sys/types.h includes bits/types.h and you've 
> already put a bits/timesizes.h include in there.
> 
> So no change to include/sys/types.h should be needed at all.

Fixed, thanks.

Cordialement,
Albert ARIBAUD
3ADEV
  
Ben Hutchings July 30, 2018, 5:38 a.m. UTC | #5
On Thu, 2018-06-14 at 15:51 +0200, Albert ARIBAUD (3ADEV) wrote:
> * Add macro __TIMESIZE equal to the bit size of time_t.
>   It equals the architecture __WORDSIZE except for x32
>   where it equals 64.
> 
> * Add type __time64_t which is always 64-bit. On 64-bit
>   architectures and on x32, it is #defined as time_t.
>   On other architectures, it has its own type.
[...]
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/x86/bits/timesizes.h
[...]
> +/* Both x86-64 and x32 use 64-bit time.  */
> +#define __TIME64_T_TYPE		__TIME_T_TYPE
[...]

But won't this file be used for regular 32-bit x86 (i386/i686) as well?

Ben.
  
Ben Hutchings July 30, 2018, 5:41 a.m. UTC | #6
On Mon, 2018-07-30 at 13:38 +0800, Ben Hutchings wrote:
> On Thu, 2018-06-14 at 15:51 +0200, Albert ARIBAUD (3ADEV) wrote:
> > * Add macro __TIMESIZE equal to the bit size of time_t.
> >   It equals the architecture __WORDSIZE except for x32
> >   where it equals 64.
> > 
> > * Add type __time64_t which is always 64-bit. On 64-bit
> >   architectures and on x32, it is #defined as time_t.
> >   On other architectures, it has its own type.
> 
> [...]
> > --- /dev/null
> > +++ b/sysdeps/unix/sysv/linux/x86/bits/timesizes.h
> 
> [...]
> > +/* Both x86-64 and x32 use 64-bit time.  */
> > +#define __TIME64_T_TYPE		__TIME_T_TYPE
> 
> [...]
> 
> But won't this file be used for regular 32-bit x86 (i386/i686) as well?

Never mind, I see this got fixed in v5.

Ben.
  

Patch

diff --git a/bits/timesize.h b/bits/timesize.h
new file mode 100644
index 0000000000..58eb22d6f6
--- /dev/null
+++ b/bits/timesize.h
@@ -0,0 +1,23 @@ 
+/* Bit size of the time_t type at glibc build time, general case.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library 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.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <bits/wordsize.h> // for __WORDSIZE
+
+/* Size in bits of the 'time_t' type; equals __WORDSIZE except for x32  */
+#define __TIMESIZE	__WORDSIZE
diff --git a/bits/timesizes.h b/bits/timesizes.h
new file mode 100644
index 0000000000..e279b15cd8
--- /dev/null
+++ b/bits/timesizes.h
@@ -0,0 +1,37 @@ 
+/* bits/timesizes.h -- underlying types for __time64_t.  Generic version.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_TYPES_H
+# error "Never include <bits/timesizes.h> directly; use <sys/types.h> instead."
+#endif
+
+#ifndef	_BITS_TIMESIZES_H
+#define	_BITS_TIMESIZES_H	1
+
+/* See <bits/types.h> for the meaning of these macros.  This file exists so
+   that <bits/types.h> need not vary across different GNU platforms.  */
+
+#if __TIMESIZE == 64
+/* If we already have 64-bit time then use it */ 
+#define __TIME64_T_TYPE		__TIME_T_TYPE
+#else
+/* Define a 64-bit type alongsize the 32-bit one */ 
+#define __TIME64_T_TYPE		__SQUAD_TYPE
+#endif
+
+#endif /* bits/timesizes.h */
diff --git a/include/sys/types.h b/include/sys/types.h
index 716732f4d4..107b0672ac 100644
--- a/include/sys/types.h
+++ b/include/sys/types.h
@@ -1 +1,2 @@ 
 #include <posix/sys/types.h>
+#include <bits/timesizes.h>
diff --git a/include/time.h b/include/time.h
index 23d2580528..fea072cbb6 100644
--- a/include/time.h
+++ b/include/time.h
@@ -3,6 +3,7 @@ 
 
 #ifndef _ISOMAC
 # include <bits/types/locale_t.h>
+# include <stdbool.h>
 
 extern __typeof (strftime_l) __strftime_l;
 libc_hidden_proto (__strftime_l)
@@ -26,10 +27,6 @@  extern __typeof (clock_getcpuclockid) __clock_getcpuclockid;
 /* Now define the internal interfaces.  */
 struct tm;
 
-/* time_t variant for representing time zone data, independent of
-   time_t.  */
-typedef __int64_t internal_time_t;
-
 /* Defined in mktime.c.  */
 extern const unsigned short int __mon_yday[2][13] attribute_hidden;
 
@@ -43,7 +40,7 @@  extern int __use_tzfile attribute_hidden;
 
 extern void __tzfile_read (const char *file, size_t extra,
 			   char **extrap) attribute_hidden;
-extern void __tzfile_compute (internal_time_t timer, int use_localtime,
+extern void __tzfile_compute (__time64_t timer, int use_localtime,
 			      long int *leap_correct, int *leap_hit,
 			      struct tm *tp) attribute_hidden;
 extern void __tzfile_default (const char *std, const char *dst,
@@ -101,10 +98,22 @@  extern char * __strptime_internal (const char *rp, const char *fmt,
 
 extern double __difftime (time_t time1, time_t time0);
 
-
 /* Use in the clock_* functions.  Size of the field representing the
    actual clock ID.  */
 #define CLOCK_IDFIELD_SIZE	3
 
+/* check whether a time64_t value fits in a time_t */
+# if __TIMESIZE == 64
+/* __time64_t is time_t, so it always fits_in_time_t */
+#  define fits_in_time_t(x)	1
+# else
+/* Not all __time64_t values can fit; check by type-casting */
+static inline bool
+fits_in_time_t (__time64_t t)
+{
+  return t == (time_t) t;
+}
+# endif
+
 #endif
 #endif
diff --git a/posix/bits/types.h b/posix/bits/types.h
index 5e22ce41bf..0c7289faf8 100644
--- a/posix/bits/types.h
+++ b/posix/bits/types.h
@@ -25,6 +25,7 @@ 
 
 #include <features.h>
 #include <bits/wordsize.h>
+#include <bits/timesize.h>
 
 /* Convenience types.  */
 typedef unsigned char __u_char;
@@ -138,6 +139,7 @@  __extension__ typedef unsigned long long int __uintmax_t;
 # error
 #endif
 #include <bits/typesizes.h>	/* Defines __*_T_TYPE macros.  */
+#include <bits/timesizes.h>	/* Defines __TIME*_T_TYPE macros.  */
 
 
 __STD_TYPE __DEV_T_TYPE __dev_t;	/* Type of device numbers.  */
@@ -211,6 +213,12 @@  __STD_TYPE __U32_TYPE __socklen_t;
    It is not currently necessary for this to be machine-specific.  */
 typedef int __sig_atomic_t;
 
+#if __TIMESIZE == 64
+# define __time64_t time_t
+#else
+__STD_TYPE __TIME64_T_TYPE __time64_t;	/* Seconds since the Epoch (_TIME_BITS==64).  */
+#endif
+
 #undef __STD_TYPE
 
 #endif /* bits/types.h */
diff --git a/stdlib/Makefile b/stdlib/Makefile
index bf1fbd4a3a..4c6e541f77 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -29,7 +29,7 @@  headers	:= stdlib.h bits/stdlib.h bits/stdlib-ldbl.h bits/stdlib-float.h      \
 	   ucontext.h sys/ucontext.h					      \
 	   alloca.h fmtmsg.h						      \
 	   bits/stdlib-bsearch.h sys/random.h bits/stdint-intn.h	      \
-	   bits/stdint-uintn.h
+	   bits/stdint-uintn.h bits/timesizes.h bits/timesize.h		      \
 
 routines	:=							      \
 	atof atoi atol atoll						      \
diff --git a/sysdeps/unix/sysv/linux/x86/bits/timesizes.h b/sysdeps/unix/sysv/linux/x86/bits/timesizes.h
new file mode 100644
index 0000000000..785beab183
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/bits/timesizes.h
@@ -0,0 +1,32 @@ 
+/* bits/typesizes.h -- underlying types for __time64_t.  Linux/x86-64 version.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_TYPES_H
+# error "Never include <bits/timesizes.h> directly; use <sys/types.h> instead."
+#endif
+
+#ifndef	_BITS_TIMESIZES_H
+#define	_BITS_TIMESIZES_H	1
+
+/* See <bits/types.h> for the meaning of these macros.  This file exists so
+   that <bits/types.h> need not vary across different GNU platforms.  */
+
+/* Both x86-64 and x32 use 64-bit time.  */
+#define __TIME64_T_TYPE		__TIME_T_TYPE
+
+#endif /* bits/timesizes.h */
diff --git a/sysdeps/x86/bits/timesize.h b/sysdeps/x86/bits/timesize.h
new file mode 100644
index 0000000000..8974d81102
--- /dev/null
+++ b/sysdeps/x86/bits/timesize.h
@@ -0,0 +1,21 @@ 
+/* Bit size of the time_t type at glibc build time, x86-64 and x32 case.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library 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.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Both x86-64 and x32 use 64-bit time.  */
+#define __TIMESIZE	64
diff --git a/time/tzfile.c b/time/tzfile.c
index 2a385b92bc..d7e391c3a3 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -44,12 +44,12 @@  struct ttinfo
 
 struct leap
   {
-    internal_time_t transition;	/* Time the transition takes effect.  */
+    __time64_t transition;	/* Time the transition takes effect.  */
     long int change;		/* Seconds of correction to apply.  */
   };
 
 static size_t num_transitions;
-libc_freeres_ptr (static internal_time_t *transitions);
+libc_freeres_ptr (static __time64_t *transitions);
 static unsigned char *type_idxs;
 static size_t num_types;
 static struct ttinfo *types;
@@ -113,8 +113,8 @@  __tzfile_read (const char *file, size_t extra, char **extrap)
   size_t tzspec_len;
   char *new = NULL;
 
-  _Static_assert (sizeof (internal_time_t) == 8,
-		  "internal_time_t must be eight bytes");
+  _Static_assert (sizeof (__time64_t) == 8,
+		  "__time64_t must be eight bytes");
 
   __use_tzfile = 0;
 
@@ -220,9 +220,9 @@  __tzfile_read (const char *file, size_t extra, char **extrap)
 
   if (__builtin_expect (num_transitions
 			> ((SIZE_MAX - (__alignof__ (struct ttinfo) - 1))
-			   / (sizeof (internal_time_t) + 1)), 0))
+			   / (sizeof (__time64_t) + 1)), 0))
     goto lose;
-  total_size = num_transitions * (sizeof (internal_time_t) + 1);
+  total_size = num_transitions * (sizeof (__time64_t) + 1);
   total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
 		& ~(__alignof__ (struct ttinfo) - 1));
   types_idx = total_size;
@@ -279,7 +279,7 @@  __tzfile_read (const char *file, size_t extra, char **extrap)
     goto lose;
 
   type_idxs = (unsigned char *) transitions + (num_transitions
-					       * sizeof (internal_time_t));
+					       * sizeof (__time64_t));
   types = (struct ttinfo *) ((char *) transitions + types_idx);
   zone_names = (char *) types + num_types * sizeof (struct ttinfo);
   leaps = (struct leap *) ((char *) transitions + leaps_idx);
@@ -580,7 +580,7 @@  __tzfile_default (const char *std, const char *dst,
 }
 
 void
-__tzfile_compute (internal_time_t timer, int use_localtime,
+__tzfile_compute (__time64_t timer, int use_localtime,
 		  long int *leap_correct, int *leap_hit,
 		  struct tm *tp)
 {
@@ -669,7 +669,7 @@  __tzfile_compute (internal_time_t timer, int use_localtime,
 	     initial search spot from it.  Half of a gregorian year
 	     has on average 365.2425 * 86400 / 2 = 15778476 seconds.
 	     The value i can be truncated if size_t is smaller than
-	     internal_time_t, but this is harmless because it is just
+	     __time64_t, but this is harmless because it is just
 	     a guess.  */
 	  i = (transitions[num_transitions - 1] - timer) / 15778476;
 	  if (i < num_transitions)