This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Re: [PATCH] fix iconv UCS-2BE/UCS-2LE unaligned access handling
- From: GOTO Masanori <gotom at debian dot or dot jp>
- To: Ulrich Drepper <drepper at redhat dot com>
- Cc: GOTO Masanori <gotom at debian dot or dot jp>, libc-alpha at sources dot redhat dot com
- Date: Mon, 28 Jun 2004 18:53:25 +0900
- Subject: Re: [PATCH] fix iconv UCS-2BE/UCS-2LE unaligned access handling
- References: <814qowmuoj.wl@omega.webmasters.gr.jp><40DF706F.7060109@redhat.com>
Hi,
At Sun, 27 Jun 2004 18:12:15 -0700,
Ulrich Drepper wrote:
> GOTO Masanori wrote:
> > The following __gconv_transform_*_* (UCS-2BE/UCS-2LE) cause unaligned
> > memory access exception when unaligned memory address is passed to
> > iconv(inbuf, outbuf) on _STRING_ARCH_unaligned=1 architectures:
>
> Write a test case which fails without the change.
Exactly, I should be care about adding test suite for checking.
Here's the patch adding test case. This test case gets unaligned
memory access trap/exception (ex: SIGBUS on Linux/Sparc) during
processing UCS-2BE and UCS-2LE.
Regards,
-- gotom
2004-06-28 GOTO Masanori <gotom@debian.or.jp>
* iconv/gconv_simple.c: Use get16/put16 for user given buffer
in ucs2/ucs2reverse when unaligned memory access is attempted.
* iconv/tst-iconv5.c: New file.
* iconv/Makefile (tests): Add tst-iconv5.
Index: iconv/Makefile
===================================================================
RCS file: /cvs/glibc/libc/iconv/Makefile,v
retrieving revision 1.33
diff -u -r1.33 Makefile
--- iconv/Makefile 11 Jun 2003 21:27:05 -0000 1.33
+++ iconv/Makefile 28 Jun 2004 07:22:54 -0000
@@ -49,7 +49,7 @@
CFLAGS-linereader.c = -DNO_TRANSLITERATION
CFLAGS-simple-hash.c = -I../locale
-tests = tst-iconv1 tst-iconv2 tst-iconv3
+tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv5
distribute = gconv_builtin.h gconv_int.h loop.c skeleton.c iconv_prog.h \
iconv_charmap.c dummy-repertoire.c gconv_charset.h strtab.c \
Index: iconv/gconv_simple.c
===================================================================
RCS file: /cvs/glibc/libc/iconv/gconv_simple.c,v
retrieving revision 1.64
diff -u -r1.64 gconv_simple.c
--- iconv/gconv_simple.c 15 Mar 2004 22:37:31 -0000 1.64
+++ iconv/gconv_simple.c 28 Jun 2004 07:22:55 -0000
@@ -1158,7 +1158,7 @@
#define LOOPFCT FROM_LOOP
#define BODY \
{ \
- uint16_t u1 = *((const uint16_t *) inptr); \
+ uint16_t u1 = get16 (inptr); \
\
if (__builtin_expect (u1 >= 0xd800 && u1 < 0xe000, 0)) \
{ \
@@ -1216,7 +1216,7 @@
} \
else \
{ \
- *((uint16_t *) outptr) = val; \
+ put16 (outptr, val); \
outptr += sizeof (uint16_t); \
inptr += 4; \
} \
@@ -1242,7 +1242,7 @@
#define LOOPFCT FROM_LOOP
#define BODY \
{ \
- uint16_t u1 = bswap_16 (*((const uint16_t *) inptr)); \
+ uint16_t u1 = bswap_16 (get16 (inptr)); \
\
if (__builtin_expect (u1 >= 0xd800 && u1 < 0xe000, 0)) \
{ \
@@ -1308,7 +1308,7 @@
} \
else \
{ \
- *((uint16_t *) outptr) = bswap_16 (val); \
+ put16 (outptr, bswap_16 (val)); \
outptr += sizeof (uint16_t); \
inptr += 4; \
} \
--- /dev/null 2004-06-26 20:05:20.000000000 +0900
+++ iconv/tst-iconv5.c 2004-06-28 16:20:20.000000000 +0900
@@ -0,0 +1,158 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by GOTO Masanori <gotom@debian.or.jp>, 2004
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <iconv.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define SIZE 256 /* enough room for conversion */
+#define SAMPLESTR "abc"
+
+struct unalign
+{
+ char str1[1];
+ char str2[SIZE];
+};
+
+struct convcode
+{
+ const char *tocode;
+ const char *fromcode;
+};
+
+/* test builtin transformation */
+struct convcode testcode[] = {
+ {"ASCII", "ASCII"},
+ {"UTF-8", "ASCII"},
+ {"UCS-2BE", "ASCII"},
+ {"UCS-2LE", "ASCII"},
+ {"UCS-4BE", "ASCII"},
+ {"UCS-4LE", "ASCII"},
+};
+
+int number = (int) sizeof (testcode) / sizeof (struct convcode);
+
+int
+convert (const char *tocode, const char *fromcode, char *inbufp,
+ size_t inbytesleft, char *outbufp, size_t outbytesleft)
+{
+ iconv_t *ic;
+ size_t outbytes = outbytesleft;
+ int ret;
+
+ ic = iconv_open (tocode, fromcode);
+ if (ic == (iconv_t *) - 1)
+ {
+ printf ("iconv_open failed: from: %s, to: %s: %s",
+ fromcode, tocode, strerror (errno));
+ return -1;
+ }
+
+ while (inbytesleft > 0)
+ {
+ ret = iconv (ic, &inbufp, &inbytesleft, &outbufp, &outbytes);
+ if (ret == -1)
+ {
+ printf ("iconv failed: from: %s, to: %s: %s",
+ fromcode, tocode, strerror (errno));
+ return -1;
+ }
+ }
+
+ ret = iconv_close (ic);
+ if (ret == -1)
+ {
+ printf ("iconv_close failed: from: %s, to: %s: %s",
+ fromcode, tocode, strerror (errno));
+ return -1;
+ }
+
+ return outbytesleft - outbytes;
+}
+
+
+int
+test_unalign (struct convcode *codes, char *str, int len)
+{
+ struct unalign *inbufp, *outbufp;
+ char *inbuf, *outbuf;
+ size_t inbytesleft, outbytesleft;
+ int retlen;
+
+ /* allocating unaligned buffer for both inbuf and outbuf */
+ inbufp = (struct unalign *) malloc (sizeof (struct unalign));
+ if (!inbufp)
+ {
+ printf ("no memory available\n");
+ exit (1);
+ }
+ inbuf = inbufp->str2;
+
+ outbufp = (struct unalign *) malloc (sizeof (struct unalign));
+ if (!outbufp)
+ {
+ printf ("no memory available\n");
+ exit (1);
+ }
+ outbuf = outbufp->str2;
+
+ /* first iconv phase */
+ memcpy (inbuf, str, len);
+ inbytesleft = len;
+ outbytesleft = sizeof (struct unalign);
+ retlen = convert (codes->tocode, codes->fromcode, inbuf, inbytesleft,
+ outbuf, outbytesleft);
+ if (retlen == -1) /* failed */
+ return 1;
+
+ /* second round trip iconv phase */
+ memcpy (inbuf, outbuf, retlen);
+ inbytesleft = retlen;
+ outbytesleft = sizeof (struct unalign);
+ retlen = convert (codes->fromcode, codes->tocode, inbuf, inbytesleft,
+ outbuf, outbytesleft);
+ if (retlen == -1) /* failed */
+ return 1;
+
+ free (inbufp);
+ free (outbufp);
+
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < number; i++)
+ {
+ ret = test_unalign (&testcode[i], (char *) SAMPLESTR, sizeof (SAMPLESTR));
+ if (ret)
+ break;
+ printf ("iconv: %s <-> %s: ok\n",
+ testcode[i].fromcode, testcode[i].tocode);
+ }
+ printf ("Succeeded.\n");
+
+ return ret;
+}