[v3,5/5] y2038: Support for Y2038 safe time on 32 bit systems
diff mbox series

Message ID 20190507131848.30980-6-lukma@denx.de
State New
Headers show
Series
  • y2038: Linux: Provide __clock_settime function supporting 64 bit time
Related show

Commit Message

Lukasz Majewski May 7, 2019, 1:18 p.m. UTC
The time_t type is now Y2038 safe, which means that it is aliased to
__time64_t when __USE_TIME_BITS64 is defined or __time_t otherwise.

On the contrary the __time_t for 32 bit systems is only 32 bit, so for
Y2038 safe system it must be 64 bit (as is time_t)

This patch introduces the Y2038 specific code to make clock_settime/
__clock_settime64 Y2038 safe on 32 bit systems.
This goal is achieved by using aliasing to clock_settime names when
__USE_TIME_BITS64 is defined.
As a result user programs call 64 bit versions of functions (i.e.
__clock_settime64 instead of __clock_settime), which must have been
globally visible for this purpose - for non Y2038 safe code those are
hidden in glibc.


* include/features.h:
  Add logic to set __USE_TIME_BITS64 according to passed (when building
  userspace Y2038 safe program on 32 bit system) _TIME_BITS and
  _FILE_OFFSET_BITS
* manual/creature.texi: Add description of _TIME_BITS
* time/bits/types/time_t.h:
  Use __time64_t as time_t when __USE_TIME_BITS64 is defined
* time/bits/types/struct_timespec.h:
  Replace tv_sec's __time_t type to Y2038 safe time_t
* include/time.h:
  Remove libc_hidden_proto (__clock_settime64) - make the __clock_settime64
  publicly available for Y2038 safe system
* time/time.h: Redirect clock_settime call to __clock_settime64 on 32 bit
  Y2038 safe systems
* time/Versions (GLIBC_PRIVATE):
  Export __clock_settime64 function as glibc private one, to be accessible from
  user programs when y2038 support is enabled
* time/bits/types/struct_timespec.h:
  Add unnamed padding around tv_nsec when __USE_TIME_BITS64 is defined

---
Changes for v3:
- Only support clock_settime conversion to be Y2038 (use it as an example
  conversion code)

Changes for v2:
- Introduce unnamed padding in the struct timespec exported by glibc
  (to the /usr/include)
---
 include/features.h                | 19 +++++++++++++++++++
 include/time.h                    |  3 ++-
 manual/creature.texi              | 28 ++++++++++++++++++++++++++++
 time/Versions                     |  3 +++
 time/bits/types/struct_timespec.h | 15 +++++++++++++--
 time/bits/types/time_t.h          |  4 ++++
 time/time.h                       |  9 +++++++++
 7 files changed, 78 insertions(+), 3 deletions(-)

Comments

Joseph Myers May 7, 2019, 4:37 p.m. UTC | #1
_TIME_BITS support should not be added to public headers until it's 
complete.  Incomplete support is very unhelpful to users, as it would mean 
lots of functions get declared to take the 64-bit time_t type when in fact 
their ABI takes a 32-bit time_t argument (so code built with _TIME_BITS=64 
wouldn't work at all in a state where it's only partly supported).

When the support *is* added to the public headers, it should come with 
tests added to the glibc testsuite that _TIME_BTIS=64 works as expected 
for all interfaces for which this can readily be tested.
Lukasz Majewski May 8, 2019, 10:27 a.m. UTC | #2
Hi Joseph,

> _TIME_BITS support should not be added to public headers until it's 
> complete.  Incomplete support is very unhelpful to users, as it would
> mean lots of functions get declared to take the 64-bit time_t type
> when in fact their ABI takes a 32-bit time_t argument (so code built
> with _TIME_BITS=64 wouldn't work at all in a state where it's only
> partly supported).

This patch is supposed to show and possible allow some
testing of Y2038 code (64 bit time support in general).

For next version of this patch set - I will mark it as "PATCH DO NOT
APPLY" or such to make it clear.

> 
> When the support *is* added to the public headers, it should come
> with tests added to the glibc testsuite that _TIME_BTIS=64 works as
> expected for all interfaces for which this can readily be tested.
> 




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de

Patch
diff mbox series

diff --git a/include/features.h b/include/features.h
index e016b3e5c7..153c6320f0 100644
--- a/include/features.h
+++ b/include/features.h
@@ -365,6 +365,25 @@ 
 # define __USE_FILE_OFFSET64	1
 #endif
 
+/* We need to know the word size in order to check the time size.  */
+#include <bits/wordsize.h>
+
+#if defined _TIME_BITS
+# if _TIME_BITS == 64
+#  if ! defined (_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS != 64
+#   error _TIME_BITS==64 is allowed only when _FILE_OFFSET_BITS==64
+#  elif __WORDSIZE == 32
+#   define __USE_TIME_BITS64	1
+#  endif
+# elif _TIME_BITS == 32
+#  if __WORDSIZE > 32
+#   error _TIME_BITS=32 is not compatible with __WORDSIZE > 32
+#  endif
+# else
+#  error Invalid _TIME_BITS value (can only be 32 or 64)
+# endif
+#endif
+
 #if defined _DEFAULT_SOURCE
 # define __USE_MISC	1
 #endif
