[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