Skip to content

Commit 424e426

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.
1 parent c2b671c commit 424e426

File tree

3 files changed

+40
-6
lines changed

3 files changed

+40
-6
lines changed

Zend/zend.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,8 +1091,33 @@ zend_result zend_post_startup(void) /* {{{ */
10911091
}
10921092
/* }}} */
10931093

1094+
/* Returns a NULL-terminated array of module entries that were dynamically loaded. */
1095+
static zend_module_entry **zend_collect_dl_loaded_module_entries(void)
1096+
{
1097+
zend_module_entry **modules = malloc(sizeof(zend_module_entry *) * (zend_hash_num_elements(&module_registry) + 1));
1098+
zend_module_entry *module;
1099+
unsigned int index = 0;
1100+
ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&module_registry, module) {
1101+
if (module->handle) {
1102+
modules[index++] = module;
1103+
}
1104+
} ZEND_HASH_FOREACH_END();
1105+
modules[index] = NULL;
1106+
return modules;
1107+
}
1108+
1109+
static void zend_unload_modules(zend_module_entry **modules)
1110+
{
1111+
while (*modules) {
1112+
module_registry_unload(*modules);
1113+
modules++;
1114+
}
1115+
}
1116+
10941117
void zend_shutdown(void) /* {{{ */
10951118
{
1119+
zend_module_entry **modules = zend_collect_dl_loaded_module_entries();
1120+
10961121
zend_vm_dtor();
10971122

10981123
zend_destroy_rsrc_list(&EG(persistent_list));
@@ -1141,6 +1166,9 @@ void zend_shutdown(void) /* {{{ */
11411166
#endif
11421167
zend_destroy_rsrc_list_dtors();
11431168

1169+
zend_unload_modules(modules);
1170+
free(modules);
1171+
11441172
zend_optimizer_shutdown();
11451173
startup_done = false;
11461174
}

Zend/zend_API.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,17 +3073,22 @@ void module_destructor(zend_module_entry *module) /* {{{ */
30733073
clean_module_functions(module);
30743074
}
30753075

3076+
#if ZEND_RC_DEBUG
3077+
zend_rc_debug = orig_rc_debug;
3078+
#endif
3079+
}
3080+
/* }}} */
3081+
3082+
void module_registry_unload(const zend_module_entry *module)
3083+
{
30763084
#if HAVE_LIBDL
30773085
if (module->handle && !getenv("ZEND_DONT_UNLOAD_MODULES")) {
30783086
DL_UNLOAD(module->handle);
30793087
}
3080-
#endif
3081-
3082-
#if ZEND_RC_DEBUG
3083-
zend_rc_debug = orig_rc_debug;
3088+
#else
3089+
ZEND_IGNORE_VALUE(module);
30843090
#endif
30853091
}
3086-
/* }}} */
30873092

30883093
ZEND_API void zend_activate_modules(void) /* {{{ */
30893094
{
@@ -3147,6 +3152,7 @@ ZEND_API void zend_post_deactivate_modules(void) /* {{{ */
31473152
break;
31483153
}
31493154
module_destructor(module);
3155+
module_registry_unload(module);
31503156
zend_string_release_ex(key, 0);
31513157
} ZEND_HASH_MAP_FOREACH_END_DEL();
31523158
} else {

Zend/zend_modules.h

Lines changed: 1 addition & 1 deletion
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)