[PATCH v4] libio: Fix ungetwc operating on byte stream [BZ #33998]

Florian Weimer fweimer@redhat.com
Thu Apr 30 16:11:16 GMT 2026


* Rocket Ma:

> diff --git a/libio/bug-wgenops-bz33998.c b/libio/bug-wgenops-bz33998.c
> new file mode 100644
> index 0000000000..b3f750a753
> --- /dev/null
> +++ b/libio/bug-wgenops-bz33998.c
> @@ -0,0 +1,44 @@
> +/* Regression test for ungetwc operating on byte stream (BZ #33998)
> +   Copyright (C) 2026 The GNU Toolchain Authors.
> +   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 <unistd.h>
> +#include <sys/mman.h>
> +#include <stdio.h>
> +#include <wchar.h>
> +#include <support/check.h>
> +
> +static int
> +do_test (void)
> +{
> +  int fd = memfd_create ("test", MFD_CLOEXEC);
> +  TEST_VERIFY (fd != -1);

This may fail on older kernels, so please use create_temp_file from
<support/temp_file.h>.

> +  TEST_COMPARE (write (fd, (unsigned char[]){ 'A', 0, 0, 0 }, 4), 4);
> +  TEST_COMPARE (lseek (fd, 0, SEEK_SET), 0);
> +  FILE *fp = fdopen (fd, "r+");

You could use xwrite, xlseek, xfopen.

> +  TEST_VERIFY (fp != NULL);
> +  TEST_COMPARE (getwc (fp), L'A');
> +
> +  /* if the bug is fixed, then ungetwc should not touch byte stream. */
> +  char *old_read_ptr = fp->_IO_read_ptr;
> +  TEST_COMPARE (ungetwc (0, fp), L'\0');

Can you please use 0 or L'\0' in both places?

> +  TEST_VERIFY (fp->_IO_read_ptr == old_read_ptr);

You could check that the null character can be read back with fgetwc.
And call xfclose at the end.

> diff --git a/libio/wgenops.c b/libio/wgenops.c
> index 6829477e0c..5f36bc49a1 100644
> --- a/libio/wgenops.c
> +++ b/libio/wgenops.c
> @@ -110,8 +110,8 @@ _IO_wdefault_pbackfail (FILE *fp, wint_t c)
>  {
>    if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
>        && !_IO_in_backup (fp)
> -      && (wint_t) fp->_IO_read_ptr[-1] == c)
> -    --fp->_IO_read_ptr;
> +      && (wint_t) fp->_wide_data->_IO_read_ptr[-1] == c)
> +    --fp->_wide_data->_IO_read_ptr;
>    else
>      {
>        /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/

The fix itself looks good to me.

Thanks,
Florian



More information about the Libc-alpha mailing list