@@ -1940,108 +1940,146 @@ ZEND_API zend_result ZEND_FASTCALL shift_right_function(zval *result, zval *op1,
1940
1940
ZEND_API zend_result ZEND_FASTCALL concat_function (zval * result , zval * op1 , zval * op2 ) /* {{{ */
1941
1941
{
1942
1942
zval * orig_op1 = op1 ;
1943
- zval op1_copy , op2_copy ;
1944
-
1945
- ZVAL_UNDEF (& op1_copy );
1946
- ZVAL_UNDEF (& op2_copy );
1943
+ zend_string * op1_string , * op2_string ;
1944
+ bool free_op1_string = false;
1945
+ bool free_op2_string = false;
1947
1946
1948
1947
do {
1949
- if (UNEXPECTED (Z_TYPE_P (op1 ) != IS_STRING )) {
1948
+ if (EXPECTED (Z_TYPE_P (op1 ) == IS_STRING )) {
1949
+ op1_string = Z_STR_P (op1 );
1950
+ } else {
1950
1951
if (Z_ISREF_P (op1 )) {
1951
1952
op1 = Z_REFVAL_P (op1 );
1952
- if (Z_TYPE_P (op1 ) == IS_STRING ) break ;
1953
+ if (Z_TYPE_P (op1 ) == IS_STRING ) {
1954
+ op1_string = Z_STR_P (op1 );
1955
+ break ;
1956
+ }
1953
1957
}
1954
1958
ZEND_TRY_BINARY_OBJECT_OPERATION (ZEND_CONCAT );
1955
- ZVAL_STR ( & op1_copy , zval_get_string_func (op1 ) );
1959
+ op1_string = zval_get_string_func (op1 );
1956
1960
if (UNEXPECTED (EG (exception ))) {
1957
- zval_ptr_dtor_str ( & op1_copy );
1961
+ zend_string_release ( op1_string );
1958
1962
if (orig_op1 != result ) {
1959
1963
ZVAL_UNDEF (result );
1960
1964
}
1961
1965
return FAILURE ;
1962
1966
}
1967
+ free_op1_string = true;
1963
1968
if (result == op1 ) {
1964
1969
if (UNEXPECTED (op1 == op2 )) {
1965
- op2 = & op1_copy ;
1970
+ op2_string = op1_string ;
1971
+ goto has_op2_string ;
1966
1972
}
1967
1973
}
1968
- op1 = & op1_copy ;
1969
1974
}
1970
1975
} while (0 );
1971
1976
do {
1972
- if (UNEXPECTED (Z_TYPE_P (op2 ) != IS_STRING )) {
1973
- if (Z_ISREF_P (op2 )) {
1974
- op2 = Z_REFVAL_P (op2 );
1975
- if (Z_TYPE_P (op2 ) == IS_STRING ) break ;
1976
- }
1977
+ if (EXPECTED (Z_TYPE_P (op2 ) == IS_STRING )) {
1978
+ op2_string = Z_STR_P (op2 );
1979
+ } else {
1980
+ if (Z_ISREF_P (op2 )) {
1981
+ op2 = Z_REFVAL_P (op2 );
1982
+ if (Z_TYPE_P (op2 ) == IS_STRING ) {
1983
+ op2_string = Z_STR_P (op2 );
1984
+ break ;
1985
+ }
1986
+ }
1987
+ /* hold an additional reference because a userland function could free this */
1988
+ if (!free_op1_string ) {
1989
+ op1_string = zend_string_copy (op1_string );
1990
+ free_op1_string = true;
1991
+ }
1977
1992
ZEND_TRY_BINARY_OP2_OBJECT_OPERATION (ZEND_CONCAT );
1978
- ZVAL_STR ( & op2_copy , zval_get_string_func (op2 ) );
1993
+ op2_string = zval_get_string_func (op2 );
1979
1994
if (UNEXPECTED (EG (exception ))) {
1980
- zval_ptr_dtor_str ( & op1_copy );
1981
- zval_ptr_dtor_str ( & op2_copy );
1995
+ zend_string_release ( op1_string );
1996
+ zend_string_release ( op2_string );
1982
1997
if (orig_op1 != result ) {
1983
1998
ZVAL_UNDEF (result );
1984
1999
}
1985
2000
return FAILURE ;
1986
2001
}
1987
- op2 = & op2_copy ;
2002
+ free_op2_string = true ;
1988
2003
}
1989
2004
} while (0 );
1990
2005
1991
- if (UNEXPECTED (Z_STRLEN_P (op1 ) == 0 )) {
1992
- if (EXPECTED (result != op2 )) {
2006
+ has_op2_string :;
2007
+ if (UNEXPECTED (ZSTR_LEN (op1_string ) == 0 )) {
2008
+ if (EXPECTED (free_op2_string || result != op2 )) {
1993
2009
if (result == orig_op1 ) {
1994
2010
i_zval_ptr_dtor (result );
1995
2011
}
1996
- ZVAL_COPY (result , op2 );
2012
+ if (free_op2_string ) {
2013
+ /* transfer ownership of op2_string */
2014
+ ZVAL_STR (result , op2_string );
2015
+ free_op2_string = false;
2016
+ } else {
2017
+ ZVAL_STR_COPY (result , op2_string );
2018
+ }
1997
2019
}
1998
- } else if (UNEXPECTED (Z_STRLEN_P ( op2 ) == 0 )) {
1999
- if (EXPECTED (result != op1 )) {
2020
+ } else if (UNEXPECTED (ZSTR_LEN ( op2_string ) == 0 )) {
2021
+ if (EXPECTED (free_op1_string || result != op1 )) {
2000
2022
if (result == orig_op1 ) {
2001
2023
i_zval_ptr_dtor (result );
2002
2024
}
2003
- ZVAL_COPY (result , op1 );
2025
+ if (free_op1_string ) {
2026
+ /* transfer ownership of op1_string */
2027
+ ZVAL_STR (result , op1_string );
2028
+ free_op1_string = false;
2029
+ } else {
2030
+ ZVAL_STR_COPY (result , op1_string );
2031
+ }
2004
2032
}
2005
2033
} else {
2006
- size_t op1_len = Z_STRLEN_P ( op1 );
2007
- size_t op2_len = Z_STRLEN_P ( op2 );
2034
+ size_t op1_len = ZSTR_LEN ( op1_string );
2035
+ size_t op2_len = ZSTR_LEN ( op2_string );
2008
2036
size_t result_len = op1_len + op2_len ;
2009
2037
zend_string * result_str ;
2010
- uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH (Z_STR_P ( op1 ), Z_STR_P ( op2 ) );
2038
+ uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH (op1_string , op2_string );
2011
2039
2012
2040
if (UNEXPECTED (op1_len > ZSTR_MAX_LEN - op2_len )) {
2041
+ if (free_op1_string ) zend_string_release (op1_string );
2042
+ if (free_op2_string ) zend_string_release (op2_string );
2013
2043
zend_throw_error (NULL , "String size overflow" );
2014
- zval_ptr_dtor_str (& op1_copy );
2015
- zval_ptr_dtor_str (& op2_copy );
2016
2044
if (orig_op1 != result ) {
2017
2045
ZVAL_UNDEF (result );
2018
2046
}
2019
2047
return FAILURE ;
2020
2048
}
2021
2049
2022
- if (result == op1 && Z_REFCOUNTED_P (result )) {
2050
+ if (result == op1 ) {
2051
+ if (free_op1_string ) {
2052
+ /* op1_string will be used as the result, so we should not free it */
2053
+ i_zval_ptr_dtor (result );
2054
+ free_op1_string = false;
2055
+ }
2023
2056
/* special case, perform operations on result */
2024
- result_str = zend_string_extend (Z_STR_P (result ), result_len , 0 );
2057
+ result_str = zend_string_extend (op1_string , result_len , 0 );
2058
+ /* account for the case where result_str == op1_string == op2_string and the realloc is done */
2059
+ if (op1_string == op2_string ) {
2060
+ if (free_op2_string ) {
2061
+ zend_string_release (op2_string );
2062
+ free_op2_string = false;
2063
+ }
2064
+ op2_string = result_str ;
2065
+ }
2025
2066
} else {
2026
2067
result_str = zend_string_alloc (result_len , 0 );
2027
- memcpy (ZSTR_VAL (result_str ), Z_STRVAL_P ( op1 ), op1_len );
2068
+ memcpy (ZSTR_VAL (result_str ), ZSTR_VAL ( op1_string ), op1_len );
2028
2069
if (result == orig_op1 ) {
2029
2070
i_zval_ptr_dtor (result );
2030
2071
}
2031
2072
}
2032
2073
GC_ADD_FLAGS (result_str , flags );
2033
2074
2034
- /* This has to happen first to account for the cases where result == op1 == op2 and
2035
- * the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to
2036
- * point to the new string. The first op2_len bytes of result will still be the same. */
2037
2075
ZVAL_NEW_STR (result , result_str );
2038
-
2039
- memcpy (ZSTR_VAL (result_str ) + op1_len , Z_STRVAL_P (op2 ), op2_len );
2076
+ memcpy (ZSTR_VAL (result_str ) + op1_len , ZSTR_VAL (op2_string ), op2_len );
2040
2077
ZSTR_VAL (result_str )[result_len ] = '\0' ;
2041
2078
}
2042
2079
2043
- zval_ptr_dtor_str (& op1_copy );
2044
- zval_ptr_dtor_str (& op2_copy );
2080
+ if (free_op1_string ) zend_string_release (op1_string );
2081
+ if (free_op2_string ) zend_string_release (op2_string );
2082
+
2045
2083
return SUCCESS ;
2046
2084
}
2047
2085
/* }}} */
0 commit comments