@@ -278,6 +278,24 @@ void shutdown_executor(void) /* {{{ */
278
278
if (!fast_shutdown ) {
279
279
zend_hash_graceful_reverse_destroy (& EG (symbol_table ));
280
280
281
+ /* Constants may contain objects, destroy them before the object store. */
282
+ if (EG (full_tables_cleanup )) {
283
+ zend_hash_reverse_apply (EG (zend_constants ), clean_non_persistent_constant_full );
284
+ } else {
285
+ ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL (EG (zend_constants ), key , zv ) {
286
+ zend_constant * c = Z_PTR_P (zv );
287
+ if (_idx == EG (persistent_constants_count )) {
288
+ break ;
289
+ }
290
+ zval_ptr_dtor_nogc (& c -> value );
291
+ if (c -> name ) {
292
+ zend_string_release_ex (c -> name , 0 );
293
+ }
294
+ efree (c );
295
+ zend_string_release_ex (key , 0 );
296
+ } ZEND_HASH_FOREACH_END_DEL ();
297
+ }
298
+
281
299
/* Release static properties and static variables prior to the final GC run,
282
300
* as they may hold GC roots. */
283
301
ZEND_HASH_REVERSE_FOREACH_VAL (EG (function_table ), zv ) {
@@ -302,6 +320,15 @@ void shutdown_executor(void) /* {{{ */
302
320
303
321
if (ZEND_MAP_PTR (ce -> mutable_data ) && ZEND_MAP_PTR_GET_IMM (ce -> mutable_data )) {
304
322
zend_cleanup_mutable_class_data (ce );
323
+ } else if (ce -> type == ZEND_USER_CLASS && !(ce -> ce_flags & ZEND_ACC_IMMUTABLE )) {
324
+ /* Constants may contain objects, destroy the values before the object store. */
325
+ zend_class_constant * c ;
326
+ ZEND_HASH_FOREACH_PTR (& ce -> constants_table , c ) {
327
+ if (c -> ce == ce ) {
328
+ zval_ptr_dtor_nogc (& c -> value );
329
+ ZVAL_UNDEF (& c -> value );
330
+ }
331
+ } ZEND_HASH_FOREACH_END ();
305
332
}
306
333
307
334
if (ce -> ce_flags & ZEND_HAS_STATIC_IN_METHODS ) {
@@ -340,6 +367,8 @@ void shutdown_executor(void) /* {{{ */
340
367
gc_collect_cycles ();
341
368
}
342
369
#endif
370
+ } else {
371
+ zend_hash_discard (EG (zend_constants ), EG (persistent_constants_count ));
343
372
}
344
373
345
374
zend_objects_store_free_object_storage (& EG (objects_store ), fast_shutdown );
@@ -356,31 +385,16 @@ void shutdown_executor(void) /* {{{ */
356
385
* Zend Memory Manager frees memory by its own. We don't have to free
357
386
* each allocated block separately.
358
387
*/
359
- zend_hash_discard (EG (zend_constants ), EG (persistent_constants_count ));
360
388
zend_hash_discard (EG (function_table ), EG (persistent_functions_count ));
361
389
zend_hash_discard (EG (class_table ), EG (persistent_classes_count ));
362
390
zend_cleanup_internal_classes ();
363
391
} else {
364
392
zend_vm_stack_destroy ();
365
393
366
394
if (EG (full_tables_cleanup )) {
367
- zend_hash_reverse_apply (EG (zend_constants ), clean_non_persistent_constant_full );
368
395
zend_hash_reverse_apply (EG (function_table ), clean_non_persistent_function_full );
369
396
zend_hash_reverse_apply (EG (class_table ), clean_non_persistent_class_full );
370
397
} else {
371
- ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL (EG (zend_constants ), key , zv ) {
372
- zend_constant * c = Z_PTR_P (zv );
373
- if (_idx == EG (persistent_constants_count )) {
374
- break ;
375
- }
376
- zval_ptr_dtor_nogc (& c -> value );
377
- if (c -> name ) {
378
- zend_string_release_ex (c -> name , 0 );
379
- }
380
- efree (c );
381
- zend_string_release_ex (key , 0 );
382
- } ZEND_HASH_FOREACH_END_DEL ();
383
-
384
398
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL (EG (function_table ), key , zv ) {
385
399
zend_function * func = Z_PTR_P (zv );
386
400
if (_idx == EG (persistent_functions_count )) {
0 commit comments