diff --git a/include/time.h b/include/time.h
index 670226df0c..d4b11cb1a9 100644
--- a/include/time.h
+++ b/include/time.h
@@ -132,7 +132,8 @@  libc_hidden_proto (__timegm64)
 #else
 extern int __clock_settime64 (clockid_t clock_id,
                               const struct __timespec64 *tp);
-libc_hidden_proto (__clock_settime64)
+/* For Y2038 safe system the __clock_settime64 needs to be a visible
+   symbol as a replacement for Y2038 unsafe clock_settime.  */
 #endif
 
 /* Compute the `struct tm' representation of T,
diff --git a/manual/creature.texi b/manual/creature.texi
index 8876b2ab77..10b7111043 100644
--- a/manual/creature.texi
+++ b/manual/creature.texi
@@ -165,6 +165,34 @@  This macro was introduced as part of the Large File Support extension
 (LFS).
 @end defvr
 
+@defvr Macro _TIME_BITS
+This macro determines the bit size of @code{time_t} (and therefore the
+bit size of all @code{time_t} derived types and the prototypes of all
+related functions). If @code{_TIME_BITS} is undefined, the bit size of
+time_t equals the bit size of the architecture.
+
+If @code{_TIME_BITS} is undefined, or if @code{_TIME_BITS} is defined
+to the value @code{32} and @code{__WORDSIZE} is defined to the value
+@code{32}, or or if @code{_TIME_BITS} is defined to the value @code{64}
+and @code{__WORDSIZE} is defined to the value @code{64}, nothing changes.
+
+If @code{_TIME_BITS} is defined to the value @code{64} and if
+@code{__WORDSIZE} is defined to the value @code{32}, then the @w{64 bit}
+time API and implementation are used even though the architecture word
+size is @code{32}. Also, if the kernel provides @w{64 bit} time support,
+it is used; otherwise, the @w{32 bit} kernel time support is used (with
+no provision to address kernel Y2038 shortcomings).
+
+If @code{_TIME_BITS} is defined to the value @code{32} and if
+@code{__WORDSIZE} is defined to the value @code{64}, then a compile-time
+error is emitted.
+
+If @code{_TIME_BITS} is defined to a value different from both @code{32}
+and @code{64}, then a compile-time error is emitted.
+
+This macro was introduced as part of the Y2038 support.
+@end defvr
+
 @defvr Macro _ISOC99_SOURCE
 @standards{GNU, (none)}
 If this macro is defined, features from ISO C99 are included.  Since
diff --git a/time/Versions b/time/Versions
index fd838181e4..5109c45ce2 100644
--- a/time/Versions
+++ b/time/Versions
@@ -1,4 +1,7 @@ 
 libc {
+  GLIBC_PRIVATE {
+    __clock_settime64;
+  }
   GLIBC_2.0 {
     # global variables
     __daylight; __timezone; __tzname;
diff --git a/time/bits/types/struct_timespec.h b/time/bits/types/struct_timespec.h
index 5b77c52b4f..f34df0a18c 100644
--- a/time/bits/types/struct_timespec.h
+++ b/time/bits/types/struct_timespec.h
@@ -3,13 +3,24 @@ 
 #define _STRUCT_TIMESPEC 1
 
 #include <bits/types.h>
+#include <bits/types/time_t.h>
 
 /* POSIX.1b structure for a time value.  This is like a `struct timeval' but
    has nanoseconds instead of microseconds.  */
 struct timespec
 {
-  __time_t tv_sec;		/* Seconds.  */
-  __syscall_slong_t tv_nsec;	/* Nanoseconds.  */
+  time_t tv_sec;		/* Seconds.  */
+# ifdef __USE_TIME_BITS64
+#  if __BYTE_ORDER == __BIG_ENDIAN
+  int : 32;
+  __syscall_slong_t tv_nsec; /* Nanoseconds.  */
+#  else
+  __syscall_slong_t tv_nsec; /* Nanoseconds.  */
+  int : 32;
+#  endif
+# else
+  __syscall_slong_t tv_nsec; /* Nanoseconds.  */
+# endif
 };
 
 #endif
diff --git a/time/bits/types/time_t.h b/time/bits/types/time_t.h
index ab8287c6fe..84d67f6ac3 100644
--- a/time/bits/types/time_t.h
+++ b/time/bits/types/time_t.h
@@ -4,6 +4,10 @@ 
 #include <bits/types.h>
 
 /* Returned by `time'.  */
+#ifdef __USE_TIME_BITS64
+typedef __time64_t time_t;
+#else
 typedef __time_t time_t;
+#endif
 
 #endif
diff --git a/time/time.h b/time/time.h
index cba6d15260..0bfd1de925 100644
--- a/time/time.h
+++ b/time/time.h
@@ -222,6 +222,15 @@  extern int clock_gettime (clockid_t __clock_id, struct timespec *__tp) __THROW;
 extern int clock_settime (clockid_t __clock_id, const struct timespec *__tp)
      __THROW;
 
+#ifdef __USE_TIME_BITS64
+# if defined(__REDIRECT)
+extern int __REDIRECT (clock_settime, (clockid_t __clock_id, const struct
+                                       timespec *__tp), __clock_settime64) __THROW;
+# else
+# define clock_settime __clock_settime64
+# endif
+#endif
+
 # ifdef __USE_XOPEN2K
 /* High-resolution sleep with the specified clock.