This recent bug relating to ctime suggests that the ctime module is more trouble than it's worth now. I propose that we remove it. Proposed patch attached (but not installed).
From 7261860a4ce805fc91ce49a2a9658fd4128ec18d Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Sat, 3 Feb 2024 13:41:06 -0800
Subject: [PROPOSED] ctime: remove module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The ctime module is a maintenance hassle and ctime is a recipe for
undefined behavior on today's platforms.  I don't know of any
package using it, and at this point any such package should be
fixed to use strftime or sprintf anyway.
* MODULES.html.sh (func_all_modules): Remove ctime.
* NEWS: Mention this.
* lib/ctime.c, m4/ctime.m4, modules/ctime: Remove.
* doc/posix-functions/asctime.texi (asctime):
* doc/posix-functions/asctime_r.texi (asctime_r):
* doc/posix-functions/ctime_r.texi (ctime_r):
Refer to ctime’s buffer overflow doc.
* doc/posix-functions/ctime.texi (ctime): Remove mention of module.
Document why we got into this mess.
* doc/posix-functions/ctime_r.texi (ctime_r): Remove now-incorrect
commentary that I think is about old SunOS ctime_r.
* lib/time.in.h (ctime):
* m4/time_h.m4 (gl_TIME_H_REQUIRE_DEFAULTS, gl_TIME_H_DEFAULTS):
* modules/time-h (Depends-on):
* tests/test-time-h-c++.cc:
Remove everything concerning the ctime module.
---
 ChangeLog                          | 22 +++++++++++
 MODULES.html.sh                    |  1 -
 NEWS                               |  3 ++
 doc/posix-functions/asctime.texi   |  4 +-
 doc/posix-functions/asctime_r.texi |  5 ++-
 doc/posix-functions/ctime.texi     | 36 ++++++++++++------
 doc/posix-functions/ctime_r.texi   | 15 ++------
 lib/ctime.c                        | 59 ------------------------------
 lib/time.in.h                      | 23 ------------
 m4/ctime.m4                        | 14 -------
 m4/time_h.m4                       |  2 -
 modules/ctime                      | 32 ----------------
 modules/time-h                     |  2 -
 tests/test-time-h-c++.cc           |  4 --
 14 files changed, 59 insertions(+), 163 deletions(-)
 delete mode 100644 lib/ctime.c
 delete mode 100644 m4/ctime.m4
 delete mode 100644 modules/ctime

diff --git a/ChangeLog b/ChangeLog
index 84f91b4fc9..663e8a150c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,27 @@
 2024-02-03  Paul Eggert  <egg...@cs.ucla.edu>
 
+	ctime: remove module
+	The ctime module is a maintenance hassle and ctime is a recipe for
+	undefined behavior on today's platforms.  I don't know of any
+	package using it, and at this point any such package should be
+	fixed to use strftime or sprintf anyway.
+	* MODULES.html.sh (func_all_modules): Remove ctime.
+	* NEWS: Mention this.
+	* lib/ctime.c, m4/ctime.m4, modules/ctime: Remove.
+	* doc/posix-functions/asctime.texi (asctime):
+	* doc/posix-functions/asctime_r.texi (asctime_r):
+	* doc/posix-functions/ctime_r.texi (ctime_r):
+	Refer to ctime’s buffer overflow doc.
+	* doc/posix-functions/ctime.texi (ctime): Remove mention of module.
+	Document why we got into this mess.
+	* doc/posix-functions/ctime_r.texi (ctime_r): Remove now-incorrect
+	commentary that I think is about old SunOS ctime_r.
+	* lib/time.in.h (ctime):
+	* m4/time_h.m4 (gl_TIME_H_REQUIRE_DEFAULTS, gl_TIME_H_DEFAULTS):
+	* modules/time-h (Depends-on):
+	* tests/test-time-h-c++.cc:
+	Remove everything concerning the ctime module.
+
 	ctime: fix false positive
 	Problem reported by Bjarni Ingi Gislason in:
 	https://lists.gnu.org/r/bug-gnulib/2024-02/msg00006.html
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 76a6291303..b42689a9f9 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -1679,7 +1679,6 @@ func_all_modules ()
 
   func_begin_table
   func_module atexit
-  func_module ctime
   func_module localtime
   func_module strtod
   func_module strerror
diff --git a/NEWS b/NEWS
index a7c22ecb33..fe140c3cb2 100644
--- a/NEWS
+++ b/NEWS
@@ -74,6 +74,9 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2024-02-03  ctime           Removed.  Portable code should use strftime
+                            (or even sprintf) instead.
+
 2023-09-03  same-inode      SAME_INODE, ST_BLKSIZE and ST_NBLOCKS args
             stat-size       must be addressable lvalues.
 
