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

Message ID 20190507131848.30980-12-lukma@denx.de
State New
Headers show
Series
  • Untitled series #13145
Related show

Commit Message

Lukasz Majewski May 7, 2019, 1:18 p.m.
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(-)

-- 
2.11.0

Comments

Andreas Schwab May 7, 2019, 1:34 p.m. | #1
On Mai 07 2019, Lukasz Majewski <lukma@denx.de> wrote:

> 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


Perhaps:

#   error _TIME_BITS=64 is allowed only with _FILE_OFFSET_BITS=64

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

Patch

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.