]> 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>
Fri, 8 May 2015 19:55:39 +0000 (12:55 -0700)
ext/iconv/config.m4
ext/iconv/iconv.c
ext/iconv/tests/bug48147.phpt [new file with mode: 0644]

index 88e5abf97e21f89b84a1a2f7d83ac8a32e65ab64..efde95e038f48205a077b6c8431b4b2fe3e4b824 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 35e4d943d5b7633909a2c33c4a00e46575cdc914..8042916c0dd98fd34ea6ce776cbe1ac03de2c271 100644 (file)
@@ -535,6 +535,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, zend_string **out, const char *out_charset, const char *in_charset)
@@ -613,6 +631,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
        size_t bsz, result = 0;
        php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
        zend_string *out_buf;
+       int ignore_ilseq = _php_check_ignore(out_charset);
 
        *out = NULL;
 
@@ -636,6 +655,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) ""