[php-src] PR #23103: opcache: set ZEND_ACC_PRELOADED for compile-only preloaded enums

From: Date: Fri, 07 Aug 2026 14:48:21 +0000
Subject: [php-src] PR #23103: opcache: set ZEND_ACC_PRELOADED for compile-only preloaded enums
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-37618@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/23103 Author: Nibbler999 > **Disclosure: this description, the patch and its test were drafted with an LLM.** ### Summary GH-17835 fixed [GH-17715](https://github.com/php/php-src/issues/17715) for enums that preload **declares**. It does not cover enums that preload only **compiles**, and those still crash on 8.4 and 8.5. ```php // preload.php opcache_compile_file(__DIR__ . '/e.php'); // e.php enum E { case Foo; } // request E::cases(); // SIGSEGV with any Observer API extension loaded ``` ### Cause zend_enum_register_func() sets ZEND_ACC_PRELOADED inside the if (EG(active)) branch. zend_persist_class_method() keys on that flag to choose ZEND_MAP_PTR_NEW_STATIC() over ZEND_MAP_PTR_NEW(), i.e. a run_time_cache slot that survives into every request — which is what a class living in SHM permanently needs. An enum that preload reaches via opcache_compile_file() is not linked while the preload script executes. It is linked from preload_link(), which runs after the preload request has ended, so EG(active) is already false, the else branch is taken and the flag is never set. gdb on the crash, on an unpatched 8.5.9: ``` Program received signal SIGSEGV, Segmentation fault. #0 zend_observer_fcall_begin_specialized (...) at Zend/zend_observer.h:92 #1 ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER () at Zend/zend_vm_execute.h:2281 #2 execute_ex (...) at Zend/zend_vm_execute.h:116541 function : cases type: 1 (internal) T: 1 fn_flags : 0x2002011 = PUBLIC|STATIC|HAS_RETURN_TYPE|ARENA_ALLOCATED ZEND_ACC_PRELOADED (1<<10) absent run_time_cache : 0 ``` ZEND_OBSERVER_DATA() computes RUN_TIME_CACHE(...) + handle = NULL + 0 and dereferences it — the same null deref, and the same Zend/zend_observer.h:92, that GH-17715's UBSAN output reports. ### Fix Move the tag out of the EG(active) branch so both linking paths set it. The compile-only case then follows the identical, already-proven route as the declared case; no new mechanism is introduced. ### Test ext/opcache/tests/preload_enum_observed_compile_only.phpt mirrors the existing preload_enum_observed.phpt and reuses its preload_enum.inc fixture, changing only how preload reaches it.

« previous php.git-pulls (#37618) next »