summaryrefslogtreecommitdiff
path: root/ungetc-Fix-backup-buffer-leak-on-program-exit-BZ-278.patch
diff options
context:
space:
mode:
Diffstat (limited to 'ungetc-Fix-backup-buffer-leak-on-program-exit-BZ-278.patch')
-rw-r--r--ungetc-Fix-backup-buffer-leak-on-program-exit-BZ-278.patch145
1 files changed, 145 insertions, 0 deletions
diff --git a/ungetc-Fix-backup-buffer-leak-on-program-exit-BZ-278.patch b/ungetc-Fix-backup-buffer-leak-on-program-exit-BZ-278.patch
new file mode 100644
index 0000000..9faa58c
--- /dev/null
+++ b/ungetc-Fix-backup-buffer-leak-on-program-exit-BZ-278.patch
@@ -0,0 +1,145 @@
+From b9f72bd5de931eac39219018c2fa319a449bb2cf Mon Sep 17 00:00:00 2001
+From: Siddhesh Poyarekar <siddhesh@sourceware.org>
+Date: Tue, 13 Aug 2024 21:08:49 -0400
+Subject: [PATCH] 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)
+---
+ libio/genops.c | 6 ++++++
+ libio/libioP.h | 4 ++--
+ stdio-common/Makefile | 7 +++++++
+ stdio-common/tst-ungetc-leak.c | 32 ++++++++++++++++++++++++++++++++
+ 4 files changed, 47 insertions(+), 2 deletions(-)
+ create mode 100644 stdio-common/tst-ungetc-leak.c
+
+diff --git a/libio/genops.c b/libio/genops.c
+index c673c0acec..fb06245467 100644
+--- a/libio/genops.c
++++ b/libio/genops.c
+@@ -789,6 +789,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 745278e076..e75ee770bc 100644
+--- a/libio/libioP.h
++++ b/libio/libioP.h
+@@ -577,8 +577,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 2bcbaf754a..381040570b 100644
+--- a/stdio-common/Makefile
++++ b/stdio-common/Makefile
+@@ -256,6 +256,7 @@ tests := \
+ tst-swscanf \
+ tst-tmpnam \
+ tst-ungetc \
++ tst-ungetc-leak \
+ tst-unlockedio \
+ tst-vfprintf-mbs-prec \
+ tst-vfprintf-user-type \
+@@ -300,6 +301,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
+
+@@ -314,6 +316,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
+@@ -403,6 +407,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 0000000000..6c5152b43f
+--- /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>
+--
+2.33.0
+