diff options
author | Stanislav Malyshev <stas@php.net> | 2015-05-08 00:03:54 -0700 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2015-05-09 18:54:40 -0700 |
commit | 473ec539a1c3d242c8b171dd6a5a98fa17e05c13 (patch) | |
tree | 3cee3463971709735b037dc12ca7527d2612a118 /ext/iconv | |
parent | 8026001943109dea3f908b8dd0720a0de9781af6 (diff) | |
download | php-git-473ec539a1c3d242c8b171dd6a5a98fa17e05c13.tar.gz |
Fix #48147 - implement manual handling of //IGNORE for broken libc
Conflicts:
ext/iconv/iconv.c
Diffstat (limited to 'ext/iconv')
-rw-r--r-- | ext/iconv/config.m4 | 39 | ||||
-rw-r--r-- | ext/iconv/iconv.c | 30 | ||||
-rw-r--r-- | ext/iconv/tests/bug48147.phpt | 27 |
3 files changed, 92 insertions, 4 deletions
diff --git a/ext/iconv/config.m4 b/ext/iconv/config.m4 index 10d21ccc6d..fce59931b9 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 12127d8c8f..5921d47597 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 0000000000..342f920093 --- /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) "" |