Skip to content

Commit a7bbfc9

Browse files
committed
Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3: Fix #79200: Some iconv functions cut Windows-1258
2 parents 4576da0 + 32a2644 commit a7bbfc9

File tree

3 files changed

+68
-38
lines changed

3 files changed

+68
-38
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ PHP NEWS
1414
. Fixed bug #79396 (DateTime hour incorrect during DST jump forward). (Nate
1515
Brunette)
1616

17+
- Iconv:
18+
. Fixed bug #79200 (Some iconv functions cut Windows-1258). (cmb)
19+
1720
- SimpleXML:
1821
. Fixed bug #61597 (SXE properties may lack attributes and content). (cmb)
1922

ext/iconv/iconv.c

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ static php_iconv_err_t _php_iconv_strlen(size_t *pretval, const char *str, size_
724724
size_t out_left;
725725

726726
size_t cnt;
727+
int more;
727728

728729
*pretval = (size_t)-1;
729730

@@ -743,25 +744,23 @@ static php_iconv_err_t _php_iconv_strlen(size_t *pretval, const char *str, size_
743744

744745
errno = 0;
745746
out_left = 0;
747+
more = nbytes > 0;
746748

747-
for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0; cnt+=2) {
748-
size_t prev_in_left;
749+
for (in_p = str, in_left = nbytes, cnt = 0; more;) {
749750
out_p = buf;
750751
out_left = sizeof(buf);
751752

752-
prev_in_left = in_left;
753+
more = in_left > 0;
753754

754-
if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
755-
if (prev_in_left == in_left) {
756-
break;
757-
}
755+
iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left);
756+
if (out_left == sizeof(buf)) {
757+
break;
758+
} else {
759+
ZEND_ASSERT((sizeof(buf) - out_left) % GENERIC_SUPERSET_NBYTES == 0);
760+
cnt += (sizeof(buf) - out_left) / GENERIC_SUPERSET_NBYTES;
758761
}
759762
}
760763

761-
if (out_left > 0) {
762-
cnt -= out_left / GENERIC_SUPERSET_NBYTES;
763-
}
764-
765764
#if ICONV_SUPPORTS_ERRNO
766765
switch (errno) {
767766
case EINVAL:
@@ -810,6 +809,7 @@ static php_iconv_err_t _php_iconv_substr(smart_str *pretval,
810809

811810
size_t cnt;
812811
size_t total_len;
812+
int more;
813813

814814
err = _php_iconv_strlen(&total_len, str, nbytes, enc);
815815
if (err != PHP_ICONV_ERR_SUCCESS) {
@@ -864,18 +864,17 @@ static php_iconv_err_t _php_iconv_substr(smart_str *pretval,
864864

865865
cd2 = (iconv_t)NULL;
866866
errno = 0;
867+
more = nbytes > 0 && len > 0;
867868

868-
for (in_p = str, in_left = nbytes, cnt = 0; in_left > 0 && len > 0; ++cnt) {
869-
size_t prev_in_left;
869+
for (in_p = str, in_left = nbytes, cnt = 0; more; ++cnt) {
870870
out_p = buf;
871871
out_left = sizeof(buf);
872872

873-
prev_in_left = in_left;
873+
more = in_left > 0 && len > 0;
874874

875-
if (iconv(cd1, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
876-
if (prev_in_left == in_left) {
877-
break;
878-
}
875+
iconv(cd1, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left);
876+
if (out_left == sizeof(buf)) {
877+
break;
879878
}
880879

881880
if ((zend_long)cnt >= offset) {
@@ -963,6 +962,8 @@ static php_iconv_err_t _php_iconv_strpos(size_t *pretval,
963962
size_t ndl_buf_left;
964963

965964
size_t match_ofs;
965+
int more;
966+
size_t iconv_ret;
966967

967968
*pretval = (size_t)-1;
968969

@@ -995,37 +996,38 @@ static php_iconv_err_t _php_iconv_strpos(size_t *pretval,
995996
ndl_buf_p = ZSTR_VAL(ndl_buf);
996997
ndl_buf_left = ZSTR_LEN(ndl_buf);
997998
match_ofs = (size_t)-1;
999+
more = haystk_nbytes > 0;
9981000

999-
for (in_p = haystk, in_left = haystk_nbytes, cnt = 0; in_left > 0; ++cnt) {
1000-
size_t prev_in_left;
1001+
for (in_p = haystk, in_left = haystk_nbytes, cnt = 0; more; ++cnt) {
10011002
out_p = buf;
10021003
out_left = sizeof(buf);
10031004

1004-
prev_in_left = in_left;
1005+
more = in_left > 0;
10051006

1006-
if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
1007-
if (prev_in_left == in_left) {
1007+
iconv_ret = iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left);
1008+
if (out_left == sizeof(buf)) {
1009+
break;
1010+
}
10081011
#if ICONV_SUPPORTS_ERRNO
1009-
switch (errno) {
1010-
case EINVAL:
1011-
err = PHP_ICONV_ERR_ILLEGAL_CHAR;
1012-
break;
1012+
if (iconv_ret == (size_t)-1) {
1013+
switch (errno) {
1014+
case EINVAL:
1015+
err = PHP_ICONV_ERR_ILLEGAL_CHAR;
1016+
break;
10131017

1014-
case EILSEQ:
1015-
err = PHP_ICONV_ERR_ILLEGAL_SEQ;
1016-
break;
1018+
case EILSEQ:
1019+
err = PHP_ICONV_ERR_ILLEGAL_SEQ;
1020+
break;
10171021

1018-
case E2BIG:
1019-
break;
1022+
case E2BIG:
1023+
break;
10201024

1021-
default:
1022-
err = PHP_ICONV_ERR_UNKNOWN;
1023-
break;
1024-
}
1025-
#endif
1026-
break;
1025+
default:
1026+
err = PHP_ICONV_ERR_UNKNOWN;
1027+
break;
10271028
}
10281029
}
1030+
#endif
10291031
if (offset >= 0) {
10301032
if (cnt >= (size_t)offset) {
10311033
if (_php_iconv_memequal(buf, ndl_buf_p, sizeof(buf))) {
@@ -1997,6 +1999,13 @@ static php_iconv_err_t _php_iconv_mime_decode(smart_str *pretval, const char *st
19971999
*next_pos = p1;
19982000
}
19992001

2002+
if (cd != (iconv_t)(-1)) {
2003+
_php_iconv_appendl(pretval, NULL, 0, cd);
2004+
}
2005+
if (cd_pl != (iconv_t)(-1)) {
2006+
_php_iconv_appendl(pretval, NULL, 0, cd_pl);
2007+
}
2008+
20002009
smart_str_0(pretval);
20012010
out:
20022011
if (cd != (iconv_t)(-1)) {

ext/iconv/tests/bug79200.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Bug #79200 (Some iconv functions cut Windows-1258)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('iconv')) die('skip iconv extension not available');
6+
?>
7+
--FILE--
8+
<?php
9+
var_dump(iconv_mime_decode('=?windows-1258?Q?test=20test?=', 0, 'UTF-8'));
10+
var_dump(iconv_strlen('test test', 'WINDOWS-1258'));
11+
var_dump(iconv_strpos('test test', 'test test', 0, 'WINDOWS-1258'));
12+
var_dump(iconv_substr('test test', 0 , 9, 'WINDOWS-1258'));
13+
?>
14+
--EXPECT--
15+
string(9) "test test"
16+
int(9)
17+
int(0)
18+
string(9) "test test"

0 commit comments

Comments
 (0)