@@ -2216,14 +2216,45 @@ static void zend_get_gc_buffer_release(void) {
2216
2216
* of the value, we would end up leaking it. To avoid this, root all live TMPVAR values here. */
2217
2217
static void zend_gc_check_root_tmpvars (void ) {
2218
2218
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
+
2219
2250
for (; ex ; ex = ex -> prev_execute_data ) {
2220
2251
zend_function * func = ex -> func ;
2221
2252
if (!func || !ZEND_USER_CODE (func -> type )) {
2222
2253
continue ;
2223
2254
}
2224
2255
2225
2256
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 ++ ) {
2227
2258
const zend_live_range * range = & func -> op_array .live_range [i ];
2228
2259
if (range -> start > op_num ) {
2229
2260
break ;
@@ -2246,14 +2277,45 @@ static void zend_gc_check_root_tmpvars(void) {
2246
2277
2247
2278
static void zend_gc_remove_root_tmpvars (void ) {
2248
2279
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
+
2249
2311
for (; ex ; ex = ex -> prev_execute_data ) {
2250
2312
zend_function * func = ex -> func ;
2251
2313
if (!func || !ZEND_USER_CODE (func -> type )) {
2252
2314
continue ;
2253
2315
}
2254
2316
2255
2317
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 ++ ) {
2257
2319
const zend_live_range * range = & func -> op_array .live_range [i ];
2258
2320
if (range -> start > op_num ) {
2259
2321
break ;
0 commit comments