@@ -1840,106 +1840,125 @@ ZEND_API zend_result ZEND_FASTCALL shift_right_function(zval *result, zval *op1,
1840
1840
ZEND_API zend_result ZEND_FASTCALL concat_function (zval * result , zval * op1 , zval * op2 ) /* {{{ */
1841
1841
{
1842
1842
zval * orig_op1 = op1 ;
1843
- zval op1_copy , op2_copy ;
1844
-
1845
- ZVAL_UNDEF (& op1_copy );
1846
- ZVAL_UNDEF (& op2_copy );
1843
+ zend_string * op1_string , * op2_string = NULL ;
1844
+ bool op1_string_from_func = false;
1845
+ bool op2_string_from_func = false;
1847
1846
1848
1847
do {
1849
1848
if (UNEXPECTED (Z_TYPE_P (op1 ) != IS_STRING )) {
1850
1849
if (Z_ISREF_P (op1 )) {
1851
1850
op1 = Z_REFVAL_P (op1 );
1852
- if (Z_TYPE_P (op1 ) == IS_STRING ) break ;
1851
+ if (Z_TYPE_P (op1 ) == IS_STRING ) {
1852
+ op1_string = zend_string_copy (Z_STR_P (op1 ));
1853
+ break ;
1854
+ }
1853
1855
}
1854
1856
ZEND_TRY_BINARY_OBJECT_OPERATION (ZEND_CONCAT );
1855
- ZVAL_STR ( & op1_copy , zval_get_string_func (op1 ) );
1857
+ op1_string = zval_get_string_func (op1 );
1856
1858
if (UNEXPECTED (EG (exception ))) {
1857
- zval_ptr_dtor_str (& op1_copy );
1858
1859
if (orig_op1 != result ) {
1859
1860
ZVAL_UNDEF (result );
1860
1861
}
1861
1862
return FAILURE ;
1862
1863
}
1864
+ op1_string_from_func = true;
1863
1865
if (result == op1 ) {
1864
1866
if (UNEXPECTED (op1 == op2 )) {
1865
- op2 = & op1_copy ;
1867
+ op2_string = op1_string ;
1866
1868
}
1867
1869
}
1868
- op1 = & op1_copy ;
1869
- }
1870
+ } else {
1871
+ op1_string = zend_string_copy (Z_STR_P (op1 ));
1872
+ }
1870
1873
} while (0 );
1871
1874
do {
1872
- if (UNEXPECTED (Z_TYPE_P (op2 ) != IS_STRING )) {
1875
+ if (UNEXPECTED (Z_TYPE_P (op2 ) != IS_STRING ) && ! op2_string ) {
1873
1876
if (Z_ISREF_P (op2 )) {
1874
1877
op2 = Z_REFVAL_P (op2 );
1875
- if (Z_TYPE_P (op2 ) == IS_STRING ) break ;
1878
+ if (Z_TYPE_P (op2 ) == IS_STRING ) {
1879
+ op2_string = Z_STR_P (op2 );
1880
+ break ;
1881
+ }
1876
1882
}
1877
1883
ZEND_TRY_BINARY_OP2_OBJECT_OPERATION (ZEND_CONCAT );
1878
- ZVAL_STR ( & op2_copy , zval_get_string_func (op2 ) );
1884
+ op2_string = zval_get_string_func (op2 );
1879
1885
if (UNEXPECTED (EG (exception ))) {
1880
- zval_ptr_dtor_str (& op1_copy );
1881
- zval_ptr_dtor_str (& op2_copy );
1886
+ zend_string_release (op1_string );
1882
1887
if (orig_op1 != result ) {
1883
1888
ZVAL_UNDEF (result );
1884
1889
}
1885
1890
return FAILURE ;
1886
1891
}
1887
- op2 = & op2_copy ;
1892
+ op2_string_from_func = true;
1893
+ } else if (!op2_string ) {
1894
+ op2_string = Z_STR_P (op2 );
1888
1895
}
1889
1896
} while (0 );
1890
1897
1891
- if (UNEXPECTED (Z_STRLEN_P ( op1 ) == 0 )) {
1892
- if (EXPECTED (result != op2 )) {
1898
+ if (UNEXPECTED (ZSTR_LEN ( op1_string ) == 0 )) {
1899
+ if (EXPECTED (op2_string_from_func || result != op2 )) {
1893
1900
if (result == orig_op1 ) {
1894
1901
i_zval_ptr_dtor (result );
1895
1902
}
1896
- ZVAL_COPY (result , op2 );
1903
+ ZVAL_STR_COPY (result , op2_string );
1897
1904
}
1898
- } else if (UNEXPECTED (Z_STRLEN_P (op2 ) == 0 )) {
1899
- if (EXPECTED (result != op1 )) {
1905
+ zend_string_release (op1_string );
1906
+ } else if (UNEXPECTED (ZSTR_LEN (op2_string ) == 0 )) {
1907
+ if (EXPECTED (op1_string_from_func || result != op1 )) {
1900
1908
if (result == orig_op1 ) {
1901
1909
i_zval_ptr_dtor (result );
1902
1910
}
1903
- ZVAL_COPY (result , op1 );
1911
+ ZVAL_STR (result , op1_string );
1912
+ } else {
1913
+ zend_string_release (op1_string );
1904
1914
}
1905
1915
} else {
1906
- size_t op1_len = Z_STRLEN_P ( op1 );
1907
- size_t op2_len = Z_STRLEN_P ( op2 );
1916
+ size_t op1_len = ZSTR_LEN ( op1_string );
1917
+ size_t op2_len = ZSTR_LEN ( op2_string );
1908
1918
size_t result_len = op1_len + op2_len ;
1909
1919
zend_string * result_str ;
1910
1920
1911
1921
if (UNEXPECTED (op1_len > ZSTR_MAX_LEN - op2_len )) {
1922
+ zend_string_release (op1_string );
1923
+ if (op2_string_from_func ) zend_string_release (op2_string );
1912
1924
zend_throw_error (NULL , "String size overflow" );
1913
- zval_ptr_dtor_str (& op1_copy );
1914
- zval_ptr_dtor_str (& op2_copy );
1915
1925
if (orig_op1 != result ) {
1916
1926
ZVAL_UNDEF (result );
1917
1927
}
1918
1928
return FAILURE ;
1919
1929
}
1920
1930
1921
- if (result == op1 && Z_REFCOUNTED_P (result )) {
1931
+ if (result == op1 ) {
1932
+ /* As result == op1, op1_string is equal to Z_STR_P(result) and we thus we have a double reference.
1933
+ * We should drop it before extending such that it can be extended in place in most cases. */
1934
+ if (!op1_string_from_func ) {
1935
+ zend_string_release (op1_string );
1936
+ } else {
1937
+ i_zval_ptr_dtor (result );
1938
+ }
1922
1939
/* special case, perform operations on result */
1923
- result_str = zend_string_extend (Z_STR_P (result ), result_len , 0 );
1940
+ result_str = zend_string_extend (op1_string , result_len , 0 );
1941
+ /* account for the case where result == op1 == op2 and the realloc is done */
1942
+ if (op1_string == op2_string ) {
1943
+ op2_string = result_str ;
1944
+ op2_string_from_func = false;
1945
+ }
1924
1946
} else {
1925
1947
result_str = zend_string_alloc (result_len , 0 );
1926
- memcpy (ZSTR_VAL (result_str ), Z_STRVAL_P ( op1 ), op1_len );
1948
+ memcpy (ZSTR_VAL (result_str ), ZSTR_VAL ( op1_string ), op1_len );
1927
1949
if (result == orig_op1 ) {
1928
1950
i_zval_ptr_dtor (result );
1929
1951
}
1952
+ zend_string_release (op1_string );
1930
1953
}
1931
1954
1932
- /* This has to happen first to account for the cases where result == op1 == op2 and
1933
- * the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to
1934
- * point to the new string. The first op2_len bytes of result will still be the same. */
1935
1955
ZVAL_NEW_STR (result , result_str );
1936
-
1937
- memcpy (ZSTR_VAL (result_str ) + op1_len , Z_STRVAL_P (op2 ), op2_len );
1956
+ memcpy (ZSTR_VAL (result_str ) + op1_len , ZSTR_VAL (op2_string ), op2_len );
1938
1957
ZSTR_VAL (result_str )[result_len ] = '\0' ;
1939
1958
}
1940
1959
1941
- zval_ptr_dtor_str ( & op1_copy );
1942
- zval_ptr_dtor_str ( & op2_copy );
1960
+ if ( op2_string_from_func ) zend_string_release ( op2_string );
1961
+
1943
1962
return SUCCESS ;
1944
1963
}
1945
1964
/* }}} */
0 commit comments