[php-src] Issue #24350: ext/date: MINIT reads a stale external tz database after an in-process module restart

From: Date: Thu, 15 Oct 2026 13:11:55 +0000
Subject: [php-src] Issue #24350: ext/date: MINIT reads a stale external tz database after an in-process module restart
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-253001@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24350 Author: TamasSzigeti ### Description PHP_MINIT_FUNCTION(date) calls REGISTER_INI_ENTRIES() before it resets php_date_global_timezone_db: ```c PHP_MINIT_FUNCTION(date) { REGISTER_INI_ENTRIES(); /* fires OnUpdate_date_timezone("UTC") */ ... php_date_global_timezone_db = NULL; php_date_global_timezone_db_enabled = 0; ``` OnUpdate_date_timezone validates the value through DATE_TIMEZONEDB, which still holds whatever the previous startup left there. When a SAPI shuts the engine down and starts it again in the same process, and a shared extension had installed its own database with php_date_set_tzdb() (PECL timezonedb), that pointer refers to a .so that module_destructor() has already unloaded. The second startup then reads unmapped memory: a segfault, or a hang where the SAPI's signal handling swallows it. Neither the extension nor date's MSHUTDOWN clears the pointer, and the extension can't safely do it itself: php_date_set_tzdb(NULL) dereferences its argument. ### Who hits it Any SAPI that restarts the engine in-process with timezonedb loaded: - Apache mod_php on a graceful reload: php/pecl-datetime-timezonedb#16 has the backtrace (seek_to_tz_position ← timelib_timezone_id_is_valid ← OnUpdate_date_timezone ← zm_startup_date). - FrankenPHP ≥ 1.12.5, which restarts the engine on a watched-file change, an OPcache restart or opcache_reset(): php/frankenphp#2667. ### Reproduction (FrankenPHP 1.13.0, PHP 8.5.11 ZTS, Docker) A minimal worker script with watch on one file; touch that file, then send one request. With only timezonedb loaded, the restart never completed in 9 of 10 fresh containers. Without it, 0 of 10. With ZEND_DONT_UNLOAD_MODULES=1, which keeps the .so mapped, 0 of 20. ### Suggested fix Reset the pointer before the INI entries are registered (or in MSHUTDOWN): ```c PHP_MINIT_FUNCTION(date) { php_date_global_timezone_db = NULL; php_date_global_timezone_db_enabled = 0; REGISTER_INI_ENTRIES(); ... ``` ### PHP Version PHP 8.5.11 (same code on master) ### Operating System Debian (dunglas/frankenphp:1.13-php8.5), aarch64

« previous php.bugs (#253001) next »