diff --git a/libio/Makefile b/libio/Makefile index cd5a3afeeb..4370152964 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -86,6 +86,8 @@ tests = \ bug-wmemstream1 \ bug-wsetpos \ test-fmemopen \ + test-fputs-unbuffered-full \ + test-fputws-unbuffered-full \ tst-atime \ tst-bz22415 \ tst-bz24051 \ diff --git a/libio/test-fputs-unbuffered-full.c b/libio/test-fputs-unbuffered-full.c new file mode 100644 index 0000000000..145b4b6a57 --- /dev/null +++ b/libio/test-fputs-unbuffered-full.c @@ -0,0 +1,78 @@ +/* Regression test for 20632. + Copyright (C) 2024 Free Software Foundation, Inc. + Copyright 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 + . */ + +#include +#include +#include +#include +#include +#include + +#ifndef WIDE +# define TEST_NAME "fputs-unbuffered-full" +# define CHAR char +# define FPUTS fputs +# define TEXT "0123456789ABCDEF" +#else +# include +# define TEST_NAME "fputws-unbuffered-full" +# define CHAR wchar_t +# define FPUTS fputws +# define TEXT L"0123456789ABCDEF" +#endif /* WIDE */ + + +static int +do_test (void) +{ + /* Open an unbuffered stream to /dev/full. */ + FILE *fp = fopen ("/dev/full", "w"); + TEST_VERIFY_EXIT (fp != NULL); + int ret = setvbuf (fp, NULL, _IONBF, 0); + TEST_VERIFY_EXIT (ret == 0); + + /* Output a long string. */ + const int sz = 4096; + CHAR *buff = calloc (sz+1, sizeof *buff); + for (int i=0; i < sz; i++) + buff[i] = (CHAR) 'x'; + buff[sz] = (CHAR) '\0'; + errno = 0; + ret = FPUTS (buff, fp); + TEST_VERIFY (ret == EOF); + TEST_VERIFY (errno == ENOSPC); + free (buff); + + /* Output shorter strings. */ + for (int i=0; i < 1024; i++) + { + errno = 0; + ret = FPUTS (TEXT, fp); + TEST_VERIFY (ret == EOF); + TEST_VERIFY (errno == ENOSPC); + + /* Call malloc, triggering a crash if its + function pointers have been overwritten. */ + void *volatile ptr = malloc (1); + free (ptr); + } + return 0; +} + +#include diff --git a/libio/test-fputws-unbuffered-full.c b/libio/test-fputws-unbuffered-full.c new file mode 100644 index 0000000000..f3d79326e4 --- /dev/null +++ b/libio/test-fputws-unbuffered-full.c @@ -0,0 +1,21 @@ +/* Regression test for 20632. + Copyright (C) 2024 Free Software Foundation, Inc. + Copyright 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 + . */ + +#define WIDE 1 +#include "./test-fputs-unbuffered-full.c" diff --git a/libio/wfileops.c b/libio/wfileops.c index 6de5968358..fdbe8692e8 100644 --- a/libio/wfileops.c +++ b/libio/wfileops.c @@ -420,14 +420,14 @@ _IO_wfile_overflow (FILE *f, wint_t wch) { _IO_wdoallocbuf (f); _IO_free_wbackup_area (f); - _IO_wsetg (f, f->_wide_data->_IO_buf_base, - f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base); if (f->_IO_write_base == NULL) { _IO_doallocbuf (f); _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); } + _IO_wsetg (f, f->_wide_data->_IO_buf_base, + f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base); } else { @@ -958,7 +958,7 @@ _IO_wfile_xsputn (FILE *f, const void *data, size_t n) const wchar_t *s = (const wchar_t *) data; size_t to_do = n; int must_flush = 0; - size_t count; + size_t count = 0; if (n <= 0) return 0; @@ -967,7 +967,6 @@ _IO_wfile_xsputn (FILE *f, const void *data, size_t n) (or the filebuf is unbuffered), use sys_write directly. */ /* First figure out how much space is available in the buffer. */ - count = f->_wide_data->_IO_write_end - f->_wide_data->_IO_write_ptr; if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) { count = f->_wide_data->_IO_buf_end - f->_wide_data->_IO_write_ptr; @@ -985,6 +984,10 @@ _IO_wfile_xsputn (FILE *f, const void *data, size_t n) } } } + else if (f->_wide_data->_IO_write_end > f->_wide_data->_IO_write_ptr) + count = f->_wide_data->_IO_write_end + - f->_wide_data->_IO_write_ptr; /* Space available. */ + /* Then fill the buffer. */ if (count > 0) {