You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
5.2 KiB
136 lines
5.2 KiB
commit a5cd39541396b91d90cc611858ee7b3355fcfe47 |
|
Author: Siddhesh Poyarekar <siddhesh@sourceware.org> |
|
Date: Tue Aug 13 21:08:49 2024 -0400 |
|
|
|
ungetc: Fix backup buffer leak on program exit [BZ #27821] |
|
|
|
If a file descriptor is left unclosed and is cleaned up by _IO_cleanup |
|
on exit, its backup buffer remains unfreed, registering as a leak in |
|
valgrind. This is not strictly an issue since (1) the program should |
|
ideally be closing the stream once it's not in use and (2) the program |
|
is about to exit anyway, so keeping the backup buffer around a wee bit |
|
longer isn't a real problem. Free it anyway to keep valgrind happy |
|
when the streams in question are the standard ones, i.e. stdout, stdin |
|
or stderr. |
|
|
|
Also, the _IO_have_backup macro checks for _IO_save_base, |
|
which is a roundabout way to check for a backup buffer instead of |
|
directly looking for _IO_backup_base. The roundabout check breaks when |
|
the main get area has not been used and user pushes a char into the |
|
backup buffer with ungetc. Fix this to use the _IO_backup_base |
|
directly. |
|
|
|
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org> |
|
Reviewed-by: Carlos O'Donell <carlos@redhat.com> |
|
(cherry picked from commit 3e1d8d1d1dca24ae90df2ea826a8916896fc7e77) |
|
(cherry picked from commit b9f72bd5de931eac39219018c2fa319a449bb2cf) |
|
|
|
diff --git a/libio/genops.c b/libio/genops.c |
|
index a5dd6a06d9e259d8..b5fc53fd1ef6e911 100644 |
|
--- a/libio/genops.c |
|
+++ b/libio/genops.c |
|
@@ -796,6 +796,12 @@ _IO_unbuffer_all (void) |
|
legacy = 1; |
|
#endif |
|
|
|
+ /* Free up the backup area if it was ever allocated. */ |
|
+ if (_IO_have_backup (fp)) |
|
+ _IO_free_backup_area (fp); |
|
+ if (fp->_mode > 0 && _IO_have_wbackup (fp)) |
|
+ _IO_free_wbackup_area (fp); |
|
+ |
|
if (! (fp->_flags & _IO_UNBUFFERED) |
|
/* Iff stream is un-orientated, it wasn't used. */ |
|
&& (legacy || fp->_mode != 0)) |
|
diff --git a/libio/libioP.h b/libio/libioP.h |
|
index dc9a2ce9c8d7744c..bab5f3770f0760c4 100644 |
|
--- a/libio/libioP.h |
|
+++ b/libio/libioP.h |
|
@@ -529,8 +529,8 @@ extern void _IO_old_init (FILE *fp, int flags) __THROW; |
|
((__fp)->_wide_data->_IO_write_base \ |
|
= (__fp)->_wide_data->_IO_write_ptr = __p, \ |
|
(__fp)->_wide_data->_IO_write_end = (__ep)) |
|
-#define _IO_have_backup(fp) ((fp)->_IO_save_base != NULL) |
|
-#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_save_base != NULL) |
|
+#define _IO_have_backup(fp) ((fp)->_IO_backup_base != NULL) |
|
+#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_backup_base != NULL) |
|
#define _IO_in_backup(fp) ((fp)->_flags & _IO_IN_BACKUP) |
|
#define _IO_have_markers(fp) ((fp)->_markers != NULL) |
|
#define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base) |
|
diff --git a/stdio-common/Makefile b/stdio-common/Makefile |
|
index 08bedd01be61a55d..f10bf28878e0aebc 100644 |
|
--- a/stdio-common/Makefile |
|
+++ b/stdio-common/Makefile |
|
@@ -201,6 +201,7 @@ tests := \ |
|
tst-swscanf \ |
|
tst-tmpnam \ |
|
tst-ungetc \ |
|
+ tst-ungetc-leak \ |
|
tst-unlockedio \ |
|
tst-vfprintf-mbs-prec \ |
|
tst-vfprintf-user-type \ |
|
@@ -229,6 +230,7 @@ tests-special += \ |
|
$(objpfx)tst-printfsz-islongdouble.out \ |
|
$(objpfx)tst-setvbuf1-cmp.out \ |
|
$(objpfx)tst-unbputc.out \ |
|
+ $(objpfx)tst-ungetc-leak-mem.out \ |
|
$(objpfx)tst-vfprintf-width-prec-mem.out \ |
|
# tests-special |
|
|
|
@@ -243,6 +245,8 @@ generated += \ |
|
tst-printf-fp-leak-mem.out \ |
|
tst-printf-fp-leak.mtrace \ |
|
tst-scanf-bz27650.mtrace \ |
|
+ tst-ungetc-leak-mem.out \ |
|
+ tst-ungetc-leak.mtrace \ |
|
tst-vfprintf-width-prec-mem.out \ |
|
tst-vfprintf-width-prec.mtrace \ |
|
# generated |
|
@@ -288,6 +292,9 @@ tst-printf-fp-leak-ENV = \ |
|
tst-scanf-bz27650-ENV = \ |
|
MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.mtrace \ |
|
LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so |
|
+tst-ungetc-leak-ENV = \ |
|
+ MALLOC_TRACE=$(objpfx)tst-ungetc-leak.mtrace \ |
|
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so |
|
|
|
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc |
|
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \ |
|
diff --git a/stdio-common/tst-ungetc-leak.c b/stdio-common/tst-ungetc-leak.c |
|
new file mode 100644 |
|
index 0000000000000000..6c5152b43f80b217 |
|
--- /dev/null |
|
+++ b/stdio-common/tst-ungetc-leak.c |
|
@@ -0,0 +1,32 @@ |
|
+/* Test for memory leak with ungetc when stream is unused. |
|
+ 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 |
|
+ <https://www.gnu.org/licenses/>. */ |
|
+ |
|
+#include <stdio.h> |
|
+#include <mcheck.h> |
|
+#include <support/check.h> |
|
+#include <support/support.h> |
|
+ |
|
+static int |
|
+do_test (void) |
|
+{ |
|
+ mtrace (); |
|
+ TEST_COMPARE (ungetc('y', stdin), 'y'); |
|
+ return 0; |
|
+} |
|
+ |
|
+#include <support/test-driver.c>
|
|
|