@@ -1840,78 +1840,85 @@ 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 = 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 = Z_STR_P (op1 );
1872
+ }
1870
1873
} while (0 );
1871
1874
do {
1872
- if (UNEXPECTED (Z_TYPE_P (op2 ) != IS_STRING )) {
1875
+ if (UNEXPECTED (! op2_string && Z_TYPE_P (op2 ) != IS_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
+ if (op1_string_from_func ) 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
+ } else if (UNEXPECTED (ZSTR_LEN ( op2_string ) == 0 )) {
1906
+ if (EXPECTED (op1_string_from_func || result != op1 )) {
1900
1907
if (result == orig_op1 ) {
1901
1908
i_zval_ptr_dtor (result );
1902
1909
}
1903
- ZVAL_COPY (result , op1 );
1910
+ ZVAL_STR_COPY (result , op1_string );
1904
1911
}
1905
1912
} else {
1906
- size_t op1_len = Z_STRLEN_P ( op1 );
1907
- size_t op2_len = Z_STRLEN_P ( op2 );
1913
+ size_t op1_len = ZSTR_LEN ( op1_string );
1914
+ size_t op2_len = ZSTR_LEN ( op2_string );
1908
1915
size_t result_len = op1_len + op2_len ;
1909
1916
zend_string * result_str ;
1910
1917
1911
1918
if (UNEXPECTED (op1_len > ZSTR_MAX_LEN - op2_len )) {
1919
+ if (op1_string_from_func ) zend_string_release (op1_string );
1920
+ if (op2_string_from_func ) zend_string_release (op2_string );
1912
1921
zend_throw_error (NULL , "String size overflow" );
1913
- zval_ptr_dtor_str (& op1_copy );
1914
- zval_ptr_dtor_str (& op2_copy );
1915
1922
if (orig_op1 != result ) {
1916
1923
ZVAL_UNDEF (result );
1917
1924
}
@@ -1920,26 +1927,33 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval
1920
1927
1921
1928
if (result == op1 && Z_REFCOUNTED_P (result )) {
1922
1929
/* special case, perform operations on result */
1923
- result_str = zend_string_extend (Z_STR_P (result ), result_len , 0 );
1930
+ result_str = zend_string_extend (op1_string , result_len , 0 );
1931
+ /* account for the case where result == op1 == op2 and the realloc is done */
1932
+ if (op1_string == op2_string ) {
1933
+ op2_string = result_str ;
1934
+ }
1935
+ if (op1_string_from_func ) {
1936
+ i_zval_ptr_dtor (result );
1937
+ /* we will reuse the memory of op1_string */
1938
+ op1_string_from_func = false;
1939
+ }
1924
1940
} else {
1925
1941
result_str = zend_string_alloc (result_len , 0 );
1926
- memcpy (ZSTR_VAL (result_str ), Z_STRVAL_P ( op1 ), op1_len );
1942
+ memcpy (ZSTR_VAL (result_str ), ZSTR_VAL ( op1_string ), op1_len );
1927
1943
if (result == orig_op1 ) {
1928
1944
i_zval_ptr_dtor (result );
1929
1945
}
1930
1946
}
1931
1947
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
1948
ZVAL_NEW_STR (result , result_str );
1936
1949
1937
- memcpy (ZSTR_VAL (result_str ) + op1_len , Z_STRVAL_P ( op2 ), op2_len );
1950
+ memcpy (ZSTR_VAL (result_str ) + op1_len , ZSTR_VAL ( op2_string ), op2_len );
1938
1951
ZSTR_VAL (result_str )[result_len ] = '\0' ;
1939
1952
}
1940
1953
1941
- zval_ptr_dtor_str (& op1_copy );
1942
- zval_ptr_dtor_str (& op2_copy );
1954
+ if (op1_string_from_func ) zend_string_release (op1_string );
1955
+ if (op2_string_from_func ) zend_string_release (op2_string );
1956
+
1943
1957
return SUCCESS ;
1944
1958
}
1945
1959
/* }}} */
0 commit comments