bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

wcrtomb: Work around bug on Android 4.3


From: Bruno Haible
Subject: wcrtomb: Work around bug on Android 4.3
Date: Sat, 26 Jan 2019 00:46:16 +0100
User-agent: KMail/5.1.3 (Linux/4.4.0-141-generic; KDE/5.18.0; x86_64; ; )

On Android 4.3, I'm seeing these test failures:


FAIL: test-snprintf-posix
=========================

../../gltests/test-snprintf-posix.h:2795: assertion 'memcmp (result, 
"abcdefgh", i) == 0' failed
FAIL test-snprintf-posix (exit status: 139)

FAIL: test-sprintf-posix
========================

../../gltests/test-sprintf-posix.h:2781: assertion 'memcmp (result, "abcdefgh", 
i) == 0' failed
FAIL test-sprintf-posix (exit status: 139)

FAIL: test-vsnprintf-posix
==========================

../../gltests/test-snprintf-posix.h:2795: assertion 'memcmp (result, 
"abcdefgh", i) == 0' failed
FAIL test-vsnprintf-posix (exit status: 139)

FAIL: test-vsprintf-posix
=========================

../../gltests/test-sprintf-posix.h:2781: assertion 'memcmp (result, "abcdefgh", 
i) == 0' failed
FAIL test-vsprintf-posix (exit status: 139)


The reason is that the wcrtomb() function is completely broken.
It converts, for example, the wide character L'a' to 0x01 (instead of 'a').
This patch provides a replacement wcrtomb().

Also, the tests of the wcrtomb module ought to have detected this bug.
Let me add tests for wcrtomb in the C locale (like Paul added tests for
mbrtowc in the C locale on 2016-04-09).


2019-01-25  Bruno Haible  <address@hidden>

        wcrtomb: Work around bug on Android 4.3.
        * m4/wcrtomb.m4 (gl_FUNC_WCRTOMB): Test also whether wcrtomb works in
        the C locale.
        * lib/wcrtomb.c (wcrtomb): Provide alternate implementation for Android,
        which does not have the 'wctomb' function.
        * doc/posix-functions/wcrtomb.texi: Mention the Android bug.
        * tests/test-wcrtomb.c (main): Accept argument '5'.
        * tests/test-wcrtomb.sh: Add tests in the POSIX locale.

diff --git a/doc/posix-functions/wcrtomb.texi b/doc/posix-functions/wcrtomb.texi
index e3e7b57..4bdc50e 100644
--- a/doc/posix-functions/wcrtomb.texi
+++ b/doc/posix-functions/wcrtomb.texi
@@ -12,6 +12,9 @@ Portability problems fixed by Gnulib:
 This function is missing on some platforms:
 Minix 3.1.8, HP-UX 11.00, IRIX 6.5, Solaris 2.6, mingw, Interix 3.5.
 @item
+This function produces wrong characters in the C locale on some platforms:
+Android 4.3.
address@hidden
 This function returns 0 when the first argument is NULL in some locales on 
some platforms:
 AIX 4.3, OSF/1 5.1, Solaris 11.3.
 @end itemize
