[v2] Y2038: add function __localtime64
Commit Message
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.
---
v2: fix 'Y2038' => @dfn{Y2038} in manual/maint.texi
include/time.h | 9 +++-
manual/maint.texi | 122 ++++++++++++++++++++++++++++++++++++++++++++++
time/localtime.c | 18 +++++--
3 files changed, 145 insertions(+), 4 deletions(-)
Comments
On Wed, 12 Dec 2018, Albert ARIBAUD (3ADEV) wrote:
> extern struct tm *__localtime_r (const time_t *__timer,
> struct tm *__tp) attribute_hidden;
> -
I don't think this blank line removal should be included in this patch.
> +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
Two spaces after '.' in Texinfo source, throughout.
> +@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{}.
@glibcadj{} is incorrect here, this is not an adjective use.
> +aleady Y2038-proof.
"already"
> +is supporte (@code{time_t} is 64-bit, @code{time()} returns a 64-bit time
"supported"
Do not use () after a function name to indicate it's a function (see the
GNU Coding Standards).
> +/* Provide a 32-bit variant if needed */
Comments, both in code and in the manual, should follow GNU standards, so
end with ". " (full stop, two spaces).
> /* 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. */
Again, I think the patch should avoid stray removals of blank lines.
Hi Joseph,
On Wed, 12 Dec 2018 17:09:22 +0000, Joseph Myers
<joseph@codesourcery.com> wrote :
> > +@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{}.
>
> @glibcadj{} is incorrect here, this is not an adjective use.
I would need a noun form here, and manual/macros.texi does not provide
one. Should I add a @macro definition for glibcnoun there and use it in
the paragraph above?
Cordialement,
Albert ARIBAUD
3ADEV
On Wed, 12 Dec 2018, Albert ARIBAUD wrote:
> Hi Joseph,
>
> On Wed, 12 Dec 2018 17:09:22 +0000, Joseph Myers
> <joseph@codesourcery.com> wrote :
>
> > > +@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{}.
> >
> > @glibcadj{} is incorrect here, this is not an adjective use.
>
> I would need a noun form here, and manual/macros.texi does not provide
> one. Should I add a @macro definition for glibcnoun there and use it in
> the paragraph above?
I think this paragraph would better be rewritten anyway, so avoiding the
need for a new macro.
Rather than writing the text as being about a change to glibc, and so
talking about "existing" symbols or object code and "newer" glibc, it
might better be written in terms of there being two kinds of glibc
configurations: those that only support 64-bit time_t, and those that
support both 32-bit and 64-bit time_t. (With a note, to be removed later,
that the latter are a work in progress, so that external interfaces for
64-bit time_t are not yet enabled on such configurations.)
Then you can explain that for the configurations with only 64-bit time_t,
there are no variant symbol names or function definitions for different
time_t choices (with the consequent internal #defines, etc.) - whereas on
configurations with both 32-bit and 64-bit time_t, time-related functions
generally have two definitions, one being a wrapper round the other (and
the symbol names not containing a "64" are the ones for 32-bit time_t).
This avoids needing to apply descriptions like "newer" or "Y2038-proof" to
"GNU C Library" (although such descriptions might still be relevant to
apply to functions).
With this structure, the fact that configurations with both 32-bit and
64-bit time_t are ones that used to have only 32-bit time_t is essentially
a historical note that explains why a particular design is used. At the
level of individual symbols, it may not even be true that one is the old
symbol and one is the new one; it's entirely plausible that new
time-related functions may be added after the 64-bit time_t support for
such platforms is complete (but before 32-bit time_t support is completely
obsoleted and the relevant symbols made into compat symbols), and so would
get both versions of the symbol added to glibc at the same time.
@@ -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)
@@ -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 @dfn{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{}
@@ -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