動態載入(.so)的 PHP 擴展在模組卸載時,若註冊了全域變數析構函數(dtor),會因模組已被 DL_UNLOAD 卸載導致函數指標失效,觸發 Core Dump。此問題僅發生於動態載入擴展,靜態編譯不受影響。
shared 方式編譯(產生 .so)ZEND_MODULE_GLOBALS_DTOR_N 註冊全域變數析構函數zend_shutdown()
→ zend_destroy_modules()
→ zend_hash_graceful_reverse_destroy()
→ zend_hash_apply_deleter()
→ module_destructor()
→ DL_UNLOAD(module->handle) // 模組先被卸載
→ tsrm_shutdown() // 此時才呼叫 dtor,但代碼已不在記憶體
Zend 引擎關閉流程中,先卸載模組再關閉 TSRM,導致動態載入擴展的 dtor 回調函數在被呼叫時,其所屬代碼段已被釋放。
RSHUTDOWN 階段主動釋放資源,不依賴 TSRM 關閉時的 dtor此為 PHP 5 時代已知內核缺陷,開發動態擴展時務必注意模組卸載順序與資源生命週期管理。