[tz] [PROPOSED 4/4] Avoid some static aliasing unless C89

Paul Eggert eggert at cs.ucla.edu
Wed Nov 30 19:25:52 UTC 2022


C89 requires that localtime(...) == gmtime(...) when both are
successful, and similarly for asctime(...) == ctime(...).
This can lead to bugs in badly-written programs, so continue to
support it only if compiling with -DSUPPORT_C89, since the
requirement was removed in C99.
* Makefile, NEWS: Mention this.
* asctime.c (buf_ctime):
New macro or (if !SUPPORT_C89) static variable.
(asctime_r): Check for it.
(ctime): Use it.
* localtime.c (tm) [!SUPPORT_C89]:
Use three instances of this variable instead of one.
* private.h (SUPPORT_C89): Default to 0.
---
 Makefile    |  2 ++
 NEWS        | 13 +++++++++++++
 asctime.c   | 16 +++++++++++++---
 localtime.c | 15 +++++++++++++++
 private.h   |  4 ++++
 5 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index f0cbf7f..63f3b5c 100644
--- a/Makefile
+++ b/Makefile
@@ -245,6 +245,8 @@ LDLIBS=
 #  -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers
 #	with external linkage, e.g., applications cannot define 'localtime'.
 #  -Dssize_t=long on hosts like MS-Windows that lack ssize_t
+#  -DSUPPORT_C89 if you build or run tzcode on a C89 platform; this option
+#	is obsolescent and is planned to be removed when C99+ is required.
 #  -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;
diff --git a/NEWS b/NEWS
index 701e490..9cb175e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,18 @@
 News for the tz database
 
+Unreleased, experimental changes
+
+  Briefly:
+    tzcode no longer supports C89 unless built with -DSUPPORT_C89
+
+  Changes to code
+
+    tzcode no longer supports C89 by default.  To build or run in a
+    C89 environment, compile with -DSUPPORT_C89, a transitional aid
+    that is planned to be removed in a near-future version, when C99
+    or later will be required.
+
+
 Release 2022g - 2022-11-29 08:58:31 -0800
 
   Briefly:
diff --git a/asctime.c b/asctime.c
index c001621..c84fe8c 100644
--- a/asctime.c
+++ b/asctime.c
@@ -50,6 +50,16 @@ enum { STD_ASCTIME_BUF_SIZE = 26 };
 */
 static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
 
+/* A similar buffer for ctime.
+   C89 requires that they be the same buffer.
+   This requirement was removed in C99, so support it only if requested,
+   as support is more likely to lead to bugs in badly-written programs.  */
+#if SUPPORT_C89
+# define buf_ctime buf_asctime
+#else
+static char buf_ctime[sizeof buf_asctime];
+#endif
+
 char *
 asctime_r(register const struct tm *timeptr, char *buf)
 {
@@ -91,7 +101,8 @@ asctime_r(register const struct tm *timeptr, char *buf)
 		timeptr->tm_mday, timeptr->tm_hour,
 		timeptr->tm_min, timeptr->tm_sec,
 		year);
-	if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime)
+	if (strlen(result) < STD_ASCTIME_BUF_SIZE
+	    || buf == buf_ctime || buf == buf_asctime)
 		return strcpy(buf, result);
 	else {
 		errno = EOVERFLOW;
@@ -116,6 +127,5 @@ ctime_r(const time_t *timep, char *buf)
 char *
 ctime(const time_t *timep)
 {
-  struct tm *tmp = localtime(timep);
-  return tmp ? asctime(tmp) : NULL;
+  return ctime_r(timep, buf_ctime);
 }
diff --git a/localtime.c b/localtime.c
index cb34a9e..f8a0a6e 100644
--- a/localtime.c
+++ b/localtime.c
@@ -186,9 +186,14 @@ static int		lcl_is_set;
 **	ctime, gmtime, localtime] return values in one of two static
 **	objects: a broken-down time structure and an array of char.
 ** Thanks to Paul Eggert for noting this.
+**
+** This requirement was removed in C99, so support it only if requested,
+** as support is more likely to lead to bugs in badly-written programs.
 */
 
+#if SUPPORT_C89
 static struct tm	tm;
+#endif
 
 #if 2 <= HAVE_TZNAME + TZ_TIME_T
 char *			tzname[2] = {
@@ -1648,6 +1653,9 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
 struct tm *
 localtime(const time_t *timep)
 {
+#if !SUPPORT_C89
+  static struct tm tm;
+#endif
   return localtime_tzset(timep, &tm, true);
 }
 
@@ -1694,6 +1702,9 @@ gmtime_r(const time_t *timep, struct tm *tmp)
 struct tm *
 gmtime(const time_t *timep)
 {
+#if !SUPPORT_C89
+  static struct tm tm;
+#endif
   return gmtime_r(timep, &tm);
 }
 
@@ -1703,6 +1714,10 @@ struct tm *
 offtime(const time_t *timep, long offset)
 {
   gmtcheck();
+
+#if !SUPPORT_C89
+  static struct tm tm;
+#endif
   return gmtsub(gmtptr, timep, offset, &tm);
 }
 
diff --git a/private.h b/private.h
index 4a1f667..c22354a 100644
--- a/private.h
+++ b/private.h
@@ -704,6 +704,10 @@ extern int daylight;
 extern long altzone;
 #endif
 
+#ifndef SUPPORT_C89
+# define SUPPORT_C89 0
+#endif
+
 /*
 ** The STD_INSPIRED functions are similar, but most also need
 ** declarations if time_tz is defined.
-- 
2.38.1



More information about the tz mailing list