diff --git a/doc/posix-functions/asctime.texi b/doc/posix-functions/asctime.texi
index c212a76118..7b19deaa22 100644
--- a/doc/posix-functions/asctime.texi
+++ b/doc/posix-functions/asctime.texi
@@ -18,5 +18,7 @@ Likewise, POSIX says this function is obsolescent and it is planned to be
 removed in a future version.
 Portable applications can use @code{strftime} (or even @code{sprintf}) instead.
 @item
-This function may overflow its internal buffer if an invalid year is passed.
+This function may overflow its internal buffer if its argument
+specifies a time before the year 1000 or after the year 9999.
+@xref{ctime}.
 @end itemize
diff --git a/doc/posix-functions/asctime_r.texi b/doc/posix-functions/asctime_r.texi
index 3b19860363..ae527bd197 100644
--- a/doc/posix-functions/asctime_r.texi
+++ b/doc/posix-functions/asctime_r.texi
@@ -25,6 +25,7 @@ POSIX says this function is obsolescent and it is planned to be
 removed in a future version.
 Use the function @code{strftime} (or even @code{sprintf}) instead.
 @item
-This function may put more than 26 bytes into the argument buffer if an
-invalid year is passed.
+This function may overflow its output buffer if its argument
+specifies a time before the year 1000 or after the year 9999.
+@xref{ctime}.
 @end itemize
diff --git a/doc/posix-functions/ctime.texi b/doc/posix-functions/ctime.texi
index bab929c08c..421f985261 100644
--- a/doc/posix-functions/ctime.texi
+++ b/doc/posix-functions/ctime.texi
@@ -4,15 +4,6 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/ctime.html}
 
-Gnulib module: ctime
-
-Portability problems fixed by Gnulib:
-@itemize
-@item
-On native Windows platforms (mingw, MSVC), this function works incorrectly
-when the environment variable @code{TZ} has been set by Cygwin.
-@end itemize
-
 Portability problems not fixed by Gnulib:
 @itemize
 @item
@@ -22,7 +13,27 @@ removed in a future version.
 Portable applications can use @code{localtime_r} and @code{strftime}
 (or even @code{sprintf}) instead.
 @item
-This function may overflow its internal buffer if an invalid year is passed.
+This function may overflow its internal buffer if its argument
+specifies a time before the year 1000 or after the year 9999.
+
+Here is some history about this.
+This function was safe to use decades ago when @code{time_t} was narrow
+and there was no @code{strftime} or internationalization.
+Code could call @code{ctime} and then select the parts needed.
+For example, in Unix 7th Edition @file{/usr/src/cmd/ls.c} (1979):
+
+@example
+cp = ctime(&p->lmtime);
+if(p->lmtime < year)
+        printf(" %-7.7s %-4.4s ", cp+4, cp+20); else
+        printf(" %-12.12s ", cp+4);
+@end example
+
+This has well-defined behavior if @code{time_t} is only 32 bits
+and so was OK for circa 1979 platforms.
+However, today's platforms have a @code{time_t} so wide
+that the year might not be in the range [1000, 9999],
+and ISO C says that in this case the behavior of @code{ctime} is undefined.
 @item
 The @code{ctime} function need not be reentrant, and consequently is
 not required to be thread safe.  Implementations of @code{ctime}
@@ -31,7 +42,10 @@ call @code{ctime} at roughly the same time, you might end up with the
 wrong date in one of the threads, or some undefined string.  There is
 a reentrant interface @code{ctime_r}.
 @item
-Native Windows platforms (mingw, MSVC) support only a subset of time
+On native Windows platforms (mingw, MSVC), this function works incorrectly
+when the environment variable @code{TZ} has been set by Cygwin.
+@item
+Native Windows platforms support only a subset of time
 zones supported by GNU or specified by POSIX@.  @xref{tzset}.
 @end itemize
 
diff --git a/doc/posix-functions/ctime_r.texi b/doc/posix-functions/ctime_r.texi
index 8b5dd136cc..1ecf59bbd4 100644
--- a/doc/posix-functions/ctime_r.texi
+++ b/doc/posix-functions/ctime_r.texi
@@ -26,19 +26,10 @@ removed in a future version.
 Use the functions @code{localtime_r} and @code{strftime}
 (or even @code{sprintf}) instead.
 @item
-This function may put more than 26 bytes into the argument buffer if an
-invalid year is passed.
+This function may overflow its output buffer if its argument
+specifies a time before the year 1000 or after the year 9999.
+@xref{ctime}.
 @end itemize
 
