{"id":2219443,"url":"http://patchwork.ozlabs.org/api/patches/2219443/?format=json","web_url":"http://patchwork.ozlabs.org/project/glibc/patch/20260403015721.343918-1-gaoxiang@kylinos.cn/","project":{"id":41,"url":"http://patchwork.ozlabs.org/api/projects/41/?format=json","name":"GNU C Library","link_name":"glibc","list_id":"libc-alpha.sourceware.org","list_email":"libc-alpha@sourceware.org","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260403015721.343918-1-gaoxiang@kylinos.cn>","list_archive_url":null,"date":"2026-04-03T01:57:21","name":"[v4] libio: Fix wide stream backup buffer leak on fclose [BZ #33999]","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"136fa9bae0ff9442fcf3be2366587643bd2a280d","submitter":{"id":92909,"url":"http://patchwork.ozlabs.org/api/people/92909/?format=json","name":"Gao Xiang","email":"gaoxiang@kylinos.cn"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/glibc/patch/20260403015721.343918-1-gaoxiang@kylinos.cn/mbox/","series":[{"id":498577,"url":"http://patchwork.ozlabs.org/api/series/498577/?format=json","web_url":"http://patchwork.ozlabs.org/project/glibc/list/?series=498577","date":"2026-04-03T01:57:21","name":"[v4] libio: Fix wide stream backup buffer leak on fclose [BZ #33999]","version":4,"mbox":"http://patchwork.ozlabs.org/series/498577/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2219443/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2219443/checks/","tags":{},"related":[],"headers":{"Return-Path":"<libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org>","X-Original-To":["incoming@patchwork.ozlabs.org","libc-alpha@sourceware.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","libc-alpha@sourceware.org"],"Authentication-Results":["legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n dmarc=none (p=none dis=none) header.from=kylinos.cn","sourceware.org; spf=pass smtp.mailfrom=kylinos.cn","server2.sourceware.org;\n arc=none smtp.remote-ip=124.126.103.232"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fn21S6tddz1yCs\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 03 Apr 2026 12:57:58 +1100 (AEDT)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id E74B74BA2E1A\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  3 Apr 2026 01:57:55 +0000 (GMT)","from mailgw.kylinos.cn (mailgw.kylinos.cn [124.126.103.232])\n by sourceware.org (Postfix) with ESMTPS id 4FF654BA2E14\n for <libc-alpha@sourceware.org>; Fri,  3 Apr 2026 01:57:33 +0000 (GMT)","from fedora [(183.242.174.22)] by mailgw.kylinos.cn\n (envelope-from <gaoxiang@kylinos.cn>)\n (Generic MTA with TLSv1.3 TLS_AES_256_GCM_SHA384 256/256)\n with ESMTP id 735260717; Fri, 03 Apr 2026 09:57:27 +0800"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org E74B74BA2E1A","OpenDKIM Filter v2.11.0 sourceware.org 4FF654BA2E14"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 4FF654BA2E14","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 4FF654BA2E14","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775181454; cv=none;\n b=EXYSN9Tqun7SxoTZelSqehYyncoIA1foRvaFISsVM0cy4T3E1TMN4pAK7FbgKwigVt8mwKcnU9JoSDHhPV+NKt7MFjK8WzumszYniRgVJWdfcJFog46Wkdu9nJUMpn/0yIgdOwzZPXLzATAAnQRIMLG3dTNRDfR/Hgxl4/XRCAI=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1775181454; c=relaxed/simple;\n bh=yCDxkSOKimN7QgFxmSE0yrgES2caE+QZl8T7Mlxs5Bg=;\n h=From:To:Subject:Date:Message-ID:MIME-Version;\n b=ng2VgbgwmZzAHajNi6l055N2/oE1xSsatWXs5C9CwxkgrT7pb7LVPYoGhUdIlIDNEMtG9Lh5KkJ6NW7G/I08Rc+/Wip6+w+YaKgjXpt6nc3M8LvQKOrj3yQt6gb2IeZ8rSL3sVyiLtU/is3op/sZ5FRBQDUTdGBzu/8hvzYM8dQ=","ARC-Authentication-Results":"i=1; server2.sourceware.org","X-UUID":["777d3ffe2f0011f1aa26b74ffac11d73-20260403","777d3ffe2f0011f1aa26b74ffac11d73-20260403"],"X-CTIC-Tags":"HR_CC_COUNT, HR_CC_DOMAIN_COUNT, HR_CC_NAME, HR_CC_NO_NAME,\n HR_CTE_8B\n HR_CTT_MISS, HR_DATE_H, HR_DATE_WKD, HR_DATE_ZONE, HR_FROM_NAME\n HR_SJ_DIGIT_LEN, HR_SJ_LANG, HR_SJ_LEN, HR_SJ_LETTER, HR_SJ_NOR_SYM\n HR_SJ_PHRASE, HR_SJ_PHRASE_LEN, HR_SJ_WS, HR_TO_COUNT, HR_TO_DOMAIN_COUNT\n HR_TO_NO_NAME, IP_TRUSTED, SRC_TRUSTED, DN_TRUSTED, SA_TRUSTED\n SA_EXISTED, SN_TRUSTED, SN_EXISTED, SPF_NOPASS, DKIM_NOPASS\n DMARC_NOPASS, UD_TRUSTED, CIE_BAD, CIE_GOOD, CIE_GOOD_SPF\n GTI_FG_BS, GTI_C_CI, GTI_FG_IT, GTI_RG_INFO, GTI_C_BU\n AMN_GOOD, ABX_BLACK, ABX_EXPLOIT, ABX_MISS_RDNS","X-CID-O-RULE":"Release_Ham","X-CID-RULE":"Release_Ham","X-CID-O-INFO":"VERSION:1.3.12, REQID:555ef820-4eb7-4103-93f8-e194f8272a31,\n IP:10,\n URL:0,TC:0,Content:0,EDM:25,RT:0,SF:-5,FILE:0,BULK:0,RULE:Release_Ham,ACTI\n ON:release,TS:30","X-CID-INFO":"VERSION:1.3.12, REQID:555ef820-4eb7-4103-93f8-e194f8272a31, IP:10,\n UR\n L:0,TC:0,Content:0,EDM:25,RT:0,SF:-5,FILE:0,BULK:0,RULE:Release_Ham,ACTION\n :release,TS:30","X-CID-META":"VersionHash:e7bac3a, CLOUDID:423fbf08067294ca74ad3496fd31d19c,\n BulkI\n D:260403095728NH1GQZNT,BulkQuantity:0,Recheck:0,SF:17|19|66|78|81|82|102|1\n 27|898,TC:nil,Content:0|15|50,EDM:5,IP:-2,URL:99|1,File:nil,RT:nil,Bulk:ni\n l,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE\n :0,ARC:0","X-CID-BVR":"2,SSN|SDN","X-CID-BAS":"2,SSN|SDN,0,_","X-CID-FACTOR":"TF_CID_SPAM_SNR,TF_CID_SPAM_FAS,TF_CID_SPAM_FSD,TF_CID_SPAM_ULS","X-CID-RHF":"D41D8CD98F00B204E9800998ECF8427E","X-User":"gaoxiang@kylinos.cn","From":"Gao Xiang <gaoxiang@kylinos.cn>","To":"schwab@suse.de","Cc":"libc-alpha@sourceware.org,\n\tXiang Gao <gaoxiang@kylinos.cn>","Subject":"[PATCH v4] libio: Fix wide stream backup buffer leak on fclose [BZ\n #33999]","Date":"Fri,  3 Apr 2026 09:57:21 +0800","Message-ID":"<20260403015721.343918-1-gaoxiang@kylinos.cn>","X-Mailer":"git-send-email 2.53.0","In-Reply-To":"<mvmo6k1bkb6.fsf@suse.de>","References":"<mvmo6k1bkb6.fsf@suse.de>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"libc-alpha@sourceware.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Libc-alpha mailing list <libc-alpha.sourceware.org>","List-Unsubscribe":"<https://sourceware.org/mailman/options/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=unsubscribe>","List-Archive":"<https://sourceware.org/pipermail/libc-alpha/>","List-Post":"<mailto:libc-alpha@sourceware.org>","List-Help":"<mailto:libc-alpha-request@sourceware.org?subject=help>","List-Subscribe":"<https://sourceware.org/mailman/listinfo/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=subscribe>","Errors-To":"libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org"},"content":"From: Xiang Gao <gaoxiang@kylinos.cn>\n\nThis patch fixes a memory leak when ungetwc is used on a wide oriented stream.\nThe backup buffer was never freed on fclose, causing a memory leak per\nungetwc/fclose call.\n\nThe leak has two causes:\n\nIn iofclose.c, for wide streams (fp->mode > 0), _IO_new_fclose never calls\n_IO_free_wbackup_area. Fixed by adding the missing call.\n\nIn wgenops.c, _IO_wdefault_finish checks fp->_IO_save_base (the narrow field,\nalways NULL for wide streams) instead of fp->_wide_data->_IO_save_base,\nand uses a bare free() that leaves _IO_save_end and _IO_backup_base dangling.\nReplace the hand-rolled cleanup with _IO_have_wbackup/_IO_free_wbackup_area,\nwhich handles backup-mode switching and clears all three pointers.\n\nThis was independently reported by Rocket Ma [1], whose patch corrects the condition\nbut still uses the manual free path.\n\nApply the same _IO_have_backup condition in genops.c for consistency.\n\nTested by:\n\"make test t=libio/*\" on x86_64-linux-gnu with no regressions.\n\n[1] https://patchwork.sourceware.org/project/glibc/patch/20260323171742.1039768-1-marocketbd@gmail.com/\n\nSigned-off-by: Xiang Gao <gaoxiang@kylinos.cn>\n---\nChanges since v3:\n - Add rewind(fp) before ungetwc() to properly switch from output\n   to input mode as suggested.\n---\n libio/Makefile           |  1 +\n libio/genops.c           |  7 ++----\n libio/iofclose.c         |  3 +++\n libio/tst-wbackup-leak.c | 52 ++++++++++++++++++++++++++++++++++++++++\n libio/wgenops.c          |  7 ++----\n 5 files changed, 60 insertions(+), 10 deletions(-)\n create mode 100644 libio/tst-wbackup-leak.c","diff":"diff --git a/libio/Makefile b/libio/Makefile\nindex 08e1e0ec25..93656466df 100644\n--- a/libio/Makefile\n+++ b/libio/Makefile\n@@ -135,6 +135,7 @@ tests = \\\n   tst-swscanf \\\n   tst-ungetwc1 \\\n   tst-ungetwc2 \\\n+  tst-wbackup-leak \\\n   tst-wfile-sync \\\n   tst-wfiledoallocate-static \\\n   tst-widetext \\\ndiff --git a/libio/genops.c b/libio/genops.c\nindex cc1684e00a..90e08e6571 100644\n--- a/libio/genops.c\n+++ b/libio/genops.c\n@@ -636,11 +636,8 @@ _IO_default_finish (FILE *fp, int dummy)\n   for (mark = fp->_markers; mark != NULL; mark = mark->_next)\n     mark->_sbuf = NULL;\n \n-  if (fp->_IO_save_base)\n-    {\n-      _IO_free_backup_buf (fp, fp->_IO_save_base);\n-      fp->_IO_save_base = NULL;\n-    }\n+  if (_IO_have_backup (fp))\n+    _IO_free_backup_area (fp);\n \n   _IO_un_link ((struct _IO_FILE_plus *) fp);\n \ndiff --git a/libio/iofclose.c b/libio/iofclose.c\nindex 89782e99d7..e250053446 100644\n--- a/libio/iofclose.c\n+++ b/libio/iofclose.c\n@@ -67,6 +67,9 @@ _IO_new_fclose (FILE *fp)\n   _IO_FINISH (fp);\n   if (fp->_mode > 0)\n     {\n+      if (_IO_have_wbackup (fp))\n+\t_IO_free_wbackup_area (fp);\n+\n       /* This stream has a wide orientation.  This means we have to free\n \t the conversion functions.  */\n       struct _IO_codecvt *cc = fp->_codecvt;\ndiff --git a/libio/tst-wbackup-leak.c b/libio/tst-wbackup-leak.c\nnew file mode 100644\nindex 0000000000..5629c22285\n--- /dev/null\n+++ b/libio/tst-wbackup-leak.c\n@@ -0,0 +1,52 @@\n+/* Test _IO_wdefault_finish frees wide backup buffer [BZ #33999].  */\n+\n+#include <malloc.h>\n+#include <stdio.h>\n+#include <wchar.h>\n+#include <support/check.h>\n+\n+static void\n+one_round (void)\n+{\n+  wchar_t *buf = NULL;\n+  size_t size = 0;\n+\n+  FILE *fp = open_wmemstream (&buf, &size);\n+  TEST_VERIFY_EXIT (fp != NULL);\n+  fputwc (L'A', fp);\n+  fflush (fp);\n+  /* Push back without prior read. rewind switches from output to\n+     input mode.  read_ptr == read_base, so _IO_wdefault_pbackfail\n+     skips the buggy narrow read_ptr access (BZ #33998) and goes\n+     straight to allocating a wide backup buffer at\n+     fp->_wide_data->_IO_save_base.\n+\n+     Note: this testcase relies on the fact that open_wmemstream\n+     does not set _IO_NO_READS on the stream.  If that implementation\n+     is changed, this test would need a different stream type to verify\n+     the leak.  */\n+  rewind (fp);\n+  ungetwc (L'Z', fp);\n+  fclose (fp);\n+  free (buf);\n+}\n+\n+static int\n+do_test (void)\n+{\n+  /* Warm up to stabilize allocator state.  */\n+  one_round ();\n+\n+  struct mallinfo2 before = mallinfo2 ();\n+  for (int i = 0; i < 1000; i++)\n+    one_round ();\n+  struct mallinfo2 after = mallinfo2 ();\n+\n+  /* Each leak is 128 * sizeof(wchar_t) = 512 bytes.\n+     1000 iterations would leak ~512 KB.  Allow 4 KB noise.  */\n+  TEST_VERIFY (after.uordblks - before.uordblks < 4096);\n+\n+  return 0;\n+}\n+\n+#include <support/test-driver.c>\ndiff --git a/libio/wgenops.c b/libio/wgenops.c\nindex 064d71266d..6829477e0c 100644\n--- a/libio/wgenops.c\n+++ b/libio/wgenops.c\n@@ -181,11 +181,8 @@ _IO_wdefault_finish (FILE *fp, int dummy)\n   for (mark = fp->_markers; mark != NULL; mark = mark->_next)\n     mark->_sbuf = NULL;\n \n-  if (fp->_IO_save_base)\n-    {\n-      free (fp->_wide_data->_IO_save_base);\n-      fp->_IO_save_base = NULL;\n-    }\n+  if (_IO_have_wbackup (fp))\n+    _IO_free_wbackup_area (fp);\n \n #ifdef _IO_MTSAFE_IO\n   if (fp->_lock != NULL)\n","prefixes":["v4"]}