diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index b2aa21986efb..4b5eed39a7b5 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -16,11 +16,15 @@ PHP 8.7 INTERNALS UPGRADE NOTES - Removed zend_execute_scripts(). Manually call zend_execute_script() in a loop instead. +- Removed ZEND_STATIC_ASSERT(). Use C11 static_assert() directly instead. ======================== 2. Build system changes ======================== +- Unix build system changes: + . Autoconf minimum required version upgraded to 2.71. + ======================== 3. Module changes ======================== diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 1f4e5e26f00e..377cf40b12bd 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -133,13 +133,13 @@ dnl AC_DEFUN([ZEND_INIT], [dnl AC_REQUIRE([AC_PROG_CC]) -AC_CHECK_HEADERS(m4_normalize([ +AC_CHECK_HEADERS([ cpuid.h libproc.h -])) +]) dnl Check for library functions. -AC_CHECK_FUNCS(m4_normalize([ +AC_CHECK_FUNCS([ getpid gettid kill @@ -151,7 +151,7 @@ AC_CHECK_FUNCS(m4_normalize([ pthread_getthrds_np pthread_stackseg_np strnlen -])) +]) AC_CHECK_DECL([clock_gettime_nsec_np], [AC_DEFINE([HAVE_CLOCK_GETTIME_NSEC_NP], [1], diff --git a/Zend/tests/partial_application/const_arg_opt_004.phpt b/Zend/tests/partial_application/const_arg_opt_004.phpt new file mode 100644 index 000000000000..f80c14dc6abd --- /dev/null +++ b/Zend/tests/partial_application/const_arg_opt_004.phpt @@ -0,0 +1,35 @@ +--TEST-- +Constant argument optimization - coerced arg with '...' on non-variadic function +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.file_update_protection=0 +--FILE-- + +--EXPECT-- +string(2) "15" +array(2) { + [0]=> + string(2) "15" + [1]=> + int(1) +} +string(2) "15" +array(3) { + [0]=> + string(2) "15" + [1]=> + int(2) + [2]=> + int(3) +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bad60a5f1071..8d65f1e91394 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -5944,7 +5944,7 @@ static void zend_compile_static_var_common(zend_string *var_name, zval *value, u opline->op1_type = IS_CV; opline->op1.var = lookup_cv(var_name); - ZEND_STATIC_ASSERT(sizeof(Bucket) % 8 == 0, "Bucket size not compatible with storing flags in lower three bits"); + static_assert(sizeof(Bucket) % 8 == 0, "Bucket size not compatible with storing flags in lower three bits"); opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | mode; } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 6502770a2662..ec6d8b09bbe7 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -713,7 +713,7 @@ struct _zend_execute_data { (call)->This.u2.num_args /* Ensure the correct alignment before slots calculation */ -ZEND_STATIC_ASSERT(ZEND_MM_ALIGNED_SIZE(sizeof(zval)) == sizeof(zval), +static_assert(ZEND_MM_ALIGNED_SIZE(sizeof(zval)) == sizeof(zval), "zval must be aligned by ZEND_MM_ALIGNMENT"); /* A number of call frame slots (zvals) reserved for zend_execute_data. */ #define ZEND_CALL_FRAME_SLOT \ diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 2250a873af29..f7679d920d21 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -295,7 +295,7 @@ struct _zend_vm_stack { }; /* Ensure the correct alignment before slots calculation */ -ZEND_STATIC_ASSERT(ZEND_MM_ALIGNED_SIZE(sizeof(zval)) == sizeof(zval), +static_assert(ZEND_MM_ALIGNED_SIZE(sizeof(zval)) == sizeof(zval), "zval must be aligned by ZEND_MM_ALIGNMENT"); /* A number of call frame slots (zvals) reserved for _zend_vm_stack. */ #define ZEND_VM_STACK_HEADER_SLOTS \ diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index d945a23d2b65..368cc6bf78b6 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -178,6 +178,7 @@ bool zend_lazy_object_decr_lazy_props(const zend_object *obj) return info->lazy_properties_count == 0; } +#if ZEND_DEBUG /* See zend_update_class_constants(). */ static zend_always_inline bool zend_class_constants_are_updated(const zend_class_entry *ce) { if (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) { @@ -189,6 +190,7 @@ static zend_always_inline bool zend_class_constants_are_updated(const zend_class } return false; } +#endif /** * Making objects lazy diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 1f74830b900e..e938f53cc3cf 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -566,7 +566,10 @@ static zend_ast *zp_compile_forwarding_call( ZEND_ASSERT(!Z_REFCOUNTED(argv[offset])); /* This argument never changes, so we can burn it into the op_array - * and check its type ahead of time. */ + * and check its type ahead of time. + * Work with a value copy because a scalar type check may coerce this value. */ + zval value; + ZVAL_COPY_VALUE(&value, &argv[offset]); zend_arg_info *arg_info; if (offset < function->common.num_args) { @@ -577,18 +580,18 @@ static zend_ast *zp_compile_forwarding_call( arg_info = NULL; } if (arg_info && ZEND_TYPE_IS_SET(arg_info->type) - && UNEXPECTED(!zend_check_type_ex(&arg_info->type, &argv[offset], + && UNEXPECTED(!zend_check_type_ex(&arg_info->type, &value, /* current_frame */ true, /* is_internal */ false))) { zend_string *need_msg = zend_type_to_string_resolved(arg_info->type, function->common.scope); zend_argument_type_error_ex(function, offset + 1, "must be of type %s, %s given", - ZSTR_VAL(need_msg), zend_zval_value_name(&argv[offset])); + ZSTR_VAL(need_msg), zend_zval_value_name(&value)); zend_string_release(need_msg); goto error; } - args_ast = zend_ast_list_add(args_ast, zend_ast_create_zval(&argv[offset])); + args_ast = zend_ast_list_add(args_ast, zend_ast_create_zval(&value)); } else { args_ast = zend_ast_list_add(args_ast, zend_ast_create(ZEND_AST_VAR, zend_ast_create_zval_from_str(zend_string_copy(var_names->params[offset])))); diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index ccad24682fdb..e6c7ed992b40 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -862,16 +862,7 @@ extern "C++" { /** @deprecated */ #define ZEND_CGG_DIAGNOSTIC_IGNORED_END ZEND_DIAGNOSTIC_IGNORED_END -#if defined(__cplusplus) -# define ZEND_STATIC_ASSERT(c, m) static_assert((c), m) -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ -# define ZEND_STATIC_ASSERT(c, m) _Static_assert((c), m) -#else -# define ZEND_STATIC_ASSERT(c, m) -#endif - -#if ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) /* C11 */ \ - || (defined(__cplusplus) && __cplusplus >= 201103L) /* C++11 */) && !defined(ZEND_WIN32) +#if !defined(ZEND_WIN32) typedef max_align_t zend_max_align_t; #else typedef union { diff --git a/configure.ac b/configure.ac index 5a62f91848f2..50df06a6b479 100644 --- a/configure.ac +++ b/configure.ac @@ -22,10 +22,10 @@ m4_include([Zend/Zend.m4]) dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- -AC_PREREQ([2.68]) +AC_PREREQ([2.71]) AC_INIT([PHP],[8.7.0-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) -AC_CONFIG_MACRO_DIR([build]) +AC_CONFIG_MACRO_DIRS([build]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER @@ -120,11 +120,14 @@ dnl ---------------------------------------------------------------------------- PKG_PROG_PKG_CONFIG AC_PROG_CC([cc gcc]) + +dnl Check if C compiler accepts C11. +AS_CASE([$ac_prog_cc_stdc], [c99|c89|no], + [AC_MSG_ERROR([C compiler would not accept C11 code.])]) + PHP_DETECT_ICC PHP_DETECT_SUNCC -dnl AC_PROG_CC_C99 is obsolete with autoconf >= 2.70 yet necessary for <= 2.69. -m4_version_prereq([2.70],,[AC_PROG_CC_C99]) AC_PROG_CPP AC_USE_SYSTEM_EXTENSIONS AC_PROG_LN_S @@ -135,17 +138,6 @@ AS_VAR_IF([cross_compiling], [yes], AC_MSG_RESULT([$BUILD_CC])], [BUILD_CC=$CC]) -dnl The macro AC_PROG_CC_C99 sets the shell variable ac_cv_prog_cc_c99 to 'no' -dnl if the compiler does not support C99.i.e. does not support any of _Bool, -dnl flexible arrays, inline, long long int, mixed code and declarations, -dnl named initialization of structs, restrict, varargs macros, variable -dnl declarations in for loops and variable length arrays. -dnl -dnl https://www.gnu.org/software/autoconf/manual/autoconf-2.60/html_node/C-Compiler.html -if test "$ac_cv_prog_cc_c99" = no; then - AC_MSG_ERROR([C compiler would not accept C99 code]) -fi - dnl Support systems with system libraries in e.g. /usr/lib64. PHP_ARG_WITH([libdir], [for system library directory], @@ -380,7 +372,7 @@ dnl Then headers. dnl ---------------------------------------------------------------------------- dnl QNX requires unix.h to allow functions in libunix to work properly. -AC_CHECK_HEADERS(m4_normalize([ +AC_CHECK_HEADERS([ dirent.h sys/param.h sys/types.h @@ -428,7 +420,7 @@ AC_CHECK_HEADERS(m4_normalize([ nmmintrin.h wmmintrin.h immintrin.h -]),,, [dnl +],,, [dnl #ifdef HAVE_SYS_PARAM_H #include #endif @@ -452,8 +444,6 @@ PHP_BROKEN_GETCWD AS_VAR_IF([GCC], [yes], [PHP_BROKEN_GCC_STRLEN_OPT]) dnl Detect the headers required to use makedev, major, and minor. -dnl Autoconf <= 2.69 didn't check glibc 2.25 deprecated macros in sys/types.h. -m4_version_prereq([2.70],,[ac_cv_header_sys_types_h_makedev=no]) AC_HEADER_MAJOR dnl Checks for typedefs, structures, and compiler characteristics. @@ -546,7 +536,7 @@ PHP_CHECK_VARIABLE_ATTRIBUTE([aligned]) dnl Checks for library functions. dnl ---------------------------------------------------------------------------- -AC_CHECK_FUNCS(m4_normalize([ +AC_CHECK_FUNCS([ alphasort asctime_r asprintf @@ -609,7 +599,7 @@ AC_CHECK_FUNCS(m4_normalize([ usleep utime vasprintf -])) +]) PHP_ARG_ENABLE([system-glob], [whether to use the system glob function], diff --git a/ext/date/time_duration.c b/ext/date/time_duration.c index a9f69db7a3d8..f84bee1fc72e 100644 --- a/ext/date/time_duration.c +++ b/ext/date/time_duration.c @@ -25,8 +25,8 @@ #define NANOS_IN_MILLI 1000000 #define MILLIS_IN_SEC 1000 -ZEND_STATIC_ASSERT(NANOS_IN_MICRO * MICROS_IN_SEC == NANOS_IN_SEC, ""); -ZEND_STATIC_ASSERT(NANOS_IN_MILLI * MILLIS_IN_SEC == NANOS_IN_SEC, ""); +static_assert(NANOS_IN_MICRO * MICROS_IN_SEC == NANOS_IN_SEC, ""); +static_assert(NANOS_IN_MILLI * MILLIS_IN_SEC == NANOS_IN_SEC, ""); #define Z_PARAM_ULONG(l) { \ zend_long __##l; \ diff --git a/ext/dom/tests/gh23897.phpt b/ext/dom/tests/gh23897.phpt new file mode 100644 index 000000000000..79c465ec1947 --- /dev/null +++ b/ext/dom/tests/gh23897.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-23897 (Assertion failure in php_dom_xpath_callback_dispatch() after failed registerPhpFunctions()) +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); + +$xpath = new DOMXPath($dom); +$xpath->registerNamespace('php', 'http://php.net/xpath'); +try { + $xpath->registerPhpFunctions('testPhpFunction'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +try { + var_dump($xpath->evaluate('php:function("testPhpFunction")')); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +?> +--EXPECT-- +TypeError: DOMXPath::registerPhpFunctions(): Argument #1 ($restrict) must be a callable, function "testPhpFunction" not found or invalid function name +Error: No callbacks were registered diff --git a/ext/dom/xpath_callbacks.c b/ext/dom/xpath_callbacks.c index cb817b41dd3f..e4ad6c59b3d1 100644 --- a/ext/dom/xpath_callbacks.c +++ b/ext/dom/xpath_callbacks.c @@ -412,7 +412,7 @@ static zend_result php_dom_xpath_callback_dispatch(php_dom_xpath_callbacks *xpat { zval callback_retval; - if (UNEXPECTED(ns == NULL)) { + if (UNEXPECTED(ns == NULL || ns->mode == PHP_DOM_REG_FUNC_MODE_NONE)) { zend_throw_error(NULL, "No callbacks were registered"); return FAILURE; } diff --git a/ext/ldap/config.m4 b/ext/ldap/config.m4 index 65a3d3b90eed..fd56d2d0c361 100644 --- a/ext/ldap/config.m4 +++ b/ext/ldap/config.m4 @@ -132,7 +132,7 @@ if test "$PHP_LDAP" != "no"; then dnl Solaris 2.8 claims to be 2004 API, but doesn't have ldap_parse_reference() dnl nor ldap_start_tls_s() - AC_CHECK_FUNCS(m4_normalize([ + AC_CHECK_FUNCS([ ldap_control_find ldap_extended_operation_s ldap_parse_extended_result @@ -142,7 +142,7 @@ if test "$PHP_LDAP" != "no"; then ldap_refresh_s ldap_start_tls_s ldap_whoami_s - ])) + ]) dnl Sanity check AC_CHECK_FUNC([ldap_sasl_bind_s],, diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 7b6f62237859..2adb934f1256 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -650,6 +650,11 @@ static zend_property_info* zend_get_known_property_info(const zend_op_array *op_ } if (info->flags & ZEND_ACC_PUBLIC) { + if ((info->flags & ZEND_ACC_CHANGED) + && op_array->scope + && op_array->scope != ce) { + return NULL; + } return info; } else if (on_this) { if (ce == info->ce) { diff --git a/ext/opcache/tests/jit/gh23679.phpt b/ext/opcache/tests/jit/gh23679.phpt new file mode 100644 index 000000000000..8b3c65c6567f --- /dev/null +++ b/ext/opcache/tests/jit/gh23679.phpt @@ -0,0 +1,116 @@ +--TEST-- +GH-23679: tracing JIT must not write a parent private property into a child's shadowing public property +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.protect_memory=1 +opcache.jit=tracing +opcache.jit_hot_loop=1 +opcache.jit_hot_func=1 +opcache.jit_hot_return=1 +opcache.jit_hot_side_exit=1 +--EXTENSIONS-- +opcache +--FILE-- +arr[$k] = $v; + return $x; + } + + public function setAll($v) + { + $x = clone $this; + $x->arr = $v; + return $x; + } + + public function inc() + { + $x = clone $this; + $x->n++; + return $x; + } + + public function addN($k) + { + $x = clone $this; + $x->n += $k; + return $x; + } + + public function getDim($k) + { + return $this->arr[$k] ?? 'MISSING'; + } + + public function getN() + { + return $this->n; + } +} + +class B extends A +{ + public $arr = []; + public $n = 100; +} + +for ($i = 0; $i < 50; $i++) { + (new A)->setDim('x', 1)->getDim('x'); + (new A)->setAll(['x' => 1])->getDim('x'); + (new A)->inc()->getN(); + (new A)->addN(5)->getN(); + + $b = new B; + $b->arr = ['keep' => 1]; + $b->n = 100; + + $r = $b->setDim('x', 2); + if ($r->getDim('x') !== 2 || $r->arr !== ['keep' => 1]) { + echo "dim-assign i=$i private="; + var_dump($r->getDim('x')); + echo "dim-assign i=$i public="; + var_dump($r->arr); + exit(1); + } + + $r = $b->setAll(['y' => 4]); + if ($r->getDim('y') !== 4 || $r->arr !== ['keep' => 1]) { + echo "assign i=$i private="; + var_dump($r->getDim('y')); + echo "assign i=$i public="; + var_dump($r->arr); + exit(1); + } + + $r = $b->inc(); + if ($r->getN() !== 1 || $r->n !== 100) { + echo "inc i=$i private="; + var_dump($r->getN()); + echo "inc i=$i public="; + var_dump($r->n); + exit(1); + } + + $r = $b->addN(5); + if ($r->getN() !== 5 || $r->n !== 100) { + echo "assign-op i=$i private="; + var_dump($r->getN()); + echo "assign-op i=$i public="; + var_dump($r->n); + exit(1); + } +} +echo "ok\n"; +?> +--EXPECT-- +ok diff --git a/ext/pcntl/config.m4 b/ext/pcntl/config.m4 index 553419114fd2..d0fffb45037e 100644 --- a/ext/pcntl/config.m4 +++ b/ext/pcntl/config.m4 @@ -9,7 +9,7 @@ if test "$PHP_PCNTL" != "no"; then [AC_MSG_FAILURE([ext/pcntl: required function $function() not found.])]) done - AC_CHECK_FUNCS(m4_normalize([ + AC_CHECK_FUNCS([ forkx getcpuid getpriority @@ -26,7 +26,7 @@ if test "$PHP_PCNTL" != "no"; then waitid wait6 syscall - ])) + ]) AC_CHECK_FUNCS([WIFCONTINUED],, [AC_CHECK_DECL([WIFCONTINUED], [AC_DEFINE([HAVE_WIFCONTINUED], [1])],, diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 265b47e52dc7..38e6c4ae2bc3 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -29,6 +29,7 @@ #include "ext/standard/info.h" #include "php_signal.h" #include "php_ticks.h" +#include "zend_exceptions.h" #include "zend_fibers.h" #include "main/php_main.h" @@ -1352,6 +1353,9 @@ void pcntl_signal_dispatch(void) { zval params[2], *handle, retval; struct php_pcntl_pending_signal *queue, *next; + zend_object *old_exception; + const zend_op *old_opline_before_exception = NULL; + const zend_op *old_opline = NULL; sigset_t mask; sigset_t old_mask; @@ -1379,8 +1383,24 @@ void pcntl_signal_dispatch(void) PCNTL_G(head) = NULL; /* simple stores are atomic */ PCNTL_G(tail) = NULL; + /* Dispatching can happen with an exception pending, e.g. from the interrupt check that runs + * right after an internal function threw. call_user_function() does nothing in that state, + * so set the exception aside while the handlers run. The frame is left as found: depending + * on the caller, the exception may not be registered on it yet, or may already be on its + * way to a catch block, and the caller takes it from there once we return. */ + old_exception = EG(exception); + if (old_exception) { + if (EG(current_execute_data)) { + old_opline = EG(current_execute_data)->opline; + } + old_opline_before_exception = EG(opline_before_exception); + EG(exception) = NULL; + } + /* Allocate */ while (queue) { + bool handler_threw = false; + if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) { if (Z_TYPE_P(handle) != IS_LONG) { ZVAL_LONG(¶ms[0], queue->signo); @@ -1392,9 +1412,7 @@ void pcntl_signal_dispatch(void) zval_ptr_dtor(&retval); zval_ptr_dtor(¶ms[1]); - if (EG(exception)) { - break; - } + handler_threw = NULL != EG(exception); } } @@ -1402,17 +1420,44 @@ void pcntl_signal_dispatch(void) queue->next = PCNTL_G(spares); PCNTL_G(spares) = queue; queue = next; + + /* No other handler can be called while the exception propagates */ + if (handler_threw) { + break; + } } - /* drain the remaining in case of exception thrown */ - while (queue) { - next = queue->next; - queue->next = PCNTL_G(spares); - PCNTL_G(spares) = queue; - queue = next; + if (old_exception) { + if (EG(current_execute_data)) { + EG(current_execute_data)->opline = old_opline; + } + EG(opline_before_exception) = old_opline_before_exception; + if (EG(exception)) { + zend_exception_set_previous(EG(exception), old_exception); + } else { + EG(exception) = old_exception; + } } - PCNTL_G(pending_signals) = false; + if (UNEXPECTED(queue)) { + /* Put back what the throwing handler did not get to, instead of dropping it, and ask + * the engine to come back once the exception has been handled. Signals are still + * blocked here, so PCNTL_G(head) cannot have been repopulated in the meantime. */ + next = queue; + + while (next->next) { + next = next->next; + } + + PCNTL_G(head) = queue; + PCNTL_G(tail) = next; + + if (PCNTL_G(async_signals)) { + zend_atomic_bool_store_ex(&EG(vm_interrupt), true); + } + } else { + PCNTL_G(pending_signals) = false; + } /* Re-enable queue */ PCNTL_G(processing_signal_queue) = false; diff --git a/ext/pcntl/tests/pcntl_signal_dispatch_exception_2.phpt b/ext/pcntl/tests/pcntl_signal_dispatch_exception_2.phpt new file mode 100644 index 000000000000..ebd868df5d4b --- /dev/null +++ b/ext/pcntl/tests/pcntl_signal_dispatch_exception_2.phpt @@ -0,0 +1,44 @@ +--TEST-- +pcntl_signal_dispatch() keeps the signals left in the queue by a throwing handler +--EXTENSIONS-- +pcntl +posix +--FILE-- +getMessage() . "\n"; +} + +echo "Handlers called: " . implode(', ', $called) . "\n"; + +pcntl_signal_dispatch(); + +echo "Handlers called: " . implode(', ', $called) . "\n"; + +?> +--EXPECT-- +Exception in signal handler +Handlers called: SIGUSR1 +Handlers called: SIGUSR1, SIGUSR2, SIGHUP diff --git a/ext/pcntl/tests/pcntl_signal_dispatch_exception_3.phpt b/ext/pcntl/tests/pcntl_signal_dispatch_exception_3.phpt new file mode 100644 index 000000000000..ff877e3c0400 --- /dev/null +++ b/ext/pcntl/tests/pcntl_signal_dispatch_exception_3.phpt @@ -0,0 +1,47 @@ +--TEST-- +pcntl_signal_dispatch() delivers the signals a throwing handler left behind once its exception is handled +--EXTENSIONS-- +pcntl +posix +--FILE-- +getMessage() . "\n"; +} + +// No explicit dispatch: the engine delivers what the throwing handler left behind +// on its own, as soon as the exception has been handled +usleep(1000); + +echo "Handlers called: " . implode(', ', $called) . "\n"; + +?> +--EXPECT-- +Exception in signal handler +Handlers called: SIGUSR1, SIGUSR2, SIGHUP diff --git a/ext/pcntl/tests/pcntl_signal_dispatch_exception_pending.phpt b/ext/pcntl/tests/pcntl_signal_dispatch_exception_pending.phpt new file mode 100644 index 000000000000..5a7968e9b382 --- /dev/null +++ b/ext/pcntl/tests/pcntl_signal_dispatch_exception_pending.phpt @@ -0,0 +1,24 @@ +--TEST-- +pcntl_signal_dispatch() runs the handlers of the signals raised while an internal function ran and then threw +--EXTENSIONS-- +pcntl +zend_test +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Handler called +Exception after raise() diff --git a/ext/pcntl/tests/pcntl_signal_dispatch_exception_pending_user_frame.phpt b/ext/pcntl/tests/pcntl_signal_dispatch_exception_pending_user_frame.phpt new file mode 100644 index 000000000000..bae00348c144 --- /dev/null +++ b/ext/pcntl/tests/pcntl_signal_dispatch_exception_pending_user_frame.phpt @@ -0,0 +1,33 @@ +--TEST-- +pcntl_signal_dispatch() with an exception pending after an internal function called from a user frame +--EXTENSIONS-- +pcntl +zend_test +--FILE-- + +--EXPECTF-- +Handler called from test() + +Fatal error: Uncaught Exception: Exception after raise() in %s:%d +Stack trace: +#0 %s(%d): zend_test_raise_and_throw(%d) +#1 %s(%d): test() +#2 {main} + thrown in %s on line %d diff --git a/ext/posix/config.m4 b/ext/posix/config.m4 index 865546356953..b0f6b1879593 100644 --- a/ext/posix/config.m4 +++ b/ext/posix/config.m4 @@ -12,7 +12,7 @@ if test "$PHP_POSIX" = "yes"; then [$ext_shared],, [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) - AC_CHECK_FUNCS(m4_normalize([ + AC_CHECK_FUNCS([ ctermid eaccess getgrgid_r @@ -28,7 +28,7 @@ if test "$PHP_POSIX" = "yes"; then seteuid setrlimit setsid - ])) + ]) dnl Check for makedev. If it's defined as a macro, AC_CHECK_FUNCS won't work. dnl Required headers are included by the AC_HEADER_MAJOR logic. diff --git a/ext/random/engine_mt19937.c b/ext/random/engine_mt19937.c index a84fb9585c80..bccf3770fb43 100644 --- a/ext/random/engine_mt19937.c +++ b/ext/random/engine_mt19937.c @@ -85,7 +85,7 @@ */ #define N 624 /* length of state vector */ -ZEND_STATIC_ASSERT( +static_assert( N == sizeof(((php_random_status_state_mt19937*)0)->state) / sizeof(((php_random_status_state_mt19937*)0)->state[0]), "Assumed length of Mt19937 state vector does not match actual size." ); diff --git a/ext/random/php_random_zend_utils.h b/ext/random/php_random_zend_utils.h index 56718e5c214b..411da02a075c 100644 --- a/ext/random/php_random_zend_utils.h +++ b/ext/random/php_random_zend_utils.h @@ -25,7 +25,7 @@ typedef struct php_random_bytes_insecure_state_for_zend { php_random_status_state_xoshiro256starstar xoshiro256starstar_state; } php_random_bytes_insecure_state_for_zend; -ZEND_STATIC_ASSERT(sizeof(zend_random_bytes_insecure_state) >= sizeof(php_random_bytes_insecure_state_for_zend), ""); +static_assert(sizeof(zend_random_bytes_insecure_state) >= sizeof(php_random_bytes_insecure_state_for_zend), ""); ZEND_ATTRIBUTE_NONNULL PHPAPI void php_random_bytes_insecure_for_zend( zend_random_bytes_insecure_state *state, void *bytes, size_t size); diff --git a/ext/soap/tests/GHSA-rgrp-mwpx-f6rm-href-chain.phpt b/ext/soap/tests/GHSA-rgrp-mwpx-f6rm-href-chain.phpt index e07f78d816f3..a8e96473166b 100644 --- a/ext/soap/tests/GHSA-rgrp-mwpx-f6rm-href-chain.phpt +++ b/ext/soap/tests/GHSA-rgrp-mwpx-f6rm-href-chain.phpt @@ -2,6 +2,12 @@ GHSA-rgrp-mwpx-f6rm: Stack overflow on a chain of href references --EXTENSIONS-- soap +--SKIPIF-- + --FILE-- --FILE-- loadXML(''); + +$xsl = new DOMDocument(); +$xsl->loadXML(<< + + + + +XML); + +$xslt = new XSLTProcessor(); +try { + $xslt->registerPHPFunctions('testPhpFunction'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +$xslt->importStylesheet($xsl); +try { + var_dump($xslt->transformToXml($dom)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +?> +--EXPECT-- +TypeError: XSLTProcessor::registerPHPFunctions(): Argument #1 ($functions) must be a callable, function "testPhpFunction" not found or invalid function name +Error: No callbacks were registered diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 82bfa8d38e33..4853e1f61e70 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -41,6 +41,8 @@ #include "zend_observer.h" #include "test_decl.h" +#include + #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) # include # include @@ -1444,6 +1446,22 @@ static ZEND_FUNCTION(zend_test_uri_parser) php_uri_free(uri); } +static ZEND_FUNCTION(zend_test_raise_and_throw) +{ + zend_long signo; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(signo) + ZEND_PARSE_PARAMETERS_END(); + + if (raise((int) signo) != 0) { + zend_throw_error(NULL, "raise() failed"); + RETURN_THROWS(); + } + + zend_throw_exception(NULL, "Exception after raise()", 0); +} + static bool has_opline(zend_execute_data *execute_data) { return execute_data diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 3c09668bddb1..afeae903c668 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -423,6 +423,8 @@ function zend_get_map_ptr_last(): int {} function zend_test_crash(?string $message = null): void {} + function zend_test_raise_and_throw(int $signal): void {} + function zend_test_fill_packed_array(array &$array): void {} /** @return resource */ diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index f3901c9b7330..d01e3d036c7f 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 4d728e740122add9d4c91f5c1abb5f5017690636 + * Stub hash: 2b25ec2985ed2c14165625a0603ad2a122a255c7 * Has decl header: yes */ #include "zend_attributes.h" @@ -285,6 +285,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_crash, 0, 0, IS_VOID, ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_raise_and_throw, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, signal, IS_LONG, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_fill_packed_array, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(1, array, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -507,6 +511,7 @@ static ZEND_FUNCTION(zend_test_zend_call_stack_use_all); static ZEND_FUNCTION(zend_test_is_string_marked_as_valid_utf8); static ZEND_FUNCTION(zend_get_map_ptr_last); static ZEND_FUNCTION(zend_test_crash); +static ZEND_FUNCTION(zend_test_raise_and_throw); static ZEND_FUNCTION(zend_test_fill_packed_array); static ZEND_FUNCTION(zend_test_create_throwing_resource); static ZEND_FUNCTION(get_open_basedir); @@ -683,6 +688,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_is_string_marked_as_valid_utf8, arginfo_zend_test_is_string_marked_as_valid_utf8) ZEND_FE(zend_get_map_ptr_last, arginfo_zend_get_map_ptr_last) ZEND_FE(zend_test_crash, arginfo_zend_test_crash) + ZEND_FE(zend_test_raise_and_throw, arginfo_zend_test_raise_and_throw) ZEND_FE(zend_test_fill_packed_array, arginfo_zend_test_fill_packed_array) ZEND_FE(zend_test_create_throwing_resource, arginfo_zend_test_create_throwing_resource) ZEND_FE(get_open_basedir, arginfo_get_open_basedir) diff --git a/ext/zend_test/test_decl.h b/ext/zend_test/test_decl.h index 7e41dc18eabb..d2bc04df8f4e 100644 --- a/ext/zend_test/test_decl.h +++ b/ext/zend_test/test_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 4d728e740122add9d4c91f5c1abb5f5017690636 */ + * Stub hash: 2b25ec2985ed2c14165625a0603ad2a122a255c7 */ -#ifndef ZEND_TEST_DECL_4d728e740122add9d4c91f5c1abb5f5017690636_H -#define ZEND_TEST_DECL_4d728e740122add9d4c91f5c1abb5f5017690636_H +#ifndef ZEND_TEST_DECL_2b25ec2985ed2c14165625a0603ad2a122a255c7_H +#define ZEND_TEST_DECL_2b25ec2985ed2c14165625a0603ad2a122a255c7_H typedef enum zend_enum_ZendTestUnitEnum { ZEND_ENUM_ZendTestUnitEnum_Foo = 1, @@ -27,4 +27,4 @@ typedef enum zend_enum_ZendTestEnumWithInterface { ZEND_ENUM_ZendTestEnumWithInterface_Bar = 2, } zend_enum_ZendTestEnumWithInterface; -#endif /* ZEND_TEST_DECL_4d728e740122add9d4c91f5c1abb5f5017690636_H */ +#endif /* ZEND_TEST_DECL_2b25ec2985ed2c14165625a0603ad2a122a255c7_H */ diff --git a/ext/zend_test/test_legacy_arginfo.h b/ext/zend_test/test_legacy_arginfo.h index d9a7709ab22f..e12e72eb6d28 100644 --- a/ext/zend_test/test_legacy_arginfo.h +++ b/ext/zend_test/test_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 4d728e740122add9d4c91f5c1abb5f5017690636 + * Stub hash: 2b25ec2985ed2c14165625a0603ad2a122a255c7 * Has decl header: yes */ #include "zend_constants.h" @@ -227,6 +227,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_crash, 0, 0, 0) ZEND_ARG_INFO(0, message) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_raise_and_throw, 0, 0, 1) + ZEND_ARG_INFO(0, signal) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_fill_packed_array, 0, 0, 1) ZEND_ARG_INFO(1, array) ZEND_END_ARG_INFO() @@ -431,6 +435,7 @@ static ZEND_FUNCTION(zend_test_zend_call_stack_use_all); static ZEND_FUNCTION(zend_test_is_string_marked_as_valid_utf8); static ZEND_FUNCTION(zend_get_map_ptr_last); static ZEND_FUNCTION(zend_test_crash); +static ZEND_FUNCTION(zend_test_raise_and_throw); static ZEND_FUNCTION(zend_test_fill_packed_array); static ZEND_FUNCTION(zend_test_create_throwing_resource); static ZEND_FUNCTION(get_open_basedir); @@ -579,6 +584,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_is_string_marked_as_valid_utf8, arginfo_zend_test_is_string_marked_as_valid_utf8) ZEND_FE(zend_get_map_ptr_last, arginfo_zend_get_map_ptr_last) ZEND_FE(zend_test_crash, arginfo_zend_test_crash) + ZEND_FE(zend_test_raise_and_throw, arginfo_zend_test_raise_and_throw) ZEND_FE(zend_test_fill_packed_array, arginfo_zend_test_fill_packed_array) ZEND_FE(zend_test_create_throwing_resource, arginfo_zend_test_create_throwing_resource) ZEND_FE(get_open_basedir, arginfo_get_open_basedir) diff --git a/scripts/phpize.m4 b/scripts/phpize.m4 index 6bfad3846596..21b5a856344d 100644 --- a/scripts/phpize.m4 +++ b/scripts/phpize.m4 @@ -15,7 +15,7 @@ m4_include([build/php_cxx_compile_stdcxx.m4]) m4_include([build/php.m4]) m4_include([build/pkg.m4]) -AC_PREREQ([2.68]) +AC_PREREQ([2.71]) AC_INIT AC_CONFIG_SRCDIR([config.m4]) AC_CONFIG_AUX_DIR([build]) @@ -36,6 +36,11 @@ PHP_INIT_BUILD_SYSTEM PKG_PROG_PKG_CONFIG AC_PROG_CC([cc gcc]) + +dnl Check if C compiler accepts C11. +AS_CASE([$ac_prog_cc_stdc], [c99|c89|no], + [AC_MSG_ERROR([C compiler would not accept C11 code.])]) + PHP_DETECT_ICC PHP_DETECT_SUNCC