Paul Eggert wrote:
> > After the Solaris crash fix, the nstrftime tests still fail, due to this
> > output:
> > 
> > <-00>0: expected "1970-01-01 00:00:00 -0000 (-00)", got "1970-01-01 
> > 00:00:00 +0000 (-00)"
> > <-00>0: expected "1985-11-05 00:53:21 -0000 (-00)", got "1985-11-05 
> > 00:53:21 +0000 (-00)"
> > <-00>0: expected "2001-09-09 01:46:42 -0000 (-00)", got "2001-09-09 
> > 01:46:42 +0000 (-00)"
> ...
> I installed the attached to try to fix that issue. Thanks for reporting it.

Thanks. I confirm it fixes the test failure on Solaris 11.4.

But there are two problems:

1) On FreeBSD 5.2.1 and OpenBSD 6.0, I see a compiler warning:

gcc -std=gnu99 -DHAVE_CONFIG_H -I. -I../../gllib -I..  
-DGNULIB_STRICT_CHECKING=1 -I/home/bruno/include -I/usr/local/include -Wall 
-D_THREAD_SAFE  -g -O2 -MT c-nstrftime.o -MD -MP -MF .deps/c-nstrftime.Tpo -c 
-o c-nstrftime.o ../../gllib/c-nstrftime.c
In file included from ../../gllib/c-nstrftime.c:20:
../../gllib/strftime.c: In function `__strftime_internal':
../../gllib/strftime.c:1471: warning: label `underlying_strftime' defined but 
not used

Also, there is an inconsistency: In underlying_strftime, the condition is
  # if USE_C_LOCALE && (HAVE_STRFTIME_L || HAVE_STRFTIME_LZ)
whereas the rest of the code has
  # if USE_C_LOCALE && HAVE_STRFTIME_L
and also a dozen of
  # if USE_C_LOCALE && !HAVE_STRFTIME_L

Fixed through the first patch below.

2) On NetBSD, one out of 4 unit tests fails:

PASS: test-c-nstrftime-1.sh
PASS: test-c-nstrftime-2.sh
PASS: test-nstrftime-1.sh
FAIL: test-nstrftime-2.sh

The cause is a crash:
main
  -> locales_test
       -> FUNC_CHECKED
            -> nstrftime
                 -> __strftime_internal
                      -> underlying_strftime
                           -> strftime_lz
                                -> _fmt
                                     -> _fmt
                                          -> __tzgetname50

tzgetname = __tzgetname50 assumes that its first argument is != NULL.

strftime_lz and _fmt pass their timezone_t argument down.

The crashing call is
  underlying_strftime (tz=NULL, ubuf, ubufsize=1024, modifier=0, 
format_char='c', tp)

tz=NULL means universal time (a.k.a. GMT) in our strftime.h, but is undefined
behaviour for NetBSD's functions. See https://man.netbsd.org/tzset.3 .

Fixed through the second patch below.

Bruno

>From 0e5d4c8bc02ea8615e43cae70a9fc114eabcf778 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 18 Jun 2024 14:27:18 +0200
Subject: [PATCH 1/3] c-nstrftime: Fix warning on platforms without strftime_l.

* lib/strftime.c: Add comment regarding HAVE_STRFTIME_L.
(underlying_strftime): Don't define if this function is not used.
Correct indentation. Simplify #if condition.
(__strftime_internal): Disable code that is not used on platforms
without strftime_l.
---
 ChangeLog      |  9 +++++++++
 lib/strftime.c | 22 +++++++++++++++-------
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 75f06623d6..cb44449076 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2024-06-18  Bruno Haible  <br...@clisp.org>
+
+	c-nstrftime: Fix warning on platforms without strftime_l.
+	* lib/strftime.c: Add comment regarding HAVE_STRFTIME_L.
+	(underlying_strftime): Don't define if this function is not used.
+	Correct indentation. Simplify #if condition.
+	(__strftime_internal): Disable code that is not used on platforms
+	without strftime_l.
+
 2024-06-17  Paul Eggert  <egg...@cs.ucla.edu>
 
 	Improve wording for Y2038 and largefile probes
diff --git a/lib/strftime.c b/lib/strftime.c
index ff52fc8119..a757b4f313 100644
--- a/lib/strftime.c
+++ b/lib/strftime.c
@@ -38,8 +38,6 @@
 # include "time-internal.h"
 #endif
 
