Skip to content

Commit 2f60582

Browse files
committed
Workaround ZTS persistent resource crashes (PHP 8.3 and lower)
For master (8.4-dev) I merged phpGH-13381. But that PR changes public API of TSRM, so cannot be used on lower branches. This patch is a safe workaround for the issue, in combination with a pre-existing fix using `ifdef ZTS + if (module_started)` inside pgsql and odbc. The idea is to delay unloading modules until the persistent resources are destroyed. This will keep the destructor code accessible in memory. This is not a proper fix on its own, because we still need the workaround of not accessing globals after module destruction. The proper fix is in master. Closes phpGH-13388.
1 parent 5373f5d commit 2f60582

File tree

5 files changed

+44
-7
lines changed

5 files changed

+44
-7
lines changed

NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.2.17
44

5+
- Core:
6+
. Fix ZTS persistent resource crashes on shutdown. (nielsdos)
7+
58
- Curl:
69
. Fix failing tests due to string changes in libcurl 8.6.0. (Ayesh)
710

Zend/zend.c

+2
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,8 @@ void zend_shutdown(void) /* {{{ */
11411141
#endif
11421142
zend_destroy_rsrc_list_dtors();
11431143

1144+
zend_unload_modules();
1145+
11441146
zend_optimizer_shutdown();
11451147
startup_done = false;
11461148
}

Zend/zend.h

+1
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ void zend_shutdown(void);
277277
void zend_register_standard_ini_entries(void);
278278
zend_result zend_post_startup(void);
279279
void zend_set_utility_values(zend_utility_values *utility_values);
280+
void zend_unload_modules(void);
280281

281282
ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32_t lineno);
282283
ZEND_API size_t zend_get_page_size(void);

Zend/zend_API.c

+37-6
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ ZEND_API HashTable module_registry;
4141
static zend_module_entry **module_request_startup_handlers;
4242
static zend_module_entry **module_request_shutdown_handlers;
4343
static zend_module_entry **module_post_deactivate_handlers;
44+
static zend_module_entry **modules_dl_loaded;
4445

4546
static zend_class_entry **class_cleanup_handlers;
4647

@@ -2292,6 +2293,7 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
22922293
int startup_count = 0;
22932294
int shutdown_count = 0;
22942295
int post_deactivate_count = 0;
2296+
int dl_loaded_count = 0;
22952297
zend_class_entry *ce;
22962298
int class_count = 0;
22972299

@@ -2306,6 +2308,9 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
23062308
if (module->post_deactivate_func) {
23072309
post_deactivate_count++;
23082310
}
2311+
if (module->handle) {
2312+
dl_loaded_count++;
2313+
}
23092314
} ZEND_HASH_FOREACH_END();
23102315
module_request_startup_handlers = (zend_module_entry**)realloc(
23112316
module_request_startup_handlers,
@@ -2318,6 +2323,9 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
23182323
module_request_shutdown_handlers[shutdown_count] = NULL;
23192324
module_post_deactivate_handlers = module_request_shutdown_handlers + shutdown_count + 1;
23202325
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+
modules_dl_loaded = realloc(modules_dl_loaded, sizeof(zend_module_entry*) * (dl_loaded_count + 1));
2328+
modules_dl_loaded[dl_loaded_count] = NULL;
23212329
startup_count = 0;
23222330

23232331
ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
@@ -2330,6 +2338,9 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
23302338
if (module->post_deactivate_func) {
23312339
module_post_deactivate_handlers[--post_deactivate_count] = module;
23322340
}
2341+
if (module->handle) {
2342+
modules_dl_loaded[--dl_loaded_count] = module;
2343+
}
23332344
} ZEND_HASH_FOREACH_END();
23342345

23352346
/* Collect internal classes with static members */
@@ -3073,18 +3084,23 @@ void module_destructor(zend_module_entry *module) /* {{{ */
30733084
clean_module_functions(module);
30743085
}
30753086

3076-
#if HAVE_LIBDL
3077-
if (module->handle && !getenv("ZEND_DONT_UNLOAD_MODULES")) {
3078-
DL_UNLOAD(module->handle);
3079-
}
3080-
#endif
3081-
30823087
#if ZEND_RC_DEBUG
30833088
zend_rc_debug = orig_rc_debug;
30843089
#endif
30853090
}
30863091
/* }}} */
30873092

3093+
void module_registry_unload(const zend_module_entry *module)
3094+
{
3095+
#if HAVE_LIBDL
3096+
if (!getenv("ZEND_DONT_UNLOAD_MODULES")) {
3097+
DL_UNLOAD(module->handle);
3098+
}
3099+
#else
3100+
ZEND_IGNORE_VALUE(module);
3101+
#endif
3102+
}
3103+
30883104
ZEND_API void zend_activate_modules(void) /* {{{ */
30893105
{
30903106
zend_module_entry **p = module_request_startup_handlers;
@@ -3129,6 +3145,18 @@ ZEND_API void zend_deactivate_modules(void) /* {{{ */
31293145
}
31303146
/* }}} */
31313147

3148+
void zend_unload_modules(void) /* {{{ */
3149+
{
3150+
zend_module_entry **modules = modules_dl_loaded;
3151+
while (*modules) {
3152+
module_registry_unload(*modules);
3153+
modules++;
3154+
}
3155+
free(modules_dl_loaded);
3156+
modules_dl_loaded = NULL;
3157+
}
3158+
/* }}} */
3159+
31323160
ZEND_API void zend_post_deactivate_modules(void) /* {{{ */
31333161
{
31343162
if (EG(full_tables_cleanup)) {
@@ -3147,6 +3175,9 @@ ZEND_API void zend_post_deactivate_modules(void) /* {{{ */
31473175
break;
31483176
}
31493177
module_destructor(module);
3178+
if (module->handle) {
3179+
module_registry_unload(module);
3180+
}
31503181
zend_string_release_ex(key, 0);
31513182
} ZEND_HASH_MAP_FOREACH_END_DEL();
31523183
} else {

Zend/zend_modules.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ extern ZEND_API HashTable module_registry;
125125

126126
void module_destructor(zend_module_entry *module);
127127
int module_registry_request_startup(zend_module_entry *module);
128-
int module_registry_unload_temp(const zend_module_entry *module);
128+
void module_registry_unload(const zend_module_entry *module);
129129
END_EXTERN_C()
130130

131131
#endif

0 commit comments

Comments
 (0)