diff options
| author | Joseph Myers <josmyers@redhat.com> | 2025-01-28 19:38:27 +0000 |
|---|---|---|
| committer | Joseph Myers <josmyers@redhat.com> | 2025-01-28 19:38:27 +0000 |
| commit | 377e9733b50ce41e496c467ddcc112f73c88f3bd (patch) | |
| tree | 2aaeddae812df4ad17ff3ca426b59c18cd307096 /stdio-common | |
| parent | 1515f74fd81035a79861cd9fa12053fa9450ec65 (diff) | |
| download | glibc-377e9733b50ce41e496c467ddcc112f73c88f3bd.tar.xz glibc-377e9733b50ce41e496c467ddcc112f73c88f3bd.zip | |
Fix fflush after ungetc on input file (bug 5994)
As discussed in bug 5994 (plus duplicates), POSIX requires fflush
after ungetc to discard pushed-back characters but preserve the file
position indicator. For this purpose, each ungetc decrements the file
position indicator by 1; it is unspecified after ungetc at the start
of the file, and after ungetwc, so no special handling is needed for
either of those cases.
This is fixed with appropriate logic in _IO_new_file_sync. I haven't
made any attempt to test or change things in this area for the "old"
functions; the case of files using mmap is addressed in a subsequent
patch (and there seem to be no problems in this area with files opened
with fmemopen).
Tested for x86_64.
Diffstat (limited to 'stdio-common')
| -rw-r--r-- | stdio-common/Makefile | 1 | ||||
| -rw-r--r-- | stdio-common/tst-ungetc-fflush.c | 64 |
2 files changed, 65 insertions, 0 deletions
diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 1e7bca641e..4a3810cdf2 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -305,6 +305,7 @@ tests := \ tst-swscanf \ tst-tmpnam \ tst-ungetc \ + tst-ungetc-fflush \ tst-ungetc-leak \ tst-ungetc-nomem \ tst-unlockedio \ diff --git a/stdio-common/tst-ungetc-fflush.c b/stdio-common/tst-ungetc-fflush.c new file mode 100644 index 0000000000..a86d1fdb7f --- /dev/null +++ b/stdio-common/tst-ungetc-fflush.c @@ -0,0 +1,64 @@ +/* Test flushing input file after ungetc (bug 5994). + Copyright (C) 2025 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 <stdio.h> + +#include <support/check.h> +#include <support/temp_file.h> +#include <support/xstdio.h> +#include <support/xunistd.h> + +int +do_test (void) +{ + char *filename = NULL; + int fd = create_temp_file ("tst-ungetc-fflush", &filename); + TEST_VERIFY_EXIT (fd != -1); + xclose (fd); + + /* Test as in bug 5994. */ + FILE *fp = xfopen (filename, "w"); + TEST_VERIFY_EXIT (fputs ("#include", fp) >= 0); + xfclose (fp); + fp = xfopen (filename, "r"); + TEST_COMPARE (fgetc (fp), '#'); + TEST_COMPARE (fgetc (fp), 'i'); + TEST_COMPARE (ungetc ('@', fp), '@'); + TEST_COMPARE (fflush (fp), 0); + TEST_COMPARE (lseek (fileno (fp), 0, SEEK_CUR), 1); + TEST_COMPARE (fgetc (fp), 'i'); + TEST_COMPARE (fgetc (fp), 'n'); + xfclose (fp); + + /* Test as in bug 12799 (duplicate of 5994). */ + fp = xfopen (filename, "w+"); + TEST_VERIFY_EXIT (fputs ("hello world", fp) >= 0); + rewind (fp); + TEST_VERIFY (fileno (fp) >= 0); + char buffer[10]; + TEST_COMPARE (fread (buffer, 1, 5, fp), 5); + TEST_COMPARE (fgetc (fp), ' '); + TEST_COMPARE (ungetc ('@', fp), '@'); + TEST_COMPARE (fflush (fp), 0); + TEST_COMPARE (fgetc (fp), ' '); + xfclose (fp); + + return 0; +} + +#include <support/test-driver.c> |
