Y2038: add function __localtime64

Message ID 20181212012823.481-1-albert.aribaud@3adev.fr
State New, archived
Headers

Commit Message

Albert ARIBAUD Dec. 12, 2018, 1:28 a.m. UTC
  Tested with 'make check' on x86_64-linux-gnu and i686-linux.gnu.

	* include/time.h
	(__localtime64): Add.
        * manual/maint.texi: Document Y2038 symbol handling.
	* time/localtime.c
	(__localtime64): Add.
	[__TIMERSIZE != 64] (__localtime): Turn into a wrapper.
---
 include/time.h    |   9 +++-
 manual/maint.texi | 122 ++++++++++++++++++++++++++++++++++++++++++++++
 time/localtime.c  |  18 +++++--
 3 files changed, 145 insertions(+), 4 deletions(-)
  

Comments

Andreas Schwab Dec. 12, 2018, 9:18 a.m. UTC | #1
On Dez 12 2018, "Albert ARIBAUD (3ADEV)" <albert.aribaud@3adev.fr> wrote:

> +Some of the architectures supported by @theglibc{} already use 64-bit
> +time (@code{__TIMESIZE == 64}), while other architectures use 32-bit time
> +(@code{__TIMESIZE != 64}) and therefore cannot handle dates beyond
> +2038-01-19 03:14:07 (aka 'Y2038').

