@@ -41,6 +41,7 @@ ZEND_API HashTable module_registry;
41
41
static zend_module_entry * * module_request_startup_handlers ;
42
42
static zend_module_entry * * module_request_shutdown_handlers ;
43
43
static zend_module_entry * * module_post_deactivate_handlers ;
44
+ static zend_module_entry * * modules_dl_loaded ;
44
45
45
46
static zend_class_entry * * class_cleanup_handlers ;
46
47
@@ -2292,6 +2293,7 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
2292
2293
int startup_count = 0 ;
2293
2294
int shutdown_count = 0 ;
2294
2295
int post_deactivate_count = 0 ;
2296
+ int dl_loaded_count = 0 ;
2295
2297
zend_class_entry * ce ;
2296
2298
int class_count = 0 ;
2297
2299
@@ -2306,6 +2308,9 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
2306
2308
if (module -> post_deactivate_func ) {
2307
2309
post_deactivate_count ++ ;
2308
2310
}
2311
+ if (module -> handle ) {
2312
+ dl_loaded_count ++ ;
2313
+ }
2309
2314
} ZEND_HASH_FOREACH_END ();
2310
2315
module_request_startup_handlers = (zend_module_entry * * )realloc (
2311
2316
module_request_startup_handlers ,
@@ -2318,6 +2323,10 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
2318
2323
module_request_shutdown_handlers [shutdown_count ] = NULL ;
2319
2324
module_post_deactivate_handlers = module_request_shutdown_handlers + shutdown_count + 1 ;
2320
2325
module_post_deactivate_handlers [post_deactivate_count ] = NULL ;
2326
+ /* Cannot reuse module_request_startup_handlers because it is freed in zend_destroy_modules, which happens before zend_unload_modules.
2327
+ * It is possible to move freeing module_request_startup_handlers to zend_unload_modules, but that changes public API. */
2328
+ modules_dl_loaded = realloc (modules_dl_loaded , sizeof (zend_module_entry * ) * (dl_loaded_count + 1 ));
2329
+ modules_dl_loaded [dl_loaded_count ] = NULL ;
2321
2330
startup_count = 0 ;
2322
2331
2323
2332
ZEND_HASH_MAP_FOREACH_PTR (& module_registry , module ) {
@@ -2330,6 +2339,9 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
2330
2339
if (module -> post_deactivate_func ) {
2331
2340
module_post_deactivate_handlers [-- post_deactivate_count ] = module ;
2332
2341
}
2342
+ if (module -> handle ) {
2343
+ modules_dl_loaded [-- dl_loaded_count ] = module ;
2344
+ }
2333
2345
} ZEND_HASH_FOREACH_END ();
2334
2346
2335
2347
/* Collect internal classes with static members */
@@ -3082,7 +3094,7 @@ void module_destructor(zend_module_entry *module) /* {{{ */
3082
3094
void module_registry_unload (const zend_module_entry * module )
3083
3095
{
3084
3096
#if HAVE_LIBDL
3085
- if (module -> handle && !getenv ("ZEND_DONT_UNLOAD_MODULES" )) {
3097
+ if (!getenv ("ZEND_DONT_UNLOAD_MODULES" )) {
3086
3098
DL_UNLOAD (module -> handle );
3087
3099
}
3088
3100
#else
@@ -3134,6 +3146,17 @@ ZEND_API void zend_deactivate_modules(void) /* {{{ */
3134
3146
}
3135
3147
/* }}} */
3136
3148
3149
+ void zend_unload_modules (void ) /* {{{ */
3150
+ {
3151
+ zend_module_entry * * modules = modules_dl_loaded ;
3152
+ while (* modules ) {
3153
+ module_registry_unload (* modules );
3154
+ modules ++ ;
3155
+ }
3156
+ free (modules_dl_loaded );
3157
+ }
3158
+ /* }}} */
3159
+
3137
3160
ZEND_API void zend_post_deactivate_modules (void ) /* {{{ */
3138
3161
{
3139
3162
if (EG (full_tables_cleanup )) {
@@ -3152,7 +3175,9 @@ ZEND_API void zend_post_deactivate_modules(void) /* {{{ */
3152
3175
break ;
3153
3176
}
3154
3177
module_destructor (module );
3155
- module_registry_unload (module );
3178
+ if (module -> handle ) {
3179
+ module_registry_unload (module );
3180
+ }
3156
3181
zend_string_release_ex (key , 0 );
3157
3182
} ZEND_HASH_MAP_FOREACH_END_DEL ();
3158
3183
} else {
0 commit comments