diff options
author | Keyur Govande <keyur@php.net> | 2014-08-14 00:55:14 +0000 |
---|---|---|
committer | Keyur Govande <keyur@php.net> | 2014-08-14 00:55:14 +0000 |
commit | 32314f6b6715ec6bfd5a2d88310768e2fa9bf707 (patch) | |
tree | d530587e1465216a870cb3b71310bec6d8cd86d0 | |
parent | 42437dd870de28eee6c9127f4c7e7c78ba8e0152 (diff) | |
download | php-git-32314f6b6715ec6bfd5a2d88310768e2fa9bf707.tar.gz |
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.
-rw-r--r-- | Zend/zend.c | 11 | ||||
-rw-r--r-- | Zend/zend_compile.h | 2 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 6 |
3 files changed, 16 insertions, 3 deletions
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); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 50ee3a4d7f..3110edd060 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -639,6 +639,8 @@ ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC); ZEND_API void zend_cleanup_internal_classes(TSRMLS_D); ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC); ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC); +ZEND_API int clean_non_persistent_function_full(zend_function *function TSRMLS_DC); +ZEND_API int clean_non_persistent_class_full(zend_class_entry **ce TSRMLS_DC); ZEND_API void destroy_zend_function(zend_function *function TSRMLS_DC); ZEND_API void zend_function_dtor(zend_function *function); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index a38504fbb4..9efc13bf85 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -108,19 +108,19 @@ static int clean_non_persistent_function(zend_function *function TSRMLS_DC) /* { } /* }}} */ -static int clean_non_persistent_function_full(zend_function *function TSRMLS_DC) /* {{{ */ +ZEND_API int clean_non_persistent_function_full(zend_function *function TSRMLS_DC) /* {{{ */ { return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; } /* }}} */ -static int clean_non_persistent_class(zend_class_entry **ce TSRMLS_DC) /* {{{ */ +ZEND_API int clean_non_persistent_class(zend_class_entry **ce TSRMLS_DC) /* {{{ */ { return ((*ce)->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE; } /* }}} */ -static int clean_non_persistent_class_full(zend_class_entry **ce TSRMLS_DC) /* {{{ */ +ZEND_API int clean_non_persistent_class_full(zend_class_entry **ce TSRMLS_DC) /* {{{ */ { return ((*ce)->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; } |