-#define HAVE_NATIVE_TIME_Z (USE_C_LOCALE ? HAVE_STRFTIME_LZ : HAVE_STRFTIME_Z)
-
 /* Whether to require GNU behavior for AM and PM indicators, even on
    other platforms.  This matters only in non-C locales.
    The default is to require it; you can override this via
@@ -377,6 +375,15 @@ memcpy_uppcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
 #endif
 
 
+/* Note: We assume that HAVE_STRFTIME_LZ implies HAVE_STRFTIME_L.
+   Otherwise, we would have to write (HAVE_STRFTIME_L || HAVE_STRFTIME_LZ)
+   instead of HAVE_STRFTIME_L everywhere.  */
+
+/* Define to 1 if we can use the system's native functions that takes a
+   timezone_t argument.  As of 2024, this is only true on NetBSD.  */
+#define HAVE_NATIVE_TIME_Z \
+  (USE_C_LOCALE && HAVE_STRFTIME_L ? HAVE_STRFTIME_LZ : HAVE_STRFTIME_Z)
+
 #if USE_C_LOCALE && HAVE_STRFTIME_L
 
 /* Cache for the C locale object.
@@ -837,7 +844,8 @@ static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
                                    bool, enum pad_style, int, bool *
                                    extra_args_spec LOCALE_PARAM);
 
-#ifndef _LIBC
+#if !defined _LIBC \
+    && (!(USE_C_LOCALE && !HAVE_STRFTIME_L) || !HAVE_STRUCT_TM_TM_ZONE)
 
 /* Make sure we're calling the actual underlying strftime.
    In some cases, time.h contains something like
@@ -869,17 +877,17 @@ underlying_strftime (timezone_t tz, char *ubuf, size_t ubufsize,
   *u++ = format_char;
   *u = '\0';
 
-#if !HAVE_NATIVE_TIME_Z
+# if !HAVE_NATIVE_TIME_Z
   if (tz && tz != local_tz)
     {
       tz = set_tz (tz);
       if (!tz)
         return 0;
     }
-#endif
+# endif
 
   size_t len;
-# if USE_C_LOCALE && (HAVE_STRFTIME_L || HAVE_STRFTIME_LZ)
+# if USE_C_LOCALE && HAVE_STRFTIME_L
   locale_t locale = c_locale ();
   if (!locale)
     return 0; /* errno is set here */
@@ -1467,7 +1475,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
           }
           break;
 
-#ifndef _LIBC
+#if !defined _LIBC && !(USE_C_LOCALE && !HAVE_STRFTIME_L)
         underlying_strftime:
           {
             char ubuf[1024]; /* enough for any single format in practice */
-- 
2.34.1

>From de1ab2cd57af884c6b2389b7a24640c1f24e61ec Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 18 Jun 2024 14:58:30 +0200
Subject: [PATCH 2/3] nstrftime: Fix crash on NetBSD 10.0.

* lib/strftime.c (utc_timezone_cache): New variable.
(utc_timezone): New function.
(underlying_strftime): Use it when tz is NULL.
---
 ChangeLog      |  7 +++++++
 lib/strftime.c | 28 ++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index cb44449076..0c39edd886 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2024-06-18  Bruno Haible  <br...@clisp.org>
+
+	nstrftime: Fix crash on NetBSD 10.0.
+	* lib/strftime.c (utc_timezone_cache): New variable.
+	(utc_timezone): New function.
+	(underlying_strftime): Use it when tz is NULL.
+
 2024-06-18  Bruno Haible  <br...@clisp.org>
 
 	c-nstrftime: Fix warning on platforms without strftime_l.
diff --git a/lib/strftime.c b/lib/strftime.c
index a757b4f313..ffc1670f23 100644
--- a/lib/strftime.c
+++ b/lib/strftime.c
@@ -403,6 +403,25 @@ c_locale (void)
 
 #endif
 
+#if HAVE_NATIVE_TIME_Z
+
+/* Cache for the UTC time zone object.
+   Marked volatile so that different threads see the same value
+   (avoids locking).  */
+static volatile timezone_t utc_timezone_cache;
+
+/* Return the UTC time zone object, or (timezone_t) 0 with errno set
+   if it cannot be created.  */
+static timezone_t
+utc_timezone (void)
+{
+  if (!utc_timezone_cache)
+    utc_timezone_cache = tzalloc ("UTC");
+  return utc_timezone_cache;
+}
+
+#endif
+
 
 #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
 
@@ -877,6 +896,15 @@ underlying_strftime (timezone_t tz, char *ubuf, size_t ubufsize,
   *u++ = format_char;
   *u = '\0';
 
+# if HAVE_NATIVE_TIME_Z
+  if (!tz)
+    {
+      tz = utc_timezone ();
+      if (!tz)
+        return 0; /* errno is set here */
+    }
+# endif
+
 # if !HAVE_NATIVE_TIME_Z
   if (tz && tz != local_tz)
     {
-- 
2.34.1

Reply via email to