Bruno Haible <[email protected]> writes:
> I disagree with the direction of this patch. Your previous commits from
> 2025-10-10 were based on the assumption that glibc 2.42 has a bug.
> But now that POSIX has relaxed the requirements [4], it's not a bug any
> more: all three behaviours are POSIX compliant. It's merely a portability
> problem.
>
> Since, additionally, this portability problem is not frequently encountered,
> and glibc 2.43 fixes only half of the "bug", I would suggest that
> - the modules 'getdelim', 'getline' guarantee only what POSIX guarantees,
> - there is no module 'getdelim-gnu'.
Oh right. I was focusing on making the behavior consistent, but I think
agree with you now since the module is not named 'getdelim-gnu'.
How about this patch? It mostly reverts my earlier changes. However, I
kept the ./configure test changes that moved to this idiom:
int result = 0;
if (/* Some check that fails. */)
result |= 2;
if (/* Some other check that fails. */)
result |= 4;
Since I find it very helpful when trying to understand a function is
replaced and what issues a platform has.
> So, getdelim.m4 should be changed so that all three implementations are
> accepted:
> - the one from glibc 2.42, musl, OpenBSD, AIX,
> - the one from macOS, FreeBSD, Solaris,
> - the one from glibc 2.43,
> and none of these system functions gets overridden.
I tested this patch on glibc 2.42 and glibc 2.43 the function does not
get replaced.
I also tested it on FreeBSD 15.0, Solaris 11.4, and OpenBSD 7.8 and
confirm they do not get replaced there too. They also all pass 'make
check'. I didn't bother testing MacOS since we replace getdelim
unconditionally because of an uninitialized read.
Collin
>From 7f12b242cbf9a1da87a054b6804e870beb62efcb Mon Sep 17 00:00:00 2001
Message-ID: <7f12b242cbf9a1da87a054b6804e870beb62efcb.1769146489.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Thu, 22 Jan 2026 21:15:29 -0800
Subject: [PATCH] getdelim, getline: Don't replace these functions on glibc.
This largely reverts my 2025-10-10 commits since POSIX has relaxed the
requirements to make glibc's behavior compliant. See:
<https://www.austingroupbugs.net/bug_view_page.php?bug_id=1953>.
* doc/posix-functions/getdelim.texi: Move the text about glibc 2.42
to under "Portability problems not fixed by Gnulib".
* doc/posix-functions/getline.texi: Likewise.
* m4/getdelim.m4 (gl_FUNC_GETDELIM): Remove the test on an empty file.
* m4/getline.m4 (gl_FUNC_GETLINE): Likewise.
* tests/test-getdelim.c (main): Remove the test case.
* tests/test-getline.c (main): Likewise.
---
ChangeLog | 12 +++++++++
doc/posix-functions/getdelim.texi | 10 +++----
doc/posix-functions/getline.texi | 10 +++----
m4/getdelim.m4 | 43 ++++++++++++++-----------------
m4/getline.m4 | 43 ++++++++++++++-----------------
tests/test-getdelim.c | 4 ---
tests/test-getline.c | 4 ---
7 files changed, 60 insertions(+), 66 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 2444097d60..29bd6c6200 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
2026-01-22 Collin Funk <[email protected]>
+ getdelim, getline: Don't replace these functions on glibc.
+ This largely reverts my 2025-10-10 commits since POSIX has relaxed the
+ requirements to make glibc's behavior compliant. See:
+ <https://www.austingroupbugs.net/bug_view_page.php?bug_id=1953>.
+ * doc/posix-functions/getdelim.texi: Move the text about glibc 2.42
+ to under "Portability problems not fixed by Gnulib".
+ * doc/posix-functions/getline.texi: Likewise.
+ * m4/getdelim.m4 (gl_FUNC_GETDELIM): Remove the test on an empty file.
+ * m4/getline.m4 (gl_FUNC_GETLINE): Likewise.
+ * tests/test-getdelim.c (main): Remove the test case.
+ * tests/test-getline.c (main): Likewise.
+
doc: document a portability issue with macOS getrusage.
* doc/posix-functions/getrusage.texi: Document that the 'ru_maxrss'
field of 'struct rusage' is measured in bytes on macOS.
diff --git a/doc/posix-functions/getdelim.texi b/doc/posix-functions/getdelim.texi
index 5801452212..abccdd0496 100644
--- a/doc/posix-functions/getdelim.texi
+++ b/doc/posix-functions/getdelim.texi
@@ -19,11 +19,6 @@ @node getdelim
This function crashes when passed a pointer to a NULL buffer together with a
pointer to a non-zero buffer size on some platforms:
FreeBSD 8.0.
-@item
-This function does not NUL terminate the buffer when the first
-character read is EOF on some platforms:
-@c https://sourceware.org/PR28038
-glibc 2.42.
@end itemize
Portability problems not fixed by Gnulib:
@@ -31,4 +26,9 @@ @node getdelim
@item
This function has quadratic running time for long lines on some platforms:
uClibc 0.9.31.
+@item
+This function does not NUL terminate the buffer when the first
+character read is EOF on some platforms:
+@c https://sourceware.org/PR28038
+glibc 2.42.
@end itemize
diff --git a/doc/posix-functions/getline.texi b/doc/posix-functions/getline.texi
index cfef3c8867..48281a9168 100644
--- a/doc/posix-functions/getline.texi
+++ b/doc/posix-functions/getline.texi
@@ -22,11 +22,6 @@ @node getline
This function crashes when passed a pointer to a NULL buffer together with a
pointer to a non-zero buffer size on some platforms:
FreeBSD 8.0.
-@item
-This function does not NUL terminate the buffer when the first
-character read is EOF on some platforms:
-@c https://sourceware.org/PR28038
-glibc 2.42.
@end itemize
Portability problems not fixed by Gnulib:
@@ -34,4 +29,9 @@ @node getline
@item
This function has quadratic running time for long lines on some platforms:
uClibc 0.9.31.
+@item
+This function does not NUL terminate the buffer when the first
+character read is EOF on some platforms:
+@c https://sourceware.org/PR28038
+glibc 2.42.
@end itemize
diff --git a/m4/getdelim.m4 b/m4/getdelim.m4
index 8b6eff47aa..736c4e8b2e 100644
--- a/m4/getdelim.m4
+++ b/m4/getdelim.m4
@@ -1,5 +1,5 @@
# getdelim.m4
-# serial 21
+# serial 22
dnl Copyright (C) 2005-2007, 2009-2026 Free Software Foundation, Inc.
dnl
@@ -37,7 +37,6 @@ AC_DEFUN([gl_FUNC_GETDELIM]
gl_cv_func_working_getdelim=no ;;
*)
echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data
- touch conftest.empty
AC_RUN_IFELSE([AC_LANG_SOURCE([[
# include <stdio.h>
# include <stdlib.h>
@@ -68,36 +67,32 @@ AC_DEFUN([gl_FUNC_GETDELIM]
free (line);
}
fclose (in);
- {
- /* Test that reading EOF as the first character sets the first byte
- in the buffer to NUL. This fails on glibc 2.42 and earlier. */
- in = fopen ("./conftest.empty", "r");
- if (!in)
- return 1;
- char *line = malloc (1);
- line[0] = 'A';
- size_t siz = 1;
- if (getdelim (&line, &siz, '\n', in) != -1 || line[0] != '\0')
- result |= 8;
- free (line);
- }
- fclose (in);
return result;
}
]])],
[gl_cv_func_working_getdelim=yes],
[gl_cv_func_working_getdelim=no],
- [case "$host_os" in
- # Guess yes on musl.
- *-musl* | midipix*) gl_cv_func_working_getdelim="guessing yes" ;;
- # Guess no on glibc.
- *-gnu* | gnu*) gl_cv_func_working_getdelim="guessing no" ;;
- *) gl_cv_func_working_getdelim="$gl_cross_guess_normal" ;;
- esac
+ [dnl We're cross compiling.
+ dnl Guess it works on glibc2 systems and musl systems.
+ AC_EGREP_CPP([Lucky GNU user],
+ [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ >= 2) && !defined __UCLIBC__
+ Lucky GNU user
+ #endif
+#endif
+ ],
+ [gl_cv_func_working_getdelim="guessing yes"],
+ [case "$host_os" in
+ *-musl* | midipix*) gl_cv_func_working_getdelim="guessing yes" ;;
+ *) gl_cv_func_working_getdelim="$gl_cross_guess_normal" ;;
+ esac
+ ])
])
;;
esac
- rm -f conftest.data conftest.empty
+ rm -f conftest.data
])
case "$gl_cv_func_working_getdelim" in
*yes) ;;
diff --git a/m4/getline.m4 b/m4/getline.m4
index ed32fa10bf..25539dc20c 100644
--- a/m4/getline.m4
+++ b/m4/getline.m4
@@ -1,5 +1,5 @@
# getline.m4
-# serial 35
+# serial 36
dnl Copyright (C) 1998-2003, 2005-2007, 2009-2026 Free Software Foundation,
dnl Inc.
@@ -31,7 +31,6 @@ AC_DEFUN([gl_FUNC_GETLINE]
AC_CACHE_CHECK([for working getline function],
[am_cv_func_working_getline],
[echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data
- touch conftest.empty
AC_RUN_IFELSE([AC_LANG_SOURCE([[
# include <stdio.h>
# include <stdlib.h>
@@ -62,34 +61,30 @@ AC_DEFUN([gl_FUNC_GETLINE]
free (line);
}
fclose (in);
- {
- /* Test that reading EOF as the first character sets the first byte
- in the buffer to NUL. This fails on glibc 2.42 and earlier. */
- in = fopen ("./conftest.empty", "r");
- if (!in)
- return 1;
- char *line = malloc (1);
- line[0] = 'A';
- size_t siz = 1;
- if (getline (&line, &siz, in) != -1 || line[0] != '\0')
- result |= 8;
- free (line);
- }
- fclose (in);
return result;
}
]])],
[am_cv_func_working_getline=yes],
[am_cv_func_working_getline=no],
- [case "$host_os" in
- # Guess yes on musl.
- *-musl* | midipix*) am_cv_func_working_getline="guessing yes" ;;
- # Guess no on glibc.
- *-gnu* | gnu*) am_cv_func_working_getline="guessing no" ;;
- *) am_cv_func_working_getline="$gl_cross_guess_normal" ;;
- esac
+ [dnl We're cross compiling.
+ dnl Guess it works on glibc2 systems and musl systems.
+ AC_EGREP_CPP([Lucky GNU user],
+ [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ >= 2) && !defined __UCLIBC__
+ Lucky GNU user
+ #endif
+#endif
+ ],
+ [am_cv_func_working_getline="guessing yes"],
+ [case "$host_os" in
+ *-musl* | midipix*) am_cv_func_working_getline="guessing yes" ;;
+ *) am_cv_func_working_getline="$gl_cross_guess_normal" ;;
+ esac
+ ])
])
- rm -f conftest.data conftest.empty
+ rm -f conftest.data
])
else
am_cv_func_working_getline=no
diff --git a/tests/test-getdelim.c b/tests/test-getdelim.c
index d472285c5e..25b53ee1d5 100644
--- a/tests/test-getdelim.c
+++ b/tests/test-getdelim.c
@@ -84,11 +84,7 @@ main (void)
ASSERT (memcmp (line, "d\0f", 4) == 0);
ASSERT (3 < len);
- /* Test that reading an EOF will terminate the buffer with a NUL
- character. */
result = getdelim (&line, &len, 'n', f);
- ASSERT (0 < len);
- ASSERT (line[0] == '\0');
ASSERT (result == -1);
free (line);
diff --git a/tests/test-getline.c b/tests/test-getline.c
index 8572611d65..eda571eeed 100644
--- a/tests/test-getline.c
+++ b/tests/test-getline.c
@@ -84,11 +84,7 @@ main (void)
ASSERT (memcmp (line, "d\0f", 4) == 0);
ASSERT (3 < len);
- /* Test that reading an EOF will terminate the buffer with a NUL
- character. */
result = getline (&line, &len, f);
- ASSERT (0 < len);
- ASSERT (line[0] == '\0');
ASSERT (result == -1);
free (line);
--
2.52.0