Files
glibc/libio/iogetwline.c
Shamil Abdulaev ad66f46380 libio: Use __wunderflow in _IO_getwline_info
After a buffer refill, _IO_getwline_info reads the first character
through __wuflow and handles it on a separate path from the rest of
the buffer.  When extract_delim is negative, that path calls
_IO_sputbackc, the narrow-stream putback, on a wide stream, so it
would operate on fp->_IO_read_ptr instead of
fp->_wide_data->_IO_read_ptr.  No current caller passes a negative
extract_delim, so this is not reachable today.

Refill the buffer with __wunderflow instead, which does not consume
anything, and let the wmemchr path handle every character including
the delimiter.  This removes the duplicated delimiter handling and
the wrong putback.  Every wide underflow implementation either
returns WEOF or leaves at least one character in the buffer, so the
loop cannot spin.

No functional change for fgetws and fgetws_unlocked.  Tested with the
libio tests on x86_64-linux-gnu, including tst-fgetws and tst-widetext.

Signed-off-by: Shamil Abdulaev <ashamil435@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-10-07 07:43:12 -03:00

94 lines
2.9 KiB
C

/* Copyright (C) 1993-2026 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/>.
As a special exception, if you link the code in this file with
files compiled with a GNU compiler to produce an executable,
that does not cause the resulting executable to be covered by
the GNU Lesser General Public License. This exception does not
however invalidate any other reasons why the executable file
might be covered by the GNU Lesser General Public License.
This exception applies to code released by its copyright holders
in files containing the exception. */
#include "libioP.h"
#include <string.h>
#include <wchar.h>
size_t
_IO_getwline (FILE *fp, wchar_t *buf, size_t n, wint_t delim,
int extract_delim)
{
return _IO_getwline_info (fp, buf, n, delim, extract_delim, (wint_t *) 0);
}
/* Algorithm based on that used by Berkeley pre-4.4 fgets implementation.
Read chars into buf (of size n), until delim is seen.
Return number of chars read (at most n).
Does not put a terminating '\0' in buf.
If extract_delim < 0, leave delimiter unread.
If extract_delim > 0, insert delim in output. */
size_t
_IO_getwline_info (FILE *fp, wchar_t *buf, size_t n, wint_t delim,
int extract_delim, wint_t *eof)
{
wchar_t *ptr = buf;
if (eof != NULL)
*eof = 0;
if (__builtin_expect (fp->_mode, 1) == 0)
_IO_fwide (fp, 1);
while (n != 0)
{
wchar_t *read_ptr = fp->_wide_data->_IO_read_ptr;
if (fp->_wide_data->_IO_read_end <= read_ptr)
{
/* Refill the buffer without consuming anything, so that the
delimiter is always handled by the block path below. */
if (__wunderflow (fp) == WEOF)
{
if (eof != NULL)
*eof = WEOF;
break;
}
continue;
}
size_t len = fp->_wide_data->_IO_read_end - read_ptr;
if (len > n)
len = n;
wchar_t *t = wmemchr (read_ptr, delim, len);
if (t != NULL)
{
len = t - read_ptr;
if (extract_delim >= 0)
{
++t;
if (extract_delim > 0)
++len;
}
__wmemcpy (ptr, read_ptr, len);
fp->_wide_data->_IO_read_ptr = t;
return (ptr - buf) + len;
}
__wmemcpy (ptr, read_ptr, len);
fp->_wide_data->_IO_read_ptr = read_ptr + len;
ptr += len;
n -= len;
}
return ptr - buf;
}