diff --git a/NEWS b/NEWS index 58e69261024..e1a2a5c491d 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PHP NEWS - Core: . Fixed bug OSS-Fuzz #382922236 (Duplicate dynamic properties in hooked object iterator properties table). (ilutov) + . Fixed unstable get_iterator pointer for hooked classes in shm on Windows. + (ilutov) - DBA: . Skip test if inifile is disabled. (orlitzky) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2d1a50191ff..456c0b8f410 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -8575,10 +8575,13 @@ static void zend_compile_property_hooks( ce->num_hooked_props++; + /* See zend_link_hooked_object_iter(). */ +#ifndef ZEND_OPCACHE_SHM_REATTACHMENT if (!ce->get_iterator) { /* Will be removed again, in case of Iterator or IteratorAggregate. */ ce->get_iterator = zend_hooked_object_get_iterator; } +#endif if (!prop_info->ce->parent_name) { zend_verify_hooked_property(ce, prop_info, prop_name); @@ -9104,6 +9107,10 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) /* We currently don't early-bind classes that implement interfaces or use traits */ if (!ce->num_interfaces && !ce->num_traits && !ce->num_hooked_prop_variance_checks +#ifdef ZEND_OPCACHE_SHM_REATTACHMENT + /* See zend_link_hooked_object_iter(). */ + && !ce->num_hooked_props +#endif && !(CG(compiler_options) & ZEND_COMPILE_WITHOUT_EXECUTION)) { if (toplevel) { if (extends_ast) { diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 98ada65cd3f..8197e616284 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1746,6 +1746,27 @@ ZEND_API inheritance_status zend_verify_property_hook_variance(const zend_proper return zend_perform_covariant_type_check(ce, prop_info->type, ce, value_arg_info->type); } +#ifdef ZEND_OPCACHE_SHM_REATTACHMENT +/* Hooked properties set get_iterator, which causes issues on for shm + * reattachment. Avoid early-binding on Windows and set get_iterator during + * inheritance. The linked class may not use inheritance cache. */ +static void zend_link_hooked_object_iter(zend_class_entry *ce) { + if (!ce->get_iterator && ce->num_hooked_props) { + ce->get_iterator = zend_hooked_object_get_iterator; + ce->ce_flags &= ~ZEND_ACC_CACHEABLE; + if (CG(current_linking_class) == ce) { +# if ZEND_DEBUG + /* This check is executed before inheriting any elements that can + * track dependencies. */ + HashTable *ht = (HashTable*)ce->inheritance_cache; + ZEND_ASSERT(!ht); +# endif + CG(current_linking_class) = NULL; + } + } +} +#endif + ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked) /* {{{ */ { zend_property_info *property_info; @@ -3405,7 +3426,7 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) return ce; } -#ifndef ZEND_WIN32 +#ifndef ZEND_OPCACHE_SHM_REATTACHMENT # define UPDATE_IS_CACHEABLE(ce) do { \ if ((ce)->type == ZEND_USER_CLASS) { \ is_cacheable &= (ce)->ce_flags; \ @@ -3550,6 +3571,10 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string zend_enum_register_funcs(ce); } +#ifdef ZEND_OPCACHE_SHM_REATTACHMENT + zend_link_hooked_object_iter(ce); +#endif + if (parent) { if (!(parent->ce_flags & ZEND_ACC_LINKED)) { add_dependency_obligation(ce, parent); @@ -3838,6 +3863,10 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_ zend_begin_record_errors(); } +#ifdef ZEND_OPCACHE_SHM_REATTACHMENT + zend_link_hooked_object_iter(ce); +#endif + zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS); if (parent_ce && parent_ce->num_interfaces) { zend_do_inherit_interfaces(ce, parent_ce); diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 5be8d7e4f5c..e4195402fc2 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -863,4 +863,11 @@ static zend_always_inline uint64_t ZEND_BYTES_SWAP64(uint64_t u) } #endif +#ifdef ZEND_WIN32 +/* Whether it's allowed to reattach to a shm segment from different processes on + * this platform. This prevents pointing to internal structures from shm due to + * ASLR. Currently only possible on Windows. */ +# define ZEND_OPCACHE_SHM_REATTACHMENT 1 +#endif + #endif /* ZEND_PORTABILITY_H */ diff --git a/ext/opcache/tests/dump_property_hooks.phpt b/ext/opcache/tests/dump_property_hooks.phpt index d8727e873b8..5083ad385f3 100644 --- a/ext/opcache/tests/dump_property_hooks.phpt +++ b/ext/opcache/tests/dump_property_hooks.phpt @@ -6,6 +6,12 @@ opcache.enable_cli=1 opcache.opt_debug_level=0x20000 --EXTENSIONS-- opcache +--SKIPIF-- + --FILE--