[tz] [PROPOSED 3/4] POSIX.1-2024 removes asctime_r, ctime_r
Paul Eggert
eggert at cs.ucla.edu
Sat May 25 21:24:34 UTC 2024
Support POSIX.1-2024 by defining asctime_r and ctime_r only on
platforms conforming to POSIX.1-2017 and earlier.
* Makefile, NEWS, localtime.c, newctime.3: Document this.
* asctime.c (asctime_static): New macro.
(asctime_r, ctime_r): Now private static functions
unless supporting older POSIX.
* private.h (HAVE_DECL_ASCTIME_R): Default to 1
only if SUPPORT_POSIX2008.
(SUPPORT_POSIX2008): New macro.
(asctime_r, ctime_r): Declare only if SUPPORT_POSIX2008.
---
Makefile | 16 ++++++++++------
NEWS | 7 +++++++
asctime.c | 19 ++++++++++++++++---
localtime.c | 4 ++--
newctime.3 | 9 +++++++++
private.h | 45 +++++++++++++++++++++++++++++++++++----------
6 files changed, 79 insertions(+), 21 deletions(-)
diff --git a/Makefile b/Makefile
index d60aacc9..6b093013 100644
--- a/Makefile
+++ b/Makefile
@@ -10,10 +10,10 @@
# To affect how this Makefile works, you can run a shell script like this:
#
# #!/bin/sh
-# make CC='gcc -std=gnu11' "$@"
+# make CC='gcc -std=gnu23' "$@"
#
-# This example script is appropriate for a pre-2017 GNU/Linux system
-# where a non-default setting is needed to support this package's use of C99.
+# This example script is appropriate for a circa 2024 GNU/Linux system
+# where a non-default setting enables this package's optional use of C23.
#
# Alternatively, you can simply edit this Makefile to tailor the following
# macro definitions.
@@ -53,7 +53,7 @@ DATAFORM= main
LOCALTIME= Factory
-# The POSIXRULES macro controls interpretation of POSIX-2017.1-like TZ
+# The POSIXRULES macro controls interpretation of POSIX-like TZ
# settings like TZ='EET-2EEST' that lack DST transition rules.
# If POSIXRULES is '-', no template is installed; this is the default.
# Any other value for POSIXRULES is obsolete and should not be relied on, as:
@@ -219,6 +219,7 @@ LDLIBS=
# than what POSIX specifies, assuming local time is UT.
# For example, N is 252460800 on AmigaOS.
# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
+# on POSIX platforms predating POSIX.1-2024
# -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
# -DHAVE_DECL_TIMEGM=0 if <time.h> does not declare timegm
# -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
@@ -229,7 +230,7 @@ LDLIBS=
# where LDLIBS also needs to contain -lintl on some hosts;
# -DHAVE_GETTEXT=0 to avoid using gettext
# -DHAVE_INCOMPATIBLE_CTIME_R if your system's time.h declares
-# ctime_r and asctime_r incompatibly with the POSIX standard
+# ctime_r and asctime_r incompatibly with POSIX.1-2017
# (Solaris when _POSIX_PTHREAD_SEMANTICS is not defined).
# -DHAVE_INTTYPES_H=0 if <inttypes.h> does not work*+
# -DHAVE_LINK=0 if your system lacks a link function
@@ -263,6 +264,8 @@ LDLIBS=
# -Dssize_t=long on hosts like MS-Windows that lack ssize_t
# -DSUPPORT_C89 if the tzcode library should support C89 callers+
# However, this might trigger latent bugs in C99-or-later callers.
+# -DSUPPORT_POSIX2008 if the library should support older POSIX callers+
+# However, this might cause problems in POSIX.1-2024-or-later callers.
# -DSUPPRESS_TZDIR to not prepend TZDIR to file names; this has
# security implications and is not recommended for general use
# -DTHREAD_SAFE to make localtime.c thread-safe, as POSIX requires;
@@ -302,7 +305,8 @@ LDLIBS=
#
# * Options marked "*" can be omitted if your compiler is C23 compatible.
# * Options marked "+" are obsolescent and are planned to be removed
-# once the code assumes C99 or later, say in the year 2029.
+# once the code assumes C99 or later (say in the year 2029)
+# and POSIX.1-2024 or later (say in the year 2034).
#
# Select instrumentation via "make GCC_INSTRUMENT='whatever'".
GCC_INSTRUMENT = \
diff --git a/NEWS b/NEWS
index 2b34f78c..596a67ab 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ Unreleased, experimental changes
System V names are now obsolescent.
The main data form now uses %z.
The code now conforms to RFC 8536 for early timestamps.
+ Support POSIX.1-2024, which removes asctime_r and ctime_r.
Improve historical data for Portugal and possessions.
Changes to data
@@ -52,6 +53,12 @@ Unreleased, experimental changes
does not affect behavior when reading TZif files generated by zic
2018f and later.
+ POSIX.1-2024 removes asctime_r and ctime_r and does not let
+ libraries define them, so remove them except when needed to
+ conform to earlier POSIX. These functions are dangerous as they
+ can overrun user buffers. If you still need them, add
+ -DSUPPORT_POSIX2008 to CFLAGS.
+
Release 2024a - 2024-02-01 09:28:56 -0800
diff --git a/asctime.c b/asctime.c
index a40661f2..f75ec868 100644
--- a/asctime.c
+++ b/asctime.c
@@ -1,4 +1,4 @@
-/* asctime and asctime_r a la POSIX and ISO C, except pad years before 1000. */
+/* asctime a la ISO C. */
/*
** This file is in the public domain, so clarified as of
@@ -25,8 +25,8 @@
** leading zeroes to get the newline in the traditional place.
** The -4 ensures that we get four characters of output even if
** we call a strftime variant that produces fewer characters for some years.
-** The ISO C and POSIX standards prohibit padding the year,
-** but many implementations pad anyway; most likely the standards are buggy.
+** This conforms to recent ISO C and POSIX standards, which say behavior
+** is undefined when the year is less than 1000 or greater than 9999.
*/
static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n";
/*
@@ -60,6 +60,18 @@ static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
static char buf_ctime[sizeof buf_asctime];
#endif
+/* Publish asctime_r and ctime_r only when supporting older POSIX. */
+#if SUPPORT_POSIX2008
+# define asctime_static
+#else
+# define asctime_static static
+# undef asctime_r
+# undef ctime_r
+# define asctime_r static_asctime_r
+# define ctime_r static_ctime_r
+#endif
+
+asctime_static
char *
asctime_r(struct tm const *restrict timeptr, char *restrict buf)
{
@@ -116,6 +128,7 @@ asctime(register const struct tm *timeptr)
return asctime_r(timeptr, buf_asctime);
}
+asctime_static
char *
ctime_r(const time_t *timep, char *buf)
{
diff --git a/localtime.c b/localtime.c
index 6d8030cd..83466575 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1408,8 +1408,8 @@ tzfree(timezone_t sp)
}
/*
-** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
-** ctime_r are obsolescent and have potential security problems that
+** NetBSD 6.1.4 has ctime_rz, but omit it because C23 deprecates ctime and
+** POSIX.1-2024 removes ctime_r. Both have potential security problems that
** ctime_rz would share. Callers can instead use localtime_rz + strftime.
**
** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
diff --git a/newctime.3 b/newctime.3
index d6abd61f..ccc19748 100644
--- a/newctime.3
+++ b/newctime.3
@@ -13,12 +13,14 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time
.PP
.B [[deprecated]] char *ctime(time_t const *clock);
.PP
+/* Only in POSIX.1-2017 and earlier. */
.B char *ctime_r(time_t const *clock, char *buf);
.PP
.B double difftime(time_t time1, time_t time0);
.PP
.B [[deprecated]] char *asctime(struct tm const *tm);
.PP
+/* Only in POSIX.1-2017 and earlier. */
.B "char *asctime_r(struct tm const *restrict tm,"
.B " char *restrict result);"
.PP
@@ -223,6 +225,13 @@ and
functions
are like their unsuffixed counterparts, except that they accept an
additional argument specifying where to store the result if successful.
+The
+.B ctime_r
+and
+.B asctime_r
+functions are present only on systems supporting POSIX.1-2017 and earlier,
+as they are removed in POSIX.1-2024 and user code can define these
+functions with other meanings.
.PP
The
.B localtime_rz
diff --git a/private.h b/private.h
index 0dac6af4..67061fbb 100644
--- a/private.h
+++ b/private.h
@@ -69,10 +69,6 @@
** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'.
*/
-#ifndef HAVE_DECL_ASCTIME_R
-# define HAVE_DECL_ASCTIME_R 1
-#endif
-
#if !defined HAVE__GENERIC && defined __has_extension
# if !__has_extension(c_generic_selections)
# define HAVE__GENERIC 0
@@ -236,6 +232,31 @@
# include <unistd.h> /* for R_OK, and other POSIX goodness */
#endif /* HAVE_UNISTD_H */
+/* SUPPORT_POSIX2008 means the tzcode library should support
+ POSIX.1-2017-and-earlier callers in addition to the usual support for
+ POSIX.1-2024-and-later callers; however, this can be
+ incompatible with POSIX.1-2024-and-later callers.
+ This macro is obsolescent, and the plan is to remove it
+ along with any code needed only when it is nonzero.
+ A good time to do that might be in the year 2034.
+ This macro's name is SUPPORT_POSIX2008 because _POSIX_VERSION == 200809
+ in POSIX.1-2017, a minor revision of POSIX.1-2008. */
+#ifndef SUPPORT_POSIX2008
+# if defined _POSIX_VERSION && _POSIX_VERSION <= 200809
+# define SUPPORT_POSIX2008 1
+# else
+# define SUPPORT_POSIX2008 0
+# endif
+#endif
+
+#ifndef HAVE_DECL_ASCTIME_R
+# if SUPPORT_POSIX2008
+# define HAVE_DECL_ASCTIME_R 1
+# else
+# define HAVE_DECL_ASCTIME_R 0
+# endif
+#endif
+
#ifndef HAVE_STRFTIME_L
# if _POSIX_VERSION < 200809
# define HAVE_STRFTIME_L 0
@@ -604,12 +625,8 @@ typedef time_tz tz_time_t;
# undef asctime
# define asctime tz_asctime
-# undef asctime_r
-# define asctime_r tz_asctime_r
# undef ctime
# define ctime tz_ctime
-# undef ctime_r
-# define ctime_r tz_ctime_r
# undef difftime
# define difftime tz_difftime
# undef gmtime
@@ -654,6 +671,12 @@ typedef time_tz tz_time_t;
# define tzfree tz_tzfree
# undef tzset
# define tzset tz_tzset
+# if SUPPORT_POSIX2008
+# undef asctime_r
+# define asctime_r tz_asctime_r
+# undef ctime_r
+# define ctime_r tz_ctime_r
+# endif
# if HAVE_STRFTIME_L
# undef strftime_l
# define strftime_l tz_strftime_l
@@ -679,9 +702,11 @@ typedef time_tz tz_time_t;
# define DEPRECATED_IN_C23 ATTRIBUTE_DEPRECATED
# endif
DEPRECATED_IN_C23 char *asctime(struct tm const *);
-char *asctime_r(struct tm const *restrict, char *restrict);
DEPRECATED_IN_C23 char *ctime(time_t const *);
+#if SUPPORT_POSIX2008
+char *asctime_r(struct tm const *restrict, char *restrict);
char *ctime_r(time_t const *, char *);
+#endif
ATTRIBUTE_UNSEQUENCED double difftime(time_t, time_t);
size_t strftime(char *restrict, size_t, char const *restrict,
struct tm const *restrict);
@@ -713,7 +738,7 @@ void tzset(void);
time_t timegm(struct tm *);
#endif
-#if !HAVE_DECL_ASCTIME_R && !defined asctime_r
+#if !HAVE_DECL_ASCTIME_R && !defined asctime_r && SUPPORT_POSIX2008
extern char *asctime_r(struct tm const *restrict, char *restrict);
#endif
--
2.45.1
More information about the tz
mailing list