-@code{ctime_r} takes a pre-allocated buffer and length of the buffer,
-and returns @code{NULL} on errors.
-The input buffer should be at least 26 bytes in size.  The output
-string is locale-independent.  However, years can have more than 4
-digits if @code{time_t} is sufficiently wide, so the length of the
-required output buffer is not easy to determine.  Increasing the
-buffer size when @code{ctime_r} returns @code{NULL} is not necessarily
-sufficient.  The @code{NULL} return value could mean some other error
-condition, which will not go away by increasing the buffer size.
-
 A more flexible function is @code{strftime}.  However, note that it is
 locale dependent.
diff --git a/lib/ctime.c b/lib/ctime.c
deleted file mode 100644
index a11adc5c74..0000000000
--- a/lib/ctime.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Work around platform bugs in ctime.
-   Copyright (C) 2017-2024 Free Software Foundation, Inc.
-
-   This file is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of the
-   License, or (at your option) any later version.
-
-   This file is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
-
-#include <config.h>
-
-/* Specification.  */
-#include <time.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#undef ctime
-
-char *
-rpl_ctime (const time_t *tp)
-{
-#if defined _WIN32 && ! defined __CYGWIN__
-  /* Rectify the value of the environment variable TZ.
-     There are four possible kinds of such values:
-       - Traditional US time zone names, e.g. "PST8PDT".  Syntax: see
-         <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/tzset>
-       - Time zone names based on geography, that contain one or more
-         slashes, e.g. "Europe/Moscow".
-       - Time zone names based on geography, without slashes, e.g.
-         "Singapore".
-       - Time zone names that contain explicit DST rules.  Syntax: see
-         <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03>
-     The Microsoft CRT understands only the first kind.  It produces incorrect
-     results if the value of TZ is of the other kinds.
-     But in a Cygwin environment, /etc/profile.d/tzset.sh sets TZ to a value
-     of the second kind for most geographies, or of the first kind in a few
-     other geographies.  If it is of the second kind, neutralize it.  For the
-     Microsoft CRT, an absent or empty TZ means the time zone that the user
-     has set in the Windows Control Panel.
-     If the value of TZ is of the third or fourth kind -- Cygwin programs
-     understand these syntaxes as well --, it does not matter whether we
-     neutralize it or not, since these values occur only when a Cygwin user
-     has set TZ explicitly; this case is 1. rare and 2. under the user's
-     responsibility.  */
-  const char *tz = getenv ("TZ");
-  if (tz != NULL && strchr (tz, '/') != NULL)
-    _putenv ("TZ=");
-#endif
-
-  return ctime (tp);
-}
diff --git a/lib/time.in.h b/lib/time.in.h
index df99c8abca..875abbe5d7 100644
--- a/lib/time.in.h
+++ b/lib/time.in.h
@@ -418,29 +418,6 @@ _GL_WARN_ON_USE (strptime, "strptime is unportable - "
 #  endif
 # endif
 
-/* Convert *TP to a date and time string.  See
-   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/ctime.html>.  */
-# if @GNULIB_CTIME@
-#  if @REPLACE_CTIME@
-#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-#    define ctime rpl_ctime
-#   endif
-#   ifndef __cplusplus
-_GL_ATTRIBUTE_DEPRECATED
-#   endif
-_GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp)
-                                 _GL_ARG_NONNULL ((1)));
-_GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp));
-#  else
-_GL_CXXALIAS_SYS (ctime, char *, (time_t const *__tp));
-#  endif
-#  if __GLIBC__ >= 2
-_GL_CXXALIASWARN (ctime);
-#  endif
-# elif defined GNULIB_POSIXCHECK
-/* No need to warn about portability, as a more serious warning is below.  */
-# endif
-
 /* Convert *TP to a date and time string.  See
    <https://pubs.opengroup.org/onlinepubs/9699919799/functions/strftime.html>.  */
 # if @GNULIB_STRFTIME@
