]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Y2038: make __tz_convert compatible with 64-bit-time
authorAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Wed, 11 Apr 2018 19:32:34 +0000 (21:32 +0200)
committerAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Wed, 13 Jun 2018 07:10:16 +0000 (09:10 +0200)
This implies that its callers be 64-bit-time compatible too.
It is done by creating 64-bit-time versions of these and
turning their original 32-bit-time versions into wrappers
(at a slight execution time cost).

The callers affected are:

  * localtime
  * localtime_r
  * ctime
  * ctime_r
  * gmtime
  * gmtime_r

Note that in time/tzfile.c we do not need to check for time_t
overflows anymore as introduced by commit fc79706a323 since we
now use internal_time_t.

include/time.h
time/Versions
time/ctime.c
time/ctime_r.c
time/gmtime.c
time/localtime.c
time/offtime.c
time/tzfile.c
time/tzset.c

index 93638aa215cb62a02aad7b8783b509b48bbf737c..c67e163eb8d98814ba24e9c6ef64f2894e36218a 100644 (file)
@@ -9,6 +9,8 @@ extern __typeof (strftime_l) __strftime_l;
 libc_hidden_proto (__strftime_l)
 extern __typeof (strptime_l) __strptime_l;
 
+extern struct tm *__localtime64 (const __time64_t *__timer);
+
 libc_hidden_proto (time)
 libc_hidden_proto (asctime)
 libc_hidden_proto (mktime)
@@ -17,6 +19,8 @@ libc_hidden_proto (localtime)
 libc_hidden_proto (strftime)
 libc_hidden_proto (strptime)
 
+libc_hidden_proto (__localtime64)
+
 extern __typeof (clock_getres) __clock_getres;
 extern __typeof (clock_gettime) __clock_gettime;
 libc_hidden_proto (__clock_gettime)
@@ -51,7 +55,7 @@ extern void __tzfile_default (const char *std, const char *dst,
                              long int stdoff, long int dstoff)
   attribute_hidden;
 extern void __tzset_parse_tz (const char *tz) attribute_hidden;
-extern void __tz_compute (time_t timer, struct tm *tm, int use_localtime)
+extern void __tz_compute (internal_time_t timer, struct tm *tm, int use_localtime)
   __THROW attribute_hidden;
 
 /* Subroutine of `mktime'.  Return the `time_t' representation of TP and
@@ -64,15 +68,21 @@ extern time_t __mktime_internal (struct tm *__tp,
 extern struct tm *__localtime_r (const time_t *__timer,
                                 struct tm *__tp) attribute_hidden;
 
+extern struct tm *__localtime64_r (const __time64_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)
 
-/* Compute the `struct tm' representation of *T,
+extern struct tm *__gmtime64_r (const __time64_t *__restrict __timer,
+                               struct tm *__restrict __tp);
+
+/* Compute the `struct tm' representation of T,
    offset OFFSET seconds east of UTC,
    and store year, yday, mon, mday, wday, hour, min, sec into *TP.
    Return nonzero if successful.  */
