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