Commit 50e38ac74c8 for php
commit 50e38ac74c8e8a60faac2fe1318ca80c94f24969
Merge: 593ed68ac95 10b26c49ec5
Author: Arnaud Le Blanc <arnaud.lb@gmail.com>
Date: Tue Oct 27 13:28:34 2026 +0100
Merge branch 'PHP-8.6'
* PHP-8.6:
Fix GH-24577: CE-cache flag on interned class name visible before map_ptr offset (#24585)
diff --cc Zend/zend.c
index 21605651121,55ad84f189f..a0a1a2af022
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@@ -2119,6 -2143,7 +2119,7 @@@ ZEND_API void zend_alloc_ce_cache(zend_
do {
ret = ZEND_MAP_PTR_NEW_OFFSET();
} while (ret <= 2);
- GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR);
GC_SET_REFCOUNT(type_name, ret);
- ZEND_ATOMIC_FENCE_RELEASE();
++ atomic_thread_fence(memory_order_release);
+ GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR);
}
diff --cc Zend/zend_types.h
index 932d131820d,1c409ec45a0..fb1c4a93249
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@@ -960,8 -961,14 +961,29 @@@ static zend_always_inline uint32_t zend
#define OBJ_EXTRA_FLAGS(obj) ((obj)->extra_flags)
++static zend_always_inline uint32_t zend_atomic_load_acquire_32(const uint32_t *ptr)
++{
++#if defined(__GNUC__) || defined(__clang__) || defined(HAVE_GNUC_ATOMICS)
++ return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
++#else
++ uint32_t val = *(const volatile uint32_t *)ptr;
++ ZEND_ATOMIC_FENCE_ACQUIRE();
++ return val;
++#endif
++}
++
/* Fast class cache */
- #define ZSTR_HAS_CE_CACHE(s) (GC_FLAGS(s) & IS_STR_CLASS_NAME_MAP_PTR)
+ static zend_always_inline bool zstr_has_ce_cache(const zend_string *s)
+ {
- uint32_t type_info = ZEND_ATOMIC_LOAD_ACQUIRE_32(&GC_TYPE_INFO(s));
++ static_assert(sizeof(_Atomic uint32_t) == sizeof(uint32_t), "atomic size");
++ static_assert(alignof(_Atomic uint32_t) == alignof(uint32_t), "atomic align");
++ static_assert(ATOMIC_INT_LOCK_FREE == 2, "not always lock-free");
++
++ uint32_t type_info = atomic_load_explicit((_Atomic uint32_t *)&GC_TYPE_INFO(s), memory_order_acquire);
+ return (type_info & (IS_STR_CLASS_NAME_MAP_PTR << GC_FLAGS_SHIFT)) != 0;
+ }
+
+ #define ZSTR_HAS_CE_CACHE(s) zstr_has_ce_cache(s)
#define ZSTR_GET_CE_CACHE(s) ZSTR_GET_CE_CACHE_EX(s, 1)
#define ZSTR_SET_CE_CACHE(s, ce) ZSTR_SET_CE_CACHE_EX(s, ce, 1)
diff --cc ext/opcache/ZendAccelerator.c
index 2318f5b28c8,28032182e29..3834190ffe9
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@@ -457,8 -457,9 +457,9 @@@ static void accel_interned_strings_rest
/* 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);
- ZEND_ATOMIC_FENCE_RELEASE();
++ atomic_thread_fence(memory_order_release);
+ GC_SET_REFCOUNT(s, 2);
}
}
@@@ -567,6 -568,7 +568,7 @@@ finish
if (ZSTR_HAS_CE_CACHE(str) && !ZSTR_HAS_CE_CACHE(s)) {
ZEND_ASSERT(GC_FLAGS(str) & IS_STR_PERMANENT);
GC_SET_REFCOUNT(s, GC_REFCOUNT(str));
- ZEND_ATOMIC_FENCE_RELEASE();
++ atomic_thread_fence(memory_order_release);
GC_ADD_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
}
diff --cc ext/opcache/zend_persist.c
index 3d70dfcaccf,052411a0eb0..84043ed0450
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@@ -371,6 -371,7 +371,7 @@@ void zend_accel_pending_ce_cache_commit
ZEND_ASSERT(!ZSTR_HAS_CE_CACHE(type_name));
GC_SET_REFCOUNT(type_name, (uint32_t)Z_LVAL_P(zv));
- ZEND_ATOMIC_FENCE_RELEASE();
++ atomic_thread_fence(memory_order_release);
GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR);
} ZEND_HASH_FOREACH_END();