From patchwork Thu Mar 24 13:16:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Schwab X-Patchwork-Id: 11500 Received: (qmail 30787 invoked by alias); 24 Mar 2016 13:16:21 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 27592 invoked by uid 89); 24 Mar 2016 13:16:20 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=sk:cflags, sk:cflags-, sk:CFLAGS-, sk:CFLAGS X-HELO: mx2.suse.de From: Andreas Schwab To: libc-alpha@sourceware.org Subject: [PATCH] Fix iconv error checks for UCS-4 conversions (bug 19726) X-Yow: I am NOT a nut.... Date: Thu, 24 Mar 2016 14:16:06 +0100 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) MIME-Version: 1.0 ucs4le_internal_loop failed to update the pointers when encountering an invalid input. Also, the unaligned versions of the ucs4(le) to internal conversions have a wrong range check. Tested on armv7l to cover the unaligned case. Andreas. [BZ #19726] * iconv/gconv_simple.c (ucs4le_internal_loop): Update *inptrp and *outptrp on error return. (ucs4_internal_loop_unaligned): Correct range check. (ucs4_internal_loop_single): Likewise. (ucs4le_internal_loop_unaligned): Likewise. (ucs4le_internal_loop_single): Likewise. * iconv/Makefile (tests): Add tst-iconv7. * iconv/tst-iconv7.c: New file. diff --git a/iconv/Makefile b/iconv/Makefile index c2299c9..30c8e83 100644 --- a/iconv/Makefile +++ b/iconv/Makefile @@ -42,7 +42,8 @@ CFLAGS-charmap.c = -DCHARMAP_PATH='"$(i18ndir)/charmaps"' \ CFLAGS-linereader.c = -DNO_TRANSLITERATION CFLAGS-simple-hash.c = -I../locale -tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 +tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 \ + tst-iconv7 others = iconv_prog iconvconfig install-others-programs = $(inst_bindir)/iconv diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c index cf93a16..0aa8115 100644 --- a/iconv/gconv_simple.c +++ b/iconv/gconv_simple.c @@ -313,7 +313,7 @@ ucs4_internal_loop_unaligned (struct __gconv_step *step, for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) { - if (__glibc_unlikely (inptr[0] > 0x80)) + if (__glibc_unlikely (inptr[0] > 0x7f)) { /* The value is too large. We don't try transliteration here since this is not an error because of the lack of possibilities to @@ -391,7 +391,7 @@ ucs4_internal_loop_single (struct __gconv_step *step, return __GCONV_INCOMPLETE_INPUT; } - if (__builtin_expect (((unsigned char *) state->__value.__wchb)[0] > 0x80, + if (__builtin_expect (((unsigned char *) state->__value.__wchb)[0] > 0x7f, 0)) { /* The value is too large. We don't try transliteration here since @@ -644,6 +644,8 @@ ucs4le_internal_loop (struct __gconv_step *step, continue; } + *inptrp = inptr; + *outptrp = outptr; return __GCONV_ILLEGAL_INPUT; } @@ -688,7 +690,7 @@ ucs4le_internal_loop_unaligned (struct __gconv_step *step, for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) { - if (__glibc_unlikely (inptr[3] > 0x80)) + if (__glibc_unlikely (inptr[3] > 0x7f)) { /* The value is too large. We don't try transliteration here since this is not an error because of the lack of possibilities to @@ -770,7 +772,7 @@ ucs4le_internal_loop_single (struct __gconv_step *step, return __GCONV_INCOMPLETE_INPUT; } - if (__builtin_expect (((unsigned char *) state->__value.__wchb)[3] > 0x80, + if (__builtin_expect (((unsigned char *) state->__value.__wchb)[3] > 0x7f, 0)) { /* The value is too large. We don't try transliteration here since diff --git a/iconv/tst-iconv7.c b/iconv/tst-iconv7.c new file mode 100644 index 0000000..341be49 --- /dev/null +++ b/iconv/tst-iconv7.c @@ -0,0 +1,97 @@ +/* Test iconv error checking with UCS-4 + Copyright (C) 2016 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 + . */ + +/* Derived from BZ #19726. */ +#include +#include +#include +#include +#include + +int +test_iconv (const char *test_name, + const char *incode, const char *outcode, char *input, size_t size) +{ + iconv_t cd = iconv_open (outcode, incode); + if (cd == (iconv_t) -1) + { + printf ("%s: iconv_open failed\n", test_name); + return 1; + } + + char *inptr = input; + size_t insize = size; + char output[size]; + char *outptr = output; + size_t outsize = size; + + size_t ret = iconv (cd, &inptr, &insize, &outptr, &outsize); + if (ret != (size_t) -1) + { + printf ("%s: iconv succeeded\n", test_name); + return 1; + } + if (errno != EILSEQ) + { + printf ("%s: iconv failed with %s\n", test_name, strerror (errno)); + return 1; + } + if (inptr != (char *) input + 4) + { + printf ("%s: iconv consumed %td characters\n", test_name, + inptr - (char *) input); + return 1; + } + + if (iconv_close (cd) == -1) + { + printf ("%s: iconv_close failed\n", test_name); + return 1; + } + return 0; +} + +int +do_test (void) +{ + int ret = 0; + uint32_t input[3]; + + memset (input, 0, sizeof (input)); + ((unsigned char *) input)[7] = 0x80; + ret |= test_iconv ("LE", "UCS-4LE", "UCS-4BE", (char *) input, + sizeof (input)); + memset (input, 0, sizeof (input)); + ((unsigned char *) input)[8] = 0x80; + ret |= test_iconv ("LE unaligned", "UCS-4LE", "UCS-4BE", (char *) input + 1, + sizeof (input)); + + memset (input, 0, sizeof (input)); + ((unsigned char *) input)[4] = 0x80; + ret |= test_iconv ("BE", "UCS-4BE", "UCS-4LE", (char *) input, + sizeof (input)); + memset (input, 0, sizeof (input)); + ((unsigned char *) input)[5] = 0x80; + ret |= test_iconv ("BE unaligned", "UCS-4BE", "UCS-4LE", (char *) input + 1, + sizeof (input)); + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c"