[PATCH 2/2] iconvdata: Test case for bug 34556

Florian Weimer <[email protected]>
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <a84ddf0c310b16fed6898412e2409a91b57d2f65.1787307116.git.fweimer@redhat.com>
Assisted-by: LLM
---
 iconvdata/Makefile                      |   5 +-
 iconvdata/tst-shift-jisx0213-progress.c | 118 ++++++++++++++++++++++++
 2 files changed, 122 insertions(+), 1 deletion(-)
 create mode 100644 iconvdata/tst-shift-jisx0213-progress.c

diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index fbb0067302..7343350a9a 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -76,7 +76,8 @@ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
 	tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
 	bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
 	bug-iconv13 bug-iconv14 bug-iconv15 \
-	tst-iconv-iso-2022-cn-ext tst-bug33980
+	tst-iconv-iso-2022-cn-ext tst-bug33980 \
+	tst-shift-jisx0213-progress
 ifeq ($(have-thread-library),yes)
 tests += bug-iconv3
 endif
@@ -335,6 +336,8 @@ $(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules))
 					$(addprefix $(objpfx),$(modules.so))
 $(objpfx)tst-bug33980.out: $(addprefix $(objpfx), $(gconv-modules)) \
 			   $(addprefix $(objpfx),$(modules.so))
+$(objpfx)tst-shift-jisx0213-progress.out: \
+  $(addprefix $(objpfx), $(gconv-modules)) $(addprefix $(objpfx),$(modules.so))
 
 $(objpfx)iconv-test.out: run-iconv-test.sh \
 			 $(addprefix $(objpfx), $(gconv-modules)) \
diff --git a/iconvdata/tst-shift-jisx0213-progress.c b/iconvdata/tst-shift-jisx0213-progress.c
new file mode 100644
index 0000000000..264b7141f5
--- /dev/null
+++ b/iconvdata/tst-shift-jisx0213-progress.c
@@ -0,0 +1,118 @@
+/* Test SHIFT_JISX0213 combining character conversion progress (bug 34556).
+   Copyright (C) 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/>.  */
+
+/* SHIFT_JISX0213 bytes 0x82 0xF5 map to a combining sequence:
+   U+304B (HIRAGANA LETTER KA) + U+309A (COMBINING SEMI-VOICED SOUND
+   MARK).  When converting to UTF-32LE with a small output buffer, the
+   first code point is emitted and the second is queued in the
+   converter state.  This test verifies that the queued code point is
+   consumed exactly once on retry, so that the conversion makes
+   progress and terminates.  */
+
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/support.h>
+
+static void
+test_one (size_t outbufsize)
+{
+  /* Combining sequence followed by a plain ASCII character.  */
+  char input[] = { '\x82', '\xf5', 'A' };
+
+  /* Expected UTF-32 output.  */
+  static const wchar_t expected[] = { 0x304b, 0x309a, 'A' };
+
+  iconv_t cd = iconv_open ("WCHAR_T", "SHIFT_JISX0213");
+  TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+  char result[64];
+  size_t result_len = 0;
+
+  char *inptr = input;
+  size_t inleft = sizeof (input);
+
+  char outbuf[64];
+
+  int iterations = 0;
+  while (inleft > 0)
+    {
+      char *outptr = outbuf;
+      size_t outleft = outbufsize;
+      size_t inleft_before = inleft;
+
+      size_t ret = iconv (cd, &inptr, &inleft, &outptr, &outleft);
+      size_t produced = outptr - outbuf;
+
+      TEST_VERIFY_EXIT (result_len + produced <= sizeof (result));
+      memcpy (result + result_len, outbuf, produced);
+      result_len += produced;
+
+      if (ret == (size_t) -1 && errno == E2BIG)
+	{
+	  if (produced == 0 && inleft == inleft_before)
+	    {
+	      /* Output buffer too small for a single code point.  */
+	      TEST_VERIFY_EXIT (outbufsize < 4);
+	      break;
+	    }
+	  /* Bound iterations to detect non-progress bugs.  */
+	  TEST_VERIFY_EXIT (++iterations < 10);
+	  continue;
+	}
+      if (ret == (size_t) -1)
+	FAIL_EXIT1 ("outbufsize %zu: iconv: %m", outbufsize);
+      break;
+    }
+
+  /* Flush pending converter state.  */
+  {
+    char *outptr = outbuf;
+    size_t outleft = outbufsize;
+    size_t ret = iconv (cd, NULL, NULL, &outptr, &outleft);
+    TEST_VERIFY (ret == 0);
+    size_t produced = outptr - outbuf;
+    memcpy (result + result_len, outbuf, produced);
+    result_len += produced;
+  }
+
+  if (outbufsize >= 4)
+    {
+      TEST_COMPARE (inleft, 0);
+      TEST_COMPARE_BLOB (result, result_len,
+			 expected, sizeof (expected));
+    }
+
+  TEST_VERIFY_EXIT (iconv_close (cd) == 0);
+}
+
+static int
+do_test (void)
+{
+  for (size_t outbufsize = 1; outbufsize <= 16; outbufsize++)
+    {
+      printf ("info: testing output buffer size %zu\n", outbufsize);
+      test_one (outbufsize);
+    }
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.