diff --git a/lib/wcrtomb.c b/lib/wcrtomb.c
index 9fc40cf..8e56732 100644
--- a/lib/wcrtomb.c
+++ b/lib/wcrtomb.c
@@ -27,8 +27,8 @@
 size_t
 wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
 {
-  /* This implementation of wcrtomb on top of wctomb() supports only
-     stateless encodings.  ps must be in the initial state.  */
+  /* This implementation of wcrtomb supports only stateless encodings.
+     ps must be in the initial state.  */
   if (ps != NULL && !mbsinit (ps))
     {
       errno = EINVAL;
@@ -40,10 +40,21 @@ wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
     return 1;
   else
     {
+#if defined __ANDROID__
+      /* Implement consistently with mbrtowc(): through a 1:1 correspondence,
+         as in ISO-8859-1.  */
+      if (wc >= 0 && wc <= 0xff)
+        {
+          *s = (unsigned char) wc;
+          return 1;
+        }
+#else
+      /* Implement on top of wctomb().  */
       int ret = wctomb (s, wc);
 
       if (ret >= 0)
         return ret;
+#endif
       else
         {
           errno = EILSEQ;
diff --git a/m4/wcrtomb.m4 b/m4/wcrtomb.m4
index f4f37f5..fec22f3 100644
--- a/m4/wcrtomb.m4
+++ b/m4/wcrtomb.m4
@@ -1,4 +1,4 @@
-# wcrtomb.m4 serial 13
+# wcrtomb.m4 serial 14
 dnl Copyright (C) 2008-2019 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,7 +33,9 @@ AC_DEFUN([gl_FUNC_WCRTOMB],
   else
     if test $REPLACE_MBSTATE_T = 1; then
       REPLACE_WCRTOMB=1
-    else
+    fi
+    if test $REPLACE_WCRTOMB = 0; then
+      dnl On Android 4.3, wcrtomb produces wrong characters in the C locale.
       dnl On AIX 4.3, OSF/1 5.1 and Solaris <= 11.3, wcrtomb (NULL, 0, NULL)
       dnl sometimes returns 0 instead of 1.
       AC_REQUIRE([AC_PROG_CC])
@@ -42,6 +44,45 @@ AC_DEFUN([gl_FUNC_WCRTOMB],
       AC_REQUIRE([gt_LOCALE_JA])
       AC_REQUIRE([gt_LOCALE_ZH_CN])
       AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+      AC_CACHE_CHECK([whether wcrtomb works in the C locale],
+        [gl_cv_func_wcrtomb_works],
+        [AC_RUN_IFELSE(
+           [AC_LANG_SOURCE([[
+#include <string.h>
+#include <stdlib.h>
+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
+   <wchar.h>.
+   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
+   included before <wchar.h>.  */
+#include <stddef.h>
+#include <stdio.h>
+#include <wchar.h>
+int main ()
+{
+  mbstate_t state;
+  char out[64];
+  int count;
+  memset (&state, 0, sizeof (state));
+  out[0] = 'x';
+  count = wcrtomb (out, L'a', &state);
+  return !(count == 1 && out[0] == 'a');
+}]])],
+           [gl_cv_func_wcrtomb_works=yes],
+           [gl_cv_func_wcrtomb_works=no],
+           [case "$host_os" in
+                               # Guess no on Android.
+              linux*-android*) gl_cv_func_wcrtomb_works="guessing no";;
+                               # Guess yes otherwise.
+              *)               gl_cv_func_wcrtomb_works="guessing yes";;
+            esac
+           ])
+        ])
+      case "$gl_cv_func_wcrtomb_works" in
+        *yes) ;;
+        *) REPLACE_WCRTOMB=1 ;;
+      esac
+    fi
+    if test $REPLACE_WCRTOMB = 0; then
       AC_CACHE_CHECK([whether wcrtomb return value is correct],
         [gl_cv_func_wcrtomb_retval],
         [
diff --git a/tests/test-wcrtomb.c b/tests/test-wcrtomb.c
index c4baf38..2f0b64b 100644
--- a/tests/test-wcrtomb.c
+++ b/tests/test-wcrtomb.c
@@ -156,6 +156,10 @@ main (int argc, char *argv[])
           check_character (input + 3, 4);
         }
         return 0;
+
+      case '5':
+        /* C locale; tested above.  */
+        return 0;
       }
 
   return 1;
diff --git a/tests/test-wcrtomb.sh b/tests/test-wcrtomb.sh
index 3eda8f3..c183505 100755
--- a/tests/test-wcrtomb.sh
+++ b/tests/test-wcrtomb.sh
@@ -32,4 +32,8 @@ if test $LOCALE_ZH_CN != none; then
   || exit 1
 fi
 
+# Test in the POSIX locale.
+LC_ALL=C     ./test-wcrtomb${EXEEXT} 5 || exit 1
+LC_ALL=POSIX ./test-wcrtomb${EXEEXT} 5 || exit 1
+
 exit 0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]