@@ -936,13 +936,32 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval
936
936
937
937
static zend_never_inline void zend_assign_to_string_offset (zval * str , zval * dim , zval * value , zval * result )
938
938
{
939
- zend_string * old_str ;
940
939
zend_uchar c ;
941
940
size_t string_len ;
942
941
zend_long offset ;
942
+ zend_string * s ;
943
+
944
+ /* separate string */
945
+ if (Z_REFCOUNTED_P (str ) && Z_REFCOUNT_P (str ) == 1 ) {
946
+ s = Z_STR_P (str );
947
+ } else {
948
+ s = zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 );
949
+ ZSTR_H (s ) = ZSTR_H (Z_STR_P (str ));
950
+ ZVAL_NEW_STR (str , s );
951
+ }
943
952
944
953
if (UNEXPECTED (Z_TYPE_P (dim ) != IS_LONG )) {
954
+ /* The string may be destroyed while throwing the notice.
955
+ * Temporarily increase the refcount to detect this situation. */
956
+ GC_ADDREF (s );
945
957
offset = zend_check_string_offset (dim /*, BP_VAR_W*/ );
958
+ if (GC_DELREF (s ) == 0 ) {
959
+ zend_string_efree (s );
960
+ if (result ) {
961
+ ZVAL_NULL (result );
962
+ }
963
+ return ;
964
+ }
946
965
if (UNEXPECTED (EG (exception ) != NULL )) {
947
966
if (UNEXPECTED (result )) {
948
967
ZVAL_UNDEF (result );
@@ -952,7 +971,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
952
971
} else {
953
972
offset = Z_LVAL_P (dim );
954
973
}
955
- if (offset < - (zend_long )Z_STRLEN_P ( str )) {
974
+ if (offset < - (zend_long )ZSTR_LEN ( s )) {
956
975
/* Error on negative offset */
957
976
zend_error (E_WARNING , "Illegal string offset " ZEND_LONG_FMT , offset );
958
977
if (result ) {
@@ -962,8 +981,35 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
962
981
}
963
982
964
983
if (Z_TYPE_P (value ) != IS_STRING ) {
984
+ zend_string * tmp ;
985
+
986
+ /* The string may be destroyed while throwing the notice.
987
+ * Temporarily increase the refcount to detect this situation. */
988
+ GC_ADDREF (s );
989
+
990
+ if (UNEXPECTED (Z_TYPE_P (value ) == IS_UNDEF )) {
991
+ const zend_op * op_data = EG (current_execute_data )-> opline + 1 ;
992
+ ZEND_ASSERT (op_data -> opcode == ZEND_OP_DATA && op_data -> op1_type == IS_CV );
993
+ zend_jit_undefined_op_helper (op_data -> op1 .var );
994
+ value = & EG (uninitialized_zval );
995
+ }
996
+
965
997
/* Convert to string, just the time to pick the 1st byte */
966
- zend_string * tmp = zval_try_get_string_func (value );
998
+ tmp = zval_try_get_string_func (value );
999
+
1000
+ if (GC_DELREF (s ) == 0 ) {
1001
+ zend_string_efree (s );
1002
+ if (result ) {
1003
+ ZVAL_NULL (result );
1004
+ }
1005
+ return ;
1006
+ }
1007
+ if (UNEXPECTED (!tmp )) {
1008
+ if (result ) {
1009
+ ZVAL_UNDEF (result );
1010
+ }
1011
+ return ;
1012
+ }
967
1013
968
1014
if (UNEXPECTED (!tmp )) {
969
1015
if (result ) {
@@ -991,27 +1037,37 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
991
1037
return ;
992
1038
}
993
1039
1040
+ /* The string may be destroyed while throwing the notice.
1041
+ * Temporarily increase the refcount to detect this situation. */
1042
+ GC_ADDREF (s );
994
1043
zend_error (E_WARNING , "Only the first byte will be assigned to the string offset" );
1044
+ if (GC_DELREF (s ) == 0 ) {
1045
+ zend_string_efree (s );
1046
+ if (result ) {
1047
+ ZVAL_NULL (result );
1048
+ }
1049
+ return ;
1050
+ }
1051
+ /* Illegal offset assignment */
1052
+ if (UNEXPECTED (EG (exception ) != NULL )) {
1053
+ if (result ) {
1054
+ ZVAL_UNDEF (result );
1055
+ }
1056
+ return ;
1057
+ }
995
1058
}
996
1059
997
1060
if (offset < 0 ) { /* Handle negative offset */
998
- offset += (zend_long )Z_STRLEN_P ( str );
1061
+ offset += (zend_long )ZSTR_LEN ( s );
999
1062
}
1000
1063
1001
- if ((size_t )offset >= Z_STRLEN_P ( str )) {
1064
+ if ((size_t )offset >= ZSTR_LEN ( s )) {
1002
1065
/* Extend string if needed */
1003
- zend_long old_len = Z_STRLEN_P (str );
1004
- Z_STR_P (str ) = zend_string_extend (Z_STR_P (str ), offset + 1 , 0 );
1005
- Z_TYPE_INFO_P (str ) = IS_STRING_EX ;
1066
+ zend_long old_len = ZSTR_LEN (s );
1067
+ ZVAL_NEW_STR (str , zend_string_extend (s , (size_t )offset + 1 , 0 ));
1006
1068
memset (Z_STRVAL_P (str ) + old_len , ' ' , offset - old_len );
1007
1069
Z_STRVAL_P (str )[offset + 1 ] = 0 ;
1008
- } else if (!Z_REFCOUNTED_P (str )) {
1009
- old_str = Z_STR_P (str );
1010
- Z_STR_P (str ) = zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 );
1011
- Z_TYPE_INFO_P (str ) = IS_STRING_EX ;
1012
- zend_string_release (old_str );
1013
1070
} else {
1014
- SEPARATE_STRING (str );
1015
1071
zend_string_forget_hash_val (Z_STR_P (str ));
1016
1072
}
1017
1073
@@ -1112,6 +1168,11 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_rw_helper(zval *object_ptr, zva
1112
1168
1113
1169
static void ZEND_FASTCALL zend_jit_assign_dim_helper (zval * object_ptr , zval * dim , zval * value , zval * result )
1114
1170
{
1171
+ if (EXPECTED (Z_TYPE_P (object_ptr ) == IS_STRING ) && EXPECTED (dim != NULL )) {
1172
+ zend_assign_to_string_offset (object_ptr , dim , value , result );
1173
+ return ;
1174
+ }
1175
+
1115
1176
if (dim && UNEXPECTED (Z_TYPE_P (dim ) == IS_UNDEF )) {
1116
1177
const zend_op * opline = EG (current_execute_data )-> opline ;
1117
1178
zend_jit_undefined_op_helper (opline -> op2 .var );
@@ -1136,13 +1197,9 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim
1136
1197
}
1137
1198
}
1138
1199
} else if (EXPECTED (Z_TYPE_P (object_ptr ) == IS_STRING )) {
1139
- if (!dim ) {
1140
- zend_throw_error (NULL , "[] operator not supported for strings" );
1141
- if (result ) {
1142
- ZVAL_UNDEF (result );
1143
- }
1144
- } else {
1145
- zend_assign_to_string_offset (object_ptr , dim , value , result );
1200
+ zend_throw_error (NULL , "[] operator not supported for strings" );
1201
+ if (result ) {
1202
+ ZVAL_UNDEF (result );
1146
1203
}
1147
1204
} else if (Z_TYPE_P (object_ptr ) == IS_FALSE ) {
1148
1205
zend_false_to_array_deprecated ();
0 commit comments