-extern int __offtime (const time_t *__timer,
+extern int __offtime (const internal_time_t __timer,
                      long int __offset,
                      struct tm *__tp) attribute_hidden;
 
@@ -81,8 +91,8 @@ extern char *__asctime_r (const struct tm *__tp, char *__buf)
 extern void __tzset (void) attribute_hidden;
 
 /* Prototype for the internal function to get information based on TZ.  */
-extern struct tm *__tz_convert (const time_t *timer, int use_localtime,
-                               struct tm *tp) attribute_hidden;
+extern struct tm *__tz_convert (const internal_time_t timer, int use_localtime,
+                               struct tm *tp) attribute_hidden;
 
 extern int __nanosleep (const struct timespec *__requested_time,
                        struct timespec *__remaining);
index fd838181e4f0969dbd9a553d0378a7e8d4a90eff..8b83f5b04136d7471cbbb7cba41440a170eede03 100644 (file)
@@ -65,4 +65,9 @@ libc {
   GLIBC_2.16 {
     timespec_get;
   }
+  GLIBC_2.28 {
+    __ctime64; __ctime64_r;
+    __gmtime64; __gmtime64_r;
+    __localtime64; __localtime64_r;
+  }
 }
index 1222614f2951e3d6cd83788b409106004750e2e9..de7f3c5bd373e141d8da46a7465aeef471b7b825 100644 (file)
    <http://www.gnu.org/licenses/>.  */
 
 #include <time.h>
+#include <errno.h>
 
 /* Return a string as returned by asctime which
    is the representation of *T in that form.  */
 char *
+__ctime64 (const __time64_t *t)
+{
+  /* Apply the same rule as ctime:
+     make ctime64 (t) is equivalent to asctime (localtime64 (t)).  */
+  return asctime (__localtime64 (t));
+}
+
+/* The 32-bit time wrapper.  */
+char *
 ctime (const time_t *t)
 {
-  /* The C Standard says ctime (t) is equivalent to asctime (localtime (t)).
-     In particular, ctime and asctime must yield the same pointer.  */
-  return asctime (localtime (t));
+  __time64_t t64;
+  if (t == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+  t64 = *t;
+  return __ctime64 (&t64);
 }
index c111146d76d9ea502ad96d2960c62387fe8f1901..eb6e2f3ed68be5b0d16bdc4767ab0b5a67675162 100644 (file)
    <http://www.gnu.org/licenses/>.  */
 
 #include <time.h>
+#include <errno.h>
 
 /* Return a string as returned by asctime which is the representation
-   of *T in that form.  Reentrant version.  */
+   of *T in that form.  Reentrant Y2038-proof version.  */
 char *
-ctime_r (const time_t *t, char *buf)
+__ctime64_r (const __time64_t *t, char *buf)
 {
   struct tm tm;
-  return __asctime_r (__localtime_r (t, &tm), buf);
+  return __asctime_r (__localtime64_r (t, &tm), buf);
+}
+
+/* The 32-bit-time wrapper.  */
+char *
+ctime_r (const time_t *t, char *buf)
+{
+  __time64_t t64;
+  if (t == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+  t64 = *t;
+  return __ctime64_r (&t64, buf);
 }
index dc33b3e68ab67a0748528fd07757a4cafdd5a3eb..b5ec84f36ad0c71838a27462e983fffe622c271c 100644 (file)
    <http://www.gnu.org/licenses/>.  */
 
 #include <time.h>
+#include <errno.h>
 
-/* Return the `struct tm' representation of *T in UTC,
-   using *TP to store the result.  */
+/* Return the `struct tm' representation of 64-bit-time *T
+   in UTC, using *TP to store the result.  */
+struct tm *
+__gmtime64_r (const __time64_t *t, struct tm *tp)
+{
+  return __tz_convert (*t, 0, tp);
+}
+
+/* The 32-bit-time wrapper.  */
 struct tm *
 __gmtime_r (const time_t *t, struct tm *tp)
 {
-  return __tz_convert (t, 0, tp);
+  __time64_t t64;
+  if (t == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+  t64 = *t;
+  return __gmtime64_r (&t64, tp);
 }
 libc_hidden_def (__gmtime_r)
 weak_alias (__gmtime_r, gmtime_r)
 
+/* Return the `struct tm' representation of 64-bit-time *T in UTC.     */
+struct tm *
+__gmtime64 (const __time64_t *t)
+{
+  return __tz_convert (*t, 0, &_tmbuf);
+}
 
-/* Return the `struct tm' representation of *T in UTC. */
+/* The 32-bit-time wrapper. */
 struct tm *
 gmtime (const time_t *t)
 {
-  return __tz_convert (t, 0, &_tmbuf);
+  __time64_t t64;
+  if (t == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+  t64 = *t;
+  return __gmtime64 (&t64);
 }
index 8684a8a9713fd4638270fd0b2390781f9b7bb102..68f5322b218ba576af173c0052933ab11225fcd5 100644 (file)
    <http://www.gnu.org/licenses/>.  */
 
 #include <time.h>
+#include <errno.h>
 
 /* 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 *
+__localtime64_r (const __time64_t *t, struct tm *tp)
+{
+  return __tz_convert (*t, 1, tp);
+}
+
+/* The 32-bit-time wrapper.  */
+struct tm *
 __localtime_r (const time_t *t, struct tm *tp)
 {
-  return __tz_convert (t, 1, tp);
+  __time64_t t64;
+  if (t == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+  t64 = *t;
+  return __localtime64_r (&t64, tp);
 }
 weak_alias (__localtime_r, localtime_r)
 
-
 /* Return the `struct tm' representation of *T in local time.  */
 struct tm *
+__localtime64 (const __time64_t *t)
+{
+  return __tz_convert (*t, 1, &_tmbuf);
+}
+
+/* The 32-bit-time wrapper.  */
+struct tm *
 localtime (const time_t *t)
 {
-  return __tz_convert (t, 1, &_tmbuf);
+  __time64_t t64;
+  if (t == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+  t64 = *t;
+  return __localtime64 (&t64);
 }
 libc_hidden_def (localtime)
+
index 04c48389fc288bf543eda4bf9e1e0fd7356950c3..1ff71e3c7ec1d2e92eb9bac80d9ec7e5654e7f76 100644 (file)
 #define        SECS_PER_HOUR   (60 * 60)
 #define        SECS_PER_DAY    (SECS_PER_HOUR * 24)
 
-/* Compute the `struct tm' representation of *T,
+/* Compute the `struct tm' representation of T,
    offset OFFSET seconds east of UTC,
    and store year, yday, mon, mday, wday, hour, min, sec into *TP.
    Return nonzero if successful.  */
 int
-__offtime (const time_t *t, long int offset, struct tm *tp)
+__offtime (const internal_time_t t, long int offset, struct tm *tp)
 {
-  time_t days, rem, y;
+  internal_time_t days, rem, y;
   const unsigned short int *ip;
 
-  days = *t / SECS_PER_DAY;
-  rem = *t % SECS_PER_DAY;
+  days = t / SECS_PER_DAY;
+  rem = t % SECS_PER_DAY;
   rem += offset;
   while (rem < 0)
     {
@@ -60,7 +60,7 @@ __offtime (const time_t *t, long int offset, struct tm *tp)
   while (days < 0 || days >= (__isleap (y) ? 366 : 365))
     {
       /* Guess a corrected year, assuming 365 days per year.  */
-      time_t yg = y + days / 365 - (days % 365 < 0);
+      internal_time_t yg = y + days / 365 - (days % 365 < 0);
 
       /* Adjust DAYS and Y to match the guessed year.  */
       days -= ((yg - y) * 365
index 2a385b92bcdefec08576a835293ccd10e5572019..94ca3323d5fbf72f00e322bfece0f33274c95d50 100644 (file)
@@ -635,16 +635,10 @@ __tzfile_compute (internal_time_t timer, int use_localtime,
 
          /* Convert to broken down structure.  If this fails do not
             use the string.  */
-         {
-           time_t truncated = timer;
-           if (__glibc_unlikely (truncated != timer
-                                 || ! __offtime (&truncated, 0, tp)))
-             goto use_last;
-         }
-
-         /* Use the rules from the TZ string to compute the change.
-            timer fits into time_t due to the truncation check
-            above.  */
+         if (__glibc_unlikely (! __offtime (timer, 0, tp)))
+           goto use_last;
+
+         /* Use the rules from the TZ string to compute the change.  */
          __tz_compute (timer, tp, 1);
 
          /* If tzspec comes from posixrules loaded by __tzfile_default,
index a828b9fb75bed6ca18460d32c83e31eb30e161b7..c2bb6cdffabf5c66def4b0ca89f00186934d974a 100644 (file)
@@ -16,7 +16,6 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <ctype.h>
-#include <errno.h>
 #include <libc-lock.h>
 #include <stdbool.h>
 #include <stddef.h>
@@ -27,7 +26,7 @@
 
 #include <timezone/tzfile.h>
 
-#define SECSPERDAY ((time_t) 86400)
+#define SECSPERDAY ((internal_time_t) 86400)
 
 char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
 int __daylight = 0;
@@ -55,7 +54,7 @@ typedef struct
 
     /* We cache the computed time of change for a
        given year so we don't have to recompute it.  */
-    time_t change;     /* When to change to this zone.  */
+    internal_time_t change;    /* When to change to this zone.  */
     int computed_for;  /* Year above is computed for.  */
   } tz_rule;
 
@@ -416,7 +415,7 @@ tzset_internal (int always)
       tz_rules[0].name = tz_rules[1].name = "UTC";
       if (J0 != 0)
        tz_rules[0].type = tz_rules[1].type = J0;
-      tz_rules[0].change = tz_rules[1].change = (time_t) -1;
+      tz_rules[0].change = tz_rules[1].change = (internal_time_t) -1;
       update_vars ();
       return;
     }
@@ -424,13 +423,13 @@ tzset_internal (int always)
   __tzset_parse_tz (tz);
 }
 \f
-/* Figure out the exact time (as a time_t) in YEAR
+/* Figure out the exact time (as an internal_time_t) in YEAR
    when the change described by RULE will occur and
    put it in RULE->change, saving YEAR in RULE->computed_for.  */
 static void
 compute_change (tz_rule *rule, int year)
 {
-  time_t t;
+  internal_time_t t;
 
   if (year != -1 && rule->computed_for == year)
     /* Operations on times in 2 BC will be slower.  Oh well.  */
@@ -514,9 +513,10 @@ compute_change (tz_rule *rule, int year)
 
 
 /* Figure out the correct timezone for TM and set `__tzname',
-   `__timezone', and `__daylight' accordingly.  */
+   `__timezone', and `__daylight' accordingly.
+   NOTE: this takes an internal_time_t value, so passing a __time_t value is OK. */
 void
-__tz_compute (time_t timer, struct tm *tm, int use_localtime)
+__tz_compute (internal_time_t timer, struct tm *tm, int use_localtime)
 {
   compute_change (&tz_rules[0], 1900 + tm->tm_year);
   compute_change (&tz_rules[1], 1900 + tm->tm_year);
@@ -562,20 +562,14 @@ __tzset (void)
 }
 weak_alias (__tzset, tzset)
 \f
-/* Return the `struct tm' representation of *TIMER in the local timezone.
+/* Return the `struct tm' representation of TIMER in the local timezone.
    Use local time if USE_LOCALTIME is nonzero, UTC otherwise.  */
 struct tm *
-__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
+__tz_convert (const internal_time_t timer, int use_localtime, struct tm *tp)
 {
   long int leap_correction;
   int leap_extra_secs;
 
-  if (timer == NULL)
-    {
-      __set_errno (EINVAL);
-      return NULL;
-    }
-
   __libc_lock_lock (tzset_lock);
 
   /* Update internal database according to current TZ setting.
@@ -584,14 +578,14 @@ __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
   tzset_internal (tp == &_tmbuf && use_localtime);
 
   if (__use_tzfile)
-    __tzfile_compute (*timer, use_localtime, &leap_correction,
+    __tzfile_compute (timer, use_localtime, &leap_correction,
                      &leap_extra_secs, tp);
   else
     {
       if (! __offtime (timer, 0, tp))
        tp = NULL;
       else
-       __tz_compute (*timer, tp, use_localtime);
+       __tz_compute (timer, tp, use_localtime);
       leap_correction = 0L;
       leap_extra_secs = 0;
     }