]> granicus.if.org Git - php/commitdiff
Fix #48147 - implement manual handling of //IGNORE for broken libc
authorStanislav Malyshev <stas@php.net>
Fri, 8 May 2015 07:03:54 +0000 (00:03 -0700)
committerStanislav Malyshev <stas@php.net>
Sun, 10 May 2015 01:54:40 +0000 (18:54 -0700)
Conflicts:
ext/iconv/iconv.c

NEWS
ext/iconv/config.m4
ext/iconv/iconv.c
ext/iconv/tests/bug48147.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 2e0b8b1ecf4edb8ed9a6abeb2c06ca64a9a82a9e..9f843c718c5ce2354952e3814e27bd5a2691de12 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,9 @@ PHP                                                                        NEWS
   . Fixed bug #69566 (Conditional jump or move depends on uninitialised value
     in extension trait). (jbboehr at gmail dot com)
 
+- Iconv:
+  . Fixed bug #48147 (iconv with //IGNORE cuts the string). (Stas)
+
 - Opcache
   . Fixed bug #69549 (Memory leak with opcache.optimization_level=0xFFFFFFFF).
     (Laruence, Dmitry)
index 10d21ccc6de6dc157089be21b029ba30a22a47f7..fce59931b9505ed7b18712340b6e996920c13cf6 100644 (file)
@@ -35,7 +35,7 @@ if test "$PHP_ICONV" != "no"; then
       PHP_ICONV_H_PATH="$PHP_ICONV_PREFIX/include/giconv.h"
     else
       PHP_ICONV_H_PATH="$PHP_ICONV_PREFIX/include/iconv.h"
-    fi 
+       fi
 
     AC_MSG_CHECKING([if iconv is glibc's])
     AC_TRY_LINK([#include <gnu/libc-version.h>],[gnu_get_libc_version();],
@@ -53,8 +53,8 @@ if test "$PHP_ICONV" != "no"; then
       AC_TRY_RUN([
 #include <$PHP_ICONV_H_PATH>
 int main() {
-       printf("%d", _libiconv_version);
-       return 0;
+  printf("%d", _libiconv_version);
+  return 0;
 }
       ],[
         AC_MSG_RESULT(yes)
@@ -138,7 +138,7 @@ int main() {
   if (cd == (iconv_t)(-1)) {
     if (errno == EINVAL) {
       return 0;
-       } else {
+  } else {
       return 1;
     }
   }
@@ -159,6 +159,37 @@ int main() {
       AC_DEFINE([ICONV_SUPPORTS_ERRNO],0,[Whether iconv supports error no or not])
     ])
 
+    AC_MSG_CHECKING([if iconv supports //IGNORE])
+    AC_TRY_RUN([
+#include <$PHP_ICONV_H_PATH>
+#include <stdlib.h>
+
+int main() {
+  iconv_t cd = iconv_open( "UTF-8//IGNORE", "UTF-8" );
+  char *in_p = "\xC3\xC3\xC3\xB8";
+  size_t in_left = 4, out_left = 4096;
+  char *out = malloc(out_left);
+  char *out_p = out;
+  size_t result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
+  if(result == (size_t)-1) {
+    return 1;
+  }
+  return 0;
+}
+   ],[
+      AC_MSG_RESULT(yes)
+      PHP_DEFINE([ICONV_BROKEN_IGNORE],0,[ext/iconv])
+      AC_DEFINE([ICONV_BROKEN_IGNORE],0,[Whether iconv supports IGNORE])
+    ],[
+      AC_MSG_RESULT(no)
+      PHP_DEFINE([ICONV_BROKEN_IGNORE],1,[ext/iconv])
+      AC_DEFINE([ICONV_BROKEN_IGNORE],1,[Whether iconv supports IGNORE])
+    ],[
+      AC_MSG_RESULT(no, cross-compiling)
+      PHP_DEFINE([ICONV_SUPPORTS_ERRNO],0,[ext/iconv])
+      AC_DEFINE([ICONV_SUPPORTS_ERRNO],0,[Whether iconv supports IGNORE])
+    ])
+
     AC_MSG_CHECKING([if your cpp allows macro usage in include lines])
     AC_TRY_COMPILE([
 #define FOO <$PHP_ICONV_H_PATH>
index 12127d8c8fd328cc32b1d28f096a4fa915f338a6..5921d475979a7fa076d8d24566e84ecb51ff8dcf 100644 (file)
@@ -464,6 +464,24 @@ static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd
 }
 /* }}} */
 
+/* {{{ */
+#if ICONV_BROKEN_IGNORE
+static int _php_check_ignore(const char *charset)
+{
+  size_t clen = strlen(charset);
+  if (clen >= 9 && strcmp("//IGNORE", charset+clen-8) == 0) {
+    return 1;
+  }
+  if (clen >= 19 && strcmp("//IGNORE//TRANSLIT", charset+clen-18) == 0) {
+    return 1;
+  }
+  return 0;
+}
+#else
+#define _php_check_ignore(x) (0)
+#endif
+/* }}} */
+
 /* {{{ php_iconv_string()
  */
 PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
@@ -545,6 +563,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
        char *out_p, *out_buf, *tmp_buf;
        size_t bsz, result = 0;
        php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
+       int ignore_ilseq = _php_check_ignore(out_charset);
 
        *out = NULL;
        *out_len = 0;
@@ -569,6 +588,17 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
                result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
                out_size = bsz - out_left;
                if (result == (size_t)(-1)) {
+                       if (ignore_ilseq && errno == EILSEQ) {
+                               if (in_left <= 1) {
+                                       result = 0;
+                               } else {
+                                       errno = 0;
+                                       in_p++;
+                                       in_left--;
+                                       continue;
+                               }
+                       }
+
                        if (errno == E2BIG && in_left > 0) {
                                /* converted string is longer than out buffer */
                                bsz += in_len;
diff --git a/ext/iconv/tests/bug48147.phpt b/ext/iconv/tests/bug48147.phpt
new file mode 100644 (file)
index 0000000..342f920
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+Bug #48147 (iconv with //IGNORE cuts the string)
+--SKIPIF--
+<?php extension_loaded('iconv') or die('skip iconv extension is not available'); ?>
+--FILE--
+<?php
+$text = "aa\xC3\xC3\xC3\xB8aa";
+var_dump(iconv("UTF-8", "UTF-8", $text));
+var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", $text)));
+// only invalid
+var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "\xC3")));
+// start invalid
+var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "\xC3\xC3\xC3\xB8aa")));
+// finish invalid
+var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "aa\xC3\xC3\xC3")));
+?>
+--EXPECTF--
+Notice: iconv(): Detected an illegal character in input string in %s on line %d
+bool(false)
+string(10) "aa%C3%B8aa"
+
+Notice: iconv(): Detected an incomplete multibyte character in input string in %s on line %d
+string(0) ""
+string(8) "%C3%B8aa"
+
+Notice: iconv(): Detected an incomplete multibyte character in input string in %s on line %d
+string(0) ""