@@ -2045,14 +2045,45 @@ static void zend_get_gc_buffer_release(void) {
2045
2045
* of the value, we would end up leaking it. To avoid this, root all live TMPVAR values here. */
2046
2046
static void zend_gc_check_root_tmpvars (void ) {
2047
2047
zend_execute_data * ex = EG (current_execute_data );
2048
+
2049
+ if (!ex ) {
2050
+ return ;
2051
+ }
2052
+
2053
+ if (ZEND_USER_CODE (ex -> func -> type )) {
2054
+ const zend_op * op = ex -> opline ;
2055
+ if (op -> result_type & (IS_VAR | IS_TMP_VAR )) {
2056
+ switch (op -> opcode ) {
2057
+ case ZEND_ADD_ARRAY_ELEMENT :
2058
+ case ZEND_ADD_ARRAY_UNPACK :
2059
+ case ZEND_ROPE_INIT :
2060
+ case ZEND_ROPE_ADD :
2061
+ break ; /* live range handling will check those */
2062
+
2063
+ case ZEND_FETCH_CLASS :
2064
+ case ZEND_DECLARE_ANON_CLASS :
2065
+ break ; /* return value is zend_class_entry pointer */
2066
+
2067
+ default :
2068
+ /* smart branch opcodes may not initialize result */
2069
+ if (!zend_is_smart_branch (op )) {
2070
+ zval * var = ZEND_CALL_VAR (ex , op -> result .var );
2071
+ if (Z_COLLECTABLE_P (var )) {
2072
+ gc_check_possible_root (Z_COUNTED_P (var ));
2073
+ }
2074
+ }
2075
+ }
2076
+ }
2077
+ }
2078
+
2048
2079
for (; ex ; ex = ex -> prev_execute_data ) {
2049
2080
zend_function * func = ex -> func ;
2050
2081
if (!func || !ZEND_USER_CODE (func -> type )) {
2051
2082
continue ;
2052
2083
}
2053
2084
2054
2085
uint32_t op_num = ex -> opline - ex -> func -> op_array .opcodes ;
2055
- for (uint32_t i = 0 ; i < func -> op_array .last_live_range ; i ++ ) {
2086
+ for (int i = 0 ; i < func -> op_array .last_live_range ; i ++ ) {
2056
2087
const zend_live_range * range = & func -> op_array .live_range [i ];
2057
2088
if (range -> start > op_num ) {
2058
2089
break ;
@@ -2075,14 +2106,45 @@ static void zend_gc_check_root_tmpvars(void) {
2075
2106
2076
2107
static void zend_gc_remove_root_tmpvars (void ) {
2077
2108
zend_execute_data * ex = EG (current_execute_data );
2109
+
2110
+ if (!ex ) {
2111
+ return ;
2112
+ }
2113
+
2114
+ if (ZEND_USER_CODE (ex -> func -> type )) {
2115
+ const zend_op * op = ex -> opline ;
2116
+ if (op -> result_type & (IS_VAR | IS_TMP_VAR )) {
2117
+ switch (op -> opcode ) {
2118
+ case ZEND_ADD_ARRAY_ELEMENT :
2119
+ case ZEND_ADD_ARRAY_UNPACK :
2120
+ case ZEND_ROPE_INIT :
2121
+ case ZEND_ROPE_ADD :
2122
+ break ; /* live range handling will remove those */
2123
+
2124
+ case ZEND_FETCH_CLASS :
2125
+ case ZEND_DECLARE_ANON_CLASS :
2126
+ break ; /* return value is zend_class_entry pointer */
2127
+
2128
+ default :
2129
+ /* smart branch opcodes may not initialize result */
2130
+ if (!zend_is_smart_branch (op )) {
2131
+ zval * var = ZEND_CALL_VAR (ex , op -> result .var );
2132
+ if (Z_COLLECTABLE_P (var )) {
2133
+ GC_REMOVE_FROM_BUFFER (Z_COUNTED_P (var ));
2134
+ }
2135
+ }
2136
+ }
2137
+ }
2138
+ }
2139
+
2078
2140
for (; ex ; ex = ex -> prev_execute_data ) {
2079
2141
zend_function * func = ex -> func ;
2080
2142
if (!func || !ZEND_USER_CODE (func -> type )) {
2081
2143
continue ;
2082
2144
}
2083
2145
2084
2146
uint32_t op_num = ex -> opline - ex -> func -> op_array .opcodes ;
2085
- for (uint32_t i = 0 ; i < func -> op_array .last_live_range ; i ++ ) {
2147
+ for (int i = 0 ; i < func -> op_array .last_live_range ; i ++ ) {
2086
2148
const zend_live_range * range = & func -> op_array .live_range [i ];
2087
2149
if (range -> start > op_num ) {
2088
2150
break ;
0 commit comments