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