Extend getline testing (RHEL-115819)

Resolves: RHEL-115819
This commit is contained in:
Frédéric Bérat 2025-09-23 09:10:42 +02:00
parent e95aa14bd2
commit 7ef0dba232
2 changed files with 1008 additions and 0 deletions

378
glibc-RHEL-115819-1.patch Normal file
View File

@ -0,0 +1,378 @@
commit a7fe3e805d2ee128ac5f43b2a24201726d41cc04
Author: Carlos O'Donell <carlos@redhat.com>
Date: Wed Jun 19 11:48:05 2024 -0400
Fix conditionals on mtrace-based tests (bug 31892)
The conditionals for several mtrace-based tests in catgets, elf, libio,
malloc, misc, nptl, posix, and stdio-common were incorrect leading to
test failures when bootstrapping glibc without perl.
The correct conditional for mtrace-based tests requires three checks:
first checking for run-built-tests, then build-shared, and lastly that
PERL is not equal to "no" (missing perl).
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
stdio-common/Makefile
(fixup context)
diff --git a/catgets/Makefile b/catgets/Makefile
index 24b4560d5fefcd08..40c65eac950ee662 100644
--- a/catgets/Makefile
+++ b/catgets/Makefile
@@ -43,8 +43,12 @@ tests-special += \
$(objpfx)test-gencat.out \
$(objpfx)test1.cat \
$(objpfx)test2.cat \
- $(objpfx)tst-catgets-mem.out
# tests-special
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+tests-special += $(objpfx)tst-catgets-mem.out
+endif
+endif
endif
gencat-modules = xmalloc
@@ -68,9 +72,17 @@ generated += \
test1.h \
test2.cat \
test2.h \
+ # generated
+ifeq ($(run-built-tests),yes)
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+generated += \
tst-catgets-mem.out \
tst-catgets.mtrace \
# generated
+endif
+endif
+endif
generated-dirs += \
de \
diff --git a/elf/Makefile b/elf/Makefile
index fb35102f827b96cd..fc721b4f6379cb07 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -647,13 +647,19 @@ $(objpfx)tst-valgrind-smoke.out: tst-valgrind-smoke.sh $(objpfx)ld.so $(objpfx)v
tests += $(tests-execstack-$(have-z-execstack))
ifeq ($(run-built-tests),yes)
tests-special += \
- $(objpfx)noload-mem.out \
$(objpfx)tst-ldconfig-X.out \
$(objpfx)tst-ldconfig-p.out \
$(objpfx)tst-ldconfig-soname.out \
- $(objpfx)tst-leaks1-mem.out \
$(objpfx)tst-rtld-help.out \
# tests-special
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+tests-special += \
+ $(objpfx)noload-mem.out \
+ $(objpfx)tst-leaks1-mem.out \
+ # tests-special
+endif
+endif
endif
tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
diff --git a/libio/Makefile b/libio/Makefile
index b189455bb9b8fd1b..03ffb659e8c0f347 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -264,15 +264,28 @@ tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace \
tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
-generated += test-fmemopen.mtrace test-fmemopen.check
-generated += tst-fdopen-seek-failure.mtrace tst-fdopen-seek-failure.check
-generated += tst-fopenloc.mtrace tst-fopenloc.check
-generated += tst-bz22415.mtrace tst-bz22415.check
-
aux := fileops genops stdfiles stdio strops
+ifeq ($(run-built-tests),yes)
+ifeq ($(build-shared),yes)
+ifneq ($(PERL),no)
+generated += \
+ test-fmemopen.check \
+ test-fmemopen.mtrace \
+ tst-bz22415.check \
+ tst-bz22415.mtrace \
+ tst-bz24228.check \
+ tst-bz24228.mtrace \
+ tst-fdopen-seek-failure.check \
+ tst-fdopen-seek-failure.mtrace \
+ tst-fopenloc.check \
+ tst-fopenloc.mtrace \
+ # generated
+endif
+endif
+endif
+
ifeq ($(build-shared),yes)
-generated += tst-bz24228.mtrace tst-bz24228.check
aux += oldfileops oldstdfiles
tests += \
tst-stderr-compat \
@@ -289,16 +302,23 @@ shared-only-routines = oldiofopen oldiofdopen oldiofclose oldfileops \
ifeq ($(run-built-tests),yes)
tests-special += \
- $(objpfx)test-fmemopen-mem.out \
$(objpfx)test-freopen.out \
- $(objpfx)tst-bz22415-mem.out \
- $(objpfx)tst-fdopen-seek-failure-mem.out \
# tests-special
ifeq (yes,$(build-shared))
# Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
# library is enabled since they depend on tst-fopenloc.out.
-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
- $(objpfx)tst-bz24228-mem.out
+tests-special += $(objpfx)tst-fopenloc-cmp.out
+ifeq ($(build-shared),yes)
+ifneq ($(PERL),no)
+tests-special += \
+ $(objpfx)test-fmemopen-mem.out \
+ $(objpfx)tst-bz22415-mem.out \
+ $(objpfx)tst-bz24228-mem.out \
+ $(objpfx)tst-fdopen-seek-failure-mem.out \
+ $(objpfx)tst-fopenloc-mem.out \
+ # tests-special
+endif
+endif
endif
tests += \
diff --git a/misc/Makefile b/misc/Makefile
index 6aa74d332b40ca94..a932b1aab461bc7d 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -214,12 +214,18 @@ routines_no_fortify += \
syslog \
# routines_no_fortify
+ifeq ($(run-built-tests),yes)
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
generated += \
tst-allocate_once-mem.out \
tst-allocate_once.mtrace \
tst-error1-mem.out \
tst-error1.mtrace \
# generated
+endif
+endif
+endif
aux := init-misc
install-lib := libg.a
@@ -293,8 +299,14 @@ xtests += \
# xtests
ifeq ($(run-built-tests),yes)
-tests-special += $(objpfx)tst-error1-mem.out \
- $(objpfx)tst-allocate_once-mem.out
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+tests-special += \
+ $(objpfx)tst-allocate_once-mem.out \
+ $(objpfx)tst-error1-mem.out \
+ # tests-special
+endif
+endif
endif
tests-container := \
diff --git a/nptl/Makefile b/nptl/Makefile
index c9d9079cdb8a5643..34c80f6f38261669 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -558,10 +558,12 @@ xtests-static += tst-setuid1-static
ifeq ($(run-built-tests),yes)
tests-special += \
$(objpfx)tst-oddstacklimit.out \
- $(objpfx)tst-stack3-mem.out \
# tests-special
ifeq ($(build-shared),yes)
tests-special += $(objpfx)tst-tls6.out
+ifneq ($(PERL),no)
+tests-special += $(objpfx)tst-stack3-mem.out
+endif
endif
endif
@@ -619,10 +621,17 @@ tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace \
$(objpfx)tst-stack3-mem.out: $(objpfx)tst-stack3.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@; \
$(evaluate-test)
+
+ifeq ($(run-built-tests),yes)
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
generated += \
tst-stack3-mem.out \
tst-stack3.mtrace \
# generated
+endif
+endif
+endif
tst-stack4mod.sos=$(shell for i in 0 1 2 3 4 5 6 7 8 9 10 \
11 12 13 14 15 16 17 18 19; do \
diff --git a/posix/Makefile b/posix/Makefile
index 18ddb8c34176848e..830278a4233d7234 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -419,6 +419,17 @@ generated += \
$(addprefix wordexp-test-result, 1 2 3 4 5 6 7 8 9 10) \
annexc \
annexc.out \
+ getconf.speclist \
+ ptestcases.h \
+ testcases.h \
+ tst-getconf.out \
+ wordexp-tst.out \
+ # generated
+
+ifeq ($(run-built-tests),yes)
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+generated += \
bug-ga2-mem.out \
bug-ga2.mtrace \
bug-glob2-mem.out \
@@ -431,23 +442,22 @@ generated += \
bug-regex21.mtrace \
bug-regex31-mem.out \
bug-regex31.mtrace \
+ bug-regex36-mem.out \
bug-regex36.mtrace \
- getconf.speclist \
- ptestcases.h \
- testcases.h \
tst-boost-mem.out \
tst-boost.mtrace \
tst-fnmatch-mem.out \
tst-fnmatch.mtrace \
- tst-getconf.out \
tst-pcre-mem.out \
tst-pcre.mtrace \
tst-rxspencer-no-utf8-mem.out \
tst-rxspencer-no-utf8.mtrace \
tst-vfork3-mem.out \
tst-vfork3.mtrace \
- wordexp-tst.out \
# generated
+endif
+endif
+endif
ifeq ($(run-built-tests),yes)
ifeq (yes,$(build-shared))
@@ -462,6 +472,9 @@ endif
# XXX Please note that for now we ignore the result of this test.
tests-special += $(objpfx)annexc.out
ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-getconf.out
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
tests-special += \
$(objpfx)bug-ga2-mem.out \
$(objpfx)bug-glob2-mem.out \
@@ -472,13 +485,14 @@ tests-special += \
$(objpfx)bug-regex36-mem.out \
$(objpfx)tst-boost-mem.out \
$(objpfx)tst-fnmatch-mem.out \
- $(objpfx)tst-getconf.out \
$(objpfx)tst-glob-tilde-mem.out \
$(objpfx)tst-pcre-mem.out \
$(objpfx)tst-rxspencer-no-utf8-mem.out \
$(objpfx)tst-vfork3-mem.out \
# tests-special
endif
+endif
+endif
include ../Rules
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 74512f20d39f8fec..2a01b1de6639bb6f 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -232,10 +232,6 @@ tests := \
tst-popen \
tst-popen2 \
tst-printf-binary \
- tst-printf-bz18872 \
- tst-printf-bz25691 \
- tst-printf-fp-free \
- tst-printf-fp-leak \
tst-printf-intn \
tst-printf-oct \
tst-printf-round \
@@ -266,7 +262,6 @@ tests := \
tst-vfprintf-mbs-prec \
tst-vfprintf-user-type \
tst-vfprintf-width-i18n \
- tst-vfprintf-width-prec \
tst-vfprintf-width-prec-alloc \
tst-wc-printf \
tstdiomisc \
@@ -275,6 +270,20 @@ tests := \
xbug \
# tests
+ifeq ($(run-built-tests),yes)
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+tests += \
+ tst-printf-bz18872 \
+ tst-printf-bz25691 \
+ tst-printf-fp-free \
+ tst-printf-fp-leak \
+ tst-vfprintf-width-prec \
+ # tests
+endif
+endif
+endif
+
tests-container += \
tst-popen3 \
tst-setvbuf2 \
@@ -302,14 +311,19 @@ test-srcs = \
ifeq ($(run-built-tests),yes)
tests-special += \
- $(objpfx)tst-printf-bz18872-mem.out \
- $(objpfx)tst-printf-bz25691-mem.out \
- $(objpfx)tst-printf-fp-free-mem.out \
- $(objpfx)tst-printf-fp-leak-mem.out \
$(objpfx)tst-printf.out \
$(objpfx)tst-printfsz-islongdouble.out \
$(objpfx)tst-setvbuf1-cmp.out \
$(objpfx)tst-unbputc.out \
+ # tests-special
+
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+tests-special += \
+ $(objpfx)tst-printf-bz18872-mem.out \
+ $(objpfx)tst-printf-bz25691-mem.out \
+ $(objpfx)tst-printf-fp-free-mem.out \
+ $(objpfx)tst-printf-fp-leak-mem.out \
$(objpfx)tst-ungetc-leak-mem.out \
$(objpfx)tst-vfprintf-width-prec-mem.out \
# tests-special
@@ -330,6 +344,8 @@ generated += \
tst-vfprintf-width-prec-mem.out \
tst-vfprintf-width-prec.mtrace \
# generated
+endif
+endif
endif # $(run-built-tests)
tests-special += $(objpfx)tst-errno-manual.out

630
glibc-RHEL-115819-2.patch Normal file
View File

@ -0,0 +1,630 @@
commit 7f04bb4e49413bd57ac3215f3480b09ae7131968
Author: Joseph Myers <josmyers@redhat.com>
Date: Wed Aug 21 19:58:14 2024 +0000
Add more tests of getline
There is very little test coverage for getline (only a minimal
stdio-common/tstgetln.c which doesn't verify anything about the
results of the getline calls). Add some more thorough tests
(generally using fopencookie for convenience in testing various cases
for what the input and possible errors / EOF in the file read might
look like).
Note the following regarding testing of error cases:
* Nothing is said in the specifications about what if anything might
be written into the buffer, and whether it might be reallocated, in
error cases. The expectation of the tests (required to avoid memory
leaks on error) is that at least on error cases, the invariant that
lineptr points to at least n bytes is maintained.
* The optional EOVERFLOW error case specified in POSIX, "The number of
bytes to be written into the buffer, including the delimiter
character (if encountered), would exceed {SSIZE_MAX}.", doesn't seem
practically testable, as any case reading so many characters (half
the address space) would also be liable to run into allocation
failure along (ENOMEM) the way.
* If a read error occurs part way through reading an input line, it
seems unclear whether a partial line should be returned by getline
(avoid input getting lost), which is what glibc does at least in the
fopencookie case used in this test, or whether getline should return
-1 (error) (so avoiding the program misbehaving by processing a
truncated line as if it were complete). (There was a short,
inconclusive discussion about this on the Austin Group list on 9-10
November 2014.)
* The POSIX specification of getline inherits errors from fgetc. I
didn't try to cover fgetc errors systematically, just one example of
such an error.
Tested for x86_64 and x86.
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 2a01b1de6639bb6f..98fcd8a38523b728 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -221,6 +221,8 @@ tests := \
tst-fread \
tst-fseek \
tst-fwrite \
+ tst-getline \
+ tst-getline-enomem \
tst-gets \
tst-grouping \
tst-grouping2 \
@@ -320,6 +322,8 @@ tests-special += \
ifeq (yes,$(build-shared))
ifneq ($(PERL),no)
tests-special += \
+ $(objpfx)tst-getline-enomem-mem.out \
+ $(objpfx)tst-getline-mem.out \
$(objpfx)tst-printf-bz18872-mem.out \
$(objpfx)tst-printf-bz25691-mem.out \
$(objpfx)tst-printf-fp-free-mem.out \
@@ -329,6 +333,10 @@ tests-special += \
# tests-special
generated += \
+ tst-getline-enomem-mem.out \
+ tst-getline-enomem.mtrace \
+ tst-getline-mem.out \
+ tst-getline.mtrace \
tst-printf-bz18872-mem.out \
tst-printf-bz18872.c \
tst-printf-bz18872.mtrace \
@@ -438,6 +446,12 @@ tst-scanf-bz27650-ENV = \
tst-ungetc-leak-ENV = \
MALLOC_TRACE=$(objpfx)tst-ungetc-leak.mtrace \
LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-getline-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-getline.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-getline-enomem-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-getline-enomem.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
diff --git a/stdio-common/tst-getline-enomem.c b/stdio-common/tst-getline-enomem.c
new file mode 100644
index 0000000000000000..7fc70ea9b51d1262
--- /dev/null
+++ b/stdio-common/tst-getline-enomem.c
@@ -0,0 +1,78 @@
+/* Test getline: ENOMEM on allocation failure.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+
+#include <support/check.h>
+#include <support/test-driver.h>
+
+/* Produce a stream of test data based on data in COOKIE (ignored),
+ storing up to SIZE bytes in BUF. */
+
+static ssize_t
+io_read (void *cookie, char *buf, size_t size)
+{
+ memset (buf, 'x', size);
+ return size;
+}
+
+/* Set up a test stream with fopencookie. */
+
+static FILE *
+open_test_stream (void)
+{
+ static cookie_io_functions_t io_funcs = { .read = io_read };
+ static int cookie;
+ FILE *fp = fopencookie (&cookie, "r", io_funcs);
+ TEST_VERIFY_EXIT (fp != NULL);
+ return fp;
+}
+
+int
+do_test (void)
+{
+ FILE *fp;
+ char *lineptr = NULL;
+ size_t size = 0;
+ ssize_t ret;
+ mtrace ();
+ /* Test ENOMEM (and error indicator for stream set) for memory
+ allocation failure. */
+ verbose_printf ("Testing memory allocation failure\n");
+ fp = open_test_stream ();
+ struct rlimit limit;
+ TEST_VERIFY_EXIT (getrlimit (RLIMIT_AS, &limit) == 0);
+ limit.rlim_cur = 32 * 1024 * 1024;
+ TEST_VERIFY_EXIT (setrlimit (RLIMIT_AS, &limit) == 0);
+ errno = 0;
+ ret = getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (errno, ENOMEM);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ free (lineptr);
+ fclose (fp);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-getline.c b/stdio-common/tst-getline.c
new file mode 100644
index 0000000000000000..29eb7cec0f344872
--- /dev/null
+++ b/stdio-common/tst-getline.c
@@ -0,0 +1,451 @@
+/* Test getline.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <mcheck.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/test-driver.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+static struct test_data
+{
+ /* Input test data for fopencookie stream. */
+ const char *in_data;
+
+ /* The amount of test data left. */
+ size_t in_data_left;
+
+ /* Error number for forcing an error on next read. */
+ int in_error;
+
+ /* Error number for forcing an error (rather than EOF) after all
+ bytes read. */
+ int in_error_after;
+} the_cookie;
+
+/* Produce a stream of test data based on data in COOKIE, storing up
+ to SIZE bytes in BUF. */
+
+static ssize_t
+io_read (void *cookie, char *buf, size_t size)
+{
+ struct test_data *p = cookie;
+ if (p->in_error)
+ {
+ errno = p->in_error;
+ return -1;
+ }
+ if (size > p->in_data_left)
+ size = p->in_data_left;
+ memcpy (buf, p->in_data, size);
+ p->in_data += size;
+ p->in_data_left -= size;
+ if (p->in_data_left == 0)
+ p->in_error = p->in_error_after;
+ return size;
+}
+
+/* Set up a test stream with fopencookie. */
+
+static FILE *
+open_test_stream (const char *in_data, size_t size)
+{
+ static cookie_io_functions_t io_funcs = { .read = io_read };
+ the_cookie.in_data = in_data;
+ the_cookie.in_data_left = size;
+ the_cookie.in_error = 0;
+ the_cookie.in_error_after = 0;
+ FILE *fp = fopencookie (&the_cookie, "r", io_funcs);
+ TEST_VERIFY_EXIT (fp != NULL);
+ return fp;
+}
+
+/* Set up a test stream with fopencookie, using data from a string
+ literal. */
+#define OPEN_TEST_STREAM(IN_DATA) open_test_stream (IN_DATA, sizeof (IN_DATA))
+
+/* Wrap getline to verify that (as per the glibc manual), *LINEPTR is
+ returned as non-null and with at least *N bytes (even on error or
+ EOF). Also clear errno for the benefit of tests that check the
+ value of errno after the call. */
+
+ssize_t
+wrap_getline (char **lineptr, size_t *n, FILE *stream)
+{
+ errno = 0;
+ ssize_t ret = getline (lineptr, n, stream);
+ if (lineptr != NULL && n != NULL)
+ {
+ TEST_VERIFY (*lineptr != NULL);
+ TEST_VERIFY (malloc_usable_size (*lineptr) >= *n);
+ }
+ return ret;
+}
+
+int
+do_test (void)
+{
+ FILE *fp;
+ char *lineptr = NULL;
+ size_t size = 0;
+ ssize_t ret;
+ mtrace ();
+ /* Test failure with EINVAL (and error indicator for stream set) if
+ lineptr is a null pointer. */
+ verbose_printf ("Testing lineptr == NULL\n");
+ fp = OPEN_TEST_STREAM ("test");
+ ret = wrap_getline (NULL, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (errno, EINVAL);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ fclose (fp);
+ /* Test failure with EINVAL (and error indicator for stream set) if
+ n is a null pointer. */
+ verbose_printf ("Testing n == NULL\n");
+ fp = OPEN_TEST_STREAM ("test");
+ ret = wrap_getline (&lineptr, NULL, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (errno, EINVAL);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ fclose (fp);
+ /* Test failure with EINVAL (and error indicator for stream set) if
+ both lineptr and n are null pointers. */
+ verbose_printf ("Testing lineptr == NULL and n == NULL\n");
+ fp = OPEN_TEST_STREAM ("test");
+ ret = wrap_getline (NULL, NULL, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (errno, EINVAL);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ fclose (fp);
+ /* Test normal line, fitting in available space (including case with
+ null bytes). */
+ verbose_printf ("Testing normal nonempty input\n");
+ lineptr = xmalloc (10);
+ size = 10;
+ fp = OPEN_TEST_STREAM ("foo\nbar\0\n\0baz\nte\0st\n");
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "foo\n", 5);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "bar\0\n", 6);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "\0baz\n", 6);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 6);
+ TEST_COMPARE_BLOB (lineptr, 7, "te\0st\n", 7);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 1);
+ TEST_COMPARE_BLOB (lineptr, 1, "", 1);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (!!feof (fp), 1);
+ fclose (fp);
+ /* Test normal line, with reallocation (including case with null bytes). */
+ verbose_printf ("Testing normal nonempty input with reallocation\n");
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = OPEN_TEST_STREAM ("foo\nbar\0\n\0baz\nte\0st\n"
+ "foo\nbar\0\n\0baz\nte\0st\n");
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "foo\n", 5);
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "bar\0\n", 6);
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "\0baz\n", 6);
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 6);
+ TEST_COMPARE_BLOB (lineptr, 7, "te\0st\n", 7);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "foo\n", 5);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "bar\0\n", 6);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "\0baz\n", 6);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 6);
+ TEST_COMPARE_BLOB (lineptr, 7, "te\0st\n", 7);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 1);
+ TEST_COMPARE_BLOB (lineptr, 1, "", 1);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (!!feof (fp), 1);
+ fclose (fp);
+ /* Test EOF before delimiter but after some bytes read, fitting in
+ available space (including case with null bytes). */
+ verbose_printf ("Testing EOF before delimiter\n");
+ free (lineptr);
+ lineptr = xmalloc (10);
+ size = 10;
+ fp = open_test_stream ("foo", 3);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 3);
+ TEST_COMPARE_BLOB (lineptr, 4, "foo", 4);
+ fclose (fp);
+ free (lineptr);
+ lineptr = xmalloc (10);
+ size = 10;
+ fp = open_test_stream ("bar\0", 4);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "bar\0", 5);
+ fclose (fp);
+ free (lineptr);
+ lineptr = xmalloc (10);
+ size = 10;
+ fp = open_test_stream ("\0baz", 4);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "\0baz", 5);
+ fclose (fp);
+ free (lineptr);
+ lineptr = xmalloc (10);
+ size = 10;
+ fp = open_test_stream ("te\0st", 5);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "te\0st", 6);
+ fclose (fp);
+ /* Test EOF before delimiter but after some bytes read, with
+ reallocation (including case with null bytes). */
+ verbose_printf ("Testing EOF before delimiter with reallocation\n");
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = open_test_stream ("foo", 3);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 3);
+ TEST_COMPARE_BLOB (lineptr, 4, "foo", 4);
+ fclose (fp);
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = open_test_stream ("bar\0", 4);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "bar\0", 5);
+ fclose (fp);
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = open_test_stream ("\0baz", 4);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "\0baz", 5);
+ fclose (fp);
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = open_test_stream ("te\0st", 5);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "te\0st", 6);
+ fclose (fp);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ fp = open_test_stream ("foo", 3);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 3);
+ TEST_COMPARE_BLOB (lineptr, 4, "foo", 4);
+ fclose (fp);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ fp = open_test_stream ("bar\0", 4);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "bar\0", 5);
+ fclose (fp);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ fp = open_test_stream ("\0baz", 4);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 4);
+ TEST_COMPARE_BLOB (lineptr, 5, "\0baz", 5);
+ fclose (fp);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ fp = open_test_stream ("te\0st", 5);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 5);
+ TEST_COMPARE_BLOB (lineptr, 6, "te\0st", 6);
+ fclose (fp);
+ /* Test EOF with no bytes read (nothing is specified about anything
+ written to the buffer), including EOF again when already at end
+ of file. */
+ verbose_printf ("Testing EOF with no bytes read\n");
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = open_test_stream ("", 0);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (!!feof (fp), 1);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (!!feof (fp), 1);
+ fclose (fp);
+ free (lineptr);
+ lineptr = xmalloc (1);
+ size = 1;
+ fp = open_test_stream ("", 0);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (!!feof (fp), 1);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (ferror (fp), 0);
+ TEST_COMPARE (!!feof (fp), 1);
+ fclose (fp);
+ /* Test error occurring with no bytes read, including calling
+ wrap_getline again while the file is in error state. */
+ verbose_printf ("Testing error with no bytes read\n");
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = open_test_stream ("", 0);
+ the_cookie.in_error = EINVAL;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (errno, EINVAL);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ /* Make sure error state is sticky. */
+ the_cookie.in_error = 0;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ fclose (fp);
+ /* Test error occurring after some bytes read. Specifications are
+ ambiguous here; at least in the fopencookie case used for
+ testing, glibc returns the partial line (but with the error
+ indicator on the stream set). */
+ verbose_printf ("Testing error after some bytes read\n");
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = open_test_stream ("foo", 3);
+ the_cookie.in_error_after = EINVAL;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, 3);
+ TEST_COMPARE_BLOB (lineptr, 4, "foo", 4);
+ TEST_COMPARE (errno, EINVAL);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ /* Make sure error state is sticky. */
+ the_cookie.in_error = 0;
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ fclose (fp);
+ /* Test EBADF error as a representative example of an fgetc error
+ resulting in an error from wrap_getline. We don't try to cover all
+ error cases for fgetc here. */
+ verbose_printf ("Testing EBADF error\n");
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ fp = xfopen ("/dev/null", "r");
+ xclose (fileno (fp));
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (errno, EBADF);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ fclose (fp);
+ /* Test EAGAIN error as an example of an fgetc error on a valid file
+ descriptor. */
+ verbose_printf ("Testing EAGAIN error\n");
+ free (lineptr);
+ lineptr = NULL;
+ size = 0;
+ int pipefd[2];
+ xpipe (pipefd);
+ ret = fcntl (pipefd[0], F_SETFL, O_NONBLOCK);
+ TEST_VERIFY_EXIT (ret == 0);
+ fp = fdopen (pipefd[0], "r");
+ TEST_VERIFY_EXIT (fp != NULL);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (errno, EAGAIN);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ /* Make sure error state is sticky (even after more data is
+ available to read). */
+ xwrite (pipefd[1], "x\n", 2);
+ ret = wrap_getline (&lineptr, &size, fp);
+ TEST_COMPARE (ret, -1);
+ TEST_COMPARE (!!ferror (fp), 1);
+ TEST_COMPARE (feof (fp), 0);
+ fclose (fp);
+ free (lineptr);
+ return 0;
+}
+
+#include <support/test-driver.c>