Skip to content

Commit 3f339ec

Browse files
committed
Merge branch 'PHP-7.4'
2 parents 937d5f6 + ec9a96d commit 3f339ec

File tree

2 files changed

+73
-48
lines changed

2 files changed

+73
-48
lines changed

Zend/tests/bug78335.phpt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
Bug #78335: Static properties/variables containing cycles report as leak
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public static $test;
8+
9+
public static function method() {
10+
static $foo;
11+
$foo = [&$foo];
12+
}
13+
}
14+
15+
function test() {
16+
static $foo;
17+
$foo = [&$foo];
18+
}
19+
20+
$foo = [&$foo];
21+
Test::$test = $foo;
22+
test();
23+
Test::method();
24+
25+
?>
26+
===DONE===
27+
--EXPECT--
28+
===DONE===

Zend/zend_execute_API.c

Lines changed: 45 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,54 @@ void shutdown_executor(void) /* {{{ */
268268
zend_close_rsrc_list(&EG(regular_list));
269269
} zend_end_try();
270270

271+
/* No PHP callback functions should be called after this point. */
272+
EG(active) = 0;
273+
271274
if (!fast_shutdown) {
272275
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
273276

277+
/* Release static properties and static variables prior to the final GC run,
278+
* as they may hold GC roots. */
279+
ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
280+
zend_op_array *op_array = Z_PTR_P(zv);
281+
if (op_array->type == ZEND_INTERNAL_FUNCTION) {
282+
break;
283+
}
284+
if (op_array->static_variables) {
285+
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
286+
if (ht) {
287+
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
288+
zend_array_destroy(ht);
289+
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
290+
}
291+
}
292+
} ZEND_HASH_FOREACH_END();
293+
ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
294+
zend_class_entry *ce = Z_PTR_P(zv);
295+
if (ce->type == ZEND_INTERNAL_CLASS) {
296+
break;
297+
}
298+
if (ce->default_static_members_count) {
299+
zend_cleanup_internal_class_data(ce);
300+
}
301+
if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
302+
zend_op_array *op_array;
303+
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
304+
if (op_array->type == ZEND_USER_FUNCTION) {
305+
if (op_array->static_variables) {
306+
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
307+
if (ht) {
308+
if (GC_DELREF(ht) == 0) {
309+
zend_array_destroy(ht);
310+
}
311+
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
312+
}
313+
}
314+
}
315+
} ZEND_HASH_FOREACH_END();
316+
}
317+
} ZEND_HASH_FOREACH_END();
318+
274319
#if ZEND_DEBUG
275320
if (gc_enabled() && !CG(unclean_shutdown)) {
276321
gc_collect_cycles();
@@ -282,10 +327,6 @@ void shutdown_executor(void) /* {{{ */
282327

283328
zend_weakrefs_shutdown();
284329

285-
/* All resources and objects are destroyed. */
286-
/* No PHP callback functions may be called after this point. */
287-
EG(active) = 0;
288-
289330
zend_try {
290331
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
291332
} zend_end_try();
@@ -346,57 +387,13 @@ void shutdown_executor(void) /* {{{ */
346387
zend_string_release_ex(key, 0);
347388
} ZEND_HASH_FOREACH_END_DEL();
348389

349-
/* Cleanup preloaded immutable functions */
350-
ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
351-
zend_op_array *op_array = Z_PTR_P(zv);
352-
if (op_array->type == ZEND_INTERNAL_FUNCTION) {
353-
break;
354-
}
355-
ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_IMMUTABLE);
356-
if (op_array->static_variables) {
357-
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
358-
if (ht) {
359-
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
360-
zend_array_destroy(ht);
361-
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
362-
}
363-
}
364-
} ZEND_HASH_FOREACH_END();
365-
366390
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
367391
if (_idx == EG(persistent_classes_count)) {
368392
break;
369393
}
370394
destroy_zend_class(zv);
371395
zend_string_release_ex(key, 0);
372396
} ZEND_HASH_FOREACH_END_DEL();
373-
374-
/* Cleanup preloaded immutable classes */
375-
ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
376-
zend_class_entry *ce = Z_PTR_P(zv);
377-
if (ce->type == ZEND_INTERNAL_CLASS) {
378-
break;
379-
}
380-
ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
381-
if (ce->default_static_members_count) {
382-
zend_cleanup_internal_class_data(ce);
383-
}
384-
if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
385-
zend_op_array *op_array;
386-
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
387-
if (op_array->type == ZEND_USER_FUNCTION) {
388-
if (op_array->static_variables) {
389-
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
390-
if (ht) {
391-
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
392-
zend_array_destroy(ht);
393-
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
394-
}
395-
}
396-
}
397-
} ZEND_HASH_FOREACH_END();
398-
}
399-
} ZEND_HASH_FOREACH_END();
400397
}
401398

402399
zend_cleanup_internal_classes();

0 commit comments

Comments
 (0)