Skip to content

Commit 587ae73

Browse files
committed
Imply UTF8 validity in implode function
1 parent 9584939 commit 587ae73

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

Zend/zend_string.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ static zend_always_inline zend_string *zend_string_dup(zend_string *s, bool pers
241241
if (ZSTR_IS_INTERNED(s)) {
242242
return s;
243243
} else {
244-
return zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent);
244+
zend_string *res = zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent);
245+
ZSTR_COPY_CONCAT_PROPERTIES(res, s);
246+
return res;
245247
}
246248
}
247249

ext/standard/string.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,11 +955,14 @@ PHPAPI void php_implode(const zend_string *glue, HashTable *pieces, zval *return
955955

956956
ptr = strings = do_alloca((sizeof(*strings)) * numelems, use_heap);
957957

958+
uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(glue);
959+
958960
ZEND_HASH_FOREACH_VAL(pieces, tmp) {
959961
if (EXPECTED(Z_TYPE_P(tmp) == IS_STRING)) {
960962
ptr->str = Z_STR_P(tmp);
961963
len += ZSTR_LEN(ptr->str);
962964
ptr->lval = 0;
965+
flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(ptr->str);
963966
ptr++;
964967
} else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_LONG)) {
965968
zend_long val = Z_LVAL_P(tmp);
@@ -978,12 +981,14 @@ PHPAPI void php_implode(const zend_string *glue, HashTable *pieces, zval *return
978981
ptr->str = zval_get_string_func(tmp);
979982
len += ZSTR_LEN(ptr->str);
980983
ptr->lval = 1;
984+
flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(ptr->str);
981985
ptr++;
982986
}
983987
} ZEND_HASH_FOREACH_END();
984988

985989
/* numelems cannot be 0, we checked above */
986990
str = zend_string_safe_alloc(numelems - 1, ZSTR_LEN(glue), len, 0);
991+
GC_ADD_FLAGS(str, flags);
987992
cptr = ZSTR_VAL(str) + ZSTR_LEN(str);
988993
*cptr = 0;
989994

ext/zend_test/tests/strings_marked_as_utf8.phpt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,33 @@ $string = "\xff";
115115
$string_concat = str_repeat($string, 100);
116116
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
117117

118+
echo "implode:\n";
119+
$arr = ['a', 'b'];
120+
$string_concat = implode('', $arr);
121+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
122+
$string_concat = implode('|', $arr);
123+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
124+
$string_concat = implode('', ['c', ...$arr]);
125+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
126+
$string_concat = implode('', [...$arr, 'c']);
127+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
128+
$string_concat = implode('', ["\xff", ...$arr]);
129+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
130+
$string_concat = implode('', [...$arr, "\xff"]);
131+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
132+
$string_concat = implode("\xff", $arr);
133+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
134+
$string_concat = implode('', []);
135+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
136+
$string_concat = implode("\xff", []);
137+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
138+
$string_concat = implode('', ['a']);
139+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
140+
$string_concat = implode("\xff", ['a']);
141+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
142+
$string_concat = implode('', [1, 1.0, 'a']);
143+
var_dump(zend_test_is_string_marked_as_valid_utf8($string_concat));
144+
118145
?>
119146
--EXPECT--
120147
Empty strings:
@@ -159,3 +186,16 @@ bool(true)
159186
str_repeat:
160187
bool(true)
161188
bool(false)
189+
implode:
190+
bool(true)
191+
bool(true)
192+
bool(true)
193+
bool(true)
194+
bool(false)
195+
bool(false)
196+
bool(false)
197+
bool(true)
198+
bool(true)
199+
bool(true)
200+
bool(true)
201+
bool(true)

0 commit comments

Comments
 (0)