[PATCH 5/6] Fix fflush handling for mmap files after ungetc (bug 32535)
DJ Delorie
dj@redhat.com
Wed Jan 15 07:17:22 GMT 2025
Some of the logic seems a little off to me, but it might be my brand new
understanding of how _IO_* works ;-)
Also, the test seems weak somehow.
Joseph Myers <josmyers@redhat.com> writes:
> diff --git a/libio/fileops.c b/libio/fileops.c
> int
> _IO_file_sync_mmap (FILE *fp)
> {
> + off64_t o = fp->_offset - (fp->_IO_read_end - fp->_IO_read_ptr);
To be consistent with logic elsewhere, this could have been:
> off64_t o = fp->_offset + (fp->_IO_read_ptr - fp->_IO_read_end);
But this logic doesn't reflect the true meaning of the underlying
pointers when _IO_in_backup() is true. It ends up calculating the same
value, but it's applying fp->_offset to the wrong buffer in that case.
The effective offset of the backup buffer's end is the main buffer's
current read pointer.
This is how it's done elsewhere, though, so ok.
> if (fp->_IO_read_ptr != fp->_IO_read_end)
> {
> - if (__lseek64 (fp->_fileno, fp->_IO_read_ptr - fp->_IO_buf_base,
> - SEEK_SET)
> - != fp->_IO_read_ptr - fp->_IO_buf_base)
> + if (_IO_in_backup (fp))
> + {
> + _IO_switch_to_main_get_area (fp);
> + o -= fp->_IO_read_end - fp->_IO_read_base;
Shouldn't one of these be _IO_read_ptr ?
> + }
> + if (__lseek64 (fp->_fileno, o, SEEK_SET) != o)
Ok.
> {
> fp->_flags |= _IO_ERR_SEEN;
> return EOF;
> }
> }
> - fp->_offset = fp->_IO_read_ptr - fp->_IO_buf_base;
> + fp->_offset = o;
> fp->_IO_read_end = fp->_IO_read_ptr = fp->_IO_read_base;
> return 0;
> }
Ok.
> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index 06c9eaf426..703e8af7e8 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -239,6 +239,7 @@ tests := \
> tst-fdopen2 \
> tst-ferror \
> tst-fflush-all-input \
> + tst-fflush-mmap \
> tst-fgets \
> tst-fgets2 \
> tst-fileno \
Ok.
> diff --git a/stdio-common/tst-fflush-mmap.c b/stdio-common/tst-fflush-mmap.c
> +/* Test fflush after ungetc on files using mmap (bug 32535).
> + 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>
Ok.
> +int
> +do_test (void)
> +{
> + char *filename = NULL;
> + int fd = create_temp_file ("tst-fflush-mmap", &filename);
> + TEST_VERIFY_EXIT (fd != -1);
> + xclose (fd);
Ok.
> + /* Test fflush after ungetc (bug 32535). */
> + FILE *fp = xfopen (filename, "w");
> + TEST_VERIFY (0 <= fputs ("test", fp));
> + xfclose (fp);
Ok.
> + fp = xfopen (filename, "rm");
> + TEST_COMPARE (fgetc (fp), 't');
> + TEST_COMPARE (ungetc ('u', fp), 'u');
> + TEST_COMPARE (fflush (fp), 0);
Should we test that fflush() did the right thing, somehow?
Can we, for mmap'd files?
> + xfclose (fp);
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
Ok.
More information about the Libc-alpha
mailing list