@@ -1125,13 +1125,32 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(void)
1125
1125
1126
1126
static zend_never_inline void zend_assign_to_string_offset (zval * str , zval * dim , zval * value , zval * result )
1127
1127
{
1128
- zend_string * old_str ;
1129
1128
zend_uchar c ;
1130
1129
size_t string_len ;
1131
1130
zend_long offset ;
1131
+ zend_string * s ;
1132
+
1133
+ /* separate string */
1134
+ if (Z_REFCOUNTED_P (str ) && Z_REFCOUNT_P (str ) == 1 ) {
1135
+ s = Z_STR_P (str );
1136
+ } else {
1137
+ s = zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 );
1138
+ ZSTR_H (s ) = ZSTR_H (Z_STR_P (str ));
1139
+ ZVAL_NEW_STR (str , s );
1140
+ }
1132
1141
1133
1142
if (UNEXPECTED (Z_TYPE_P (dim ) != IS_LONG )) {
1143
+ /* The string may be destroyed while throwing the notice.
1144
+ * Temporarily increase the refcount to detect this situation. */
1145
+ GC_ADDREF (s );
1134
1146
offset = zend_check_string_offset (dim /*, BP_VAR_W*/ );
1147
+ if (GC_DELREF (s ) == 0 ) {
1148
+ zend_string_efree (s );
1149
+ if (result ) {
1150
+ ZVAL_NULL (result );
1151
+ }
1152
+ return ;
1153
+ }
1135
1154
if (UNEXPECTED (EG (exception ) != NULL )) {
1136
1155
if (UNEXPECTED (result )) {
1137
1156
ZVAL_UNDEF (result );
@@ -1141,7 +1160,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1141
1160
} else {
1142
1161
offset = Z_LVAL_P (dim );
1143
1162
}
1144
- if (offset < - (zend_long )Z_STRLEN_P ( str )) {
1163
+ if (offset < - (zend_long )ZSTR_LEN ( s )) {
1145
1164
/* Error on negative offset */
1146
1165
zend_error (E_WARNING , "Illegal string offset " ZEND_LONG_FMT , offset );
1147
1166
if (result ) {
@@ -1151,8 +1170,35 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1151
1170
}
1152
1171
1153
1172
if (Z_TYPE_P (value ) != IS_STRING ) {
1173
+ zend_string * tmp ;
1174
+
1175
+ /* The string may be destroyed while throwing the notice.
1176
+ * Temporarily increase the refcount to detect this situation. */
1177
+ GC_ADDREF (s );
1178
+
1179
+ if (UNEXPECTED (Z_TYPE_P (value ) == IS_UNDEF )) {
1180
+ const zend_op * op_data = EG (current_execute_data )-> opline + 1 ;
1181
+ ZEND_ASSERT (op_data -> opcode == ZEND_OP_DATA && op_data -> op1_type == IS_CV );
1182
+ zend_jit_undefined_op_helper (op_data -> op1 .var );
1183
+ value = & EG (uninitialized_zval );
1184
+ }
1185
+
1154
1186
/* Convert to string, just the time to pick the 1st byte */
1155
- zend_string * tmp = zval_try_get_string_func (value );
1187
+ tmp = zval_try_get_string_func (value );
1188
+
1189
+ if (GC_DELREF (s ) == 0 ) {
1190
+ zend_string_efree (s );
1191
+ if (result ) {
1192
+ ZVAL_NULL (result );
1193
+ }
1194
+ return ;
1195
+ }
1196
+ if (UNEXPECTED (!tmp )) {
1197
+ if (result ) {
1198
+ ZVAL_UNDEF (result );
1199
+ }
1200
+ return ;
1201
+ }
1156
1202
1157
1203
if (UNEXPECTED (!tmp )) {
1158
1204
if (result ) {
@@ -1180,27 +1226,37 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1180
1226
return ;
1181
1227
}
1182
1228
1229
+ /* The string may be destroyed while throwing the notice.
1230
+ * Temporarily increase the refcount to detect this situation. */
1231
+ GC_ADDREF (s );
1183
1232
zend_error (E_WARNING , "Only the first byte will be assigned to the string offset" );
1233
+ if (GC_DELREF (s ) == 0 ) {
1234
+ zend_string_efree (s );
1235
+ if (result ) {
1236
+ ZVAL_NULL (result );
1237
+ }
1238
+ return ;
1239
+ }
1240
+ /* Illegal offset assignment */
1241
+ if (UNEXPECTED (EG (exception ) != NULL )) {
1242
+ if (result ) {
1243
+ ZVAL_UNDEF (result );
1244
+ }
1245
+ return ;
1246
+ }
1184
1247
}
1185
1248
1186
1249
if (offset < 0 ) { /* Handle negative offset */
1187
- offset += (zend_long )Z_STRLEN_P ( str );
1250
+ offset += (zend_long )ZSTR_LEN ( s );
1188
1251
}
1189
1252
1190
- if ((size_t )offset >= Z_STRLEN_P ( str )) {
1253
+ if ((size_t )offset >= ZSTR_LEN ( s )) {
1191
1254
/* Extend string if needed */
1192
- zend_long old_len = Z_STRLEN_P (str );
1193
- Z_STR_P (str ) = zend_string_extend (Z_STR_P (str ), offset + 1 , 0 );
1194
- Z_TYPE_INFO_P (str ) = IS_STRING_EX ;
1255
+ zend_long old_len = ZSTR_LEN (s );
1256
+ ZVAL_NEW_STR (str , zend_string_extend (s , (size_t )offset + 1 , 0 ));
1195
1257
memset (Z_STRVAL_P (str ) + old_len , ' ' , offset - old_len );
1196
1258
Z_STRVAL_P (str )[offset + 1 ] = 0 ;
1197
- } else if (!Z_REFCOUNTED_P (str )) {
1198
- old_str = Z_STR_P (str );
1199
- Z_STR_P (str ) = zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 );
1200
- Z_TYPE_INFO_P (str ) = IS_STRING_EX ;
1201
- zend_string_release (old_str );
1202
1259
} else {
1203
- SEPARATE_STRING (str );
1204
1260
zend_string_forget_hash_val (Z_STR_P (str ));
1205
1261
}
1206
1262
@@ -1283,6 +1339,11 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_rw_helper(zval *object_ptr, zva
1283
1339
1284
1340
static void ZEND_FASTCALL zend_jit_assign_dim_helper (zval * object_ptr , zval * dim , zval * value , zval * result )
1285
1341
{
1342
+ if (EXPECTED (Z_TYPE_P (object_ptr ) == IS_STRING ) && EXPECTED (dim != NULL )) {
1343
+ zend_assign_to_string_offset (object_ptr , dim , value , result );
1344
+ return ;
1345
+ }
1346
+
1286
1347
if (dim && UNEXPECTED (Z_TYPE_P (dim ) == IS_UNDEF )) {
1287
1348
const zend_op * opline = EG (current_execute_data )-> opline ;
1288
1349
zend_jit_undefined_op_helper (opline -> op2 .var );
@@ -1307,13 +1368,9 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim
1307
1368
}
1308
1369
}
1309
1370
} else if (EXPECTED (Z_TYPE_P (object_ptr ) == IS_STRING )) {
1310
- if (!dim ) {
1311
- zend_throw_error (NULL , "[] operator not supported for strings" );
1312
- if (result ) {
1313
- ZVAL_UNDEF (result );
1314
- }
1315
- } else {
1316
- zend_assign_to_string_offset (object_ptr , dim , value , result );
1371
+ zend_throw_error (NULL , "[] operator not supported for strings" );
1372
+ if (result ) {
1373
+ ZVAL_UNDEF (result );
1317
1374
}
1318
1375
} else {
1319
1376
zend_throw_error (NULL , "Cannot use a scalar value as an array" );
0 commit comments