diff --git a/m4/ctime.m4 b/m4/ctime.m4
deleted file mode 100644
index b6d70868a8..0000000000
--- a/m4/ctime.m4
+++ /dev/null
@@ -1,14 +0,0 @@
-# ctime.m4 serial 4
-dnl Copyright (C) 2017-2024 Free Software Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-AC_DEFUN([gl_FUNC_CTIME],
-[
-  AC_REQUIRE([gl_TIME_H_DEFAULTS])
-  AC_REQUIRE([AC_CANONICAL_HOST])
-  case "$host_os" in
-    mingw* | windows*) REPLACE_CTIME=1 ;;
-  esac
-])
diff --git a/m4/time_h.m4 b/m4/time_h.m4
index 32fade0f40..e1a0fa8be8 100644
--- a/m4/time_h.m4
+++ b/m4/time_h.m4
@@ -134,7 +134,6 @@ AC_DEFUN([gl_TIME_MODULE_INDICATOR],
 AC_DEFUN([gl_TIME_H_REQUIRE_DEFAULTS],
 [
   m4_defun(GL_MODULE_INDICATOR_PREFIX[_TIME_H_MODULE_INDICATOR_DEFAULTS], [
-    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CTIME])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKTIME])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALTIME])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NANOSLEEP])
@@ -165,7 +164,6 @@ AC_DEFUN([gl_TIME_H_DEFAULTS],
   HAVE_TIMESPEC_GETRES=1;                AC_SUBST([HAVE_TIMESPEC_GETRES])
   dnl Even GNU libc does not have timezone_t yet.
   HAVE_TIMEZONE_T=0;                     AC_SUBST([HAVE_TIMEZONE_T])
-  REPLACE_CTIME=0;                       AC_SUBST([REPLACE_CTIME])
   REPLACE_GMTIME=0;                      AC_SUBST([REPLACE_GMTIME])
   REPLACE_LOCALTIME=0;                   AC_SUBST([REPLACE_LOCALTIME])
   REPLACE_LOCALTIME_R=0;                 AC_SUBST([REPLACE_LOCALTIME_R])
diff --git a/modules/ctime b/modules/ctime
deleted file mode 100644
index 11de22f2d9..0000000000
--- a/modules/ctime
+++ /dev/null
@@ -1,32 +0,0 @@
-Description:
-ctime() function: convert time to string.
-
-Notice:
-The function 'ctime' is deprecated.
-New code should use 'localtime_r' and 'strftime' (or even 'sprintf') instead.
-
-Files:
-lib/ctime.c
-m4/ctime.m4
-
-Depends-on:
-time-h
-
-configure.ac:
-gl_FUNC_CTIME
-gl_CONDITIONAL([GL_COND_OBJ_CTIME], [test $REPLACE_CTIME = 1])
-gl_TIME_MODULE_INDICATOR([ctime])
-
-Makefile.am:
-if GL_COND_OBJ_CTIME
-lib_SOURCES += ctime.c
-endif
-
-Include:
-<time.h>
-
-License:
-LGPLv2+
-
-Maintainer:
-all
diff --git a/modules/time-h b/modules/time-h
index 3b07845b56..f4aa264e6f 100644
--- a/modules/time-h
+++ b/modules/time-h
@@ -32,7 +32,6 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
 	      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
 	      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
 	      -e 's|@''NEXT_TIME_H''@|$(NEXT_TIME_H)|g' \
-	      -e 's/@''GNULIB_CTIME''@/$(GNULIB_CTIME)/g' \
 	      -e 's/@''GNULIB_LOCALTIME''@/$(GNULIB_LOCALTIME)/g' \
 	      -e 's/@''GNULIB_MKTIME''@/$(GNULIB_MKTIME)/g' \
 	      -e 's/@''GNULIB_NANOSLEEP''@/$(GNULIB_NANOSLEEP)/g' \
@@ -53,7 +52,6 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
 	      -e 's|@''HAVE_TIMESPEC_GET''@|$(HAVE_TIMESPEC_GET)|g' \
 	      -e 's|@''HAVE_TIMESPEC_GETRES''@|$(HAVE_TIMESPEC_GETRES)|g' \
 	      -e 's|@''HAVE_TIMEZONE_T''@|$(HAVE_TIMEZONE_T)|g' \
-	      -e 's|@''REPLACE_CTIME''@|$(REPLACE_CTIME)|g' \
 	      -e 's|@''REPLACE_GMTIME''@|$(REPLACE_GMTIME)|g' \
 	      -e 's|@''REPLACE_LOCALTIME''@|$(REPLACE_LOCALTIME)|g' \
 	      -e 's|@''REPLACE_LOCALTIME_R''@|$(REPLACE_LOCALTIME_R)|g' \
diff --git a/tests/test-time-h-c++.cc b/tests/test-time-h-c++.cc
index 2f0b6e9645..d77c8cd829 100644
--- a/tests/test-time-h-c++.cc
+++ b/tests/test-time-h-c++.cc
@@ -66,10 +66,6 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::strptime, char *,
                  (char const *, char const *, struct tm *));
 #endif
 
-#if GNULIB_TEST_CTIME
-SIGNATURE_CHECK (GNULIB_NAMESPACE::ctime, char *, (time_t const *));
-#endif
-
 #if GNULIB_TEST_STRFTIME
 SIGNATURE_CHECK (GNULIB_NAMESPACE::strftime, size_t,
                  (char *, size_t, const char *, const struct tm *));
-- 
2.43.0

Reply via email to