From 86d470f3e02ee5f450e838435ff04fcd7d8cf5d0 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 13 Sep 2021 15:17:32 +0200 Subject: [PATCH] Reset CE cache slots on opcache reset Permanent opcache interned strings could have ce_cache pointing to non-permanent map_ptr slots. On reset, those would be left dangling. Clear any non-permanent ce_cache slots when the interned string state is reset. This was fun to debug... --- ext/opcache/ZendAccelerator.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 19c7f35ff59..a50cf630b9c 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -411,6 +411,15 @@ static void accel_interned_strings_restore_state(void) n = 0; if (EXPECTED(s < top)) { do { + if (ZSTR_HAS_CE_CACHE(s)) { + /* Discard non-global CE_CACHE slots on reset. */ + uintptr_t idx = (GC_REFCOUNT(s) - 1) / sizeof(void *); + if (idx >= ZCSG(map_ptr_last)) { + GC_SET_REFCOUNT(s, 2); + GC_DEL_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR); + } + } + hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), ZSTR_H(s)); STRTAB_COLLISION(s) = *hash_slot; *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);