@@ -1498,45 +1498,41 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type
1498
1498
zend_long offset ;
1499
1499
1500
1500
try_again :
1501
- if (UNEXPECTED (Z_TYPE_P (dim ) != IS_LONG )) {
1502
- switch (Z_TYPE_P (dim )) {
1503
- case IS_STRING :
1504
- {
1505
- bool trailing_data = false;
1506
- /* For BC reasons we allow errors so that we can warn on leading numeric string */
1507
- if (IS_LONG == is_numeric_string_ex (Z_STRVAL_P (dim ), Z_STRLEN_P (dim ), & offset , NULL ,
1508
- /* allow errors */ true, NULL , & trailing_data )) {
1509
- if (UNEXPECTED (trailing_data ) && type != BP_VAR_UNSET ) {
1510
- zend_error (E_WARNING , "Illegal string offset \"%s\"" , Z_STRVAL_P (dim ));
1511
- }
1512
- return offset ;
1501
+ switch (Z_TYPE_P (dim )) {
1502
+ case IS_LONG :
1503
+ return Z_LVAL_P (dim );
1504
+ case IS_STRING :
1505
+ {
1506
+ bool trailing_data = false;
1507
+ /* For BC reasons we allow errors so that we can warn on leading numeric string */
1508
+ if (IS_LONG == is_numeric_string_ex (Z_STRVAL_P (dim ), Z_STRLEN_P (dim ), & offset , NULL ,
1509
+ /* allow errors */ true, NULL , & trailing_data )) {
1510
+ if (UNEXPECTED (trailing_data ) && type != BP_VAR_UNSET ) {
1511
+ zend_error (E_WARNING , "Illegal string offset \"%s\"" , Z_STRVAL_P (dim ));
1513
1512
}
1514
- zend_illegal_string_offset (dim );
1515
- return 0 ;
1513
+ return offset ;
1516
1514
}
1517
- case IS_UNDEF :
1518
- ZVAL_UNDEFINED_OP2 ();
1519
- ZEND_FALLTHROUGH ;
1520
- case IS_DOUBLE :
1521
- case IS_NULL :
1522
- case IS_FALSE :
1523
- case IS_TRUE :
1524
- zend_error (E_WARNING , "String offset cast occurred" );
1525
- break ;
1526
- case IS_REFERENCE :
1527
- dim = Z_REFVAL_P (dim );
1528
- goto try_again ;
1529
- default :
1530
- zend_illegal_string_offset (dim );
1531
- return 0 ;
1515
+ zend_illegal_string_offset (dim );
1516
+ return 0 ;
1532
1517
}
1533
-
1534
- offset = zval_get_long_func (dim , /* is_strict */ false);
1535
- } else {
1536
- offset = Z_LVAL_P (dim );
1518
+ case IS_UNDEF :
1519
+ ZVAL_UNDEFINED_OP2 ();
1520
+ ZEND_FALLTHROUGH ;
1521
+ case IS_DOUBLE :
1522
+ case IS_NULL :
1523
+ case IS_FALSE :
1524
+ case IS_TRUE :
1525
+ zend_error (E_WARNING , "String offset cast occurred" );
1526
+ break ;
1527
+ case IS_REFERENCE :
1528
+ dim = Z_REFVAL_P (dim );
1529
+ goto try_again ;
1530
+ default :
1531
+ zend_illegal_string_offset (dim );
1532
+ return 0 ;
1537
1533
}
1538
1534
1539
- return offset ;
1535
+ return zval_get_long_func ( dim , /* is_strict */ false) ;
1540
1536
}
1541
1537
1542
1538
ZEND_API ZEND_COLD void zend_wrong_string_offset_error (void )
@@ -1672,17 +1668,43 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1672
1668
zend_uchar c ;
1673
1669
size_t string_len ;
1674
1670
zend_long offset ;
1671
+ zend_string * s ;
1675
1672
1676
- offset = zend_check_string_offset (dim , BP_VAR_W EXECUTE_DATA_CC );
1677
- /* Illegal offset assignment */
1678
- if (UNEXPECTED (EG (exception ) != NULL )) {
1679
- if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1680
- ZVAL_UNDEF (EX_VAR (opline -> result .var ));
1673
+ /* separate string */
1674
+ if (Z_REFCOUNTED_P (str ) && Z_REFCOUNT_P (str ) == 1 ) {
1675
+ s = Z_STR_P (str );
1676
+ } else {
1677
+ s = zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 );
1678
+ ZSTR_H (s ) = ZSTR_H (Z_STR_P (str ));
1679
+ ZVAL_NEW_STR (str , s );
1680
+ }
1681
+
1682
+ if (EXPECTED (Z_TYPE_P (dim ) == IS_LONG )) {
1683
+ offset = Z_LVAL_P (dim );
1684
+ } else {
1685
+ /* The string may be destroyed while throwing the notice.
1686
+ * Temporarily increase the refcount to detect this situation. */
1687
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE )) {
1688
+ GC_ADDREF (s );
1689
+ }
1690
+ offset = zend_check_string_offset (dim , BP_VAR_W EXECUTE_DATA_CC );
1691
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE ) && GC_DELREF (s ) == 0 ) {
1692
+ zend_string_efree (s );
1693
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1694
+ ZVAL_NULL (EX_VAR (opline -> result .var ));
1695
+ }
1696
+ return ;
1697
+ }
1698
+ /* Illegal offset assignment */
1699
+ if (UNEXPECTED (EG (exception ) != NULL )) {
1700
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1701
+ ZVAL_UNDEF (EX_VAR (opline -> result .var ));
1702
+ }
1703
+ return ;
1681
1704
}
1682
- return ;
1683
1705
}
1684
1706
1685
- if (offset < - (zend_long )Z_STRLEN_P ( str )) {
1707
+ if (UNEXPECTED ( offset < - (zend_long )ZSTR_LEN ( s ) )) {
1686
1708
/* Error on negative offset */
1687
1709
zend_error (E_WARNING , "Illegal string offset " ZEND_LONG_FMT , offset );
1688
1710
if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
@@ -1691,9 +1713,28 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1691
1713
return ;
1692
1714
}
1693
1715
1694
- if (Z_TYPE_P (value ) != IS_STRING ) {
1716
+ if (offset < 0 ) { /* Handle negative offset */
1717
+ offset += (zend_long )ZSTR_LEN (s );
1718
+ }
1719
+
1720
+ if (UNEXPECTED (Z_TYPE_P (value ) != IS_STRING )) {
1721
+ /* The string may be destroyed while throwing the notice.
1722
+ * Temporarily increase the refcount to detect this situation. */
1723
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE )) {
1724
+ GC_ADDREF (s );
1725
+ }
1726
+ if (UNEXPECTED (Z_TYPE_P (value ) == IS_UNDEF )) {
1727
+ zval_undefined_cv ((opline + 1 )-> op1 .var EXECUTE_DATA_CC );
1728
+ }
1695
1729
/* Convert to string, just the time to pick the 1st byte */
1696
1730
zend_string * tmp = zval_try_get_string_func (value );
1731
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE ) && GC_DELREF (s ) == 0 ) {
1732
+ zend_string_efree (s );
1733
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1734
+ ZVAL_NULL (EX_VAR (opline -> result .var ));
1735
+ }
1736
+ return ;
1737
+ }
1697
1738
if (UNEXPECTED (!tmp )) {
1698
1739
if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1699
1740
ZVAL_UNDEF (EX_VAR (opline -> result .var ));
@@ -1709,7 +1750,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1709
1750
c = (zend_uchar )Z_STRVAL_P (value )[0 ];
1710
1751
}
1711
1752
1712
- if (string_len != 1 ) {
1753
+ if (UNEXPECTED ( string_len != 1 ) ) {
1713
1754
if (string_len == 0 ) {
1714
1755
/* Error on empty input string */
1715
1756
zend_throw_error (NULL , "Cannot assign an empty string to a string offset" );
@@ -1719,24 +1760,34 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
1719
1760
return ;
1720
1761
}
1721
1762
1763
+ /* The string may be destroyed while throwing the notice.
1764
+ * Temporarily increase the refcount to detect this situation. */
1765
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE )) {
1766
+ GC_ADDREF (s );
1767
+ }
1722
1768
zend_error (E_WARNING , "Only the first byte will be assigned to the string offset" );
1769
+ if (!(GC_FLAGS (s ) & IS_ARRAY_IMMUTABLE ) && GC_DELREF (s ) == 0 ) {
1770
+ zend_string_efree (s );
1771
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1772
+ ZVAL_NULL (EX_VAR (opline -> result .var ));
1773
+ }
1774
+ return ;
1775
+ }
1776
+ /* Illegal offset assignment */
1777
+ if (UNEXPECTED (EG (exception ) != NULL )) {
1778
+ if (UNEXPECTED (RETURN_VALUE_USED (opline ))) {
1779
+ ZVAL_UNDEF (EX_VAR (opline -> result .var ));
1780
+ }
1781
+ return ;
1782
+ }
1723
1783
}
1724
1784
1725
- if (offset < 0 ) { /* Handle negative offset */
1726
- offset += (zend_long )Z_STRLEN_P (str );
1727
- }
1728
-
1729
- if ((size_t )offset >= Z_STRLEN_P (str )) {
1785
+ if ((size_t )offset >= ZSTR_LEN (s )) {
1730
1786
/* Extend string if needed */
1731
- zend_long old_len = Z_STRLEN_P ( str );
1732
- ZVAL_NEW_STR (str , zend_string_extend (Z_STR_P ( str ) , (size_t )offset + 1 , 0 ));
1787
+ zend_long old_len = ZSTR_LEN ( s );
1788
+ ZVAL_NEW_STR (str , zend_string_extend (s , (size_t )offset + 1 , 0 ));
1733
1789
memset (Z_STRVAL_P (str ) + old_len , ' ' , offset - old_len );
1734
1790
Z_STRVAL_P (str )[offset + 1 ] = 0 ;
1735
- } else if (!Z_REFCOUNTED_P (str )) {
1736
- ZVAL_NEW_STR (str , zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 ));
1737
- } else if (Z_REFCOUNT_P (str ) > 1 ) {
1738
- Z_DELREF_P (str );
1739
- ZVAL_NEW_STR (str , zend_string_init (Z_STRVAL_P (str ), Z_STRLEN_P (str ), 0 ));
1740
1791
} else {
1741
1792
zend_string_forget_hash_val (Z_STR_P (str ));
1742
1793
}
0 commit comments