@@ -1840,106 +1840,138 @@ 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_is_non_string_or_copy = false;
1845
+ bool op2_is_non_string_or_copy = false;
1847
1846
1848
1847
do {
1849
- if (UNEXPECTED (Z_TYPE_P (op1 ) != IS_STRING )) {
1848
+ if (EXPECTED (Z_TYPE_P (op1 ) == IS_STRING )) {
1849
+ op1_string = Z_STR_P (op1 );
1850
+ } else {
1850
1851
if (Z_ISREF_P (op1 )) {
1851
1852
op1 = Z_REFVAL_P (op1 );
1852
- if (Z_TYPE_P (op1 ) == IS_STRING ) break ;
1853
+ if (Z_TYPE_P (op1 ) == IS_STRING ) {
1854
+ op1_string = Z_STR_P (op1 );
1855
+ break ;
1856
+ }
1853
1857
}
1854
1858
ZEND_TRY_BINARY_OBJECT_OPERATION (ZEND_CONCAT );
1855
- ZVAL_STR ( & op1_copy , zval_get_string_func (op1 ) );
1859
+ op1_string = zval_get_string_func (op1 );
1856
1860
if (UNEXPECTED (EG (exception ))) {
1857
- zval_ptr_dtor_str ( & op1_copy );
1861
+ zend_string_release ( op1_string );
1858
1862
if (orig_op1 != result ) {
1859
1863
ZVAL_UNDEF (result );
1860
1864
}
1861
1865
return FAILURE ;
1862
1866
}
1867
+ op1_is_non_string_or_copy = true;
1863
1868
if (result == op1 ) {
1864
1869
if (UNEXPECTED (op1 == op2 )) {
1865
- op2 = & op1_copy ;
1870
+ op2_string = op1_string ;
1866
1871
}
1867
1872
}
1868
- op1 = & op1_copy ;
1869
1873
}
1870
1874
} while (0 );
1871
1875
do {
1872
- if (UNEXPECTED (Z_TYPE_P (op2 ) != IS_STRING )) {
1873
- if (Z_ISREF_P (op2 )) {
1874
- op2 = Z_REFVAL_P (op2 );
1875
- if (Z_TYPE_P (op2 ) == IS_STRING ) break ;
1876
- }
1877
- ZEND_TRY_BINARY_OP2_OBJECT_OPERATION (ZEND_CONCAT );
1878
- ZVAL_STR (& op2_copy , zval_get_string_func (op2 ));
1879
- if (UNEXPECTED (EG (exception ))) {
1880
- zval_ptr_dtor_str (& op1_copy );
1881
- zval_ptr_dtor_str (& op2_copy );
1882
- if (orig_op1 != result ) {
1883
- ZVAL_UNDEF (result );
1876
+ if (!op2_string ) {
1877
+ if (EXPECTED (Z_TYPE_P (op2 ) == IS_STRING )) {
1878
+ op2_string = Z_STR_P (op2 );
1879
+ } else {
1880
+ if (Z_ISREF_P (op2 )) {
1881
+ op2 = Z_REFVAL_P (op2 );
1882
+ if (Z_TYPE_P (op2 ) == IS_STRING ) {
1883
+ op2_string = Z_STR_P (op2 );
1884
+ break ;
1885
+ }
1884
1886
}
1885
- return FAILURE ;
1887
+ /* hold an additional reference because a userland function could free this */
1888
+ if (!op1_is_non_string_or_copy ) {
1889
+ op1_string = zend_string_copy (op1_string );
1890
+ op1_is_non_string_or_copy = true;
1891
+ }
1892
+ ZEND_TRY_BINARY_OP2_OBJECT_OPERATION (ZEND_CONCAT );
1893
+ op2_string = zval_get_string_func (op2 );
1894
+ if (UNEXPECTED (EG (exception ))) {
1895
+ zend_string_release (op1_string );
1896
+ zend_string_release (op2_string );
1897
+ if (orig_op1 != result ) {
1898
+ ZVAL_UNDEF (result );
1899
+ }
1900
+ return FAILURE ;
1901
+ }
1902
+ op2_is_non_string_or_copy = true;
1886
1903
}
1887
- op2 = & op2_copy ;
1888
1904
}
1889
1905
} while (0 );
1890
1906
1891
- if (UNEXPECTED (Z_STRLEN_P ( op1 ) == 0 )) {
1892
- if (EXPECTED (result != op2 )) {
1907
+ if (UNEXPECTED (ZSTR_LEN ( op1_string ) == 0 )) {
1908
+ if (EXPECTED (op2_is_non_string_or_copy || result != op2 )) {
1893
1909
if (result == orig_op1 ) {
1894
1910
i_zval_ptr_dtor (result );
1895
1911
}
1896
- ZVAL_COPY (result , op2 );
1912
+ if (op2_is_non_string_or_copy ) {
1913
+ ZVAL_STR (result , op2_string );
1914
+ op2_is_non_string_or_copy = false;
1915
+ } else {
1916
+ ZVAL_STR_COPY (result , op2_string );
1917
+ }
1897
1918
}
1898
- } else if (UNEXPECTED (Z_STRLEN_P ( op2 ) == 0 )) {
1899
- if (EXPECTED (result != op1 )) {
1919
+ } else if (UNEXPECTED (ZSTR_LEN ( op2_string ) == 0 )) {
1920
+ if (EXPECTED (op1_is_non_string_or_copy || result != op1 )) {
1900
1921
if (result == orig_op1 ) {
1901
1922
i_zval_ptr_dtor (result );
1902
1923
}
1903
- ZVAL_COPY (result , op1 );
1924
+ if (op1_is_non_string_or_copy ) {
1925
+ ZVAL_STR (result , op1_string );
1926
+ op1_is_non_string_or_copy = false;
1927
+ } else {
1928
+ ZVAL_STR_COPY (result , op1_string );
1929
+ }
1904
1930
}
1905
1931
} else {
1906
- size_t op1_len = Z_STRLEN_P ( op1 );
1907
- size_t op2_len = Z_STRLEN_P ( op2 );
1932
+ size_t op1_len = ZSTR_LEN ( op1_string );
1933
+ size_t op2_len = ZSTR_LEN ( op2_string );
1908
1934
size_t result_len = op1_len + op2_len ;
1909
1935
zend_string * result_str ;
1910
1936
1911
1937
if (UNEXPECTED (op1_len > ZSTR_MAX_LEN - op2_len )) {
1938
+ if (op1_is_non_string_or_copy ) zend_string_release (op1_string );
1939
+ if (op2_is_non_string_or_copy ) zend_string_release (op2_string );
1912
1940
zend_throw_error (NULL , "String size overflow" );
1913
- zval_ptr_dtor_str (& op1_copy );
1914
- zval_ptr_dtor_str (& op2_copy );
1915
1941
if (orig_op1 != result ) {
1916
1942
ZVAL_UNDEF (result );
1917
1943
}
1918
1944
return FAILURE ;
1919
1945
}
1920
1946
1921
- if (result == op1 && Z_REFCOUNTED_P (result )) {
1947
+ if (result == op1 ) {
1948
+ if (op1_is_non_string_or_copy ) {
1949
+ i_zval_ptr_dtor (result );
1950
+ op1_is_non_string_or_copy = false;
1951
+ }
1922
1952
/* special case, perform operations on result */
1923
- result_str = zend_string_extend (Z_STR_P (result ), result_len , 0 );
1953
+ result_str = zend_string_extend (op1_string , result_len , 0 );
1954
+ /* account for the case where result == op1 == op2 and the realloc is done */
1955
+ if (op1_string == op2_string ) {
1956
+ op2_string = result_str ;
1957
+ op2_is_non_string_or_copy = false;
1958
+ }
1924
1959
} else {
1925
1960
result_str = zend_string_alloc (result_len , 0 );
1926
- memcpy (ZSTR_VAL (result_str ), Z_STRVAL_P ( op1 ), op1_len );
1961
+ memcpy (ZSTR_VAL (result_str ), ZSTR_VAL ( op1_string ), op1_len );
1927
1962
if (result == orig_op1 ) {
1928
1963
i_zval_ptr_dtor (result );
1929
1964
}
1930
1965
}
1931
1966
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
1967
ZVAL_NEW_STR (result , result_str );
1936
-
1937
- memcpy (ZSTR_VAL (result_str ) + op1_len , Z_STRVAL_P (op2 ), op2_len );
1968
+ memcpy (ZSTR_VAL (result_str ) + op1_len , ZSTR_VAL (op2_string ), op2_len );
1938
1969
ZSTR_VAL (result_str )[result_len ] = '\0' ;
1939
1970
}
1940
1971
1941
- zval_ptr_dtor_str (& op1_copy );
1942
- zval_ptr_dtor_str (& op2_copy );
1972
+ if (op1_is_non_string_or_copy ) zend_string_release (op1_string );
1973
+ if (op2_is_non_string_or_copy ) zend_string_release (op2_string );
1974
+
1943
1975
return SUCCESS ;
1944
1976
}
1945
1977
/* }}} */
0 commit comments