From 32314f6b6715ec6bfd5a2d88310768e2fa9bf707 Mon Sep 17 00:00:00 2001 From: Keyur Govande Date: Thu, 14 Aug 2014 00:55:14 +0000 Subject: Fix destruction order in zend_shutdown (bug #65463, #66036) If Apache or a similar SAPI receives a signal during PHP processing it calls zend_shutdown() without calling shutdown_executor(). #65463: If a module like Gearman or Memcached is loaded, in the unfixed version it is unloaded by zend_destroy_modules() before the CG(CLASS_TABLE) is destructed. When CG(CLASS_TABLE) is destructed, any pointers to methods (specifically around destruction) in the unloaded module's .so are now dangling and the process segfaults. #66036: Any subclasses of an internal class like ArrayObject need to be destructed in order: subclass first and then the internal class. In the unfixed version zend_shutdown() clears the CG(CLASS_TABLE) from the head of the list onwards, so internal classes are destructed first and user-defined classes last. Internal classes are alloc/deallocated with malloc/free while user-defined classes with emalloc/efree. If there's shared data between them then efree() could be called instead of free() leading to a seg-fault. --- Zend/zend.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'Zend/zend.c') diff --git a/Zend/zend.c b/Zend/zend.c index fc443d95b9..e0f400ab22 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -817,6 +817,17 @@ void zend_shutdown(TSRMLS_D) /* {{{ */ zend_shutdown_timeout_thread(); #endif zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); + + /* + * The order of destruction is important here. + * See bugs #65463 and 66036. + */ + zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); + zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) zend_cleanup_user_class_data TSRMLS_CC); + zend_cleanup_internal_classes(TSRMLS_C); + zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full TSRMLS_CC); + zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full TSRMLS_CC); + zend_destroy_modules(); zend_hash_destroy(GLOBAL_FUNCTION_TABLE); -- cgit v1.2.1 From 437612f65615a93fe338fd5c25acb82d3e81a6f7 Mon Sep 17 00:00:00 2001 From: Keyur Govande Date: Sat, 23 Aug 2014 14:17:37 +0000 Subject: Only destruct if EG(active) in zend_shutdown(). (bug #65463, #66036) --- Zend/zend.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'Zend/zend.c') diff --git a/Zend/zend.c b/Zend/zend.c index e0f400ab22..35f215f320 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -818,15 +818,18 @@ void zend_shutdown(TSRMLS_D) /* {{{ */ #endif zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); - /* - * The order of destruction is important here. - * See bugs #65463 and 66036. - */ - zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); - zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) zend_cleanup_user_class_data TSRMLS_CC); - zend_cleanup_internal_classes(TSRMLS_C); - zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full TSRMLS_CC); - zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full TSRMLS_CC); + if (EG(active)) + { + /* + * The order of destruction is important here. + * See bugs #65463 and 66036. + */ + zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); + zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) zend_cleanup_user_class_data TSRMLS_CC); + zend_cleanup_internal_classes(TSRMLS_C); + zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full TSRMLS_CC); + zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full TSRMLS_CC); + } zend_destroy_modules(); -- cgit v1.2.1