@@ -2045,14 +2045,45 @@ static void zend_get_gc_buffer_release(void) {
20452045 * of the value, we would end up leaking it. To avoid this, root all live TMPVAR values here. */
20462046static void zend_gc_check_root_tmpvars (void ) {
20472047 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+
20482079 for (; ex ; ex = ex -> prev_execute_data ) {
20492080 zend_function * func = ex -> func ;
20502081 if (!func || !ZEND_USER_CODE (func -> type )) {
20512082 continue ;
20522083 }
20532084
20542085 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 ++ ) {
20562087 const zend_live_range * range = & func -> op_array .live_range [i ];
20572088 if (range -> start > op_num ) {
20582089 break ;
@@ -2075,14 +2106,45 @@ static void zend_gc_check_root_tmpvars(void) {
20752106
20762107static void zend_gc_remove_root_tmpvars (void ) {
20772108 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+
20782140 for (; ex ; ex = ex -> prev_execute_data ) {
20792141 zend_function * func = ex -> func ;
20802142 if (!func || !ZEND_USER_CODE (func -> type )) {
20812143 continue ;
20822144 }
20832145
20842146 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 ++ ) {
20862148 const zend_live_range * range = & func -> op_array .live_range [i ];
20872149 if (range -> start > op_num ) {
20882150 break ;
0 commit comments