Просмотр исходного кода

Avoid some static aliasing unless C89

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.
Paul Eggert 3 лет назад
Родитель
Сommit
e8810783aa
5 измененных файлов с 47 добавлено и 3 удалено
  1. 2 0
      Makefile
  2. 13 0
      NEWS
  3. 13 3
      asctime.c
  4. 15 0
      localtime.c
  5. 4 0
      private.h

+ 2 - 0
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;

+ 13 - 0
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:

+ 13 - 3
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);
 }

+ 15 - 0
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);
 }
 

+ 4 - 0
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.