diff --git a/glibc-RHEL-115819-1.patch b/glibc-RHEL-115819-1.patch new file mode 100644 index 0000000..d28762e --- /dev/null +++ b/glibc-RHEL-115819-1.patch @@ -0,0 +1,378 @@ +commit a7fe3e805d2ee128ac5f43b2a24201726d41cc04 +Author: Carlos O'Donell +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 + +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 diff --git a/glibc-RHEL-115819-2.patch b/glibc-RHEL-115819-2.patch new file mode 100644 index 0000000..33ae6ce --- /dev/null +++ b/glibc-RHEL-115819-2.patch @@ -0,0 +1,630 @@ +commit 7f04bb4e49413bd57ac3215f3480b09ae7131968 +Author: Joseph Myers +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* 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 +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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++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