@@ -862,6 +862,7 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(void)
862
862
static zend_never_inline void zend_assign_to_string_offset (zval * str , zval * dim , zval * value , zval * result )
863
863
{
864
864
zend_string * old_str ;
865
+ zend_long old_len = Z_STRLEN_P (str );
865
866
zend_uchar c ;
866
867
size_t string_len ;
867
868
zend_long offset ;
@@ -895,27 +896,63 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
895
896
c = (zend_uchar )Z_STRVAL_P (value )[0 ];
896
897
}
897
898
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
+
901
923
if (result ) {
902
- ZVAL_NULL (result );
924
+ /* Return the new character */
925
+ ZVAL_INTERNED_STR (result , ZSTR_CHAR (c ));
903
926
}
904
927
return ;
905
928
}
906
929
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 ;
911
932
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 ));
916
936
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 )) {
919
956
old_str = Z_STR_P (str );
920
957
Z_STR_P (str ) = zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 );
921
958
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,
925
962
zend_string_forget_hash_val (Z_STR_P (str ));
926
963
}
927
964
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 );
929
967
930
968
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 ));
933
970
}
934
971
}
935
972
0 commit comments