]> granicus.if.org Git - php/commitdiff
Fix destruction order in zend_shutdown (bug #65463, #66036)
authorKeyur Govande <keyur@php.net>
Thu, 14 Aug 2014 00:55:14 +0000 (00:55 +0000)
committerKeyur Govande <keyur@php.net>
Thu, 14 Aug 2014 00:55:14 +0000 (00:55 +0000)
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
Zend/zend_compile.h
Zend/zend_execute_API.c

index fc443d95b919b7ef00a8402090829a6706425a98..e0f400ab223757f2d38777c375ab376c858bf433 100644 (file)
@@ -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);
index 50ee3a4d7fd338c77a197e3c5381fe5265ca0263..3110edd0605371f200198d64c4084beda850ac20 100644 (file)
@@ -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);
index a38504fbb4c20a71d18071af544274dec801a05f..9efc13bf8509ac21bb0f971b41894c7f08adda56 100644 (file)
@@ -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;
 }