@@ -2216,14 +2216,45 @@ static void zend_get_gc_buffer_release(void) {
22162216 * of the value, we would end up leaking it. To avoid this, root all live TMPVAR values here. */
22172217static void zend_gc_check_root_tmpvars (void ) {
22182218 zend_execute_data * ex = EG (current_execute_data );
2219+
2220+ if (!ex ) {
2221+ return ;
2222+ }
2223+
2224+ if (ZEND_USER_CODE (ex -> func -> type )) {
2225+ const zend_op * op = ex -> opline ;
2226+ if (op -> result_type & (IS_VAR | IS_TMP_VAR )) {
2227+ switch (op -> opcode ) {
2228+ case ZEND_ADD_ARRAY_ELEMENT :
2229+ case ZEND_ADD_ARRAY_UNPACK :
2230+ case ZEND_ROPE_INIT :
2231+ case ZEND_ROPE_ADD :
2232+ break ; /* live range handling will check those */
2233+
2234+ case ZEND_FETCH_CLASS :
2235+ case ZEND_DECLARE_ANON_CLASS :
2236+ break ; /* return value is zend_class_entry pointer */
2237+
2238+ default :
2239+ /* smart branch opcodes may not initialize result */
2240+ if (!zend_is_smart_branch (op )) {
2241+ zval * var = ZEND_CALL_VAR (ex , op -> result .var );
2242+ if (Z_COLLECTABLE_P (var )) {
2243+ gc_check_possible_root (Z_COUNTED_P (var ));
2244+ }
2245+ }
2246+ }
2247+ }
2248+ }
2249+
22192250 for (; ex ; ex = ex -> prev_execute_data ) {
22202251 zend_function * func = ex -> func ;
22212252 if (!func || !ZEND_USER_CODE (func -> type )) {
22222253 continue ;
22232254 }
22242255
22252256 uint32_t op_num = ex -> opline - ex -> func -> op_array .opcodes ;
2226- for (uint32_t i = 0 ; i < func -> op_array .last_live_range ; i ++ ) {
2257+ for (int i = 0 ; i < func -> op_array .last_live_range ; i ++ ) {
22272258 const zend_live_range * range = & func -> op_array .live_range [i ];
22282259 if (range -> start > op_num ) {
22292260 break ;
@@ -2246,14 +2277,45 @@ static void zend_gc_check_root_tmpvars(void) {
22462277
22472278static void zend_gc_remove_root_tmpvars (void ) {
22482279 zend_execute_data * ex = EG (current_execute_data );
2280+
2281+ if (!ex ) {
2282+ return ;
2283+ }
2284+
2285+ if (ZEND_USER_CODE (ex -> func -> type )) {
2286+ const zend_op * op = ex -> opline ;
2287+ if (op -> result_type & (IS_VAR | IS_TMP_VAR )) {
2288+ switch (op -> opcode ) {
2289+ case ZEND_ADD_ARRAY_ELEMENT :
2290+ case ZEND_ADD_ARRAY_UNPACK :
2291+ case ZEND_ROPE_INIT :
2292+ case ZEND_ROPE_ADD :
2293+ break ; /* live range handling will remove those */
2294+
2295+ case ZEND_FETCH_CLASS :
2296+ case ZEND_DECLARE_ANON_CLASS :
2297+ break ; /* return value is zend_class_entry pointer */
2298+
2299+ default :
2300+ /* smart branch opcodes may not initialize result */
2301+ if (!zend_is_smart_branch (op )) {
2302+ zval * var = ZEND_CALL_VAR (ex , op -> result .var );
2303+ if (Z_COLLECTABLE_P (var )) {
2304+ GC_REMOVE_FROM_BUFFER (Z_COUNTED_P (var ));
2305+ }
2306+ }
2307+ }
2308+ }
2309+ }
2310+
22492311 for (; ex ; ex = ex -> prev_execute_data ) {
22502312 zend_function * func = ex -> func ;
22512313 if (!func || !ZEND_USER_CODE (func -> type )) {
22522314 continue ;
22532315 }
22542316
22552317 uint32_t op_num = ex -> opline - ex -> func -> op_array .opcodes ;
2256- for (uint32_t i = 0 ; i < func -> op_array .last_live_range ; i ++ ) {
2318+ for (int i = 0 ; i < func -> op_array .last_live_range ; i ++ ) {
22572319 const zend_live_range * range = & func -> op_array .live_range [i ];
22582320 if (range -> start > op_num ) {
22592321 break ;
0 commit comments