@@ -1368,44 +1368,40 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type
1368
1368
zend_long offset ;
1369
1369
1370
1370
try_again :
1371
- if (UNEXPECTED (Z_TYPE_P (dim ) != IS_LONG )) {
1372
- switch (Z_TYPE_P (dim )) {
1373
- case IS_STRING :
1374
- {
1375
- bool trailing_data = false;
1376
- /* For BC reasons we allow errors so that we can warn on leading numeric string */
1377
- if (IS_LONG == is_numeric_string_ex (Z_STRVAL_P (dim ), Z_STRLEN_P (dim ), & offset , NULL ,
1378
- /* allow errors */ true, NULL , & trailing_data )) {
1379
- if (UNEXPECTED (trailing_data ) && type != BP_VAR_UNSET ) {
1380
- zend_error (E_WARNING , "Illegal string offset \"%s\"" , Z_STRVAL_P (dim ));
1381
- }
1382
- return offset ;
1371
+ switch (Z_TYPE_P (dim )) {
1372
+ case IS_LONG :
1373
+ return Z_LVAL_P (dim );
1374
+ case IS_STRING :
1375
+ {
1376
+ bool trailing_data = false;
1377
+ /* For BC reasons we allow errors so that we can warn on leading numeric string */
1378
+ if (IS_LONG == is_numeric_string_ex (Z_STRVAL_P (dim ), Z_STRLEN_P (dim ), & offset , NULL ,
1379
+ /* allow errors */ true, NULL , & trailing_data )) {
1380
+ if (UNEXPECTED (trailing_data ) && type != BP_VAR_UNSET ) {
1381
+ zend_error (E_WARNING , "Illegal string offset \"%s\"" , Z_STRVAL_P (dim ));
1383
1382
}
1384
- zend_illegal_string_offset (dim );
1385
- return 0 ;
1383
+ return offset ;
1386
1384
}
1387
- case IS_UNDEF :
1388
- ZVAL_UNDEFINED_OP2 ();
1389
- case IS_DOUBLE :
1390
- case IS_NULL :
1391
- case IS_FALSE :
1392
- case IS_TRUE :
1393
- zend_error (E_WARNING , "String offset cast occurred" );
1394
- break ;
1395
- case IS_REFERENCE :
1396
- dim = Z_REFVAL_P (dim );
1397
- goto try_again ;
1398
- default :
1399
- zend_illegal_string_offset (dim );
1400
- return 0 ;
1385
+ zend_illegal_string_offset (dim );
1386
+ return 0 ;
1401
1387
}
1402
-
1403
- offset = zval_get_long_func (dim );
1404
- } else {
1405
- offset = Z_LVAL_P (dim );
1388
+ case IS_UNDEF :
1389
+ ZVAL_UNDEFINED_OP2 ();
1390
+ case IS_DOUBLE :
1391
+ case IS_NULL :
1392
+ case IS_FALSE :
1393
+ case IS_TRUE :
1394
+ zend_error (E_WARNING , "String offset cast occurred" );
1395
+ break ;
1396
+ case IS_REFERENCE :
1397
+ dim = Z_REFVAL_P (dim );
1398
+ goto try_again ;
1399
+ default :
1400
+ zend_illegal_string_offset (dim );
1401
+ return 0 ;
1406
1402
}
1407
1403
1408
- return offset ;
1404
+ return zval_get_long_func ( dim ) ;
1409
1405
}
1410
1406
1411
1407
static zend_never_inline ZEND_COLD void zend_wrong_string_offset (EXECUTE_DATA_D )
@@ -1535,17 +1531,43 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1535
1531
zend_uchar c ;
1536
1532
size_t string_len ;
1537
1533
zend_long offset ;
1534
+ zend_string * s ;
1538
1535
1539
- offset = zend_check_string_offset (dim , BP_VAR_W EXECUTE_DATA_CC );
1540
- /* Illegal offset assignment */
1541
- if (UNEXPECTED (EG (exception ) != NULL )) {
1542
- if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1543
- ZVAL_UNDEF (EX_VAR (opline -> result .var ));
1536
+ /* separate string */
1537
+ if (Z_REFCOUNTED_P (str ) && Z_REFCOUNT_P (str ) == 1 ) {
1538
+ s = Z_STR_P (str );
1539
+ } else {
1540
+ s = zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 );
1541
+ ZSTR_H (s ) = ZSTR_H (Z_STR_P (str ));
1542
+ ZVAL_NEW_STR (str , s );
1543
+ }
1544
+
1545
+ if (EXPECTED (Z_TYPE_P (dim ) == IS_LONG )) {
1546
+ offset = Z_LVAL_P (dim );
1547
+ } else {
1548
+ /* The string may be destroyed while throwing the notice.
1549
+ * Temporarily increase the refcount to detect this situation. */
1550
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE )) {
1551
+ GC_ADDREF (s );
1552
+ }
1553
+ offset = zend_check_string_offset (dim , BP_VAR_W EXECUTE_DATA_CC );
1554
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE ) && GC_DELREF (s ) == 0 ) {
1555
+ zend_string_efree (s );
1556
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1557
+ ZVAL_NULL (EX_VAR (opline -> result .var ));
1558
+ }
1559
+ return ;
1560
+ }
1561
+ /* Illegal offset assignment */
1562
+ if (UNEXPECTED (EG (exception ) != NULL )) {
1563
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1564
+ ZVAL_UNDEF (EX_VAR (opline -> result .var ));
1565
+ }
1566
+ return ;
1544
1567
}
1545
- return ;
1546
1568
}
1547
1569
1548
- if (offset < - (zend_long )Z_STRLEN_P ( str )) {
1570
+ if (UNEXPECTED ( offset < - (zend_long )ZSTR_LEN ( s ) )) {
1549
1571
/* Error on negative offset */
1550
1572
zend_error (E_WARNING , "Illegal string offset " ZEND_LONG_FMT , offset );
1551
1573
if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
@@ -1554,9 +1576,28 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1554
1576
return ;
1555
1577
}
1556
1578
1557
- if (Z_TYPE_P (value ) != IS_STRING ) {
1579
+ if (offset < 0 ) { /* Handle negative offset */
1580
+ offset += (zend_long )ZSTR_LEN (s );
1581
+ }
1582
+
1583
+ if (UNEXPECTED (Z_TYPE_P (value ) != IS_STRING )) {
1584
+ /* The string may be destroyed while throwing the notice.
1585
+ * Temporarily increase the refcount to detect this situation. */
1586
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE )) {
1587
+ GC_ADDREF (s );
1588
+ }
1589
+ if (UNEXPECTED (Z_TYPE_P (value ) == IS_UNDEF )) {
1590
+ zval_undefined_cv ((opline + 1 )-> op1 .var EXECUTE_DATA_CC );
1591
+ }
1558
1592
/* Convert to string, just the time to pick the 1st byte */
1559
1593
zend_string * tmp = zval_try_get_string_func (value );
1594
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE ) && GC_DELREF (s ) == 0 ) {
1595
+ zend_string_efree (s );
1596
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1597
+ ZVAL_NULL (EX_VAR (opline -> result .var ));
1598
+ }
1599
+ return ;
1600
+ }
1560
1601
if (UNEXPECTED (!tmp )) {
1561
1602
if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1562
1603
ZVAL_UNDEF (EX_VAR (opline -> result .var ));
@@ -1572,7 +1613,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1572
1613
c = (zend_uchar )Z_STRVAL_P (value )[0 ];
1573
1614
}
1574
1615
1575
- if (string_len != 1 ) {
1616
+ if (UNEXPECTED ( string_len != 1 ) ) {
1576
1617
if (string_len == 0 ) {
1577
1618
/* Error on empty input string */
1578
1619
zend_throw_error (NULL , "Cannot assign an empty string to a string offset" );
@@ -1582,24 +1623,34 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1582
1623
return ;
1583
1624
}
1584
1625
1626
+ /* The string may be destroyed while throwing the notice.
1627
+ * Temporarily increase the refcount to detect this situation. */
1628
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE )) {
1629
+ GC_ADDREF (s );
1630
+ }
1585
1631
zend_error (E_WARNING , "Only the first byte will be assigned to the string offset" );
1632
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE ) && GC_DELREF (s ) == 0 ) {
1633
+ zend_string_efree (s );
1634
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1635
+ ZVAL_NULL (EX_VAR (opline -> result .var ));
1636
+ }
1637
+ return ;
1638
+ }
1639
+ /* Illegal offset assignment */
1640
+ if (UNEXPECTED (EG (exception ) != NULL )) {
1641
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1642
+ ZVAL_UNDEF (EX_VAR (opline -> result .var ));
1643
+ }
1644
+ return ;
1645
+ }
1586
1646
}
1587
1647
1588
- if (offset < 0 ) { /* Handle negative offset */
1589
- offset += (zend_long )Z_STRLEN_P (str );
1590
- }
1591
-
1592
- if ((size_t )offset >= Z_STRLEN_P (str )) {
1648
+ if ((size_t )offset >= ZSTR_LEN (s )) {
1593
1649
/* Extend string if needed */
1594
- zend_long old_len = Z_STRLEN_P ( str );
1595
- ZVAL_NEW_STR (str , zend_string_extend (Z_STR_P ( str ) , (size_t )offset + 1 , 0 ));
1650
+ zend_long old_len = ZSTR_LEN ( s );
1651
+ ZVAL_NEW_STR (str , zend_string_extend (s , (size_t )offset + 1 , 0 ));
1596
1652
memset (Z_STRVAL_P (str ) + old_len , ' ' , offset - old_len );
1597
1653
Z_STRVAL_P (str )[offset + 1 ] = 0 ;
1598
- } else if (!Z_REFCOUNTED_P (str )) {
1599
- ZVAL_NEW_STR (str , zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 ));
1600
- } else if (Z_REFCOUNT_P (str ) > 1 ) {
1601
- Z_DELREF_P (str );
1602
- ZVAL_NEW_STR (str , zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 ));
1603
1654
} else {
1604
1655
zend_string_forget_hash_val (Z_STR_P (str ));
1605
1656
}
0 commit comments