This should be `Y2038' or @dfn{Y2038}.

Andreas.
  

Patch

diff --git a/include/time.h b/include/time.h
index 37964f7b76..251a2b0329 100644
--- a/include/time.h
+++ b/include/time.h
@@ -56,9 +56,16 @@  extern time_t __mktime_internal (struct tm *__tp,
 				 struct tm *(*__func) (const time_t *,
 						       struct tm *),
 				 long int *__offset) attribute_hidden;
+
+#if __TIMESIZE == 64
+# define __localtime64 localtime
+#else
+extern struct tm *__localtime64 (const __time64_t *__timer);
+libc_hidden_proto (__localtime64)
+#endif
+
 extern struct tm *__localtime_r (const time_t *__timer,
 				 struct tm *__tp) attribute_hidden;
-
 extern struct tm *__gmtime_r (const time_t *__restrict __timer,
 			      struct tm *__restrict __tp);
 libc_hidden_proto (__gmtime_r)
diff --git a/manual/maint.texi b/manual/maint.texi
index fce06bfa88..c707544095 100644
--- a/manual/maint.texi
+++ b/manual/maint.texi
@@ -5,6 +5,7 @@ 
 @menu
 * Source Layout::         How to add new functions or header files
                              to the GNU C Library.
+* Symbol handling::       How to handle symbols in the GNU C Library.
 * Porting::               How to port the GNU C Library to
                              a new machine or operating system.
 @end menu
@@ -183,6 +184,127 @@  header file in the machine-specific directory, e.g.,
 @file{sysdeps/powerpc/sys/platform/ppc.h}.
 
 
+@node Symbol handling
+@appendixsec Symbol handling in the GNU C Library
+
+@menu
+* 64-bit time symbol handling :: How to handle 64-bit time related
+                                    symbols in the GNU C Library.
+@end menu
+
+@node 64-bit time symbol handling
+@appendixsubsec 64-bit time symbol handling in the GNU C Library
+
+Some of the architectures supported by @theglibc{} already use 64-bit
+time (@code{__TIMESIZE == 64}), while other architectures use 32-bit time
+(@code{__TIMESIZE != 64}) and therefore cannot handle dates beyond
+2038-01-19 03:14:07 (aka 'Y2038').
+
+In order to make @theglibc{} Y2038-proof, 64-bit time support must be
+added to those 32-bit-time-only architectures. When adding new code
+for Y2038 support, some principles must be followed:
+
+@itemize @bullet
+
+@item
+Y2038 support code added to @theglibc{} must not modify or remove
+existing symbols on 32-bit time architectures. This ensures that
+existing user object code will remain able to link against the newer
+Y2038-proof @glibcadj{}.
+
+@item
+Y2038 support code added to @theglibc{} must not add any new symbol
+when building on 64-bit time architectures when existing symbols are
+aleady Y2038-proof.
+
+@item
+In public headers, @theglibc{} supports either 64- or 32-bit time with
+a single set of names. On 64-bit time architectures, only 64-bit time
+is supporte (@code{time_t} is 64-bit, @code{time()} returns a 64-bit time
+etc); on 32-bit architectures, 32-bit time is supported (@code{time_t}
+is 32-bit, @code{time()} returns a 32-bit time etc) unless
+@code{_TIME_BITS} is defined equal to @code{64} before including
+headers from @theglibc{}, in which case 64-bit time is supported.
+
+@end itemize
+
+In order to simplify Y2038 support, all Y2038 proofing follows the
+same mechanism: for each non-Y2038-proof 32-bit-time function, a
+Y2038-proof 64-bit-time version is created, and the 32-bit-time function
+is rewritten as a wrapper around the 64-bit-time function.
+
+Here is an example with @code{localtime}:
+
+Function @code{localtime} is declared in @file{time/time.h} as
+@smallexample
+extern struct tm *localtime (const time_t *__timer) __THROW;
+libc_hidden_proto (localtime)
+@end smallexample
+
+On 64-bit time architectures, we declare @code{__localtime64} to be a
+macro which evaluates to @code{localtime}, so that
+@smallexample
+extern struct tm *__localtime64 (const __time64_t *__timer) __THROW;
+@end smallexample
+evaluates to
+@smallexample
+extern struct tm *localtime (const time_t *__timer) __THROW;
+@end smallexample
+
+(for 64-bit-time architectures, @code{__time64_t} is declared as a
+macro which evaluates to @code{time_t})
+
+On 32-bit time architectures, we declare @code{__localtime64} similar
+to @code{localtime} except it uses Y2038-proof types:
+@smallexample
+#if __TIMESIZE == 64
+# define __localtime64 localtime
+#else
+extern struct tm *__localtime64 (const __time64_t *__timer) __THROW;
+libc_hidden_proto (__localtime64)
+#endif
+@end smallexample
+
+(type @code{time_t} is replaced with @code{__time64_t} because
+@code{time_t} is not Y2038-proof, whereas @code{struct tm} is not
+replaced because it is already Y2038-proof.)
+
+The implementation of @code{localtime} is replaced as follows:
+
+@smallexample
+struct tm *
+__localtime64 (const __time64_t *t)
+(
+  return __tz_convert (*t, 1, &_tmbuf);
+)
+libc_hidden_def (__localtime64)
+
+/* Provide a 32-bit variant if needed */
+
+#if __TIMESIZE != 64
+
+struct tm *
+localtime (const time_t *t)
+(
+  __time64_t t64 = *t;
+  return __localtime64 (&t64);
+)
+libc_hidden_def (localtime)
+
+#endif
+@end smallexample
+
+For 64-bit-time architectures, @code{__localtime64} is a macro which
+evaluates to @code{localtime} and @code{__time64} is a macro which
+evaluates to @code{time_t}, so the first definition above amounts to
+the original definition of @code{localtime}; and since @code{__TIMESIZE}
+equals 64, the second definition is removed by the preprocessor.
+
+For 32-bit architectures, the first definition creates the new function
+@code{__localtime64} which uses Y2038-proof types, and since
+@code{__TIMESIZE} is different from 64, the second definition provides
+@code{localtime} as a wrapper around @code{__localtime64}.
+
 @node Porting
 @appendixsec Porting @theglibc{}
 
diff --git a/time/localtime.c b/time/localtime.c
index 92dbfe0f8c..50e0be2272 100644
--- a/time/localtime.c
+++ b/time/localtime.c
@@ -21,7 +21,6 @@ 
 /* The C Standard says that localtime and gmtime return the same pointer.  */
 struct tm _tmbuf;
 
-
 /* Return the `struct tm' representation of *T in local time,
    using *TP to store the result.  */
 struct tm *
@@ -31,11 +30,24 @@  __localtime_r (const time_t *t, struct tm *tp)
 }
 weak_alias (__localtime_r, localtime_r)
 
-
 /* Return the `struct tm' representation of *T in local time.  */
 struct tm *
-localtime (const time_t *t)
+__localtime64 (const __time64_t *t)
 {
   return __tz_convert (*t, 1, &_tmbuf);
 }
+libc_hidden_def (__localtime64)
+
+/* Provide a 32-bit variant if needed */
+
+#if __TIMESIZE != 64
+
+struct tm *
+localtime (const time_t *t)
+{
+  __time64_t t64 = *t;
+  return __localtime64 (&t64);
+}
 libc_hidden_def (localtime)
+
+#endif