| From ec2f1fddf29053957d061dfe310f106388472a4f Mon Sep 17 00:00:00 2001 |
| From: Florian Weimer <fweimer@redhat.com> |
| Date: Wed, 15 Jul 2020 12:37:01 +0200 |
| Subject: [PATCH 11/11] libio: Remove __libc_readline_unlocked |
| |
| __nss_readline supersedes it. This reverts part of commit |
| 3f5e3f5d066dcffb80af48ae2cf35a01a85a8f10 ("libio: Implement |
| internal function __libc_readline_unlocked"). The internal |
| aliases __fseeko64 and __ftello64 are preserved because |
| they are needed by __nss_readline as well. |
| |
| Tested-by: Carlos O'Donell <carlos@redhat.com> |
| Reviewed-by: Carlos O'Donell <carlos@redhat.com> |
| |
| include/stdio.h | 13 --- |
| libio/Makefile | 4 +- |
| libio/Versions | 1 - |
| libio/readline.c | 170 ------------------------------------ |
| libio/tst-readline.c | 237 --------------------------------------------------- |
| 5 files changed, 2 insertions(+), 423 deletions(-) |
| delete mode 100644 libio/readline.c |
| delete mode 100644 libio/tst-readline.c |
| |
| diff -rupN a/include/stdio.h b/include/stdio.h |
| |
| |
| @@ -135,19 +135,6 @@ extern int __fxprintf (FILE *__fp, const |
| extern int __fxprintf_nocancel (FILE *__fp, const char *__fmt, ...) |
| __attribute__ ((__format__ (__printf__, 2, 3))) attribute_hidden; |
| |
| -/* Read the next line from FP into BUFFER, of LENGTH bytes. LINE will |
| - include the line terminator and a NUL terminator. On success, |
| - return the length of the line, including the line terminator, but |
| - excluding the NUL termintor. On EOF, return zero and write a NUL |
| - terminator. On error, return -1 and set errno. If the total byte |
| - count (line and both terminators) exceeds LENGTH, return -1 and set |
| - errno to ERANGE (but do not mark the stream as failed). |
| - |
| - The behavior is undefined if FP is not seekable, or if the stream |
| - is already in an error state. */ |
| -ssize_t __libc_readline_unlocked (FILE *fp, char *buffer, size_t length); |
| -libc_hidden_proto (__libc_readline_unlocked); |
| - |
| extern const char *const _sys_errlist_internal[] attribute_hidden; |
| extern int _sys_nerr_internal attribute_hidden; |
| |
| diff -rupN a/libio/Makefile b/libio/Makefile |
| |
| |
| @@ -49,7 +49,7 @@ routines := \ |
| __fbufsize __freading __fwriting __freadable __fwritable __flbf \ |
| __fpurge __fpending __fsetlocking \ |
| \ |
| - libc_fatal fmemopen oldfmemopen vtables readline |
| + libc_fatal fmemopen oldfmemopen vtables |
| |
| tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ |
| tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \ |
| @@ -67,7 +67,7 @@ tests = tst_swprintf tst_wprintf tst_sws |
| tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \ |
| tst-wfile-sync |
| |
| -tests-internal = tst-vtables tst-vtables-interposed tst-readline |
| +tests-internal = tst-vtables tst-vtables-interposed |
| |
| ifeq (yes,$(build-shared)) |
| # Add test-fopenloc only if shared library is enabled since it depends on |
| diff -rupN a/libio/Versions b/libio/Versions |
| |
| |
| @@ -161,6 +161,5 @@ libc { |
| |
| __fseeko64; |
| __ftello64; |
| - __libc_readline_unlocked; |
| } |
| } |
| diff -rupN a/libio/readline.c b/libio/readline.c |
| |
| |
| @@ -1,170 +0,0 @@ |
| -/* fgets with ERANGE error reporting and size_t buffer length. |
| - Copyright (C) 2018 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 |
| - <http://www.gnu.org/licenses/>. */ |
| - |
| -#include <assert.h> |
| -#include <errno.h> |
| -#include <stdio.h> |
| -#include <string.h> |
| - |
| -#include "libioP.h" |
| - |
| -/* Return -1 and set errno to EINVAL if it is ERANGE. */ |
| -static ssize_t |
| -fail_no_erange (void) |
| -{ |
| - if (errno == ERANGE) |
| - __set_errno (EINVAL); |
| - return -1; |
| -} |
| - |
| -/* Slow path for reading the line. Called with no data in the stream |
| - read buffer. Write data to [BUFFER, BUFFER_END). */ |
| -static ssize_t |
| -readline_slow (FILE *fp, char *buffer, char *buffer_end) |
| -{ |
| - char *start = buffer; |
| - |
| - while (buffer < buffer_end) |
| - { |
| - if (__underflow (fp) == EOF) |
| - { |
| - if (_IO_ferror_unlocked (fp)) |
| - /* If the EOF was caused by a read error, report it. */ |
| - return fail_no_erange (); |
| - *buffer = '\0'; |
| - /* Do not include the null terminator. */ |
| - return buffer - start; |
| - } |
| - |
| - /* __underflow has filled the buffer. */ |
| - char *readptr = fp->_IO_read_ptr; |
| - ssize_t readlen = fp->_IO_read_end - readptr; |
| - /* Make sure that __underflow really has acquired some data. */ |
| - assert (readlen > 0); |
| - char *pnl = memchr (readptr, '\n', readlen); |
| - if (pnl != NULL) |
| - { |
| - /* We found the terminator. */ |
| - size_t line_length = pnl - readptr; |
| - if (line_length + 2 > buffer_end - buffer) |
| - /* Not enough room in the caller-supplied buffer. */ |
| - break; |
| - memcpy (buffer, readptr, line_length + 1); |
| - buffer[line_length + 1] = '\0'; |
| - fp->_IO_read_ptr = pnl + 1; |
| - /* Do not include the null terminator. */ |
| - return buffer - start + line_length + 1; |
| - } |
| - |
| - if (readlen >= buffer_end - buffer) |
| - /* Not enough room in the caller-supplied buffer. */ |
| - break; |
| - |
| - /* Save and consume the stream buffer. */ |
| - memcpy (buffer, readptr, readlen); |
| - fp->_IO_read_ptr = fp->_IO_read_end; |
| - buffer += readlen; |
| - } |
| - |
| - /* The line does not fit into the buffer. */ |
| - __set_errno (ERANGE); |
| - return -1; |
| -} |
| - |
| -ssize_t |
| -__libc_readline_unlocked (FILE *fp, char *buffer, size_t buffer_length) |
| -{ |
| - char *buffer_end = buffer + buffer_length; |
| - |
| - /* Orient the stream. */ |
| - if (__builtin_expect (fp->_mode, -1) == 0) |
| - _IO_fwide (fp, -1); |
| - |
| - /* Fast path: The line terminator is found in the buffer. */ |
| - char *readptr = fp->_IO_read_ptr; |
| - ssize_t readlen = fp->_IO_read_end - readptr; |
| - off64_t start_offset; /* File offset before reading anything. */ |
| - if (readlen > 0) |
| - { |
| - char *pnl = memchr (readptr, '\n', readlen); |
| - if (pnl != NULL) |
| - { |
| - size_t line_length = pnl - readptr; |
| - /* Account for line and null terminators. */ |
| - if (line_length + 2 > buffer_length) |
| - { |
| - __set_errno (ERANGE); |
| - return -1; |
| - } |
| - memcpy (buffer, readptr, line_length + 1); |
| - buffer[line_length + 1] = '\0'; |
| - /* Consume the entire line. */ |
| - fp->_IO_read_ptr = pnl + 1; |
| - return line_length + 1; |
| - } |
| - |
| - /* If the buffer does not have enough space for what is pending |
| - in the stream (plus a NUL terminator), the buffer is too |
| - small. */ |
| - if (readlen + 1 > buffer_length) |
| - { |
| - __set_errno (ERANGE); |
| - return -1; |
| - } |
| - |
| - /* End of line not found. We need all the buffered data. Fall |
| - through to the slow path. */ |
| - memcpy (buffer, readptr, readlen); |
| - buffer += readlen; |
| - /* The original length is invalid after this point. Use |
| - buffer_end instead. */ |
| -#pragma GCC poison buffer_length |
| - /* Read the old offset before updating the read pointer. */ |
| - start_offset = __ftello64 (fp); |
| - fp->_IO_read_ptr = fp->_IO_read_end; |
| - } |
| - else |
| - { |
| - readlen = 0; |
| - start_offset = __ftello64 (fp); |
| - } |
| - |
| - /* Slow path: Read more data from the underlying file. We need to |
| - restore the file pointer if the buffer is too small. First, |
| - check if the __ftello64 call above failed. */ |
| - if (start_offset < 0) |
| - return fail_no_erange (); |
| - |
| - ssize_t result = readline_slow (fp, buffer, buffer_end); |
| - if (result < 0) |
| - { |
| - if (errno == ERANGE) |
| - { |
| - /* Restore the file pointer so that the caller may read the |
| - same line again. */ |
| - if (__fseeko64 (fp, start_offset, SEEK_SET) < 0) |
| - return fail_no_erange (); |
| - __set_errno (ERANGE); |
| - } |
| - /* Do not restore the file position on other errors; it is |
| - likely that the __fseeko64 call would fail, too. */ |
| - return -1; |
| - } |
| - return readlen + result; |
| -} |
| -libc_hidden_def (__libc_readline_unlocked) |
| diff -rupN a/libio/tst-readline.c b/libio/tst-readline.c |
| |
| |
| @@ -1,237 +0,0 @@ |
| -/* Test the __libc_readline_unlocked function. |
| - Copyright (C) 2018 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 |
| - <http://www.gnu.org/licenses/>. */ |
| - |
| -/* Exercise __libc_readline_unlocked with various combinations of line |
| - lengths, stdio buffer sizes, and line read buffer sizes. */ |
| - |
| -#include <errno.h> |
| -#include <stdbool.h> |
| -#include <stdio.h> |
| -#include <string.h> |
| -#include <support/check.h> |
| -#include <support/support.h> |
| -#include <support/temp_file.h> |
| -#include <support/test-driver.h> |
| -#include <support/xmemstream.h> |
| -#include <support/xstdio.h> |
| -#include <support/xunistd.h> |
| - |
| -enum |
| - { |
| - maximum_line_length = 7, |
| - number_of_lines = 3, |
| - }; |
| - |
| -/* -1: Do not set buffer size. 0: unbuffered. Otherwise, use this as |
| - the size of the buffer. */ |
| -static int buffer_size; |
| - |
| -/* These size of the buffer used for reading. Must be at least 2. */ |
| -static int read_size; |
| - |
| -/* If a read files with ERANGE, increase the buffer size by this |
| - amount. Must be positive. */ |
| -static int read_size_increment; |
| - |
| -/* If non-zero, do not reset the read size after an ERANGE error. */ |
| -static int read_size_preserve; |
| - |
| -/* If non-zero, no '\n' at the end of the file. */ |
| -static int no_newline_at_eof; |
| - |
| -/* Length of the line, or -1 if the line is not present. */ |
| -static int line_lengths[number_of_lines]; |
| - |
| -/* The name of the test file. */ |
| -static char *test_file_path; |
| - |
| -/* The contents of the test file. */ |
| -static char expected_contents[(maximum_line_length + 2) * number_of_lines + 1]; |
| -static size_t expected_length; |
| - |
| -/* Returns a random byte which is not zero or the line terminator. */ |
| -static char |
| -random_char (void) |
| -{ |
| - static unsigned int rand_state = 1; |
| - while (true) |
| - { |
| - char result = rand_r (&rand_state) >> 16; |
| - if (result != 0 && result != '\n') |
| - return result; |
| - } |
| -} |
| - |
| -/* Create the test file. */ |
| -static void |
| -prepare (int argc, char **argv) |
| -{ |
| - int fd = create_temp_file ("tst-readline-", &test_file_path); |
| - TEST_VERIFY_EXIT (fd >= 0); |
| - xclose (fd); |
| -} |
| - |
| -/* Prepare the test file. Return false if the test parameters are |
| - incongruent and the test should be skipped. */ |
| -static bool |
| -write_test_file (void) |
| -{ |
| - expected_length = 0; |
| - char *p = expected_contents; |
| - for (int lineno = 0; lineno < number_of_lines; ++lineno) |
| - for (int i = 0; i < line_lengths[lineno]; ++i) |
| - *p++ = random_char (); |
| - expected_length = p - &expected_contents[0]; |
| - if (no_newline_at_eof) |
| - { |
| - if (expected_length == 0) |
| - return false; |
| - --expected_length; |
| - --p; |
| - } |
| - if (test_verbose > 0) |
| - { |
| - printf ("info: writing test file of %zu bytes:\n", expected_length); |
| - for (int i = 0; i < number_of_lines; ++i) |
| - printf (" line %d: %d\n", i, line_lengths[i]); |
| - if (no_newline_at_eof) |
| - puts (" (no newline at EOF)"); |
| - } |
| - TEST_VERIFY_EXIT (expected_length < sizeof (expected_contents)); |
| - *p++ = '\0'; |
| - support_write_file_string (test_file_path, expected_contents); |
| - return true; |
| -} |
| - |
| -/* Run a single test (a combination of a test file and read |
| - parameters). */ |
| -static void |
| -run_test (void) |
| -{ |
| - TEST_VERIFY_EXIT (read_size_increment > 0); |
| - if (test_verbose > 0) |
| - { |
| - printf ("info: running test: buffer_size=%d read_size=%d\n" |
| - " read_size_increment=%d read_size_preserve=%d\n", |
| - buffer_size, read_size, read_size_increment, read_size_preserve); |
| - } |
| - |
| - struct xmemstream result; |
| - xopen_memstream (&result); |
| - |
| - FILE *fp = xfopen (test_file_path, "rce"); |
| - char *fp_buffer = NULL; |
| - if (buffer_size == 0) |
| - TEST_VERIFY_EXIT (setvbuf (fp, NULL, _IONBF, 0) == 0); |
| - if (buffer_size > 0) |
| - { |
| - fp_buffer = xmalloc (buffer_size); |
| - TEST_VERIFY_EXIT (setvbuf (fp, fp_buffer, _IOFBF, buffer_size) == 0); |
| - } |
| - |
| - char *line_buffer = xmalloc (read_size); |
| - size_t line_buffer_size = read_size; |
| - |
| - while (true) |
| - { |
| - ssize_t ret = __libc_readline_unlocked |
| - (fp, line_buffer, line_buffer_size); |
| - if (ret < 0) |
| - { |
| - TEST_VERIFY (ret == -1); |
| - if (errno != ERANGE) |
| - FAIL_EXIT1 ("__libc_readline_unlocked: %m"); |
| - line_buffer_size += read_size_increment; |
| - free (line_buffer); |
| - line_buffer = xmalloc (line_buffer_size); |
| - /* Try reading this line again. */ |
| - } |
| - else if (ret == 0) |
| - break; |
| - else |
| - { |
| - /* A line has been read. Save it. */ |
| - TEST_VERIFY (ret == strlen (line_buffer)); |
| - const char *pnl = strchr (line_buffer, '\n'); |
| - /* If there is a \n, it must be at the end. */ |
| - TEST_VERIFY (pnl == NULL || pnl == line_buffer + ret - 1); |
| - fputs (line_buffer, result.out); |
| - |
| - /* Restore the original read size if required. */ |
| - if (line_buffer_size > read_size && !read_size_preserve) |
| - { |
| - line_buffer_size = read_size; |
| - free (line_buffer); |
| - line_buffer = xmalloc (line_buffer_size); |
| - } |
| - } |
| - } |
| - |
| - xfclose (fp); |
| - free (fp_buffer); |
| - free (line_buffer); |
| - |
| - xfclose_memstream (&result); |
| - TEST_VERIFY (result.length == expected_length); |
| - TEST_VERIFY (strcmp (result.buffer, expected_contents) == 0); |
| - if (test_verbose > 0) |
| - { |
| - printf ("info: expected (%zu): [[%s]]\n", |
| - expected_length, expected_contents); |
| - printf ("info: actual (%zu): [[%s]]\n", result.length, result.buffer); |
| - } |
| - free (result.buffer); |
| -} |
| - |
| -/* Test one test file with multiple read parameters. */ |
| -static void |
| -test_one_file (void) |
| -{ |
| - for (buffer_size = -1; buffer_size <= maximum_line_length + 1; ++buffer_size) |
| - for (read_size = 2; read_size <= maximum_line_length + 2; ++read_size) |
| - for (read_size_increment = 1; read_size_increment <= 4; |
| - ++read_size_increment) |
| - for (read_size_preserve = 0; read_size_preserve < 2; |
| - ++read_size_preserve) |
| - run_test (); |
| -} |
| - |
| - |
| -static int |
| -do_test (void) |
| -{ |
| - /* Set up the test file contents. */ |
| - for (line_lengths[0] = -1; line_lengths[0] <= maximum_line_length; |
| - ++line_lengths[0]) |
| - for (line_lengths[1] = -1; line_lengths[1] <= maximum_line_length; |
| - ++line_lengths[1]) |
| - for (line_lengths[2] = -1; line_lengths[2] <= maximum_line_length; |
| - ++line_lengths[2]) |
| - for (no_newline_at_eof = 0; no_newline_at_eof < 2; ++no_newline_at_eof) |
| - { |
| - if (!write_test_file ()) |
| - continue; |
| - test_one_file (); |
| - } |
| - free (test_file_path); |
| - return 0; |
| -} |
| - |
| -#define TIMEOUT 100 |
| -#define PREPARE prepare |
| -#include <support/test-driver.c> |