diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 2709fb56391..34e9c0fe2d5 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2764,101 +2764,113 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string #endif bool orig_record_errors = EG(record_errors); - if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { - if (is_cacheable) { - if (zend_inheritance_cache_get && zend_inheritance_cache_add) { - zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces); - if (ret) { - if (traits_and_interfaces) { - free_alloca(traits_and_interfaces, use_heap); - } - zv = zend_hash_find_known_hash(CG(class_table), key); - Z_CE_P(zv) = ret; - return ret; + + if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) { + if (zend_inheritance_cache_get && zend_inheritance_cache_add) { + zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces); + if (ret) { + if (traits_and_interfaces) { + free_alloca(traits_and_interfaces, use_heap); } - - /* Make sure warnings (such as deprecations) thrown during inheritance - * will be recoreded in the inheritance cache. */ - zend_begin_record_errors(); - } else { - is_cacheable = 0; + zv = zend_hash_find_known_hash(CG(class_table), key); + Z_CE_P(zv) = ret; + return ret; } - proto = ce; + + /* Make sure warnings (such as deprecations) thrown during inheritance + * will be recorded in the inheritance cache. */ + zend_begin_record_errors(); + } else { + is_cacheable = 0; } - /* Lazy class loading */ - ce = zend_lazy_class_load(ce); - zv = zend_hash_find_known_hash(CG(class_table), key); - Z_CE_P(zv) = ce; - } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) { - /* Lazy class loading */ - ce = zend_lazy_class_load(ce); - ce->ce_flags &= ~ZEND_ACC_FILE_CACHED; - zv = zend_hash_find_known_hash(CG(class_table), key); - Z_CE_P(zv) = ce; + proto = ce; } - if (CG(unlinked_uses)) { - zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t) ce); - } - - orig_linking_class = CG(current_linking_class); - CG(current_linking_class) = is_cacheable ? ce : NULL; - - if (ce->ce_flags & ZEND_ACC_ENUM) { - /* Only register builtin enum methods during inheritance to avoid persisting them in - * opcache. */ - zend_enum_register_funcs(ce); - } - - if (parent) { - if (!(parent->ce_flags & ZEND_ACC_LINKED)) { - add_dependency_obligation(ce, parent); + zend_try { + if (ce->ce_flags & ZEND_ACC_IMMUTABLE) { + /* Lazy class loading */ + ce = zend_lazy_class_load(ce); + zv = zend_hash_find_known_hash(CG(class_table), key); + Z_CE_P(zv) = ce; + } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) { + /* Lazy class loading */ + ce = zend_lazy_class_load(ce); + ce->ce_flags &= ~ZEND_ACC_FILE_CACHED; + zv = zend_hash_find_known_hash(CG(class_table), key); + Z_CE_P(zv) = ce; } - zend_do_inheritance(ce, parent); - } - if (ce->num_traits) { - zend_do_bind_traits(ce, traits_and_interfaces); - } - if (ce->num_interfaces) { - /* Also copy the parent interfaces here, so we don't need to reallocate later. */ - uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0; - zend_class_entry **interfaces = emalloc( - sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces)); - if (num_parent_interfaces) { - memcpy(interfaces, parent->interfaces, - sizeof(zend_class_entry *) * num_parent_interfaces); + if (CG(unlinked_uses)) { + zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t) ce); } - memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits, - sizeof(zend_class_entry *) * ce->num_interfaces); - zend_do_implement_interfaces(ce, interfaces); - } else if (parent && parent->num_interfaces) { - zend_do_inherit_interfaces(ce, parent); - } - if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) - && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) - ) { - zend_verify_abstract_class(ce); - } - if (ce->ce_flags & ZEND_ACC_ENUM) { - zend_verify_enum(ce); - } + orig_linking_class = CG(current_linking_class); + CG(current_linking_class) = is_cacheable ? ce : NULL; - /* Normally Stringable is added during compilation. However, if it is imported from a trait, - * we need to explicilty add the interface here. */ - if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT) + if (ce->ce_flags & ZEND_ACC_ENUM) { + /* Only register builtin enum methods during inheritance to avoid persisting them in + * opcache. */ + zend_enum_register_funcs(ce); + } + + if (parent) { + if (!(parent->ce_flags & ZEND_ACC_LINKED)) { + add_dependency_obligation(ce, parent); + } + zend_do_inheritance(ce, parent); + } + if (ce->num_traits) { + zend_do_bind_traits(ce, traits_and_interfaces); + } + if (ce->num_interfaces) { + /* Also copy the parent interfaces here, so we don't need to reallocate later. */ + uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0; + zend_class_entry **interfaces = emalloc( + sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces)); + + if (num_parent_interfaces) { + memcpy(interfaces, parent->interfaces, + sizeof(zend_class_entry *) * num_parent_interfaces); + } + memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits, + sizeof(zend_class_entry *) * ce->num_interfaces); + + zend_do_implement_interfaces(ce, interfaces); + } else if (parent && parent->num_interfaces) { + zend_do_inherit_interfaces(ce, parent); + } + if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) + && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) + ) { + zend_verify_abstract_class(ce); + } + if (ce->ce_flags & ZEND_ACC_ENUM) { + zend_verify_enum(ce); + } + + /* Normally Stringable is added during compilation. However, if it is imported from a trait, + * we need to explicilty add the interface here. */ + if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT) && !zend_class_implements_interface(ce, zend_ce_stringable)) { - ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE); - ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES; - ce->num_interfaces++; - ce->interfaces = perealloc(ce->interfaces, - sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS); - ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable; - do_interface_implementation(ce, zend_ce_stringable); - } + ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE); + ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES; + ce->num_interfaces++; + ce->interfaces = perealloc(ce->interfaces, + sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS); + ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable; + do_interface_implementation(ce, zend_ce_stringable); + } + + zend_build_properties_info_table(ce); + } zend_catch { + /* Do not leak recorded errors to the next linked class. */ + if (!orig_record_errors) { + EG(record_errors) = false; + zend_free_recorded_errors(); + } + zend_bailout(); + } zend_end_try(); - zend_build_properties_info_table(ce); EG(record_errors) = orig_record_errors; if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) { @@ -3027,22 +3039,29 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_ orig_linking_class = CG(current_linking_class); CG(current_linking_class) = is_cacheable ? ce : NULL; - if (is_cacheable) { - zend_begin_record_errors(); - } + zend_try{ + if (is_cacheable) { + zend_begin_record_errors(); + } - zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS); - if (parent_ce && parent_ce->num_interfaces) { - zend_do_inherit_interfaces(ce, parent_ce); - } - zend_build_properties_info_table(ce); - if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { - zend_verify_abstract_class(ce); - } - ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)); - ce->ce_flags |= ZEND_ACC_LINKED; + zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS); + if (parent_ce && parent_ce->num_interfaces) { + zend_do_inherit_interfaces(ce, parent_ce); + } + zend_build_properties_info_table(ce); + if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { + zend_verify_abstract_class(ce); + } + ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)); + ce->ce_flags |= ZEND_ACC_LINKED; + + CG(current_linking_class) = orig_linking_class; + } zend_catch { + EG(record_errors) = false; + zend_free_recorded_errors(); + zend_bailout(); + } zend_end_try(); - CG(current_linking_class) = orig_linking_class; EG(record_errors) = false; if (is_cacheable) { diff --git a/ext/opcache/tests/gh8063-001.phpt b/ext/opcache/tests/gh8063-001.phpt new file mode 100644 index 00000000000..320d40aa3a8 --- /dev/null +++ b/ext/opcache/tests/gh8063-001.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug GH-8063 (Opcache breaks autoloading after E_COMPILE_ERROR) 001 +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.record_warnings=0 +--EXTENSIONS-- +opcache +--FILE-- +idle_kill) { + fpm_pctl_kill(child->pid, FPM_PCTL_KILL); + } else { + child->idle_kill = 1; + fpm_pctl_kill(child->pid, FPM_PCTL_QUIT); + } +} +/* }}} */ + static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /* {{{ */ { struct fpm_worker_pool_s *wp; @@ -375,8 +389,7 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /* {{{ fpm_request_last_activity(last_idle_child, &last); fpm_clock_get(&now); if (last.tv_sec < now.tv_sec - wp->config->pm_process_idle_timeout) { - last_idle_child->idle_kill = 1; - fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_QUIT); + fpm_pctl_kill_idle_child(last_idle_child); } continue; @@ -388,8 +401,7 @@ static void fpm_pctl_perform_idle_server_maintenance(struct timeval *now) /* {{{ zlog(ZLOG_DEBUG, "[pool %s] currently %d active children, %d spare children, %d running children. Spawning rate %d", wp->config->name, active, idle, wp->running_children, wp->idle_spawn_rate); if (idle > wp->config->pm_max_spare_servers && last_idle_child) { - last_idle_child->idle_kill = 1; - fpm_pctl_kill(last_idle_child->pid, FPM_PCTL_QUIT); + fpm_pctl_kill_idle_child(last_idle_child); wp->idle_spawn_rate = 1; continue; } diff --git a/sapi/fpm/fpm/fpm_process_ctl.h b/sapi/fpm/fpm/fpm_process_ctl.h index 5c7ed6165d5..0db7044c17b 100644 --- a/sapi/fpm/fpm/fpm_process_ctl.h +++ b/sapi/fpm/fpm/fpm_process_ctl.h @@ -42,7 +42,8 @@ enum { FPM_PCTL_TERM, FPM_PCTL_STOP, FPM_PCTL_CONT, - FPM_PCTL_QUIT + FPM_PCTL_QUIT, + FPM_PCTL_KILL }; #endif diff --git a/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt b/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt new file mode 100644 index 00000000000..6fc08493435 --- /dev/null +++ b/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt @@ -0,0 +1,65 @@ +--TEST-- +FPM: Blocked SIGQUIT prevents idle process to be killed +--EXTENSIONS-- +pcntl +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +$tester->multiRequest(2); +$tester->status([ + 'total processes' => 2, +]); +// wait for process to be killed +sleep(7); +$tester->expectLogWarning('child \\d+ exited on signal 9 \\(SIGKILL\\) after \\d+.\\d+ seconds from start', 'unconfined'); +$tester->expectLogNotice('child \\d+ started', 'unconfined'); +$tester->expectLogWarning('child \\d+ exited on signal 9 \\(SIGKILL\\) after \\d+.\\d+ seconds from start', 'unconfined'); +$tester->expectLogNotice('child \\d+ started', 'unconfined'); +$tester->status([ + 'total processes' => 1, +]); +$tester->terminate(); +$tester->expectLogTerminatingNotices(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- +