com php-src: Fix #48147 - implement manual handling of //IGNORE for broken libc: NEWS ext/iconv/config.m4 ext/iconv/iconv.c
ext/iconv/tests/bug48147.phpt
| From: | Stanislav Malyshev | Date: | Sun, 10 May 2015 01:54:40 +0000 |
| Subject: | com php-src: Fix #48147 - implement manual handling of //IGNORE for broken libc: NEWS ext/iconv/config.m4 ext/iconv/iconv.c ext/iconv/tests/bug48147.phpt |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-86659@lists.php.net to get a copy of this message | ||
Commit: 473ec539a1c3d242c8b171dd6a5a98fa17e05c13
Author: Stanislav Malyshev <stas@php.net> Fri, 8 May 2015 00:03:54 -0700
Parents: 8026001943109dea3f908b8dd0720a0de9781af6
Branches: PHP-5.5 PHP-5.6 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=473ec539a1c3d242c8b171dd6a5a98fa17e05c13
Log:
Fix #48147 - implement manual handling of //IGNORE for broken libc
Conflicts:
ext/iconv/iconv.c
Bugs:
https://bugs.php.net/48147
Changed paths:
M NEWS
M ext/iconv/config.m4
M ext/iconv/iconv.c
A ext/iconv/tests/bug48147.phpt
Diff:
diff --git a/NEWS b/NEWS
index 2e0b8b1..9f843c7 100644
--- 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)
diff --git a/ext/iconv/config..m4 b/ext/iconv/config.m4
index 10d21cc..fce5993 100644
--- a/ext/iconv/config.m4
+++ b/ext/iconv/config.m4
@@ -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>
diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c
index 12127d8..5921d47 100644
--- a/ext/iconv/iconv.c
+++ b/ext/iconv/iconv.c
@@ -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
index 0000000..342f920
--- /dev/null
+++ b/ext/iconv/tests/bug48147.phpt
@@ -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) ""