00db10
From e4613df21e25e063d120ee23a650c65cd16df4be Mon Sep 17 00:00:00 2001
00db10
From: Stefan Liebler <stli@linux.vnet.ibm.com>
00db10
Date: Mon, 7 Nov 2016 17:30:22 +0100
00db10
Subject: [PATCH 16/17] Fix ucs4le_internal_loop in error case. [BZ #19726]
00db10
00db10
Upstream commit 8f25676c83eef5c85db98f9cf027890fbe810447
00db10
00db10
When converting from UCS4LE to INTERNAL, the input-value is checked for a too
00db10
large value and the iconv() call sets errno to EILSEQ. In this case the inbuf
00db10
argument of the iconv() call should point to the invalid character, but it
00db10
points to the beginning of the inbuf.
00db10
Thus this patch updates the pointers inptrp and outptrp before returning in
00db10
this error case.
00db10
00db10
This patch also adds a new testcase for this issue.
00db10
The new test was tested on a s390, power, intel machine.
00db10
00db10
ChangeLog:
00db10
00db10
	[BZ #19726]
00db10
	* iconv/gconv_simple.c (ucs4le_internal_loop): Update inptrp and
00db10
	outptrp in case of an illegal input.
00db10
	* iconv/tst-iconv6.c: New file.
00db10
	* iconv/Makefile (tests): Add tst-iconv6.
00db10
---
00db10
 iconv/Makefile       |   2 +-
00db10
 iconv/gconv_simple.c |   2 +
00db10
 iconv/tst-iconv6.c   | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++
00db10
 3 files changed, 120 insertions(+), 1 deletion(-)
00db10
 create mode 100644 iconv/tst-iconv6.c
00db10
00db10
diff --git a/iconv/Makefile b/iconv/Makefile
00db10
index 3e7f567..4d34c3f 100644
00db10
--- a/iconv/Makefile
00db10
+++ b/iconv/Makefile
00db10
@@ -43,7 +43,7 @@ CFLAGS-charmap.c = -DCHARMAP_PATH='"$(i18ndir)/charmaps"' \
00db10
 CFLAGS-linereader.c = -DNO_TRANSLITERATION
00db10
 CFLAGS-simple-hash.c = -I../locale
00db10
 
00db10
-tests	= tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5
00db10
+tests	= tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6
00db10
 
00db10
 others		= iconv_prog iconvconfig
00db10
 install-others-programs	= $(inst_bindir)/iconv
00db10
diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c
00db10
index 8697309..b9f846d 100644
00db10
--- a/iconv/gconv_simple.c
00db10
+++ b/iconv/gconv_simple.c
00db10
@@ -634,6 +634,8 @@ ucs4le_internal_loop (struct __gconv_step *step,
00db10
 	      continue;
00db10
 	    }
00db10
 
00db10
+	  *inptrp = inptr;
00db10
+	  *outptrp = outptr;
00db10
 	  return __GCONV_ILLEGAL_INPUT;
00db10
 	}
00db10
 
00db10
diff --git a/iconv/tst-iconv6.c b/iconv/tst-iconv6.c
00db10
new file mode 100644
00db10
index 0000000..57d7f38
00db10
--- /dev/null
00db10
+++ b/iconv/tst-iconv6.c
00db10
@@ -0,0 +1,117 @@
00db10
+/* Testing ucs4le_internal_loop() in gconv_simple.c.
00db10
+   Copyright (C) 2016 Free Software Foundation, Inc.
00db10
+   This file is part of the GNU C Library.
00db10
+
00db10
+   The GNU C Library is free software; you can redistribute it and/or
00db10
+   modify it under the terms of the GNU Lesser General Public
00db10
+   License as published by the Free Software Foundation; either
00db10
+   version 2.1 of the License, or (at your option) any later version.
00db10
+
00db10
+   The GNU C Library is distributed in the hope that it will be useful,
00db10
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
00db10
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00db10
+   Lesser General Public License for more details.
00db10
+
00db10
+   You should have received a copy of the GNU Lesser General Public
00db10
+   License along with the GNU C Library; if not, see
00db10
+   <http://www.gnu.org/licenses/>.  */
00db10
+
00db10
+#include <stdio.h>
00db10
+#include <errno.h>
00db10
+#include <string.h>
00db10
+#include <inttypes.h>
00db10
+#include <iconv.h>
00db10
+#include <byteswap.h>
00db10
+
00db10
+static int
00db10
+do_test (void)
00db10
+{
00db10
+  iconv_t cd;
00db10
+  char *inptr;
00db10
+  size_t inlen;
00db10
+  char *outptr;
00db10
+  size_t outlen;
00db10
+  size_t n;
00db10
+  int e;
00db10
+  int result = 0;
00db10
+
00db10
+#if __BYTE_ORDER == __BIG_ENDIAN
00db10
+  /* On big-endian machines, ucs4le_internal_loop() swaps the bytes before
00db10
+     error checking. Thus the input values has to be swapped.  */
00db10
+# define VALUE(val) bswap_32 (val)
00db10
+#else
00db10
+# define VALUE(val) val
00db10
+#endif
00db10
+  uint32_t inbuf[3] = { VALUE (0x41), VALUE (0x80000000), VALUE (0x42) };
00db10
+  uint32_t outbuf[3] = { 0, 0, 0 };
00db10
+
00db10
+  cd = iconv_open ("WCHAR_T", "UCS-4LE");
00db10
+  if (cd == (iconv_t) -1)
00db10
+    {
00db10
+      printf ("cannot convert from UCS4LE to wchar_t: %m\n");
00db10
+      return 1;
00db10
+    }
00db10
+
00db10
+  inptr = (char *) inbuf;
00db10
+  inlen = sizeof (inbuf);
00db10
+  outptr = (char *) outbuf;
00db10
+  outlen = sizeof (outbuf);
00db10
+
00db10
+  n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
00db10
+  e = errno;
00db10
+
00db10
+  if (n != (size_t) -1)
00db10
+    {
00db10
+      printf ("incorrect iconv() return value: %zd, expected -1\n", n);
00db10
+      result = 1;
00db10
+    }
00db10
+
00db10
+  if (e != EILSEQ)
00db10
+    {
00db10
+      printf ("incorrect error value: %s, expected %s\n",
00db10
+	      strerror (e), strerror (EILSEQ));
00db10
+      result = 1;
00db10
+    }
00db10
+
00db10
+  if (inptr != (char *) &inbuf[1])
00db10
+    {
00db10
+      printf ("inptr=0x%p does not point to invalid character! Expected=0x%p\n"
00db10
+	      , inptr, &inbuf[1]);
00db10
+      result = 1;
00db10
+    }
00db10
+
00db10
+  if (inlen != sizeof (inbuf) - sizeof (uint32_t))
00db10
+    {
00db10
+      printf ("inlen=%zd != %zd\n"
00db10
+	      , inlen, sizeof (inbuf) - sizeof (uint32_t));
00db10
+      result = 1;
00db10
+    }
00db10
+
00db10
+  if (outptr != (char *) &outbuf[1])
00db10
+    {
00db10
+      printf ("outptr=0x%p does not point to invalid character in inbuf! "
00db10
+	      "Expected=0x%p\n"
00db10
+	      , outptr, &outbuf[1]);
00db10
+      result = 1;
00db10
+    }
00db10
+
00db10
+  if (outlen != sizeof (inbuf) - sizeof (uint32_t))
00db10
+    {
00db10
+      printf ("outlen=%zd != %zd\n"
00db10
+	      , outlen, sizeof (outbuf) - sizeof (uint32_t));
00db10
+      result = 1;
00db10
+    }
00db10
+
00db10
+  if (outbuf[0] != 0x41 || outbuf[1] != 0 || outbuf[2] != 0)
00db10
+    {
00db10
+      puts ("Characters conversion is incorrect!");
00db10
+      result = 1;
00db10
+    }
00db10
+
00db10
+  iconv_close (cd);
00db10
+
00db10
+  return result;
00db10
+}
00db10
+
00db10
+#define TEST_FUNCTION do_test ()
00db10
+#include "../test-skeleton.c"
00db10
-- 
00db10
1.8.3.1
00db10