[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