Skip to content

Commit f5efc92

Browse files
committed
New implementation (without leaks)
1 parent 2009d9a commit f5efc92

File tree

2 files changed

+77
-59
lines changed

2 files changed

+77
-59
lines changed

Zend/zend_execute.c

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
15711571
{
15721572
char *string_value;
15731573
size_t string_len;
1574+
zend_long old_len = Z_STRLEN_P(str);
15741575
zend_long offset;
15751576

15761577
offset = zend_check_string_offset(dim, BP_VAR_W EXECUTE_DATA_CC);
@@ -1611,7 +1612,6 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
16111612

16121613
if ((size_t)offset >= Z_STRLEN_P(str)) {
16131614
/* Extend string if needed */
1614-
zend_long old_len = Z_STRLEN_P(str);
16151615
ZVAL_NEW_STR(str, zend_string_extend(Z_STR_P(str), offset + 1, 0));
16161616
memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
16171617
Z_STRVAL_P(str)[offset+1] = 0;
@@ -1633,61 +1633,42 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
16331633
return;
16341634
}
16351635

1636+
/* -1 for the byte we are replacing */
1637+
zend_long new_len = old_len + string_len - 1;
16361638
if ((size_t)offset >= Z_STRLEN_P(str)) {
1637-
/* Extend string if needed */
1638-
zend_long old_len = Z_STRLEN_P(str);
1639+
/* Extend string */
16391640
ZVAL_NEW_STR(str, zend_string_extend(Z_STR_P(str), offset + string_len, 0));
16401641
memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
1641-
ZVAL_NEW_STR(str, zend_string_init(strcat(Z_STRVAL_P(str), string_value), offset + string_len, 0));
1642+
memcpy(Z_STRVAL_P(str) + offset, string_value, string_len);
16421643
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1643-
ZVAL_INTERNED_STR(EX_VAR(opline->result.var), zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
1644+
ZVAL_STR(EX_VAR(opline->result.var), zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
16441645
}
16451646
return;
1646-
} else if (!Z_REFCOUNTED_P(str)) {
1647-
ZVAL_NEW_STR(str, zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
1647+
}
1648+
1649+
zend_string *tmp = zend_string_init(Z_STRVAL_P(str), new_len, 0);
1650+
if (string_len > 0) {
1651+
memcpy(ZSTR_VAL(tmp) + offset, string_value, string_len);
1652+
}
1653+
/* Copy after the replacement string, from the position of the initial string after the offset,
1654+
* for the remainder of the initial string (old length - offset) */
1655+
memcpy(ZSTR_VAL(tmp) + offset + string_len, Z_STRVAL_P(str) + offset + 1, old_len - offset);
1656+
1657+
if (!Z_REFCOUNTED_P(str)) {
1658+
ZVAL_NEW_STR(str, zend_string_init(Z_STRVAL_P(str), new_len, 0));
16481659
} else if (Z_REFCOUNT_P(str) > 1) {
16491660
Z_DELREF_P(str);
1650-
ZVAL_NEW_STR(str, zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
1661+
ZVAL_NEW_STR(str, zend_string_init(Z_STRVAL_P(str), new_len, 0));
16511662
} else {
16521663
zend_string_forget_hash_val(Z_STR_P(str));
16531664
}
1665+
1666+
memcpy(Z_STRVAL_P(str), ZSTR_VAL(tmp), new_len);
1667+
zend_string_release_ex(tmp, 0);
16541668

1655-
// Buffer offset
1656-
int k = 0;
1657-
// Source offset
1658-
int i = 0;
1659-
char *buffer = emalloc(Z_STRLEN_P(str) + string_len - 1); // -1 as we replace a byte
1660-
char *source = Z_STRVAL_P(str);
1661-
// Append bytes from the source string to the buffer until the offset is reached
1662-
while (i < offset) {
1663-
buffer[k] = source[i];
1664-
i++;
1665-
k++;
1666-
}
1667-
i++; // Skip byte being replaced
1668-
// If not an empty string then append all the bytes from the value to the buffer
1669-
if (string_len > 0) {
1670-
int j = 0;
1671-
while (string_value[j] != '\0') {
1672-
buffer[k] = string_value[j];
1673-
j++;
1674-
k++;
1675-
}
1676-
}
1677-
// Add remaining bytes from the source string.
1678-
while (source[i] != '\0') {
1679-
buffer[k] = source[i];
1680-
i++;
1681-
k++;
1682-
}
1683-
// Append NUL byte to make a valid C string.
1684-
buffer[k] = '\0';
1685-
ZVAL_NEW_STR(str, zend_string_init(buffer, Z_STRLEN_P(str) + string_len - 1, 0));
16861669
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1687-
ZVAL_INTERNED_STR(EX_VAR(opline->result.var), zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
1670+
ZVAL_STR(EX_VAR(opline->result.var), zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
16881671
}
1689-
1690-
efree(buffer);
16911672
}
16921673

16931674
static zend_property_info *zend_get_prop_not_accepting_double(zend_reference *ref)

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(void)
862862
static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result)
863863
{
864864
zend_string *old_str;
865+
zend_long old_len = Z_STRLEN_P(str);
865866
zend_uchar c;
866867
size_t string_len;
867868
zend_long offset;
@@ -895,27 +896,63 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
895896
c = (zend_uchar)Z_STRVAL_P(value)[0];
896897
}
897898

898-
if (string_len == 0) {
899-
/* Error on empty input string */
900-
zend_error(E_WARNING, "Cannot assign an empty string to a string offset");
899+
if (offset < 0) { /* Handle negative offset */
900+
offset += (zend_long)Z_STRLEN_P(str);
901+
}
902+
903+
/* If it's a byte char replace byte directly */
904+
if (string_len == 1) {
905+
if ((size_t) offset >= Z_STRLEN_P(str)) {
906+
/* Extend string if needed */
907+
Z_STR_P(str) = zend_string_extend(Z_STR_P(str), offset + 1, 0);
908+
Z_TYPE_INFO_P(str) = IS_STRING_EX;
909+
memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
910+
Z_STRVAL_P(str)[offset + 1] = 0;
911+
} else if (!Z_REFCOUNTED_P(str)) {
912+
old_str = Z_STR_P(str);
913+
Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
914+
Z_TYPE_INFO_P(str) = IS_STRING_EX;
915+
zend_string_release(old_str);
916+
} else {
917+
SEPARATE_STRING(str);
918+
zend_string_forget_hash_val(Z_STR_P(str));
919+
}
920+
921+
Z_STRVAL_P(str)[offset] = c;
922+
901923
if (result) {
902-
ZVAL_NULL(result);
924+
/* Return the new character */
925+
ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
903926
}
904927
return;
905928
}
906929

907-
if (offset < 0) { /* Handle negative offset */
908-
offset += (zend_long)Z_STRLEN_P(str);
909-
}
910-
930+
/* -1 for the byte we are replacing */
931+
zend_long new_len = old_len + string_len - 1;
911932
if ((size_t)offset >= Z_STRLEN_P(str)) {
912-
/* Extend string if needed */
913-
zend_long old_len = Z_STRLEN_P(str);
914-
Z_STR_P(str) = zend_string_extend(Z_STR_P(str), offset + 1, 0);
915-
Z_TYPE_INFO_P(str) = IS_STRING_EX;
933+
old_str = Z_STR_P(str);
934+
/* Extend string */
935+
ZVAL_NEW_STR(str, zend_string_extend(Z_STR_P(str), offset + string_len, 0));
916936
memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
917-
Z_STRVAL_P(str)[offset+1] = 0;
918-
} else if (!Z_REFCOUNTED_P(str)) {
937+
memcpy(Z_STRVAL_P(str) + offset, ZSTR_VAL(old_str), string_len);
938+
939+
zend_string_release(old_str);
940+
if (result) {
941+
ZVAL_STR(result, zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
942+
}
943+
return;
944+
}
945+
946+
old_str = Z_STR_P(str);
947+
zend_string *tmp = zend_string_init(Z_STRVAL_P(str), new_len, 0);
948+
if (string_len > 0) {
949+
memcpy(ZSTR_VAL(tmp) + offset, ZSTR_VAL(old_str), string_len);
950+
}
951+
/* Copy after the replacement string, from the position of the initial string after the offset,
952+
* for the remainder of the initial string (old length - offset) */
953+
memcpy(ZSTR_VAL(tmp) + offset + string_len, Z_STRVAL_P(str) + offset + 1, old_len - offset);
954+
955+
if (!Z_REFCOUNTED_P(str)) {
919956
old_str = Z_STR_P(str);
920957
Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
921958
Z_TYPE_INFO_P(str) = IS_STRING_EX;
@@ -925,11 +962,11 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
925962
zend_string_forget_hash_val(Z_STR_P(str));
926963
}
927964

928-
Z_STRVAL_P(str)[offset] = c;
965+
memcpy(Z_STRVAL_P(str), ZSTR_VAL(tmp), new_len);
966+
zend_string_release_ex(tmp, 0);
929967

930968
if (result) {
931-
/* Return the new character */
932-
ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
969+
ZVAL_STR(result, zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0));
933970
}
934971
}
935972

0 commit comments

Comments
 (0)