diff '--color=auto' -Naur php-8.4.18/build/gen_stub.php php-8.4.20RC1/build/gen_stub.php --- php-8.4.18/build/gen_stub.php 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/build/gen_stub.php 2026-04-01 04:35:35.991525982 +0000 @@ -84,7 +84,7 @@ } /* Because exit() and die() are proper token/keywords we need to hack-around */ - $hasSpecialExitAsFunctionHandling = str_ends_with($stubFile, 'zend_builtin_functions.stub.php'); + $hasSpecialExitAsFunctionHandling = basename($stubFile) == 'zend_builtin_functions.stub.php'; if (!$fileInfo = $context->parsedFiles[$stubFile] ?? null) { initPhpParser(); $stubContent = $stubCode ?? file_get_contents($stubFile); diff '--color=auto' -Naur php-8.4.18/.circleci/config.yml php-8.4.20RC1/.circleci/config.yml --- php-8.4.18/.circleci/config.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.circleci/config.yml 2026-04-01 04:35:35.979935853 +0000 @@ -5,7 +5,7 @@ resource_class: arm.medium docker: - image: cimg/base:current-22.04 - - image: mysql:8.3 + - image: mysql:8.4 environment: MYSQL_ALLOW_EMPTY_PASSWORD: true MYSQL_ROOT_PASSWORD: '' @@ -167,6 +167,7 @@ name: Test no_output_timeout: 30m command: | + export RUN_RESOURCE_HEAVY_TESTS=1 sapi/cli/php run-tests.php \ -d zend_extension=opcache.so \ -d opcache.enable_cli=1 \ diff '--color=auto' -Naur php-8.4.18/configure.ac php-8.4.20RC1/configure.ac --- php-8.4.18/configure.ac 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/configure.ac 2026-04-01 04:39:06.630074157 +0000 @@ -17,7 +17,7 @@ dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.4.18],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.4.20RC1],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff '--color=auto' -Naur php-8.4.18/configure.ac.orig php-8.4.20RC1/configure.ac.orig --- php-8.4.18/configure.ac.orig 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/configure.ac.orig 2026-02-10 17:48:03.000000000 +0000 @@ -0,0 +1,1836 @@ +dnl Process this file with autoconf to produce a configure script. + +dnl Include external macro definitions before the AC_INIT to also remove +dnl comments starting with # and empty newlines from the included files. +dnl ---------------------------------------------------------------------------- +m4_include([build/ax_check_compile_flag.m4]) +m4_include([build/ax_func_which_gethostbyname_r.m4]) +m4_include([build/ax_gcc_func_attribute.m4]) +m4_include([build/libtool.m4]) +m4_include([build/php_cxx_compile_stdcxx.m4]) +m4_include([build/php.m4]) +m4_include([build/pkg.m4]) +m4_include([TSRM/threads.m4]) +m4_include([Zend/Zend.m4]) + +dnl Basic autoconf initialization, generation of config.nice. +dnl ---------------------------------------------------------------------------- + +AC_PREREQ([2.68]) +AC_INIT([PHP],[8.4.18],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_CONFIG_SRCDIR([main/php_version.h]) +AC_CONFIG_AUX_DIR([build]) +AC_PRESERVE_HELP_ORDER + +PHP_CONFIG_NICE([config.nice]) + +PHP_CANONICAL_HOST_TARGET + +AC_CONFIG_HEADERS([main/php_config.h]) + +AH_TOP([ +#ifndef PHP_CONFIG_H +#define PHP_CONFIG_H + +#if defined(__GNUC__) && __GNUC__ >= 4 +# define ZEND_API __attribute__ ((visibility("default"))) +# define ZEND_DLEXPORT __attribute__ ((visibility("default"))) +#else +# define ZEND_API +# define ZEND_DLEXPORT +#endif + +#define ZEND_DLIMPORT +]) +AH_BOTTOM([ +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#include + +#endif /* PHP_CONFIG_H */ +]) + +ac_IFS=$IFS; IFS="." +set $(echo AC_PACKAGE_VERSION | "${SED}" 's/\([[0-9\.]]*\)\(.*\)/\1\.\2/') +IFS=$ac_IFS +PHP_MAJOR_VERSION=[$]1 +PHP_MINOR_VERSION=[$]2 +PHP_RELEASE_VERSION=[$]3 +dnl Allow overriding PHP_EXTRA_VERSION through the homonymous env var +AC_ARG_VAR([PHP_EXTRA_VERSION], + [Extra PHP version label suffix, e.g. '-dev', 'rc1', '-acme'])dnl +AS_VAR_IF([PHP_EXTRA_VERSION],, [PHP_EXTRA_VERSION=[$]4]) +PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION" +PHP_VERSION_ID=$(expr [$]PHP_MAJOR_VERSION \* 10000 + [$]PHP_MINOR_VERSION \* 100 + [$]PHP_RELEASE_VERSION) + +dnl Allow version values to be used in Makefile. +PHP_SUBST([PHP_MAJOR_VERSION]) +PHP_SUBST([PHP_MINOR_VERSION]) +PHP_SUBST([PHP_RELEASE_VERSION]) +PHP_SUBST([PHP_EXTRA_VERSION]) + +dnl Setting up the PHP version based on the information above. +dnl ---------------------------------------------------------------------------- + +echo "/* automatically generated by configure */" > php_version.h.new +echo "/* edit configure.ac to change version number */" >> php_version.h.new +echo "#define PHP_MAJOR_VERSION $PHP_MAJOR_VERSION" >> php_version.h.new +echo "#define PHP_MINOR_VERSION $PHP_MINOR_VERSION" >> php_version.h.new +echo "#define PHP_RELEASE_VERSION $PHP_RELEASE_VERSION" >> php_version.h.new +echo "#define PHP_EXTRA_VERSION \"$PHP_EXTRA_VERSION\"" >> php_version.h.new +echo "#define PHP_VERSION \"$PHP_VERSION\"" >> php_version.h.new +echo "#define PHP_VERSION_ID $PHP_VERSION_ID" >> php_version.h.new +cmp php_version.h.new $srcdir/main/php_version.h >/dev/null 2>&1 +if test $? -ne 0 ; then + rm -f $srcdir/main/php_version.h && mv php_version.h.new $srcdir/main/php_version.h && \ + echo 'Updated main/php_version.h' +else + rm -f php_version.h.new +fi + +dnl Settings we want to make before the checks. +dnl ---------------------------------------------------------------------------- + +PHP_INIT_BUILD_SYSTEM + +dnl Because 'make install' is often performed by the superuser, we create the +dnl libs subdirectory as the user who configures PHP. Otherwise, the current +dnl user will not be able to delete libs or the contents of libs. + +$php_shtool mkdir -p libs +rm -f libs/* + +dnl Checks for programs. +dnl ---------------------------------------------------------------------------- + +PKG_PROG_PKG_CONFIG +AC_PROG_CC([cc gcc]) +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 + +AS_VAR_IF([cross_compiling], [yes], + [AC_CHECK_PROGS([BUILD_CC], [gcc clang c99 c89 cc cl], [none]) + AC_MSG_CHECKING([for native build C compiler]) + AC_MSG_RESULT([$BUILD_CC])], + [BUILD_CC=$CC]) + +dnl Support systems with system libraries in e.g. /usr/lib64. +PHP_ARG_WITH([libdir], + [for system library directory], + [AS_HELP_STRING([--with-libdir=NAME], + [Look for libraries in .../NAME rather than .../lib])], + [lib], + [no]) + +PHP_ARG_ENABLE([rpath], + [whether to enable runpaths], + [AS_HELP_STRING([--disable-rpath], + [Disable passing additional runtime library search paths])], + [yes], + [no]) + +dnl Check for -R, etc. switch. +PHP_RUNPATH_SWITCH + +dnl Checks for some support/generator progs. +PHP_PROG_BISON([3.0.0]) +PHP_PROG_RE2C([1.0.3], [--no-generation-date]) +dnl Find installed PHP. Minimum supported version for gen_stub.php is PHP 7.4. +PHP_PROG_PHP([7.4]) + +PHP_ARG_ENABLE([re2c-cgoto], + [whether to enable computed goto extension with re2c], + [AS_HELP_STRING([--enable-re2c-cgoto], + [Enable re2c -g flag to optimize conditional jumps using computed goto + extension, if supported by the compiler])], + [no], + [no]) + +AS_VAR_IF([PHP_RE2C_CGOTO], [no],, +[AC_CACHE_CHECK([whether re2c -g works], [php_cv_have_re2c_cgoto], + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +int main(void) +{ +label1: + ; +label2: + ; + static void *adr[] = { &&label1, &&label2 }; + goto *adr[0]; + return 0; +}]])], + [php_cv_have_re2c_cgoto=yes], + [php_cv_have_re2c_cgoto=no])]) +AS_VAR_IF([php_cv_have_re2c_cgoto], [yes], + [AS_VAR_APPEND([RE2C_FLAGS], [" -g"])]) +]) + +dnl Platform-specific compile settings. +dnl ---------------------------------------------------------------------------- + +dnl See bug #28605 +case $host_cpu in + alpha*) + if test "$GCC" = "yes"; then + CFLAGS="$CFLAGS -mieee" + else + CFLAGS="$CFLAGS -ieee" + fi + ;; + sparc*) + if test "$SUNCC" = "yes"; then + CFLAGS="$CFLAGS -xmemalign=8s" + fi + ;; +esac + +dnl See https://github.com/php/php-src/issues/14140 +AX_CHECK_COMPILE_FLAG([-ffp-contract=off], [CFLAGS="$CFLAGS -ffp-contract=off"]) + +dnl Mark symbols hidden by default if the compiler (for example, gcc >= 4) +dnl supports it. This can help reduce the binary size and startup time. +AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], + [CFLAGS="$CFLAGS -fvisibility=hidden"]) + +case $host_alias in + *solaris*) + CPPFLAGS="$CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" + ;; + *hpux*) + if test "$GCC" = "yes"; then + CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE_EXTENDED" + fi + ;; +esac + +dnl Disable PIC mode by default where it is known to be safe to do so, to avoid +dnl the performance hit from the lost register. +AC_MSG_CHECKING([whether to force non-PIC code in shared modules]) +case $host_alias in + i?86-*-linux*|i?86-*-freebsd*) + if test "${with_pic+set}" != "set" || test "$with_pic" = "no"; then + with_pic=no + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; +esac + +dnl Detect musl libc +AC_MSG_CHECKING([whether we are using musl libc]) +if command -v ldd >/dev/null && ldd --version 2>&1 | grep ^musl >/dev/null 2>&1 +then + AC_MSG_RESULT([yes]) + AC_DEFINE([__MUSL__], [1], [Define to 1 when using musl libc.]) +else + AC_MSG_RESULT([no]) +fi + +dnl Add _GNU_SOURCE compile definition because the php_config.h with definitions +dnl by AC_USE_SYSTEM_EXTENSIONS might be included after the system headers which +dnl require extensions to C and POSIX. +AS_VAR_APPEND([CPPFLAGS], [" -D_GNU_SOURCE"]) + +PTHREADS_CHECK +PHP_HELP_SEPARATOR([SAPI modules:]) +PHP_SHLIB_SUFFIX_NAMES +PHP_BUILD_PROGRAM +PHP_SAPI=none + +dnl SAPI configuration. +dnl ---------------------------------------------------------------------------- + +dnl Paths to the targets are relative to the build directory. +SAPI_LIBNAME=libphp +SAPI_LIBNAME_SHARED=$SAPI_LIBNAME.[]$SHLIB_DL_SUFFIX_NAME +SAPI_LIBNAME_STATIC=$SAPI_LIBNAME.a +SAPI_SHARED=libs/$SAPI_LIBNAME_SHARED +SAPI_STATIC=libs/$SAPI_LIBNAME_STATIC +SAPI_LIBTOOL=libphp.la + +PHP_CONFIGURE_PART([Configuring SAPI modules]) + +esyscmd(./build/config-stubs sapi) + +dnl Show which main SAPI was selected. +AC_MSG_CHECKING([for chosen SAPI module]) +AC_MSG_RESULT([$PHP_SAPI]) + +dnl Show which binaries were selected. +AC_MSG_CHECKING([for executable SAPI binaries]) +AS_VAR_IF([PHP_BINARIES],, + [AC_MSG_RESULT([none])], + [AC_MSG_RESULT([$PHP_BINARIES])]) + +dnl Exit early. +AS_VAR_IF([PHP_INSTALLED_SAPIS],, [AC_MSG_ERROR([Nothing to build.])]) + +dnl Add POSIX threads compilation and linker flags when thread safety is enabled +dnl with either the '--enable-zts' configure option or automatically enabled by +dnl PHP SAPIs. For example, Apache SAPI. +AS_VAR_IF([enable_zts], [yes], [ + if test -n "$ac_cv_pthreads_lib"; then + LIBS="$LIBS -l$ac_cv_pthreads_lib" + fi + if test -n "$ac_cv_pthreads_cflags"; then + CFLAGS="$CFLAGS $ac_cv_pthreads_cflags" + fi + + PTHREADS_FLAGS +]) + +dnl Starting system checks. +dnl ---------------------------------------------------------------------------- + +PHP_CONFIGURE_PART([Running system checks]) + +dnl Find sendmail binary. +PHP_PROG_SENDMAIL + +dnl Check whether the system uses EBCDIC (not ASCII) as its native codeset. +PHP_EBCDIC + +dnl Check whether the system byte ordering is bigendian. +PHP_C_BIGENDIAN + +dnl Check whether writing to stdout works. +PHP_TEST_WRITE_STDOUT + +dnl Check for /usr/pkg/{lib,include} which is where NetBSD puts binary and +dnl source packages. This should be harmless on other OSs. +if test -d /usr/pkg/include && test -d /usr/pkg/lib; then + CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" + LDFLAGS="$LDFLAGS -L/usr/pkg/lib" +fi +test -d /usr/ucblib && PHP_ADD_LIBPATH([/usr/ucblib]) + +dnl First, library checks. +dnl ---------------------------------------------------------------------------- + +AC_SEARCH_LIBS([socket], [socket network]) + +AC_CHECK_FUNCS([socketpair],, + [AC_SEARCH_LIBS([socketpair], [socket network], + [AC_DEFINE([HAVE_SOCKETPAIR], [1])])]) + +AC_SEARCH_LIBS([gethostbyaddr], [nsl network]) + +AC_SEARCH_LIBS([dlopen], [dl], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define to 1 if you have the 'dl' library (-ldl).])]) + +AC_SEARCH_LIBS([sin], [m]) + +case $host_alias in + riscv64*) + PHP_CHECK_FUNC(__atomic_exchange_1, atomic) + ;; +esac + +dnl Solaris/Illumos for process mapping. +AC_SEARCH_LIBS([Pgrab], [proc]) + +dnl Haiku does not have network api in libc. +AC_SEARCH_LIBS([setsockopt], [network]) + +dnl Check for openpty. It may require linking against libutil or libbsd. +AC_CHECK_FUNCS([openpty],, + [AC_SEARCH_LIBS([openpty], [util bsd], [AC_DEFINE([HAVE_OPENPTY], [1])])]) + +dnl Then headers. +dnl ---------------------------------------------------------------------------- + +dnl QNX requires unix.h to allow functions in libunix to work properly. +AC_CHECK_HEADERS(m4_normalize([ + dirent.h + sys/param.h + sys/types.h + sys/time.h + netinet/in.h + alloca.h + arpa/inet.h + arpa/nameser.h + dns.h + fcntl.h + grp.h + ieeefp.h + langinfo.h + linux/sock_diag.h + poll.h + pty.h + pwd.h + resolv.h + strings.h + syslog.h + sysexits.h + sys/ioctl.h + sys/file.h + sys/mman.h + sys/mount.h + sys/poll.h + sys/resource.h + sys/select.h + sys/socket.h + sys/stat.h + sys/statfs.h + sys/statvfs.h + sys/vfs.h + sys/sysexits.h + sys/uio.h + sys/wait.h + sys/loadavg.h + unistd.h + unix.h + utime.h + sys/utsname.h + sys/ipc.h + dlfcn.h + tmmintrin.h + nmmintrin.h + wmmintrin.h + immintrin.h +]),,, [dnl +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_NAMESER_H +#include +#endif +]) + +PHP_FOPENCOOKIE +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. +dnl ---------------------------------------------------------------------------- + +AC_STRUCT_TIMEZONE + +PHP_MISSING_TIME_R_DECL + +AC_CHECK_TYPES([struct flock],,,[#include ]) +AC_CHECK_TYPES([socklen_t], [], [], [ + #ifdef HAVE_SYS_TYPES_H + # include + #endif + #ifdef HAVE_SYS_SOCKET_H + # include + #endif +]) + +dnl These are defined elsewhere than stdio.h. +PHP_CHECK_SIZEOF([intmax_t], [0]) +PHP_CHECK_SIZEOF([ssize_t], [8]) +PHP_CHECK_SIZEOF([ptrdiff_t], [8]) + +dnl Check stdint types (must be after header check). +PHP_CHECK_STDINT_TYPES + +dnl Check GNU C builtins. +PHP_CHECK_BUILTIN([__builtin_clz]) +PHP_CHECK_BUILTIN([__builtin_clzl]) +PHP_CHECK_BUILTIN([__builtin_clzll]) +PHP_CHECK_BUILTIN([__builtin_cpu_init]) +PHP_CHECK_BUILTIN([__builtin_cpu_supports]) +PHP_CHECK_BUILTIN([__builtin_ctzl]) +PHP_CHECK_BUILTIN([__builtin_ctzll]) +PHP_CHECK_BUILTIN([__builtin_expect]) +PHP_CHECK_BUILTIN([__builtin_frame_address]) +PHP_CHECK_BUILTIN([__builtin_saddl_overflow]) +PHP_CHECK_BUILTIN([__builtin_saddll_overflow]) +PHP_CHECK_BUILTIN([__builtin_smull_overflow]) +PHP_CHECK_BUILTIN([__builtin_smulll_overflow]) +PHP_CHECK_BUILTIN([__builtin_ssubl_overflow]) +PHP_CHECK_BUILTIN([__builtin_ssubll_overflow]) +PHP_CHECK_BUILTIN([__builtin_unreachable]) +PHP_CHECK_BUILTIN([__builtin_usub_overflow]) + +dnl Check AVX512 +PHP_CHECK_AVX512_SUPPORTS +dnl Check AVX512 VBMI +PHP_CHECK_AVX512_VBMI_SUPPORTS + +dnl Check for __alignof__ support in the compiler +AC_CACHE_CHECK([whether the compiler supports __alignof__], +[php_cv_have_alignof], +[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [ + int align = __alignof__(int); + (void)align; +])], +[php_cv_have_alignof=yes], +[php_cv_have_alignof=no])]) +AS_VAR_IF([php_cv_have_alignof], [yes], + [AC_DEFINE([HAVE_ALIGNOF], [1], + [Define to 1 if the compiler supports '__alignof__'.])]) + +dnl Check for structure members. +AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[#include ]) +AC_CHECK_MEMBERS([struct stat.st_blksize, struct stat.st_rdev]) +dnl AC_STRUCT_ST_BLOCKS will screw QNX because fileblocks.o does not exist. +if test "$(uname -s 2>/dev/null)" != "QNX"; then + AC_STRUCT_ST_BLOCKS +fi + +dnl Checks for types. +AC_TYPE_UID_T + +dnl Checks for sockaddr_storage and sockaddr.sa_len. +AC_CHECK_TYPES([struct sockaddr_storage],,,[#include ]) +AC_CHECK_MEMBERS([struct sockaddr.sa_len],,,[#include ]) + +dnl Checks for GCC function attributes on all systems except ones without glibc +dnl Fix for these systems is already included in GCC 7, but not on GCC 6. +dnl +dnl At least some versions of FreeBSD seem to have buggy ifunc support, see +dnl bug #77284. Conservatively don't use ifuncs on FreeBSD prior to version 12. +AS_CASE([$host_alias], [*-*-*android*|*-*-*uclibc*|*-*-*musl*|*openbsd*], [true], [ + if test "$(uname -s 2>/dev/null)" != "FreeBSD" || test "$(uname -U 2>/dev/null)" -ge 1200000; then + AX_GCC_FUNC_ATTRIBUTE([ifunc]) + AX_GCC_FUNC_ATTRIBUTE([target]) + fi +]) + +dnl Check for __attribute__ ((__aligned__)) support in the compiler. +PHP_CHECK_VARIABLE_ATTRIBUTE([aligned]) + +dnl Checks for library functions. +dnl ---------------------------------------------------------------------------- + +AC_CHECK_FUNCS(m4_normalize([ + alphasort + asctime_r + asprintf + chroot + ctime_r + explicit_memset + fdatasync + flock + ftok + funopen + gai_strerror + getcwd + getgrnam_r + gethostname + getloadavg + getlogin + getprotobyname + getprotobynumber + getpwnam_r + getpwuid_r + getrusage + getservbyname + getservbyport + gettimeofday + getwd + glob + gmtime_r + lchown + localtime_r + memcntl + memfd_create + memmem + mempcpy + memrchr + mkstemp + mmap + nice + nl_langinfo + poll + pthread_jit_write_protect_np + putenv + scandir + setenv + setitimer + shutdown + sigprocmask + statfs + statvfs + std_syslog + strcasecmp + strnlen + strptime + strtok_r + symlink + tzset + unsetenv + usleep + utime + vasprintf +])) + +AC_CHECK_FUNC([inet_ntop],, [AC_MSG_FAILURE([Required inet_ntop not found.])]) +AC_CHECK_FUNC([inet_pton],, [AC_MSG_FAILURE([Required inet_pton not found.])]) + +dnl Check for strerror_r, and if its a POSIX-compatible or a GNU specific version. +AC_FUNC_STRERROR_R + +dnl Check for functions inside their belonging headers. +AC_CHECK_HEADER([sys/prctl.h], [AC_CHECK_FUNCS([prctl])]) +AC_CHECK_HEADER([sys/procctl.h], [AC_CHECK_FUNCS([procctl])]) + +AX_FUNC_WHICH_GETHOSTBYNAME_R + +dnl Some systems (Solaris 10) do not have nanosleep in libc. +AC_CHECK_FUNCS([nanosleep],, + [AC_SEARCH_LIBS([nanosleep], [rt], [AC_DEFINE([HAVE_NANOSLEEP], [1])])]) + +dnl Check for getaddrinfo, should be a better way, but... Also check for working +dnl getaddrinfo. +AC_CACHE_CHECK([for getaddrinfo], [php_cv_func_getaddrinfo], +[AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [struct addrinfo *g,h;g=&h;getaddrinfo("","",g,&g);])], + [AC_RUN_IFELSE([AC_LANG_SOURCE([ +#include +#include +#include +#include +#ifndef AF_INET +# include +#endif +int main(void) { + struct addrinfo *ai, *pai, hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + + if (getaddrinfo("127.0.0.1", 0, &hints, &ai) < 0) { + return 1; + } + + if (ai == 0) { + return 1; + } + + pai = ai; + + while (pai) { + if (pai->ai_family != AF_INET) { + /* 127.0.0.1/NUMERICHOST should only resolve ONE way */ + return 1; + } + if (pai->ai_addr->sa_family != AF_INET) { + /* 127.0.0.1/NUMERICHOST should only resolve ONE way */ + return 1; + } + pai = pai->ai_next; + } + freeaddrinfo(ai); + return 0; +} + ])], + [php_cv_func_getaddrinfo=yes], + [php_cv_func_getaddrinfo=no], + [AS_CASE([$host_alias], + [*linux*|*midipix], [php_cv_func_getaddrinfo=yes], + [php_cv_func_getaddrinfo=no])])], +[php_cv_func_getaddrinfo=no])]) +AS_VAR_IF([php_cv_func_getaddrinfo], [yes], + [AC_DEFINE([HAVE_GETADDRINFO], [1], + [Define to 1 if you have the 'getaddrinfo' function.])]) + +dnl on FreeBSD, copy_file_range() works only with the undocumented flag 0x01000000; +dnl until the problem is fixed properly, copy_file_range() is used only on Linux +AC_CACHE_CHECK([for copy_file_range], [php_cv_func_copy_file_range], +[AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +#ifndef __linux__ +# error "unsupported platform" +#endif +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,3,0) +# error "kernel too old" +#endif +#include +int main(void) +{ + (void)copy_file_range(-1, 0, -1, 0, 0, 0); + return 0; +} +])], +[php_cv_func_copy_file_range=yes], +[php_cv_func_copy_file_range=no]) +]) +AS_VAR_IF([php_cv_func_copy_file_range], [yes], + [AC_DEFINE([HAVE_COPY_FILE_RANGE], [1], + [Define to 1 if you have the 'copy_file_range' function.])]) + +AC_REPLACE_FUNCS([strlcat strlcpy explicit_bzero getopt]) +AC_FUNC_ALLOCA +PHP_TIME_R_TYPE + +AC_CACHE_CHECK([for aarch64 CRC32 API], [php_cv_func___crc32d], +[AC_LINK_IFELSE([AC_LANG_PROGRAM([ +#include +# if defined(__GNUC__) +# if!defined(__clang__) +# pragma GCC push_options +# pragma GCC target ("+nothing+crc") +# elif defined(__APPLE__) +# pragma clang attribute push(__attribute__((target("crc"))), apply_to=function) +# else +# pragma clang attribute push(__attribute__((target("+nothing+crc"))), apply_to=function) +# endif +# endif +], [__crc32d(0, 0);])], +[php_cv_func___crc32d=yes], +[php_cv_func___crc32d=no])]) +AS_VAR_IF([php_cv_func___crc32d], [yes], + [AC_DEFINE([HAVE_AARCH64_CRC32], [1], + [Define to 1 when aarch64 CRC32 API is available.])]) + +dnl Check for asm goto support. +AC_CACHE_CHECK([for asm goto], [php_cv_have__asm_goto], +[AC_LINK_IFELSE([AC_LANG_PROGRAM([], [ +#if defined(__x86_64__) || defined(__i386__) + __asm__ goto("jmp %l0\n" :::: end); +#elif defined(__aarch64__) + __asm__ goto("b %l0\n" :::: end); +#endif +end: + return 0; +])], +[php_cv_have__asm_goto=yes], +[php_cv_have__asm_goto=no])]) +AS_VAR_IF([php_cv_have__asm_goto], [yes], + [AC_DEFINE([HAVE_ASM_GOTO], [1], + [Define to 1 if asm goto support is available.])]) + +dnl Check Valgrind support. +PHP_ARG_WITH([valgrind], + [whether to enable Valgrind support], + [AS_HELP_STRING([--with-valgrind], + [Enable Valgrind support])], + [no], + [no]) + +AS_VAR_IF([PHP_VALGRIND], [no],, [ + PKG_CHECK_MODULES([VALGRIND], [valgrind], + [PHP_EVAL_INCLINE([$VALGRIND_CFLAGS]) + AC_DEFINE([HAVE_VALGRIND], [1], + [Define to 1 if Valgrind is enabled and supported.])]) + save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $VALGRIND_CFLAGS" + AC_CHECK_HEADERS([valgrind/cachegrind.h]) + CFLAGS=$save_CFLAGS +]) + +dnl General settings. +dnl ---------------------------------------------------------------------------- +PHP_CONFIGURE_PART([General settings]) + +PHP_HELP_SEPARATOR([General settings:]) + +PHP_ARG_ENABLE([gcov], + [whether to include gcov symbols], + [AS_HELP_STRING([--enable-gcov], + [Enable GCOV code coverage - FOR DEVELOPERS ONLY!!])], + [no], + [no]) + +AS_VAR_IF([PHP_GCOV], [yes], [ + AS_VAR_IF([GCC], [yes],, + [AC_MSG_ERROR([GNU C compatible compiler is required for --enable-gcov])]) + + dnl Check if ccache is being used. + AS_CASE([$($php_shtool path $CC)], + [*ccache*], [gcc_ccache=yes], + [gcc_ccache=no]) + + if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then + AC_MSG_ERROR(m4_text_wrap([ + ccache must be disabled when --enable-gcov option is used. You can disable + ccache by setting environment variable CCACHE_DISABLE=1. + ])) + fi + + AC_DEFINE([HAVE_GCOV], [1], [Define to 1 if GCOV code coverage is enabled.]) + PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/build/Makefile.gcov], [$abs_srcdir]) + + dnl Remove all optimization flags from CFLAGS. + PHP_REMOVE_OPTIMIZATION_FLAGS + + dnl Add the special gcc flags. + CFLAGS="$CFLAGS -O0 -fprofile-arcs -ftest-coverage" + CXXFLAGS="$CXXFLAGS -O0 -fprofile-arcs -ftest-coverage" +]) + +PHP_ARG_ENABLE([debug], + [whether to include debugging symbols], + [AS_HELP_STRING([--enable-debug], + [Compile with debugging symbols])], + [no], + [no]) + +AS_VAR_IF([PHP_DEBUG], [yes], [ + PHP_DEBUG=1 + ZEND_DEBUG=yes + PHP_REMOVE_OPTIMIZATION_FLAGS + dnl Add -O0 only if GCC or ICC is used. + if test "$GCC" = "yes" || test "$ICC" = "yes"; then + CFLAGS="$CFLAGS -O0" + CXXFLAGS="$CXXFLAGS -g -O0" + fi + if test "$SUNCC" = "yes"; then + if test -n "$auto_cflags"; then + CFLAGS="-g" + CXXFLAGS="-g" + else + CFLAGS="$CFLAGS -g" + CXXFLAGS="$CFLAGS -g" + fi + fi +], [ + PHP_DEBUG=0 + ZEND_DEBUG=no +]) + +PHP_ARG_ENABLE([debug-assertions], + [whether to enable debug assertions in release mode], + [AS_HELP_STRING([--enable-debug-assertions], + [Compile with debug assertions even in release mode])], + [no], + [no]) + +AS_VAR_IF([PHP_DEBUG_ASSERTIONS], [yes], [ + PHP_DEBUG=1 + ZEND_DEBUG=yes +]) + +AC_ARG_ENABLE([zts], + [AS_HELP_STRING([--enable-zts], + [Enable thread safety])], + [ZEND_ZTS=$enableval], + [ZEND_ZTS=no]) + +AS_VAR_IF([ZEND_ZTS], [yes], [PHP_THREAD_SAFETY=yes], [PHP_THREAD_SAFETY=no]) + +AS_VAR_IF([PHP_THREAD_SAFETY], [yes], [ + AS_VAR_IF([pthreads_working], [yes], [], + [AC_MSG_FAILURE(m4_text_wrap([ + Unable to verify system support for POSIX Threads, which are required for + PHP thread safety (ZTS) build. + ]))]) + + AC_MSG_CHECKING([for POSIX threads]) + AC_MSG_RESULT([yes]) +]) + +PHP_ARG_ENABLE([rtld-now], + [whether to dlopen extensions with RTLD_NOW instead of RTLD_LAZY], + [AS_HELP_STRING([--enable-rtld-now], + [Use dlopen with RTLD_NOW instead of RTLD_LAZY])], + [no], + [no]) + +AS_VAR_IF([PHP_RTLD_NOW], [yes], + [AC_DEFINE([PHP_USE_RTLD_NOW], [1], + [Define to 1 if 'dlopen()' uses the 'RTLD_NOW' mode flag instead of + 'RTLD_LAZY'.])]) + +PHP_ARG_WITH([layout], + [layout of installed files], + [AS_HELP_STRING([--with-layout=TYPE], + [Set how installed files will be laid out. Type can be either PHP or GNU [PHP]])], + [PHP], + [no]) + +AS_CASE([$PHP_LAYOUT], [GNU], [oldstyleextdir=no], [oldstyleextdir=yes]) + +PHP_ARG_WITH([config-file-path], + [path to configuration file], + [AS_HELP_STRING([--with-config-file-path=PATH], + [Set the path in which to look for php.ini [PREFIX/lib]])], + [DEFAULT], + [no]) + +AS_VAR_IF([PHP_CONFIG_FILE_PATH], [DEFAULT], + [AS_CASE([$PHP_LAYOUT], + [GNU], [PHP_CONFIG_FILE_PATH=$sysconfdir], + [PHP_CONFIG_FILE_PATH=$libdir])]) + +AC_MSG_CHECKING([where to scan for configuration files]) +PHP_ARG_WITH([config-file-scan-dir],, + [AS_HELP_STRING([--with-config-file-scan-dir=PATH], + [Set the path where to scan for configuration files])], + [DEFAULT], + [no]) + +AS_VAR_IF([PHP_CONFIG_FILE_SCAN_DIR], [DEFAULT], [PHP_CONFIG_FILE_SCAN_DIR=]) +AC_MSG_RESULT([$PHP_CONFIG_FILE_SCAN_DIR]) + +PHP_ARG_ENABLE([sigchild], + [whether to enable PHP's own SIGCHLD handler], + [AS_HELP_STRING([--enable-sigchild], + [Enable PHP's own SIGCHLD handler])], + [no], + [no]) + +AH_TEMPLATE([PHP_SIGCHILD], + [Define to 1 if PHP uses its own SIGCHLD handler, and to 0 if not.]) +AS_VAR_IF([PHP_SIGCHILD], [yes], + [AC_DEFINE([PHP_SIGCHILD], [1])], + [AC_DEFINE([PHP_SIGCHILD], [0])]) + +PHP_ARG_ENABLE([libgcc], + [whether to explicitly link against libgcc], + [AS_HELP_STRING([--enable-libgcc], + [Enable explicitly linking against libgcc])], + [no], + [no]) + +AS_VAR_IF([PHP_LIBGCC], [yes], [ + PHP_LIBGCC_LIBPATH([gcc]) + AS_VAR_IF([libgcc_libpath],, + [AC_MSG_ERROR([Cannot locate libgcc. Make sure that gcc is in your path])]) + PHP_ADD_LIBPATH([$libgcc_libpath]) + PHP_ADD_LIBRARY([gcc], [yes]) +]) + +PHP_ARG_ENABLE([short-tags], + [whether to enable short tags by default], + [AS_HELP_STRING([--disable-short-tags], + [Disable the short-form + #include + #include + ], [[ + struct sockaddr_in6 s; + struct in6_addr t = in6addr_any; + int i = AF_INET6; + (void)s; + t.s6_addr[0] = 0; + (void)i; + ]])], + [php_cv_have_ipv6=yes], + [php_cv_have_ipv6=no])]) +]) +AS_VAR_IF([php_cv_have_ipv6], [yes], + [AC_DEFINE([HAVE_IPV6], [1], + [Define to 1 if IPv6 is enabled and supported.])]) + +dnl DTRACE checks. Note: this has to be done after SAPI configuration. +PHP_ARG_ENABLE([dtrace], + [whether to enable DTrace support], + [AS_HELP_STRING([--enable-dtrace], + [Enable DTrace support])], + [no], + [no]) + +AS_VAR_IF([PHP_DTRACE], [yes], [ + PHP_INIT_DTRACE([Zend/zend_dtrace.d], [Zend/zend_dtrace_gen.h], [ + main/main.c + Zend/zend_API.c + Zend/zend_dtrace.c + Zend/zend_exceptions.c + Zend/zend_execute.c + Zend/zend.c + ]) + AC_DEFINE([HAVE_DTRACE], [1], [Define to 1 if DTrace support is enabled.]) +]) + +AC_MSG_CHECKING([how big to make fd sets]) +PHP_ARG_ENABLE([fd-setsize],, + [AS_HELP_STRING([--enable-fd-setsize], + [Set size of descriptor sets])], + [no], + [no]) + +AS_VAR_IF([PHP_FD_SETSIZE], [no], [AC_MSG_RESULT([using system default])], [ + if test "0$PHP_FD_SETSIZE" -gt 0 2>/dev/null; then + CPPFLAGS="$CPPFLAGS -DFD_SETSIZE=$PHP_FD_SETSIZE" + AC_MSG_RESULT([using $PHP_FD_SETSIZE]) + else + AC_MSG_ERROR([Invalid value passed to --enable-fd-setsize!]) + fi +]) + +PHP_ARG_ENABLE([werror],, + [AS_HELP_STRING([--enable-werror], + [Enable -Werror])], + [no], + [no]) +PHP_ARG_ENABLE([memory-sanitizer],, + [AS_HELP_STRING([--enable-memory-sanitizer], + [Enable memory sanitizer (clang only)])], + [no], + [no]) +PHP_ARG_ENABLE([address-sanitizer],, + [AS_HELP_STRING([--enable-address-sanitizer], + [Enable address sanitizer])], + [no], + [no]) +PHP_ARG_ENABLE([undefined-sanitizer],, + [AS_HELP_STRING([--enable-undefined-sanitizer], + [Enable undefined sanitizer])], + [no], + [no]) + +dnl Extension configuration. +dnl ---------------------------------------------------------------------------- + +PHP_HELP_SEPARATOR([[Extensions: + --with-EXTENSION=[shared[,PATH]] + + NOTE: Not all extensions can be built as 'shared'. + + Example: --with-foobar=shared,/usr/local/foobar/ + + o Builds the foobar extension as shared extension. + o foobar package install prefix is /usr/local/foobar/ +]]) + +PHP_CONFIGURE_PART([Configuring extensions]) + +dnl Check if all enabled by default extensions should be disabled. +AC_ARG_ENABLE([all], + [AS_HELP_STRING([--disable-all], + [Disable all extensions which are enabled by default])], + [PHP_ENABLE_ALL=$enableval]) + +dnl Reading config stubs. +esyscmd(./build/config-stubs ext) + +dnl Extensions post-config. +dnl ---------------------------------------------------------------------------- + +dnl Align segments on huge page boundary +AS_CASE([$host_alias], [[i[3456]86-*-linux-* | x86_64-*-linux-*]], + [AC_CACHE_CHECK([linker support for -zcommon-page-size=2097152], + [php_cv_have_common_page_size], [ + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-zcommon-page-size=2097152 -Wl,-zmax-page-size=2097152" + AC_RUN_IFELSE([AC_LANG_PROGRAM()], + [php_cv_have_common_page_size=yes], + [php_cv_have_common_page_size=no], + [php_cv_have_common_page_size=no]) + LDFLAGS=$save_LDFLAGS]) + AS_VAR_IF([php_cv_have_common_page_size], [yes], + [EXTRA_LDFLAGS_PROGRAM="$EXTRA_LDFLAGS_PROGRAM -Wl,-zcommon-page-size=2097152 -Wl,-zmax-page-size=2097152"], + [AC_CACHE_CHECK([linker support for -zmax-page-size=2097152], + [php_cv_have_max_page_size], [ + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-zmax-page-size=2097152" + AC_RUN_IFELSE([AC_LANG_PROGRAM()], + [php_cv_have_max_page_size=yes], + [php_cv_have_max_page_size=no], + [php_cv_have_max_page_size=no]) + LDFLAGS=$save_LDFLAGS]) + AS_VAR_IF([php_cv_have_max_page_size], [yes], + [EXTRA_LDFLAGS_PROGRAM="$EXTRA_LDFLAGS_PROGRAM -Wl,-zmax-page-size=2097152"]) + ]) +]) + +enable_shared=yes +enable_static=yes + +case $php_sapi_module in + shared[)] + if test "$PHP_CGI" = "no" && test "$PHP_CLI" = "no" && test "$PHP_FPM" = "no" && test "$PHP_LITESPEED" = "no" && test "$PHP_PHPDBG" = "no"; then + enable_static=no + fi + case $with_pic in + yes) + standard_libtool_flag='-prefer-pic' + ;; + no) + standard_libtool_flag='-prefer-non-pic' + ;; + esac + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -avoid-version -module" + ;; + *[)] + standard_libtool_flag='-prefer-non-pic -static' + if test -z "$PHP_MODULES" && test -z "$PHP_ZEND_EX"; then + enable_shared=no + fi + ;; +esac + +EXTRA_LIBS="$EXTRA_LIBS $DLIBS $LIBS" +unset LIBS + +dnl PEAR +dnl ---------------------------------------------------------------------------- + +PHP_HELP_SEPARATOR([PEAR:]) +PHP_CONFIGURE_PART([Configuring PEAR]) + +dnl If CLI is disabled disable PEAR. +AS_VAR_IF([PHP_CLI], [no], [with_pear=no]) + +PHP_ARG_WITH([pear], + [whether to install PEAR], + [AS_HELP_STRING([[--with-pear[=DIR]]], + [Install PEAR in DIR [PREFIX/lib/php]])], + [no], + [yes]) + +AS_VAR_IF([PHP_PEAR], [no],, [ + AC_MSG_WARN([The --with-pear option is deprecated]) + + dnl PEAR dependencies. + AS_VAR_IF([PHP_XML], [no], [AC_MSG_ERROR(m4_text_wrap([ + PEAR requires XML to be enabled. Add '--enable-xml' to the configure line, + or disable PEAR (--without-pear). + ]))]) + + install_pear=install-pear + + AS_VAR_IF([PHP_PEAR], [yes], + [AS_CASE([$PHP_LAYOUT], + [GNU], [PEAR_INSTALLDIR=$datadir/pear], + [PEAR_INSTALLDIR=$libdir/php])], + [PEAR_INSTALLDIR=$PHP_PEAR]) + + PHP_SUBST([PEAR_INSTALLDIR]) + PHP_ADD_BUILD_DIR([pear]) + PHP_ADD_MAKEFILE_FRAGMENT([$abs_srcdir/pear/Makefile.frag], + [$abs_srcdir/pear], + [pear]) +]) + +dnl Configuring Zend and TSRM. +dnl ---------------------------------------------------------------------------- + +PHP_HELP_SEPARATOR([Zend:]) +PHP_CONFIGURE_PART([Configuring Zend]) + +AC_ARG_ENABLE([fiber-asm], + [AS_HELP_STRING([--disable-fiber-asm], + [Disable the use of boost fiber assembly files])], + [fiber_asm=$enableval], [fiber_asm='yes']) + +AS_CASE([$host_cpu], + [x86_64*|amd64*], [fiber_cpu="x86_64"], + [x86*|amd*|i?86*|pentium], [fiber_cpu="i386"], + [aarch64*|arm64*], [fiber_cpu="arm64"], + [arm*], [fiber_cpu="arm32"], + [ppc64*|powerpc64*], [fiber_cpu="ppc64"], + [ppc*|powerpc*], [fiber_cpu="ppc32"], + [riscv64*], [fiber_cpu="riscv64"], + [sparc64], [fiber_cpu="sparc64"], + [s390x*], [fiber_cpu="s390x"], + [loongarch64*], [fiber_cpu="loongarch64"], + [mips64*], [fiber_cpu="mips64"], + [mips*], [fiber_cpu="mips32"], + [fiber_cpu="unknown"] +) + +AS_CASE([$host_os], + [darwin*], [fiber_os="mac"], + [aix*|os400*], [fiber_os="aix"], + [freebsd*], [fiber_os="freebsd"], + [midipix], [fiber_os="midipix"], + [fiber_os="other"] +) + +AS_CASE([$fiber_cpu], + [x86_64], [fiber_asm_file_prefix="x86_64_sysv"], + [i386], [fiber_asm_file_prefix="i386_sysv"], + [arm64], [fiber_asm_file_prefix="arm64_aapcs"], + [arm32], [fiber_asm_file_prefix="arm_aapcs"], + [ppc64], [fiber_asm_file_prefix="ppc64_sysv"], + [ppc32], [fiber_asm_file_prefix="ppc32_sysv"], + [riscv64], [fiber_asm_file_prefix="riscv64_sysv"], + [sparc64], [fiber_asm_file_prefix="sparc64_sysv"], + [s390x], [fiber_asm_file_prefix="s390x_sysv"], + [loongarch64], [fiber_asm_file_prefix="loongarch64_sysv"], + [mips64], [fiber_asm_file_prefix="mips64_n64"], + [mips32], [fiber_asm_file_prefix="mips32_o32"], + [fiber_asm_file_prefix="unknown"] +) + +if test "$fiber_os" = 'mac'; then + fiber_asm_file="combined_sysv_macho_gas" +elif test "$fiber_os" = 'aix'; then + # AIX uses a different calling convention (shared with non-_CALL_ELF Linux). + # The AIX assembler isn't GNU, but the file is compatible. + fiber_asm_file="${fiber_asm_file_prefix}_xcoff_gas" +elif test "$fiber_os" = 'freebsd'; then + case $fiber_cpu in + i386*) + fiber_asm="no" + ;; + *) + fiber_asm_file="${fiber_asm_file_prefix}_elf_gas" + ;; + esac +elif test "$fiber_os" = 'midipix'; then + case $fiber_cpu in + i386*) + fiber_asm="no" + ;; + x86_64) + fiber_asm_file="x86_64_ms_pe_gas" + ;; + esac +elif test "$fiber_asm_file_prefix" != 'unknown'; then + fiber_asm_file="${fiber_asm_file_prefix}_elf_gas" +else + fiber_asm="no" +fi + +AC_CACHE_CHECK([whether syscall to create shadow stack exists], +[php_cv_have_shadow_stack_syscall], +[AC_RUN_IFELSE([AC_LANG_SOURCE([ +#include +#include +int main(void) { + /* test if syscall 451, i.e., map_shadow_stack is available */ + void* base = (void *)syscall(451, 0, 0x20000, 0x1); + if (base != (void*)-1) { + munmap(base, 0x20000); + return 0; + } + return 1; +} +])], + [php_cv_have_shadow_stack_syscall=yes], + [php_cv_have_shadow_stack_syscall=no], + [php_cv_have_shadow_stack_syscall=no]) +]) +dnl The asm files can't see macro from AC_DEFINE, workaround this via cflag. If +dnl the syscall doesn't exist, we may block the final ELF from __PROPERTY_SHSTK +dnl via redefine macro as "-D__CET__=1". +AS_VAR_IF([php_cv_have_shadow_stack_syscall], [yes], + [fiber_asm_cflag="-DSHADOW_STACK_SYSCALL=1"], + [fiber_asm_cflag="-DSHADOW_STACK_SYSCALL=0"]) + +if test "$fiber_asm" = 'yes'; then + AC_MSG_CHECKING([for fiber switching context]) + PHP_ADD_SOURCES([Zend/asm], + [make_${fiber_asm_file}.S jump_${fiber_asm_file}.S], + [$fiber_asm_cflag]) + AC_MSG_RESULT([$fiber_asm_file]) +else + AS_VAR_IF([fiber_os], [mac], [AC_DEFINE([_XOPEN_SOURCE], [1], [ ])]) + AC_CHECK_HEADER([ucontext.h], + [AC_DEFINE([ZEND_FIBER_UCONTEXT], [1], + [Define to 1 if Zend fiber uses ucontext instead of boost context.])], + [AC_MSG_FAILURE([fibers not available on this platform])]) +fi + +ZEND_INIT + +ZEND_EXTRA_LIBS=$LIBS +unset LIBS + +PHP_ADD_INCLUDE([$abs_srcdir], [1]) +PHP_ADD_INCLUDE([$abs_srcdir/main], [1]) +PHP_ADD_INCLUDE([$abs_builddir], [1]) +PHP_ADD_INCLUDE([$abs_builddir/main], [1]) +PHP_ADD_INCLUDE([$abs_builddir/TSRM]) +PHP_ADD_INCLUDE([$abs_builddir/Zend]) +PHP_ADD_INCLUDE([$abs_srcdir/Zend]) +PHP_ADD_INCLUDE([$abs_srcdir/TSRM]) + +EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LDFLAGS" +EXTRA_LDFLAGS_PROGRAM="$EXTRA_LDFLAGS_PROGRAM $LDFLAGS" +unset LDFLAGS + +AC_ARG_PROGRAM + +AS_VAR_IF([prefix], [NONE], [prefix=/usr/local]) +AS_VAR_IF([exec_prefix], [NONE], [exec_prefix='${prefix}']) +AS_VAR_IF([program_prefix], [NONE], [program_prefix=]) +AS_VAR_IF([program_suffix], [NONE], [program_suffix=]) + +orig_libdir=$libdir +AS_CASE([$libdir], + ['${exec_prefix}/lib'], [libdir=$libdir/php]) + +AS_CASE([$(eval echo $datadir)], + ['${prefix}/share'], [datadir=$datadir/php]) + +phptempdir=$(pwd)/libs + +old_exec_prefix=$exec_prefix +old_libdir=$libdir +old_datadir=$datadir +exec_prefix=$(eval echo $exec_prefix) +libdir=$(eval echo $libdir) +datadir=$(eval eval echo $datadir) + +dnl Build extension directory path. +ZEND_MODULE_API_NO=$($EGREP '#define ZEND_MODULE_API_NO ' $srcdir/Zend/zend_modules.h|"${SED}" 's/#define ZEND_MODULE_API_NO //') + +AC_ARG_VAR([EXTENSION_DIR], + [Default directory for dynamically loadable PHP extensions. If left empty, it + is determined automatically. Can be overridden using the PHP 'extension_dir' + INI directive.]) +AS_VAR_IF([EXTENSION_DIR],, [ + extbasedir=$ZEND_MODULE_API_NO + AS_VAR_IF([oldstyleextdir], [yes], [ + AS_VAR_IF([PHP_DEBUG], [1], [part1=debug], [part1=no-debug]) + AS_VAR_IF([PHP_THREAD_SAFETY], [yes], [part2=zts], [part2=non-zts]) + extbasedir=$part1-$part2-$extbasedir + EXTENSION_DIR=$libdir/extensions/$extbasedir + ], [ + AS_VAR_IF([PHP_THREAD_SAFETY], [yes], [extbasedir=$extbasedir-zts]) + AS_VAR_IF([PHP_DEBUG], [1], [extbasedir=$extbasedir-debug]) + EXTENSION_DIR=$libdir/$extbasedir + ]) +]) + +AS_CASE([$PHP_LAYOUT], + [GNU], [datarootdir=$prefix/share], + [datarootdir=$prefix/php]) + +dnl Expand all directory names for use in macros/constants. +EXPANDED_PEAR_INSTALLDIR=$(eval echo $PEAR_INSTALLDIR) +EXPANDED_EXTENSION_DIR=$(eval echo $EXTENSION_DIR) +EXPANDED_LOCALSTATEDIR=$(eval echo $localstatedir) +EXPANDED_BINDIR=$(eval echo $bindir) +EXPANDED_SBINDIR=$(eval echo $sbindir) +EXPANDED_MANDIR=$(eval echo $mandir) +EXPANDED_LIBDIR=$libdir +EXPANDED_SYSCONFDIR=$(eval echo $sysconfdir) +EXPANDED_DATADIR=$datadir +EXPANDED_PHP_CONFIG_FILE_PATH=$(eval echo "$PHP_CONFIG_FILE_PATH") +EXPANDED_PHP_CONFIG_FILE_SCAN_DIR=$(eval echo "$PHP_CONFIG_FILE_SCAN_DIR") +INCLUDE_PATH=.:$EXPANDED_PEAR_INSTALLDIR + +exec_prefix=$old_exec_prefix +libdir=$old_libdir +datadir=$old_datadir + +AC_SUBST([INCLUDE_PATH]) +AC_SUBST([EXPANDED_PEAR_INSTALLDIR]) +AC_SUBST([EXPANDED_EXTENSION_DIR]) +AC_SUBST([EXPANDED_BINDIR]) +AC_SUBST([EXPANDED_SBINDIR]) +AC_SUBST([EXPANDED_MANDIR]) +AC_SUBST([EXPANDED_LIBDIR]) +AC_SUBST([EXPANDED_DATADIR]) +AC_SUBST([EXPANDED_SYSCONFDIR]) +AC_SUBST([EXPANDED_LOCALSTATEDIR]) +AC_SUBST([EXPANDED_PHP_CONFIG_FILE_PATH]) +AC_SUBST([EXPANDED_PHP_CONFIG_FILE_SCAN_DIR]) +AC_SUBST([PHP_INSTALLED_SAPIS]) +AC_SUBST([SAPI_LIBNAME_SHARED]) +AC_SUBST([SAPI_LIBNAME_STATIC]) +AC_SUBST([PHP_VERSION]) +AC_SUBST([PHP_VERSION_ID]) +AC_SUBST([PHP_LDFLAGS]) + +PHP_UTILIZE_RPATHS + +PHP_REMOVE_USR_LIB([PHP_LDFLAGS]) +PHP_REMOVE_USR_LIB([LDFLAGS]) + +EXTRA_LDFLAGS="$EXTRA_LDFLAGS $PHP_LDFLAGS" +EXTRA_LDFLAGS_PROGRAM="$EXTRA_LDFLAGS_PROGRAM $PHP_LDFLAGS" + +AC_ARG_VAR([PHP_UNAME], + [System information (defaults to the 'uname -a' output)]) +AS_VAR_IF([PHP_UNAME],, [PHP_UNAME=$(uname -a | xargs)]) +AC_DEFINE_UNQUOTED([PHP_UNAME], ["$PHP_UNAME"], [The 'uname -a' output.]) + +PHP_OS=$(uname | xargs) +AC_DEFINE_UNQUOTED([PHP_OS], ["$PHP_OS"], [The 'uname' output.]) + +AC_ARG_VAR([PHP_BUILD_SYSTEM], + [The system that PHP was built on (defaults to the 'uname -a' output)]) +AS_VAR_IF([PHP_BUILD_SYSTEM],, [PHP_BUILD_SYSTEM=$PHP_UNAME]) +AC_DEFINE_UNQUOTED([PHP_BUILD_SYSTEM], ["$PHP_BUILD_SYSTEM"], + [The system that PHP was built on.]) + +AC_ARG_VAR([PHP_BUILD_PROVIDER], [The PHP build provider information]) +AS_VAR_IF([PHP_BUILD_PROVIDER],,, + [AC_DEFINE_UNQUOTED([PHP_BUILD_PROVIDER], ["$PHP_BUILD_PROVIDER"], + [The PHP build provider information.])]) + +AC_ARG_VAR([PHP_BUILD_COMPILER], + [Information about the compiler used for the PHP build]) +AS_VAR_IF([PHP_BUILD_COMPILER],,, + [AC_DEFINE_UNQUOTED([PHP_BUILD_COMPILER], ["$PHP_BUILD_COMPILER"], + [The compiler used for the PHP build.])]) + +AC_ARG_VAR([PHP_BUILD_ARCH], [The build architecture]) +AS_VAR_IF([PHP_BUILD_ARCH],,, + [AC_DEFINE_UNQUOTED([PHP_BUILD_ARCH], ["$PHP_BUILD_ARCH"], + [The build architecture.])]) + +PHP_SUBST([PHP_FASTCGI_OBJS]) +PHP_SUBST([PHP_SAPI_OBJS]) +PHP_SUBST([PHP_BINARY_OBJS]) +PHP_SUBST([PHP_GLOBAL_OBJS]) +PHP_SUBST([PHP_BINARIES]) +PHP_SUBST([PHP_MODULES]) +PHP_SUBST([PHP_ZEND_EX]) +PHP_SUBST([bindir]) +PHP_SUBST([sbindir]) +PHP_SUBST([exec_prefix]) +PHP_SUBST_OLD([program_prefix]) +PHP_SUBST_OLD([program_suffix]) +PHP_SUBST([includedir]) +PHP_SUBST_OLD([orig_libdir]) +PHP_SUBST([libdir]) +PHP_SUBST([mandir]) +PHP_SUBST([phptempdir]) +PHP_SUBST([prefix]) +PHP_SUBST([localstatedir]) +PHP_SUBST([datadir]) +PHP_SUBST([datarootdir]) +PHP_SUBST([sysconfdir]) +PHP_SUBST([EXEEXT]) +PHP_SUBST([CC]) +PHP_SUBST([BUILD_CC]) +PHP_SUBST([CFLAGS]) +PHP_SUBST([CFLAGS_CLEAN]) +PHP_SUBST([CPP]) +PHP_SUBST([CPPFLAGS]) +PHP_SUBST([CXX]) +PHP_SUBST([CXXFLAGS]) +PHP_SUBST([CXXFLAGS_CLEAN]) +PHP_SUBST_OLD([EXTENSION_DIR]) +PHP_SUBST([EXTRA_LDFLAGS]) +PHP_SUBST([EXTRA_LDFLAGS_PROGRAM]) +PHP_SUBST_OLD([EXTRA_LIBS]) +PHP_SUBST([ZEND_EXTRA_LIBS]) +PHP_SUBST([INCLUDES]) +PHP_SUBST([EXTRA_INCLUDES]) +PHP_SUBST([INSTALL_IT]) +PHP_SUBST([LIBTOOL]) +PHP_SUBST([LN_S]) +PHP_SUBST([NATIVE_RPATHS]) +PHP_SUBST([OVERALL_TARGET]) +PHP_SUBST([PHP_RPATHS]) +PHP_SUBST([PHP_SAPI]) +PHP_SUBST([SHELL]) +PHP_SUBST([PHP_FRAMEWORKS]) +PHP_SUBST([PHP_FRAMEWORKPATH]) +PHP_SUBST([INSTALL_HEADERS]) + +if test "$PHP_THREAD_SAFETY" = "yes" && test -n "$ac_cv_pthreads_cflags"; then + CXXFLAGS="$CXXFLAGS $ac_cv_pthreads_cflags" + CPPFLAGS="$CPPFLAGS $ac_cv_pthreads_cflags" +fi + +dnl Enable -Werror late, because it may break configure checks throwing warnings. +AS_VAR_IF([PHP_WERROR], [yes], [ + CFLAGS="$CFLAGS -Werror" + CXXFLAGS="$CXXFLAGS -Werror" +]) + +if test "$PHP_MEMORY_SANITIZER" = "yes" && + test "$PHP_ADDRESS_SANITIZER" = "yes"; then + AC_MSG_ERROR([MemorySanitizer and AddressSanitizer are mutually exclusive]) +fi + +dnl Enable -fsanitize=memory late, because interceptors may break linking detection. +AS_VAR_IF([PHP_MEMORY_SANITIZER], [yes], + [AX_CHECK_COMPILE_FLAG([-fsanitize=memory -fsanitize-memory-track-origins], [ + CFLAGS="$CFLAGS -fsanitize=memory -fsanitize-memory-track-origins" + CXXFLAGS="$CXXFLAGS -fsanitize=memory -fsanitize-memory-track-origins" + ], [AC_MSG_ERROR([MemorySanitizer is not available])]) +]) + +AS_VAR_IF([PHP_ADDRESS_SANITIZER], [yes], + [AS_VAR_IF([PHP_VALGRIND], [no],, [AC_MSG_ERROR(m4_text_wrap([ + Valgrind and address sanitizer are not compatible. Either disable Valgrind + (remove --with-valgrind) or disable address sanitizer (remove + --enable-address-sanitizer). + ]))]) + + AX_CHECK_COMPILE_FLAG([-fsanitize=address], [ + CFLAGS="$CFLAGS -fsanitize=address -DZEND_TRACK_ARENA_ALLOC" + CXXFLAGS="$CXXFLAGS -fsanitize=address -DZEND_TRACK_ARENA_ALLOC" + ], [AC_MSG_ERROR([AddressSanitizer is not available])]) +]) + +AS_VAR_IF([PHP_UNDEFINED_SANITIZER], [yes], + [AX_CHECK_COMPILE_FLAG([-fsanitize=undefined], [ + CFLAGS="$CFLAGS -fsanitize=undefined -fno-sanitize-recover=undefined" + CXXFLAGS="$CXXFLAGS -fsanitize=undefined -fno-sanitize-recover=undefined" + AX_CHECK_COMPILE_FLAG([-fno-sanitize=object-size], [ + dnl Disable object-size sanitizer, because it is incompatible with our zend_function + dnl union, and this can't be easily fixed. + CFLAGS="$CFLAGS -fno-sanitize=object-size" + CXXFLAGS="$CFLAGS -fno-sanitize=object-size" + ]) + + dnl Clang 17 adds stricter function pointer compatibility checks where pointer args cannot be + dnl cast to void*. In that case, set -fno-sanitize=function. + OLD_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -fno-sanitize-recover=undefined" + AC_CACHE_CHECK([whether to add -fno-sanitize=function], + [php_cv_ubsan_no_function], + [AC_RUN_IFELSE([AC_LANG_SOURCE([ + void foo(char *string) { (void)string; } + int main(void) { + void (*f)(void *) = (void (*)(void *))foo; + f("foo"); + return 0; + } + ])], + [php_cv_ubsan_no_function=no], + [php_cv_ubsan_no_function=yes], + [php_cv_ubsan_no_function=no])]) + CFLAGS=$OLD_CFLAGS + AS_VAR_IF([php_cv_ubsan_no_function], [yes], [ + CFLAGS="$CFLAGS -fno-sanitize=function" + CXXFLAGS="$CFLAGS -fno-sanitize=function" + ]) + ], [AC_MSG_ERROR([UndefinedBehaviorSanitizer is not available])]) +]) + +if test "$PHP_MEMORY_SANITIZER" = "yes" || + test "$PHP_ADDRESS_SANITIZER" = "yes" || + test "$PHP_UNDEFINED_SANITIZER" = "yes"; then + CFLAGS="$CFLAGS -fno-omit-frame-pointer" + CXXFLAGS="$CXXFLAGS -fno-omit-frame-pointer" +fi + +dnl +dnl Libtool creation. +dnl + +PHP_HELP_SEPARATOR([Libtool:]) +PHP_CONFIGURE_PART([Configuring libtool]) + +dnl Silence warning: "ar: 'u' modifier ignored since 'D' is the default". +dnl See https://github.com/php/php-src/pull/3017 +AC_SUBST([AR_FLAGS], [cr]) + +dnl Only allow AC_PROG_CXX and AC_PROG_CXXCPP if they are explicitly called (by +dnl PHP_REQUIRE_CXX). Otherwise AC_PROG_LIBTOOL fails if there is no working C++ +dnl compiler. +AC_PROVIDE_IFELSE([PHP_REQUIRE_CXX], [], [ + undefine([AC_PROG_CXX]) + AC_DEFUN([AC_PROG_CXX], []) + undefine([AC_PROG_CXXCPP]) + AC_DEFUN([AC_PROG_CXXCPP], [php_prog_cxxcpp=disabled]) +]) +AC_PROG_LIBTOOL + +PHP_SET_LIBTOOL_VARIABLE([--silent]) + +dnl libtool 1.4.3 needs this. +PHP_SET_LIBTOOL_VARIABLE([--preserve-dup-deps]) + +PHP_CONFIGURE_PART([Generating files]) + +CXXFLAGS_CLEAN=$CXXFLAGS +CFLAGS_CLEAN="$CFLAGS \$(PROF_FLAGS)" +CFLAGS="\$(CFLAGS_CLEAN) $standard_libtool_flag" +CXXFLAGS="$CXXFLAGS $standard_libtool_flag \$(PROF_FLAGS)" + +if test "$PHP_PHAR" != "no" && test "$PHP_CLI" != "no"; then + pharcmd=pharcmd + pharcmd_install=install-pharcmd +else + pharcmd= + pharcmd_install= +fi; + +all_targets="\$(OVERALL_TARGET) \$(PHP_MODULES) \$(PHP_ZEND_EX) \$(PHP_BINARIES) $pharcmd" +install_targets="$install_sapi $install_modules $install_binaries install-build install-headers install-programs $install_pear $pharcmd_install" + +PHP_SUBST([all_targets]) +PHP_SUBST([install_targets]) +PHP_SUBST([install_binary_targets]) + +PHP_INSTALL_HEADERS([Zend/ TSRM/ main/ main/streams/]) +PHP_INSTALL_HEADERS([Zend/Optimizer], m4_normalize([ + zend_call_graph.h + zend_cfg.h + zend_dfg.h + zend_dump.h + zend_func_info.h + zend_inference.h + zend_optimizer.h + zend_ssa.h + zend_worklist.h +])) + +PHP_ADD_SOURCES([TSRM], [TSRM.c], [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) + +PHP_ADD_SOURCES([main], m4_normalize([ + explicit_bzero.c + fopen_wrappers.c + getopt.c + main.c + network.c + output.c + php_content_types.c + php_ini_builder.c + php_ini.c + php_odbc_utils.c + php_open_temporary_file.c + php_scandir.c + php_syslog.c + php_ticks.c + php_variables.c + reentrancy.c + rfc1867.c + safe_bcmp.c + SAPI.c + snprintf.c + spprintf.c + strlcat.c + strlcpy.c + ]), + [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) + +if printf "#if __ELF__\nelf\n#endif\n" | $CC -E - | grep elf > /dev/null; then + PHP_ADD_SOURCES([main], [debug_gdb_scripts.c]) + + cat >> Makefile.objects < header file.]) + +PHP_ADD_BUILD_DIR([ + main + main/streams + scripts + scripts/man1 + TSRM + Zend + Zend/asm + Zend/Optimizer +]) + +AC_CONFIG_FILES([ + main/build-defs.h + scripts/man1/php-config.1 + scripts/man1/phpize.1 + scripts/php-config + scripts/phpize +]) + +AC_CONFIG_COMMANDS_PRE([PHP_PATCH_CONFIG_HEADERS([main/php_config.h.in])]) + +AC_CONFIG_COMMANDS([Zend/zend_config.h], [ +cat >Zend/zend_config.h < +FEO +]) + +AC_CONFIG_COMMANDS([main/internal_functions.c], [], [ + AWK="$AWK" $SHELL $srcdir/build/genif.sh \ + $srcdir/main/internal_functions.c.in \ + "$EXT_STATIC" > main/internal_functions.c +]) + +AC_CONFIG_COMMANDS([main/internal_functions_cli.c], [], [ + AWK="$AWK" $SHELL $srcdir/build/genif.sh \ + $srcdir/main/internal_functions.c.in \ + "$EXT_CLI_STATIC" > main/internal_functions_cli.c +]) + +AC_CONFIG_COMMANDS([default], [ +cat < 0) { /* compression is better then 2:1, need to allocate more memory */ bzs.avail_out = source_len; - size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32; -#ifndef ZEND_ENABLE_ZVAL_LONG64 + size = (((uint64_t) bzs.total_out_hi32) << 32U) + bzs.total_out_lo32; if (size > SIZE_MAX) { /* no reason to continue if we're going to drop it anyway */ break; } -#endif dest = zend_string_safe_realloc(dest, 1, bzs.avail_out+1, (size_t) size, 0); bzs.next_out = ZSTR_VAL(dest) + size; } if (error == BZ_STREAM_END || error == BZ_OK) { - size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32; -#ifndef ZEND_ENABLE_ZVAL_LONG64 + size = (((uint64_t) bzs.total_out_hi32) << 32U) + bzs.total_out_lo32; if (UNEXPECTED(size > SIZE_MAX)) { php_error_docref(NULL, E_WARNING, "Decompressed size too big, max is %zd", SIZE_MAX); zend_string_efree(dest); RETVAL_LONG(BZ_MEM_ERROR); - } else -#endif - { + } else { dest = zend_string_safe_realloc(dest, 1, (size_t)size, 1, 0); ZSTR_LEN(dest) = (size_t)size; ZSTR_VAL(dest)[(size_t)size] = '\0'; diff '--color=auto' -Naur php-8.4.18/ext/bz2/tests/gh20620.phpt php-8.4.20RC1/ext/bz2/tests/gh20620.phpt --- php-8.4.18/ext/bz2/tests/gh20620.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/bz2/tests/gh20620.phpt 2026-04-01 04:35:35.992272473 +0000 @@ -4,6 +4,7 @@ bz2 --SKIPIF-- diff '--color=auto' -Naur php-8.4.18/ext/bz2/tests/gh20807.phpt php-8.4.20RC1/ext/bz2/tests/gh20807.phpt --- php-8.4.18/ext/bz2/tests/gh20807.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/bz2/tests/gh20807.phpt 2026-04-01 04:35:35.992361431 +0000 @@ -0,0 +1,21 @@ +--TEST-- +Truncation of total output size causing erroneous size and data +--EXTENSIONS-- +bz2 +--INI-- +memory_limit=-1 +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(40) "d4b5e52ed34a774fa645f94369b0c61375436d30" diff '--color=auto' -Naur php-8.4.18/ext/curl/interface.c php-8.4.20RC1/ext/curl/interface.c --- php-8.4.18/ext/curl/interface.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/curl/interface.c 2026-04-01 04:35:35.992524208 +0000 @@ -583,7 +583,7 @@ return fwrite(data, size, nmemb, write_handler->fp); case PHP_CURL_RETURN: if (length > 0) { - smart_str_appendl(&write_handler->buf, data, (int) length); + smart_str_appendl(&write_handler->buf, data, length); } break; case PHP_CURL_USER: { @@ -621,6 +621,10 @@ zval argv[3]; zval retval; + if (!ZEND_FCC_INITIALIZED(ch->handlers.fnmatch)) { + return rval; + } + GC_ADDREF(&ch->std); ZVAL_OBJ(&argv[0], &ch->std); ZVAL_STRING(&argv[1], pattern); @@ -652,6 +656,9 @@ fprintf(stderr, "curl_progress() called\n"); fprintf(stderr, "clientp = %x, dltotal = %f, dlnow = %f, ultotal = %f, ulnow = %f\n", clientp, dltotal, dlnow, ultotal, ulnow); #endif + if (!ZEND_FCC_INITIALIZED(ch->handlers.progress)) { + return rval; + } zval args[5]; zval retval; @@ -690,6 +697,9 @@ fprintf(stderr, "curl_xferinfo() called\n"); fprintf(stderr, "clientp = %x, dltotal = %ld, dlnow = %ld, ultotal = %ld, ulnow = %ld\n", clientp, dltotal, dlnow, ultotal, ulnow); #endif + if (!ZEND_FCC_INITIALIZED(ch->handlers.xferinfo)) { + return rval; + } zval argv[5]; zval retval; @@ -850,7 +860,7 @@ if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); if (Z_TYPE(retval) == IS_STRING) { - length = MIN((size * nmemb), Z_STRLEN(retval)); + length = MIN(size * nmemb, Z_STRLEN(retval)); memcpy(data, Z_STRVAL(retval), length); } else if (Z_TYPE(retval) == IS_LONG) { length = Z_LVAL_P(&retval); @@ -881,7 +891,7 @@ /* Handle special case write when we're returning the entire transfer */ if (ch->handlers.write->method == PHP_CURL_RETURN && length > 0) { - smart_str_appendl(&ch->handlers.write->buf, data, (int) length); + smart_str_appendl(&ch->handlers.write->buf, data, length); } else { PHPWRITE(data, length); } diff '--color=auto' -Naur php-8.4.18/ext/curl/tests/gh21023.phpt php-8.4.20RC1/ext/curl/tests/gh21023.phpt --- php-8.4.18/ext/curl/tests/gh21023.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/curl/tests/gh21023.phpt 2026-04-01 04:35:35.992737241 +0000 @@ -0,0 +1,27 @@ +--TEST-- +GH-21023 (crash with CURLOPT_XFERINFOFUNCTION set with an invalid callback) +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +OK diff '--color=auto' -Naur php-8.4.18/ext/date/lib/timezonedb.h php-8.4.20RC1/ext/date/lib/timezonedb.h --- php-8.4.18/ext/date/lib/timezonedb.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/date/lib/timezonedb.h 2026-04-01 04:35:36.001936172 +0000 @@ -323,290 +323,290 @@ { (char*) "Asia/Taipei" , 0x02DF83 }, { (char*) "Asia/Tashkent" , 0x02E18E }, { (char*) "Asia/Tbilisi" , 0x02E319 }, - { (char*) "Asia/Tehran" , 0x02E59A }, - { (char*) "Asia/Tel_Aviv" , 0x02E8D2 }, - { (char*) "Asia/Thimbu" , 0x02ED10 }, - { (char*) "Asia/Thimphu" , 0x02EDB6 }, - { (char*) "Asia/Tokyo" , 0x02EE5C }, - { (char*) "Asia/Tomsk" , 0x02EF3D }, - { (char*) "Asia/Ujung_Pandang" , 0x02F248 }, - { (char*) "Asia/Ulaanbaatar" , 0x02F312 }, - { (char*) "Asia/Ulan_Bator" , 0x02F580 }, - { (char*) "Asia/Urumqi" , 0x02F7DE }, - { (char*) "Asia/Ust-Nera" , 0x02F87C }, - { (char*) "Asia/Vientiane" , 0x02FB9F }, - { (char*) "Asia/Vladivostok" , 0x02FC85 }, - { (char*) "Asia/Yakutsk" , 0x02FF8A }, - { (char*) "Asia/Yangon" , 0x03028E }, - { (char*) "Asia/Yekaterinburg" , 0x030355 }, - { (char*) "Asia/Yerevan" , 0x030667 }, - { (char*) "Atlantic/Azores" , 0x030937 }, - { (char*) "Atlantic/Bermuda" , 0x030EC2 }, - { (char*) "Atlantic/Canary" , 0x0312CE }, - { (char*) "Atlantic/Cape_Verde" , 0x0314C6 }, - { (char*) "Atlantic/Faeroe" , 0x031581 }, - { (char*) "Atlantic/Faroe" , 0x031746 }, - { (char*) "Atlantic/Jan_Mayen" , 0x03190B }, - { (char*) "Atlantic/Madeira" , 0x031BD8 }, - { (char*) "Atlantic/Reykjavik" , 0x03214F }, - { (char*) "Atlantic/South_Georgia" , 0x03244C }, - { (char*) "Atlantic/St_Helena" , 0x0324DC }, - { (char*) "Atlantic/Stanley" , 0x03257D }, - { (char*) "Australia/ACT" , 0x03289E }, - { (char*) "Australia/Adelaide" , 0x032C32 }, - { (char*) "Australia/Brisbane" , 0x032FE6 }, - { (char*) "Australia/Broken_Hill" , 0x03312A }, - { (char*) "Australia/Canberra" , 0x0334FF }, - { (char*) "Australia/Currie" , 0x033893 }, - { (char*) "Australia/Darwin" , 0x033C8A }, - { (char*) "Australia/Eucla" , 0x033D92 }, - { (char*) "Australia/Hobart" , 0x033EF1 }, - { (char*) "Australia/LHI" , 0x0342F0 }, - { (char*) "Australia/Lindeman" , 0x0345B0 }, - { (char*) "Australia/Lord_Howe" , 0x034720 }, - { (char*) "Australia/Melbourne" , 0x0349F0 }, - { (char*) "Australia/North" , 0x034D8C }, - { (char*) "Australia/NSW" , 0x034E82 }, - { (char*) "Australia/Perth" , 0x035216 }, - { (char*) "Australia/Queensland" , 0x035372 }, - { (char*) "Australia/South" , 0x03549F }, - { (char*) "Australia/Sydney" , 0x035844 }, - { (char*) "Australia/Tasmania" , 0x035BF4 }, - { (char*) "Australia/Victoria" , 0x035FEB }, - { (char*) "Australia/West" , 0x03637F }, - { (char*) "Australia/Yancowinna" , 0x0364BD }, - { (char*) "Brazil/Acre" , 0x036876 }, - { (char*) "Brazil/DeNoronha" , 0x036A24 }, - { (char*) "Brazil/East" , 0x036C14 }, - { (char*) "Brazil/West" , 0x036FD8 }, - { (char*) "Canada/Atlantic" , 0x037180 }, - { (char*) "Canada/Central" , 0x037814 }, - { (char*) "Canada/Eastern" , 0x037D2E }, - { (char*) "Canada/Mountain" , 0x0383EF }, - { (char*) "Canada/Newfoundland" , 0x0387C5 }, - { (char*) "Canada/Pacific" , 0x038F27 }, - { (char*) "Canada/Saskatchewan" , 0x039465 }, - { (char*) "Canada/Yukon" , 0x0396EF }, - { (char*) "CET" , 0x039B00 }, - { (char*) "Chile/Continental" , 0x039F5B }, - { (char*) "Chile/EasterIsland" , 0x03A4B1 }, - { (char*) "CST6CDT" , 0x03A953 }, - { (char*) "Cuba" , 0x03B039 }, - { (char*) "EET" , 0x03B4A2 }, - { (char*) "Egypt" , 0x03B758 }, - { (char*) "Eire" , 0x03BC81 }, - { (char*) "EST" , 0x03C265 }, - { (char*) "EST5EDT" , 0x03C306 }, - { (char*) "Etc/GMT" , 0x03C9E2 }, - { (char*) "Etc/GMT+0" , 0x03CA5D }, - { (char*) "Etc/GMT+1" , 0x03CAD8 }, - { (char*) "Etc/GMT+10" , 0x03CB55 }, - { (char*) "Etc/GMT+11" , 0x03CBD3 }, - { (char*) "Etc/GMT+12" , 0x03CC51 }, - { (char*) "Etc/GMT+2" , 0x03CCCF }, - { (char*) "Etc/GMT+3" , 0x03CD4C }, - { (char*) "Etc/GMT+4" , 0x03CDC9 }, - { (char*) "Etc/GMT+5" , 0x03CE46 }, - { (char*) "Etc/GMT+6" , 0x03CEC3 }, - { (char*) "Etc/GMT+7" , 0x03CF40 }, - { (char*) "Etc/GMT+8" , 0x03CFBD }, - { (char*) "Etc/GMT+9" , 0x03D03A }, - { (char*) "Etc/GMT-0" , 0x03D0B7 }, - { (char*) "Etc/GMT-1" , 0x03D132 }, - { (char*) "Etc/GMT-10" , 0x03D1B0 }, - { (char*) "Etc/GMT-11" , 0x03D22F }, - { (char*) "Etc/GMT-12" , 0x03D2AE }, - { (char*) "Etc/GMT-13" , 0x03D32D }, - { (char*) "Etc/GMT-14" , 0x03D3AC }, - { (char*) "Etc/GMT-2" , 0x03D42B }, - { (char*) "Etc/GMT-3" , 0x03D4A9 }, - { (char*) "Etc/GMT-4" , 0x03D527 }, - { (char*) "Etc/GMT-5" , 0x03D5A5 }, - { (char*) "Etc/GMT-6" , 0x03D623 }, - { (char*) "Etc/GMT-7" , 0x03D6A1 }, - { (char*) "Etc/GMT-8" , 0x03D71F }, - { (char*) "Etc/GMT-9" , 0x03D79D }, - { (char*) "Etc/GMT0" , 0x03D81B }, - { (char*) "Etc/Greenwich" , 0x03D896 }, - { (char*) "Etc/UCT" , 0x03D911 }, - { (char*) "Etc/Universal" , 0x03D98C }, - { (char*) "Etc/UTC" , 0x03DA07 }, - { (char*) "Etc/Zulu" , 0x03DA82 }, - { (char*) "Europe/Amsterdam" , 0x03DAFD }, - { (char*) "Europe/Andorra" , 0x03DF38 }, - { (char*) "Europe/Astrakhan" , 0x03E0C9 }, - { (char*) "Europe/Athens" , 0x03E3BD }, - { (char*) "Europe/Belfast" , 0x03E673 }, - { (char*) "Europe/Belgrade" , 0x03ECBE }, - { (char*) "Europe/Berlin" , 0x03EEA8 }, - { (char*) "Europe/Bratislava" , 0x03F184 }, - { (char*) "Europe/Brussels" , 0x03F463 }, - { (char*) "Europe/Bucharest" , 0x03F8BE }, - { (char*) "Europe/Budapest" , 0x03FB5F }, - { (char*) "Europe/Busingen" , 0x03FE69 }, - { (char*) "Europe/Chisinau" , 0x04006E }, - { (char*) "Europe/Copenhagen" , 0x04036D }, - { (char*) "Europe/Dublin" , 0x0405E8 }, - { (char*) "Europe/Gibraltar" , 0x040BCC }, - { (char*) "Europe/Guernsey" , 0x04109C }, - { (char*) "Europe/Helsinki" , 0x0416F3 }, - { (char*) "Europe/Isle_of_Man" , 0x0418E0 }, - { (char*) "Europe/Istanbul" , 0x041F2B }, - { (char*) "Europe/Jersey" , 0x0423E7 }, - { (char*) "Europe/Kaliningrad" , 0x042A3E }, - { (char*) "Europe/Kiev" , 0x042DE6 }, - { (char*) "Europe/Kirov" , 0x043020 }, - { (char*) "Europe/Kyiv" , 0x043319 }, - { (char*) "Europe/Lisbon" , 0x043562 }, - { (char*) "Europe/Ljubljana" , 0x043B38 }, - { (char*) "Europe/London" , 0x043D22 }, - { (char*) "Europe/Luxembourg" , 0x04436D }, - { (char*) "Europe/Madrid" , 0x0447B8 }, - { (char*) "Europe/Malta" , 0x044B55 }, - { (char*) "Europe/Mariehamn" , 0x044F01 }, - { (char*) "Europe/Minsk" , 0x0450EE }, - { (char*) "Europe/Monaco" , 0x045422 }, - { (char*) "Europe/Moscow" , 0x045888 }, - { (char*) "Europe/Nicosia" , 0x045C34 }, - { (char*) "Europe/Oslo" , 0x045E95 }, - { (char*) "Europe/Paris" , 0x046145 }, - { (char*) "Europe/Podgorica" , 0x0465A2 }, - { (char*) "Europe/Prague" , 0x04678C }, - { (char*) "Europe/Riga" , 0x046A6B }, - { (char*) "Europe/Rome" , 0x046D2D }, - { (char*) "Europe/Samara" , 0x0470EC }, - { (char*) "Europe/San_Marino" , 0x0473ED }, - { (char*) "Europe/Sarajevo" , 0x0477AC }, - { (char*) "Europe/Saratov" , 0x047996 }, - { (char*) "Europe/Simferopol" , 0x047C88 }, - { (char*) "Europe/Skopje" , 0x047FFB }, - { (char*) "Europe/Sofia" , 0x0481E5 }, - { (char*) "Europe/Stockholm" , 0x048441 }, - { (char*) "Europe/Tallinn" , 0x04863E }, - { (char*) "Europe/Tirane" , 0x0488ED }, - { (char*) "Europe/Tiraspol" , 0x048B55 }, - { (char*) "Europe/Ulyanovsk" , 0x048E54 }, - { (char*) "Europe/Uzhgorod" , 0x04916A }, - { (char*) "Europe/Vaduz" , 0x0493A4 }, - { (char*) "Europe/Vatican" , 0x04958E }, - { (char*) "Europe/Vienna" , 0x04994D }, - { (char*) "Europe/Vilnius" , 0x049BEB }, - { (char*) "Europe/Volgograd" , 0x049E9B }, - { (char*) "Europe/Warsaw" , 0x04A1AA }, - { (char*) "Europe/Zagreb" , 0x04A551 }, - { (char*) "Europe/Zaporozhye" , 0x04A73B }, - { (char*) "Europe/Zurich" , 0x04A975 }, - { (char*) "Factory" , 0x04AB72 }, - { (char*) "GB" , 0x04ABEF }, - { (char*) "GB-Eire" , 0x04B23A }, - { (char*) "GMT" , 0x04B885 }, - { (char*) "GMT+0" , 0x04B900 }, - { (char*) "GMT-0" , 0x04B97B }, - { (char*) "GMT0" , 0x04B9F6 }, - { (char*) "Greenwich" , 0x04BA71 }, - { (char*) "Hongkong" , 0x04BAEC }, - { (char*) "HST" , 0x04BDFF }, - { (char*) "Iceland" , 0x04BEE8 }, - { (char*) "Indian/Antananarivo" , 0x04BF76 }, - { (char*) "Indian/Chagos" , 0x04C022 }, - { (char*) "Indian/Christmas" , 0x04C0C6 }, - { (char*) "Indian/Cocos" , 0x04C157 }, - { (char*) "Indian/Comoro" , 0x04C1EF }, - { (char*) "Indian/Kerguelen" , 0x04C27E }, - { (char*) "Indian/Mahe" , 0x04C30F }, - { (char*) "Indian/Maldives" , 0x04C3A0 }, - { (char*) "Indian/Mauritius" , 0x04C444 }, - { (char*) "Indian/Mayotte" , 0x04C503 }, - { (char*) "Indian/Reunion" , 0x04C592 }, - { (char*) "Iran" , 0x04C623 }, - { (char*) "Israel" , 0x04C95B }, - { (char*) "Jamaica" , 0x04CD99 }, - { (char*) "Japan" , 0x04CEF8 }, - { (char*) "Kwajalein" , 0x04CFD9 }, - { (char*) "Libya" , 0x04D0C0 }, - { (char*) "MET" , 0x04D27B }, - { (char*) "Mexico/BajaNorte" , 0x04D6D6 }, - { (char*) "Mexico/BajaSur" , 0x04DC39 }, - { (char*) "Mexico/General" , 0x04DEF7 }, - { (char*) "MST" , 0x04E208 }, - { (char*) "MST7MDT" , 0x04E304 }, - { (char*) "Navajo" , 0x04E722 }, - { (char*) "NZ" , 0x04EB40 }, - { (char*) "NZ-CHAT" , 0x04EF5F }, - { (char*) "Pacific/Apia" , 0x04F293 }, - { (char*) "Pacific/Auckland" , 0x04F436 }, - { (char*) "Pacific/Bougainville" , 0x04F868 }, - { (char*) "Pacific/Chatham" , 0x04F949 }, - { (char*) "Pacific/Chuuk" , 0x04FC8C }, - { (char*) "Pacific/Easter" , 0x04FD6A }, - { (char*) "Pacific/Efate" , 0x050219 }, - { (char*) "Pacific/Enderbury" , 0x05037B }, - { (char*) "Pacific/Fakaofo" , 0x050433 }, - { (char*) "Pacific/Fiji" , 0x0504D8 }, - { (char*) "Pacific/Funafuti" , 0x050670 }, - { (char*) "Pacific/Galapagos" , 0x050702 }, - { (char*) "Pacific/Gambier" , 0x0507CE }, - { (char*) "Pacific/Guadalcanal" , 0x05086D }, - { (char*) "Pacific/Guam" , 0x0508FF }, - { (char*) "Pacific/Honolulu" , 0x050A69 }, - { (char*) "Pacific/Johnston" , 0x050B58 }, - { (char*) "Pacific/Kanton" , 0x050C41 }, - { (char*) "Pacific/Kiritimati" , 0x050D08 }, - { (char*) "Pacific/Kosrae" , 0x050DCE }, - { (char*) "Pacific/Kwajalein" , 0x050ED2 }, - { (char*) "Pacific/Majuro" , 0x050FC2 }, - { (char*) "Pacific/Marquesas" , 0x0510C0 }, - { (char*) "Pacific/Midway" , 0x051168 }, - { (char*) "Pacific/Nauru" , 0x05122B }, - { (char*) "Pacific/Niue" , 0x0512EE }, - { (char*) "Pacific/Norfolk" , 0x051394 }, - { (char*) "Pacific/Noumea" , 0x05148D }, - { (char*) "Pacific/Pago_Pago" , 0x05155F }, - { (char*) "Pacific/Palau" , 0x0515FD }, - { (char*) "Pacific/Pitcairn" , 0x05169D }, - { (char*) "Pacific/Pohnpei" , 0x051742 }, - { (char*) "Pacific/Ponape" , 0x051832 }, - { (char*) "Pacific/Port_Moresby" , 0x0518C4 }, - { (char*) "Pacific/Rarotonga" , 0x051982 }, - { (char*) "Pacific/Saipan" , 0x051B24 }, - { (char*) "Pacific/Samoa" , 0x051C85 }, - { (char*) "Pacific/Tahiti" , 0x051D23 }, - { (char*) "Pacific/Tarawa" , 0x051DC3 }, - { (char*) "Pacific/Tongatapu" , 0x051E64 }, - { (char*) "Pacific/Truk" , 0x051F5D }, - { (char*) "Pacific/Wake" , 0x052003 }, - { (char*) "Pacific/Wallis" , 0x0520A0 }, - { (char*) "Pacific/Yap" , 0x052132 }, - { (char*) "Poland" , 0x0521D8 }, - { (char*) "Portugal" , 0x05257F }, - { (char*) "PRC" , 0x052B42 }, - { (char*) "PST8PDT" , 0x052CD7 }, - { (char*) "ROC" , 0x0531F1 }, - { (char*) "ROK" , 0x0533FC }, - { (char*) "Singapore" , 0x0535A7 }, - { (char*) "Turkey" , 0x0536B3 }, - { (char*) "UCT" , 0x053B6F }, - { (char*) "Universal" , 0x053BEA }, - { (char*) "US/Alaska" , 0x053C65 }, - { (char*) "US/Aleutian" , 0x054042 }, - { (char*) "US/Arizona" , 0x054417 }, - { (char*) "US/Central" , 0x054513 }, - { (char*) "US/East-Indiana" , 0x054BF9 }, - { (char*) "US/Eastern" , 0x054E18 }, - { (char*) "US/Hawaii" , 0x0554F4 }, - { (char*) "US/Indiana-Starke" , 0x0555DD }, - { (char*) "US/Michigan" , 0x0559E1 }, - { (char*) "US/Mountain" , 0x055D70 }, - { (char*) "US/Pacific" , 0x05618E }, - { (char*) "US/Samoa" , 0x0566A8 }, - { (char*) "UTC" , 0x056746 }, - { (char*) "W-SU" , 0x0567C1 }, - { (char*) "WET" , 0x056B59 }, - { (char*) "Zulu" , 0x05711C }, + { (char*) "Asia/Tehran" , 0x02E591 }, + { (char*) "Asia/Tel_Aviv" , 0x02E8C9 }, + { (char*) "Asia/Thimbu" , 0x02ED07 }, + { (char*) "Asia/Thimphu" , 0x02EDAD }, + { (char*) "Asia/Tokyo" , 0x02EE53 }, + { (char*) "Asia/Tomsk" , 0x02EF34 }, + { (char*) "Asia/Ujung_Pandang" , 0x02F23F }, + { (char*) "Asia/Ulaanbaatar" , 0x02F309 }, + { (char*) "Asia/Ulan_Bator" , 0x02F577 }, + { (char*) "Asia/Urumqi" , 0x02F7D5 }, + { (char*) "Asia/Ust-Nera" , 0x02F873 }, + { (char*) "Asia/Vientiane" , 0x02FB96 }, + { (char*) "Asia/Vladivostok" , 0x02FC7C }, + { (char*) "Asia/Yakutsk" , 0x02FF81 }, + { (char*) "Asia/Yangon" , 0x030285 }, + { (char*) "Asia/Yekaterinburg" , 0x03034C }, + { (char*) "Asia/Yerevan" , 0x03065E }, + { (char*) "Atlantic/Azores" , 0x03092E }, + { (char*) "Atlantic/Bermuda" , 0x030EB9 }, + { (char*) "Atlantic/Canary" , 0x0312C5 }, + { (char*) "Atlantic/Cape_Verde" , 0x0314BD }, + { (char*) "Atlantic/Faeroe" , 0x031578 }, + { (char*) "Atlantic/Faroe" , 0x03173D }, + { (char*) "Atlantic/Jan_Mayen" , 0x031902 }, + { (char*) "Atlantic/Madeira" , 0x031BCF }, + { (char*) "Atlantic/Reykjavik" , 0x032146 }, + { (char*) "Atlantic/South_Georgia" , 0x032443 }, + { (char*) "Atlantic/St_Helena" , 0x0324D3 }, + { (char*) "Atlantic/Stanley" , 0x032574 }, + { (char*) "Australia/ACT" , 0x032895 }, + { (char*) "Australia/Adelaide" , 0x032C29 }, + { (char*) "Australia/Brisbane" , 0x032FDD }, + { (char*) "Australia/Broken_Hill" , 0x033121 }, + { (char*) "Australia/Canberra" , 0x0334F6 }, + { (char*) "Australia/Currie" , 0x03388A }, + { (char*) "Australia/Darwin" , 0x033C81 }, + { (char*) "Australia/Eucla" , 0x033D89 }, + { (char*) "Australia/Hobart" , 0x033EE8 }, + { (char*) "Australia/LHI" , 0x0342E7 }, + { (char*) "Australia/Lindeman" , 0x0345A7 }, + { (char*) "Australia/Lord_Howe" , 0x034717 }, + { (char*) "Australia/Melbourne" , 0x0349E7 }, + { (char*) "Australia/North" , 0x034D83 }, + { (char*) "Australia/NSW" , 0x034E79 }, + { (char*) "Australia/Perth" , 0x03520D }, + { (char*) "Australia/Queensland" , 0x035369 }, + { (char*) "Australia/South" , 0x035496 }, + { (char*) "Australia/Sydney" , 0x03583B }, + { (char*) "Australia/Tasmania" , 0x035BEB }, + { (char*) "Australia/Victoria" , 0x035FE2 }, + { (char*) "Australia/West" , 0x036376 }, + { (char*) "Australia/Yancowinna" , 0x0364B4 }, + { (char*) "Brazil/Acre" , 0x03686D }, + { (char*) "Brazil/DeNoronha" , 0x036A1B }, + { (char*) "Brazil/East" , 0x036C0B }, + { (char*) "Brazil/West" , 0x036FCF }, + { (char*) "Canada/Atlantic" , 0x037177 }, + { (char*) "Canada/Central" , 0x03780B }, + { (char*) "Canada/Eastern" , 0x037D25 }, + { (char*) "Canada/Mountain" , 0x0383E6 }, + { (char*) "Canada/Newfoundland" , 0x0387BC }, + { (char*) "Canada/Pacific" , 0x038F1E }, + { (char*) "Canada/Saskatchewan" , 0x03945C }, + { (char*) "Canada/Yukon" , 0x0396E6 }, + { (char*) "CET" , 0x039AF7 }, + { (char*) "Chile/Continental" , 0x039F52 }, + { (char*) "Chile/EasterIsland" , 0x03A4A8 }, + { (char*) "CST6CDT" , 0x03A94A }, + { (char*) "Cuba" , 0x03B030 }, + { (char*) "EET" , 0x03B499 }, + { (char*) "Egypt" , 0x03B74F }, + { (char*) "Eire" , 0x03BC78 }, + { (char*) "EST" , 0x03C25C }, + { (char*) "EST5EDT" , 0x03C2FD }, + { (char*) "Etc/GMT" , 0x03C9D9 }, + { (char*) "Etc/GMT+0" , 0x03CA54 }, + { (char*) "Etc/GMT+1" , 0x03CACF }, + { (char*) "Etc/GMT+10" , 0x03CB4C }, + { (char*) "Etc/GMT+11" , 0x03CBCA }, + { (char*) "Etc/GMT+12" , 0x03CC48 }, + { (char*) "Etc/GMT+2" , 0x03CCC6 }, + { (char*) "Etc/GMT+3" , 0x03CD43 }, + { (char*) "Etc/GMT+4" , 0x03CDC0 }, + { (char*) "Etc/GMT+5" , 0x03CE3D }, + { (char*) "Etc/GMT+6" , 0x03CEBA }, + { (char*) "Etc/GMT+7" , 0x03CF37 }, + { (char*) "Etc/GMT+8" , 0x03CFB4 }, + { (char*) "Etc/GMT+9" , 0x03D031 }, + { (char*) "Etc/GMT-0" , 0x03D0AE }, + { (char*) "Etc/GMT-1" , 0x03D129 }, + { (char*) "Etc/GMT-10" , 0x03D1A7 }, + { (char*) "Etc/GMT-11" , 0x03D226 }, + { (char*) "Etc/GMT-12" , 0x03D2A5 }, + { (char*) "Etc/GMT-13" , 0x03D324 }, + { (char*) "Etc/GMT-14" , 0x03D3A3 }, + { (char*) "Etc/GMT-2" , 0x03D422 }, + { (char*) "Etc/GMT-3" , 0x03D4A0 }, + { (char*) "Etc/GMT-4" , 0x03D51E }, + { (char*) "Etc/GMT-5" , 0x03D59C }, + { (char*) "Etc/GMT-6" , 0x03D61A }, + { (char*) "Etc/GMT-7" , 0x03D698 }, + { (char*) "Etc/GMT-8" , 0x03D716 }, + { (char*) "Etc/GMT-9" , 0x03D794 }, + { (char*) "Etc/GMT0" , 0x03D812 }, + { (char*) "Etc/Greenwich" , 0x03D88D }, + { (char*) "Etc/UCT" , 0x03D908 }, + { (char*) "Etc/Universal" , 0x03D983 }, + { (char*) "Etc/UTC" , 0x03D9FE }, + { (char*) "Etc/Zulu" , 0x03DA79 }, + { (char*) "Europe/Amsterdam" , 0x03DAF4 }, + { (char*) "Europe/Andorra" , 0x03DF2F }, + { (char*) "Europe/Astrakhan" , 0x03E0C0 }, + { (char*) "Europe/Athens" , 0x03E3B4 }, + { (char*) "Europe/Belfast" , 0x03E66A }, + { (char*) "Europe/Belgrade" , 0x03ECB5 }, + { (char*) "Europe/Berlin" , 0x03EE9F }, + { (char*) "Europe/Bratislava" , 0x03F17B }, + { (char*) "Europe/Brussels" , 0x03F45A }, + { (char*) "Europe/Bucharest" , 0x03F8B5 }, + { (char*) "Europe/Budapest" , 0x03FB56 }, + { (char*) "Europe/Busingen" , 0x03FE60 }, + { (char*) "Europe/Chisinau" , 0x040065 }, + { (char*) "Europe/Copenhagen" , 0x040528 }, + { (char*) "Europe/Dublin" , 0x0407A3 }, + { (char*) "Europe/Gibraltar" , 0x040D87 }, + { (char*) "Europe/Guernsey" , 0x041257 }, + { (char*) "Europe/Helsinki" , 0x0418AE }, + { (char*) "Europe/Isle_of_Man" , 0x041A9B }, + { (char*) "Europe/Istanbul" , 0x0420E6 }, + { (char*) "Europe/Jersey" , 0x0425A2 }, + { (char*) "Europe/Kaliningrad" , 0x042BF9 }, + { (char*) "Europe/Kiev" , 0x042FA1 }, + { (char*) "Europe/Kirov" , 0x0431DB }, + { (char*) "Europe/Kyiv" , 0x0434D4 }, + { (char*) "Europe/Lisbon" , 0x04371D }, + { (char*) "Europe/Ljubljana" , 0x043CF3 }, + { (char*) "Europe/London" , 0x043EDD }, + { (char*) "Europe/Luxembourg" , 0x044528 }, + { (char*) "Europe/Madrid" , 0x044973 }, + { (char*) "Europe/Malta" , 0x044D10 }, + { (char*) "Europe/Mariehamn" , 0x0450BC }, + { (char*) "Europe/Minsk" , 0x0452A9 }, + { (char*) "Europe/Monaco" , 0x0455DD }, + { (char*) "Europe/Moscow" , 0x045A43 }, + { (char*) "Europe/Nicosia" , 0x045DEF }, + { (char*) "Europe/Oslo" , 0x046050 }, + { (char*) "Europe/Paris" , 0x046300 }, + { (char*) "Europe/Podgorica" , 0x04675D }, + { (char*) "Europe/Prague" , 0x046947 }, + { (char*) "Europe/Riga" , 0x046C26 }, + { (char*) "Europe/Rome" , 0x046EE8 }, + { (char*) "Europe/Samara" , 0x0472A7 }, + { (char*) "Europe/San_Marino" , 0x0475A8 }, + { (char*) "Europe/Sarajevo" , 0x047967 }, + { (char*) "Europe/Saratov" , 0x047B51 }, + { (char*) "Europe/Simferopol" , 0x047E43 }, + { (char*) "Europe/Skopje" , 0x0481B6 }, + { (char*) "Europe/Sofia" , 0x0483A0 }, + { (char*) "Europe/Stockholm" , 0x0485FC }, + { (char*) "Europe/Tallinn" , 0x0487F9 }, + { (char*) "Europe/Tirane" , 0x048AA8 }, + { (char*) "Europe/Tiraspol" , 0x048D10 }, + { (char*) "Europe/Ulyanovsk" , 0x0491D3 }, + { (char*) "Europe/Uzhgorod" , 0x0494E9 }, + { (char*) "Europe/Vaduz" , 0x049723 }, + { (char*) "Europe/Vatican" , 0x04990D }, + { (char*) "Europe/Vienna" , 0x049CCC }, + { (char*) "Europe/Vilnius" , 0x049F6A }, + { (char*) "Europe/Volgograd" , 0x04A21A }, + { (char*) "Europe/Warsaw" , 0x04A529 }, + { (char*) "Europe/Zagreb" , 0x04A8D0 }, + { (char*) "Europe/Zaporozhye" , 0x04AABA }, + { (char*) "Europe/Zurich" , 0x04ACF4 }, + { (char*) "Factory" , 0x04AEF1 }, + { (char*) "GB" , 0x04AF6E }, + { (char*) "GB-Eire" , 0x04B5B9 }, + { (char*) "GMT" , 0x04BC04 }, + { (char*) "GMT+0" , 0x04BC7F }, + { (char*) "GMT-0" , 0x04BCFA }, + { (char*) "GMT0" , 0x04BD75 }, + { (char*) "Greenwich" , 0x04BDF0 }, + { (char*) "Hongkong" , 0x04BE6B }, + { (char*) "HST" , 0x04C17E }, + { (char*) "Iceland" , 0x04C267 }, + { (char*) "Indian/Antananarivo" , 0x04C2F5 }, + { (char*) "Indian/Chagos" , 0x04C3A1 }, + { (char*) "Indian/Christmas" , 0x04C445 }, + { (char*) "Indian/Cocos" , 0x04C4D6 }, + { (char*) "Indian/Comoro" , 0x04C56E }, + { (char*) "Indian/Kerguelen" , 0x04C5FD }, + { (char*) "Indian/Mahe" , 0x04C68E }, + { (char*) "Indian/Maldives" , 0x04C71F }, + { (char*) "Indian/Mauritius" , 0x04C7C3 }, + { (char*) "Indian/Mayotte" , 0x04C882 }, + { (char*) "Indian/Reunion" , 0x04C911 }, + { (char*) "Iran" , 0x04C9A2 }, + { (char*) "Israel" , 0x04CCDA }, + { (char*) "Jamaica" , 0x04D118 }, + { (char*) "Japan" , 0x04D277 }, + { (char*) "Kwajalein" , 0x04D358 }, + { (char*) "Libya" , 0x04D43F }, + { (char*) "MET" , 0x04D5FA }, + { (char*) "Mexico/BajaNorte" , 0x04DA55 }, + { (char*) "Mexico/BajaSur" , 0x04DFB8 }, + { (char*) "Mexico/General" , 0x04E276 }, + { (char*) "MST" , 0x04E587 }, + { (char*) "MST7MDT" , 0x04E683 }, + { (char*) "Navajo" , 0x04EAA1 }, + { (char*) "NZ" , 0x04EEBF }, + { (char*) "NZ-CHAT" , 0x04F2DE }, + { (char*) "Pacific/Apia" , 0x04F612 }, + { (char*) "Pacific/Auckland" , 0x04F7B5 }, + { (char*) "Pacific/Bougainville" , 0x04FBE7 }, + { (char*) "Pacific/Chatham" , 0x04FCC8 }, + { (char*) "Pacific/Chuuk" , 0x05000B }, + { (char*) "Pacific/Easter" , 0x0500E9 }, + { (char*) "Pacific/Efate" , 0x050598 }, + { (char*) "Pacific/Enderbury" , 0x0506FA }, + { (char*) "Pacific/Fakaofo" , 0x0507B2 }, + { (char*) "Pacific/Fiji" , 0x050857 }, + { (char*) "Pacific/Funafuti" , 0x0509EF }, + { (char*) "Pacific/Galapagos" , 0x050A81 }, + { (char*) "Pacific/Gambier" , 0x050B4D }, + { (char*) "Pacific/Guadalcanal" , 0x050BEC }, + { (char*) "Pacific/Guam" , 0x050C7E }, + { (char*) "Pacific/Honolulu" , 0x050DE8 }, + { (char*) "Pacific/Johnston" , 0x050ED7 }, + { (char*) "Pacific/Kanton" , 0x050FC0 }, + { (char*) "Pacific/Kiritimati" , 0x051087 }, + { (char*) "Pacific/Kosrae" , 0x05114D }, + { (char*) "Pacific/Kwajalein" , 0x051251 }, + { (char*) "Pacific/Majuro" , 0x051341 }, + { (char*) "Pacific/Marquesas" , 0x05143F }, + { (char*) "Pacific/Midway" , 0x0514E7 }, + { (char*) "Pacific/Nauru" , 0x0515AA }, + { (char*) "Pacific/Niue" , 0x05166D }, + { (char*) "Pacific/Norfolk" , 0x051713 }, + { (char*) "Pacific/Noumea" , 0x05180C }, + { (char*) "Pacific/Pago_Pago" , 0x0518DE }, + { (char*) "Pacific/Palau" , 0x05197C }, + { (char*) "Pacific/Pitcairn" , 0x051A1C }, + { (char*) "Pacific/Pohnpei" , 0x051AC1 }, + { (char*) "Pacific/Ponape" , 0x051BB1 }, + { (char*) "Pacific/Port_Moresby" , 0x051C43 }, + { (char*) "Pacific/Rarotonga" , 0x051D01 }, + { (char*) "Pacific/Saipan" , 0x051EA3 }, + { (char*) "Pacific/Samoa" , 0x052004 }, + { (char*) "Pacific/Tahiti" , 0x0520A2 }, + { (char*) "Pacific/Tarawa" , 0x052142 }, + { (char*) "Pacific/Tongatapu" , 0x0521E3 }, + { (char*) "Pacific/Truk" , 0x0522DC }, + { (char*) "Pacific/Wake" , 0x052382 }, + { (char*) "Pacific/Wallis" , 0x05241F }, + { (char*) "Pacific/Yap" , 0x0524B1 }, + { (char*) "Poland" , 0x052557 }, + { (char*) "Portugal" , 0x0528FE }, + { (char*) "PRC" , 0x052EC1 }, + { (char*) "PST8PDT" , 0x053056 }, + { (char*) "ROC" , 0x053570 }, + { (char*) "ROK" , 0x05377B }, + { (char*) "Singapore" , 0x053926 }, + { (char*) "Turkey" , 0x053A32 }, + { (char*) "UCT" , 0x053EEE }, + { (char*) "Universal" , 0x053F69 }, + { (char*) "US/Alaska" , 0x053FE4 }, + { (char*) "US/Aleutian" , 0x0543C1 }, + { (char*) "US/Arizona" , 0x054796 }, + { (char*) "US/Central" , 0x054892 }, + { (char*) "US/East-Indiana" , 0x054F78 }, + { (char*) "US/Eastern" , 0x055197 }, + { (char*) "US/Hawaii" , 0x055873 }, + { (char*) "US/Indiana-Starke" , 0x05595C }, + { (char*) "US/Michigan" , 0x055D60 }, + { (char*) "US/Mountain" , 0x0560EF }, + { (char*) "US/Pacific" , 0x05650D }, + { (char*) "US/Samoa" , 0x056A27 }, + { (char*) "UTC" , 0x056AC5 }, + { (char*) "W-SU" , 0x056B40 }, + { (char*) "WET" , 0x056ED8 }, + { (char*) "Zulu" , 0x05749B }, }; -const unsigned char timelib_timezone_db_data_builtin[356759] = { +const unsigned char timelib_timezone_db_data_builtin[357654] = { /* Africa/Abidjan */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -13242,7 +13242,7 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0x56, 0xB6, 0xBA, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0x19, 0x9A, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xDA, 0x0C, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x27, 0x99, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0xCE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x17, 0x08, 0xCD, 0x40, 0x00, @@ -13260,24 +13260,23 @@ 0x00, 0x00, 0x00, 0x2C, 0xA4, 0xA3, 0x40, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xA2, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x84, 0x85, 0x40, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0x76, 0x40, 0x00, 0x00, 0x00, 0x00, 0x30, 0x64, 0x59, 0x30, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0x92, 0xC0, 0x00, -0x00, 0x00, 0x00, 0x33, 0x3D, 0x66, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x41, 0xB0, 0x00, -0x00, 0x00, 0x00, 0x35, 0x1D, 0x56, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0x23, 0xB0, 0x00, -0x00, 0x00, 0x00, 0x36, 0xFD, 0x38, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, 0x40, 0x30, 0x00, -0x00, 0x00, 0x00, 0x38, 0xDD, 0x1A, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, 0x22, 0x30, 0x00, -0x00, 0x00, 0x00, 0x3A, 0xBC, 0xFC, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, 0x04, 0x30, 0x00, -0x00, 0x00, 0x00, 0x3C, 0xA6, 0x19, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBA, 0xE6, 0x30, 0x00, -0x00, 0x00, 0x00, 0x3E, 0x85, 0xFB, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9A, 0xC8, 0x30, 0x00, -0x00, 0x00, 0x00, 0x40, 0x65, 0xDD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0xDD, 0xC7, 0xB0, 0x00, -0x00, 0x00, 0x00, 0x41, 0x84, 0x1C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xE9, 0x70, 0x01, -0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x05, 0x02, 0x05, 0x02, 0x05, 0x02, 0x05, 0x04, 0x03, 0x04, -0x03, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x05, 0x02, 0x04, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x04, 0x00, -0x00, 0x2A, 0x30, 0x00, 0x09, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, 0x00, -0x11, 0x00, 0x00, 0x38, 0x40, 0x01, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x54, 0x42, 0x4D, 0x54, 0x00, -0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x0A, 0x3C, 0x2B, 0x30, -0x34, 0x3E, 0x2D, 0x34, 0x0A, 0x00, 0xC8, 0xFB, 0xD2, 0x01, 0x57, 0x0B, 0x02, 0x00, 0x00, 0x00, -0x00, +0x00, 0x00, 0x00, 0x34, 0x52, 0x41, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x56, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x36, 0x32, 0x23, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x38, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x38, 0x1B, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x1A, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x39, 0xFB, 0x22, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBC, 0xFC, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x3B, 0xDB, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x19, 0x40, 0x00, +0x00, 0x00, 0x00, 0x3D, 0xBA, 0xE6, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x85, 0xFB, 0x40, 0x00, +0x00, 0x00, 0x00, 0x3F, 0x9A, 0xC8, 0x30, 0x00, 0x00, 0x00, 0x00, 0x40, 0x65, 0xDD, 0x40, 0x00, +0x00, 0x00, 0x00, 0x40, 0xDD, 0xC7, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x1C, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x42, 0x45, 0xE9, 0x70, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x05, 0x02, +0x05, 0x02, 0x05, 0x02, 0x05, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x05, 0x02, 0x04, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x00, +0x00, 0x00, 0x29, 0xFF, 0x00, 0x04, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x09, 0x00, 0x00, 0x46, 0x50, +0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, 0x00, 0x11, 0x00, 0x00, 0x38, 0x40, 0x01, 0x11, 0x4C, 0x4D, +0x54, 0x00, 0x54, 0x42, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, +0x30, 0x34, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x34, 0x3E, 0x2D, 0x34, 0x0A, 0x00, 0xC8, 0xFB, 0xD2, +0x01, 0x57, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x00, /* Asia/Tehran */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x49, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -18107,7 +18106,7 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x26, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x26, 0xFF, 0xFF, 0xFF, 0xFF, 0x56, 0xB6, 0xC8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x9E, 0x6B, 0x9F, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0xB0, 0xD2, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xB9, 0x3E, 0xF3, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xB9, 0xEF, 0x9C, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xDF, 0x8D, 0x60, 0xFF, @@ -18137,19 +18136,48 @@ 0x00, 0x00, 0x00, 0x2C, 0xA4, 0xB1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xB0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x84, 0x93, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0x92, 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x64, 0x75, 0x50, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0xAE, 0xE0, 0x00, -0x00, 0x00, 0x00, 0x32, 0x72, 0x7B, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x32, 0xC9, 0x8C, 0xE0, 0x01, +0x00, 0x00, 0x00, 0x32, 0x72, 0x7B, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0xAD, 0x00, 0x00, +0x00, 0x00, 0x00, 0x34, 0x52, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x8F, 0x00, 0x00, +0x00, 0x00, 0x00, 0x36, 0x32, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x71, 0x00, 0x00, +0x00, 0x00, 0x00, 0x38, 0x1B, 0x86, 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x53, 0x00, 0x00, +0x00, 0x00, 0x00, 0x39, 0xFB, 0x68, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBD, 0x35, 0x00, 0x00, +0x00, 0x00, 0x00, 0x3B, 0xDB, 0x4A, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x51, 0x80, 0x00, +0x00, 0x00, 0x00, 0x3D, 0xBB, 0x2C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x86, 0x33, 0x80, 0x00, +0x00, 0x00, 0x00, 0x3F, 0x9B, 0x0E, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x15, 0x80, 0x00, +0x00, 0x00, 0x00, 0x41, 0x84, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xF7, 0x80, 0x00, +0x00, 0x00, 0x00, 0x43, 0x64, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0xD9, 0x80, 0x00, +0x00, 0x00, 0x00, 0x45, 0x43, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xBB, 0x80, 0x00, +0x00, 0x00, 0x00, 0x47, 0x23, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEE, 0xD8, 0x00, 0x00, +0x00, 0x00, 0x00, 0x49, 0x03, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0xCE, 0xBA, 0x00, 0x00, +0x00, 0x00, 0x00, 0x4A, 0xE3, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0x9C, 0x00, 0x00, +0x00, 0x00, 0x00, 0x4C, 0xCC, 0xB1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x7E, 0x00, 0x00, +0x00, 0x00, 0x00, 0x4E, 0xAC, 0x93, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6E, 0x60, 0x00, 0x00, +0x00, 0x00, 0x00, 0x50, 0x8C, 0x75, 0x80, 0x00, 0x00, 0x00, 0x00, 0x51, 0x57, 0x7C, 0x80, 0x00, +0x00, 0x00, 0x00, 0x52, 0x6C, 0x57, 0x80, 0x00, 0x00, 0x00, 0x00, 0x53, 0x37, 0x5E, 0x80, 0x00, +0x00, 0x00, 0x00, 0x54, 0x4C, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x55, 0x17, 0x40, 0x80, 0x00, +0x00, 0x00, 0x00, 0x56, 0x2C, 0x1B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x56, 0xF7, 0x22, 0x80, 0x00, +0x00, 0x00, 0x00, 0x58, 0x15, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xD7, 0x04, 0x80, 0x00, +0x00, 0x00, 0x00, 0x59, 0xF5, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xB6, 0xE6, 0x80, 0x00, +0x00, 0x00, 0x00, 0x5B, 0xD4, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA0, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x5D, 0xB4, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xE5, 0x00, 0x00, +0x00, 0x00, 0x00, 0x5F, 0x94, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xC7, 0x00, 0x00, +0x00, 0x00, 0x00, 0x61, 0x7D, 0xDC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x61, 0xCF, 0x7D, 0x60, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x06, 0x05, 0x06, 0x05, 0x06, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x04, 0x00, 0x00, 0x1B, 0x08, 0x00, -0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x18, 0x78, 0x00, 0x08, 0x00, 0x00, 0x2A, -0x30, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x15, 0x00, -0x00, 0x1C, 0x20, 0x01, 0x19, 0x00, 0x00, 0x38, 0x40, 0x01, 0x1E, 0x00, 0x00, 0x2A, 0x30, 0x00, -0x22, 0x4C, 0x4D, 0x54, 0x00, 0x43, 0x4D, 0x54, 0x00, 0x42, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, -0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00, 0x4D, -0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, -0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, -0x2F, 0x33, 0x0A, 0x00, 0xD1, 0x0B, 0xA0, 0x01, 0x3E, 0xA7, 0x85, 0x00, 0x00, 0x00, 0x00, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x04, 0x00, 0x00, 0x1B, +0x08, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x18, 0x78, 0x00, 0x08, 0x00, +0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x0E, 0x10, 0x00, +0x15, 0x00, 0x00, 0x1C, 0x20, 0x01, 0x19, 0x00, 0x00, 0x38, 0x40, 0x01, 0x1E, 0x00, 0x00, 0x2A, +0x30, 0x00, 0x22, 0x4C, 0x4D, 0x54, 0x00, 0x43, 0x4D, 0x54, 0x00, 0x42, 0x4D, 0x54, 0x00, 0x45, +0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, +0x00, 0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, +0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x2C, 0x4D, 0x31, 0x30, +0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x34, 0x0A, 0x00, 0xD1, 0x0B, 0xA0, 0x01, 0x3E, 0xA7, 0x85, 0x00, +0x00, 0x00, 0x00, /* Europe/Copenhagen */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x44, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -20427,7 +20455,7 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x26, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x26, 0xFF, 0xFF, 0xFF, 0xFF, 0x56, 0xB6, 0xC8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x9E, 0x6B, 0x9F, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0xB0, 0xD2, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xB9, 0x3E, 0xF3, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xB9, 0xEF, 0x9C, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xDF, 0x8D, 0x60, 0xFF, @@ -20457,19 +20485,48 @@ 0x00, 0x00, 0x00, 0x2C, 0xA4, 0xB1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xB0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x84, 0x93, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0x92, 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x64, 0x75, 0x50, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0xAE, 0xE0, 0x00, -0x00, 0x00, 0x00, 0x32, 0x72, 0x7B, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x32, 0xC9, 0x8C, 0xE0, 0x01, +0x00, 0x00, 0x00, 0x32, 0x72, 0x7B, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0xAD, 0x00, 0x00, +0x00, 0x00, 0x00, 0x34, 0x52, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x8F, 0x00, 0x00, +0x00, 0x00, 0x00, 0x36, 0x32, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x71, 0x00, 0x00, +0x00, 0x00, 0x00, 0x38, 0x1B, 0x86, 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x53, 0x00, 0x00, +0x00, 0x00, 0x00, 0x39, 0xFB, 0x68, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBD, 0x35, 0x00, 0x00, +0x00, 0x00, 0x00, 0x3B, 0xDB, 0x4A, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x51, 0x80, 0x00, +0x00, 0x00, 0x00, 0x3D, 0xBB, 0x2C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x86, 0x33, 0x80, 0x00, +0x00, 0x00, 0x00, 0x3F, 0x9B, 0x0E, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x15, 0x80, 0x00, +0x00, 0x00, 0x00, 0x41, 0x84, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xF7, 0x80, 0x00, +0x00, 0x00, 0x00, 0x43, 0x64, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0xD9, 0x80, 0x00, +0x00, 0x00, 0x00, 0x45, 0x43, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xBB, 0x80, 0x00, +0x00, 0x00, 0x00, 0x47, 0x23, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEE, 0xD8, 0x00, 0x00, +0x00, 0x00, 0x00, 0x49, 0x03, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0xCE, 0xBA, 0x00, 0x00, +0x00, 0x00, 0x00, 0x4A, 0xE3, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0x9C, 0x00, 0x00, +0x00, 0x00, 0x00, 0x4C, 0xCC, 0xB1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x7E, 0x00, 0x00, +0x00, 0x00, 0x00, 0x4E, 0xAC, 0x93, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6E, 0x60, 0x00, 0x00, +0x00, 0x00, 0x00, 0x50, 0x8C, 0x75, 0x80, 0x00, 0x00, 0x00, 0x00, 0x51, 0x57, 0x7C, 0x80, 0x00, +0x00, 0x00, 0x00, 0x52, 0x6C, 0x57, 0x80, 0x00, 0x00, 0x00, 0x00, 0x53, 0x37, 0x5E, 0x80, 0x00, +0x00, 0x00, 0x00, 0x54, 0x4C, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x55, 0x17, 0x40, 0x80, 0x00, +0x00, 0x00, 0x00, 0x56, 0x2C, 0x1B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x56, 0xF7, 0x22, 0x80, 0x00, +0x00, 0x00, 0x00, 0x58, 0x15, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xD7, 0x04, 0x80, 0x00, +0x00, 0x00, 0x00, 0x59, 0xF5, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xB6, 0xE6, 0x80, 0x00, +0x00, 0x00, 0x00, 0x5B, 0xD4, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA0, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x5D, 0xB4, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xE5, 0x00, 0x00, +0x00, 0x00, 0x00, 0x5F, 0x94, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xC7, 0x00, 0x00, +0x00, 0x00, 0x00, 0x61, 0x7D, 0xDC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x61, 0xCF, 0x7D, 0x60, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x06, 0x05, 0x06, 0x05, 0x06, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x08, 0x07, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x04, 0x00, 0x00, 0x1B, 0x08, 0x00, -0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x18, 0x78, 0x00, 0x08, 0x00, 0x00, 0x2A, -0x30, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x15, 0x00, -0x00, 0x1C, 0x20, 0x01, 0x19, 0x00, 0x00, 0x38, 0x40, 0x01, 0x1E, 0x00, 0x00, 0x2A, 0x30, 0x00, -0x22, 0x4C, 0x4D, 0x54, 0x00, 0x43, 0x4D, 0x54, 0x00, 0x42, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, -0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00, 0x4D, -0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, -0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, -0x2F, 0x33, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x04, 0x00, 0x00, 0x1B, +0x08, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x18, 0x78, 0x00, 0x08, 0x00, +0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x0E, 0x10, 0x00, +0x15, 0x00, 0x00, 0x1C, 0x20, 0x01, 0x19, 0x00, 0x00, 0x38, 0x40, 0x01, 0x1E, 0x00, 0x00, 0x2A, +0x30, 0x00, 0x22, 0x4C, 0x4D, 0x54, 0x00, 0x43, 0x4D, 0x54, 0x00, 0x42, 0x4D, 0x54, 0x00, 0x45, +0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, +0x00, 0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, +0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x2C, 0x4D, 0x31, 0x30, +0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x34, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, /* Europe/Ulyanovsk */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -24720,290 +24777,290 @@ { (char*) "Asia/Taipei" , 0x053BCB }, { (char*) "Asia/Tashkent" , 0x053ED0 }, { (char*) "Asia/Tbilisi" , 0x05412E }, - { (char*) "Asia/Tehran" , 0x054537 }, - { (char*) "Asia/Tel_Aviv" , 0x054A23 }, - { (char*) "Asia/Thimbu" , 0x055383 }, - { (char*) "Asia/Thimphu" , 0x05544C }, - { (char*) "Asia/Tokyo" , 0x055515 }, - { (char*) "Asia/Tomsk" , 0x055656 }, - { (char*) "Asia/Ujung_Pandang" , 0x055B27 }, - { (char*) "Asia/Ulaanbaatar" , 0x055C31 }, - { (char*) "Asia/Ulan_Bator" , 0x055FBA }, - { (char*) "Asia/Urumqi" , 0x056333 }, - { (char*) "Asia/Ust-Nera" , 0x0563E3 }, - { (char*) "Asia/Vientiane" , 0x0568D9 }, - { (char*) "Asia/Vladivostok" , 0x056A1A }, - { (char*) "Asia/Yakutsk" , 0x056EE3 }, - { (char*) "Asia/Yangon" , 0x0573AB }, - { (char*) "Asia/Yekaterinburg" , 0x0574B5 }, - { (char*) "Asia/Yerevan" , 0x05799C }, - { (char*) "Atlantic/Azores" , 0x057E19 }, - { (char*) "Atlantic/Bermuda" , 0x058B9D }, - { (char*) "Atlantic/Canary" , 0x059505 }, - { (char*) "Atlantic/Cape_Verde" , 0x059C88 }, - { (char*) "Atlantic/Faeroe" , 0x059D94 }, - { (char*) "Atlantic/Faroe" , 0x05A4B7 }, - { (char*) "Atlantic/Jan_Mayen" , 0x05ABDA }, - { (char*) "Atlantic/Madeira" , 0x05B4E0 }, - { (char*) "Atlantic/Reykjavik" , 0x05C22C }, - { (char*) "Atlantic/South_Georgia" , 0x05C6C2 }, - { (char*) "Atlantic/St_Helena" , 0x05C764 }, - { (char*) "Atlantic/Stanley" , 0x05C826 }, - { (char*) "Australia/ACT" , 0x05CCE2 }, - { (char*) "Australia/Adelaide" , 0x05D57C }, - { (char*) "Australia/Brisbane" , 0x05DE37 }, - { (char*) "Australia/Broken_Hill" , 0x05DFFD }, - { (char*) "Australia/Canberra" , 0x05E8DA }, - { (char*) "Australia/Currie" , 0x05F174 }, - { (char*) "Australia/Darwin" , 0x05FAB6 }, - { (char*) "Australia/Eucla" , 0x05FC19 }, - { (char*) "Australia/Hobart" , 0x05FE06 }, - { (char*) "Australia/LHI" , 0x060750 }, - { (char*) "Australia/Lindeman" , 0x060E92 }, - { (char*) "Australia/Lord_Howe" , 0x061098 }, - { (char*) "Australia/Melbourne" , 0x0617EA }, - { (char*) "Australia/North" , 0x06208C }, - { (char*) "Australia/NSW" , 0x0621DD }, - { (char*) "Australia/Perth" , 0x062A77 }, - { (char*) "Australia/Queensland" , 0x062C5F }, - { (char*) "Australia/South" , 0x062E0E }, - { (char*) "Australia/Sydney" , 0x0636BA }, - { (char*) "Australia/Tasmania" , 0x063F70 }, - { (char*) "Australia/Victoria" , 0x0648B2 }, - { (char*) "Australia/West" , 0x06514C }, - { (char*) "Australia/Yancowinna" , 0x065316 }, - { (char*) "Brazil/Acre" , 0x065BD7 }, - { (char*) "Brazil/DeNoronha" , 0x065E49 }, - { (char*) "Brazil/East" , 0x066113 }, - { (char*) "Brazil/West" , 0x0666B5 }, - { (char*) "Canada/Atlantic" , 0x06690F }, - { (char*) "Canada/Central" , 0x06767B }, - { (char*) "Canada/Eastern" , 0x0681BB }, - { (char*) "Canada/Mountain" , 0x068F6D }, - { (char*) "Canada/Newfoundland" , 0x069895 }, - { (char*) "Canada/Pacific" , 0x06A6E8 }, - { (char*) "Canada/Saskatchewan" , 0x06B240 }, - { (char*) "Canada/Yukon" , 0x06B620 }, - { (char*) "CET" , 0x06BC7A }, - { (char*) "Chile/Continental" , 0x06C7FB }, - { (char*) "Chile/EasterIsland" , 0x06D1DA }, - { (char*) "CST6CDT" , 0x06DA91 }, - { (char*) "Cuba" , 0x06E8A5 }, - { (char*) "EET" , 0x06F221 }, - { (char*) "Egypt" , 0x06FB03 }, - { (char*) "Eire" , 0x07046E }, - { (char*) "EST" , 0x07121E }, - { (char*) "EST5EDT" , 0x0712E0 }, - { (char*) "Etc/GMT" , 0x0720CC }, - { (char*) "Etc/GMT+0" , 0x07214A }, - { (char*) "Etc/GMT+1" , 0x0721C8 }, - { (char*) "Etc/GMT+10" , 0x072248 }, - { (char*) "Etc/GMT+11" , 0x0722C9 }, - { (char*) "Etc/GMT+12" , 0x07234A }, - { (char*) "Etc/GMT+2" , 0x0723CB }, - { (char*) "Etc/GMT+3" , 0x07244B }, - { (char*) "Etc/GMT+4" , 0x0724CB }, - { (char*) "Etc/GMT+5" , 0x07254B }, - { (char*) "Etc/GMT+6" , 0x0725CB }, - { (char*) "Etc/GMT+7" , 0x07264B }, - { (char*) "Etc/GMT+8" , 0x0726CB }, - { (char*) "Etc/GMT+9" , 0x07274B }, - { (char*) "Etc/GMT-0" , 0x0727CB }, - { (char*) "Etc/GMT-1" , 0x072849 }, - { (char*) "Etc/GMT-10" , 0x0728CA }, - { (char*) "Etc/GMT-11" , 0x07294C }, - { (char*) "Etc/GMT-12" , 0x0729CE }, - { (char*) "Etc/GMT-13" , 0x072A50 }, - { (char*) "Etc/GMT-14" , 0x072AD2 }, - { (char*) "Etc/GMT-2" , 0x072B54 }, - { (char*) "Etc/GMT-3" , 0x072BD5 }, - { (char*) "Etc/GMT-4" , 0x072C56 }, - { (char*) "Etc/GMT-5" , 0x072CD7 }, - { (char*) "Etc/GMT-6" , 0x072D58 }, - { (char*) "Etc/GMT-7" , 0x072DD9 }, - { (char*) "Etc/GMT-8" , 0x072E5A }, - { (char*) "Etc/GMT-9" , 0x072EDB }, - { (char*) "Etc/GMT0" , 0x072F5C }, - { (char*) "Etc/Greenwich" , 0x072FDA }, - { (char*) "Etc/UCT" , 0x073058 }, - { (char*) "Etc/Universal" , 0x0730D6 }, - { (char*) "Etc/UTC" , 0x073154 }, - { (char*) "Etc/Zulu" , 0x0731D2 }, - { (char*) "Europe/Amsterdam" , 0x073250 }, - { (char*) "Europe/Andorra" , 0x073DBA }, - { (char*) "Europe/Astrakhan" , 0x074494 }, - { (char*) "Europe/Athens" , 0x074931 }, - { (char*) "Europe/Belfast" , 0x075213 }, - { (char*) "Europe/Belgrade" , 0x07606F }, - { (char*) "Europe/Berlin" , 0x0767FB }, - { (char*) "Europe/Bratislava" , 0x077110 }, - { (char*) "Europe/Brussels" , 0x077A19 }, - { (char*) "Europe/Bucharest" , 0x07859A }, - { (char*) "Europe/Budapest" , 0x078E2E }, - { (char*) "Europe/Busingen" , 0x07977A }, - { (char*) "Europe/Chisinau" , 0x079F03 }, - { (char*) "Europe/Copenhagen" , 0x07A865 }, - { (char*) "Europe/Dublin" , 0x07B0CA }, - { (char*) "Europe/Gibraltar" , 0x07BE7A }, - { (char*) "Europe/Guernsey" , 0x07CA82 }, - { (char*) "Europe/Helsinki" , 0x07D922 }, - { (char*) "Europe/Isle_of_Man" , 0x07E09A }, - { (char*) "Europe/Istanbul" , 0x07EEE6 }, - { (char*) "Europe/Jersey" , 0x07F67F }, - { (char*) "Europe/Kaliningrad" , 0x08051F }, - { (char*) "Europe/Kiev" , 0x080B14 }, - { (char*) "Europe/Kirov" , 0x081368 }, - { (char*) "Europe/Kyiv" , 0x081823 }, - { (char*) "Europe/Lisbon" , 0x082086 }, - { (char*) "Europe/Ljubljana" , 0x082E6C }, - { (char*) "Europe/London" , 0x0835F8 }, - { (char*) "Europe/Luxembourg" , 0x084454 }, - { (char*) "Europe/Madrid" , 0x084FE2 }, - { (char*) "Europe/Malta" , 0x085A34 }, - { (char*) "Europe/Mariehamn" , 0x08647C }, - { (char*) "Europe/Minsk" , 0x086BF4 }, - { (char*) "Europe/Monaco" , 0x08711B }, - { (char*) "Europe/Moscow" , 0x087CA7 }, - { (char*) "Europe/Nicosia" , 0x0882C6 }, - { (char*) "Europe/Oslo" , 0x088AA4 }, - { (char*) "Europe/Paris" , 0x089364 }, - { (char*) "Europe/Podgorica" , 0x089F02 }, - { (char*) "Europe/Prague" , 0x08A68E }, - { (char*) "Europe/Riga" , 0x08AF97 }, - { (char*) "Europe/Rome" , 0x08B839 }, - { (char*) "Europe/Samara" , 0x08C296 }, - { (char*) "Europe/San_Marino" , 0x08C76C }, - { (char*) "Europe/Sarajevo" , 0x08D1C9 }, - { (char*) "Europe/Saratov" , 0x08D955 }, - { (char*) "Europe/Simferopol" , 0x08DE02 }, - { (char*) "Europe/Skopje" , 0x08E3D1 }, - { (char*) "Europe/Sofia" , 0x08EB5D }, - { (char*) "Europe/Stockholm" , 0x08F386 }, - { (char*) "Europe/Tallinn" , 0x08FB07 }, - { (char*) "Europe/Tirane" , 0x090377 }, - { (char*) "Europe/Tiraspol" , 0x090BA7 }, - { (char*) "Europe/Ulyanovsk" , 0x091509 }, - { (char*) "Europe/Uzhgorod" , 0x091A0C }, - { (char*) "Europe/Vaduz" , 0x092260 }, - { (char*) "Europe/Vatican" , 0x0929CC }, - { (char*) "Europe/Vienna" , 0x093429 }, - { (char*) "Europe/Vilnius" , 0x093CCD }, - { (char*) "Europe/Volgograd" , 0x09454B }, - { (char*) "Europe/Warsaw" , 0x094A12 }, - { (char*) "Europe/Zagreb" , 0x09547C }, - { (char*) "Europe/Zaporozhye" , 0x095C08 }, - { (char*) "Europe/Zurich" , 0x09645C }, - { (char*) "Factory" , 0x096BDD }, - { (char*) "GB" , 0x096C5D }, - { (char*) "GB-Eire" , 0x097AB9 }, - { (char*) "GMT" , 0x098915 }, - { (char*) "GMT+0" , 0x098993 }, - { (char*) "GMT-0" , 0x098A11 }, - { (char*) "GMT0" , 0x098A8F }, - { (char*) "Greenwich" , 0x098B0D }, - { (char*) "Hongkong" , 0x098B8B }, - { (char*) "HST" , 0x099068 }, - { (char*) "Iceland" , 0x0991BD }, - { (char*) "Indian/Antananarivo" , 0x09925D }, - { (char*) "Indian/Chagos" , 0x099344 }, - { (char*) "Indian/Christmas" , 0x099409 }, - { (char*) "Indian/Cocos" , 0x0994AC }, - { (char*) "Indian/Comoro" , 0x099558 }, - { (char*) "Indian/Kerguelen" , 0x0995F9 }, - { (char*) "Indian/Mahe" , 0x09969C }, - { (char*) "Indian/Maldives" , 0x09973F }, - { (char*) "Indian/Mauritius" , 0x099804 }, - { (char*) "Indian/Mayotte" , 0x0998F3 }, - { (char*) "Indian/Reunion" , 0x099994 }, - { (char*) "Iran" , 0x099A37 }, - { (char*) "Israel" , 0x099F23 }, - { (char*) "Jamaica" , 0x09A883 }, - { (char*) "Japan" , 0x09AA71 }, - { (char*) "Kwajalein" , 0x09ABB2 }, - { (char*) "Libya" , 0x09ACEC }, - { (char*) "MET" , 0x09AF69 }, - { (char*) "Mexico/BajaNorte" , 0x09BAEA }, - { (char*) "Mexico/BajaSur" , 0x09C650 }, - { (char*) "Mexico/General" , 0x09CA80 }, - { (char*) "MST" , 0x09CF52 }, - { (char*) "MST7MDT" , 0x09D0C6 }, - { (char*) "Navajo" , 0x09DA6E }, - { (char*) "NZ" , 0x09E416 }, - { (char*) "NZ-CHAT" , 0x09EDA7 }, - { (char*) "Pacific/Apia" , 0x09F5B9 }, - { (char*) "Pacific/Auckland" , 0x09F81B }, - { (char*) "Pacific/Bougainville" , 0x0A01BF }, - { (char*) "Pacific/Chatham" , 0x0A02D5 }, - { (char*) "Pacific/Chuuk" , 0x0A0AF6 }, - { (char*) "Pacific/Easter" , 0x0A0C10 }, - { (char*) "Pacific/Efate" , 0x0A14D4 }, - { (char*) "Pacific/Enderbury" , 0x0A16EC }, - { (char*) "Pacific/Fakaofo" , 0x0A17D4 }, - { (char*) "Pacific/Fiji" , 0x0A189A }, - { (char*) "Pacific/Funafuti" , 0x0A1ADA }, - { (char*) "Pacific/Galapagos" , 0x0A1B7E }, - { (char*) "Pacific/Gambier" , 0x0A1C7B }, - { (char*) "Pacific/Guadalcanal" , 0x0A1D2C }, - { (char*) "Pacific/Guam" , 0x0A1DD0 }, - { (char*) "Pacific/Honolulu" , 0x0A1FCA }, - { (char*) "Pacific/Johnston" , 0x0A2125 }, - { (char*) "Pacific/Kanton" , 0x0A227A }, - { (char*) "Pacific/Kiritimati" , 0x0A2371 }, - { (char*) "Pacific/Kosrae" , 0x0A2469 }, - { (char*) "Pacific/Kwajalein" , 0x0A25CC }, - { (char*) "Pacific/Majuro" , 0x0A270F }, - { (char*) "Pacific/Marquesas" , 0x0A285B }, - { (char*) "Pacific/Midway" , 0x0A2917 }, - { (char*) "Pacific/Nauru" , 0x0A2A0A }, - { (char*) "Pacific/Niue" , 0x0A2B04 }, - { (char*) "Pacific/Norfolk" , 0x0A2BCD }, - { (char*) "Pacific/Noumea" , 0x0A2F3B }, - { (char*) "Pacific/Pago_Pago" , 0x0A3069 }, - { (char*) "Pacific/Palau" , 0x0A3124 }, - { (char*) "Pacific/Pitcairn" , 0x0A31D6 }, - { (char*) "Pacific/Pohnpei" , 0x0A329E }, - { (char*) "Pacific/Ponape" , 0x0A33D9 }, - { (char*) "Pacific/Port_Moresby" , 0x0A347D }, - { (char*) "Pacific/Rarotonga" , 0x0A354D }, - { (char*) "Pacific/Saipan" , 0x0A37A6 }, - { (char*) "Pacific/Samoa" , 0x0A3992 }, - { (char*) "Pacific/Tahiti" , 0x0A3A4D }, - { (char*) "Pacific/Tarawa" , 0x0A3AFF }, - { (char*) "Pacific/Tongatapu" , 0x0A3BB2 }, - { (char*) "Pacific/Truk" , 0x0A3D24 }, - { (char*) "Pacific/Wake" , 0x0A3DDC }, - { (char*) "Pacific/Wallis" , 0x0A3E8B }, - { (char*) "Pacific/Yap" , 0x0A3F2F }, - { (char*) "Poland" , 0x0A3FE7 }, - { (char*) "Portugal" , 0x0A4A51 }, - { (char*) "PRC" , 0x0A5824 }, - { (char*) "PST8PDT" , 0x0A5A61 }, - { (char*) "ROC" , 0x0A6591 }, - { (char*) "ROK" , 0x0A6896 }, - { (char*) "Singapore" , 0x0A6B0B }, - { (char*) "Turkey" , 0x0A6CA8 }, - { (char*) "UCT" , 0x0A7441 }, - { (char*) "Universal" , 0x0A74BF }, - { (char*) "US/Alaska" , 0x0A753D }, - { (char*) "US/Aleutian" , 0x0A7E8C }, - { (char*) "US/Arizona" , 0x0A87CC }, - { (char*) "US/Central" , 0x0A8940 }, - { (char*) "US/East-Indiana" , 0x0A9754 }, - { (char*) "US/Eastern" , 0x0A9DF2 }, - { (char*) "US/Hawaii" , 0x0AABDE }, - { (char*) "US/Indiana-Starke" , 0x0AAD33 }, - { (char*) "US/Michigan" , 0x0AB6CB }, - { (char*) "US/Mountain" , 0x0ABF8D }, - { (char*) "US/Pacific" , 0x0AC935 }, - { (char*) "US/Samoa" , 0x0AD465 }, - { (char*) "UTC" , 0x0AD520 }, - { (char*) "W-SU" , 0x0AD59E }, - { (char*) "WET" , 0x0ADBA9 }, - { (char*) "Zulu" , 0x0AE97C }, + { (char*) "Asia/Tehran" , 0x054529 }, + { (char*) "Asia/Tel_Aviv" , 0x054A15 }, + { (char*) "Asia/Thimbu" , 0x055375 }, + { (char*) "Asia/Thimphu" , 0x05543E }, + { (char*) "Asia/Tokyo" , 0x055507 }, + { (char*) "Asia/Tomsk" , 0x055648 }, + { (char*) "Asia/Ujung_Pandang" , 0x055B19 }, + { (char*) "Asia/Ulaanbaatar" , 0x055C23 }, + { (char*) "Asia/Ulan_Bator" , 0x055FAC }, + { (char*) "Asia/Urumqi" , 0x056325 }, + { (char*) "Asia/Ust-Nera" , 0x0563D5 }, + { (char*) "Asia/Vientiane" , 0x0568CB }, + { (char*) "Asia/Vladivostok" , 0x056A0C }, + { (char*) "Asia/Yakutsk" , 0x056ED5 }, + { (char*) "Asia/Yangon" , 0x05739D }, + { (char*) "Asia/Yekaterinburg" , 0x0574A7 }, + { (char*) "Asia/Yerevan" , 0x05798E }, + { (char*) "Atlantic/Azores" , 0x057E0B }, + { (char*) "Atlantic/Bermuda" , 0x058B8F }, + { (char*) "Atlantic/Canary" , 0x0594F7 }, + { (char*) "Atlantic/Cape_Verde" , 0x059C7A }, + { (char*) "Atlantic/Faeroe" , 0x059D86 }, + { (char*) "Atlantic/Faroe" , 0x05A4A9 }, + { (char*) "Atlantic/Jan_Mayen" , 0x05ABCC }, + { (char*) "Atlantic/Madeira" , 0x05B4D2 }, + { (char*) "Atlantic/Reykjavik" , 0x05C21E }, + { (char*) "Atlantic/South_Georgia" , 0x05C6B4 }, + { (char*) "Atlantic/St_Helena" , 0x05C756 }, + { (char*) "Atlantic/Stanley" , 0x05C818 }, + { (char*) "Australia/ACT" , 0x05CCD4 }, + { (char*) "Australia/Adelaide" , 0x05D56E }, + { (char*) "Australia/Brisbane" , 0x05DE29 }, + { (char*) "Australia/Broken_Hill" , 0x05DFEF }, + { (char*) "Australia/Canberra" , 0x05E8CC }, + { (char*) "Australia/Currie" , 0x05F166 }, + { (char*) "Australia/Darwin" , 0x05FAA8 }, + { (char*) "Australia/Eucla" , 0x05FC0B }, + { (char*) "Australia/Hobart" , 0x05FDF8 }, + { (char*) "Australia/LHI" , 0x060742 }, + { (char*) "Australia/Lindeman" , 0x060E84 }, + { (char*) "Australia/Lord_Howe" , 0x06108A }, + { (char*) "Australia/Melbourne" , 0x0617DC }, + { (char*) "Australia/North" , 0x06207E }, + { (char*) "Australia/NSW" , 0x0621CF }, + { (char*) "Australia/Perth" , 0x062A69 }, + { (char*) "Australia/Queensland" , 0x062C51 }, + { (char*) "Australia/South" , 0x062E00 }, + { (char*) "Australia/Sydney" , 0x0636AC }, + { (char*) "Australia/Tasmania" , 0x063F62 }, + { (char*) "Australia/Victoria" , 0x0648A4 }, + { (char*) "Australia/West" , 0x06513E }, + { (char*) "Australia/Yancowinna" , 0x065308 }, + { (char*) "Brazil/Acre" , 0x065BC9 }, + { (char*) "Brazil/DeNoronha" , 0x065E3B }, + { (char*) "Brazil/East" , 0x066105 }, + { (char*) "Brazil/West" , 0x0666A7 }, + { (char*) "Canada/Atlantic" , 0x066901 }, + { (char*) "Canada/Central" , 0x06766D }, + { (char*) "Canada/Eastern" , 0x0681AD }, + { (char*) "Canada/Mountain" , 0x068F5F }, + { (char*) "Canada/Newfoundland" , 0x069887 }, + { (char*) "Canada/Pacific" , 0x06A6DA }, + { (char*) "Canada/Saskatchewan" , 0x06B232 }, + { (char*) "Canada/Yukon" , 0x06B612 }, + { (char*) "CET" , 0x06BC6C }, + { (char*) "Chile/Continental" , 0x06C7ED }, + { (char*) "Chile/EasterIsland" , 0x06D1CC }, + { (char*) "CST6CDT" , 0x06DA83 }, + { (char*) "Cuba" , 0x06E897 }, + { (char*) "EET" , 0x06F213 }, + { (char*) "Egypt" , 0x06FAF5 }, + { (char*) "Eire" , 0x070460 }, + { (char*) "EST" , 0x071210 }, + { (char*) "EST5EDT" , 0x0712D2 }, + { (char*) "Etc/GMT" , 0x0720BE }, + { (char*) "Etc/GMT+0" , 0x07213C }, + { (char*) "Etc/GMT+1" , 0x0721BA }, + { (char*) "Etc/GMT+10" , 0x07223A }, + { (char*) "Etc/GMT+11" , 0x0722BB }, + { (char*) "Etc/GMT+12" , 0x07233C }, + { (char*) "Etc/GMT+2" , 0x0723BD }, + { (char*) "Etc/GMT+3" , 0x07243D }, + { (char*) "Etc/GMT+4" , 0x0724BD }, + { (char*) "Etc/GMT+5" , 0x07253D }, + { (char*) "Etc/GMT+6" , 0x0725BD }, + { (char*) "Etc/GMT+7" , 0x07263D }, + { (char*) "Etc/GMT+8" , 0x0726BD }, + { (char*) "Etc/GMT+9" , 0x07273D }, + { (char*) "Etc/GMT-0" , 0x0727BD }, + { (char*) "Etc/GMT-1" , 0x07283B }, + { (char*) "Etc/GMT-10" , 0x0728BC }, + { (char*) "Etc/GMT-11" , 0x07293E }, + { (char*) "Etc/GMT-12" , 0x0729C0 }, + { (char*) "Etc/GMT-13" , 0x072A42 }, + { (char*) "Etc/GMT-14" , 0x072AC4 }, + { (char*) "Etc/GMT-2" , 0x072B46 }, + { (char*) "Etc/GMT-3" , 0x072BC7 }, + { (char*) "Etc/GMT-4" , 0x072C48 }, + { (char*) "Etc/GMT-5" , 0x072CC9 }, + { (char*) "Etc/GMT-6" , 0x072D4A }, + { (char*) "Etc/GMT-7" , 0x072DCB }, + { (char*) "Etc/GMT-8" , 0x072E4C }, + { (char*) "Etc/GMT-9" , 0x072ECD }, + { (char*) "Etc/GMT0" , 0x072F4E }, + { (char*) "Etc/Greenwich" , 0x072FCC }, + { (char*) "Etc/UCT" , 0x07304A }, + { (char*) "Etc/Universal" , 0x0730C8 }, + { (char*) "Etc/UTC" , 0x073146 }, + { (char*) "Etc/Zulu" , 0x0731C4 }, + { (char*) "Europe/Amsterdam" , 0x073242 }, + { (char*) "Europe/Andorra" , 0x073DAC }, + { (char*) "Europe/Astrakhan" , 0x074486 }, + { (char*) "Europe/Athens" , 0x074923 }, + { (char*) "Europe/Belfast" , 0x075205 }, + { (char*) "Europe/Belgrade" , 0x076061 }, + { (char*) "Europe/Berlin" , 0x0767ED }, + { (char*) "Europe/Bratislava" , 0x077102 }, + { (char*) "Europe/Brussels" , 0x077A0B }, + { (char*) "Europe/Bucharest" , 0x07858C }, + { (char*) "Europe/Budapest" , 0x078E20 }, + { (char*) "Europe/Busingen" , 0x07976C }, + { (char*) "Europe/Chisinau" , 0x079EF5 }, + { (char*) "Europe/Copenhagen" , 0x07A879 }, + { (char*) "Europe/Dublin" , 0x07B0DE }, + { (char*) "Europe/Gibraltar" , 0x07BE8E }, + { (char*) "Europe/Guernsey" , 0x07CA96 }, + { (char*) "Europe/Helsinki" , 0x07D936 }, + { (char*) "Europe/Isle_of_Man" , 0x07E0AE }, + { (char*) "Europe/Istanbul" , 0x07EEFA }, + { (char*) "Europe/Jersey" , 0x07F693 }, + { (char*) "Europe/Kaliningrad" , 0x080533 }, + { (char*) "Europe/Kiev" , 0x080B28 }, + { (char*) "Europe/Kirov" , 0x08137C }, + { (char*) "Europe/Kyiv" , 0x081837 }, + { (char*) "Europe/Lisbon" , 0x08209A }, + { (char*) "Europe/Ljubljana" , 0x082E80 }, + { (char*) "Europe/London" , 0x08360C }, + { (char*) "Europe/Luxembourg" , 0x084468 }, + { (char*) "Europe/Madrid" , 0x084FF6 }, + { (char*) "Europe/Malta" , 0x085A48 }, + { (char*) "Europe/Mariehamn" , 0x086490 }, + { (char*) "Europe/Minsk" , 0x086C08 }, + { (char*) "Europe/Monaco" , 0x08712F }, + { (char*) "Europe/Moscow" , 0x087CBB }, + { (char*) "Europe/Nicosia" , 0x0882DA }, + { (char*) "Europe/Oslo" , 0x088AB8 }, + { (char*) "Europe/Paris" , 0x089378 }, + { (char*) "Europe/Podgorica" , 0x089F16 }, + { (char*) "Europe/Prague" , 0x08A6A2 }, + { (char*) "Europe/Riga" , 0x08AFAB }, + { (char*) "Europe/Rome" , 0x08B84D }, + { (char*) "Europe/Samara" , 0x08C2AA }, + { (char*) "Europe/San_Marino" , 0x08C780 }, + { (char*) "Europe/Sarajevo" , 0x08D1DD }, + { (char*) "Europe/Saratov" , 0x08D969 }, + { (char*) "Europe/Simferopol" , 0x08DE16 }, + { (char*) "Europe/Skopje" , 0x08E3E5 }, + { (char*) "Europe/Sofia" , 0x08EB71 }, + { (char*) "Europe/Stockholm" , 0x08F39A }, + { (char*) "Europe/Tallinn" , 0x08FB1B }, + { (char*) "Europe/Tirane" , 0x09038B }, + { (char*) "Europe/Tiraspol" , 0x090BBB }, + { (char*) "Europe/Ulyanovsk" , 0x09153F }, + { (char*) "Europe/Uzhgorod" , 0x091A42 }, + { (char*) "Europe/Vaduz" , 0x092296 }, + { (char*) "Europe/Vatican" , 0x092A02 }, + { (char*) "Europe/Vienna" , 0x09345F }, + { (char*) "Europe/Vilnius" , 0x093D03 }, + { (char*) "Europe/Volgograd" , 0x094581 }, + { (char*) "Europe/Warsaw" , 0x094A48 }, + { (char*) "Europe/Zagreb" , 0x0954B2 }, + { (char*) "Europe/Zaporozhye" , 0x095C3E }, + { (char*) "Europe/Zurich" , 0x096492 }, + { (char*) "Factory" , 0x096C13 }, + { (char*) "GB" , 0x096C93 }, + { (char*) "GB-Eire" , 0x097AEF }, + { (char*) "GMT" , 0x09894B }, + { (char*) "GMT+0" , 0x0989C9 }, + { (char*) "GMT-0" , 0x098A47 }, + { (char*) "GMT0" , 0x098AC5 }, + { (char*) "Greenwich" , 0x098B43 }, + { (char*) "Hongkong" , 0x098BC1 }, + { (char*) "HST" , 0x09909E }, + { (char*) "Iceland" , 0x0991F3 }, + { (char*) "Indian/Antananarivo" , 0x099293 }, + { (char*) "Indian/Chagos" , 0x09937A }, + { (char*) "Indian/Christmas" , 0x09943F }, + { (char*) "Indian/Cocos" , 0x0994E2 }, + { (char*) "Indian/Comoro" , 0x09958E }, + { (char*) "Indian/Kerguelen" , 0x09962F }, + { (char*) "Indian/Mahe" , 0x0996D2 }, + { (char*) "Indian/Maldives" , 0x099775 }, + { (char*) "Indian/Mauritius" , 0x09983A }, + { (char*) "Indian/Mayotte" , 0x099929 }, + { (char*) "Indian/Reunion" , 0x0999CA }, + { (char*) "Iran" , 0x099A6D }, + { (char*) "Israel" , 0x099F59 }, + { (char*) "Jamaica" , 0x09A8B9 }, + { (char*) "Japan" , 0x09AAA7 }, + { (char*) "Kwajalein" , 0x09ABE8 }, + { (char*) "Libya" , 0x09AD22 }, + { (char*) "MET" , 0x09AF9F }, + { (char*) "Mexico/BajaNorte" , 0x09BB20 }, + { (char*) "Mexico/BajaSur" , 0x09C686 }, + { (char*) "Mexico/General" , 0x09CAB6 }, + { (char*) "MST" , 0x09CF88 }, + { (char*) "MST7MDT" , 0x09D0FC }, + { (char*) "Navajo" , 0x09DAA4 }, + { (char*) "NZ" , 0x09E44C }, + { (char*) "NZ-CHAT" , 0x09EDDD }, + { (char*) "Pacific/Apia" , 0x09F5EF }, + { (char*) "Pacific/Auckland" , 0x09F851 }, + { (char*) "Pacific/Bougainville" , 0x0A01F5 }, + { (char*) "Pacific/Chatham" , 0x0A030B }, + { (char*) "Pacific/Chuuk" , 0x0A0B2C }, + { (char*) "Pacific/Easter" , 0x0A0C46 }, + { (char*) "Pacific/Efate" , 0x0A150A }, + { (char*) "Pacific/Enderbury" , 0x0A1722 }, + { (char*) "Pacific/Fakaofo" , 0x0A180A }, + { (char*) "Pacific/Fiji" , 0x0A18D0 }, + { (char*) "Pacific/Funafuti" , 0x0A1B10 }, + { (char*) "Pacific/Galapagos" , 0x0A1BB4 }, + { (char*) "Pacific/Gambier" , 0x0A1CB1 }, + { (char*) "Pacific/Guadalcanal" , 0x0A1D62 }, + { (char*) "Pacific/Guam" , 0x0A1E06 }, + { (char*) "Pacific/Honolulu" , 0x0A2000 }, + { (char*) "Pacific/Johnston" , 0x0A215B }, + { (char*) "Pacific/Kanton" , 0x0A22B0 }, + { (char*) "Pacific/Kiritimati" , 0x0A23A7 }, + { (char*) "Pacific/Kosrae" , 0x0A249F }, + { (char*) "Pacific/Kwajalein" , 0x0A2602 }, + { (char*) "Pacific/Majuro" , 0x0A2745 }, + { (char*) "Pacific/Marquesas" , 0x0A2891 }, + { (char*) "Pacific/Midway" , 0x0A294D }, + { (char*) "Pacific/Nauru" , 0x0A2A40 }, + { (char*) "Pacific/Niue" , 0x0A2B3A }, + { (char*) "Pacific/Norfolk" , 0x0A2C03 }, + { (char*) "Pacific/Noumea" , 0x0A2F71 }, + { (char*) "Pacific/Pago_Pago" , 0x0A309F }, + { (char*) "Pacific/Palau" , 0x0A315A }, + { (char*) "Pacific/Pitcairn" , 0x0A320C }, + { (char*) "Pacific/Pohnpei" , 0x0A32D4 }, + { (char*) "Pacific/Ponape" , 0x0A340F }, + { (char*) "Pacific/Port_Moresby" , 0x0A34B3 }, + { (char*) "Pacific/Rarotonga" , 0x0A3583 }, + { (char*) "Pacific/Saipan" , 0x0A37DC }, + { (char*) "Pacific/Samoa" , 0x0A39C8 }, + { (char*) "Pacific/Tahiti" , 0x0A3A83 }, + { (char*) "Pacific/Tarawa" , 0x0A3B35 }, + { (char*) "Pacific/Tongatapu" , 0x0A3BE8 }, + { (char*) "Pacific/Truk" , 0x0A3D5A }, + { (char*) "Pacific/Wake" , 0x0A3E12 }, + { (char*) "Pacific/Wallis" , 0x0A3EC1 }, + { (char*) "Pacific/Yap" , 0x0A3F65 }, + { (char*) "Poland" , 0x0A401D }, + { (char*) "Portugal" , 0x0A4A87 }, + { (char*) "PRC" , 0x0A585A }, + { (char*) "PST8PDT" , 0x0A5A97 }, + { (char*) "ROC" , 0x0A65C7 }, + { (char*) "ROK" , 0x0A68CC }, + { (char*) "Singapore" , 0x0A6B41 }, + { (char*) "Turkey" , 0x0A6CDE }, + { (char*) "UCT" , 0x0A7477 }, + { (char*) "Universal" , 0x0A74F5 }, + { (char*) "US/Alaska" , 0x0A7573 }, + { (char*) "US/Aleutian" , 0x0A7EC2 }, + { (char*) "US/Arizona" , 0x0A8802 }, + { (char*) "US/Central" , 0x0A8976 }, + { (char*) "US/East-Indiana" , 0x0A978A }, + { (char*) "US/Eastern" , 0x0A9E28 }, + { (char*) "US/Hawaii" , 0x0AAC14 }, + { (char*) "US/Indiana-Starke" , 0x0AAD69 }, + { (char*) "US/Michigan" , 0x0AB701 }, + { (char*) "US/Mountain" , 0x0ABFC3 }, + { (char*) "US/Pacific" , 0x0AC96B }, + { (char*) "US/Samoa" , 0x0AD49B }, + { (char*) "UTC" , 0x0AD556 }, + { (char*) "W-SU" , 0x0AD5D4 }, + { (char*) "WET" , 0x0ADBDF }, + { (char*) "Zulu" , 0x0AE9B2 }, }; -const unsigned char timelib_timezone_db_data_builtin[715258] = { +const unsigned char timelib_timezone_db_data_builtin[715312] = { /* Africa/Abidjan */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -47351,7 +47408,7 @@ /* Asia/Tbilisi */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x47, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x15, 0x80, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x15, 0x80, 0x00, 0x00, 0x00, 0xAA, 0x19, 0x9A, 0x01, 0xE7, 0xDA, 0x0C, 0x50, 0x15, 0x27, 0x99, 0xC0, 0x16, 0x18, 0xCE, 0x30, 0x17, 0x08, 0xCD, 0x40, 0x17, 0xFA, 0x01, 0xB0, 0x18, 0xEA, 0x00, 0xC0, 0x19, 0xDB, 0x35, 0x30, 0x1A, 0xCC, 0x85, 0xC0, 0x1B, 0xBC, 0x92, 0xE0, 0x1C, 0xAC, 0x83, 0xE0, 0x1D, 0x9C, 0x74, 0xE0, @@ -47360,60 +47417,59 @@ 0x26, 0x0B, 0xED, 0xE0, 0x27, 0x05, 0x19, 0x60, 0x27, 0xF5, 0x0A, 0x60, 0x28, 0xE5, 0x09, 0x70, 0x29, 0xD4, 0xDE, 0x50, 0x2A, 0xC4, 0xC1, 0x40, 0x2B, 0xB4, 0xC0, 0x50, 0x2C, 0xA4, 0xA3, 0x40, 0x2D, 0x94, 0xA2, 0x50, 0x2E, 0x84, 0x85, 0x40, 0x2F, 0x74, 0x76, 0x40, 0x30, 0x64, 0x59, 0x30, -0x31, 0x5D, 0x92, 0xC0, 0x33, 0x3D, 0x66, 0xB0, 0x34, 0x52, 0x41, 0xB0, 0x35, 0x1D, 0x56, 0xC0, -0x36, 0x32, 0x23, 0xB0, 0x36, 0xFD, 0x38, 0xC0, 0x38, 0x1B, 0x40, 0x30, 0x38, 0xDD, 0x1A, 0xC0, -0x39, 0xFB, 0x22, 0x30, 0x3A, 0xBC, 0xFC, 0xC0, 0x3B, 0xDB, 0x04, 0x30, 0x3C, 0xA6, 0x19, 0x40, -0x3D, 0xBA, 0xE6, 0x30, 0x3E, 0x85, 0xFB, 0x40, 0x3F, 0x9A, 0xC8, 0x30, 0x40, 0x65, 0xDD, 0x40, -0x40, 0xDD, 0xC7, 0xB0, 0x41, 0x84, 0x1C, 0xF0, 0x42, 0x45, 0xE9, 0x70, 0x01, 0x02, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, -0x05, 0x06, 0x05, 0x07, 0x08, 0x09, 0x02, 0x09, 0x02, 0x09, 0x04, 0x03, 0x04, 0x03, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x09, 0x08, 0x04, -0x00, 0x00, 0x29, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x04, 0x00, 0x00, 0x2A, 0x30, -0x00, 0x09, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, 0x00, 0x11, 0x00, 0x00, -0x38, 0x40, 0x00, 0x11, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, 0x01, 0x11, -0x00, 0x00, 0x2A, 0x30, 0x00, 0x09, 0x00, 0x00, 0x38, 0x40, 0x01, 0x11, 0x00, 0x00, 0x38, 0x40, -0x00, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x54, 0x42, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, -0x30, 0x35, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, -0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x15, 0xFF, 0xFF, -0xFF, 0xFF, 0x56, 0xB6, 0xBA, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0x19, 0x9A, 0x01, 0xFF, 0xFF, -0xFF, 0xFF, 0xE7, 0xDA, 0x0C, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x27, 0x99, 0xC0, 0x00, 0x00, -0x00, 0x00, 0x16, 0x18, 0xCE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x17, 0x08, 0xCD, 0x40, 0x00, 0x00, -0x00, 0x00, 0x17, 0xFA, 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x18, 0xEA, 0x00, 0xC0, 0x00, 0x00, -0x00, 0x00, 0x19, 0xDB, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xCC, 0x85, 0xC0, 0x00, 0x00, -0x00, 0x00, 0x1B, 0xBC, 0x92, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xAC, 0x83, 0xE0, 0x00, 0x00, -0x00, 0x00, 0x1D, 0x9C, 0x74, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x8C, 0x65, 0xE0, 0x00, 0x00, -0x00, 0x00, 0x1F, 0x7C, 0x56, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6C, 0x47, 0xE0, 0x00, 0x00, -0x00, 0x00, 0x21, 0x5C, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x22, 0x4C, 0x29, 0xE0, 0x00, 0x00, -0x00, 0x00, 0x23, 0x3C, 0x1A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2C, 0x0B, 0xE0, 0x00, 0x00, -0x00, 0x00, 0x25, 0x1B, 0xFC, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0B, 0xED, 0xE0, 0x00, 0x00, -0x00, 0x00, 0x27, 0x05, 0x19, 0x60, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF5, 0x0A, 0x60, 0x00, 0x00, -0x00, 0x00, 0x28, 0xE5, 0x09, 0x70, 0x00, 0x00, 0x00, 0x00, 0x29, 0xD4, 0xDE, 0x50, 0x00, 0x00, -0x00, 0x00, 0x2A, 0xC4, 0xC1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xB4, 0xC0, 0x50, 0x00, 0x00, -0x00, 0x00, 0x2C, 0xA4, 0xA3, 0x40, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xA2, 0x50, 0x00, 0x00, -0x00, 0x00, 0x2E, 0x84, 0x85, 0x40, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0x76, 0x40, 0x00, 0x00, -0x00, 0x00, 0x30, 0x64, 0x59, 0x30, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0x92, 0xC0, 0x00, 0x00, -0x00, 0x00, 0x33, 0x3D, 0x66, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x41, 0xB0, 0x00, 0x00, -0x00, 0x00, 0x35, 0x1D, 0x56, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0x23, 0xB0, 0x00, 0x00, -0x00, 0x00, 0x36, 0xFD, 0x38, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, 0x40, 0x30, 0x00, 0x00, -0x00, 0x00, 0x38, 0xDD, 0x1A, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, 0x22, 0x30, 0x00, 0x00, -0x00, 0x00, 0x3A, 0xBC, 0xFC, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, 0x04, 0x30, 0x00, 0x00, -0x00, 0x00, 0x3C, 0xA6, 0x19, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBA, 0xE6, 0x30, 0x00, 0x00, -0x00, 0x00, 0x3E, 0x85, 0xFB, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9A, 0xC8, 0x30, 0x00, 0x00, -0x00, 0x00, 0x40, 0x65, 0xDD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0xDD, 0xC7, 0xB0, 0x00, 0x00, -0x00, 0x00, 0x41, 0x84, 0x1C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xE9, 0x70, 0x01, 0x02, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, -0x05, 0x06, 0x05, 0x06, 0x05, 0x07, 0x08, 0x09, 0x02, 0x09, 0x02, 0x09, 0x04, 0x03, 0x04, 0x03, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x09, -0x08, 0x04, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x04, 0x00, 0x00, -0x2A, 0x30, 0x00, 0x09, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, 0x00, 0x11, -0x00, 0x00, 0x38, 0x40, 0x00, 0x11, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, -0x01, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x09, 0x00, 0x00, 0x38, 0x40, 0x01, 0x11, 0x00, 0x00, -0x38, 0x40, 0x00, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x54, 0x42, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, -0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, -0x01, 0x01, 0x00, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x34, 0x3E, 0x2D, 0x34, 0x0A, 0x00, 0xC8, 0xFB, -0xD2, 0x01, 0x57, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x00, +0x31, 0x5D, 0x92, 0xC0, 0x34, 0x52, 0x41, 0xB0, 0x35, 0x1D, 0x56, 0xC0, 0x36, 0x32, 0x23, 0xB0, +0x36, 0xFD, 0x38, 0xC0, 0x38, 0x1B, 0x40, 0x30, 0x38, 0xDD, 0x1A, 0xC0, 0x39, 0xFB, 0x22, 0x30, +0x3A, 0xBC, 0xFC, 0xC0, 0x3B, 0xDB, 0x04, 0x30, 0x3C, 0xA6, 0x19, 0x40, 0x3D, 0xBA, 0xE6, 0x30, +0x3E, 0x85, 0xFB, 0x40, 0x3F, 0x9A, 0xC8, 0x30, 0x40, 0x65, 0xDD, 0x40, 0x40, 0xDD, 0xC7, 0xB0, +0x41, 0x84, 0x1C, 0xF0, 0x42, 0x45, 0xE9, 0x70, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, +0x04, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x07, +0x08, 0x09, 0x02, 0x09, 0x02, 0x09, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, +0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x09, 0x08, 0x04, 0x00, 0x00, 0x29, 0xFF, 0x00, +0x00, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x04, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x09, 0x00, 0x00, 0x46, +0x50, 0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, 0x00, 0x11, 0x00, 0x00, 0x38, 0x40, 0x00, 0x11, 0x00, +0x00, 0x46, 0x50, 0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, 0x01, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x00, +0x09, 0x00, 0x00, 0x38, 0x40, 0x01, 0x11, 0x00, 0x00, 0x38, 0x40, 0x00, 0x11, 0x4C, 0x4D, 0x54, +0x00, 0x54, 0x42, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, +0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x54, 0x5A, 0x69, +0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x33, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0x56, 0xB6, 0xBA, +0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0x19, 0x9A, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xDA, 0x0C, +0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x27, 0x99, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0xCE, +0x30, 0x00, 0x00, 0x00, 0x00, 0x17, 0x08, 0xCD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x17, 0xFA, 0x01, +0xB0, 0x00, 0x00, 0x00, 0x00, 0x18, 0xEA, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x19, 0xDB, 0x35, +0x30, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xCC, 0x85, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xBC, 0x92, +0xE0, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xAC, 0x83, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x9C, 0x74, +0xE0, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x8C, 0x65, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x56, +0xE0, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6C, 0x47, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x5C, 0x38, +0xE0, 0x00, 0x00, 0x00, 0x00, 0x22, 0x4C, 0x29, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x23, 0x3C, 0x1A, +0xE0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2C, 0x0B, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1B, 0xFC, +0xE0, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0B, 0xED, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x05, 0x19, +0x60, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF5, 0x0A, 0x60, 0x00, 0x00, 0x00, 0x00, 0x28, 0xE5, 0x09, +0x70, 0x00, 0x00, 0x00, 0x00, 0x29, 0xD4, 0xDE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xC4, 0xC1, +0x40, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xB4, 0xC0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xA4, 0xA3, +0x40, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xA2, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x84, 0x85, +0x40, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0x76, 0x40, 0x00, 0x00, 0x00, 0x00, 0x30, 0x64, 0x59, +0x30, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0x92, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x41, +0xB0, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x56, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0x23, +0xB0, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x38, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, 0x40, +0x30, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x1A, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, 0x22, +0x30, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBC, 0xFC, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, 0x04, +0x30, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x19, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBA, 0xE6, +0x30, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x85, 0xFB, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9A, 0xC8, +0x30, 0x00, 0x00, 0x00, 0x00, 0x40, 0x65, 0xDD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0xDD, 0xC7, +0xB0, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x1C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xE9, +0x70, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x07, 0x08, 0x09, 0x02, 0x09, 0x02, 0x09, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x09, 0x08, 0x04, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x04, +0x00, 0x00, 0x2A, 0x30, 0x00, 0x09, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0D, 0x00, 0x00, 0x38, 0x40, +0x00, 0x11, 0x00, 0x00, 0x38, 0x40, 0x00, 0x11, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0D, 0x00, 0x00, +0x38, 0x40, 0x01, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x09, 0x00, 0x00, 0x38, 0x40, 0x01, 0x11, +0x00, 0x00, 0x38, 0x40, 0x00, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x54, 0x42, 0x4D, 0x54, 0x00, 0x2B, +0x30, 0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x34, 0x3E, 0x2D, 0x34, 0x0A, 0x00, +0xC8, 0xFB, 0xD2, 0x01, 0x57, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x00, /* Asia/Tehran */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x49, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -57363,7 +57419,7 @@ /* Europe/Chisinau */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x4D, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x26, 0x80, 0x00, 0x00, 0x00, 0x9E, 0x6B, 0x9F, 0x0C, 0xB7, 0xB0, 0xD2, 0x08, 0xB9, 0x3E, 0xF3, 0x60, 0xB9, 0xEF, 0x9C, 0x60, 0xBA, 0xDF, 0x8D, 0x60, 0xBB, 0xCF, 0x7E, 0x60, 0xBC, 0xC8, 0xA9, 0xE0, 0xBD, 0xB8, 0x9A, 0xE0, @@ -57392,23 +57448,23 @@ 0x56, 0xF7, 0x22, 0x80, 0x58, 0x15, 0x38, 0x00, 0x58, 0xD7, 0x04, 0x80, 0x59, 0xF5, 0x1A, 0x00, 0x5A, 0xB6, 0xE6, 0x80, 0x5B, 0xD4, 0xFC, 0x00, 0x5C, 0xA0, 0x03, 0x00, 0x5D, 0xB4, 0xDE, 0x00, 0x5E, 0x7F, 0xE5, 0x00, 0x5F, 0x94, 0xC0, 0x00, 0x60, 0x5F, 0xC7, 0x00, 0x61, 0x7D, 0xDC, 0x80, -0x62, 0x3F, 0xA9, 0x00, 0x63, 0x5D, 0xBE, 0x80, 0x64, 0x1F, 0x8B, 0x00, 0x65, 0x3D, 0xA0, 0x80, -0x66, 0x08, 0xA7, 0x80, 0x67, 0x1D, 0x82, 0x80, 0x67, 0xE8, 0x89, 0x80, 0x68, 0xFD, 0x64, 0x80, -0x69, 0xC8, 0x6B, 0x80, 0x6A, 0xDD, 0x46, 0x80, 0x6B, 0xA8, 0x4D, 0x80, 0x6C, 0xC6, 0x63, 0x00, -0x6D, 0x88, 0x2F, 0x80, 0x6E, 0xA6, 0x45, 0x00, 0x6F, 0x68, 0x11, 0x80, 0x70, 0x86, 0x27, 0x00, -0x71, 0x51, 0x2E, 0x00, 0x72, 0x66, 0x09, 0x00, 0x73, 0x31, 0x10, 0x00, 0x74, 0x45, 0xEB, 0x00, -0x75, 0x10, 0xF2, 0x00, 0x76, 0x2F, 0x07, 0x80, 0x76, 0xF0, 0xD4, 0x00, 0x78, 0x0E, 0xE9, 0x80, -0x78, 0xD0, 0xB6, 0x00, 0x79, 0xEE, 0xCB, 0x80, 0x7A, 0xB0, 0x98, 0x00, 0x7B, 0xCE, 0xAD, 0x80, -0x7C, 0x99, 0xB4, 0x80, 0x7D, 0xAE, 0x8F, 0x80, 0x7E, 0x79, 0x96, 0x80, 0x7F, 0x8E, 0x71, 0x80, +0x62, 0x3F, 0xB7, 0x10, 0x63, 0x5D, 0xCC, 0x90, 0x64, 0x1F, 0x99, 0x10, 0x65, 0x3D, 0xAE, 0x90, +0x66, 0x08, 0xB5, 0x90, 0x67, 0x1D, 0x90, 0x90, 0x67, 0xE8, 0x97, 0x90, 0x68, 0xFD, 0x72, 0x90, +0x69, 0xC8, 0x79, 0x90, 0x6A, 0xDD, 0x54, 0x90, 0x6B, 0xA8, 0x5B, 0x90, 0x6C, 0xC6, 0x71, 0x10, +0x6D, 0x88, 0x3D, 0x90, 0x6E, 0xA6, 0x53, 0x10, 0x6F, 0x68, 0x1F, 0x90, 0x70, 0x86, 0x35, 0x10, +0x71, 0x51, 0x3C, 0x10, 0x72, 0x66, 0x17, 0x10, 0x73, 0x31, 0x1E, 0x10, 0x74, 0x45, 0xF9, 0x10, +0x75, 0x11, 0x00, 0x10, 0x76, 0x2F, 0x15, 0x90, 0x76, 0xF0, 0xE2, 0x10, 0x78, 0x0E, 0xF7, 0x90, +0x78, 0xD0, 0xC4, 0x10, 0x79, 0xEE, 0xD9, 0x90, 0x7A, 0xB0, 0xA6, 0x10, 0x7B, 0xCE, 0xBB, 0x90, +0x7C, 0x99, 0xC2, 0x90, 0x7D, 0xAE, 0x9D, 0x90, 0x7E, 0x79, 0xA4, 0x90, 0x7F, 0x8E, 0x7F, 0x90, 0x01, 0x02, 0x05, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x06, 0x09, 0x07, 0x08, 0x07, 0x08, 0x0B, 0x0A, 0x0B, 0x0A, 0x0B, 0x0A, 0x0B, 0x0A, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x06, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, -0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, -0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, -0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x00, 0x00, 0x1B, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x0E, 0x0F, 0x0E, +0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, +0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x00, 0x00, 0x1B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x18, 0x78, 0x00, 0x08, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x15, 0x00, 0x00, 0x1C, @@ -57418,8 +57474,9 @@ 0x00, 0x43, 0x4D, 0x54, 0x00, 0x42, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00, 0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, -0x01, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, +0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x01, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x26, 0xFF, 0xFF, 0xFF, 0xFF, 0x56, 0xB6, 0xC8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x9E, 0x6B, 0x9F, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0xB0, 0xD2, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xB9, 0x3E, 0xF3, 0x60, 0xFF, @@ -57475,32 +57532,32 @@ 0x00, 0x00, 0x00, 0x5B, 0xD4, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xB4, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x94, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xC7, 0x00, 0x00, -0x00, 0x00, 0x00, 0x61, 0x7D, 0xDC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xA9, 0x00, 0x00, -0x00, 0x00, 0x00, 0x63, 0x5D, 0xBE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x8B, 0x00, 0x00, -0x00, 0x00, 0x00, 0x65, 0x3D, 0xA0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x66, 0x08, 0xA7, 0x80, 0x00, -0x00, 0x00, 0x00, 0x67, 0x1D, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x67, 0xE8, 0x89, 0x80, 0x00, -0x00, 0x00, 0x00, 0x68, 0xFD, 0x64, 0x80, 0x00, 0x00, 0x00, 0x00, 0x69, 0xC8, 0x6B, 0x80, 0x00, -0x00, 0x00, 0x00, 0x6A, 0xDD, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xA8, 0x4D, 0x80, 0x00, -0x00, 0x00, 0x00, 0x6C, 0xC6, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x88, 0x2F, 0x80, 0x00, -0x00, 0x00, 0x00, 0x6E, 0xA6, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x68, 0x11, 0x80, 0x00, -0x00, 0x00, 0x00, 0x70, 0x86, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x51, 0x2E, 0x00, 0x00, -0x00, 0x00, 0x00, 0x72, 0x66, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x31, 0x10, 0x00, 0x00, -0x00, 0x00, 0x00, 0x74, 0x45, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x10, 0xF2, 0x00, 0x00, -0x00, 0x00, 0x00, 0x76, 0x2F, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x76, 0xF0, 0xD4, 0x00, 0x00, -0x00, 0x00, 0x00, 0x78, 0x0E, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x78, 0xD0, 0xB6, 0x00, 0x00, -0x00, 0x00, 0x00, 0x79, 0xEE, 0xCB, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xB0, 0x98, 0x00, 0x00, -0x00, 0x00, 0x00, 0x7B, 0xCE, 0xAD, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x99, 0xB4, 0x80, 0x00, -0x00, 0x00, 0x00, 0x7D, 0xAE, 0x8F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x79, 0x96, 0x80, 0x00, -0x00, 0x00, 0x00, 0x7F, 0x8E, 0x71, 0x80, 0x01, 0x02, 0x05, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x00, 0x00, 0x00, 0x61, 0x7D, 0xDC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xB7, 0x10, 0x00, +0x00, 0x00, 0x00, 0x63, 0x5D, 0xCC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x00, +0x00, 0x00, 0x00, 0x65, 0x3D, 0xAE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x66, 0x08, 0xB5, 0x90, 0x00, +0x00, 0x00, 0x00, 0x67, 0x1D, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xE8, 0x97, 0x90, 0x00, +0x00, 0x00, 0x00, 0x68, 0xFD, 0x72, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xC8, 0x79, 0x90, 0x00, +0x00, 0x00, 0x00, 0x6A, 0xDD, 0x54, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xA8, 0x5B, 0x90, 0x00, +0x00, 0x00, 0x00, 0x6C, 0xC6, 0x71, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x88, 0x3D, 0x90, 0x00, +0x00, 0x00, 0x00, 0x6E, 0xA6, 0x53, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x68, 0x1F, 0x90, 0x00, +0x00, 0x00, 0x00, 0x70, 0x86, 0x35, 0x10, 0x00, 0x00, 0x00, 0x00, 0x71, 0x51, 0x3C, 0x10, 0x00, +0x00, 0x00, 0x00, 0x72, 0x66, 0x17, 0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x31, 0x1E, 0x10, 0x00, +0x00, 0x00, 0x00, 0x74, 0x45, 0xF9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, 0x10, 0x00, +0x00, 0x00, 0x00, 0x76, 0x2F, 0x15, 0x90, 0x00, 0x00, 0x00, 0x00, 0x76, 0xF0, 0xE2, 0x10, 0x00, +0x00, 0x00, 0x00, 0x78, 0x0E, 0xF7, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xD0, 0xC4, 0x10, 0x00, +0x00, 0x00, 0x00, 0x79, 0xEE, 0xD9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xB0, 0xA6, 0x10, 0x00, +0x00, 0x00, 0x00, 0x7B, 0xCE, 0xBB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x99, 0xC2, 0x90, 0x00, +0x00, 0x00, 0x00, 0x7D, 0xAE, 0x9D, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x79, 0xA4, 0x90, 0x00, +0x00, 0x00, 0x00, 0x7F, 0x8E, 0x7F, 0x90, 0x01, 0x02, 0x05, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x06, 0x09, 0x07, 0x08, 0x07, 0x08, 0x0B, 0x0A, 0x0B, 0x0A, 0x0B, 0x0A, 0x0B, 0x0A, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x06, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, -0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, -0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, -0x06, 0x05, 0x06, 0x05, 0x00, 0x00, 0x1B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, +0x06, 0x05, 0x06, 0x05, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, +0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, +0x0E, 0x0F, 0x0E, 0x0F, 0x00, 0x00, 0x1B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x18, 0x78, 0x00, 0x08, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x15, 0x00, 0x00, 0x1C, 0x20, 0x01, 0x19, 0x00, 0x00, 0x1C, 0x20, 0x01, 0x19, @@ -57509,10 +57566,11 @@ 0x1C, 0x20, 0x00, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x43, 0x4D, 0x54, 0x00, 0x42, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00, 0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, -0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, -0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, -0x35, 0x2E, 0x30, 0x2F, 0x33, 0x0A, 0x00, 0xD1, 0x0B, 0xA0, 0x01, 0x3E, 0xA7, 0x85, 0x00, 0x00, -0x00, 0x00, +0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, +0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x2C, 0x4D, 0x31, +0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x34, 0x0A, 0x00, 0xD1, 0x0B, 0xA0, 0x01, 0x3E, 0xA7, 0x85, +0x00, 0x00, 0x00, 0x00, /* Europe/Copenhagen */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x44, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -63298,7 +63356,7 @@ /* Europe/Tiraspol */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x26, 0x80, 0x00, 0x00, 0x00, 0x9E, 0x6B, 0x9F, 0x0C, 0xB7, 0xB0, 0xD2, 0x08, 0xB9, 0x3E, 0xF3, 0x60, 0xB9, 0xEF, 0x9C, 0x60, 0xBA, 0xDF, 0x8D, 0x60, 0xBB, 0xCF, 0x7E, 0x60, 0xBC, 0xC8, 0xA9, 0xE0, 0xBD, 0xB8, 0x9A, 0xE0, @@ -63327,23 +63385,23 @@ 0x56, 0xF7, 0x22, 0x80, 0x58, 0x15, 0x38, 0x00, 0x58, 0xD7, 0x04, 0x80, 0x59, 0xF5, 0x1A, 0x00, 0x5A, 0xB6, 0xE6, 0x80, 0x5B, 0xD4, 0xFC, 0x00, 0x5C, 0xA0, 0x03, 0x00, 0x5D, 0xB4, 0xDE, 0x00, 0x5E, 0x7F, 0xE5, 0x00, 0x5F, 0x94, 0xC0, 0x00, 0x60, 0x5F, 0xC7, 0x00, 0x61, 0x7D, 0xDC, 0x80, -0x62, 0x3F, 0xA9, 0x00, 0x63, 0x5D, 0xBE, 0x80, 0x64, 0x1F, 0x8B, 0x00, 0x65, 0x3D, 0xA0, 0x80, -0x66, 0x08, 0xA7, 0x80, 0x67, 0x1D, 0x82, 0x80, 0x67, 0xE8, 0x89, 0x80, 0x68, 0xFD, 0x64, 0x80, -0x69, 0xC8, 0x6B, 0x80, 0x6A, 0xDD, 0x46, 0x80, 0x6B, 0xA8, 0x4D, 0x80, 0x6C, 0xC6, 0x63, 0x00, -0x6D, 0x88, 0x2F, 0x80, 0x6E, 0xA6, 0x45, 0x00, 0x6F, 0x68, 0x11, 0x80, 0x70, 0x86, 0x27, 0x00, -0x71, 0x51, 0x2E, 0x00, 0x72, 0x66, 0x09, 0x00, 0x73, 0x31, 0x10, 0x00, 0x74, 0x45, 0xEB, 0x00, -0x75, 0x10, 0xF2, 0x00, 0x76, 0x2F, 0x07, 0x80, 0x76, 0xF0, 0xD4, 0x00, 0x78, 0x0E, 0xE9, 0x80, -0x78, 0xD0, 0xB6, 0x00, 0x79, 0xEE, 0xCB, 0x80, 0x7A, 0xB0, 0x98, 0x00, 0x7B, 0xCE, 0xAD, 0x80, -0x7C, 0x99, 0xB4, 0x80, 0x7D, 0xAE, 0x8F, 0x80, 0x7E, 0x79, 0x96, 0x80, 0x7F, 0x8E, 0x71, 0x80, +0x62, 0x3F, 0xB7, 0x10, 0x63, 0x5D, 0xCC, 0x90, 0x64, 0x1F, 0x99, 0x10, 0x65, 0x3D, 0xAE, 0x90, +0x66, 0x08, 0xB5, 0x90, 0x67, 0x1D, 0x90, 0x90, 0x67, 0xE8, 0x97, 0x90, 0x68, 0xFD, 0x72, 0x90, +0x69, 0xC8, 0x79, 0x90, 0x6A, 0xDD, 0x54, 0x90, 0x6B, 0xA8, 0x5B, 0x90, 0x6C, 0xC6, 0x71, 0x10, +0x6D, 0x88, 0x3D, 0x90, 0x6E, 0xA6, 0x53, 0x10, 0x6F, 0x68, 0x1F, 0x90, 0x70, 0x86, 0x35, 0x10, +0x71, 0x51, 0x3C, 0x10, 0x72, 0x66, 0x17, 0x10, 0x73, 0x31, 0x1E, 0x10, 0x74, 0x45, 0xF9, 0x10, +0x75, 0x11, 0x00, 0x10, 0x76, 0x2F, 0x15, 0x90, 0x76, 0xF0, 0xE2, 0x10, 0x78, 0x0E, 0xF7, 0x90, +0x78, 0xD0, 0xC4, 0x10, 0x79, 0xEE, 0xD9, 0x90, 0x7A, 0xB0, 0xA6, 0x10, 0x7B, 0xCE, 0xBB, 0x90, +0x7C, 0x99, 0xC2, 0x90, 0x7D, 0xAE, 0x9D, 0x90, 0x7E, 0x79, 0xA4, 0x90, 0x7F, 0x8E, 0x7F, 0x90, 0x01, 0x02, 0x05, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x06, 0x09, 0x07, 0x08, 0x07, 0x08, 0x0B, 0x0A, 0x0B, 0x0A, 0x0B, 0x0A, 0x0B, 0x0A, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x06, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, -0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, -0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, -0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x00, 0x00, 0x1B, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x0E, 0x0F, 0x0E, +0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, +0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x00, 0x00, 0x1B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x18, 0x78, 0x00, 0x08, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x15, 0x00, 0x00, 0x1C, @@ -63353,8 +63411,9 @@ 0x00, 0x43, 0x4D, 0x54, 0x00, 0x42, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00, 0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, -0x01, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, +0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x01, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x26, 0xFF, 0xFF, 0xFF, 0xFF, 0x56, 0xB6, 0xC8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x9E, 0x6B, 0x9F, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0xB0, 0xD2, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xB9, 0x3E, 0xF3, 0x60, 0xFF, @@ -63410,32 +63469,32 @@ 0x00, 0x00, 0x00, 0x5B, 0xD4, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xB4, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x94, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xC7, 0x00, 0x00, -0x00, 0x00, 0x00, 0x61, 0x7D, 0xDC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xA9, 0x00, 0x00, -0x00, 0x00, 0x00, 0x63, 0x5D, 0xBE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x8B, 0x00, 0x00, -0x00, 0x00, 0x00, 0x65, 0x3D, 0xA0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x66, 0x08, 0xA7, 0x80, 0x00, -0x00, 0x00, 0x00, 0x67, 0x1D, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x67, 0xE8, 0x89, 0x80, 0x00, -0x00, 0x00, 0x00, 0x68, 0xFD, 0x64, 0x80, 0x00, 0x00, 0x00, 0x00, 0x69, 0xC8, 0x6B, 0x80, 0x00, -0x00, 0x00, 0x00, 0x6A, 0xDD, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xA8, 0x4D, 0x80, 0x00, -0x00, 0x00, 0x00, 0x6C, 0xC6, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x88, 0x2F, 0x80, 0x00, -0x00, 0x00, 0x00, 0x6E, 0xA6, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x68, 0x11, 0x80, 0x00, -0x00, 0x00, 0x00, 0x70, 0x86, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x51, 0x2E, 0x00, 0x00, -0x00, 0x00, 0x00, 0x72, 0x66, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x31, 0x10, 0x00, 0x00, -0x00, 0x00, 0x00, 0x74, 0x45, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x10, 0xF2, 0x00, 0x00, -0x00, 0x00, 0x00, 0x76, 0x2F, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x76, 0xF0, 0xD4, 0x00, 0x00, -0x00, 0x00, 0x00, 0x78, 0x0E, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x78, 0xD0, 0xB6, 0x00, 0x00, -0x00, 0x00, 0x00, 0x79, 0xEE, 0xCB, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xB0, 0x98, 0x00, 0x00, -0x00, 0x00, 0x00, 0x7B, 0xCE, 0xAD, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x99, 0xB4, 0x80, 0x00, -0x00, 0x00, 0x00, 0x7D, 0xAE, 0x8F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x79, 0x96, 0x80, 0x00, -0x00, 0x00, 0x00, 0x7F, 0x8E, 0x71, 0x80, 0x01, 0x02, 0x05, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x00, 0x00, 0x00, 0x61, 0x7D, 0xDC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xB7, 0x10, 0x00, +0x00, 0x00, 0x00, 0x63, 0x5D, 0xCC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x00, +0x00, 0x00, 0x00, 0x65, 0x3D, 0xAE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x66, 0x08, 0xB5, 0x90, 0x00, +0x00, 0x00, 0x00, 0x67, 0x1D, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xE8, 0x97, 0x90, 0x00, +0x00, 0x00, 0x00, 0x68, 0xFD, 0x72, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xC8, 0x79, 0x90, 0x00, +0x00, 0x00, 0x00, 0x6A, 0xDD, 0x54, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xA8, 0x5B, 0x90, 0x00, +0x00, 0x00, 0x00, 0x6C, 0xC6, 0x71, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x88, 0x3D, 0x90, 0x00, +0x00, 0x00, 0x00, 0x6E, 0xA6, 0x53, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x68, 0x1F, 0x90, 0x00, +0x00, 0x00, 0x00, 0x70, 0x86, 0x35, 0x10, 0x00, 0x00, 0x00, 0x00, 0x71, 0x51, 0x3C, 0x10, 0x00, +0x00, 0x00, 0x00, 0x72, 0x66, 0x17, 0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x31, 0x1E, 0x10, 0x00, +0x00, 0x00, 0x00, 0x74, 0x45, 0xF9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, 0x10, 0x00, +0x00, 0x00, 0x00, 0x76, 0x2F, 0x15, 0x90, 0x00, 0x00, 0x00, 0x00, 0x76, 0xF0, 0xE2, 0x10, 0x00, +0x00, 0x00, 0x00, 0x78, 0x0E, 0xF7, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xD0, 0xC4, 0x10, 0x00, +0x00, 0x00, 0x00, 0x79, 0xEE, 0xD9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xB0, 0xA6, 0x10, 0x00, +0x00, 0x00, 0x00, 0x7B, 0xCE, 0xBB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x99, 0xC2, 0x90, 0x00, +0x00, 0x00, 0x00, 0x7D, 0xAE, 0x9D, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x79, 0xA4, 0x90, 0x00, +0x00, 0x00, 0x00, 0x7F, 0x8E, 0x7F, 0x90, 0x01, 0x02, 0x05, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x06, 0x09, 0x07, 0x08, 0x07, 0x08, 0x0B, 0x0A, 0x0B, 0x0A, 0x0B, 0x0A, 0x0B, 0x0A, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x0C, 0x0D, 0x06, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, -0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, -0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, -0x06, 0x05, 0x06, 0x05, 0x00, 0x00, 0x1B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, +0x06, 0x05, 0x06, 0x05, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, +0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, 0x0E, 0x0F, +0x0E, 0x0F, 0x0E, 0x0F, 0x00, 0x00, 0x1B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x18, 0x78, 0x00, 0x08, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0C, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x15, 0x00, 0x00, 0x1C, 0x20, 0x01, 0x19, 0x00, 0x00, 0x1C, 0x20, 0x01, 0x19, @@ -63444,10 +63503,11 @@ 0x1C, 0x20, 0x00, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x43, 0x4D, 0x54, 0x00, 0x42, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00, 0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, -0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, -0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, -0x35, 0x2E, 0x30, 0x2F, 0x33, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, +0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, +0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x2C, 0x4D, 0x31, +0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x34, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, /* Europe/Ulyanovsk */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -71255,4 +71315,4 @@ }; #endif -const timelib_tzdb timezonedb_builtin = { "2025.3", 598, timezonedb_idx_builtin, timelib_timezone_db_data_builtin }; +const timelib_tzdb timezonedb_builtin = { "2026.1", 598, timezonedb_idx_builtin, timelib_timezone_db_data_builtin }; diff '--color=auto' -Naur php-8.4.18/ext/date/php_date.c php-8.4.20RC1/ext/date/php_date.c --- php-8.4.18/ext/date/php_date.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/date/php_date.c 2026-04-01 04:35:36.003142962 +0000 @@ -795,13 +795,24 @@ case TIMELIB_ZONETYPE_ABBR: length = slprintf(buffer, sizeof(buffer), "%s", offset->abbr); break; - case TIMELIB_ZONETYPE_OFFSET: - length = slprintf(buffer, sizeof(buffer), "%c%02d:%02d", - ((offset->offset < 0) ? '-' : '+'), - abs(offset->offset / 3600), - abs((offset->offset % 3600) / 60) - ); + case TIMELIB_ZONETYPE_OFFSET: { + int seconds = offset->offset % 60; + if (seconds == 0) { + length = slprintf(buffer, sizeof(buffer), "%c%02d:%02d", + ((offset->offset < 0) ? '-' : '+'), + abs(offset->offset / 3600), + abs((offset->offset % 3600) / 60) + ); + } else { + length = slprintf(buffer, sizeof(buffer), "%c%02d:%02d:%02d", + ((offset->offset < 0) ? '-' : '+'), + abs(offset->offset / 3600), + abs((offset->offset % 3600) / 60), + abs(seconds) + ); + } break; + } } } break; @@ -1930,6 +1941,32 @@ return zend_std_get_properties(object); } /* }}} */ +static zend_string *date_create_tz_offset_str(timelib_sll offset) +{ + int seconds = offset % 60; + size_t size; + const char *format; + + if (seconds == 0) { + size = sizeof("+05:00"); + format = "%c%02d:%02d"; + } else { + size = sizeof("+05:00:01"); + format = "%c%02d:%02d:%02d"; + } + + zend_string *tmpstr = zend_string_alloc(size - 1, 0); + + /* Note: if seconds == 0, the seconds argument will be excessive and therefore ignored. */ + ZSTR_LEN(tmpstr) = snprintf(ZSTR_VAL(tmpstr), size, format, + offset < 0 ? '-' : '+', + abs((int)(offset / 3600)), + abs((int)(offset % 3600) / 60), + abs(seconds)); + + return tmpstr; +} + static void date_object_to_hash(php_date_obj *dateobj, HashTable *props) { zval zv; @@ -1947,17 +1984,8 @@ case TIMELIB_ZONETYPE_ID: ZVAL_STRING(&zv, dateobj->time->tz_info->name); break; - case TIMELIB_ZONETYPE_OFFSET: { - zend_string *tmpstr = zend_string_alloc(sizeof("UTC+05:00")-1, 0); - int utc_offset = dateobj->time->z; - - ZSTR_LEN(tmpstr) = snprintf(ZSTR_VAL(tmpstr), sizeof("+05:00"), "%c%02d:%02d", - utc_offset < 0 ? '-' : '+', - abs(utc_offset / 3600), - abs(((utc_offset % 3600) / 60))); - - ZVAL_NEW_STR(&zv, tmpstr); - } + case TIMELIB_ZONETYPE_OFFSET: + ZVAL_NEW_STR(&zv, date_create_tz_offset_str(dateobj->time->z)); break; case TIMELIB_ZONETYPE_ABBR: ZVAL_STRING(&zv, dateobj->time->tz_abbr); @@ -2069,29 +2097,8 @@ case TIMELIB_ZONETYPE_ID: ZVAL_STRING(zv, tzobj->tzi.tz->name); break; - case TIMELIB_ZONETYPE_OFFSET: { - timelib_sll utc_offset = tzobj->tzi.utc_offset; - int seconds = utc_offset % 60; - size_t size; - const char *format; - if (seconds == 0) { - size = sizeof("+05:00"); - format = "%c%02d:%02d"; - } else { - size = sizeof("+05:00:01"); - format = "%c%02d:%02d:%02d"; - } - zend_string *tmpstr = zend_string_alloc(size - 1, 0); - - /* Note: if seconds == 0, the seconds argument will be excessive and therefore ignored. */ - ZSTR_LEN(tmpstr) = snprintf(ZSTR_VAL(tmpstr), size, format, - utc_offset < 0 ? '-' : '+', - abs((int)(utc_offset / 3600)), - abs((int)(utc_offset % 3600) / 60), - abs(seconds)); - - ZVAL_NEW_STR(zv, tmpstr); - } + case TIMELIB_ZONETYPE_OFFSET: + ZVAL_NEW_STR(zv, date_create_tz_offset_str(tzobj->tzi.utc_offset)); break; case TIMELIB_ZONETYPE_ABBR: ZVAL_STRING(zv, tzobj->tzi.z.abbr); @@ -5811,7 +5818,7 @@ php_date_obj *date_obj; date_obj = Z_PHPDATE_P(ht_entry); - if (!date_obj->time) { + if (!date_obj->time || !period_obj->start_ce) { return 0; } @@ -5832,7 +5839,7 @@ php_date_obj *date_obj; date_obj = Z_PHPDATE_P(ht_entry); - if (!date_obj->time) { + if (!date_obj->time || !period_obj->start_ce) { return 0; } diff '--color=auto' -Naur php-8.4.18/ext/date/tests/bug81565.phpt php-8.4.20RC1/ext/date/tests/bug81565.phpt --- php-8.4.18/ext/date/tests/bug81565.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/date/tests/bug81565.phpt 2026-04-01 04:35:36.003518993 +0000 @@ -15,6 +15,6 @@ \DateTime::__set_state(array( 'date' => '0021-08-21 00:00:00.000000', 'timezone_type' => 1, - 'timezone' => '+00:49', + 'timezone' => '+00:49:56', )) +01:45:30 diff '--color=auto' -Naur php-8.4.18/ext/date/tests/gh20764.phpt php-8.4.20RC1/ext/date/tests/gh20764.phpt --- php-8.4.18/ext/date/tests/gh20764.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/date/tests/gh20764.phpt 2026-04-01 04:35:36.003623931 +0000 @@ -0,0 +1,53 @@ +--TEST-- +GH-20764 (Timezone offset with seconds loses precision) +--FILE-- +format('e')); + var_dump($dt); + var_dump(unserialize(serialize($dt))->getTimezone()); +} + +?> +--EXPECTF-- +--- Testing timezone +03:00:30 --- +string(9) "+03:00:30" +object(DateTimeImmutable)#%d (3) { + ["date"]=> + string(26) "2025-04-01 00:00:00.000000" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(9) "+03:00:30" +} +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(9) "+03:00:30" +} +--- Testing timezone -03:00:30 --- +string(9) "-03:00:30" +object(DateTimeImmutable)#%d (3) { + ["date"]=> + string(26) "2025-04-01 00:00:00.000000" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(9) "-03:00:30" +} +object(DateTimeZone)#%d (2) { + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(9) "-03:00:30" +} diff '--color=auto' -Naur php-8.4.18/ext/date/tests/gh20936.phpt php-8.4.20RC1/ext/date/tests/gh20936.phpt --- php-8.4.18/ext/date/tests/gh20936.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/date/tests/gh20936.phpt 2026-04-01 04:35:36.003702640 +0000 @@ -0,0 +1,14 @@ +--TEST-- +GH-20936 (DatePeriod::__set_state() cannot handle null start) +--FILE-- + null, 'end' => $end, 'current' => null, 'interval' => $interval, 'recurrences' => 2, 'include_start_date' => false, 'include_end_date' => true]); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Error: Invalid serialization data for DatePeriod object diff '--color=auto' -Naur php-8.4.18/ext/dom/documenttype.c php-8.4.20RC1/ext/dom/documenttype.c --- php-8.4.18/ext/dom/documenttype.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/documenttype.c 2026-04-01 04:35:36.003837464 +0000 @@ -47,7 +47,7 @@ { DOM_PROP_NODE(xmlDtdPtr, dtdptr, obj); - php_dom_create_iterator(retval, DOM_DTD_NAMEDNODEMAP, php_dom_follow_spec_intern(obj)); + php_dom_create_iterator(retval, DOM_DTD_NAMEDNODEMAP, instanceof_function(obj->std.ce, dom_modern_documenttype_class_entry)); xmlHashTable *entityht = (xmlHashTable *) dtdptr->entities; @@ -68,7 +68,7 @@ { DOM_PROP_NODE(xmlDtdPtr, dtdptr, obj); - php_dom_create_iterator(retval, DOM_DTD_NAMEDNODEMAP, php_dom_follow_spec_intern(obj)); + php_dom_create_iterator(retval, DOM_DTD_NAMEDNODEMAP, instanceof_function(obj->std.ce, dom_modern_documenttype_class_entry)); xmlHashTable *notationht = (xmlHashTable *) dtdptr->notations; diff '--color=auto' -Naur php-8.4.18/ext/dom/dom_properties.h php-8.4.20RC1/ext/dom/dom_properties.h --- php-8.4.18/ext/dom/dom_properties.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/dom_properties.h 2026-04-01 04:35:36.003939257 +0000 @@ -102,6 +102,7 @@ zend_result dom_entity_reference_child_read(dom_object *obj, zval *retval); zend_result dom_entity_reference_text_content_read(dom_object *obj, zval *retval); zend_result dom_entity_reference_child_nodes_read(dom_object *obj, zval *retval); +zend_result dom_modern_entity_reference_child_nodes_read(dom_object *obj, zval *retval); /* namednodemap properties */ zend_result dom_namednodemap_length_read(dom_object *obj, zval *retval); @@ -119,6 +120,7 @@ zend_result dom_node_parent_node_read(dom_object *obj, zval *retval); zend_result dom_node_parent_element_read(dom_object *obj, zval *retval); zend_result dom_node_child_nodes_read(dom_object *obj, zval *retval); +zend_result dom_modern_node_child_nodes_read(dom_object *obj, zval *retval); zend_result dom_node_first_child_read(dom_object *obj, zval *retval); zend_result dom_node_last_child_read(dom_object *obj, zval *retval); zend_result dom_node_previous_sibling_read(dom_object *obj, zval *retval); @@ -134,6 +136,7 @@ zend_result dom_node_prefix_write(dom_object *obj, zval *newval); zend_result dom_node_local_name_read(dom_object *obj, zval *retval); zend_result dom_node_base_uri_read(dom_object *obj, zval *retval); +zend_result dom_modern_node_base_uri_read(dom_object *obj, zval *retval); zend_result dom_node_text_content_read(dom_object *obj, zval *retval); zend_result dom_node_text_content_write(dom_object *obj, zval *newval); diff '--color=auto' -Naur php-8.4.18/ext/dom/entityreference.c php-8.4.20RC1/ext/dom/entityreference.c --- php-8.4.18/ext/dom/entityreference.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/entityreference.c 2026-04-01 04:35:36.004038935 +0000 @@ -106,4 +106,12 @@ return dom_node_child_nodes_read(obj, retval); } +zend_result dom_modern_entity_reference_child_nodes_read(dom_object *obj, zval *retval) +{ + DOM_PROP_NODE(xmlNodePtr, nodep, obj); + + dom_entity_reference_fetch_and_sync_declaration(nodep); + return dom_modern_node_child_nodes_read(obj, retval); +} + #endif diff '--color=auto' -Naur php-8.4.18/ext/dom/html5_parser.c php-8.4.20RC1/ext/dom/html5_parser.c --- php-8.4.18/ext/dom/html5_parser.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/html5_parser.c 2026-04-01 04:35:36.004124116 +0000 @@ -117,6 +117,7 @@ php_dom_libxml_ns_mapper *ns_mapper = php_dom_ns_mapper_from_private(private_data); xmlNsPtr html_ns = php_dom_libxml_ns_mapper_ensure_html_ns(ns_mapper); xmlNsPtr xlink_ns = NULL; + xmlNsPtr xml_ns = NULL; xmlNsPtr prefixed_xmlns_ns = NULL; lexbor_array_obj_t work_list; @@ -256,6 +257,12 @@ xlink_ns->_private = (void *) php_dom_ns_is_xlink_magic_token; } lxml_attr->ns = xlink_ns; + } else if (attr->node.ns == LXB_NS_XML) { + if (xml_ns == NULL) { + xml_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xml", DOM_XML_NS_URI); + xml_ns->_private = (void *) php_dom_ns_is_xml_magic_token; + } + lxml_attr->ns = xml_ns; } if (last_added_attr == NULL) { diff '--color=auto' -Naur php-8.4.18/ext/dom/node.c php-8.4.20RC1/ext/dom/node.c --- php-8.4.18/ext/dom/node.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/node.c 2026-04-01 04:35:36.004292043 +0000 @@ -287,7 +287,18 @@ { DOM_PROP_NODE(xmlNodePtr, nodep, obj); - php_dom_create_iterator(retval, DOM_NODELIST, php_dom_follow_spec_intern(obj)); + php_dom_create_iterator(retval, DOM_NODELIST, false); + dom_object *intern = Z_DOMOBJ_P(retval); + dom_namednode_iter(obj, XML_ELEMENT_NODE, intern, NULL, NULL, 0, NULL, 0); + + return SUCCESS; +} + +zend_result dom_modern_node_child_nodes_read(dom_object *obj, zval *retval) +{ + DOM_PROP_NODE(xmlNodePtr, nodep, obj); + + php_dom_create_iterator(retval, DOM_NODELIST, true); dom_object *intern = Z_DOMOBJ_P(retval); dom_namednode_iter(obj, XML_ELEMENT_NODE, intern, NULL, NULL, 0, NULL, 0); @@ -659,14 +670,25 @@ ZVAL_STRING(retval, (const char *) baseuri); xmlFree(baseuri); } else { - if (php_dom_follow_spec_intern(obj)) { - if (nodep->doc->URL) { - ZVAL_STRING(retval, (const char *) nodep->doc->URL); - } else { - ZVAL_STRING(retval, "about:blank"); - } + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +zend_result dom_modern_node_base_uri_read(dom_object *obj, zval *retval) +{ + DOM_PROP_NODE(xmlNodePtr, nodep, obj); + + xmlChar *baseuri = xmlNodeGetBase(nodep->doc, nodep); + if (baseuri) { + ZVAL_STRING(retval, (const char *) baseuri); + xmlFree(baseuri); + } else { + if (nodep->doc && nodep->doc->URL) { + ZVAL_STRING(retval, (const char *) nodep->doc->URL); } else { - ZVAL_NULL(retval); + ZVAL_STRING(retval, "about:blank"); } } diff '--color=auto' -Naur php-8.4.18/ext/dom/php_dom.c php-8.4.20RC1/ext/dom/php_dom.c --- php-8.4.18/ext/dom/php_dom.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/php_dom.c 2026-04-01 04:35:36.004564107 +0000 @@ -892,12 +892,12 @@ zend_hash_init(&dom_modern_node_prop_handlers, 0, NULL, NULL, true); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "nodeType", dom_node_node_type_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "nodeName", dom_node_node_name_read, NULL); - DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "baseURI", dom_node_base_uri_read, NULL); + DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "baseURI", dom_modern_node_base_uri_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "isConnected", dom_node_is_connected_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "ownerDocument", dom_node_owner_document_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "parentNode", dom_node_parent_node_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "parentElement", dom_node_parent_element_read, NULL); - DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "childNodes", dom_node_child_nodes_read, NULL); + DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "childNodes", dom_modern_node_child_nodes_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "firstChild", dom_node_first_child_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "lastChild", dom_node_last_child_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_modern_node_prop_handlers, "previousSibling", dom_node_previous_sibling_read, NULL); @@ -1294,7 +1294,7 @@ DOM_OVERWRITE_PROP_HANDLER(&dom_modern_entity_reference_prop_handlers, "firstChild", dom_entity_reference_child_read, NULL); DOM_OVERWRITE_PROP_HANDLER(&dom_modern_entity_reference_prop_handlers, "lastChild", dom_entity_reference_child_read, NULL); DOM_OVERWRITE_PROP_HANDLER(&dom_modern_entity_reference_prop_handlers, "textContent", dom_entity_reference_text_content_read, NULL); - DOM_OVERWRITE_PROP_HANDLER(&dom_modern_entity_reference_prop_handlers, "childNodes", dom_entity_reference_child_nodes_read, NULL); + DOM_OVERWRITE_PROP_HANDLER(&dom_modern_entity_reference_prop_handlers, "childNodes", dom_modern_entity_reference_child_nodes_read, NULL); zend_hash_add_new_ptr(&classes, dom_modern_entityreference_class_entry->name, &dom_modern_entity_reference_prop_handlers); dom_processinginstruction_class_entry = register_class_DOMProcessingInstruction(dom_node_class_entry); diff '--color=auto' -Naur php-8.4.18/ext/dom/tests/modern/common/gh21077.phpt php-8.4.20RC1/ext/dom/tests/modern/common/gh21077.phpt --- php-8.4.18/ext/dom/tests/modern/common/gh21077.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/dom/tests/modern/common/gh21077.phpt 2026-04-01 04:35:36.004787860 +0000 @@ -0,0 +1,28 @@ +--TEST-- +GH-21077 (Accessing Dom\Node::baseURI can throw TypeError) +--EXTENSIONS-- +dom +--CREDITS-- +mbeccati +--FILE-- +createDocumentType('html', 'publicId', 'systemId'); + +var_dump($node->baseURI); + +$dom = Dom\XMLDocument::createEmpty(); +$dom->append($node = $dom->importNode($node)); + +var_dump($dom->saveXML()); + +var_dump($node->baseURI); + +?> +--EXPECT-- +string(11) "about:blank" +string(84) " + +" +string(11) "about:blank" diff '--color=auto' -Naur php-8.4.18/ext/dom/tests/modern/common/gh21097.phpt php-8.4.20RC1/ext/dom/tests/modern/common/gh21097.phpt --- php-8.4.18/ext/dom/tests/modern/common/gh21097.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/dom/tests/modern/common/gh21097.phpt 2026-04-01 04:35:36.004853194 +0000 @@ -0,0 +1,49 @@ +--TEST-- +GH-21097 (Accessing Dom\Node properties can can throw TypeError(s)) +--EXTENSIONS-- +dom +--CREDITS-- +mbeccati +--FILE-- +createDocumentType('html', 'publicId', 'systemId'); + +$r = new \ReflectionClass($node); +foreach ($r->getProperties(\ReflectionProperty::IS_PUBLIC) as $p) { + echo $p->getName(), ": "; + var_dump($node->{$p->getName()}); +} + +?> +--EXPECT-- +nodeType: int(10) +nodeName: string(4) "html" +baseURI: string(11) "about:blank" +isConnected: bool(false) +ownerDocument: NULL +parentNode: NULL +parentElement: NULL +childNodes: object(Dom\NodeList)#24 (1) { + ["length"]=> + int(0) +} +firstChild: NULL +lastChild: NULL +previousSibling: NULL +nextSibling: NULL +nodeValue: NULL +textContent: string(0) "" +name: string(4) "html" +entities: object(Dom\DtdNamedNodeMap)#24 (1) { + ["length"]=> + int(0) +} +notations: object(Dom\DtdNamedNodeMap)#24 (1) { + ["length"]=> + int(0) +} +publicId: string(8) "publicId" +systemId: string(8) "systemId" +internalSubset: NULL diff '--color=auto' -Naur php-8.4.18/ext/dom/tests/modern/html/parser/gh21486.phpt php-8.4.20RC1/ext/dom/tests/modern/html/parser/gh21486.phpt --- php-8.4.18/ext/dom/tests/modern/html/parser/gh21486.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/dom/tests/modern/html/parser/gh21486.phpt 2026-04-01 04:35:36.004970495 +0000 @@ -0,0 +1,18 @@ +--TEST-- +GH-21486 (Dom\HTMLDocument parser mangles xml:space and xml:lang attributes) +--EXTENSIONS-- +dom +--CREDITS-- +JKingweb +--FILE-- +"); +$e = $d->getElementsByTagName("div")[0]; +$e->innerHTML = ''; +$svg = $d->querySelector("svg"); +echo $e->innerHTML."\n"; +echo $svg->attributes[0]->localName." ".var_export($svg->attributes[0]->namespaceURI, true)."\n"; +?> +--EXPECT-- + +space 'http://www.w3.org/XML/1998/namespace' diff '--color=auto' -Naur php-8.4.18/ext/dom/tests/modern/spec/Document_implementation_createDocumentType.phpt php-8.4.20RC1/ext/dom/tests/modern/spec/Document_implementation_createDocumentType.phpt --- php-8.4.18/ext/dom/tests/modern/spec/Document_implementation_createDocumentType.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/tests/modern/spec/Document_implementation_createDocumentType.phpt 2026-04-01 04:35:36.005080072 +0000 @@ -43,7 +43,7 @@ ["nodeName"]=> string(5) "qname" ["baseURI"]=> - NULL + string(11) "about:blank" ["isConnected"]=> bool(false) ["parentNode"]=> @@ -86,7 +86,7 @@ ["nodeName"]=> string(5) "qname" ["baseURI"]=> - NULL + string(11) "about:blank" ["isConnected"]=> bool(false) ["parentNode"]=> @@ -129,7 +129,7 @@ ["nodeName"]=> string(5) "qname" ["baseURI"]=> - NULL + string(11) "about:blank" ["isConnected"]=> bool(false) ["parentNode"]=> @@ -172,7 +172,7 @@ ["nodeName"]=> string(5) "qname" ["baseURI"]=> - NULL + string(11) "about:blank" ["isConnected"]=> bool(false) ["parentNode"]=> diff '--color=auto' -Naur php-8.4.18/ext/dom/tests/modern/xml/DTDNamedNodeMap.phpt php-8.4.20RC1/ext/dom/tests/modern/xml/DTDNamedNodeMap.phpt --- php-8.4.18/ext/dom/tests/modern/xml/DTDNamedNodeMap.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/tests/modern/xml/DTDNamedNodeMap.phpt 2026-04-01 04:35:36.005163149 +0000 @@ -148,7 +148,7 @@ ["nodeName"]=> string(3) "GIF" ["baseURI"]=> - NULL + string(11) "about:blank" ["isConnected"]=> bool(false) ["parentNode"]=> diff '--color=auto' -Naur php-8.4.18/ext/dom/tests/parentnode_childnode_too_long_text.phpt php-8.4.20RC1/ext/dom/tests/parentnode_childnode_too_long_text.phpt --- php-8.4.18/ext/dom/tests/parentnode_childnode_too_long_text.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/dom/tests/parentnode_childnode_too_long_text.phpt 2026-04-01 04:35:36.005236287 +0000 @@ -6,6 +6,7 @@ memory_limit=-1 --SKIPIF-- pointer.type); } if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { - if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { - zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name)); - return &EG(uninitialized_zval); - } + zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name)); + return &EG(uninitialized_zval); } field = zend_hash_find_ptr(&type->record.fields, field_name); @@ -1334,10 +1332,8 @@ type = ZEND_FFI_TYPE(type->pointer.type); } if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { - if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { - zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name)); - return value; - } + zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name)); + return value; } field = zend_hash_find_ptr(&type->record.fields, field_name); @@ -3069,17 +3065,7 @@ FFI_G(default_type_attr) = ZEND_FFI_ATTR_STORED; if (zend_ffi_parse_decl(ZSTR_VAL(code), ZSTR_LEN(code)) == FAILURE) { - if (FFI_G(symbols)) { - zend_hash_destroy(FFI_G(symbols)); - efree(FFI_G(symbols)); - FFI_G(symbols) = NULL; - } - if (FFI_G(tags)) { - zend_hash_destroy(FFI_G(tags)); - efree(FFI_G(tags)); - FFI_G(tags) = NULL; - } - RETURN_THROWS(); + goto cleanup; } if (FFI_G(symbols)) { @@ -3091,7 +3077,7 @@ addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name)); if (!addr) { zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name)); - RETURN_THROWS(); + goto cleanup; } sym->addr = addr; } else if (sym->kind == ZEND_FFI_SYM_FUNC) { @@ -3101,7 +3087,7 @@ zend_string_release(mangled_name); if (!addr) { zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name)); - RETURN_THROWS(); + goto cleanup; } sym->addr = addr; } @@ -3118,6 +3104,22 @@ FFI_G(tags) = NULL; RETURN_OBJ(&ffi->std); + +cleanup: + if (lib && handle) { + DL_UNLOAD(handle); + } + if (FFI_G(symbols)) { + zend_hash_destroy(FFI_G(symbols)); + efree(FFI_G(symbols)); + FFI_G(symbols) = NULL; + } + if (FFI_G(tags)) { + zend_hash_destroy(FFI_G(tags)); + efree(FFI_G(tags)); + FFI_G(tags) = NULL; + } + RETURN_THROWS(); } /* }}} */ diff '--color=auto' -Naur php-8.4.18/ext/ffi/tests/gh14286_2.phpt php-8.4.20RC1/ext/ffi/tests/gh14286_2.phpt --- php-8.4.18/ext/ffi/tests/gh14286_2.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/ffi/tests/gh14286_2.phpt 2026-04-01 04:35:36.005895463 +0000 @@ -2,10 +2,6 @@ GH-14286 (ffi enum type (when enum has no name) make memory leak) --EXTENSIONS-- ffi ---SKIPIF-- - --INI-- ffi.enable=1 --FILE-- diff '--color=auto' -Naur php-8.4.18/ext/ffi/tests/gh18629_cdef_resolve_func.phpt php-8.4.20RC1/ext/ffi/tests/gh18629_cdef_resolve_func.phpt --- php-8.4.18/ext/ffi/tests/gh18629_cdef_resolve_func.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/ffi/tests/gh18629_cdef_resolve_func.phpt 2026-04-01 04:35:36.005985062 +0000 @@ -0,0 +1,16 @@ +--TEST-- +GH-18629 (FFI::cdef() leaks on function resolution failure) +--EXTENSIONS-- +ffi +--INI-- +ffi.enable=1 +--FILE-- +getMessage() . "\n"; +} +?> +--EXPECT-- +Failed resolving C function 'nonexistent_ffi_test_func' diff '--color=auto' -Naur php-8.4.18/ext/ffi/tests/gh18629_read_field_non_struct.phpt php-8.4.20RC1/ext/ffi/tests/gh18629_read_field_non_struct.phpt --- php-8.4.18/ext/ffi/tests/gh18629_read_field_non_struct.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/ffi/tests/gh18629_read_field_non_struct.phpt 2026-04-01 04:35:36.006051738 +0000 @@ -0,0 +1,17 @@ +--TEST-- +GH-18629 (Read field of non C struct/union) +--EXTENSIONS-- +ffi +--INI-- +ffi.enable=1 +--FILE-- +new("int*"); +try { + $y = $x->foo; +} catch (\FFI\Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Attempt to read field 'foo' of non C struct/union diff '--color=auto' -Naur php-8.4.18/ext/filter/logical_filters.c php-8.4.20RC1/ext/filter/logical_filters.c --- php-8.4.18/ext/filter/logical_filters.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/filter/logical_filters.c 2026-04-01 04:35:36.006187675 +0000 @@ -723,7 +723,7 @@ } /* }}} */ -static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{ */ +static int _php_filter_validate_ipv4(const char *str, size_t str_len, int *ip) /* {{{ */ { const char *end = str + str_len; int num, m; @@ -764,7 +764,7 @@ int blocks = 0; unsigned int num, n; int i; - char *ipv4; + const char *ipv4; const char *end; int ip4elm[4]; const char *s = str; diff '--color=auto' -Naur php-8.4.18/ext/gd/libgd/gd_jpeg.c php-8.4.20RC1/ext/gd/libgd/gd_jpeg.c --- php-8.4.18/ext/gd/libgd/gd_jpeg.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/gd/libgd/gd_jpeg.c 2026-04-01 04:35:36.006338480 +0000 @@ -125,6 +125,10 @@ return "9 compatible"; break; + case 100: + return "10 compatible"; + break; + default: return "unknown"; } diff '--color=auto' -Naur php-8.4.18/ext/gd/tests/bug77270.phpt php-8.4.20RC1/ext/gd/tests/bug77270.phpt --- php-8.4.18/ext/gd/tests/bug77270.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/gd/tests/bug77270.phpt 2026-04-01 04:35:36.006463797 +0000 @@ -1,7 +1,5 @@ --TEST-- Bug #77270 (imagecolormatch Out Of Bounds Write on Heap) ---INI-- -memory_limit=-1 --EXTENSIONS-- gd --SKIPIF-- diff '--color=auto' -Naur php-8.4.18/ext/gd/tests/bug77272.phpt php-8.4.20RC1/ext/gd/tests/bug77272.phpt --- php-8.4.18/ext/gd/tests/bug77272.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/gd/tests/bug77272.phpt 2026-04-01 04:35:36.006530563 +0000 @@ -6,6 +6,7 @@ gd --SKIPIF-- --INI-- diff '--color=auto' -Naur php-8.4.18/ext/gd/tests/gh16322.phpt php-8.4.20RC1/ext/gd/tests/gh16322.phpt --- php-8.4.18/ext/gd/tests/gh16322.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/gd/tests/gh16322.phpt 2026-04-01 04:35:36.006683772 +0000 @@ -2,8 +2,6 @@ GH-16322 (imageaffine overflow/underflow on affine matrix) --EXTENSIONS-- gd ---INI-- -memory_limit=-1 --FILE-- op & PHP_OUTPUT_HANDLER_CLEAN) || ((output_context->op & PHP_OUTPUT_HANDLER_START) && !(output_context->op & PHP_OUTPUT_HANDLER_FINAL)))) { size_t len; - char *p = strstr(get_output_encoding(), "//"); + const char *p = strstr(get_output_encoding(), "//"); if (p) { len = spprintf(&content_type, 0, "Content-Type:%.*s; charset=%.*s", mimetype_len ? mimetype_len : (int) strlen(mimetype), mimetype, (int) (p - get_output_encoding()), get_output_encoding()); @@ -2577,7 +2577,7 @@ { php_stream_filter *retval = NULL; php_iconv_stream_filter *inst; - char *from_charset = NULL, *to_charset = NULL; + const char *from_charset = NULL, *to_charset = NULL; size_t from_charset_len, to_charset_len; if ((from_charset = strchr(name, '.')) == NULL) { diff '--color=auto' -Naur php-8.4.18/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt php-8.4.20RC1/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt --- php-8.4.18/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt 2026-04-01 04:35:36.007008837 +0000 @@ -6,6 +6,7 @@ memory_limit=-1 --SKIPIF-- diff '--color=auto' -Naur php-8.4.18/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt php-8.4.20RC1/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt --- php-8.4.18/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt 2026-04-01 04:35:36.007070102 +0000 @@ -6,6 +6,7 @@ memory_limit=-1 --SKIPIF-- diff '--color=auto' -Naur php-8.4.18/ext/mbstring/mbstring.c php-8.4.20RC1/ext/mbstring/mbstring.c --- php-8.4.18/ext/mbstring/mbstring.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/mbstring/mbstring.c 2026-04-01 04:35:36.007301119 +0000 @@ -3376,8 +3376,9 @@ return *elist; } - /* Allocate on stack; when we return, this array is automatically freed */ - struct candidate *array = alloca(elist_size * sizeof(struct candidate)); + /* Allocate on stack or heap */ + ALLOCA_FLAG(use_heap) + struct candidate *array = do_alloca(elist_size * sizeof(struct candidate), use_heap); elist_size = init_candidate_array(array, elist_size, elist, strings, str_lengths, n, strict, order_significant); while (n--) { @@ -3385,6 +3386,7 @@ elist_size = count_demerits(array, elist_size, strict); if (elist_size == 0) { /* All candidates were eliminated */ + free_alloca(array, use_heap); return NULL; } } @@ -3396,7 +3398,10 @@ best = i; } } - return array[best].enc; + + const mbfl_encoding *result = array[best].enc; + free_alloca(array, use_heap); + return result; } /* When doing 'strict' detection, any string which is invalid in the candidate encoding diff '--color=auto' -Naur php-8.4.18/ext/mbstring/tests/gh20836_stack_limit.phpt php-8.4.20RC1/ext/mbstring/tests/gh20836_stack_limit.phpt --- php-8.4.18/ext/mbstring/tests/gh20836_stack_limit.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/mbstring/tests/gh20836_stack_limit.phpt 2026-04-01 04:35:36.007676358 +0000 @@ -12,7 +12,7 @@ } ?> --INI-- -zend.max_allowed_stack_size=128K +zend.max_allowed_stack_size=256K --FILE-- +--EXPECT-- +string(5) "UTF-8" +Done diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_aarch64.dasc php-8.4.20RC1/ext/opcache/jit/ir/ir_aarch64.dasc --- php-8.4.18/ext/opcache/jit/ir/ir_aarch64.dasc 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_aarch64.dasc 2026-04-01 04:35:36.008443898 +0000 @@ -60,7 +60,7 @@ #define ADR_IMM (1<<20) // signed imm21 #define ADRP_IMM (1LL<<32) // signed imm21 * 4096 -static bool aarch64_may_use_b(ir_code_buffer *code_buffer, const void *addr) +static bool aarch64_may_use_b(const ir_code_buffer *code_buffer, const void *addr) { if (code_buffer) { if (addr >= code_buffer->start && (char*)addr < (char*)code_buffer->end) { @@ -824,6 +824,34 @@ } } +static bool all_usages_are_fusable(ir_ctx *ctx, ir_ref ref) +{ + ir_insn *insn = &ctx->ir_base[ref]; + + if (insn->op >= IR_EQ && insn->op <= IR_UNORDERED) { + ir_use_list *use_list = &ctx->use_lists[ref]; + ir_ref n = use_list->count; + + if (n > 0) { + ir_ref *p = ctx->use_edges + use_list->refs; + + do { + insn = &ctx->ir_base[*p]; + if (insn->op != IR_IF + && insn->op != IR_GUARD + && insn->op != IR_GUARD_NOT) { + return 0; + } + p++; + n--; + } while (n); + return 1; + } + } + return 0; +} + + static uint32_t ir_match_insn(ir_ctx *ctx, ir_ref ref) { ir_insn *op2_insn; @@ -1145,7 +1173,7 @@ return IR_RETURN_FP; } case IR_IF: - if (!IR_IS_CONST_REF(insn->op2) && ctx->use_lists[insn->op2].count == 1) { + if (!IR_IS_CONST_REF(insn->op2) && (ctx->use_lists[insn->op2].count == 1 || all_usages_are_fusable(ctx, insn->op2))) { op2_insn = &ctx->ir_base[insn->op2]; if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UNORDERED) { if (IR_IS_TYPE_INT(ctx->ir_base[op2_insn->op1].type)) { @@ -1168,13 +1196,13 @@ } case IR_GUARD: case IR_GUARD_NOT: - if (!IR_IS_CONST_REF(insn->op2) && ctx->use_lists[insn->op2].count == 1) { + if (!IR_IS_CONST_REF(insn->op2) && (ctx->use_lists[insn->op2].count == 1 || all_usages_are_fusable(ctx, insn->op2))) { op2_insn = &ctx->ir_base[insn->op2]; - if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UNORDERED + if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UNORDERED) { // TODO: register allocator may clobber operands of CMP before they are used in the GUARD_CMP - && (insn->op2 == ref - 1 || - (insn->op2 == ctx->prev_ref[ref] - 1 - && ctx->ir_base[ctx->prev_ref[ref]].op == IR_SNAPSHOT))) { +//??? && (insn->op2 == ref - 1 || +//??? (insn->op2 == ctx->prev_ref[ref] - 1 +//??? && ctx->ir_base[ctx->prev_ref[ref]].op == IR_SNAPSHOT))) { if (IR_IS_TYPE_INT(ctx->ir_base[op2_insn->op1].type)) { ctx->rules[insn->op2] = IR_FUSED | IR_CMP_INT; return IR_GUARD_CMP_INT; @@ -3084,7 +3112,7 @@ } } -static ir_op ir_emit_cmp_fp_common(ir_ctx *ctx, ir_ref cmp_ref, ir_insn *cmp_insn) +static ir_op ir_emit_cmp_fp_common(ir_ctx *ctx, ir_ref root, ir_ref cmp_ref, ir_insn *cmp_insn) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; @@ -3093,16 +3121,12 @@ ir_ref op1, op2; ir_reg op1_reg, op2_reg; - if (op == IR_LT || op == IR_LE) { - /* swap operands to avoid P flag check */ - op ^= 3; - op1 = cmp_insn->op2; - op2 = cmp_insn->op1; - op1_reg = ctx->regs[cmp_ref][2]; - op2_reg = ctx->regs[cmp_ref][1]; + op1 = cmp_insn->op1; + op2 = cmp_insn->op2; + if (UNEXPECTED(ctx->rules[cmp_ref] & IR_FUSED_REG)) { + op1_reg = ir_get_fused_reg(ctx, root, cmp_ref * sizeof(ir_ref) + 1); + op2_reg = ir_get_fused_reg(ctx, root, cmp_ref * sizeof(ir_ref) + 2); } else { - op1 = cmp_insn->op1; - op2 = cmp_insn->op2; op1_reg = ctx->regs[cmp_ref][1]; op2_reg = ctx->regs[cmp_ref][2]; } @@ -3131,7 +3155,7 @@ { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; - ir_op op = ir_emit_cmp_fp_common(ctx, def, insn); + ir_op op = ir_emit_cmp_fp_common(ctx, def, def, insn); ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); //??? ir_reg tmp_reg = ctx->regs[def][3]; // TODO: take into account vs flag @@ -3348,8 +3372,15 @@ ir_type type = ctx->ir_base[cmp_insn->op1].type; ir_ref op1 = cmp_insn->op1; ir_ref op2 = cmp_insn->op2; - ir_reg op1_reg = ctx->regs[insn->op2][1]; - ir_reg op2_reg = ctx->regs[insn->op2][2]; + ir_reg op1_reg, op2_reg; + + if (UNEXPECTED(ctx->rules[insn->op2] & IR_FUSED_REG)) { + op1_reg = ir_get_fused_reg(ctx, def, insn->op2 * sizeof(ir_ref) + 1); + op2_reg = ir_get_fused_reg(ctx, def, insn->op2 * sizeof(ir_ref) + 2); + } else { + op1_reg = ctx->regs[insn->op2][1]; + op2_reg = ctx->regs[insn->op2][2]; + } if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { op1_reg = IR_REG_NUM(op1_reg); @@ -3390,7 +3421,7 @@ static void ir_emit_cmp_and_branch_fp(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn, uint32_t next_block) { - ir_op op = ir_emit_cmp_fp_common(ctx, insn->op2, &ctx->ir_base[insn->op2]); + ir_op op = ir_emit_cmp_fp_common(ctx, def, insn->op2, &ctx->ir_base[insn->op2]); ir_emit_jcc(ctx, b, def, insn, next_block, op, 0); } @@ -3459,14 +3490,14 @@ op3_reg = op2_reg; } } - if (op3 != op2 && IR_REG_SPILLED(op3_reg)) { + if (IR_REG_SPILLED(op3_reg)) { op3_reg = IR_REG_NUM(op3_reg); ir_emit_load(ctx, type, op3_reg, op3); - if (op1 == op2) { + if (op1 == op3) { op1_reg = op3_reg; } } - if (op1 != op2 && op1 != op3 && IR_REG_SPILLED(op1_reg)) { + if (IR_REG_SPILLED(op1_reg)) { op1_reg = IR_REG_NUM(op1_reg); ir_emit_load(ctx, op1_type, op1_reg, op1); } @@ -5682,9 +5713,16 @@ ir_type type = ctx->ir_base[cmp_insn->op1].type; ir_ref op1 = cmp_insn->op1; ir_ref op2 = cmp_insn->op2; - ir_reg op1_reg = ctx->regs[insn->op2][1]; - ir_reg op2_reg = ctx->regs[insn->op2][2]; void *addr; + ir_reg op1_reg, op2_reg; + + if (UNEXPECTED(ctx->rules[insn->op2] & IR_FUSED_REG)) { + op1_reg = ir_get_fused_reg(ctx, def, insn->op2 * sizeof(ir_ref) + 1); + op2_reg = ir_get_fused_reg(ctx, def, insn->op2 * sizeof(ir_ref) + 2); + } else { + op1_reg = ctx->regs[insn->op2][1]; + op2_reg = ctx->regs[insn->op2][2]; + } if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { op1_reg = IR_REG_NUM(op1_reg); @@ -5738,7 +5776,7 @@ static void ir_emit_guard_cmp_fp(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn) { - ir_op op = ir_emit_cmp_fp_common(ctx, insn->op2, &ctx->ir_base[insn->op2]); + ir_op op = ir_emit_cmp_fp_common(ctx, def, insn->op2, &ctx->ir_base[insn->op2]); void *addr = ir_jmp_addr(ctx, insn, &ctx->ir_base[insn->op3]); if (insn->op == IR_GUARD) { @@ -7143,7 +7181,7 @@ return n; } -bool ir_needs_thunk(ir_code_buffer *code_buffer, void *addr) +bool ir_needs_thunk(const ir_code_buffer *code_buffer, void *addr) { return !aarch64_may_use_b(code_buffer, addr); } diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir.c php-8.4.20RC1/ext/opcache/jit/ir/ir.c --- php-8.4.18/ext/opcache/jit/ir/ir.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir.c 2026-04-01 04:35:36.007920439 +0000 @@ -858,7 +858,7 @@ static ir_ref _ir_fold_cse(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3) { ir_ref ref = ctx->prev_insn_chain[opt & IR_OPT_OP_MASK]; - ir_insn *insn; + const ir_insn *insn; if (ref) { ir_ref limit = ctx->fold_cse_limit; @@ -954,7 +954,8 @@ * ANY and UNUSED ops are represented by 0 */ -ir_ref ir_folding(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3, ir_insn *op1_insn, ir_insn *op2_insn, ir_insn *op3_insn) +ir_ref ir_folding(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3, + const ir_insn *op1_insn, const ir_insn *op2_insn, const ir_insn *op3_insn) { uint8_t op; ir_ref ref; @@ -1136,9 +1137,9 @@ ir_insn_set_op(insn, n, val); } -ir_ref ir_get_op(ir_ctx *ctx, ir_ref ref, int32_t n) +ir_ref ir_get_op(const ir_ctx *ctx, ir_ref ref, int32_t n) { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; #ifdef IR_DEBUG if (n > 3) { @@ -1419,13 +1420,21 @@ if (old_size < new_size) { /* Reallocate the whole edges buffer (this is inefficient) */ ctx->use_edges = ir_mem_realloc(ctx->use_edges, new_size); + if (n == ctx->use_edges_count) { + ctx->use_edges[n] = ref; + use_list->count++; + ctx->use_edges_count++; + return 1; + } } else if (n == ctx->use_edges_count) { ctx->use_edges[n] = ref; use_list->count++; ctx->use_edges_count++; return 0; } - memcpy(ctx->use_edges + ctx->use_edges_count, ctx->use_edges + use_list->refs, use_list->count * sizeof(ir_ref)); + if (use_list->count) { + memcpy(ctx->use_edges + ctx->use_edges_count, ctx->use_edges + use_list->refs, use_list->count * sizeof(ir_ref)); + } use_list->refs = ctx->use_edges_count; ctx->use_edges[use_list->refs + use_list->count] = ref; use_list->count++; @@ -2025,7 +2034,7 @@ ir_alias ir_check_partial_aliasing(const ir_ctx *ctx, ir_ref addr1, ir_ref addr2, ir_type type1, ir_type type2) { - ir_insn *insn1, *insn2; + const ir_insn *insn1, *insn2; ir_ref base1, base2, off1, off2; /* this must be already check */ @@ -2117,9 +2126,9 @@ return IR_MAY_ALIAS; } -IR_ALWAYS_INLINE ir_ref ir_find_aliasing_load_i(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr, ir_ref limit) +IR_ALWAYS_INLINE ir_ref ir_find_aliasing_load_i(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr, ir_ref limit) { - ir_insn *insn; + const ir_insn *insn; uint32_t modified_regset = 0; while (ref > limit) { @@ -2159,7 +2168,7 @@ } else if (insn->op == IR_RSTORE) { modified_regset |= (1 << insn->op3); } else if (insn->op == IR_CALL) { - ir_insn *func = &ctx->ir_base[insn->op2]; + const ir_insn *func = &ctx->ir_base[insn->op2]; ir_ref func_proto; const ir_proto_t *proto; @@ -2186,14 +2195,14 @@ return IR_UNUSED; } -ir_ref ir_find_aliasing_load(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr) +ir_ref ir_find_aliasing_load(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr) { return ir_find_aliasing_load_i(ctx, ref, type, addr, (addr > 0 && addr < ref) ? addr : 1); } -IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var) +IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var) { - ir_insn *insn; + const ir_insn *insn; while (ref > var) { insn = &ctx->ir_base[ref]; @@ -2224,7 +2233,7 @@ } } } else if (insn->op == IR_CALL) { - ir_insn *func = &ctx->ir_base[insn->op2]; + const ir_insn *func = &ctx->ir_base[insn->op2]; ir_ref func_proto; const ir_proto_t *proto; @@ -2251,7 +2260,7 @@ return IR_UNUSED; } -ir_ref ir_find_aliasing_vload(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var) +ir_ref ir_find_aliasing_vload(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var) { return ir_find_aliasing_vload_i(ctx, ref, type, var); } @@ -2547,12 +2556,12 @@ } } -static ir_ref _ir_fold_condition(ir_ctx *ctx, ir_ref ref) +static ir_ref _ir_fold_condition(const ir_ctx *ctx, ir_ref ref) { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; if (insn->op == IR_NE && IR_IS_CONST_REF(insn->op2)) { - ir_insn *op2_insn = &ctx->ir_base[insn->op2]; + const ir_insn *op2_insn = &ctx->ir_base[insn->op2]; if (IR_IS_TYPE_INT(op2_insn->type) && op2_insn->val.u64 == 0) { ref = insn->op1; @@ -2565,7 +2574,7 @@ ref = insn->op1; insn = &ctx->ir_base[ref]; } else if (insn->op == IR_EQ && insn->op2 == IR_NULL) { - ir_insn *op1_insn = &ctx->ir_base[insn->op1]; + const ir_insn *op1_insn = &ctx->ir_base[insn->op1]; if (op1_insn->op == IR_ALLOCA || op1_insn->op == IR_VADDR) { return IR_FALSE; } @@ -2577,10 +2586,10 @@ return ref; } -IR_ALWAYS_INLINE ir_ref ir_check_dominating_predicates_i(ir_ctx *ctx, ir_ref ref, ir_ref condition, ir_ref limit) +IR_ALWAYS_INLINE ir_ref ir_check_dominating_predicates_i(const ir_ctx *ctx, ir_ref ref, ir_ref condition, ir_ref limit) { - ir_insn *prev = NULL; - ir_insn *insn; + const ir_insn *prev = NULL; + const ir_insn *insn; while (ref > limit) { insn = &ctx->ir_base[ref]; @@ -2610,7 +2619,7 @@ return condition; } -ir_ref ir_check_dominating_predicates(ir_ctx *ctx, ir_ref ref, ir_ref condition) +ir_ref ir_check_dominating_predicates(const ir_ctx *ctx, ir_ref ref, ir_ref condition) { IR_ASSERT(!IR_IS_CONST_REF(condition)); return ir_check_dominating_predicates_i(ctx, ref, condition, (condition < ref) ? condition : 1); @@ -2751,7 +2760,7 @@ /* count inputs count */ do { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; IR_ASSERT(insn->op == IR_END); ref = insn->op2; @@ -2781,8 +2790,10 @@ ir_ref _ir_PHI_LIST(ir_ctx *ctx, ir_ref list) { - ir_insn *merge, *end; - ir_ref phi, *ops, i; + const ir_insn *merge; + const ir_ref *ops; + ir_insn *end; + ir_ref phi, i; ir_type type; if (list == IR_UNUSED) { @@ -3246,7 +3257,8 @@ if (EXPECTED(ctx->flags & IR_OPT_FOLDING)) { ref = ir_find_aliasing_vload_i(ctx, ctx->control, type, var); if (ref) { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; + if (insn->type == type) { return ref; } else if (ir_type_size[insn->type] == ir_type_size[type]) { @@ -3312,7 +3324,8 @@ } ref = ir_find_aliasing_load_i(ctx, ctx->control, type, addr, (addr > 0) ? addr : 1); if (ref) { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; + if (insn->type == type) { return ref; } else if (ir_type_size[insn->type] == ir_type_size[type]) { diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_cfg.c php-8.4.20RC1/ext/opcache/jit/ir/ir_cfg.c --- php-8.4.18/ext/opcache/jit/ir/ir_cfg.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_cfg.c 2026-04-01 04:35:36.008870324 +0000 @@ -5,6 +5,10 @@ * Authors: Dmitry Stogov */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + #include "ir.h" #include "ir_private.h" @@ -77,12 +81,86 @@ } } +static void ir_remove_phis_inputs(ir_ctx *ctx, ir_use_list *use_list, int new_inputs_count, ir_bitset life_inputs) +{ + ir_ref i, j, n, k, *p, *q, use; + ir_insn *use_insn; + + if (new_inputs_count == 1) { + for (k = use_list->count, p = q = &ctx->use_edges[use_list->refs]; k > 0; p++, k--) { + use = *p; + use_insn = &ctx->ir_base[use]; + if (use_insn->op == IR_PHI) { + /* Convert PHI to COPY */ + n = use_insn->inputs_count; + i = 2; + for (j = 2; j <= n; j++) { + ir_ref input = ir_insn_op(use_insn, j); + + if (ir_bitset_in(life_inputs, j - 1)) { + use_insn->op1 = ir_insn_op(use_insn, j); + } else if (input > 0) { + ir_use_list_remove_one(ctx, input, use); + } + } + use_insn->op = IR_COPY; + use_insn->inputs_count = 1; + for (j = 2; j <= n; j++) { + ir_insn_set_op(use_insn, j, IR_UNUSED); + } + continue; + } + + /*compact use list */ + if (p != q){ + *q = use; + } + q++; + } + + if (p != q) { + use_list->count -= (p - q); + do { + *q = IR_UNUSED; /* clenu-op the removed tail */ + q++; + } while (p != q); + } + } else { + for (k = use_list->count, p = &ctx->use_edges[use_list->refs]; k > 0; p++, k--) { + use = *p; + use_insn = &ctx->ir_base[use]; + if (use_insn->op == IR_PHI) { + n = use_insn->inputs_count; + i = 2; + for (j = 2; j <= n; j++) { + ir_ref input = ir_insn_op(use_insn, j); + + if (ir_bitset_in(life_inputs, j - 1)) { + IR_ASSERT(input); + if (i != j) { + ir_insn_set_op(use_insn, i, input); + } + i++; + } else if (input > 0) { + ir_use_list_remove_one(ctx, input, use); + } + } + use_insn->inputs_count = i - 1; + for (j = i; j <= n; j++) { + ir_insn_set_op(use_insn, j, IR_UNUSED); + } + } + } + } +} + static uint32_t IR_NEVER_INLINE ir_cfg_remove_dead_inputs(ir_ctx *ctx, uint32_t *_blocks, ir_block *blocks, uint32_t bb_count) { uint32_t b, count = 0; ir_block *bb = blocks + 1; ir_insn *insn; ir_ref i, j, n, *ops, input; + ir_bitset life_inputs = NULL; for (b = 1; b <= bb_count; b++, bb++) { bb->successors = count; @@ -96,12 +174,27 @@ for (i = 1, j = 1; i <= n; i++) { input = ops[i]; if (_blocks[input]) { + if (life_inputs) { + ir_bitset_incl(life_inputs, i); + } if (i != j) { ops[j] = ops[i]; } j++; - } else if (input > 0) { - ir_use_list_remove_one(ctx, input, bb->start); + } else { + if (ctx->use_lists[bb->start].count > 1) { + /* Some inputs of this MERGE are deleted and we have to update the depended PHIs */ + if (!life_inputs) { + int k; + life_inputs = ir_bitset_malloc(n + 1); + for (k = 1; k < i; k++) { + ir_bitset_incl(life_inputs, k); + } + } + } + IR_ASSERT(input > 0); + IR_ASSERT(ctx->use_lists[input].count == 1 && ctx->use_edges[ctx->use_lists[input].refs] == bb->start); + CLEAR_USES(input); } } j--; @@ -115,6 +208,11 @@ for (;j <= n; j++) { ops[j] = IR_UNUSED; } + if (life_inputs) { + ir_remove_phis_inputs(ctx, &ctx->use_lists[bb->start], insn->inputs_count, life_inputs); + ir_mem_free(life_inputs); + life_inputs = NULL; + } } } count += bb->predecessors_count; @@ -375,8 +473,7 @@ static void ir_remove_merge_input(ir_ctx *ctx, ir_ref merge, ir_ref from) { - ir_ref i, j, n, k, *p, *q, use; - ir_insn *use_insn; + ir_ref i, j, n; ir_use_list *use_list; ir_bitset life_inputs; ir_insn *insn = &ctx->ir_base[merge]; @@ -402,82 +499,17 @@ } if (i == 1) { insn->op = IR_BEGIN; - insn->inputs_count = 1; - use_list = &ctx->use_lists[merge]; - if (use_list->count > 1) { - n++; - for (k = use_list->count, p = q = &ctx->use_edges[use_list->refs]; k > 0; p++, k--) { - use = *p; - use_insn = &ctx->ir_base[use]; - if (use_insn->op == IR_PHI) { - /* Convert PHI to COPY */ - i = 2; - for (j = 2; j <= n; j++) { - ir_ref input = ir_insn_op(use_insn, j); - - if (ir_bitset_in(life_inputs, j - 1)) { - use_insn->op1 = ir_insn_op(use_insn, j); - } else if (input > 0) { - ir_use_list_remove_one(ctx, input, use); - } - } - use_insn->op = IR_COPY; - use_insn->inputs_count = 1; - for (j = 2; j <= n; j++) { - ir_insn_set_op(use_insn, j, IR_UNUSED); - } - continue; - } - - /*compact use list */ - if (p != q){ - *q = use; - } - q++; - } - - if (p != q) { - use_list->count -= (p - q); - do { - *q = IR_UNUSED; /* clenu-op the removed tail */ - q++; - } while (p != q); - } - } - } else { - insn->inputs_count = i; + } + insn->inputs_count = i; - use_list = &ctx->use_lists[merge]; - if (use_list->count > 1) { - n++; - for (k = use_list->count, p = &ctx->use_edges[use_list->refs]; k > 0; p++, k--) { - use = *p; - use_insn = &ctx->ir_base[use]; - if (use_insn->op == IR_PHI) { - i = 2; - for (j = 2; j <= n; j++) { - ir_ref input = ir_insn_op(use_insn, j); - - if (ir_bitset_in(life_inputs, j - 1)) { - IR_ASSERT(input); - if (i != j) { - ir_insn_set_op(use_insn, i, input); - } - i++; - } else if (input > 0) { - ir_use_list_remove_one(ctx, input, use); - } - } - use_insn->inputs_count = i - 1; - for (j = i; j <= n; j++) { - ir_insn_set_op(use_insn, j, IR_UNUSED); - } - } - } - } + use_list = &ctx->use_lists[merge]; + if (use_list->count > 1) { + ir_remove_phis_inputs(ctx, use_list, i, life_inputs); } + ir_mem_free(life_inputs); - ir_use_list_remove_all(ctx, from, merge); + IR_ASSERT(ctx->use_lists[from].count == 1 && ctx->use_edges[ctx->use_lists[from].refs] == merge); + CLEAR_USES(from); } /* CFG constructed after SCCP pass doesn't have unreachable BBs, otherwise they should be removed */ @@ -582,59 +614,64 @@ return 1; } -static void compute_postnum(const ir_ctx *ctx, uint32_t *cur, uint32_t b) -{ - uint32_t i, *p; - ir_block *bb = &ctx->cfg_blocks[b]; - - if (bb->postnum != 0) { - return; - } - - if (bb->successors_count) { - bb->postnum = -1; /* Marker for "currently visiting" */ - p = ctx->cfg_edges + bb->successors; - i = bb->successors_count; - do { - compute_postnum(ctx, cur, *p); - p++; - } while (--i); - } - bb->postnum = (*cur)++; -} - /* Computes dominator tree using algorithm from "A Simple, Fast Dominance Algorithm" by * Cooper, Harvey and Kennedy. */ static IR_NEVER_INLINE int ir_build_dominators_tree_slow(ir_ctx *ctx) { - uint32_t blocks_count, b, postnum; + uint32_t blocks_count, b, postnum, i; ir_block *blocks, *bb; uint32_t *edges; + uint32_t *rpo = ir_mem_malloc((ctx->cfg_blocks_count + 1) * sizeof(uint32_t)); bool changed; blocks = ctx->cfg_blocks; edges = ctx->cfg_edges; blocks_count = ctx->cfg_blocks_count; - /* Clear the dominators tree */ - for (b = 0, bb = &blocks[0]; b <= blocks_count; b++, bb++) { - bb->idom = 0; - bb->dom_depth = 0; - bb->dom_child = 0; - bb->dom_next_child = 0; - } - ctx->flags2 &= ~IR_NO_LOOPS; postnum = 1; - compute_postnum(ctx, &postnum, 1); + ir_worklist work; + ir_worklist_init(&work, ctx->cfg_blocks_count + 1); + ir_worklist_push(&work, 1); + IR_ASSERT(blocks[1].next_succ == 0); + while (ir_worklist_len(&work)) { +next: + b = ir_worklist_peek(&work); + bb = &blocks[b]; + uint32_t n = bb->successors_count - bb->next_succ; + if (n) { + uint32_t *p = edges + bb->successors + bb->next_succ; + for (; n > 0; p++, n--) { + uint32_t succ = *p; + if (ir_worklist_push(&work, succ)) { + bb->next_succ = bb->successors_count - n + 1; + IR_ASSERT(blocks[succ].next_succ == 0); + goto next; + } + } + } + + /* Start from bb->idom calculated by the fast dominators algorithm */ + // bb->idom = 0; + bb->next_succ = 0; + rpo[postnum] = b; + bb->postnum = postnum++; + ir_worklist_pop(&work); + } + ir_worklist_free(&work); + + IR_ASSERT(rpo[blocks_count] == 1); /* Find immediate dominators by iterative fixed-point algorithm */ blocks[1].idom = 1; do { changed = 0; + /* Iterating in Reverse Post Order */ - for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) { + for (i = blocks_count - 1; i > 0; i--) { + b = rpo[i]; + bb = &blocks[b]; IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE)); IR_ASSERT(bb->predecessors_count > 0); if (bb->predecessors_count == 1) { @@ -687,6 +724,8 @@ } } while (changed); + ir_mem_free(rpo); + /* Build dominators tree */ blocks[1].idom = 0; blocks[1].dom_depth = 0; @@ -740,7 +779,7 @@ blocks[1].idom = 1; blocks[1].dom_depth = 0; - /* Iterating in Reverse Post Order */ + /* Iterating in Reverse Post Order (relay on existing BB order and fall-back to slow algorithm) */ for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) { IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE)); IR_ASSERT(bb->predecessors_count > 0); @@ -752,8 +791,8 @@ if (UNEXPECTED(idom >= b)) { /* In rare cases, LOOP_BEGIN.op1 may be a back-edge. Skip back-edges. */ ctx->flags2 &= ~IR_NO_LOOPS; -// IR_ASSERT(k > 1 && "Wrong blocks order: BB is before its single predecessor"); if (UNEXPECTED(k <= 1)) { + // IR_ASSERT(k > 1 && "Wrong blocks order: BB is before its single predecessor"); slow_case: ir_list_free(&worklist); return ir_build_dominators_tree_slow(ctx); @@ -767,6 +806,7 @@ break; } if (UNEXPECTED(k == 0)) { + // IR_ASSERT(0 && "Wrong blocks order: BB is before all its predecessors"); goto slow_case; } ir_list_push(&worklist, idom); @@ -799,13 +839,6 @@ bb->dom_depth = idom_bb->dom_depth + 1; } - /* Construct children lists sorted by block number */ - for (b = blocks_count, bb = &blocks[b]; b >= 2; b--, bb--) { - ir_block *idom_bb = &blocks[bb->idom]; - bb->dom_next_child = idom_bb->dom_child; - idom_bb->dom_child = b; - } - blocks[1].idom = 0; if (ir_list_len(&worklist) != 0) { @@ -843,10 +876,18 @@ if (UNEXPECTED(!complete)) { ir_list_free(&worklist); + // TODO: this algorithm may be incorrect. Prove and/or switch to ir_build_dominators_tree_slow() ??? return ir_build_dominators_tree_iterative(ctx); } } + /* Construct children lists sorted by block number */ + for (b = blocks_count, bb = &blocks[b]; b >= 2; b--, bb--) { + ir_block *idom_bb = &blocks[bb->idom]; + bb->dom_next_child = idom_bb->dom_child; + idom_bb->dom_child = b; + } + ir_list_free(&worklist); return 1; @@ -867,8 +908,6 @@ /* Clear the dominators tree, but keep already found dominators */ for (b = 0, bb = &blocks[0]; b <= blocks_count; b++, bb++) { bb->dom_depth = 0; - bb->dom_child = 0; - bb->dom_next_child = 0; } /* Find immediate dominators by iterative fixed-point algorithm */ @@ -886,20 +925,20 @@ if (blocks[idom].idom == 0) { while (1) { k--; + if (UNEXPECTED(k == 0)) break; p++; idom = *p; if (blocks[idom].idom > 0) { break; } - IR_ASSERT(k > 0); } + if (UNEXPECTED(k == 0)) continue; } IR_ASSERT(k != 0); while (--k > 0) { uint32_t pred_b = *(++p); if (blocks[pred_b].idom > 0) { - IR_ASSERT(blocks[pred_b].idom > 0); while (idom != pred_b) { while (pred_b > idom) { pred_b = blocks[pred_b].idom; @@ -949,10 +988,107 @@ return b1 == b2; } +/* Identify loops. See Sreedhar et al, "Identifying Loops Using DJ Graphs" and + * G. Ramalingam "Identifying Loops In Almost Linear Time". */ + +#define ENTRY_TIME(b) times[(b) * 2] +#define EXIT_TIME(b) times[(b) * 2 + 1] + +static IR_NEVER_INLINE void ir_collect_irreducible_loops(ir_ctx *ctx, uint32_t *times, ir_worklist *work, ir_list *list) +{ + ir_block *blocks = ctx->cfg_blocks; + uint32_t *edges = ctx->cfg_edges; + + IR_ASSERT(ir_list_len(list) != 0); + if (ir_list_len(list) > 1) { + /* Sort list to process irreducible loops in DFS order (insertion sort) */ + ir_ref *a = list->a.refs; + uint32_t n = ir_list_len(list); + uint32_t i = 1; + while (i < n) { + uint32_t j = i; + while (j > 0 && ENTRY_TIME(a[j-1]) > ENTRY_TIME(a[j])) { + ir_ref tmp = a[j]; + a[j] = a[j-1]; + a[j-1] = tmp; + j--; + } + i++; + } + } + while (ir_list_len(list)) { + uint32_t hdr = ir_list_pop(list); + ir_block *bb = &blocks[hdr]; + + IR_ASSERT(bb->flags & IR_BB_IRREDUCIBLE_LOOP); + IR_ASSERT(!bb->loop_depth); + if (!bb->loop_depth) { + /* process irreducible loop */ + + bb->flags |= IR_BB_LOOP_HEADER; + bb->loop_depth = 1; + if (ctx->ir_base[bb->start].op == IR_MERGE) { + ctx->ir_base[bb->start].op = IR_LOOP_BEGIN; + } + + /* find the closing edge(s) of the irreucible loop */ + IR_ASSERT(bb->predecessors_count > 1); + IR_ASSERT(ir_worklist_len(work) == 0); + ir_bitset_clear(work->visited, ir_bitset_len(ir_worklist_capasity(work))); + ir_bitset_incl(work->visited, hdr); + + uint32_t *p = &edges[bb->predecessors]; + uint32_t n = bb->predecessors_count; + do { + uint32_t pred = *p; + if (ENTRY_TIME(pred) > ENTRY_TIME(hdr) && EXIT_TIME(pred) < EXIT_TIME(hdr)) { + ir_worklist_push(work, pred); + } + p++; + } while (--n); + + /* collect members of the irreducible loop */ + while (ir_worklist_len(work)) { + uint32_t b = ir_worklist_pop(work); + + bb = &blocks[b]; + if (!bb->loop_header) { + bb->loop_header = hdr; + } + + uint32_t *p = &edges[bb->predecessors]; + uint32_t n = bb->predecessors_count; + + for (; n > 0; p++, n--) { + uint32_t pred = *p; + if (!ir_bitset_in(work->visited, pred)) { + if (blocks[pred].loop_header) { + if (blocks[pred].loop_header == b) continue; + do { + pred = blocks[pred].loop_header; + } while (blocks[pred].loop_header > 0); + } + if (ENTRY_TIME(pred) > ENTRY_TIME(hdr) && EXIT_TIME(pred) < EXIT_TIME(hdr)) { + /* "pred" is a descendant of "hdr" */ + ir_worklist_push(work, pred); + } else if (bb->predecessors_count > 1) { + /* another entry to the irreducible loop */ + bb->flags |= IR_BB_IRREDUCIBLE_LOOP; + if (ctx->ir_base[bb->start].op == IR_MERGE) { + ctx->ir_base[bb->start].op = IR_LOOP_BEGIN; + } + } + } + } + } + } + } +} + int ir_find_loops(ir_ctx *ctx) { - uint32_t b, j, n, count; - uint32_t *entry_times, *exit_times, *sorted_blocks, time = 1; + uint32_t b, j, n; + uint32_t *times, *sorted_blocks, time = 1; ir_block *blocks = ctx->cfg_blocks; uint32_t *edges = ctx->cfg_edges; ir_worklist work; @@ -961,52 +1097,44 @@ return 1; } - /* We don't materialize the DJ spanning tree explicitly, as we are only interested in ancestor - * queries. These are implemented by checking entry/exit times of the DFS search. */ + /* Compute entry/exit times for the CFG DFS spanning tree to perform ancestor and back-edge queries. */ ir_worklist_init(&work, ctx->cfg_blocks_count + 1); - entry_times = ir_mem_malloc((ctx->cfg_blocks_count + 1) * 3 * sizeof(uint32_t)); - exit_times = entry_times + ctx->cfg_blocks_count + 1; - sorted_blocks = exit_times + ctx->cfg_blocks_count + 1; - - memset(entry_times, 0, (ctx->cfg_blocks_count + 1) * sizeof(uint32_t)); + times = ir_mem_malloc((ctx->cfg_blocks_count + 1) * 3 * sizeof(uint32_t)); + sorted_blocks = times + (ctx->cfg_blocks_count + 1) * 2; + ir_bitset visited = ir_bitset_malloc(ctx->cfg_blocks_count + 1); ir_worklist_push(&work, 1); while (ir_worklist_len(&work)) { - ir_block *bb; - int child; - next: b = ir_worklist_peek(&work); - if (!entry_times[b]) { - entry_times[b] = time++; - } + ir_block *bb = &blocks[b]; - /* Visit blocks immediately dominated by "b". */ - bb = &blocks[b]; - for (child = bb->dom_child; child > 0; child = blocks[child].dom_next_child) { - if (ir_worklist_push(&work, child)) { - goto next; - } + if (!ir_bitset_in(visited, b)) { + ir_bitset_incl(visited, b); + ENTRY_TIME(b) = time++; } - /* Visit join edges. */ - if (bb->successors_count) { - uint32_t *p = edges + bb->successors; - for (j = 0; j < bb->successors_count; j++, p++) { + uint32_t n = bb->successors_count - bb->next_succ; + if (n) { + uint32_t *p = edges + bb->successors + bb->next_succ; + for (; n > 0; p++, n--) { uint32_t succ = *p; - - if (blocks[succ].idom == b) { - continue; - } else if (ir_worklist_push(&work, succ)) { + if (ir_worklist_push(&work, succ)) { + bb->next_succ = bb->successors_count - n + 1; + IR_ASSERT(blocks[succ].next_succ == 0); goto next; } } } - exit_times[b] = time++; + + bb->next_succ = 0; + EXIT_TIME(b) = time++; ir_worklist_pop(&work); } + ir_mem_free(visited); /* Sort blocks by level, which is the opposite order in which we want to process them */ + /* (Breadth First Search using "sorted_blocks" as a queue) */ sorted_blocks[1] = 1; j = 1; n = 2; @@ -1020,127 +1148,62 @@ } } } - count = n; + IR_ASSERT(n == ctx->cfg_blocks_count + 1); - /* Identify loops. See Sreedhar et al, "Identifying Loops Using DJ Graphs". */ +#if IR_DEBUG uint32_t prev_dom_depth = blocks[sorted_blocks[n - 1]].dom_depth; - uint32_t prev_irreducible = 0; +#endif + uint32_t irreducible_depth = 0; + ir_list irreducible_list = {0}; + while (n > 1) { b = sorted_blocks[--n]; ir_block *bb = &blocks[b]; IR_ASSERT(bb->dom_depth <= prev_dom_depth); - if (UNEXPECTED(prev_irreducible) && bb->dom_depth != prev_dom_depth) { - /* process delyed irreducible loops */ - do { - b = sorted_blocks[prev_irreducible]; - bb = &blocks[b]; - if ((bb->flags & IR_BB_IRREDUCIBLE_LOOP) && !bb->loop_depth) { - /* process irreducible loop */ - uint32_t hdr = b; - - bb->loop_depth = 1; - if (ctx->ir_base[bb->start].op == IR_MERGE) { - ctx->ir_base[bb->start].op = IR_LOOP_BEGIN; - } - /* find the closing edge(s) of the irreucible loop */ - IR_ASSERT(bb->predecessors_count > 1); - uint32_t *p = &edges[bb->predecessors]; - j = bb->predecessors_count; - do { - uint32_t pred = *p; - - if (entry_times[pred] > entry_times[b] && exit_times[pred] < exit_times[b]) { - if (!ir_worklist_len(&work)) { - ir_bitset_clear(work.visited, ir_bitset_len(ir_worklist_capasity(&work))); - } - blocks[pred].loop_header = 0; /* support for merged loops */ - ir_worklist_push(&work, pred); - } - p++; - } while (--j); - if (ir_worklist_len(&work) == 0) continue; - - /* collect members of the irreducible loop */ - while (ir_worklist_len(&work)) { - b = ir_worklist_pop(&work); - if (b != hdr) { - ir_block *bb = &blocks[b]; - bb->loop_header = hdr; - if (bb->predecessors_count) { - uint32_t *p = &edges[bb->predecessors]; - uint32_t n = bb->predecessors_count; - do { - uint32_t pred = *p; - while (blocks[pred].loop_header > 0) { - pred = blocks[pred].loop_header; - } - if (pred != hdr) { - if (entry_times[pred] > entry_times[hdr] && exit_times[pred] < exit_times[hdr]) { - /* "pred" is a descendant of "hdr" */ - ir_worklist_push(&work, pred); - } else { - /* another entry to the irreducible loop */ - bb->flags |= IR_BB_IRREDUCIBLE_LOOP; - if (ctx->ir_base[bb->start].op == IR_MERGE) { - ctx->ir_base[bb->start].op = IR_LOOP_BEGIN; - } - } - } - p++; - } while (--n); - } - } - } - } - } while (--prev_irreducible != n); - prev_irreducible = 0; - b = sorted_blocks[n]; - bb = &blocks[b]; + if (UNEXPECTED(bb->dom_depth < irreducible_depth)) { + ir_collect_irreducible_loops(ctx, times, &work, &irreducible_list); + irreducible_depth = 0; } if (bb->predecessors_count > 1) { bool irreducible = 0; + uint32_t b_entry_time = ENTRY_TIME(b); + uint32_t b_exit_time = EXIT_TIME(b); uint32_t *p = &edges[bb->predecessors]; - j = bb->predecessors_count; - do { + for (j = bb->predecessors_count; j > 0; p++, j--) { uint32_t pred = *p; - /* A join edge is one for which the predecessor does not - immediately dominate the successor. */ - if (bb->idom != pred) { - /* In a loop back-edge (back-join edge), the successor dominates - the predecessor. */ + /* Check back-edges */ + if (ENTRY_TIME(pred) >= b_entry_time && EXIT_TIME(pred) <= b_exit_time) { if (ir_dominates(blocks, b, pred)) { + /* In a loop back-edge (back-join edge), the successor dominates + the predecessor. */ if (!ir_worklist_len(&work)) { ir_bitset_clear(work.visited, ir_bitset_len(ir_worklist_capasity(&work))); } - blocks[pred].loop_header = 0; /* support for merged loops */ ir_worklist_push(&work, pred); } else { - /* Otherwise it's a cross-join edge. See if it's a branch - to an ancestor on the DJ spanning tree. */ - if (entry_times[pred] > entry_times[b] && exit_times[pred] < exit_times[b]) { - irreducible = 1; - break; - } + /* Otherwise it's a back-edge of irreducible loop. */ + irreducible = 1; + break; } } - p++; - } while (--j); + } if (UNEXPECTED(irreducible)) { - bb->flags |= IR_BB_LOOP_HEADER | IR_BB_IRREDUCIBLE_LOOP; + bb->flags |= IR_BB_IRREDUCIBLE_LOOP; ctx->flags2 |= IR_CFG_HAS_LOOPS | IR_IRREDUCIBLE_CFG; - /* Remember the position of the first irreducible loop to process all the irreducible loops - * after the reducible loops with the same dominator tree depth + /* Delay processing of all irreducible loops + * after all reducible loops with the same dominator tree depth */ - if (!prev_irreducible) { - prev_irreducible = n; - prev_dom_depth = bb->dom_depth; + irreducible_depth = bb->dom_depth; + if (!ir_list_capasity(&irreducible_list)) { + ir_list_init(&irreducible_list, 16); } + ir_list_push(&irreducible_list, b); ir_list_clear(&work.l); } else if (ir_worklist_len(&work)) { /* collect members of the reducible loop */ @@ -1152,35 +1215,48 @@ if (ctx->ir_base[bb->start].op == IR_MERGE) { ctx->ir_base[bb->start].op = IR_LOOP_BEGIN; } + ir_bitset_incl(work.visited, hdr); while (ir_worklist_len(&work)) { b = ir_worklist_pop(&work); if (b != hdr) { ir_block *bb = &blocks[b]; - bb->loop_header = hdr; - if (bb->predecessors_count) { - uint32_t *p = &edges[bb->predecessors]; - uint32_t n = bb->predecessors_count; - do { - uint32_t pred = *p; - while (blocks[pred].loop_header > 0) { - pred = blocks[pred].loop_header; - } - if (pred != hdr) { + + if (!bb->loop_header) { + bb->loop_header = hdr; + } + + uint32_t *p = &edges[bb->predecessors]; + uint32_t n = bb->predecessors_count; + for (; n > 0; p++, n--) { + uint32_t pred = *p; + if (!ir_bitset_in(work.visited, pred)) { + if (blocks[pred].loop_header) { + if (blocks[pred].loop_header == b) continue; + do { + pred = blocks[pred].loop_header; + } while (blocks[pred].loop_header > 0); ir_worklist_push(&work, pred); + } else { + ir_bitset_incl(work.visited, pred); + ir_list_push_unchecked(&work.l, pred); } - p++; - } while (--n); + } } } } } } } - IR_ASSERT(!prev_irreducible); + + IR_ASSERT(!irreducible_depth); + if (ir_list_capasity(&irreducible_list)) { + ir_list_free(&irreducible_list); + } if (ctx->flags2 & IR_CFG_HAS_LOOPS) { - for (n = 1; n < count; n++) { - b = sorted_blocks[n]; + n = ctx->cfg_blocks_count + 1; + for (j = 1; j < n; j++) { + b = sorted_blocks[j]; ir_block *bb = &blocks[b]; if (bb->loop_header > 0) { ir_block *loop = &blocks[bb->loop_header]; @@ -1211,7 +1287,7 @@ } } - ir_mem_free(entry_times); + ir_mem_free(times); ir_worklist_free(&work); return 1; @@ -1411,6 +1487,19 @@ } } } + +static bool ir_is_merged_loop_back_edge(ir_ctx *ctx, uint32_t hdr, uint32_t b) +{ + if (ctx->cfg_blocks[hdr].flags & IR_BB_LOOP_HEADER) { + uint32_t loop_depth = ctx->cfg_blocks[hdr].loop_depth; + + while (ctx->cfg_blocks[b].loop_depth > loop_depth) { + b = ctx->cfg_blocks[b].loop_header; + } + return b == hdr; + } + return 0; +} #endif static int ir_schedule_blocks_bottom_up(ir_ctx *ctx) @@ -1467,7 +1556,8 @@ } } else if (b != predecessor && ctx->cfg_blocks[predecessor].loop_header != b) { /* not a loop back-edge */ - IR_ASSERT(b == predecessor || ctx->cfg_blocks[predecessor].loop_header == b); + IR_ASSERT(b == predecessor || ctx->cfg_blocks[predecessor].loop_header == b || + ir_is_merged_loop_back_edge(ctx, b, predecessor)); } } } diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_dump.c php-8.4.20RC1/ext/opcache/jit/ir/ir_dump.c --- php-8.4.18/ext/opcache/jit/ir/ir_dump.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_dump.c 2026-04-01 04:35:36.009148690 +0000 @@ -60,7 +60,7 @@ } } -void ir_dump_dot(const ir_ctx *ctx, const char *name, FILE *f) +void ir_dump_dot(const ir_ctx *ctx, const char *name, const char *comments, FILE *f) { int DATA_WEIGHT = 0; int CONTROL_WEIGHT = 5; @@ -70,6 +70,13 @@ uint32_t flags; fprintf(f, "digraph %s {\n", name); + fprintf(f, "\tlabelloc=t;\n"); + fprintf(f, "\tlabel=\""); + ir_print_func_proto(ctx, name, 0, f); + if (comments) { + fprintf(f, " # %s", comments); + } + fprintf(f, "\"\n"); fprintf(f, "\trankdir=TB;\n"); for (i = 1 - ctx->consts_count, insn = ctx->ir_base + i; i < IR_UNUSED; i++, insn++) { fprintf(f, "\tc%d [label=\"C%d: CONST %s(", -i, -i, ir_type_name[insn->type]); diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_emit.c php-8.4.20RC1/ext/opcache/jit/ir/ir_emit.c --- php-8.4.18/ext/opcache/jit/ir/ir_emit.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_emit.c 2026-04-01 04:35:36.009261042 +0000 @@ -5,6 +5,10 @@ * Authors: Dmitry Stogov */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + #include "ir.h" #if defined(IR_TARGET_X86) || defined(IR_TARGET_X64) @@ -971,7 +975,7 @@ return 1; } -int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref) +int32_t ir_get_spill_slot_offset(const ir_ctx *ctx, ir_ref ref) { int32_t offset; diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_fold.h php-8.4.20RC1/ext/opcache/jit/ir/ir_fold.h --- php-8.4.18/ext/opcache/jit/ir/ir_fold.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_fold.h 2026-04-01 04:35:36.009413630 +0000 @@ -3439,5 +3439,84 @@ if (op2 == op3) { IR_FOLD_COPY(op2); } + + if (op1_insn->type == IR_BOOL) { + if (op2 == IR_TRUE) { + if (op3 == IR_FALSE) { + /* a ? true : false => a */ + IR_FOLD_COPY(op1); + } else { + /* a ? true : b => a | b */ + opt = IR_OPT(IR_OR, IR_BOOL); + op2 = op3; + op3 = IR_UNUSED; + IR_FOLD_RESTART; + } + } else if (op3 == IR_FALSE) { + /* a ? b : false => a & b */ + opt = IR_OPT(IR_AND, IR_BOOL); + op3 = IR_UNUSED; + IR_FOLD_RESTART; + } else if (op2 == IR_FALSE) { + if (op3 == IR_TRUE) { + /* a ? flase : true => !a */ + opt = IR_OPT(IR_NOT, IR_BOOL); + op2 = IR_UNUSED; + op3 = IR_UNUSED; + IR_FOLD_RESTART; + } + } else if (IR_IS_TYPE_INT(IR_OPT_TYPE(opt)) + && IR_IS_CONST_REF(op2) + && IR_IS_CONST_REF(op3) + && op2_insn->val.u64 == 1 + && op3_insn->val.u64 == 0) { + if (ir_type_size[IR_OPT_TYPE(opt)] > 1) { + /* a ? 1 : 0 => ZEXT(a) */ + opt = IR_OPT(IR_ZEXT, IR_OPT_TYPE(opt)); + } else { + /* a ? 1 : 0 => BITCAST(a) */ + opt = IR_OPT(IR_BITCAST, IR_OPT_TYPE(opt)); + } + op2 = IR_UNUSED; + op3 = IR_UNUSED; + IR_FOLD_RESTART; + } + } else if (IR_IS_TYPE_INT(op1_insn->type)) { + if (op2 == IR_TRUE) { + if (op3 == IR_FALSE) { + opt = IR_OPT(IR_NE, IR_BOOL); + val.u64 = 0; + op2 = ir_const(ctx, val, op1_insn->type); + op3 = IR_UNUSED; + IR_FOLD_RESTART; + } + } else if (op2 == IR_FALSE) { + if (op3 == IR_TRUE) { + opt = IR_OPT(IR_EQ, IR_BOOL); + val.u64 = 0; + op2 = ir_const(ctx, val, op1_insn->type); + op3 = IR_UNUSED; + IR_FOLD_RESTART; + } + } + } + + if (op1_insn->op == IR_NE) { + if (IR_IS_CONST_REF(op1_insn->op2) + && IR_IS_TYPE_INT(ctx->ir_base[op1_insn->op2].type) + && ctx->ir_base[op1_insn->op2].val.u64 == 0) { + op1 = op1_insn->op1; + IR_FOLD_RESTART; + } + } else if (op1_insn->op == IR_EQ) { + if (IR_IS_CONST_REF(op1_insn->op2) + && IR_IS_TYPE_INT(ctx->ir_base[op1_insn->op2].type) + && ctx->ir_base[op1_insn->op2].val.u64 == 0) { + op1 = op1_insn->op1; + SWAP_REFS(op2, op3); + IR_FOLD_RESTART; + } + } + IR_FOLD_NEXT; } diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_gcm.c php-8.4.20RC1/ext/opcache/jit/ir/ir_gcm.c --- php-8.4.18/ext/opcache/jit/ir/ir_gcm.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_gcm.c 2026-04-01 04:35:36.009619069 +0000 @@ -262,7 +262,7 @@ #endif /* 1.2. Iteratively check the predecessors of already found TOTALLY_USEFUL blocks and - * add them into TOTALLY_USEFUL set if all of their sucessors are already there. + * add them into TOTALLY_USEFUL set if all of their successors are already there. */ IR_SPARSE_SET_FOREACH(&data->totally_useful, i) { _push_predecessors(ctx, &ctx->cfg_blocks[i], data); @@ -788,7 +788,7 @@ IR_ALWAYS_INLINE bool ir_is_good_bb_order(ir_ctx *ctx, uint32_t b, ir_block *bb, ir_ref start) { - ir_insn *insn = &ctx->ir_base[start]; + ir_insn *insn = &ctx->ir_base[start]; uint32_t n = insn->inputs_count; ir_ref *p = insn->ops + 1; @@ -842,6 +842,7 @@ xlat = ir_mem_malloc(count * sizeof(uint32_t)); ir_worklist_init(&worklist, count); ir_worklist_push(&worklist, 1); + /* Schedule blocks bottom-up. Place block only after all its successurs (except back-edges) are placed. */ while (ir_worklist_len(&worklist) != 0) { next: b = ir_worklist_peek(&worklist); @@ -849,7 +850,14 @@ n = bb->successors_count; if (n == 1) { succ = ctx->cfg_edges[bb->successors]; - if (ir_worklist_push(&worklist, succ)) { + if (ir_bitset_in(worklist.visited, succ)) { + /* already processed */ + } else if ((ctx->cfg_blocks[succ].flags & IR_BB_IRREDUCIBLE_LOOP) + && ((ctx->cfg_blocks[b].flags & IR_BB_LOOP_HEADER) ? + (ctx->cfg_blocks[succ].loop_header != b) : + (ctx->cfg_blocks[succ].loop_header != ctx->cfg_blocks[b].loop_header))) { + /* "side" entry of irreducible loop (ignore) */ + } else if (ir_worklist_push(&worklist, succ)) { goto next; } } else if (n > 1) { @@ -862,12 +870,11 @@ succ = *q; if (ir_bitset_in(worklist.visited, succ)) { /* already processed */ - } else if ((ctx->cfg_blocks[succ].flags & IR_BB_LOOP_HEADER) - && (succ == b || ctx->cfg_blocks[b].loop_header == succ)) { - /* back-edge of reducible loop */ } else if ((ctx->cfg_blocks[succ].flags & IR_BB_IRREDUCIBLE_LOOP) - && (ctx->cfg_blocks[succ].loop_header == ctx->cfg_blocks[b].loop_header)) { - /* closing edge of irreducible loop */ + && ((ctx->cfg_blocks[b].flags & IR_BB_LOOP_HEADER) ? + (ctx->cfg_blocks[succ].loop_header != b) : + (ctx->cfg_blocks[succ].loop_header != ctx->cfg_blocks[b].loop_header))) { + /* "side" entry of irreducible loop (ignore) */ } else if (!best) { best = succ; best_loop_depth = ctx->cfg_blocks[best].loop_depth; @@ -883,6 +890,8 @@ goto next; } } + + /* All successors of "b" are placed. Now we can place "b" itself. */ ir_worklist_pop(&worklist); count--; new_blocks[count] = *bb; @@ -924,25 +933,120 @@ ctx->cfg_blocks = new_blocks; } +#if IR_DEBUG +static void ir_schedule_print_list(const ir_ctx *ctx, uint32_t b, const ir_ref *_next, + ir_ref start, ir_ref end, const char *label) +{ + ir_ref ref; + + fprintf(stderr, " %s [%d", label, start); + ref = _next[start]; + while (ref != end) { + fprintf(stderr, ",%d", ref); + ref = _next[ref]; + } + fprintf(stderr, ",%d]\n", ref); +} +#endif + +/* Simple Stable Topological Sort */ +static void ir_schedule_topsort(const ir_ctx *ctx, uint32_t b, const ir_block *bb, + ir_ref *_xlat, ir_ref *_next, ir_ref *_prev, + ir_ref ref, ir_ref end, + ir_ref *insns_count, ir_ref *consts_count) +{ + ir_ref i = ref; + const ir_insn *insn; + + if (bb->successors_count > 1) { + ir_ref input, j = bb->end; + ir_insn *end = &ctx->ir_base[j]; + + if (end->op == IR_IF) { + /* Move condition closer to IF */ + input = end->op2; + if (input > 0 + && ctx->cfg_map[input] == b + && !_xlat[input] + && _prev[j] != input + && (!(ir_op_flags[ctx->ir_base[input].op] & IR_OP_FLAG_CONTROL) || end->op1 == input)) { + if (input == i) { + i = _next[i]; + insn = &ctx->ir_base[i]; + } + /* remove "input" */ + _prev[_next[input]] = _prev[input]; + _next[_prev[input]] = _next[input]; + /* insert before "j" */ + _prev[input] = _prev[j]; + _next[input] = j; + _next[_prev[j]] = input; + _prev[j] = input; + } + } + } + + while (i != end) { + ir_ref n, j, input; + const ir_ref *p; + +restart: + IR_ASSERT(ctx->cfg_map[i] == b); + insn = &ctx->ir_base[i]; + n = insn->inputs_count; + for (j = n, p = insn->ops + 1; j > 0; p++, j--) { + input = *p; + if (!_xlat[input]) { + /* input is not scheduled yet */ + if (input > 0) { + if (ctx->cfg_map[input] == b) { + /* "input" should be before "i" to satisfy dependency */ +#ifdef IR_DEBUG + if (ctx->flags & IR_DEBUG_SCHEDULE) { + fprintf(stderr, "Wrong dependency %d:%d -> %d\n", b, input, i); + } +#endif + /* remove "input" */ + _prev[_next[input]] = _prev[input]; + _next[_prev[input]] = _next[input]; + /* insert before "i" */ + _prev[input] = _prev[i]; + _next[input] = i; + _next[_prev[i]] = input; + _prev[i] = input; + /* restart from "input" */ + i = input; + goto restart; + } + } else if (input < IR_TRUE) { + *consts_count += ir_count_constant(_xlat, input); + } + } + } + + _xlat[i] = *insns_count; + *insns_count += ir_insn_inputs_to_len(n); + IR_ASSERT(_next[i] != IR_UNUSED); + i = _next[i]; + } +} + int ir_schedule(ir_ctx *ctx) { - ir_ctx new_ctx; ir_ref i, j, k, n, *p, *q, ref, new_ref, prev_ref, insns_count, consts_count, use_edges_count; ir_ref *_xlat; ir_ref *edges; ir_ref prev_b_end; uint32_t b; - uint32_t *_blocks = ctx->cfg_map; ir_ref *_next = ir_mem_malloc(ctx->insns_count * sizeof(ir_ref)); ir_ref *_prev = ir_mem_malloc(ctx->insns_count * sizeof(ir_ref)); ir_block *bb; - ir_insn *insn, *new_insn; + ir_insn *insn, *new_insn, *base; ir_use_list *lists, *use_list, *new_list; bool bad_bb_order = 0; - /* Create a double-linked list of nodes ordered by BB, respecting BB->start and BB->end */ - IR_ASSERT(_blocks[1] == 1); + IR_ASSERT(ctx->cfg_map[1] == 1); /* link BB boundaries */ _prev[1] = 0; @@ -950,30 +1054,34 @@ _next[1] = prev_b_end; _prev[prev_b_end] = 1; for (b = 2, bb = ctx->cfg_blocks + 2; b <= ctx->cfg_blocks_count; b++, bb++) { - _next[prev_b_end] = bb->start; - _prev[bb->start] = prev_b_end; - _next[bb->start] = bb->end; - _prev[bb->end] = bb->start; - prev_b_end = bb->end; - if (!ir_is_good_bb_order(ctx, b, bb, bb->start)) { + ir_ref start = bb->start; + ir_ref end = bb->end; + _next[prev_b_end] = start; + _prev[start] = prev_b_end; + _next[start] = end; + _prev[end] = start; + prev_b_end = end; + if (!ir_is_good_bb_order(ctx, b, bb, start)) { bad_bb_order = 1; } } _next[prev_b_end] = 0; /* insert intermediate BB nodes */ - for (i = 2, j = 1; i < ctx->insns_count; i++) { - b = _blocks[i]; + use_edges_count = ctx->use_lists[1].count; + for (i = 2, use_list = &ctx->use_lists[i]; i < ctx->insns_count; use_list++, i++) { + b = ctx->cfg_map[i]; if (!b) continue; + use_edges_count += use_list->count; bb = &ctx->cfg_blocks[b]; if (i != bb->start && i != bb->end) { /* insert before "end" */ - ir_ref n = bb->end; - ir_ref p = _prev[n]; - _prev[i] = p; - _next[i] = n; - _next[p] = i; - _prev[n] = i; + ir_ref next = bb->end; + ir_ref prev = _prev[next]; + _prev[i] = prev; + _next[i] = next; + _next[prev] = i; + _prev[next] = i; } } @@ -981,15 +1089,6 @@ ir_fix_bb_order(ctx, _prev, _next); } -#ifdef IR_DEBUG - if (ctx->flags & IR_DEBUG_SCHEDULE) { - fprintf(stderr, "Before Schedule\n"); - for (i = 1; i != 0; i = _next[i]) { - fprintf(stderr, "%d -> %d\n", i, _blocks[i]); - } - } -#endif - _xlat = ir_mem_calloc((ctx->consts_count + ctx->insns_count), sizeof(ir_ref)); _xlat += ctx->consts_count; _xlat[IR_TRUE] = IR_TRUE; @@ -999,10 +1098,17 @@ insns_count = 1; consts_count = -(IR_TRUE - 1); - /* Topological sort according dependencies inside each basic block */ + /* Schedule instructions inside each BB (now just topological sort according to dependencies) */ for (b = 1, bb = ctx->cfg_blocks + 1; b <= ctx->cfg_blocks_count; b++, bb++) { ir_ref start; +#ifdef IR_DEBUG + if (ctx->flags & IR_DEBUG_SCHEDULE) { + fprintf(stderr, "BB%d\n", b); + ir_schedule_print_list(ctx, b, _next, bb->start, bb->end, "INITIAL"); + } +#endif + IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE)); /* Schedule BB start */ start = i = bb->start; @@ -1062,8 +1168,8 @@ for (p = &ctx->use_edges[use_list->refs]; count > 0; p++, count--) { ir_ref use = *p; ir_insn *use_insn = &ctx->ir_base[use]; - if (!_xlat[use] && (_blocks[use] || use_insn->op == IR_PARAM)) { - IR_ASSERT(_blocks[use] == b || use_insn->op == IR_PARAM); + if (!_xlat[use] && ctx->cfg_map[use]) { + IR_ASSERT(ctx->cfg_map[use] == b); if (use_insn->op == IR_PARAM || use_insn->op == IR_VAR || use_insn->op == IR_PI @@ -1100,76 +1206,20 @@ insn = &ctx->ir_base[i]; } } - if (bb->successors_count > 1) { - ir_ref input, j = bb->end; - ir_insn *end = &ctx->ir_base[j]; - - if (end->op == IR_IF) { - /* Move condition closer to IF */ - input = end->op2; - if (input > 0 - && _blocks[input] == b - && !_xlat[input] - && _prev[j] != input - && (!(ir_op_flags[ctx->ir_base[input].op] & IR_OP_FLAG_CONTROL) || end->op1 == input)) { - if (input == i) { - i = _next[i]; - insn = &ctx->ir_base[i]; - } - /* remove "input" */ - _prev[_next[input]] = _prev[input]; - _next[_prev[input]] = _next[input]; - /* insert before "j" */ - _prev[input] = _prev[j]; - _next[input] = j; - _next[_prev[j]] = input; - _prev[j] = input; - } - } + + if (i != bb->end) { + ir_schedule_topsort(ctx, b, bb, _xlat, _next, _prev, i, bb->end, &insns_count, &consts_count); } - while (i != bb->end) { - ir_ref n, j, *p, input; -restart: - IR_ASSERT(_blocks[i] == b); - n = insn->inputs_count; - for (j = n, p = insn->ops + 1; j > 0; p++, j--) { - input = *p; - if (!_xlat[input]) { - /* input is not scheduled yet */ - if (input > 0) { - if (_blocks[input] == b) { - /* "input" should be before "i" to satisfy dependency */ #ifdef IR_DEBUG - if (ctx->flags & IR_DEBUG_SCHEDULE) { - fprintf(stderr, "Wrong dependency %d:%d -> %d\n", b, input, i); - } -#endif - /* remove "input" */ - _prev[_next[input]] = _prev[input]; - _next[_prev[input]] = _next[input]; - /* insert before "i" */ - _prev[input] = _prev[i]; - _next[input] = i; - _next[_prev[i]] = input; - _prev[i] = input; - /* restart from "input" */ - i = input; - insn = &ctx->ir_base[i]; - goto restart; - } - } else if (input < IR_TRUE) { - consts_count += ir_count_constant(_xlat, input); - } - } - } - _xlat[i] = insns_count; - insns_count += ir_insn_inputs_to_len(n); - IR_ASSERT(_next[i] != IR_UNUSED); - i = _next[i]; - insn = &ctx->ir_base[i]; + if (ctx->flags & IR_DEBUG_SCHEDULE) { + ir_schedule_print_list(ctx, b, _next, start, bb->end, " FINAL"); } +#endif + /* Schedule BB end */ + i = bb->end; + insn = &ctx->ir_base[i]; _xlat[i] = bb->end = insns_count; insns_count++; if (IR_INPUT_EDGES_COUNT(ir_op_flags[insn->op]) == 2) { @@ -1179,15 +1229,6 @@ } } -#ifdef IR_DEBUG - if (ctx->flags & IR_DEBUG_SCHEDULE) { - fprintf(stderr, "After Schedule\n"); - for (i = 1; i != 0; i = _next[i]) { - fprintf(stderr, "%d -> %d (%d)\n", i, _blocks[i], _xlat[i]); - } - } -#endif - #if 1 /* Check if scheduling didn't make any modifications */ if (consts_count == ctx->consts_count && insns_count == ctx->insns_count) { @@ -1215,113 +1256,55 @@ ir_mem_free(_prev); - ir_init(&new_ctx, ctx->flags, consts_count, insns_count); - new_ctx.insns_count = insns_count; - new_ctx.flags2 = ctx->flags2; - new_ctx.ret_type = ctx->ret_type; - new_ctx.value_params = ctx->value_params; - new_ctx.mflags = ctx->mflags; - new_ctx.spill_base = ctx->spill_base; - new_ctx.fixed_stack_red_zone = ctx->fixed_stack_red_zone; - new_ctx.fixed_stack_frame_size = ctx->fixed_stack_frame_size; - new_ctx.fixed_call_stack_size = ctx->fixed_call_stack_size; - new_ctx.fixed_regset = ctx->fixed_regset; - new_ctx.fixed_save_regset = ctx->fixed_save_regset; - new_ctx.entries_count = ctx->entries_count; -#if defined(IR_TARGET_AARCH64) - new_ctx.deoptimization_exits = ctx->deoptimization_exits; - new_ctx.get_exit_addr = ctx->get_exit_addr; - new_ctx.get_veneer = ctx->get_veneer; - new_ctx.set_veneer = ctx->set_veneer; -#endif - new_ctx.loader = ctx->loader; + uint32_t *map = ir_mem_calloc(insns_count, sizeof(uint32_t)); + _prev = ir_mem_malloc(insns_count * sizeof(ir_ref)); + lists = ir_mem_malloc(insns_count * sizeof(ir_use_list)); + ir_ref *use_edges = edges = ir_mem_malloc(use_edges_count * sizeof(ir_ref)); + base = ir_mem_malloc((consts_count + insns_count) * sizeof(ir_insn)); + base += consts_count; /* Copy constants */ - if (consts_count == ctx->consts_count) { - new_ctx.consts_count = consts_count; - ref = 1 - consts_count; - insn = &ctx->ir_base[ref]; - new_insn = &new_ctx.ir_base[ref]; - - memcpy(new_insn, insn, sizeof(ir_insn) * (IR_TRUE - ref)); - if (ctx->strtab.data) { - while (ref != IR_TRUE) { - if (new_insn->op == IR_FUNC_ADDR) { - if (new_insn->proto) { - size_t len; - const char *proto = ir_get_strl(ctx, new_insn->proto, &len); - new_insn->proto = ir_strl(&new_ctx, proto, len); - } - } else if (new_insn->op == IR_FUNC) { - size_t len; - const char *name = ir_get_strl(ctx, new_insn->val.name, &len); - new_insn->val.u64 = ir_strl(&new_ctx, name, len); - if (new_insn->proto) { - const char *proto = ir_get_strl(ctx, new_insn->proto, &len); - new_insn->proto = ir_strl(&new_ctx, proto, len); - } - } else if (new_insn->op == IR_SYM || new_insn->op == IR_STR || new_insn->op == IR_LABEL) { - size_t len; - const char *str = ir_get_strl(ctx, new_insn->val.name, &len); - new_insn->val.u64 = ir_strl(&new_ctx, str, len); - } - new_insn++; - ref++; - } + if (ctx->consts_count == consts_count) { + memcpy(base - consts_count + 1, ctx->ir_base - consts_count + 1, sizeof(ir_insn) * consts_count); + for (j = -consts_count + 1; j < IR_TRUE; j++) { + _xlat[j] = j; } } else { - new_ref = -new_ctx.consts_count; - new_insn = &new_ctx.ir_base[new_ref]; - for (ref = IR_TRUE - 1, insn = &ctx->ir_base[ref]; ref > -ctx->consts_count; insn--, ref--) { - if (!_xlat[ref]) { - continue; - } - new_insn->optx = insn->optx; - new_insn->prev_const = 0; - if (insn->op == IR_FUNC_ADDR) { - new_insn->val.u64 = insn->val.u64; - if (insn->proto) { - size_t len; - const char *proto = ir_get_strl(ctx, insn->proto, &len); - new_insn->proto = ir_strl(&new_ctx, proto, len); - } else { - new_insn->proto = 0; - } - } else if (insn->op == IR_FUNC) { - size_t len; - const char *name = ir_get_strl(ctx, insn->val.name, &len); - new_insn->val.u64 = ir_strl(&new_ctx, name, len); - if (insn->proto) { - const char *proto = ir_get_strl(ctx, insn->proto, &len); - new_insn->proto = ir_strl(&new_ctx, proto, len); - } else { - new_insn->proto = 0; - } - } else if (insn->op == IR_SYM || insn->op == IR_STR || insn->op == IR_LABEL) { - size_t len; - const char *str = ir_get_strl(ctx, insn->val.name, &len); - new_insn->val.u64 = ir_strl(&new_ctx, str, len); - } else { - new_insn->val.u64 = insn->val.u64; - } - _xlat[ref] = new_ref; - new_ref--; - new_insn--; - } - new_ctx.consts_count = -new_ref; - } + ir_insn *src = ctx->ir_base - ctx->consts_count + 1; + ir_insn *dst = base - consts_count + 1; - new_ctx.cfg_map = ir_mem_calloc(ctx->insns_count, sizeof(uint32_t)); - new_ctx.prev_ref = _prev = ir_mem_malloc(insns_count * sizeof(ir_ref)); - new_ctx.use_lists = lists = ir_mem_malloc(insns_count * sizeof(ir_use_list)); - new_ctx.use_edges = edges = ir_mem_malloc(ctx->use_edges_count * sizeof(ir_ref)); + i = -ctx->consts_count + 1; + j = -consts_count + 1; + while (i < IR_TRUE) { + if (_xlat[i]) { + *dst = *src; + dst->prev_const = 0; + _xlat[i] = j; + dst++; + j++; + } + src++; + i++; + } + IR_ASSERT(j == IR_TRUE); + base[IR_TRUE].optx = IR_OPT(IR_C_BOOL, IR_BOOL); + base[IR_TRUE].val.u64 = 1; + base[IR_FALSE].optx = IR_OPT(IR_C_BOOL, IR_BOOL); + base[IR_FALSE].val.u64 = 0; + base[IR_NULL].optx = IR_OPT(IR_C_ADDR, IR_ADDR); + base[IR_NULL].val.u64 = 0; + MAKE_NOP(&base[IR_UNUSED]); + } /* Copy instructions, use lists and use edges */ +#ifdef IR_DEBUG + ir_ref orig_use_edges_count = use_edges_count; +#endif prev_ref = 0; use_edges_count = 0; for (i = 1; i != 0; i = _next[i]) { new_ref = _xlat[i]; - new_ctx.cfg_map[new_ref] = _blocks[i]; + map[new_ref] = ctx->cfg_map[i]; _prev[new_ref] = prev_ref; prev_ref = new_ref; @@ -1330,7 +1313,7 @@ k = 0; if (n == 1) { ref = ctx->use_edges[use_list->refs]; - if (_xlat[ref]) { + if (EXPECTED(_xlat[ref])) { *edges = _xlat[ref]; edges++; k = 1; @@ -1339,7 +1322,7 @@ p = &ctx->use_edges[use_list->refs]; while (n--) { ref = *p; - if (_xlat[ref]) { + if (EXPECTED(_xlat[ref])) { *edges = _xlat[ref]; edges++; k++; @@ -1353,7 +1336,7 @@ new_list->count = k; insn = &ctx->ir_base[i]; - new_insn = &new_ctx.ir_base[new_ref]; + new_insn = &base[new_ref]; new_insn->optx = insn->optx; n = new_insn->inputs_count; @@ -1365,11 +1348,7 @@ break; case 1: new_insn->op1 = _xlat[insn->op1]; - if (new_insn->op == IR_PARAM || new_insn->op == IR_VAR || new_insn->op == IR_PROTO) { - size_t len; - const char *str = ir_get_strl(ctx, insn->op2, &len); - new_insn->op2 = ir_strl(&new_ctx, str, len); - } else if (new_insn->op == IR_BEGIN && insn->op2) { + if (new_insn->op == IR_BEGIN && insn->op2) { new_insn->op2 = _xlat[insn->op2]; } else { new_insn->op2 = insn->op2; @@ -1428,12 +1407,12 @@ } /* Update list of terminators (IR_OPND_CONTROL_REF) */ - insn = &new_ctx.ir_base[1]; + insn = &base[1]; ref = insn->op1; if (ref) { insn->op1 = ref = _xlat[ref]; while (1) { - insn = &new_ctx.ir_base[ref]; + insn = &base[ref]; ref = insn->op3; if (!ref) { break; @@ -1442,36 +1421,33 @@ } } - IR_ASSERT(ctx->use_edges_count >= use_edges_count); - new_ctx.use_edges_count = use_edges_count; - new_ctx.use_edges = ir_mem_realloc(new_ctx.use_edges, use_edges_count * sizeof(ir_ref)); - if (ctx->binding) { ir_xlat_binding(ctx, _xlat); - new_ctx.binding = ctx->binding; - ctx->binding = NULL; } _xlat -= ctx->consts_count; ir_mem_free(_xlat); + ir_mem_free(_next); - new_ctx.cfg_blocks_count = ctx->cfg_blocks_count; - new_ctx.cfg_edges_count = ctx->cfg_edges_count; - new_ctx.cfg_blocks = ctx->cfg_blocks; - new_ctx.cfg_edges = ctx->cfg_edges; - ctx->cfg_blocks = NULL; - ctx->cfg_edges = NULL; - ctx->value_params = NULL; - ir_code_buffer *saved_code_buffer = ctx->code_buffer; - - ir_free(ctx); - IR_ASSERT(new_ctx.consts_count == new_ctx.consts_limit); - IR_ASSERT(new_ctx.insns_count == new_ctx.insns_limit); - memcpy(ctx, &new_ctx, sizeof(ir_ctx)); - ctx->code_buffer = saved_code_buffer; - ctx->flags2 |= IR_LINEAR; + /* Switch to new IR buffer */ + ir_mem_free(ctx->ir_base - ctx->consts_limit); + ctx->ir_base = base; + ctx->insns_count = ctx->insns_limit = insns_count; + ctx->consts_count = ctx->consts_limit = consts_count; + + ir_mem_free(ctx->use_lists); + ir_mem_free(ctx->use_edges); + IR_ASSERT(orig_use_edges_count >= use_edges_count); + ctx->use_lists = lists; + ctx->use_edges = use_edges; + ctx->use_edges_count = use_edges_count; - ir_mem_free(_next); + ir_mem_free(ctx->cfg_map); + ctx->cfg_map = map; + + ctx->prev_ref = _prev; + + ctx->flags2 |= IR_LINEAR; return 1; } diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_gdb.c php-8.4.20RC1/ext/opcache/jit/ir/ir_gdb.c --- php-8.4.18/ext/opcache/jit/ir/ir_gdb.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_gdb.c 2026-04-01 04:35:36.009855365 +0000 @@ -7,6 +7,10 @@ * Based on Mike Pall's implementation of GDB interface for LuaJIT. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + #include #include #include @@ -517,6 +521,8 @@ static bool ir_gdb_register_code(const void *object, size_t size) { ir_gdbjit_code_entry *entry; + ir_elf_header *elf_header; + ir_elf_sectheader *elf_section, *elf_section_end; entry = malloc(sizeof(ir_gdbjit_code_entry) + size); if (entry == NULL) { @@ -528,6 +534,17 @@ memcpy((char *)entry->symfile_addr, object, size); + elf_header = (ir_elf_header*)entry->symfile_addr; + elf_section = (ir_elf_sectheader*)(entry->symfile_addr + elf_header->shofs); + elf_section_end = (ir_elf_sectheader*)((char*)elf_section + (elf_header->shentsize * elf_header->shnum)); + + while (elf_section < elf_section_end) { + if ((elf_section->flags & ELFSECT_FLAGS_ALLOC) && elf_section->addr == 0) { + elf_section->addr = (uintptr_t)(entry->symfile_addr + elf_section->ofs); + } + elf_section = (ir_elf_sectheader*)((char*)elf_section + elf_header->shentsize); + } + entry->prev_entry = NULL; entry->next_entry = __jit_debug_descriptor.first_entry; diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir.h php-8.4.20RC1/ext/opcache/jit/ir/ir.h --- php-8.4.18/ext/opcache/jit/ir/ir.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir.h 2026-04-01 04:35:36.008176533 +0000 @@ -569,8 +569,6 @@ #define IR_OPT_CFG (1<<21) /* merge BBs, by remove END->BEGIN nodes during CFG construction */ #define IR_OPT_MEM2SSA (1<<22) #define IR_OPT_CODEGEN (1<<23) -#define IR_GEN_NATIVE (1<<24) -#define IR_GEN_CODE (1<<25) /* debug related */ #ifdef IR_DEBUG @@ -771,7 +769,7 @@ ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count); void ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val); -ir_ref ir_get_op(ir_ctx *ctx, ir_ref ref, int32_t n); +ir_ref ir_get_op(const ir_ctx *ctx, ir_ref ref, int32_t n); IR_ALWAYS_INLINE void ir_set_op1(ir_ctx *ctx, ir_ref ref, ir_ref val) { @@ -865,13 +863,13 @@ int ir_regs_number(void); bool ir_reg_is_int(int32_t reg); const char *ir_reg_name(int8_t reg, ir_type type); -int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref); +int32_t ir_get_spill_slot_offset(const ir_ctx *ctx, ir_ref ref); /* Target CPU instruction selection and code generation (see ir_x86.c) */ int ir_match(ir_ctx *ctx); void *ir_emit_code(ir_ctx *ctx, size_t *size); -bool ir_needs_thunk(ir_code_buffer *code_buffer, void *addr); +bool ir_needs_thunk(const ir_code_buffer *code_buffer, void *addr); void *ir_emit_thunk(ir_code_buffer *code_buffer, void *addr, size_t *size_ptr); void ir_fix_thunk(void *thunk_entry, void *addr); @@ -947,13 +945,14 @@ #define IR_SAVE_REGS (1<<4) /* add info about selected registers */ #define IR_SAVE_SAFE_NAMES (1<<5) /* add '@' prefix to symbol names */ +void ir_print_func_proto(const ir_ctx *ctx, const char *name, bool prefix, FILE *f); void ir_print_proto(const ir_ctx *ctx, ir_ref proto, FILE *f); void ir_print_proto_ex(uint8_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f); void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f); /* IR debug dump API (implementation in ir_dump.c) */ void ir_dump(const ir_ctx *ctx, FILE *f); -void ir_dump_dot(const ir_ctx *ctx, const char *name, FILE *f); +void ir_dump_dot(const ir_ctx *ctx, const char *name, const char *comments, FILE *f); void ir_dump_use_lists(const ir_ctx *ctx, FILE *f); void ir_dump_cfg(ir_ctx *ctx, FILE *f); void ir_dump_cfg_map(const ir_ctx *ctx, FILE *f); diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_perf.c php-8.4.20RC1/ext/opcache/jit/ir/ir_perf.c --- php-8.4.18/ext/opcache/jit/ir/ir_perf.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_perf.c 2026-04-01 04:35:36.009948752 +0000 @@ -14,6 +14,10 @@ * perf report -i perf.data.jitted */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + #include #include #include @@ -26,7 +30,7 @@ #if defined(__linux__) #include -#elif defined(__darwin__) +#elif defined(__APPLE__) # include #elif defined(__FreeBSD__) # include @@ -211,7 +215,7 @@ uint32_t thread_id = 0; #if defined(__linux__) thread_id = syscall(SYS_gettid); -#elif defined(__darwin__) +#elif defined(__APPLE__) uint64_t thread_id_u64; pthread_threadid_np(NULL, &thread_id_u64); thread_id = (uint32_t) thread_id_u64; diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_private.h php-8.4.20RC1/ext/opcache/jit/ir/ir_private.h --- php-8.4.18/ext/opcache/jit/ir/ir_private.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_private.h 2026-04-01 04:35:36.010041096 +0000 @@ -908,7 +908,7 @@ return 0; } -IR_ALWAYS_INLINE bool ir_ref_is_true(ir_ctx *ctx, ir_ref ref) +IR_ALWAYS_INLINE bool ir_ref_is_true(const ir_ctx *ctx, ir_ref ref) { if (ref == IR_TRUE) { return 1; @@ -1096,6 +1096,7 @@ void ir_update_op(ir_ctx *ctx, ir_ref ref, uint32_t idx, ir_ref new_val); /*** Iterative Optimization ***/ +void ir_iter_add_uses(ir_ctx *ctx, ir_ref ref, ir_bitqueue *worklist); void ir_iter_replace(ir_ctx *ctx, ir_ref ref, ir_ref new_ref, ir_bitqueue *worklist); void ir_iter_update_op(ir_ctx *ctx, ir_ref ref, uint32_t idx, ir_ref new_val, ir_bitqueue *worklist); void ir_iter_opt(ir_ctx *ctx, ir_bitqueue *worklist); @@ -1144,12 +1145,15 @@ }; union { uint32_t dom_depth; /* depth from the root of the dominators tree */ - uint32_t postnum; /* used temporary during tree constructon */ + uint32_t postnum; /* used temporary for iterative Post Ordering */ }; uint32_t dom_child; /* first dominated blocks */ uint32_t dom_next_child; /* next dominated block (linked list) */ uint32_t loop_header; - uint32_t loop_depth; + union { + uint32_t loop_depth; + uint32_t next_succ; /* used temporary for iterative Post Ordering */ + }; }; void ir_build_prev_refs(ir_ctx *ctx); @@ -1179,16 +1183,17 @@ IR_FOLD_DO_CONST } ir_fold_action; -ir_ref ir_folding(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3, ir_insn *op1_insn, ir_insn *op2_insn, ir_insn *op3_insn); +ir_ref ir_folding(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3, + const ir_insn *op1_insn, const ir_insn *op2_insn, const ir_insn *op3_insn); /*** Alias Analyzes (see ir.c) ***/ -ir_ref ir_find_aliasing_load(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr); -ir_ref ir_find_aliasing_vload(ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var); +ir_ref ir_find_aliasing_load(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref addr); +ir_ref ir_find_aliasing_vload(const ir_ctx *ctx, ir_ref ref, ir_type type, ir_ref var); ir_ref ir_find_aliasing_store(ir_ctx *ctx, ir_ref ref, ir_ref addr, ir_ref val); ir_ref ir_find_aliasing_vstore(ir_ctx *ctx, ir_ref ref, ir_ref addr, ir_ref val); /*** Predicates (see ir.c) ***/ -ir_ref ir_check_dominating_predicates(ir_ctx *ctx, ir_ref ref, ir_ref condition); +ir_ref ir_check_dominating_predicates(const ir_ctx *ctx, ir_ref ref, ir_ref condition); /*** IR Live Info ***/ typedef ir_ref ir_live_pos; @@ -1468,9 +1473,7 @@ void ir_fix_stack_frame(ir_ctx *ctx); /* Utility */ -ir_type ir_get_return_type(ir_ctx *ctx); const ir_proto_t *ir_call_proto(const ir_ctx *ctx, const ir_insn *insn); -void ir_print_call_conv(uint32_t flags, FILE *f); //#define IR_BITSET_LIVENESS diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_ra.c php-8.4.20RC1/ext/opcache/jit/ir/ir_ra.c --- php-8.4.18/ext/opcache/jit/ir/ir_ra.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_ra.c 2026-04-01 04:35:36.010241264 +0000 @@ -3761,14 +3761,13 @@ { char key[10]; - IR_ASSERT(reg != IR_REG_NONE); if (!ctx->fused_regs) { ctx->fused_regs = ir_mem_malloc(sizeof(ir_strtab)); ir_strtab_init(ctx->fused_regs, 8, 128); } memcpy(key, &root, sizeof(ir_ref)); memcpy(key + 4, &ref_and_op, sizeof(ir_ref)); - ir_strtab_lookup(ctx->fused_regs, key, 8, 0x10000000 | reg); + ir_strtab_lookup(ctx->fused_regs, key, 8, 0x10000000 | (uint8_t)reg); } static void assign_regs(ir_ctx *ctx) @@ -3874,93 +3873,88 @@ } prev_use_ref = ref; } - } else if ((!prev_use_ref || ctx->cfg_map[prev_use_ref] != ctx->cfg_map[ref]) - && needs_spill_reload(ctx, ival, ctx->cfg_map[ref], available)) { - if (!(use_pos->flags & IR_USE_MUST_BE_IN_REG) - && use_pos->hint != reg -// && ctx->ir_base[ref].op != IR_CALL -// && ctx->ir_base[ref].op != IR_TAILCALL) { - && ctx->ir_base[ref].op != IR_SNAPSHOT - && !needs_spill_load(ctx, ival, use_pos)) { - /* fuse spill load (valid only when register is not reused) */ - reg = IR_REG_NONE; - if (use_pos->next - && use_pos->op_num == 1 - && use_pos->next->pos == use_pos->pos - && !(use_pos->next->flags & IR_USE_MUST_BE_IN_REG)) { - /* Support for R2 = BINOP(R1, R1) */ - if (use_pos->hint_ref < 0) { - ref = -use_pos->hint_ref; + } else { + if ((!prev_use_ref || ctx->cfg_map[prev_use_ref] != ctx->cfg_map[ref]) + && needs_spill_reload(ctx, ival, ctx->cfg_map[ref], available)) { + if (!(use_pos->flags & IR_USE_MUST_BE_IN_REG) + && use_pos->hint != reg +// && ctx->ir_base[ref].op != IR_CALL +// && ctx->ir_base[ref].op != IR_TAILCALL) { + && ctx->ir_base[ref].op != IR_SNAPSHOT + && !needs_spill_load(ctx, ival, use_pos)) { + /* fuse spill load (valid only when register is not reused) */ + reg = IR_REG_NONE; + if (use_pos->next + && use_pos->op_num == 1 + && use_pos->next->pos == use_pos->pos + && !(use_pos->next->flags & IR_USE_MUST_BE_IN_REG)) { + /* Support for R2 = BINOP(R1, R1) */ + if (use_pos->hint_ref < 0) { + ref = -use_pos->hint_ref; + } + ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg); + use_pos = use_pos->next; } - ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg); - use_pos = use_pos->next; - } - } else { - if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) { - reg |= IR_REG_SPILL_SPECIAL; } else { - reg |= IR_REG_SPILL_LOAD; - } - if (ctx->ir_base[ref].op != IR_SNAPSHOT && !(use_pos->flags & IR_PHI_USE)) { - uint32_t use_b = ctx->cfg_map[ref]; + if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) { + reg |= IR_REG_SPILL_SPECIAL; + } else { + reg |= IR_REG_SPILL_LOAD; + } + if (ctx->ir_base[ref].op != IR_SNAPSHOT && !(use_pos->flags & IR_PHI_USE)) { + uint32_t use_b = ctx->cfg_map[ref]; - if (ir_ival_covers(ival, IR_SAVE_LIVE_POS_FROM_REF(ctx->cfg_blocks[use_b].end))) { - ir_bitset_incl(available, use_b); + if (ir_ival_covers(ival, IR_SAVE_LIVE_POS_FROM_REF(ctx->cfg_blocks[use_b].end))) { + ir_bitset_incl(available, use_b); + } + prev_use_ref = ref; } - prev_use_ref = ref; } + } else { + /* reuse register without spill load */ } - if (use_pos->hint_ref < 0 - && (old_reg = ir_get_alocated_reg(ctx, -use_pos->hint_ref, use_pos->op_num)) != IR_REG_NONE) { - if (top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL) { - reg |= IR_REG_SPILL_SPECIAL; + + if (use_pos->hint_ref < 0) { + if (use_pos->flags & IR_PHI_USE) { + IR_ASSERT(use_pos->hint_ref < 0); + IR_ASSERT(ctx->vregs[-use_pos->hint_ref]); + IR_ASSERT(ctx->live_intervals[ctx->vregs[-use_pos->hint_ref]]); + if (ctx->live_intervals[ctx->vregs[-use_pos->hint_ref]]->flags & IR_LIVE_INTERVAL_SPILLED) { + /* Spilled PHI var is passed through memory */ + reg = IR_REG_NONE; + } } else { - reg |= IR_REG_SPILL_LOAD; - } - if (reg != old_reg) { IR_ASSERT(ctx->rules[-use_pos->hint_ref] & IR_FUSED); - ctx->rules[-use_pos->hint_ref] |= IR_FUSED_REG; - ir_set_fused_reg(ctx, ref, -use_pos->hint_ref * sizeof(ir_ref) + use_pos->op_num, reg); - use_pos = use_pos->next; - continue; + old_reg = ir_get_alocated_reg(ctx, -use_pos->hint_ref, use_pos->op_num); + if ((old_reg != IR_REG_NONE && reg != old_reg) || reg == IR_REG_NONE) { + ctx->rules[-use_pos->hint_ref] |= IR_FUSED_REG; + ir_set_fused_reg(ctx, ref, -use_pos->hint_ref * sizeof(ir_ref) + use_pos->op_num, reg); + use_pos = use_pos->next; + continue; + } } + ref = -use_pos->hint_ref; } - } else if (use_pos->flags & IR_PHI_USE) { - IR_ASSERT(use_pos->hint_ref < 0); - IR_ASSERT(ctx->vregs[-use_pos->hint_ref]); - IR_ASSERT(ctx->live_intervals[ctx->vregs[-use_pos->hint_ref]]); - if (ctx->live_intervals[ctx->vregs[-use_pos->hint_ref]]->flags & IR_LIVE_INTERVAL_SPILLED) { - /* Spilled PHI var is passed through memory */ - reg = IR_REG_NONE; - } - } else if (use_pos->hint_ref < 0 - && (old_reg = ir_get_alocated_reg(ctx, -use_pos->hint_ref, use_pos->op_num)) != IR_REG_NONE) { - if (reg != old_reg) { - IR_ASSERT(ctx->rules[-use_pos->hint_ref] & IR_FUSED); - ctx->rules[-use_pos->hint_ref] |= IR_FUSED_REG; - ir_set_fused_reg(ctx, ref, -use_pos->hint_ref * sizeof(ir_ref) + use_pos->op_num, reg); - use_pos = use_pos->next; - continue; - } - } else { - /* reuse register without spill load */ - } - if (use_pos->hint_ref < 0) { - ref = -use_pos->hint_ref; } + ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg); use_pos = use_pos->next; } - } else if (!(top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL)) { + } else { use_pos = ival->use_pos; while (use_pos) { ref = IR_LIVE_POS_TO_REF(use_pos->pos); - if (ctx->ir_base[ref].op == IR_SNAPSHOT) { + if (ctx->ir_base[ref].op == IR_SNAPSHOT + && !(top_ival->flags & IR_LIVE_INTERVAL_SPILL_SPECIAL)) { IR_ASSERT(use_pos->hint_ref >= 0); /* A reference to a CPU spill slot */ reg = IR_REG_SPILL_STORE | IR_REG_STACK_POINTER; ir_set_alocated_reg(ctx, ref, use_pos->op_num, reg); + } else if (use_pos->hint_ref < 0 && !(use_pos->flags & IR_PHI_USE)) { + IR_ASSERT(ctx->rules[-use_pos->hint_ref] & IR_FUSED); + ctx->rules[-use_pos->hint_ref] |= IR_FUSED_REG; + ir_set_fused_reg(ctx, ref, -use_pos->hint_ref * sizeof(ir_ref) + use_pos->op_num, IR_REG_NONE); } use_pos = use_pos->next; } diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_save.c php-8.4.20RC1/ext/opcache/jit/ir/ir_save.c --- php-8.4.18/ext/opcache/jit/ir/ir_save.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_save.c 2026-04-01 04:35:36.010501847 +0000 @@ -18,7 +18,7 @@ } } -void ir_print_call_conv(uint32_t flags, FILE *f) +static void ir_print_call_conv(uint32_t flags, FILE *f) { switch (flags & IR_CALL_CONV_MASK) { case IR_CC_BUILTIN: @@ -74,6 +74,38 @@ fprintf(f, " __pure"); } } + +void ir_print_func_proto(const ir_ctx *ctx, const char *name, bool prefix, FILE *f) +{ + if (ctx->flags & IR_STATIC) { + fprintf(f, "static "); + } + fprintf(f, "func %s%s(", + prefix ? "@" : "", + name); + if (ctx->ir_base[2].op == IR_PARAM) { + ir_insn *insn = &ctx->ir_base[2]; + + fprintf(f, "%s", ir_type_cname[insn->type]); + insn++; + while (insn->op == IR_PARAM) { + fprintf(f, ", %s", ir_type_cname[insn->type]); + insn++;; + } + if (ctx->flags & IR_VARARG_FUNC) { + fprintf(f, ", ..."); + } + } else if (ctx->flags & IR_VARARG_FUNC) { + fprintf(f, "..."); + } + fprintf(f, "): %s", ir_type_cname[ctx->ret_type != (ir_type)-1 ? ctx->ret_type : IR_VOID]); + ir_print_call_conv(ctx->flags, f); + if (ctx->flags & IR_CONST_FUNC) { + fprintf(f, " __const"); + } else if (ctx->flags & IR_PURE_FUNC) { + fprintf(f, " __pure"); + } +} static void ir_save_dessa_moves(const ir_ctx *ctx, int b, ir_block *bb, FILE *f) { diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_sccp.c php-8.4.20RC1/ext/opcache/jit/ir/ir_sccp.c --- php-8.4.18/ext/opcache/jit/ir/ir_sccp.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_sccp.c 2026-04-01 04:35:36.010678971 +0000 @@ -19,7 +19,6 @@ #define IR_TOP IR_UNUSED #define IR_BOTTOM IR_LAST_OP -#define IR_MAKE_TOP(ref) do {IR_ASSERT(ref > 0); _values[ref].optx = IR_TOP;} while (0) #define IR_MAKE_BOTTOM(ref) do {IR_ASSERT(ref > 0); _values[ref].optx = IR_BOTTOM;} while (0) #define IR_IS_TOP(ref) (ref >= 0 && _values[ref].op == IR_TOP) @@ -27,17 +26,57 @@ #define IR_IS_REACHABLE(ref) _ir_is_reachable_ctrl(ctx, _values, ref) #define IR_IS_CONST(ref) (IR_IS_CONST_REF(ref) || IR_IS_CONST_OP(_values[ref].op)) -IR_ALWAYS_INLINE bool _ir_is_reachable_ctrl(ir_ctx *ctx, ir_insn *_values, ir_ref ref) +typedef struct { + union { + struct { + IR_STRUCT_LOHI( + union { + IR_STRUCT_LOHI( + union { + IR_STRUCT_LOHI( + uint8_t op, /* [IR_TOP - unreachable, IR_BOTTOM - reachable} for control */ + /* {IR_TOP | IR_COPY() | IR_CONST() | IR_BOTTOM} for data */ + /* {IR_TOP | IR_MERGE() | IR_BOTTOM} for IR_MERGE */ + /* {IR_TOP | IR_IF() | IR_BOTTOM} for IR_IF and IR_SWITCH */ + uint8_t type + ); + uint16_t opt; + }, + uint16_t _space_1 + ); + uint32_t optx; + }, + union { + ir_ref copy; /* identity for IR_COPY */ + ir_ref unfeasible_inputs; /* number of unfeasible inputs for IR_MERGE */ + ir_ref single_output; /* reachable output for IR_IF */ + ir_ref visited; /* for IR_TOP */ + } + ); + union { + struct { + ir_ref next; /* double-linked identities list for IR_COPY */ + ir_ref prev; /* double-linked identities list for IR_COPY */ + }; + ir_val val; /* constant value for IR_CONST */ + }; + }; + ir_insn insn; /* constant insn for IR_CONST */ + }; +} ir_sccp_val; + +IR_ALWAYS_INLINE bool _ir_is_reachable_ctrl(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref ref) { IR_ASSERT(!IR_IS_CONST_REF(ref)); IR_ASSERT(ir_op_flags[ctx->ir_base[ref].op] & IR_OP_FLAG_CONTROL); return _values[ref].op != IR_TOP; /* BOTTOM, IF or MERGE */ } -IR_ALWAYS_INLINE void ir_sccp_add_uses(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_ref ref) +IR_ALWAYS_INLINE void ir_sccp_add_uses(const ir_ctx *ctx, const ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref) { - ir_use_list *use_list; - ir_ref n, *p, use; + const ir_use_list *use_list; + const ir_ref *p; + ir_ref n, use; IR_ASSERT(!IR_IS_CONST_REF(ref)); use_list = &ctx->use_lists[ref]; @@ -50,23 +89,23 @@ } } -IR_ALWAYS_INLINE void ir_sccp_add_input(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_ref ref) +IR_ALWAYS_INLINE void ir_sccp_add_input(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref) { IR_ASSERT(!IR_IS_CONST_REF(ref)); IR_ASSERT(_values[ref].op == IR_TOP); /* do backward propagaton only once */ - if (!_values[ref].op1) { - _values[ref].op1 = 1; + if (!_values[ref].visited) { + _values[ref].visited = 1; ir_bitqueue_add(worklist, ref); } } #if IR_COMBO_COPY_PROPAGATION -IR_ALWAYS_INLINE ir_ref ir_sccp_identity(ir_ctx *ctx, ir_insn *_values, ir_ref a) +IR_ALWAYS_INLINE ir_ref ir_sccp_identity(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref a) { if (a > 0 && _values[a].op == IR_COPY) { do { - a = _values[a].op1; + a = _values[a].copy; IR_ASSERT(a > 0); } while (_values[a].op == IR_COPY); IR_ASSERT(_values[a].op == IR_BOTTOM); @@ -75,7 +114,7 @@ } #if 0 -static void CHECK_LIST(ir_insn *_values, ir_ref ref) +static void CHECK_LIST(ir_sccp_val *_values, ir_ref ref) { ir_ref member = _values[ref].op2; while (member != ref) { @@ -88,44 +127,44 @@ # define CHECK_LIST(_values, ref) #endif -static void ir_sccp_add_identity(ir_ctx *ctx, ir_insn *_values, ir_ref src, ir_ref dst) +static void ir_sccp_add_identity(const ir_ctx *ctx, ir_sccp_val *_values, ir_ref src, ir_ref dst) { IR_ASSERT(dst > 0 && _values[dst].op != IR_BOTTOM && _values[dst].op != IR_COPY); IR_ASSERT((src > 0 && (_values[src].op == IR_BOTTOM || _values[src].op == IR_COPY))); IR_ASSERT(ir_sccp_identity(ctx, _values, src) != dst); _values[dst].optx = IR_COPY; - _values[dst].op1 = src; + _values[dst].copy = src; if (_values[src].op == IR_BOTTOM) { /* initialize empty double-linked list */ - if (_values[src].op1 != src) { - _values[src].op1 = src; - _values[src].op2 = src; - _values[src].op3 = src; + if (_values[src].copy != src) { + _values[src].copy = src; + _values[src].next = src; + _values[src].prev = src; } } else { src = ir_sccp_identity(ctx, _values, src); } /* insert into circular double-linked list */ - ir_ref prev = _values[src].op3; - _values[dst].op2 = src; - _values[dst].op3 = prev; - _values[src].op3 = dst; - _values[prev].op2 = dst; + ir_ref prev = _values[src].prev; + _values[dst].next = src; + _values[dst].prev = prev; + _values[src].prev = dst; + _values[prev].next = dst; CHECK_LIST(_values, dst); } -static void ir_sccp_split_partition(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_ref ref) +static void ir_sccp_split_partition(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref) { ir_ref member, head, tail, next, prev; CHECK_LIST(_values, ref); IR_MAKE_BOTTOM(ref); - _values[ref].op1 = ref; + _values[ref].copy = ref; - member = _values[ref].op2; + member = _values[ref].next; head = tail = IR_UNUSED; while (member != ref) { if (_values[member].op != IR_BOTTOM) { @@ -133,19 +172,19 @@ } ir_sccp_add_uses(ctx, _values, worklist, member); - next = _values[member].op2; + next = _values[member].next; if (ir_sccp_identity(ctx, _values, member) == ref) { /* remove "member" from the old circular double-linked list */ - prev = _values[member].op3; - _values[prev].op2 = next; - _values[next].op3 = prev; + prev = _values[member].prev; + _values[prev].next = next; + _values[next].prev = prev; /* insert "member" into the new double-linked list */ if (!head) { head = tail = member; } else { - _values[tail].op2 = member; - _values[member].op3 = tail; + _values[tail].next = member; + _values[member].prev = tail; tail = member; } } @@ -153,26 +192,26 @@ } /* remove "ref" from the old circular double-linked list */ - next = _values[ref].op2; - prev = _values[ref].op3; - _values[prev].op2 = next; - _values[next].op3 = prev; + next = _values[ref].next; + prev = _values[ref].prev; + _values[prev].next = next; + _values[next].prev = prev; CHECK_LIST(_values, next); /* close the new circle */ if (head) { - _values[ref].op2 = head; - _values[ref].op3 = tail; - _values[tail].op2 = ref; - _values[head].op3 = ref; + _values[ref].next = head; + _values[ref].prev = tail; + _values[tail].next = ref; + _values[head].prev = ref; } else { - _values[ref].op2 = ref; - _values[ref].op3 = ref; + _values[ref].next = ref; + _values[ref].prev = ref; } CHECK_LIST(_values, ref); } -IR_ALWAYS_INLINE void ir_sccp_make_bottom_ex(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_ref ref) +IR_ALWAYS_INLINE void ir_sccp_make_bottom_ex(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref) { if (_values[ref].op == IR_COPY) { ir_sccp_split_partition(ctx, _values, worklist, ref); @@ -187,7 +226,7 @@ # define IR_MAKE_BOTTOM_EX(ref) IR_MAKE_BOTTOM(ref) #endif -IR_ALWAYS_INLINE bool ir_sccp_meet_const(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_ref ref, ir_insn *val_insn) +IR_ALWAYS_INLINE bool ir_sccp_meet_const(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, const ir_insn *val_insn) { IR_ASSERT(IR_IS_CONST_OP(val_insn->op) || IR_IS_SYM_CONST(val_insn->op)); @@ -207,46 +246,51 @@ return 1; } -IR_ALWAYS_INLINE bool ir_sccp_meet(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_ref ref, ir_ref val) +IR_ALWAYS_INLINE bool ir_sccp_meet_copy(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, ir_ref val) +{ +#if IR_COMBO_COPY_PROPAGATION + if (_values[ref].op == IR_COPY) { + /* COPY(OLD_VAL) meet COPY(NEW_VAL) => + * (IDENTITY(OLD_VAL) == IDENTITY(NEW_VAL) ? COPY(OLD_VAL) ? BOTTOM */ + if (ir_sccp_identity(ctx, _values, ref) == ir_sccp_identity(ctx, _values, val)) { + return 0; /* not changed */ + } + ir_sccp_split_partition(ctx, _values, worklist, ref); + return 1; + } else { + IR_ASSERT(_values[ref].op != IR_BOTTOM); + /* TOP meet COPY(NEW_VAL) -> COPY(NEW_VAL) */ + /* OLD_CONST meet COPY(NEW_VAL) -> COPY(NEW_VAL) */ + ir_sccp_add_identity(ctx, _values, val, ref); + return 1; + } +#endif + IR_MAKE_BOTTOM(ref); + return 1; +} + +#if 0 +IR_ALWAYS_INLINE bool ir_sccp_meet(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, ir_ref val) { - ir_ref val_identity = ir_sccp_identity(ctx, _values, val); - ir_insn *val_insn; + const ir_insn *val_insn; - if (IR_IS_CONST_REF(val_identity)) { - val_insn = &ctx->ir_base[val_identity]; + if (IR_IS_CONST_REF(val)) { + val_insn = &ctx->ir_base[val]; } else { - val_insn = &_values[val_identity]; + val_insn = &_values[val].insn; if (!IR_IS_CONST_OP(val_insn->op) && !IR_IS_SYM_CONST(val_insn->op)) { -#if IR_COMBO_COPY_PROPAGATION - if (_values[ref].op == IR_COPY) { - /* COPY(OLD_VAL) meet COPY(NEW_VAL) => - * (IDENTITY(OLD_VAL) == IDENTITY(NEW_VAL) ? COPY(OLD_VAL) ? BOTTOM */ - if (ir_sccp_identity(ctx, _values, ref) == val_identity) { - return 0; /* not changed */ - } - ir_sccp_split_partition(ctx, _values, worklist, ref); - return 1; - } else { - IR_ASSERT(_values[ref].op != IR_BOTTOM); - /* TOP meet COPY(NEW_VAL) -> COPY(NEW_VAL) */ - /* OLD_CONST meet COPY(NEW_VAL) -> COPY(NEW_VAL) */ - ir_sccp_add_identity(ctx, _values, val, ref); - return 1; - } -#endif - - IR_MAKE_BOTTOM(ref); - return 1; + return ir_sccp_meet_copy(ctx, _values, worklist, ref, val); } } return ir_sccp_meet_const(ctx, _values, worklist, ref, val_insn); } +#endif -static ir_ref ir_sccp_fold(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_ref ref, ir_insn *insn) +static ir_ref ir_sccp_fold(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref ref, const ir_insn *insn) { - ir_insn *op1_insn, *op2_insn, *op3_insn; + const ir_insn *op1_insn, *op2_insn, *op3_insn; ir_ref op1, op2, op3, copy; uint32_t opt = insn->opt; @@ -255,11 +299,11 @@ op3 = ir_sccp_identity(ctx, _values, insn->op3); restart: - op1_insn = (op1 > 0 && IR_IS_CONST_OP(_values[op1].op)) ? _values + op1 : ctx->ir_base + op1; - op2_insn = (op2 > 0 && IR_IS_CONST_OP(_values[op2].op)) ? _values + op2 : ctx->ir_base + op2; - op3_insn = (op3 > 0 && IR_IS_CONST_OP(_values[op3].op)) ? _values + op3 : ctx->ir_base + op3; + op1_insn = (op1 > 0 && IR_IS_CONST_OP(_values[op1].op)) ? &_values[op1].insn : ctx->ir_base + op1; + op2_insn = (op2 > 0 && IR_IS_CONST_OP(_values[op2].op)) ? &_values[op2].insn : ctx->ir_base + op2; + op3_insn = (op3 > 0 && IR_IS_CONST_OP(_values[op3].op)) ? &_values[op3].insn : ctx->ir_base + op3; - switch (ir_folding(ctx, opt, op1, op2, op3, op1_insn, op2_insn, op3_insn)) { + switch (ir_folding((ir_ctx*)ctx, opt, op1, op2, op3, op1_insn, op2_insn, op3_insn)) { case IR_FOLD_DO_RESTART: opt = ctx->fold_insn.optx; op1 = ctx->fold_insn.op1; @@ -272,19 +316,30 @@ return 1; case IR_FOLD_DO_COPY: copy = ctx->fold_insn.op1; - return ir_sccp_meet(ctx, _values, worklist, ref, copy); + if (IR_IS_CONST_REF(copy)) { + insn = &ctx->ir_base[copy]; + } else { + insn = &_values[copy].insn; + if (!IR_IS_CONST_OP(insn->op) && !IR_IS_SYM_CONST(insn->op)) { + return ir_sccp_meet_copy(ctx, _values, worklist, ref, copy); + } + } + goto meet_const; case IR_FOLD_DO_CONST: - return ir_sccp_meet_const(ctx, _values, worklist, ref, &ctx->fold_insn); + insn = &ctx->fold_insn; +meet_const: + return ir_sccp_meet_const(ctx, _values, worklist, ref, insn); default: IR_ASSERT(0); return 0; } } -static bool ir_sccp_analyze_phi(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_ref i, ir_insn *insn) +static bool ir_sccp_analyze_phi(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_ref i, const ir_insn *insn) { - ir_ref j, n, input, *merge_input, *p; - ir_insn *v, *new_const = NULL; + ir_ref j, n, input; + const ir_ref *merge_input, *p; + const ir_insn *v, *new_const = NULL; #if IR_COMBO_COPY_PROPAGATION ir_ref new_copy = IR_UNUSED; ir_ref new_copy_identity = IR_UNUSED; @@ -315,7 +370,7 @@ } else if (input == i) { continue; } else { - v = &_values[input]; + v = &_values[input].insn; if (v->op == IR_TOP) { ir_sccp_add_input(ctx, _values, worklist, input); continue; @@ -369,7 +424,7 @@ } else if (input == i) { continue; } else { - v = &_values[input]; + v = &_values[input].insn; if (v->op == IR_TOP) { ir_sccp_add_input(ctx, _values, worklist, input); continue; @@ -398,7 +453,9 @@ #if IR_COMBO_COPY_PROPAGATION if (new_copy) { - return ir_sccp_meet(ctx, _values, worklist, i, new_copy); + IR_ASSERT(!IR_IS_CONST_REF(new_copy)); + IR_ASSERT(!IR_IS_CONST_OP(_values[new_copy].op) && !IR_IS_SYM_CONST(_values[new_copy].op)); + return ir_sccp_meet_copy(ctx, _values, worklist, i, new_copy); } #endif @@ -409,7 +466,7 @@ return 1; } -static bool ir_is_dead_load_ex(ir_ctx *ctx, ir_ref ref, uint32_t flags, ir_insn *insn) +static bool ir_is_dead_load_ex(const ir_ctx *ctx, ir_ref ref, uint32_t flags, const ir_insn *insn) { if ((flags & (IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_MASK)) == (IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_LOAD)) { return ctx->use_lists[ref].count == 1; @@ -419,10 +476,10 @@ return 0; } -static bool ir_is_dead_load(ir_ctx *ctx, ir_ref ref) +static bool ir_is_dead_load(const ir_ctx *ctx, ir_ref ref) { if (ctx->use_lists[ref].count == 1) { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; uint32_t flags = ir_op_flags[insn->op]; if ((flags & (IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_MASK)) == (IR_OP_FLAG_MEM|IR_OP_FLAG_MEM_LOAD)) { @@ -434,7 +491,7 @@ return 0; } -static bool ir_is_dead(ir_ctx *ctx, ir_ref ref) +static bool ir_is_dead(const ir_ctx *ctx, ir_ref ref) { if (ctx->use_lists[ref].count == 0) { return IR_IS_FOLDABLE_OP(ctx->ir_base[ref].op); @@ -444,28 +501,28 @@ return 0; } -static bool ir_sccp_is_true(ir_ctx *ctx, ir_insn *_values, ir_ref a) +static bool ir_sccp_is_true(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref a) { - ir_insn *v = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a]; + const ir_insn *v = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a].insn; return ir_const_is_true(v); } -static bool ir_sccp_is_equal(ir_ctx *ctx, ir_insn *_values, ir_ref a, ir_ref b) +static bool ir_sccp_is_equal(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref a, ir_ref b) { - ir_insn *v1 = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a]; - ir_insn *v2 = IR_IS_CONST_REF(b) ? &ctx->ir_base[b] : &_values[b]; + const ir_insn *v1 = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a].insn; + const ir_insn *v2 = IR_IS_CONST_REF(b) ? &ctx->ir_base[b] : &_values[b].insn; IR_ASSERT(!IR_IS_SYM_CONST(v1->op)); IR_ASSERT(!IR_IS_SYM_CONST(v2->op)); return v1->val.u64 == v2->val.u64; } -static bool ir_sccp_in_range(ir_ctx *ctx, ir_insn *_values, ir_ref a, ir_ref b, ir_ref c) +static bool ir_sccp_in_range(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref a, ir_ref b, ir_ref c) { - ir_insn *v1 = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a]; - ir_insn *v2 = IR_IS_CONST_REF(b) ? &ctx->ir_base[b] : &_values[b]; - ir_insn *v3 = IR_IS_CONST_REF(c) ? &ctx->ir_base[c] : &_values[c]; + const ir_insn *v1 = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a].insn; + const ir_insn *v2 = IR_IS_CONST_REF(b) ? &ctx->ir_base[b] : &_values[b].insn; + const ir_insn *v3 = IR_IS_CONST_REF(c) ? &ctx->ir_base[c] : &_values[c].insn; IR_ASSERT(!IR_IS_SYM_CONST(v1->op)); IR_ASSERT(!IR_IS_SYM_CONST(v2->op)); @@ -478,13 +535,13 @@ } #ifdef IR_SCCP_TRACE -static void ir_sccp_trace_val(ir_ctx *ctx, ir_insn *_values, ir_ref i) +static void ir_sccp_trace_val(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref i) { if (IR_IS_BOTTOM(i)) { fprintf(stderr, "BOTTOM"); } else if (IR_IS_CONST_OP(_values[i].op) || IR_IS_SYM_CONST(_values[i].op)) { fprintf(stderr, "CONST("); - ir_print_const(ctx, &_values[i], stderr, true); + ir_print_const(ctx, &_values[i].insn, stderr, true); fprintf(stderr, ")"); #if IR_COMBO_COPY_PROPAGATION } else if (_values[i].op == IR_COPY) { @@ -501,13 +558,13 @@ } } -static void ir_sccp_trace_start(ir_ctx *ctx, ir_insn *_values, ir_ref i) +static void ir_sccp_trace_start(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref i) { fprintf(stderr, "%d. ", i); ir_sccp_trace_val(ctx, _values, i); } -static void ir_sccp_trace_end(ir_ctx *ctx, ir_insn *_values, ir_ref i) +static void ir_sccp_trace_end(const ir_ctx *ctx, const ir_sccp_val *_values, ir_ref i) { fprintf(stderr, " -> "); ir_sccp_trace_val(ctx, _values, i); @@ -518,11 +575,12 @@ # define ir_sccp_trace_end(c, v, i) #endif -static IR_NEVER_INLINE void ir_sccp_analyze(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_bitqueue *iter_worklist) +static IR_NEVER_INLINE void ir_sccp_analyze(const ir_ctx *ctx, ir_sccp_val *_values, ir_bitqueue *worklist, ir_bitqueue *iter_worklist) { - ir_ref i, j, n, *p, use; - ir_use_list *use_list; - ir_insn *insn, *use_insn; + ir_ref i, j, n, use; + const ir_ref *p; + const ir_use_list *use_list; + const ir_insn *insn, *use_insn; uint32_t flags; /* A bit modified SCCP algorithm of M. N. Wegman and F. K. Zadeck */ @@ -610,7 +668,7 @@ } } for (p = insn->ops + 1; n > 0; p++, n--) { - ir_ref input = *p; + const ir_ref input = *p; IR_ASSERT(input > 0); if (!IR_IS_REACHABLE(input)) { unfeasible_inputs++; @@ -618,9 +676,9 @@ } if (unfeasible_inputs == 0) { IR_MAKE_BOTTOM(i); - } else if (_values[i].op != IR_MERGE || _values[i].op1 != unfeasible_inputs) { + } else if (_values[i].op != IR_MERGE || _values[i].unfeasible_inputs != unfeasible_inputs) { _values[i].optx = IR_MERGE; - _values[i].op1 = unfeasible_inputs; + _values[i].unfeasible_inputs = unfeasible_inputs; } else { continue; } @@ -674,10 +732,10 @@ } if (_values[i].op == IR_TOP) { _values[i].optx = IR_IF; - _values[i].op1 = use; + _values[i].single_output = use; ir_bitqueue_add(worklist, use); continue; - } else if (_values[i].op == IR_IF && _values[i].op1 == use) { + } else if (_values[i].op == IR_IF && _values[i].single_output == use) { continue; } } @@ -715,10 +773,10 @@ use_insn = &ctx->ir_base[use_case]; if (_values[i].op == IR_TOP) { _values[i].optx = IR_IF; - _values[i].op1 = use_case; + _values[i].single_output = use_case; ir_bitqueue_add(worklist, use_case); continue; - } else if (_values[i].op == IR_IF || _values[i].op1 == use_case) { + } else if (_values[i].op == IR_IF || _values[i].single_output == use_case) { continue; } } @@ -768,18 +826,20 @@ for (i = 1; i < ctx->insns_count; i++) { if (IR_IS_CONST_OP(_values[i].op) || IR_IS_SYM_CONST(_values[i].op)) { fprintf(stderr, "%d. CONST(", i); - ir_print_const(ctx, &_values[i], stderr, true); + ir_print_const(ctx, &_values[i].insn, stderr, true); fprintf(stderr, ")\n"); #if IR_COMBO_COPY_PROPAGATION } else if (_values[i].op == IR_COPY) { - fprintf(stderr, "%d. COPY(%d)\n", i, _values[i].op1); + fprintf(stderr, "%d. COPY(%d)\n", i, _values[i].copy); #endif } else if (IR_IS_TOP(i)) { - fprintf(stderr, "%d. TOP\n", i); + if (ctx->ir_base[i].op != IR_TOP) { + fprintf(stderr, "%d. TOP\n", i); + } } else if (_values[i].op == IR_IF) { - fprintf(stderr, "%d. IF(%d)\n", i, _values[i].op1); + fprintf(stderr, "%d. IF(%d)\n", i, _values[i].single_output); } else if (_values[i].op == IR_MERGE) { - fprintf(stderr, "%d. MERGE(%d)\n", i, _values[i].op1); + fprintf(stderr, "%d. MERGE(%d)\n", i, _values[i].unfeasible_inputs); } else if (!IR_IS_BOTTOM(i)) { fprintf(stderr, "%d. %d\n", i, _values[i].op); } @@ -806,7 +866,7 @@ } } -static void ir_sccp_remove_insn(ir_ctx *ctx, ir_insn *_values, ir_ref ref, ir_bitqueue *worklist) +static void ir_sccp_remove_insn(ir_ctx *ctx, const ir_sccp_val *_values, ir_ref ref, ir_bitqueue *worklist) { ir_ref j, n, *p; ir_insn *insn; @@ -820,7 +880,7 @@ *p = IR_UNUSED; /* we may skip nodes that are going to be removed by SCCP (TOP, CONST and COPY) */ if (input > 0 && _values[input].op > IR_COPY) { - ir_use_list_remove_all(ctx, input, ref); + ir_use_list_remove_one(ctx, input, ref); if (ir_is_dead(ctx, input)) { /* schedule DCE */ ir_bitqueue_add(worklist, input); @@ -829,7 +889,7 @@ } } -static void ir_sccp_replace_insn(ir_ctx *ctx, ir_insn *_values, ir_ref ref, ir_ref new_ref, ir_bitqueue *worklist) +static void ir_sccp_replace_insn(ir_ctx *ctx, const ir_sccp_val *_values, ir_ref ref, ir_ref new_ref, ir_bitqueue *worklist) { ir_ref j, n, *p, use, i; ir_insn *insn; @@ -858,7 +918,7 @@ *p = IR_UNUSED; /* we may skip nodes that are going to be removed by SCCP (TOP, CONST and COPY) */ if (input > 0 && _values[input].op > IR_COPY) { - ir_use_list_remove_all(ctx, input, ref); + ir_use_list_remove_one(ctx, input, ref); if (ir_is_dead(ctx, input)) { /* schedule DCE */ ir_bitqueue_add(worklist, input); @@ -907,7 +967,7 @@ CLEAR_USES(ref); } -static void ir_sccp_remove_if(ir_ctx *ctx, ir_insn *_values, ir_ref ref, ir_ref dst) +static void ir_sccp_remove_if(ir_ctx *ctx, const ir_sccp_val *_values, ir_ref ref, ir_ref dst) { ir_ref next; ir_insn *insn, *next_insn; @@ -1054,10 +1114,10 @@ return 1; } -static IR_NEVER_INLINE void ir_sccp_transform(ir_ctx *ctx, ir_insn *_values, ir_bitqueue *worklist, ir_bitqueue *iter_worklist) +static IR_NEVER_INLINE void ir_sccp_transform(ir_ctx *ctx, const ir_sccp_val *_values, ir_bitqueue *worklist, ir_bitqueue *iter_worklist) { ir_ref i, j; - ir_insn *value; + const ir_sccp_val *value; for (i = 1, value = _values + i; i < ctx->insns_count; value++, i++) { if (value->op == IR_BOTTOM) { @@ -1072,7 +1132,7 @@ ir_sccp_replace_insn(ctx, _values, i, j, iter_worklist); #if IR_COMBO_COPY_PROPAGATION } else if (value->op == IR_COPY) { - ir_sccp_replace_insn(ctx, _values, i, ir_sccp_identity(ctx, _values, value->op1), iter_worklist); + ir_sccp_replace_insn(ctx, _values, i, ir_sccp_identity(ctx, _values, value->copy), iter_worklist); #endif } else if (value->op == IR_TOP) { /* remove unreachable instruction */ @@ -1104,7 +1164,7 @@ } } else if (value->op == IR_IF) { /* remove one way IF/SWITCH */ - ir_sccp_remove_if(ctx, _values, i, value->op1); + ir_sccp_remove_if(ctx, _values, i, value->single_output); } else if (value->op == IR_MERGE) { /* schedule merge to remove unfeasible MERGE inputs */ ir_bitqueue_add(worklist, i); @@ -1121,6 +1181,16 @@ /* Iterative Optimizations */ /***************************/ +void ir_iter_add_uses(ir_ctx *ctx, ir_ref ref, ir_bitqueue *worklist) +{ + ir_use_list *use_list = &ctx->use_lists[ref]; + ir_ref *p, n = use_list->count; + + for (p = &ctx->use_edges[use_list->refs]; n > 0; p++, n--) { + ir_bitqueue_add(worklist, *p); + } +} + /* Modification of some instruction may open new optimization oprtunities for other * instructions that use this one. * @@ -1132,16 +1202,16 @@ * * TODO: Think abput a more general solution ??? */ -static void ir_iter_add_related_uses(ir_ctx *ctx, ir_ref ref, ir_bitqueue *worklist) +static void ir_iter_add_related_uses(const ir_ctx *ctx, ir_ref ref, ir_bitqueue *worklist) { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; if (insn->op == IR_ADD || insn->op == IR_SUB) { - ir_use_list *use_list = &ctx->use_lists[ref]; + const ir_use_list *use_list = &ctx->use_lists[ref]; if (use_list->count == 1) { ir_ref use = ctx->use_edges[use_list->refs]; - ir_insn *use_insn = &ctx->ir_base[ref]; + const ir_insn *use_insn = &ctx->ir_base[ref]; if (use_insn->op == IR_ADD || use_insn->op == IR_SUB) { ir_bitqueue_add(worklist, use); @@ -1163,7 +1233,7 @@ ir_ref input = *p; *p = IR_UNUSED; if (input > 0) { - ir_use_list_remove_all(ctx, input, ref); + ir_use_list_remove_one(ctx, input, ref); if (ir_is_dead(ctx, input)) { /* schedule DCE */ ir_bitqueue_add(worklist, input); @@ -1231,7 +1301,7 @@ ir_ref input = *p; *p = IR_UNUSED; if (input > 0) { - ir_use_list_remove_all(ctx, input, ref); + ir_use_list_remove_one(ctx, input, ref); if (ir_is_dead(ctx, input)) { /* schedule DCE */ ir_bitqueue_add(worklist, input); @@ -1266,16 +1336,17 @@ } } -static ir_ref ir_iter_find_cse1(ir_ctx *ctx, uint32_t optx, ir_ref op1) +static ir_ref ir_iter_find_cse1(const ir_ctx *ctx, uint32_t optx, ir_ref op1) { IR_ASSERT(!IR_IS_CONST_REF(op1)); - ir_use_list *use_list = &ctx->use_lists[op1]; - ir_ref *p, n = use_list->count; + const ir_use_list *use_list = &ctx->use_lists[op1]; + const ir_ref *p; + ir_ref n = use_list->count; for (p = ctx->use_edges + use_list->refs; n > 0; p++, n--) { ir_ref use = *p; - ir_insn *use_insn = &ctx->ir_base[use]; + const ir_insn *use_insn = &ctx->ir_base[use]; if (use_insn->optx == optx) { IR_ASSERT(use_insn->op1 == op1); @@ -1285,12 +1356,13 @@ return IR_UNUSED; } -static ir_ref ir_iter_find_cse(ir_ctx *ctx, ir_ref ref, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3, ir_bitqueue *worklist) +static ir_ref ir_iter_find_cse(const ir_ctx *ctx, ir_ref ref, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3, ir_bitqueue *worklist) { uint32_t n = IR_INPUT_EDGES_COUNT(ir_op_flags[opt & IR_OPT_OP_MASK]); - ir_use_list *use_list = NULL; - ir_ref *p, use; - ir_insn *use_insn; + const ir_use_list *use_list = NULL; + const ir_ref *p; + ir_ref use; + const ir_insn *use_insn; if (n == 2) { if (!IR_IS_CONST_REF(op1)) { @@ -1373,7 +1445,8 @@ { uint32_t opt; ir_ref op1, op2, op3, copy; - ir_insn *op1_insn, *op2_insn, *op3_insn, *insn; + const ir_insn *op1_insn, *op2_insn, *op3_insn; + ir_insn *insn; insn = &ctx->ir_base[ref]; opt = insn->opt; @@ -1408,9 +1481,6 @@ || insn->op2 != ctx->fold_insn.op2 || insn->op3 != ctx->fold_insn.op3) { - ir_use_list *use_list; - ir_ref n, j, *p, use; - insn->optx = ctx->fold_insn.opt; IR_ASSERT(!IR_OP_HAS_VAR_INPUTS(ir_op_flags[opt & IR_OPT_OP_MASK])); insn->inputs_count = IR_INPUT_EDGES_COUNT(ir_op_flags[opt & IR_OPT_OP_MASK]); @@ -1442,12 +1512,7 @@ insn->op2 = ctx->fold_insn.op2; insn->op3 = ctx->fold_insn.op3; - use_list = &ctx->use_lists[ref]; - n = use_list->count; - for (j = 0, p = &ctx->use_edges[use_list->refs]; j < n; j++, p++) { - use = *p; - ir_bitqueue_add(worklist, use); - } + ir_iter_add_uses(ctx, ref, worklist); } break; case IR_FOLD_DO_COPY: @@ -1464,9 +1529,9 @@ } } -static bool ir_may_promote_d2f(ir_ctx *ctx, ir_ref ref) +static bool ir_may_promote_d2f(const ir_ctx *ctx, ir_ref ref) { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; IR_ASSERT(insn->type == IR_DOUBLE); if (IR_IS_CONST_REF(ref)) { @@ -1497,9 +1562,9 @@ return 0; } -static bool ir_may_promote_f2d(ir_ctx *ctx, ir_ref ref) +static bool ir_may_promote_f2d(const ir_ctx *ctx, ir_ref ref) { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; IR_ASSERT(insn->type == IR_FLOAT); if (IR_IS_CONST_REF(ref)) { @@ -1668,10 +1733,11 @@ return ref; } -static bool ir_may_promote_trunc(ir_ctx *ctx, ir_type type, ir_ref ref) +static bool ir_may_promote_trunc(const ir_ctx *ctx, ir_type type, ir_ref ref) { - ir_insn *insn = &ctx->ir_base[ref]; - ir_ref *p, n, input; + const ir_insn *insn = &ctx->ir_base[ref]; + const ir_ref *p; + ir_ref n, input; if (IR_IS_CONST_REF(ref)) { return !IR_IS_SYM_CONST(insn->op); @@ -1777,6 +1843,7 @@ } } insn->type = type; + ir_iter_add_uses(ctx, ref, worklist); return ref; } @@ -1857,7 +1924,7 @@ return ref; } -static ir_ref ir_ext_const(ir_ctx *ctx, ir_insn *val_insn, ir_op op, ir_type type) +static ir_ref ir_ext_const(ir_ctx *ctx, const ir_insn *val_insn, ir_op op, ir_type type) { ir_val new_val; @@ -1921,10 +1988,11 @@ return ref; } -static uint32_t _ir_estimated_control(ir_ctx *ctx, ir_ref val, ir_ref loop) +static uint32_t _ir_estimated_control(const ir_ctx *ctx, ir_ref val, ir_ref loop) { - ir_insn *insn; - ir_ref n, *p, input, result, ctrl; + const ir_insn *insn; + const ir_ref *p; + ir_ref n, input, result, ctrl; if (IR_IS_CONST_REF(val)) { return 1; /* IR_START */ @@ -1955,18 +2023,18 @@ return result; } -static bool ir_is_loop_invariant(ir_ctx *ctx, ir_ref ref, ir_ref loop) +static bool ir_is_loop_invariant(const ir_ctx *ctx, ir_ref ref, ir_ref loop) { ref = _ir_estimated_control(ctx, ref, loop); return ref < loop; // TODO: check dominance instead of order } -static bool ir_is_cheaper_ext(ir_ctx *ctx, ir_ref ref, ir_ref loop, ir_ref ext_ref, ir_op op) +static bool ir_is_cheaper_ext(const ir_ctx *ctx, ir_ref ref, ir_ref loop, ir_ref ext_ref, ir_op op) { if (IR_IS_CONST_REF(ref)) { return 1; } else { - ir_insn *insn = &ctx->ir_base[ref]; + const ir_insn *insn = &ctx->ir_base[ref]; if (insn->op == IR_LOAD) { if (ir_is_loop_invariant(ctx, ref, loop)) { @@ -1982,7 +2050,7 @@ for (p = &ctx->use_edges[use_list->refs], n = use_list->count; n > 0; p++, n--) { use = *p; if (use != ext_ref) { - ir_insn *use_insn = &ctx->ir_base[use]; + const ir_insn *use_insn = &ctx->ir_base[use]; if (use_insn->op != op && (!(ir_op_flags[use_insn->op] & (IR_OP_FLAG_CONTROL|IR_OP_FLAG_MEM)) @@ -2018,7 +2086,7 @@ if (use == op_ref || use == ext_ref) { continue; } else { - ir_insn *use_insn = &ctx->ir_base[use]; + const ir_insn *use_insn = &ctx->ir_base[use]; if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) { if (use_insn->op1 == phi_ref) { @@ -2057,7 +2125,7 @@ if (use == phi_ref || use == ext_ref) { continue; } else { - ir_insn *use_insn = &ctx->ir_base[use]; + const ir_insn *use_insn = &ctx->ir_base[use]; if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) { if (use_insn->op1 == phi_ref) { @@ -2194,7 +2262,7 @@ } static bool ir_try_promote_ext(ir_ctx *ctx, ir_ref ext_ref, ir_insn *insn, ir_bitqueue *worklist) - { +{ ir_ref ref = insn->op1; /* Check for simple induction variable in the form: x2 = PHI(loop, x1, x3); x3 = ADD(x2, _); */ @@ -2359,7 +2427,7 @@ next->op1 = root->op1; ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref); if (!IR_IS_CONST_REF(root->op2)) { - ir_use_list_remove_all(ctx, root->op2, root_ref); + ir_use_list_remove_one(ctx, root->op2, root_ref); if (ir_is_dead(ctx, root->op2)) { ir_bitqueue_add(worklist, root->op2); } @@ -2417,7 +2485,7 @@ ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref); if (!IR_IS_CONST_REF(root->op2)) { - ir_use_list_remove_all(ctx, root->op2, root_ref); + ir_use_list_remove_one(ctx, root->op2, root_ref); if (ir_is_dead(ctx, root->op2)) { ir_bitqueue_add(worklist, root->op2); } @@ -2445,7 +2513,7 @@ } } -static bool ir_is_zero(ir_ctx *ctx, ir_ref ref) +static bool ir_is_zero(const ir_ctx *ctx, ir_ref ref) { return IR_IS_CONST_REF(ref) && !IR_IS_SYM_CONST(ctx->ir_base[ref].op) @@ -2470,7 +2538,7 @@ ir_ref root_ref = start1->op1; ir_insn *root = &ctx->ir_base[root_ref]; - if (root->op == IR_IF && !IR_IS_CONST_REF(root->op2) && ctx->use_lists[root->op2].count == 1) { + if (root->op == IR_IF && !IR_IS_CONST_REF(root->op2)) { ir_ref cond_ref = root->op2; ir_insn *cond = &ctx->ir_base[cond_ref]; ir_type type = insn->type; @@ -2544,13 +2612,17 @@ next->op1 = root->op1; ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref); if (!IR_IS_CONST_REF(insn->op1)) { - ir_use_list_remove_all(ctx, insn->op1, cond_ref); + ir_use_list_remove_one(ctx, insn->op1, cond_ref); } if (!IR_IS_CONST_REF(insn->op2)) { - ir_use_list_remove_all(ctx, insn->op2, cond_ref); + ir_use_list_remove_one(ctx, insn->op2, cond_ref); } - MAKE_NOP(cond); CLEAR_USES(cond_ref); + if (ctx->use_lists[cond_ref].count == 1) { + MAKE_NOP(cond); CLEAR_USES(cond_ref); + } else { + ir_use_list_remove_one(ctx, cond_ref, root_ref); + } MAKE_NOP(root); CLEAR_USES(root_ref); MAKE_NOP(start1); CLEAR_USES(start1_ref); MAKE_NOP(start2); CLEAR_USES(start2_ref); @@ -2633,10 +2705,14 @@ ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref); ir_use_list_remove_one(ctx, insn->op1, neg_ref); if (!IR_IS_CONST_REF(insn->op1)) { - ir_use_list_remove_all(ctx, insn->op1, cond_ref); + ir_use_list_remove_one(ctx, insn->op1, cond_ref); } - MAKE_NOP(cond); CLEAR_USES(cond_ref); + if (ctx->use_lists[cond_ref].count == 1) { + MAKE_NOP(cond); CLEAR_USES(cond_ref); + } else { + ir_use_list_remove_one(ctx, cond_ref, root_ref); + } MAKE_NOP(root); CLEAR_USES(root_ref); MAKE_NOP(start1); CLEAR_USES(start1_ref); MAKE_NOP(start2); CLEAR_USES(start2_ref); @@ -2650,8 +2726,7 @@ } return 1; -#if 0 - } else { + } else if (cond->op != IR_OVERFLOW && insn->op2 <= cond_ref && insn->op3 <= cond_ref) { /* COND * * prev prev @@ -2696,7 +2771,7 @@ next->op1 = root->op1; ir_use_list_replace_one(ctx, cond_ref, root_ref, ref); ir_use_list_replace_one(ctx, root->op1, root_ref, next_ref); - ir_use_list_remove_all(ctx, root->op2, root_ref); + ir_use_list_remove_one(ctx, root->op2, root_ref); MAKE_NOP(root); CLEAR_USES(root_ref); MAKE_NOP(start1); CLEAR_USES(start1_ref); @@ -2705,12 +2780,12 @@ MAKE_NOP(end2); CLEAR_USES(end2_ref); MAKE_NOP(merge); CLEAR_USES(merge_ref); + ir_bitqueue_add(worklist, ref); if (ctx->ir_base[next->op1].op == IR_BEGIN || ctx->ir_base[next->op1].op == IR_MERGE) { ir_bitqueue_add(worklist, next->op1); } return 1; -#endif } } } @@ -2719,7 +2794,7 @@ return 0; } -static bool ir_cmp_is_true(ir_op op, ir_insn *op1, ir_insn *op2) +static bool ir_cmp_is_true(ir_op op, const ir_insn *op1, const ir_insn *op2) { IR_ASSERT(op1->type == op2->type); if (IR_IS_TYPE_INT(op1->type)) { @@ -2960,8 +3035,8 @@ * IF_FALSE | MERGE * | | */ - ir_use_list_remove_all(ctx, merge_ref, cond_ref); - ir_use_list_remove_all(ctx, ref, if_true_ref); + ir_use_list_remove_one(ctx, merge_ref, cond_ref); + ir_use_list_remove_one(ctx, ref, if_true_ref); if (!IR_IS_CONST_REF(cond->op3)) { ir_use_list_replace_one(ctx, cond->op3, cond_ref, end2_ref); } @@ -3155,8 +3230,8 @@ * | | */ - ir_use_list_remove_all(ctx, merge_ref, phi_ref); - ir_use_list_remove_all(ctx, ref, if_true_ref); + ir_use_list_remove_one(ctx, merge_ref, phi_ref); + ir_use_list_remove_one(ctx, ref, if_true_ref); if (!IR_IS_CONST_REF(phi->op3)) { ir_use_list_replace_one(ctx, phi->op3, phi_ref, insn->op2); } @@ -3246,7 +3321,7 @@ } } -static ir_ref ir_find_ext_use(ir_ctx *ctx, ir_ref ref) +static ir_ref ir_find_ext_use(const ir_ctx *ctx, ir_ref ref) { ir_use_list *use_list = &ctx->use_lists[ref]; ir_ref *p, n, use; @@ -3628,6 +3703,7 @@ insn->op1 = val; insn->op2 = IR_UNUSED; ir_bitqueue_add(worklist, i); + ir_iter_add_uses(ctx, i, worklist); } } } else if (insn->op == IR_STORE) { @@ -3677,11 +3753,11 @@ int ir_sccp(ir_ctx *ctx) { ir_bitqueue sccp_worklist, iter_worklist; - ir_insn *_values; + ir_sccp_val *_values; ir_bitqueue_init(&iter_worklist, ctx->insns_count); ir_bitqueue_init(&sccp_worklist, ctx->insns_count); - _values = ir_mem_calloc(ctx->insns_count, sizeof(ir_insn)); + _values = ir_mem_calloc(ctx->insns_count, sizeof(ir_sccp_val)); ctx->flags2 |= IR_OPT_IN_SCCP; ir_sccp_analyze(ctx, _values, &sccp_worklist, &iter_worklist); diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/ir/ir_x86.dasc php-8.4.20RC1/ext/opcache/jit/ir/ir_x86.dasc --- php-8.4.18/ext/opcache/jit/ir/ir_x86.dasc 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/ir/ir_x86.dasc 2026-04-01 04:35:36.011343056 +0000 @@ -1167,6 +1167,7 @@ _(CMP_AND_BRANCH_FP) \ _(TEST_AND_BRANCH_INT) \ _(JCC_INT) \ + _(COND_TEST_INT) \ _(COND_CMP_INT) \ _(COND_CMP_FP) \ _(GUARD_CMP_INT) \ @@ -1405,6 +1406,7 @@ } IR_FALLTHROUGH; case IR_COND_CMP_INT: + case IR_COND_TEST_INT: insn = &ctx->ir_base[ref]; if (IR_IS_TYPE_INT(insn->type)) { if (IR_IS_CONST_REF(insn->op3) || ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA) { @@ -2125,6 +2127,34 @@ return 0; } +static bool all_usages_are_fusable(ir_ctx *ctx, ir_ref ref) +{ + ir_insn *insn = &ctx->ir_base[ref]; + + if (insn->op >= IR_EQ && insn->op <= IR_UNORDERED) { + ir_use_list *use_list = &ctx->use_lists[ref]; + ir_ref n = use_list->count; + + if (n > 0) { + ir_ref *p = ctx->use_edges + use_list->refs; + + do { + insn = &ctx->ir_base[*p]; + if (insn->op != IR_IF + && insn->op != IR_GUARD + && insn->op != IR_GUARD_NOT + && (insn->op != IR_COND || insn->op2 == ref || insn->op3 == ref)) { + return 0; + } + p++; + n--; + } while (n); + return 1; + } + } + return 0; +} + static uint32_t ir_match_insn(ir_ctx *ctx, ir_ref ref) { ir_insn *op2_insn; @@ -2877,7 +2907,7 @@ return IR_RETURN_FP; } case IR_IF: - if (!IR_IS_CONST_REF(insn->op2) && ctx->use_lists[insn->op2].count == 1) { + if (!IR_IS_CONST_REF(insn->op2) && (ctx->use_lists[insn->op2].count == 1 || all_usages_are_fusable(ctx, insn->op2))) { op2_insn = &ctx->ir_base[insn->op2]; if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UNORDERED) { if (IR_IS_TYPE_INT(ctx->ir_base[op2_insn->op1].type)) { @@ -2889,7 +2919,9 @@ if (op1_insn->op == IR_AND && ctx->use_lists[op2_insn->op1].count == 1) { /* v = AND(_, _); c = CMP(v, 0) ... IF(c) => SKIP_TEST; SKIP ... TEST_AND_BRANCH */ - ir_match_fuse_load_test_int(ctx, op1_insn, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load_test_int(ctx, op1_insn, ref); + } ctx->rules[op2_insn->op1] = IR_FUSED | IR_TEST_INT; ctx->rules[insn->op2] = IR_FUSED | IR_SIMPLE | IR_NOP; return IR_TEST_AND_BRANCH_INT; @@ -2901,10 +2933,14 @@ op2_insn->op == IR_LT || op2_insn->op == IR_GE)))) { /* v = BINOP(_, _); c = CMP(v, 0) ... IF(c) => BINOP; SKIP_CMP ... JCC */ if (ir_op_flags[op1_insn->op] & IR_OP_FLAG_COMMUTATIVE) { - ir_match_fuse_load_commutative_int(ctx, op1_insn, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load_commutative_int(ctx, op1_insn, ref); + } ctx->rules[op2_insn->op1] = IR_BINOP_INT | IR_MAY_SWAP; } else { - ir_match_fuse_load(ctx, op1_insn->op2, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load(ctx, op1_insn->op2, ref); + } ctx->rules[op2_insn->op1] = IR_BINOP_INT; } ctx->rules[insn->op2] = IR_FUSED | IR_CMP_INT; @@ -2912,12 +2948,16 @@ } } /* c = CMP(_, _) ... IF(c) => SKIP_CMP ... CMP_AND_BRANCH */ - ir_match_fuse_load_cmp_int(ctx, op2_insn, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load_cmp_int(ctx, op2_insn, ref); + } ctx->rules[insn->op2] = IR_FUSED | IR_CMP_INT; return IR_CMP_AND_BRANCH_INT; } else { /* c = CMP(_, _) ... IF(c) => SKIP_CMP ... CMP_AND_BRANCH */ - ir_match_fuse_load_cmp_fp_br(ctx, op2_insn, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load_cmp_fp_br(ctx, op2_insn, ref); + } ctx->rules[insn->op2] = IR_FUSED | IR_CMP_FP; return IR_CMP_AND_BRANCH_FP; } @@ -3005,31 +3045,43 @@ break; } case IR_COND: - if (!IR_IS_CONST_REF(insn->op1) && ctx->use_lists[insn->op1].count == 1) { + if (!IR_IS_CONST_REF(insn->op1) && (ctx->use_lists[insn->op1].count == 1 || all_usages_are_fusable(ctx, insn->op1))) { ir_insn *op1_insn = &ctx->ir_base[insn->op1]; if (op1_insn->op >= IR_EQ && op1_insn->op <= IR_UNORDERED) { if (IR_IS_TYPE_INT(ctx->ir_base[op1_insn->op1].type)) { - ir_match_fuse_load_cmp_int(ctx, op1_insn, ref); + if (ctx->use_lists[insn->op1].count == 1) { + ir_match_fuse_load_cmp_int(ctx, op1_insn, ref); + } ctx->rules[insn->op1] = IR_FUSED | IR_CMP_INT; return IR_COND_CMP_INT; } else { - ir_match_fuse_load_cmp_fp_br(ctx, op1_insn, ref); + if (ctx->use_lists[insn->op1].count == 1) { + ir_match_fuse_load_cmp_fp_br(ctx, op1_insn, ref); + } ctx->rules[insn->op1] = IR_FUSED | IR_CMP_FP; return IR_COND_CMP_FP; } + } else if (op1_insn->op == IR_AND) { + /* c = AND(_, _) ... IF(c) => SKIP_TEST ... TEST_AND_BRANCH */ + ir_match_fuse_load_test_int(ctx, op1_insn, ref); + ctx->rules[insn->op1] = IR_FUSED | IR_TEST_INT; + return IR_COND_TEST_INT; } } + if (IR_IS_TYPE_INT(ctx->ir_base[insn->op1].type)) { + ir_match_fuse_load(ctx, insn->op1, ref); + } return IR_COND; case IR_GUARD: case IR_GUARD_NOT: - if (!IR_IS_CONST_REF(insn->op2) && ctx->use_lists[insn->op2].count == 1) { + if (!IR_IS_CONST_REF(insn->op2) && (ctx->use_lists[insn->op2].count == 1 || all_usages_are_fusable(ctx, insn->op2))) { op2_insn = &ctx->ir_base[insn->op2]; - if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UNORDERED + if (op2_insn->op >= IR_EQ && op2_insn->op <= IR_UNORDERED) { // TODO: register allocator may clobber operands of CMP before they are used in the GUARD_CMP - && (insn->op2 == ref - 1 || - (insn->op2 == ctx->prev_ref[ref] - 1 - && ctx->ir_base[ctx->prev_ref[ref]].op == IR_SNAPSHOT))) { +//??? && (insn->op2 == ref - 1 || +//??? (insn->op2 == ctx->prev_ref[ref] - 1 +//??? && ctx->ir_base[ctx->prev_ref[ref]].op == IR_SNAPSHOT))) { if (IR_IS_TYPE_INT(ctx->ir_base[op2_insn->op1].type)) { if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op) @@ -3043,10 +3095,14 @@ (op2_insn->op == IR_EQ || op2_insn->op == IR_NE || op2_insn->op == IR_LT || op2_insn->op == IR_GE))) { if (ir_op_flags[op1_insn->op] & IR_OP_FLAG_COMMUTATIVE) { - ir_match_fuse_load_commutative_int(ctx, op1_insn, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load_commutative_int(ctx, op1_insn, ref); + } ctx->rules[op2_insn->op1] = IR_BINOP_INT | IR_MAY_SWAP; } else { - ir_match_fuse_load(ctx, op1_insn->op2, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load(ctx, op1_insn->op2, ref); + } ctx->rules[op2_insn->op1] = IR_BINOP_INT; } /* v = BINOP(_, _); c = CMP(v, 0) ... IF(c) => BINOP; SKIP_CMP ... GUARD_JCC */ @@ -3054,6 +3110,7 @@ return IR_GUARD_JCC_INT; } } else if ((ctx->flags & IR_OPT_CODEGEN) + && ctx->use_lists[insn->op2].count == 1 && op2_insn->op1 == insn->op2 - 2 /* before previous instruction */ && ir_in_same_block(ctx, op2_insn->op1) && ctx->use_lists[op2_insn->op1].count == 2) { @@ -3101,12 +3158,16 @@ } } /* c = CMP(_, _) ... GUARD(c) => SKIP_CMP ... GUARD_CMP */ - ir_match_fuse_load_cmp_int(ctx, op2_insn, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load_cmp_int(ctx, op2_insn, ref); + } ctx->rules[insn->op2] = IR_FUSED | IR_CMP_INT; return IR_GUARD_CMP_INT; } else { /* c = CMP(_, _) ... GUARD(c) => SKIP_CMP ... GUARD_CMP */ - ir_match_fuse_load_cmp_fp_br(ctx, op2_insn, ref); + if (ctx->use_lists[insn->op2].count == 1) { + ir_match_fuse_load_cmp_fp_br(ctx, op2_insn, ref); + } ctx->rules[insn->op2] = IR_FUSED | IR_CMP_FP; return IR_GUARD_CMP_FP; } @@ -6051,8 +6112,15 @@ ir_type type = ctx->ir_base[cmp_insn->op1].type; ir_ref op1 = cmp_insn->op1; ir_ref op2 = cmp_insn->op2; - ir_reg op1_reg = ctx->regs[ref][1]; - ir_reg op2_reg = ctx->regs[ref][2]; + ir_reg op1_reg, op2_reg; + + if (UNEXPECTED(ctx->rules[ref] & IR_FUSED_REG)) { + op1_reg = ir_get_fused_reg(ctx, root, ref * sizeof(ir_ref) + 1); + op2_reg = ir_get_fused_reg(ctx, root, ref * sizeof(ir_ref) + 2); + } else { + op1_reg = ctx->regs[ref][1]; + op2_reg = ctx->regs[ref][2]; + } if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { op1_reg = IR_REG_NUM(op1_reg); @@ -6218,8 +6286,15 @@ ir_type type = binop_insn->type; ir_ref op1 = binop_insn->op1; ir_ref op2 = binop_insn->op2; - ir_reg op1_reg = ctx->regs[ref][1]; - ir_reg op2_reg = ctx->regs[ref][2]; + ir_reg op1_reg, op2_reg; + + if (UNEXPECTED(ctx->rules[ref] & IR_FUSED_REG)) { + op1_reg = ir_get_fused_reg(ctx, root, ref * sizeof(ir_ref) + 1); + op2_reg = ir_get_fused_reg(ctx, root, ref * sizeof(ir_ref) + 2); + } else { + op1_reg = ctx->regs[ref][1]; + op2_reg = ctx->regs[ref][2]; + } IR_ASSERT(binop_insn->op == IR_AND); if (op1_reg != IR_REG_NONE) { @@ -6329,8 +6404,13 @@ op1 = cmp_insn->op1; op2 = cmp_insn->op2; - op1_reg = ctx->regs[cmp_ref][1]; - op2_reg = ctx->regs[cmp_ref][2]; + if (UNEXPECTED(ctx->rules[cmp_ref] & IR_FUSED_REG)) { + op1_reg = ir_get_fused_reg(ctx, root, cmp_ref * sizeof(ir_ref) + 1); + op2_reg = ir_get_fused_reg(ctx, root, cmp_ref * sizeof(ir_ref) + 2); + } else { + op1_reg = ctx->regs[cmp_ref][1]; + op2_reg = ctx->regs[cmp_ref][2]; + } if (op1_reg == IR_REG_NONE && op2_reg != IR_REG_NONE && (op == IR_EQ || op == IR_NE)) { ir_reg tmp_reg; @@ -6603,8 +6683,15 @@ ir_type type = ctx->ir_base[cmp_insn->op1].type; ir_ref op1 = cmp_insn->op1; ir_ref op2 = cmp_insn->op2; - ir_reg op1_reg = ctx->regs[insn->op2][1]; - ir_reg op2_reg = ctx->regs[insn->op2][2]; + ir_reg op1_reg, op2_reg; + + if (UNEXPECTED(ctx->rules[insn->op2] & IR_FUSED_REG)) { + op1_reg = ir_get_fused_reg(ctx, def, insn->op2 * sizeof(ir_ref) + 1); + op2_reg = ir_get_fused_reg(ctx, def, insn->op2 * sizeof(ir_ref) + 2); + } else { + op1_reg = ctx->regs[insn->op2][1]; + op2_reg = ctx->regs[insn->op2][2]; + } if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { op1_reg = IR_REG_NUM(op1_reg); @@ -6735,37 +6822,24 @@ IR_ASSERT(def_reg != IR_REG_NONE); - if (op2 != op3) { - if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, type, op2_reg, op2); - if (op1 == op2) { - op1_reg = op2_reg; - } - } - if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) { - op3_reg = IR_REG_NUM(op3_reg); - ir_emit_load(ctx, type, op3_reg, op3); - if (op1 == op2) { - op1_reg = op3_reg; - } - } - } else if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) { + if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) { op2_reg = IR_REG_NUM(op2_reg); ir_emit_load(ctx, type, op2_reg, op2); - op3_reg = op2_reg; if (op1 == op2) { op1_reg = op2_reg; } - } else if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) { + if (op3 == op2) { + op3_reg = op2_reg; + } + } + if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) { op3_reg = IR_REG_NUM(op3_reg); ir_emit_load(ctx, type, op3_reg, op3); - op2_reg = op3_reg; if (op1 == op3) { - op1_reg = op3_reg; + op1_reg = op2_reg; } } - if (op1_reg != IR_REG_NONE && op1 != op2 && op1 != op3 && IR_REG_SPILLED(op1_reg)) { + if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { op1_reg = IR_REG_NUM(op1_reg); ir_emit_load(ctx, op1_type, op1_reg, op1); } @@ -6774,7 +6848,13 @@ if (op1_reg != IR_REG_NONE) { | ASM_REG_REG_OP test, op1_type, op1_reg, op1_reg } else { - ir_mem mem = ir_ref_spill_slot(ctx, op1); + ir_mem mem; + + if (ir_rule(ctx, insn->op1) & IR_FUSED) { + mem = ir_fuse_load(ctx, def, insn->op1); + } else { + mem = ir_ref_spill_slot(ctx, insn->op1); + } | ASM_MEM_IMM_OP cmp, op1_type, mem, 0 } @@ -6864,6 +6944,115 @@ } } +static void ir_emit_cond_test_int(ir_ctx *ctx, ir_ref def, ir_insn *insn) +{ + ir_backend_data *data = ctx->data; + dasm_State **Dst = &data->dasm_state; + ir_type type = insn->type; + ir_ref op2 = insn->op2; + ir_ref op3 = insn->op3; + ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg op3_reg = ctx->regs[def][3]; + + if (op2 != op3) { + if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, type, op2_reg, op2); + } + if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) { + op3_reg = IR_REG_NUM(op3_reg); + ir_emit_load(ctx, type, op3_reg, op3); + } + } else if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, type, op2_reg, op2); + op3_reg = op2_reg; + } else if (op3_reg != IR_REG_NONE && IR_REG_SPILLED(op3_reg)) { + op3_reg = IR_REG_NUM(op3_reg); + ir_emit_load(ctx, type, op3_reg, op3); + op2_reg = op3_reg; + } + + ir_emit_test_int_common(ctx, def, insn->op1, IR_NE); + + if (IR_IS_TYPE_INT(type)) { + bool eq = 0; + + if (op3_reg != IR_REG_NONE) { + if (op3_reg == def_reg) { + IR_ASSERT(op2_reg != IR_REG_NONE); + op3_reg = op2_reg; + eq = 1; // reverse + } else { + if (op2_reg != IR_REG_NONE) { + if (def_reg != op2_reg) { +// if (IR_IS_TYPE_INT(type)) { + ir_emit_mov(ctx, type, def_reg, op2_reg); +// } else { +// ir_emit_fp_mov(ctx, type, def_reg, op2_reg); +// } + } + } else if (IR_IS_CONST_REF(op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2].op)) { + /* prevent "xor" and flags clobbering */ + ir_emit_mov_imm_int(ctx, type, def_reg, ctx->ir_base[op2].val.i64); + } else { + ir_emit_load_ex(ctx, type, def_reg, op2, def); + } + } + } else { + IR_ASSERT(op2_reg != IR_REG_NONE && op2_reg != def_reg); + if (IR_IS_CONST_REF(op3) && !IR_IS_SYM_CONST(ctx->ir_base[op3].op)) { + /* prevent "xor" and flags clobbering */ + ir_emit_mov_imm_int(ctx, type, def_reg, ctx->ir_base[op3].val.i64); + } else { + ir_emit_load_ex(ctx, type, def_reg, op3, def); + } + op3_reg = op2_reg; + eq = 1; // reverse + } + + if (eq) { + | ASM_REG_REG_OP2 cmovne, type, def_reg, op3_reg + } else { + | ASM_REG_REG_OP2 cmove, type, def_reg, op3_reg + } + } else { + | jne >2 + |1: + + if (op2_reg != IR_REG_NONE) { + if (def_reg != op2_reg) { + if (IR_IS_TYPE_INT(type)) { + ir_emit_mov(ctx, type, def_reg, op2_reg); + } else { + ir_emit_fp_mov(ctx, type, def_reg, op2_reg); + } + } + } else { + ir_emit_load_ex(ctx, type, def_reg, op2, def); + } + | jmp >3 + |2: + if (op3_reg != IR_REG_NONE) { + if (def_reg != op3_reg) { + if (IR_IS_TYPE_INT(type)) { + ir_emit_mov(ctx, type, def_reg, op3_reg); + } else { + ir_emit_fp_mov(ctx, type, def_reg, op3_reg); + } + } + } else { + ir_emit_load_ex(ctx, type, def_reg, op3, def); + } + |3: + } + + if (IR_REG_SPILLED(ctx->regs[def][0])) { + ir_emit_store(ctx, type, def, def_reg); + } +} + static void ir_emit_cond_cmp_int(ir_ctx *ctx, ir_ref def, ir_insn *insn) { ir_backend_data *data = ctx->data; @@ -10454,9 +10643,16 @@ ir_type type = ctx->ir_base[cmp_insn->op1].type; ir_ref op1 = cmp_insn->op1; ir_ref op2 = cmp_insn->op2; - ir_reg op1_reg = ctx->regs[insn->op2][1]; - ir_reg op2_reg = ctx->regs[insn->op2][2]; void *addr; + ir_reg op1_reg, op2_reg; + + if (UNEXPECTED(ctx->rules[insn->op2] & IR_FUSED_REG)) { + op1_reg = ir_get_fused_reg(ctx, def, insn->op2 * sizeof(ir_ref) + 1); + op2_reg = ir_get_fused_reg(ctx, def, insn->op2 * sizeof(ir_ref) + 2); + } else { + op1_reg = ctx->regs[insn->op2][1]; + op2_reg = ctx->regs[insn->op2][2]; + } if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { op1_reg = IR_REG_NUM(op1_reg); @@ -11714,6 +11910,9 @@ case IR_COND: ir_emit_cond(ctx, i, insn); break; + case IR_COND_TEST_INT: + ir_emit_cond_test_int(ctx, i, insn); + break; case IR_COND_CMP_INT: ir_emit_cond_cmp_int(ctx, i, insn); break; @@ -12107,7 +12306,7 @@ do { /* _cldemote(p); */ - asm volatile(".byte 0x0f, 0x1c, 0x06" :: "S" (p)); + __asm__ volatile(".byte 0x0f, 0x1c, 0x06" :: "S" (p)); p += 64; } while (p < start + size); } @@ -12180,7 +12379,7 @@ return entry; } -bool ir_needs_thunk(ir_code_buffer *code_buffer, void *addr) +bool ir_needs_thunk(const ir_code_buffer *code_buffer, void *addr) { return sizeof(void*) == 8 && !IR_MAY_USE_32BIT_ADDR(code_buffer, addr); } diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/zend_jit_helpers.c php-8.4.20RC1/ext/opcache/jit/zend_jit_helpers.c --- php-8.4.18/ext/opcache/jit/zend_jit_helpers.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/zend_jit_helpers.c 2026-04-01 04:35:36.012030555 +0000 @@ -2776,7 +2776,7 @@ //??? } else { //??? prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), orig_zptr); //??? } - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_jit_assign_op_to_typed_prop(zptr, prop_info, value, binary_op); } else { @@ -2972,6 +2972,9 @@ } } else { zend_property_info *prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); + if (prop_info && !ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; + } if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) { fast_long_increment_function(prop); @@ -3042,6 +3045,9 @@ } } else { zend_property_info *prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); + if (prop_info && !ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; + } if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) { fast_long_decrement_function(prop); @@ -3110,6 +3116,9 @@ ZVAL_NULL(result); } else { zend_property_info *prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); + if (prop_info && !ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; + } if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) { ZVAL_LONG(result, Z_LVAL_P(prop)); @@ -3171,6 +3180,9 @@ ZVAL_NULL(result); } else { zend_property_info *prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); + if (prop_info && !ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; + } if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) { ZVAL_LONG(result, Z_LVAL_P(prop)); diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/zend_jit_ir.c php-8.4.20RC1/ext/opcache/jit/zend_jit_ir.c --- php-8.4.18/ext/opcache/jit/zend_jit_ir.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/zend_jit_ir.c 2026-04-01 04:35:36.012936332 +0000 @@ -8066,7 +8066,7 @@ return 1; } -static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, int8_t reg) +static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, const zend_op_array *op_array, int8_t reg) { zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg)); ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr)); @@ -8089,7 +8089,20 @@ } jit_LOAD_IP_ADDR(jit, opline - 1); - ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape)); + + /* We can't use trace_escape() because opcode handler may be overridden by JIT */ + zend_jit_op_array_trace_extension *jit_extension = + (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array); + size_t offset = jit_extension->offset; + ir_ref ref = ir_CONST_ADDR(ZEND_OP_TRACE_INFO((opline - 1), offset)->orig_handler); + if (GCC_GLOBAL_REGS) { + ir_TAILCALL(IR_VOID, ref); + } else { +#if defined(IR_TARGET_X86) + ref = ir_CAST_FC_FUNC(ref); +#endif + ir_TAILCALL_1(IR_I32, ref, jit_FP(jit)); + } ir_IF_TRUE(if_def); diff '--color=auto' -Naur php-8.4.18/ext/opcache/jit/zend_jit_trace.c php-8.4.20RC1/ext/opcache/jit/zend_jit_trace.c --- php-8.4.18/ext/opcache/jit/zend_jit_trace.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/jit/zend_jit_trace.c 2026-04-01 04:35:36.013758600 +0000 @@ -3603,7 +3603,7 @@ ZEND_ASSERT(STACK_FLAGS(parent_stack, check2) == ZREG_ZVAL_COPY); ZEND_ASSERT(reg != ZREG_NONE); - if (!zend_jit_escape_if_undef(jit, check2, flags, opline, reg)) { + if (!zend_jit_escape_if_undef(jit, check2, flags, opline, exit_info->op_array, reg)) { return 0; } if (!zend_jit_restore_zval(jit, EX_NUM_TO_VAR(check2), reg)) { @@ -4510,6 +4510,12 @@ op2_info = OP2_INFO(); op2_addr = OP2_REG_ADDR(); if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) { + if (op1_type == IS_LONG || op1_type == IS_DOUBLE) { + CHECK_OP1_TRACE_TYPE(); + } + if (op2_type == IS_LONG || op2_type == IS_DOUBLE) { + CHECK_OP2_TRACE_TYPE(); + } break; } if (opline->opcode == ZEND_ADD && @@ -4518,6 +4524,12 @@ /* pass */ } else if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) || !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) { + if (op1_type == IS_LONG || op1_type == IS_DOUBLE) { + CHECK_OP1_TRACE_TYPE(); + } + if (op2_type == IS_LONG || op2_type == IS_DOUBLE) { + CHECK_OP2_TRACE_TYPE(); + } break; } if (orig_op1_type != IS_UNKNOWN diff '--color=auto' -Naur php-8.4.18/ext/opcache/shared_alloc_shm.c php-8.4.20RC1/ext/opcache/shared_alloc_shm.c --- php-8.4.18/ext/opcache/shared_alloc_shm.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/shared_alloc_shm.c 2026-04-01 04:35:36.014208390 +0000 @@ -42,7 +42,6 @@ # define MIN(x, y) ((x) > (y)? (y) : (x)) #endif -#define SEG_ALLOC_SIZE_MAX 32*1024*1024 #define SEG_ALLOC_SIZE_MIN 2*1024*1024 typedef struct { @@ -53,36 +52,38 @@ static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, const char **error_in) { int i; - size_t allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size; + size_t allocate_size = 0, remaining_bytes, seg_allocate_size; int first_segment_id = -1; key_t first_segment_key = -1; struct shmid_ds sds; int shmget_flags; zend_shared_segment_shm *shared_segments; - seg_allocate_size = SEG_ALLOC_SIZE_MAX; - /* determine segment size we _really_ need: - * no more than to include requested_size - */ - while (requested_size * 2 <= seg_allocate_size && seg_allocate_size > SEG_ALLOC_SIZE_MIN) { - seg_allocate_size >>= 1; - } - shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL; - /* try allocating this much, if not - try shrinking */ - while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) { - allocate_size = MIN(requested_size, seg_allocate_size); - first_segment_id = shmget(first_segment_key, allocate_size, shmget_flags); - if (first_segment_id != -1) { - break; + /* Try contiguous allocation first. */ + seg_allocate_size = requested_size; + first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags); + if (UNEXPECTED(first_segment_id == -1)) { + /* Search for biggest n^2 < requested_size. */ + seg_allocate_size = SEG_ALLOC_SIZE_MIN; + while (seg_allocate_size < requested_size / 2) { + seg_allocate_size *= 2; } - seg_allocate_size >>= 1; /* shrink the allocated block */ - } - if (first_segment_id == -1) { - *error_in = "shmget"; - return ALLOC_FAILURE; + /* try allocating this much, if not - try shrinking */ + while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) { + first_segment_id = shmget(first_segment_key, seg_allocate_size, shmget_flags); + if (first_segment_id != -1) { + break; + } + seg_allocate_size >>= 1; /* shrink the allocated block */ + } + + if (first_segment_id == -1) { + *error_in = "shmget"; + return ALLOC_FAILURE; + } } *shared_segments_count = ((requested_size - 1) / seg_allocate_size) + 1; diff '--color=auto' -Naur php-8.4.18/ext/opcache/tests/gh21052_a.inc php-8.4.20RC1/ext/opcache/tests/gh21052_a.inc --- php-8.4.18/ext/opcache/tests/gh21052_a.inc 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/tests/gh21052_a.inc 2026-04-01 04:35:36.014397848 +0000 @@ -0,0 +1,13 @@ + +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + string(3) "foo" +} +array(1) { + [0]=> + string(3) "foo" +} +array(1) { + [0]=> + string(3) "foo" +} diff '--color=auto' -Naur php-8.4.18/ext/opcache/tests/gh21227.phpt php-8.4.20RC1/ext/opcache/tests/gh21227.phpt --- php-8.4.18/ext/opcache/tests/gh21227.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/tests/gh21227.phpt 2026-04-01 04:35:36.014563601 +0000 @@ -0,0 +1,23 @@ +--TEST-- +GH-21227: Borked SCCP of array containing partial object +--CREDITS-- +Daniel Chong (chongwick) +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +a = 3; + $objs = []; + $obj = new stdClass; + $objs[] = $obj; +} + +?> +===DONE=== +--EXPECT-- +===DONE=== diff '--color=auto' -Naur php-8.4.18/ext/opcache/tests/jit/gh20838.inc php-8.4.20RC1/ext/opcache/tests/jit/gh20838.inc --- php-8.4.18/ext/opcache/tests/jit/gh20838.inc 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/tests/jit/gh20838.inc 2026-04-01 04:35:36.014698536 +0000 @@ -0,0 +1,53 @@ + $value) { + if ($k[$key]['st'] == 'correction') $s += $value; + else { + if ($k[$key]['st'] == 'caa') $value = $value / $avc[$key]; + $s += $value / 5 * $k[$key]['tp'] * (1 + 50 / $k[$key]['tp'] * $pav / (100 * $c)); + } + } + } + + echo("$id $s\n"); + + return $s; +} diff '--color=auto' -Naur php-8.4.18/ext/opcache/tests/jit/gh20838.phpt php-8.4.20RC1/ext/opcache/tests/jit/gh20838.phpt --- php-8.4.18/ext/opcache/tests/jit/gh20838.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/tests/jit/gh20838.phpt 2026-04-01 04:35:36.014783507 +0000 @@ -0,0 +1,66 @@ +--TEST-- +GH-20838 (JIT compiler produces wrong arithmetic results) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_buffer_size=64M +opcache.jit_hot_loop=61 +opcache.jit_hot_func=127 +opcache.jit_hot_return=8 +opcache.jit_hot_side_exit=8 +--EXTENSIONS-- +opcache +--FILE_EXTERNAL-- +gh20838.inc +--EXPECT-- +49 0 +1080 18 +4415 31.25 +4763 75 +4926 75 +4933 60 +4935 75 +4938 75 +4939 75 +4947 60 +4952 45 +4953 75 +4962 60 +8558 45 +14888 45 +16879 13 +100003 0 +100007 60 +100013 0 +100017 13 +100019 15 +100027 45 +100031 30 +106427 -37.5 +217955 -9 +240000 30 +240010 60 +240021 45 +240079 112.66666666667 +240210 45 +240227 45 +240249 75 +240273 75 +240333 30 +240335 60 +300024 96.5 +310001 45 +310025 45 +310034 60 +310042 30 +310111 75 +310191 45 +310219 75 +310236 15 +310322 45 +310356 30 +310360 21.25 +310394 29.5 +310405 75 +310411 60 diff '--color=auto' -Naur php-8.4.18/ext/opcache/tests/jit/gh21267_blacklist.phpt php-8.4.20RC1/ext/opcache/tests/jit/gh21267_blacklist.phpt --- php-8.4.18/ext/opcache/tests/jit/gh21267_blacklist.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/tests/jit/gh21267_blacklist.phpt 2026-04-01 04:35:36.014945122 +0000 @@ -0,0 +1,36 @@ +--TEST-- +GH-21267 (JIT infinite loop on FETCH_OBJ_R with IS_UNDEF via blacklisted trace exit) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_buffer_size=64M +opcache.jit_hot_loop=0 +opcache.jit_hot_func=2 +opcache.jit_hot_return=0 +opcache.jit_hot_side_exit=1 +opcache.jit_max_side_traces=0 +--FILE-- +x; } +} + +$o1 = new C; +$o2 = new C; +$o2->x = false; +$o3 = new C; +unset($o3->x); +$a = [$o1, $o2, $o3]; + +for ($i = 0; $i < 8; $i++) { + $m = $a[$i % 3]; + $m->getX(); + $m->getX(); +} +?> +OK +--EXPECT-- +OK diff '--color=auto' -Naur php-8.4.18/ext/opcache/tests/jit/gh21267.phpt php-8.4.20RC1/ext/opcache/tests/jit/gh21267.phpt --- php-8.4.18/ext/opcache/tests/jit/gh21267.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/tests/jit/gh21267.phpt 2026-04-01 04:35:36.014864069 +0000 @@ -0,0 +1,35 @@ +--TEST-- +GH-21267 (JIT infinite loop on FETCH_OBJ_R with IS_UNDEF property in polymorphic context) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_buffer_size=64M +opcache.jit_hot_loop=0 +opcache.jit_hot_func=2 +opcache.jit_hot_return=0 +opcache.jit_hot_side_exit=1 +--FILE-- +x; } +} + +$o1 = new C; +$o2 = new C; +$o2->x = false; +$o3 = new C; +unset($o3->x); +$a = [$o1, $o2, $o3]; + +for ($i = 0; $i < 8; $i++) { + $m = $a[$i % 3]; + $m->getX(); + $m->getX(); +} +?> +OK +--EXPECT-- +OK diff '--color=auto' -Naur php-8.4.18/ext/opcache/zend_accelerator_util_funcs.c php-8.4.20RC1/ext/opcache/zend_accelerator_util_funcs.c --- php-8.4.18/ext/opcache/zend_accelerator_util_funcs.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/opcache/zend_accelerator_util_funcs.c 2026-04-01 04:35:36.015047886 +0000 @@ -360,6 +360,12 @@ : NULL; if (parent_ce || (orig_ce->ce_flags & ZEND_ACC_LINKED)) { ce = zend_try_early_bind(orig_ce, parent_ce, early_binding->lcname, zv); + } else if (ZSTR_LEN(early_binding->lc_parent_name) == 0) { + /* Parentless class: use the same binding path as the VM handler */ + zval lcname_zv[2]; + ZVAL_STR(&lcname_zv[0], early_binding->lcname); + ZVAL_STR(&lcname_zv[1], early_binding->rtd_key); + ce = zend_bind_class_in_slot(zv, lcname_zv, early_binding->lc_parent_name); } } if (ce && early_binding->cache_slot != (uint32_t) -1) { diff '--color=auto' -Naur php-8.4.18/ext/openssl/openssl.c php-8.4.20RC1/ext/openssl/openssl.c --- php-8.4.18/ext/openssl/openssl.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/openssl/openssl.c 2026-04-01 04:35:36.015288010 +0000 @@ -2291,21 +2291,13 @@ X509_INFO *xi; char cert_path[MAXPATHLEN]; - if(!(stack = sk_X509_new_null())) { - php_openssl_store_errors(); - php_error_docref(NULL, E_ERROR, "Memory allocation failure"); - goto end; - } - if (!php_openssl_check_path(cert_file, cert_file_len, cert_path, arg_num)) { - sk_X509_free(stack); goto end; } if (!(in = BIO_new_file(cert_path, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)))) { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Error opening the file, %s", cert_path); - sk_X509_free(stack); goto end; } @@ -2313,7 +2305,11 @@ if (!(sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Error reading the file, %s", cert_path); - sk_X509_free(stack); + goto end; + } + + if(!(stack = sk_X509_new_reserve(NULL, sk_X509_INFO_num(sk)))) { + php_openssl_store_errors(); goto end; } @@ -2585,7 +2581,10 @@ } } - sk_X509_push(sk, cert); + if (sk_X509_push(sk, cert) <= 0) { + X509_free(cert); + goto push_fail_exit; + } } ZEND_HASH_FOREACH_END(); } else { /* a single certificate */ @@ -2603,11 +2602,20 @@ goto clean_exit; } } - sk_X509_push(sk, cert); + if (sk_X509_push(sk, cert) <= 0) { + X509_free(cert); + goto push_fail_exit; + } } clean_exit: return sk; + +push_fail_exit: + php_openssl_store_errors(); + php_sk_X509_free(sk); + sk = NULL; + goto clean_exit; } /* }}} */ @@ -2676,6 +2684,9 @@ if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) { ca = php_array_to_X509_sk(item, 5, "extracerts"); + if (!ca) { + goto cleanup; + } } /* end parse extra config */ @@ -2769,6 +2780,9 @@ if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) { ca = php_array_to_X509_sk(item, 5, "extracerts"); + if (!ca) { + goto cleanup; + } } /* end parse extra config */ @@ -3814,7 +3828,10 @@ /* {{{ php_openssl_generate_private_key */ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) { - if (req->priv_key_bits < MIN_KEY_LENGTH) { + if ((req->priv_key_type == OPENSSL_KEYTYPE_RSA || + req->priv_key_type == OPENSSL_KEYTYPE_DH || + req->priv_key_type == OPENSSL_KEYTYPE_DSA) && + req->priv_key_bits < MIN_KEY_LENGTH) { php_error_docref(NULL, E_WARNING, "Private key length must be at least %d bits, configured to %d", MIN_KEY_LENGTH, req->priv_key_bits); return NULL; @@ -5835,7 +5852,10 @@ goto clean_exit; } } - sk_X509_push(recipcerts, cert); + if (sk_X509_push(recipcerts, cert) <= 0) { + X509_free(cert); + goto clean_exit; + } } ZEND_HASH_FOREACH_END(); } else { /* a single certificate */ @@ -5856,7 +5876,10 @@ goto clean_exit; } } - sk_X509_push(recipcerts, cert); + if (sk_X509_push(recipcerts, cert) <= 0) { + X509_free(cert); + goto clean_exit; + } } /* sanity check the cipher */ @@ -5877,16 +5900,21 @@ /* tack on extra headers */ if (zheaders) { ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) { + int ret; zend_string *str = zval_try_get_string(zcertval); if (UNEXPECTED(!str)) { goto clean_exit; } if (strindex) { - BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), ZSTR_VAL(str)); + ret = BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), ZSTR_VAL(str)); } else { - BIO_printf(outfile, "%s\n", ZSTR_VAL(str)); + ret = BIO_printf(outfile, "%s\n", ZSTR_VAL(str)); } zend_string_release(str); + if (ret < 0) { + php_openssl_store_errors(); + goto clean_exit; + } } ZEND_HASH_FOREACH_END(); } @@ -6105,6 +6133,7 @@ zend_string_release(str); if (ret < 0) { php_openssl_store_errors(); + goto clean_exit; } } ZEND_HASH_FOREACH_END(); } @@ -6444,7 +6473,10 @@ goto clean_exit; } } - sk_X509_push(recipcerts, cert); + if (sk_X509_push(recipcerts, cert) <= 0) { + php_openssl_store_errors(); + goto clean_exit; + } } ZEND_HASH_FOREACH_END(); } else { /* a single certificate */ @@ -6464,7 +6496,10 @@ goto clean_exit; } } - sk_X509_push(recipcerts, cert); + if (sk_X509_push(recipcerts, cert) <= 0) { + php_openssl_store_errors(); + goto clean_exit; + } } /* sanity check the cipher */ @@ -6489,16 +6524,21 @@ /* tack on extra headers */ if (zheaders && encoding == ENCODING_SMIME) { ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) { + int ret; zend_string *str = zval_try_get_string(zcertval); if (UNEXPECTED(!str)) { goto clean_exit; } if (strindex) { - BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), ZSTR_VAL(str)); + ret = BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), ZSTR_VAL(str)); } else { - BIO_printf(outfile, "%s\n", ZSTR_VAL(str)); + ret = BIO_printf(outfile, "%s\n", ZSTR_VAL(str)); } zend_string_release(str); + if (ret < 0) { + php_openssl_store_errors(); + goto clean_exit; + } } ZEND_HASH_FOREACH_END(); } @@ -6778,6 +6818,7 @@ zend_string_release(str); if (ret < 0) { php_openssl_store_errors(); + goto clean_exit; } } ZEND_HASH_FOREACH_END(); } diff '--color=auto' -Naur php-8.4.18/ext/openssl/tests/gh21083.phpt php-8.4.20RC1/ext/openssl/tests/gh21083.phpt --- php-8.4.18/ext/openssl/tests/gh21083.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/openssl/tests/gh21083.phpt 2026-04-01 04:35:36.015727841 +0000 @@ -0,0 +1,61 @@ +--TEST-- +GH-21083 (openssl_pkey_new() fails for EC keys when private_key_bits is not set) +--EXTENSIONS-- +openssl +--SKIPIF-- + +--ENV-- +OPENSSL_CONF= +--FILE-- + $conf, + 'private_key_type' => OPENSSL_KEYTYPE_EC, + 'curve_name' => 'prime256v1', +]); +var_dump($key !== false); +$details = openssl_pkey_get_details($key); +var_dump($details['bits']); +var_dump($details['type'] === OPENSSL_KEYTYPE_EC); +echo "EC OK\n"; + +// X25519 - fixed size key, private_key_bits should not be required +if (defined('OPENSSL_KEYTYPE_X25519')) { + $key = openssl_pkey_new([ + 'config' => $conf, + 'private_key_type' => OPENSSL_KEYTYPE_X25519, + ]); + var_dump($key !== false); + echo "X25519 OK\n"; +} else { + echo "bool(true)\nX25519 OK\n"; +} + +// Ed25519 - fixed size key, private_key_bits should not be required +if (defined('OPENSSL_KEYTYPE_ED25519')) { + $key = openssl_pkey_new([ + 'config' => $conf, + 'private_key_type' => OPENSSL_KEYTYPE_ED25519, + ]); + var_dump($key !== false); + echo "Ed25519 OK\n"; +} else { + echo "bool(true)\nEd25519 OK\n"; +} + +unlink($conf); +?> +--EXPECT-- +bool(true) +int(256) +bool(true) +EC OK +bool(true) +X25519 OK +bool(true) +Ed25519 OK diff '--color=auto' -Naur php-8.4.18/ext/pcntl/pcntl.c php-8.4.20RC1/ext/pcntl/pcntl.c --- php-8.4.18/ext/pcntl/pcntl.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/pcntl/pcntl.c 2026-04-01 04:35:36.015863858 +0000 @@ -798,15 +798,16 @@ RETURN_THROWS(); } - /* Add the function name to our signal table */ - handle = zend_hash_index_update(&PCNTL_G(php_signal_table), signo, handle); - Z_TRY_ADDREF_P(handle); - + /* Register with the OS first so that on failure we don't record a handler that was never installed */ if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == (void *)SIG_ERR) { PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error assigning signal"); RETURN_FALSE; } + + /* Add the function name to our signal table */ + handle = zend_hash_index_update(&PCNTL_G(php_signal_table), signo, handle); + Z_TRY_ADDREF_P(handle); RETURN_TRUE; } /* }}} */ @@ -1342,6 +1343,7 @@ queue = PCNTL_G(head); PCNTL_G(head) = NULL; /* simple stores are atomic */ + PCNTL_G(tail) = NULL; /* Allocate */ while (queue) { @@ -1363,6 +1365,9 @@ #ifdef HAVE_STRUCT_SIGINFO_T zval_ptr_dtor(¶ms[1]); #endif + if (EG(exception)) { + break; + } } } @@ -1372,6 +1377,14 @@ queue = next; } + /* drain the remaining in case of exception thrown */ + while (queue) { + next = queue->next; + queue->next = PCNTL_G(spares); + PCNTL_G(spares) = queue; + queue = next; + } + PCNTL_G(pending_signals) = 0; /* Re-enable queue */ @@ -1584,7 +1597,7 @@ pid = pid_is_null ? getpid() : pid; fd = syscall(SYS_pidfd_open, pid, 0); - if (errno) { + if (fd == -1) { PCNTL_G(last_error) = errno; switch (errno) { case EINVAL: @@ -1610,11 +1623,12 @@ RETURN_FALSE; } ret = setns(fd, (int)nstype); + int setns_errno = errno; close(fd); if (ret == -1) { - PCNTL_G(last_error) = errno; - switch (errno) { + PCNTL_G(last_error) = setns_errno; + switch (setns_errno) { case ESRCH: zend_argument_value_error(1, "process no longer available (" ZEND_LONG_FMT ")", pid); RETURN_THROWS(); @@ -1624,11 +1638,11 @@ RETURN_THROWS(); case EPERM: - php_error_docref(NULL, E_WARNING, "Error %d: No required capability for this process", errno); + php_error_docref(NULL, E_WARNING, "Error %d: No required capability for this process", setns_errno); break; default: - php_error_docref(NULL, E_WARNING, "Error %d", errno); + php_error_docref(NULL, E_WARNING, "Error %d", setns_errno); } RETURN_FALSE; } else { @@ -1733,6 +1747,7 @@ if (cpu < 0 || cpu >= maxcpus) { zend_argument_value_error(2, "cpu id must be between 0 and " ZEND_ULONG_FMT " (" ZEND_LONG_FMT ")", maxcpus, cpu); + PCNTL_CPU_DESTROY(mask); RETURN_THROWS(); } diff '--color=auto' -Naur php-8.4.18/ext/pcntl/tests/pcntl_signal_dispatch_exception.phpt php-8.4.20RC1/ext/pcntl/tests/pcntl_signal_dispatch_exception.phpt --- php-8.4.18/ext/pcntl/tests/pcntl_signal_dispatch_exception.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/pcntl/tests/pcntl_signal_dispatch_exception.phpt 2026-04-01 04:35:36.016037105 +0000 @@ -0,0 +1,34 @@ +--TEST-- +pcntl_signal_dispatch() stops dispatching after handler throws exception +--EXTENSIONS-- +pcntl +posix +--FILE-- +getMessage() . "\n"; +} + +echo "Handlers called: " . implode(', ', $called) . "\n"; + +?> +--EXPECT-- +Exception in signal handler +Handlers called: SIGUSR1 diff '--color=auto' -Naur php-8.4.18/ext/pcntl/tests/pcntl_signal_functions_invalid_signals.phpt php-8.4.20RC1/ext/pcntl/tests/pcntl_signal_functions_invalid_signals.phpt --- php-8.4.18/ext/pcntl/tests/pcntl_signal_functions_invalid_signals.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/pcntl/tests/pcntl_signal_functions_invalid_signals.phpt 2026-04-01 04:35:36.016099994 +0000 @@ -0,0 +1,80 @@ +--TEST-- +pcntl_sigprocmask(), pcntl_sigwaitinfo(), and pcntl_sigtimedwait() properly throw on invalid signals +--EXTENSIONS-- +pcntl +--SKIPIF-- + +--INI-- +max_execution_time=0 +--FILE-- +getMessage() . PHP_EOL; +} + +try { + pcntl_sigprocmask(SIG_BLOCK, [0]); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + pcntl_sigprocmask(SIG_BLOCK, []); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + pcntl_sigwaitinfo(["not_a_signal"]); +} catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + pcntl_sigwaitinfo([0]); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + pcntl_sigwaitinfo([]); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + pcntl_sigtimedwait(["not_a_signal"], $info, 1); +} catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + pcntl_sigtimedwait([0], $info, 1); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + pcntl_sigtimedwait([], $info, 1); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +?> +--EXPECTF-- +pcntl_sigprocmask(): Argument #2 ($signals) signals must be of type int, string given +pcntl_sigprocmask(): Argument #2 ($signals) signals must be between 1 and %d +pcntl_sigprocmask(): Argument #2 ($signals) must not be empty +pcntl_sigwaitinfo(): Argument #1 ($signals) signals must be of type int, string given +pcntl_sigwaitinfo(): Argument #1 ($signals) signals must be between 1 and %d +pcntl_sigwaitinfo(): Argument #1 ($signals) must not be empty +pcntl_sigtimedwait(): Argument #1 ($signals) signals must be of type int, string given +pcntl_sigtimedwait(): Argument #1 ($signals) signals must be between 1 and %d +pcntl_sigtimedwait(): Argument #1 ($signals) must not be empty diff '--color=auto' -Naur php-8.4.18/ext/pcre/php_pcre.c php-8.4.20RC1/ext/pcre/php_pcre.c --- php-8.4.18/ext/pcre/php_pcre.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/pcre/php_pcre.c 2026-04-01 04:35:36.016264385 +0000 @@ -840,6 +840,7 @@ if (key != regex) { zend_string_release_ex(key, 0); } + pcre2_code_free(new_entry.re); php_error_docref(NULL, E_WARNING, "Internal pcre2_pattern_info() error %d", rc); pcre_handle_exec_error(PCRE2_ERROR_INTERNAL); return NULL; @@ -850,6 +851,7 @@ if (key != regex) { zend_string_release_ex(key, 0); } + pcre2_code_free(new_entry.re); php_error_docref(NULL, E_WARNING, "Internal pcre_pattern_info() error %d", rc); pcre_handle_exec_error(PCRE2_ERROR_INTERNAL); return NULL; @@ -1173,6 +1175,7 @@ HashTable *marks = NULL; /* Array of marks for PREG_PATTERN_ORDER */ pcre2_match_data *match_data; PCRE2_SIZE start_offset2, orig_start_offset; + bool old_mdata_used; char *subject = ZSTR_VAL(subject_str); size_t subject_len = ZSTR_LEN(subject_str); @@ -1242,7 +1245,9 @@ matched = 0; PCRE_G(error_code) = PHP_PCRE_NO_ERROR; - if (!mdata_used && num_subpats <= PHP_PCRE_PREALLOC_MDATA_SIZE) { + old_mdata_used = mdata_used; + if (!old_mdata_used && num_subpats <= PHP_PCRE_PREALLOC_MDATA_SIZE) { + mdata_used = true; match_data = mdata; } else { match_data = pcre2_match_data_create_from_pattern(pce->re, PCRE_G(gctx_zmm)); @@ -1294,7 +1299,18 @@ if (subpats != NULL) { /* Try to get the list of substrings and display a warning if failed. */ if (UNEXPECTED(offsets[1] < offsets[0])) { - if (match_sets) efree(match_sets); + if (match_sets) { + for (i = 0; i < num_subpats; i++) { + zend_array_destroy(match_sets[i]); + } + efree(match_sets); + } + if (marks) { + zend_array_destroy(marks); + } + if (match_data != mdata) { + pcre2_match_data_free(match_data); + } php_error_docref(NULL, E_WARNING, "Get subpatterns list failed"); RETURN_FALSE; } @@ -1428,6 +1444,7 @@ if (match_data != mdata) { pcre2_match_data_free(match_data); } + mdata_used = old_mdata_used; /* Add the match sets to the output array and clean up */ if (match_sets) { @@ -1489,7 +1506,8 @@ /* Compile regex or get it from cache. */ pcre_cache_entry *pce; if ((pce = pcre_get_compiled_regex_cache(regex)) == NULL) { - RETURN_FALSE; + RETVAL_FALSE; + goto flf_clean; } pce->refcount++; @@ -1631,6 +1649,7 @@ size_t result_len; /* Length of result */ zend_string *result; /* Result of replacement */ pcre2_match_data *match_data; + bool old_mdata_used; /* Calculate the size of the offsets array, and allocate memory for it. */ num_subpats = pce->capture_count + 1; @@ -1644,7 +1663,9 @@ result_len = 0; PCRE_G(error_code) = PHP_PCRE_NO_ERROR; - if (!mdata_used && num_subpats <= PHP_PCRE_PREALLOC_MDATA_SIZE) { + old_mdata_used = mdata_used; + if (!old_mdata_used && num_subpats <= PHP_PCRE_PREALLOC_MDATA_SIZE) { + mdata_used = true; match_data = mdata; } else { match_data = pcre2_match_data_create_from_pattern(pce->re, PCRE_G(gctx_zmm)); @@ -1846,6 +1867,7 @@ if (match_data != mdata) { pcre2_match_data_free(match_data); } + mdata_used = old_mdata_used; return result; } @@ -2574,6 +2596,7 @@ uint32_t num_subpats; /* Number of captured subpatterns */ zval tmp; pcre2_match_data *match_data; + bool old_mdata_used; char *subject = ZSTR_VAL(subject_str); no_empty = flags & PREG_SPLIT_NO_EMPTY; @@ -2600,7 +2623,9 @@ goto last; } - if (!mdata_used && num_subpats <= PHP_PCRE_PREALLOC_MDATA_SIZE) { + old_mdata_used = mdata_used; + if (!old_mdata_used && num_subpats <= PHP_PCRE_PREALLOC_MDATA_SIZE) { + mdata_used = true; match_data = mdata; } else { match_data = pcre2_match_data_create_from_pattern(pce->re, PCRE_G(gctx_zmm)); @@ -2729,6 +2754,7 @@ if (match_data != mdata) { pcre2_match_data_free(match_data); } + mdata_used = old_mdata_used; if (PCRE_G(error_code) != PHP_PCRE_NO_ERROR) { zval_ptr_dtor(return_value); @@ -2928,6 +2954,7 @@ zend_ulong num_key; bool invert; /* Whether to return non-matching entries */ + bool old_mdata_used; pcre2_match_data *match_data; invert = flags & PREG_GREP_INVERT ? 1 : 0; @@ -2940,7 +2967,9 @@ PCRE_G(error_code) = PHP_PCRE_NO_ERROR; - if (!mdata_used && num_subpats <= PHP_PCRE_PREALLOC_MDATA_SIZE) { + old_mdata_used = mdata_used; + if (!old_mdata_used && num_subpats <= PHP_PCRE_PREALLOC_MDATA_SIZE) { + mdata_used = true; match_data = mdata; } else { match_data = pcre2_match_data_create_from_pattern(pce->re, PCRE_G(gctx_zmm)); @@ -3005,6 +3034,7 @@ if (match_data != mdata) { pcre2_match_data_free(match_data); } + mdata_used = old_mdata_used; } /* }}} */ diff '--color=auto' -Naur php-8.4.18/ext/pcre/tests/pcre_reentrancy.phpt php-8.4.20RC1/ext/pcre/tests/pcre_reentrancy.phpt --- php-8.4.18/ext/pcre/tests/pcre_reentrancy.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/pcre/tests/pcre_reentrancy.phpt 2026-04-01 04:35:36.016544294 +0000 @@ -0,0 +1,58 @@ +--TEST-- +PCRE re-entrancy: nested calls should not corrupt global match data +--EXTENSIONS-- +pcre +--FILE-- + +--EXPECT-- +Testing nested PCRE calls... +Outer match: a +Outer match: b +Outer match: c +string(3) "ABC" + +Testing deep nesting... +string(7) "SUCCESS" diff '--color=auto' -Naur php-8.4.18/ext/pcre/tests/preg_match_all_negative_length_match.phpt php-8.4.20RC1/ext/pcre/tests/preg_match_all_negative_length_match.phpt --- php-8.4.18/ext/pcre/tests/preg_match_all_negative_length_match.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/pcre/tests/preg_match_all_negative_length_match.phpt 2026-04-01 04:35:36.016621790 +0000 @@ -0,0 +1,10 @@ +--TEST-- +preg_match_all() resource cleanup when \K in lookahead causes negative-length match +--FILE-- + +--EXPECTF-- +Warning: preg_match_all(): Get subpatterns list failed in %s on line %d +bool(false) diff '--color=auto' -Naur php-8.4.18/ext/pcre/tests/preg_match_frameless_leak.phpt php-8.4.20RC1/ext/pcre/tests/preg_match_frameless_leak.phpt --- php-8.4.18/ext/pcre/tests/preg_match_frameless_leak.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/pcre/tests/preg_match_frameless_leak.phpt 2026-04-01 04:35:36.016708494 +0000 @@ -0,0 +1,23 @@ +--TEST-- +Memory leak in preg_match() frameless function with invalid regex and object arguments +--FILE-- +val = str_repeat($val, random_int(1, 1)); + } + public function __toString() { + return $this->val; + } +} + +$regex = new Str("invalid regex"); +$subject = new Str("some subject"); + +@preg_match($regex, $subject); + +echo "Done"; +?> +--EXPECT-- +Done diff '--color=auto' -Naur php-8.4.18/ext/pcre/tests/preg_match_negative_length_match.phpt php-8.4.20RC1/ext/pcre/tests/preg_match_negative_length_match.phpt --- php-8.4.18/ext/pcre/tests/preg_match_negative_length_match.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/pcre/tests/preg_match_negative_length_match.phpt 2026-04-01 04:35:36.016789287 +0000 @@ -0,0 +1,10 @@ +--TEST-- +preg_match() resource cleanup when \K in lookahead causes negative-length match +--FILE-- + +--EXPECTF-- +Warning: preg_match(): Get subpatterns list failed in %s on line %d +bool(false) diff '--color=auto' -Naur php-8.4.18/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt php-8.4.20RC1/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt --- php-8.4.18/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt 2026-04-01 04:35:36.016897581 +0000 @@ -4,6 +4,7 @@ pdo_dblib --SKIPIF-- diff '--color=auto' -Naur php-8.4.18/ext/pgsql/pgsql_arginfo.h php-8.4.20RC1/ext/pgsql/pgsql_arginfo.h --- php-8.4.18/ext/pgsql/pgsql_arginfo.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/pgsql/pgsql_arginfo.h 2026-04-01 04:35:36.017754070 +0000 @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 14b0bdd019480b850940b2c2b012b5f6d51746b8 */ + * Stub hash: c7e052b85d35ac885704016224e488c67cb83df3 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_connect, 0, 1, PgSql\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, connection_string, IS_STRING, 0) @@ -828,7 +828,7 @@ REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_PERSISTENT); -#if defined(PQTRACE_SUPPPRESS_TIMESTAMPS) +#if defined(PQTRACE_SUPPRESS_TIMESTAMPS) REGISTER_LONG_CONSTANT("PGSQL_TRACE_SUPPRESS_TIMESTAMPS", PQTRACE_SUPPRESS_TIMESTAMPS, CONST_PERSISTENT); #endif #if defined(PQTRACE_REGRESS_MODE) diff '--color=auto' -Naur php-8.4.18/ext/pgsql/pgsql.c php-8.4.20RC1/ext/pgsql/pgsql.c --- php-8.4.18/ext/pgsql/pgsql.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/pgsql/pgsql.c 2026-04-01 04:35:36.017319488 +0000 @@ -705,10 +705,12 @@ /* create the link */ pgsql = PQconnectdb(connstring); if (pgsql == NULL || PQstatus(pgsql) == CONNECTION_BAD) { - PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql) + zend_string *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql)); if (pgsql) { PQfinish(pgsql); } + php_error_docref(NULL, E_WARNING, "Unable to connect to PostgreSQL server: %s", ZSTR_VAL(msgbuf)); + zend_string_release(msgbuf); goto err; } @@ -789,19 +791,23 @@ if (connect_type & PGSQL_CONNECT_ASYNC) { pgsql = PQconnectStart(connstring); if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) { - PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql); + zend_string *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql)); if (pgsql) { PQfinish(pgsql); } + php_error_docref(NULL, E_WARNING, "Unable to connect to PostgreSQL server: %s", ZSTR_VAL(msgbuf)); + zend_string_release(msgbuf); goto err; } } else { pgsql = PQconnectdb(connstring); if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) { - PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql); + zend_string *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql)); if (pgsql) { PQfinish(pgsql); } + php_error_docref(NULL, E_WARNING, "Unable to connect to PostgreSQL server: %s", ZSTR_VAL(msgbuf)); + zend_string_release(msgbuf); goto err; } } diff '--color=auto' -Naur php-8.4.18/ext/pgsql/pgsql.stub.php php-8.4.20RC1/ext/pgsql/pgsql.stub.php --- php-8.4.18/ext/pgsql/pgsql.stub.php 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/pgsql/pgsql.stub.php 2026-04-01 04:35:36.017632730 +0000 @@ -432,7 +432,7 @@ * @cvalue PGSQL_DML_STRING */ const PGSQL_DML_STRING = UNKNOWN; -#ifdef PQTRACE_SUPPPRESS_TIMESTAMPS +#ifdef PQTRACE_SUPPRESS_TIMESTAMPS /** * @var int * @cvalue PQTRACE_SUPPRESS_TIMESTAMPS diff '--color=auto' -Naur php-8.4.18/ext/pgsql/tests/gh21162.phpt php-8.4.20RC1/ext/pgsql/tests/gh21162.phpt --- php-8.4.18/ext/pgsql/tests/gh21162.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/pgsql/tests/gh21162.phpt 2026-04-01 04:35:36.017889185 +0000 @@ -0,0 +1,18 @@ +--TEST-- +GH-21162 (pg_connect() on error memory leak) +--EXTENSIONS-- +pgsql +--FILE-- + +--EXPECT-- +Warning caught +Done diff '--color=auto' -Naur php-8.4.18/ext/phar/tests/phar_extract2.phpt php-8.4.20RC1/ext/phar/tests/phar_extract2.phpt --- php-8.4.18/ext/phar/tests/phar_extract2.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/phar/tests/phar_extract2.phpt 2026-04-01 04:35:36.017981078 +0000 @@ -46,8 +46,6 @@ @rmdir($dir . 'one/level'); @rmdir($dir . 'one'); @rmdir($dir); -$dir = __DIR__ . '/extract1/'; -@rmdir($dir); ?> --EXPECTF-- %sextract2%cfile1.txt diff '--color=auto' -Naur php-8.4.18/ext/snmp/snmp.c php-8.4.20RC1/ext/snmp/snmp.c --- php-8.4.18/ext/snmp/snmp.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/snmp/snmp.c 2026-04-01 04:35:36.018113238 +0000 @@ -959,7 +959,7 @@ /* }}} */ /* {{{ Set the authentication protocol in the snmpv3 session */ -static bool netsnmp_session_set_auth_protocol(struct snmp_session *s, zend_string *prot) +static ZEND_ATTRIBUTE_NONNULL bool netsnmp_session_set_auth_protocol(struct snmp_session *s, zend_string *prot) { #ifndef DISABLE_MD5 if (zend_string_equals_literal_ci(prot, "MD5")) { @@ -1011,7 +1011,7 @@ /* }}} */ /* {{{ Set the security protocol in the snmpv3 session */ -static bool netsnmp_session_set_sec_protocol(struct snmp_session *s, zend_string *prot) +static ZEND_ATTRIBUTE_NONNULL bool netsnmp_session_set_sec_protocol(struct snmp_session *s, zend_string *prot) { #ifndef NETSNMP_DISABLE_DES if (zend_string_equals_literal_ci(prot, "DES")) { @@ -1048,9 +1048,10 @@ /* }}} */ /* {{{ Make key from pass phrase in the snmpv3 session */ -static bool netsnmp_session_gen_auth_key(struct snmp_session *s, zend_string *pass) +static ZEND_ATTRIBUTE_NONNULL bool netsnmp_session_gen_auth_key(struct snmp_session *s, zend_string *pass) { int snmp_errno; + s->securityAuthKeyLen = USM_AUTH_KU_LEN; if ((snmp_errno = generate_Ku(s->securityAuthProto, s->securityAuthProtoLen, (uint8_t *) ZSTR_VAL(pass), ZSTR_LEN(pass), @@ -1063,7 +1064,7 @@ /* }}} */ /* {{{ Make key from pass phrase in the snmpv3 session */ -static bool netsnmp_session_gen_sec_key(struct snmp_session *s, zend_string *pass) +static ZEND_ATTRIBUTE_NONNULL bool netsnmp_session_gen_sec_key(struct snmp_session *s, zend_string *pass) { int snmp_errno; @@ -1102,9 +1103,10 @@ /* }}} */ /* {{{ Set all snmpv3-related security options */ -static bool netsnmp_session_set_security(struct snmp_session *session, zend_string *sec_level, +static ZEND_ATTRIBUTE_NONNULL_ARGS(2) bool netsnmp_session_set_security(struct snmp_session *session, zend_string *sec_level, zend_string *auth_protocol, zend_string *auth_passphrase, zend_string *priv_protocol, - zend_string *priv_passphrase, zend_string *contextName, zend_string *contextEngineID) + zend_string *priv_passphrase, zend_string *contextName, zend_string *contextEngineID, + uint32_t auth_protocol_argnum) { /* Setting the security level. */ @@ -1115,12 +1117,22 @@ if (session->securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) { + if (!auth_protocol) { + zend_argument_value_error(auth_protocol_argnum, "cannot be null when security level is \"authNoPriv\" or \"authPriv\""); + return false; + } + /* Setting the authentication protocol. */ if (!netsnmp_session_set_auth_protocol(session, auth_protocol)) { /* ValueError already generated, just bail out */ return false; } + if (!auth_passphrase) { + zend_argument_value_error(auth_protocol_argnum + 1, "cannot be null when security level is \"authNoPriv\" or \"authPriv\""); + return false; + } + /* Setting the authentication passphrase. */ if (!netsnmp_session_gen_auth_key(session, auth_passphrase)) { /* Warning message sent already, just bail out */ @@ -1128,12 +1140,23 @@ } if (session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) { + + if (!priv_protocol) { + zend_argument_value_error(auth_protocol_argnum + 2, "cannot be null when security level is \"authPriv\""); + return false; + } + /* Setting the security protocol. */ if (!netsnmp_session_set_sec_protocol(session, priv_protocol)) { /* ValueError already generated, just bail out */ return false; } + if (!priv_passphrase) { + zend_argument_value_error(auth_protocol_argnum + 3, "cannot be null when security level is \"authPriv\""); + return false; + } + /* Setting the security protocol passphrase. */ if (!netsnmp_session_gen_sec_key(session, priv_passphrase)) { /* Warning message sent already, just bail out */ @@ -1294,7 +1317,7 @@ netsnmp_session_free(&session); RETURN_FALSE; } - if (version == SNMP_VERSION_3 && !netsnmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL)) { + if (version == SNMP_VERSION_3 && !netsnmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL, 4)) { php_free_objid_query(&objid_query, oid_ht, value_ht, st); netsnmp_session_free(&session); /* Warning message sent already, just bail out */ @@ -1669,7 +1692,7 @@ RETURN_THROWS(); } - if (!netsnmp_session_set_security(snmp_object->session, a1, a2, a3, a4, a5, a6, a7)) { + if (!netsnmp_session_set_security(snmp_object->session, a1, a2, a3, a4, a5, a6, a7, 2)) { /* Warning message sent already, just bail out */ RETURN_FALSE; } diff '--color=auto' -Naur php-8.4.18/ext/snmp/tests/gh21336.phpt php-8.4.20RC1/ext/snmp/tests/gh21336.phpt --- php-8.4.18/ext/snmp/tests/gh21336.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/snmp/tests/gh21336.phpt 2026-04-01 04:35:36.018298959 +0000 @@ -0,0 +1,41 @@ +--TEST-- +GH-21336 (undefined behavior in snmp - NULL pointer dereference in setSecurity) +--EXTENSIONS-- +snmp +--FILE-- +setSecurity('authPriv'); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +// auth passphrase NULL +try { + $session->setSecurity('authNoPriv', 'MD5'); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +// priv protocol NULL +try { + $session->setSecurity('authPriv', 'MD5', 'test12345'); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} + +// priv passphrase NULL +try { + $session->setSecurity('authPriv', 'MD5', 'test12345', 'AES'); +} catch (ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +?> +--EXPECT-- +SNMP::setSecurity(): Argument #2 ($authProtocol) cannot be null when security level is "authNoPriv" or "authPriv" +SNMP::setSecurity(): Argument #3 ($authPassphrase) cannot be null when security level is "authNoPriv" or "authPriv" +SNMP::setSecurity(): Argument #4 ($privacyProtocol) cannot be null when security level is "authPriv" +SNMP::setSecurity(): Argument #5 ($privacyPassphrase) cannot be null when security level is "authPriv" diff '--color=auto' -Naur php-8.4.18/ext/soap/php_encoding.c php-8.4.20RC1/ext/soap/php_encoding.c --- php-8.4.18/ext/soap/php_encoding.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/soap/php_encoding.c 2026-04-01 04:35:36.018495951 +0000 @@ -2534,19 +2534,20 @@ xmlNsPtr nsptr; parse_namespace(attr->children->content, &type, &ns); + char *type_dup = estrdup(type); nsptr = xmlSearchNs(attr->doc, attr->parent, BAD_CAST(ns)); - end = strrchr(type,'['); + end = strrchr(type_dup,'['); if (end) { *end = '\0'; dimension = calc_dimension(end+1); dims = get_position(dimension, end+1); } if (nsptr != NULL) { - enc = get_encoder(SOAP_GLOBAL(sdl), (char*)nsptr->href, type); + enc = get_encoder(SOAP_GLOBAL(sdl), (char*)nsptr->href, type_dup); } if (ns) {efree(ns);} - + if (type_dup) efree(type_dup); } else if ((attr = get_attribute(data->properties,"itemType")) && attr->children && attr->children->content) { diff '--color=auto' -Naur php-8.4.18/ext/soap/php_http.c php-8.4.20RC1/ext/soap/php_http.c --- php-8.4.18/ext/soap/php_http.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/soap/php_http.c 2026-04-01 04:35:36.018754620 +0000 @@ -1010,23 +1010,23 @@ char *sempos = strstr(cookie, ";"); if (eqpos != NULL && (sempos == NULL || sempos > eqpos)) { smart_str name = {0}; - int cookie_len; zval zcookie; + size_t cookie_value_len; if (sempos != NULL) { - cookie_len = sempos-(eqpos+1); + cookie_value_len = sempos-(eqpos+1); } else { - cookie_len = strlen(cookie)-(eqpos-cookie)-1; + cookie_value_len = strlen(cookie)-(eqpos-cookie)-1; } smart_str_appendl(&name, cookie, eqpos - cookie); smart_str_0(&name); array_init(&zcookie); - add_index_stringl(&zcookie, 0, eqpos + 1, cookie_len); + add_index_stringl(&zcookie, 0, eqpos + 1, cookie_value_len); if (sempos != NULL) { - char *options = cookie + cookie_len+1; + char *options = sempos + 1; while (*options) { while (*options == ' ') {options++;} sempos = strstr(options, ";"); diff '--color=auto' -Naur php-8.4.18/ext/soap/tests/bugs/cookie_parse_options_offset.phpt php-8.4.20RC1/ext/soap/tests/bugs/cookie_parse_options_offset.phpt --- php-8.4.18/ext/soap/tests/bugs/cookie_parse_options_offset.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/soap/tests/bugs/cookie_parse_options_offset.phpt 2026-04-01 04:35:36.018924401 +0000 @@ -0,0 +1,61 @@ +--TEST-- +SOAP Set-Cookie option parsing starts at wrong offset due to variable shadowing +--EXTENSIONS-- +soap +--SKIPIF-- + +--FILE-- + + + + + + +XML; +PHP; + +php_cli_server_start($code, null, $args); + +$client = new SoapClient(null, [ + 'location' => 'http://' . PHP_CLI_SERVER_ADDRESS . '/test/endpoint', + 'uri' => 'test-uri', + 'trace' => true, +]); + +try { + $client->__soapCall("test", []); +} catch (SoapFault $e) { + // Response parsing may fault, cookies are still stored +} + +$cookies = $client->__getCookies(); + +// path should default to "/test" from the request URI, not "/evil" from the value. +echo "value: " . $cookies['sessionkey'][0] . "\n"; +echo "path: " . $cookies['sessionkey'][1] . "\n"; +echo "domain: " . $cookies['sessionkey'][2] . "\n"; +?> +--EXPECT-- +value: path=/evil +path: /test +domain: good.com diff '--color=auto' -Naur php-8.4.18/ext/soap/tests/soap_qname_crash.phpt php-8.4.20RC1/ext/soap/tests/soap_qname_crash.phpt --- php-8.4.18/ext/soap/tests/soap_qname_crash.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/soap/tests/soap_qname_crash.phpt 2026-04-01 04:35:36.019019981 +0000 @@ -4,6 +4,7 @@ soap --SKIPIF-- --INI-- diff '--color=auto' -Naur php-8.4.18/ext/sockets/conversions.c php-8.4.20RC1/ext/sockets/conversions.c --- php-8.4.18/ext/sockets/conversions.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/sockets/conversions.c 2026-04-01 04:35:36.019127645 +0000 @@ -611,7 +611,7 @@ } else { /* error already emitted, but let's emit another more relevant */ do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET6 " - "address", Z_STRVAL_P(zaddr_str)); + "address", ZSTR_VAL(addr_str)); } zend_tmp_string_release(tmp_addr_str); diff '--color=auto' -Naur php-8.4.18/ext/sockets/sockets.c php-8.4.20RC1/ext/sockets/sockets.c --- php-8.4.18/ext/sockets/sockets.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/sockets/sockets.c 2026-04-01 04:35:36.019294059 +0000 @@ -1584,6 +1584,12 @@ switch (php_sock->type) { case AF_UNIX: memset(&s_un, 0, sizeof(s_un)); + + if (addr_len >= sizeof(s_un.sun_path)) { + zend_argument_value_error(5, "must be less than %d", sizeof(s_un.sun_path)); + RETURN_THROWS(); + } + s_un.sun_family = AF_UNIX; snprintf(s_un.sun_path, sizeof(s_un.sun_path), "%s", addr); diff '--color=auto' -Naur php-8.4.18/ext/sockets/tests/gh21161.phpt php-8.4.20RC1/ext/sockets/tests/gh21161.phpt --- php-8.4.18/ext/sockets/tests/gh21161.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/sockets/tests/gh21161.phpt 2026-04-01 04:35:36.019484379 +0000 @@ -0,0 +1,19 @@ +--TEST-- +GH-21161 (IPV6_PKTINFO socket option crash with null addr array entry) +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- + null, 'ifindex' => 0]); +?> +--EXPECTF-- +Warning: socket_set_option(): Host lookup failed [%i]: %s on line %d + +Warning: socket_set_option(): error converting user data (path: in6_pktinfo > addr): could not resolve address '' to get an AF_INET6 address in %s on line %d diff '--color=auto' -Naur php-8.4.18/ext/sockets/tests/socket_sendto_unix_addr_too_long.phpt php-8.4.20RC1/ext/sockets/tests/socket_sendto_unix_addr_too_long.phpt --- php-8.4.18/ext/sockets/tests/socket_sendto_unix_addr_too_long.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/sockets/tests/socket_sendto_unix_addr_too_long.phpt 2026-04-01 04:35:36.019552277 +0000 @@ -0,0 +1,29 @@ +--TEST-- +socket_sendto() with AF_UNIX rejects address exceeding sun_path limit +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; +} + +socket_close($socket); +?> +--EXPECTF-- +socket_sendto(): Argument #5 ($address) must be less than %d diff '--color=auto' -Naur php-8.4.18/ext/spl/spl_heap.c php-8.4.20RC1/ext/spl/spl_heap.c --- php-8.4.18/ext/spl/spl_heap.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/spl/spl_heap.c 2026-04-01 04:35:36.019681081 +0000 @@ -961,7 +961,7 @@ { spl_heap_object *object = Z_SPLHEAP_P(&iter->data); - if (UNEXPECTED(spl_heap_consistency_validations(object, false) != SUCCESS)) { + if (UNEXPECTED(spl_heap_consistency_validations(object, true) != SUCCESS)) { return; } @@ -992,6 +992,10 @@ RETURN_THROWS(); } + if (UNEXPECTED(spl_heap_consistency_validations(intern, true) != SUCCESS)) { + RETURN_THROWS(); + } + spl_ptr_heap_delete_top(intern->heap, NULL, ZEND_THIS); } /* }}} */ diff '--color=auto' -Naur php-8.4.18/ext/spl/tests/heap_next_write_lock.phpt php-8.4.20RC1/ext/spl/tests/heap_next_write_lock.phpt --- php-8.4.18/ext/spl/tests/heap_next_write_lock.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/spl/tests/heap_next_write_lock.phpt 2026-04-01 04:35:36.019808051 +0000 @@ -0,0 +1,34 @@ +--TEST-- +SplHeap::next() write lock +--CREDITS-- +cnitlrt +--FILE-- +did) { + $this->did = true; + // Re-entrant write during internal heap insertion comparison. + if (!$this->isEmpty()) { + $this->next(); // no write-lock validation + } + } + return parent::compare($p1, $p2); + } +} + +$q = new EvilPQ(); +try { + for ($i = 0; $i < 200; $i++) { + $q->insert("d$i", 100 - $i); + } +} catch (RuntimeException $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +RuntimeException: Heap cannot be changed when it is already being modified. diff '--color=auto' -Naur php-8.4.18/ext/standard/basic_functions.c php-8.4.20RC1/ext/standard/basic_functions.c --- php-8.4.18/ext/standard/basic_functions.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/basic_functions.c 2026-04-01 04:35:36.019945510 +0000 @@ -1768,7 +1768,10 @@ } if (i) { - php_output_start_default(); + if (UNEXPECTED(php_output_start_default() != SUCCESS)) { + zend_throw_error(NULL, "Unable to start output handler"); + RETURN_THROWS(); + } } php_get_highlight_struct(&syntax_highlighter_ini); @@ -1803,7 +1806,10 @@ Z_PARAM_PATH_STR(filename) ZEND_PARSE_PARAMETERS_END(); - php_output_start_default(); + if (UNEXPECTED(php_output_start_default() != SUCCESS)) { + zend_throw_error(NULL, "Unable to start output handler"); + RETURN_THROWS(); + } zend_stream_init_filename_ex(&file_handle, filename); zend_save_lexical_state(&original_lex_state); @@ -1840,7 +1846,10 @@ ZEND_PARSE_PARAMETERS_END(); if (i) { - php_output_start_default(); + if (UNEXPECTED(php_output_start_default() != SUCCESS)) { + zend_throw_error(NULL, "Unable to start output handler"); + RETURN_THROWS(); + } } EG(error_reporting) = E_ERROR; diff '--color=auto' -Naur php-8.4.18/ext/standard/exec.c php-8.4.20RC1/ext/standard/exec.c --- php-8.4.18/ext/standard/exec.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/exec.c 2026-04-01 04:35:36.020108188 +0000 @@ -282,7 +282,7 @@ size_t x, y; zend_string *cmd; #ifndef PHP_WIN32 - char *p = NULL; + const char *p = NULL; #endif ZEND_ASSERT(ZSTR_LEN(unescaped_cmd) == strlen(ZSTR_VAL(unescaped_cmd)) && "Must be a binary safe string"); diff '--color=auto' -Naur php-8.4.18/ext/standard/filters.c php-8.4.20RC1/ext/standard/filters.c --- php-8.4.18/ext/standard/filters.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/filters.c 2026-04-01 04:35:36.020229847 +0000 @@ -1559,7 +1559,7 @@ php_convert_filter *inst; php_stream_filter *retval = NULL; - char *dot; + const char *dot; int conv_mode = 0; if (filterparams != NULL && Z_TYPE_P(filterparams) != IS_ARRAY) { diff '--color=auto' -Naur php-8.4.18/ext/standard/libavifinfo/avifinfo.c php-8.4.20RC1/ext/standard/libavifinfo/avifinfo.c --- php-8.4.18/ext/standard/libavifinfo/avifinfo.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/libavifinfo/avifinfo.c 2026-04-01 04:35:36.020473528 +0000 @@ -34,14 +34,15 @@ // uint32_t is used everywhere in this file. It is unlikely to be insufficient // to parse AVIF headers. #define AVIFINFO_MAX_SIZE UINT32_MAX -// AvifInfoInternalFeatures uses uint8_t to store values and the number of -// values is clamped to 32 to limit the stack size. +// Be reasonable. Avoid timeouts and out-of-memory. +#define AVIFINFO_MAX_NUM_BOXES 4096 +// AvifInfoInternalFeatures uses uint8_t to store values. #define AVIFINFO_MAX_VALUE UINT8_MAX -#define AVIFINFO_UNDEFINED 0 // Maximum number of stored associations. Past that, they are skipped. #define AVIFINFO_MAX_TILES 16 #define AVIFINFO_MAX_PROPS 32 #define AVIFINFO_MAX_FEATURES 8 +#define AVIFINFO_UNDEFINED 0 // Reads an unsigned integer from 'input' with most significant bits first. // 'input' must be at least 'num_bytes'-long. @@ -93,6 +94,12 @@ #define AVIFINFO_CHECK_NOT_FOUND(check_status) \ AVIFINFO_CHECK_STATUS_IS((check_status), kNotFound) +#if defined(AVIFINFO_ENABLE_DEBUG_LOG) +#define AVIF_DEBUG_LOG(...) printf(__VA_ARGS__) +#else +#define AVIF_DEBUG_LOG(...) +#endif + //------------------------------------------------------------------------------ // Streamed input struct and helper functions. @@ -101,6 +108,7 @@ read_stream_t read; // Used to fetch more bytes from the 'stream'. skip_stream_t skip; // Used to advance the position in the 'stream'. // Fallback to 'read' if 'skip' is null. + uint64_t num_read_bytes; // Number of bytes read or skipped. } AvifInfoInternalStream; // Reads 'num_bytes' from the 'stream'. They are available at '*data'. @@ -109,6 +117,7 @@ AvifInfoInternalStream* stream, uint32_t num_bytes, const uint8_t** data) { *data = stream->read(stream->stream, num_bytes); AVIFINFO_CHECK(*data != NULL, kTruncated); + stream->num_read_bytes += num_bytes; return kFound; } @@ -127,6 +136,7 @@ return AvifInfoInternalRead(stream, num_bytes, &unused); } stream->skip(stream->stream, num_bytes); + stream->num_read_bytes += num_bytes; } return kFound; } @@ -137,6 +147,7 @@ typedef struct { uint8_t tile_item_id; uint8_t parent_item_id; + uint8_t dimg_idx; // Index of this association in the dimg box (0-based). } AvifInfoInternalTile; // Tile item id <-> parent item id associations. typedef struct { @@ -156,10 +167,15 @@ typedef struct { uint8_t has_primary_item; // True if "pitm" was parsed. - uint8_t has_alpha; // True if an alpha "auxC" was parsed. + uint8_t has_alpha; // True if an alpha "auxC" was parsed. + // Index of the gain map auxC property. + uint8_t gainmap_property_index; uint8_t primary_item_id; AvifInfoFeatures primary_item_features; // Deduced from the data below. uint8_t data_was_skipped; // True if some loops/indices were skipped. + uint8_t tone_mapped_item_id; // Id of the "tmap" box, > 0 if present. + uint8_t iinf_parsed; // True if the "iinf" (item info) box was parsed. + uint8_t iref_parsed; // True if the "iref" (item reference) box was parsed. uint8_t num_tiles; AvifInfoInternalTile tiles[AVIFINFO_MAX_TILES]; @@ -227,6 +243,36 @@ AVIFINFO_CHECK(f->has_primary_item, kNotFound); // Early exit. AVIFINFO_CHECK(f->num_dim_props > 0 && f->num_chan_props, kNotFound); + + // Look for a gain map. + // HEIF scheme: gain map is a hidden input of a derived item. + if (f->tone_mapped_item_id) { + for (uint32_t tile = 0; tile < f->num_tiles; ++tile) { + if (f->tiles[tile].parent_item_id == f->tone_mapped_item_id && + f->tiles[tile].dimg_idx == 1) { + f->primary_item_features.has_gainmap = 1; + f->primary_item_features.gainmap_item_id = f->tiles[tile].tile_item_id; + break; + } + } + } + // Adobe scheme: gain map is an auxiliary item. + if (!f->primary_item_features.has_gainmap && f->gainmap_property_index > 0) { + for (uint32_t prop_item = 0; prop_item < f->num_props; ++prop_item) { + if (f->props[prop_item].property_index == f->gainmap_property_index) { + f->primary_item_features.has_gainmap = 1; + f->primary_item_features.gainmap_item_id = f->props[prop_item].item_id; + break; + } + } + } + // If the gain map has not been found but we haven't read all the relevant + // metadata, we might still find one later and cannot stop now. + if (!f->primary_item_features.has_gainmap && + (!f->iinf_parsed || (f->tone_mapped_item_id && !f->iref_parsed))) { + return kNotFound; + } + AVIFINFO_CHECK_FOUND( AvifInfoInternalGetItemFeatures(f, f->primary_item_id, /*tile_depth=*/0)); @@ -250,8 +296,9 @@ // 'num_remaining_bytes' is the remaining size of the container of the 'box' // (either the file size itself or the content size of the parent of the 'box'). static AvifInfoInternalStatus AvifInfoInternalParseBox( - AvifInfoInternalStream* stream, uint32_t num_remaining_bytes, - uint32_t* num_parsed_boxes, AvifInfoInternalBox* box) { + int nesting_level, AvifInfoInternalStream* stream, + uint32_t num_remaining_bytes, uint32_t* num_parsed_boxes, + AvifInfoInternalBox* box) { const uint8_t* data; // See ISO/IEC 14496-12:2012(E) 4.2 uint32_t box_header_size = 8; // box 32b size + 32b type (at least) @@ -271,22 +318,38 @@ // Read the 32 least-significant bits. box->size = AvifInfoInternalReadBigEndian(data + 4, sizeof(uint32_t)); } else if (box->size == 0) { + // ISO/IEC 14496-12 4.2.2: + // if size is 0, then this box shall be in a top-level box + // (i.e. not contained in another box) + AVIFINFO_CHECK(nesting_level == 0, kInvalid); box->size = num_remaining_bytes; } AVIFINFO_CHECK(box->size >= box_header_size, kInvalid); AVIFINFO_CHECK(box->size <= num_remaining_bytes, kInvalid); + // 16 bytes of usertype should be read here if the box type is 'uuid'. + // 'uuid' boxes are skipped so usertype is part of the skipped body. + const int has_fullbox_header = !memcmp(box->type, "meta", 4) || !memcmp(box->type, "pitm", 4) || !memcmp(box->type, "ipma", 4) || !memcmp(box->type, "ispe", 4) || !memcmp(box->type, "pixi", 4) || !memcmp(box->type, "iref", 4) || - !memcmp(box->type, "auxC", 4); + !memcmp(box->type, "auxC", 4) || !memcmp(box->type, "iinf", 4) || + !memcmp(box->type, "infe", 4); if (has_fullbox_header) box_header_size += 4; AVIFINFO_CHECK(box->size >= box_header_size, kInvalid); box->content_size = box->size - box_header_size; - // Avoid timeouts. The maximum number of parsed boxes is arbitrary. - ++*num_parsed_boxes; - AVIFINFO_CHECK(*num_parsed_boxes < 4096, kAborted); + // AvifInfoGetFeaturesStream() can be called on a full stream or on a stream + // where the 'ftyp' box was already read. Do not count 'ftyp' boxes towards + // AVIFINFO_MAX_NUM_BOXES, so that this function returns the same status in + // both situations (because of the AVIFINFO_MAX_NUM_BOXES check that would + // compare a different box count otherwise). This is fine because top-level + // 'ftyp' boxes are just skipped anyway. + if (nesting_level != 0 || memcmp(box->type, "ftyp", 4)) { + // Avoid timeouts. The maximum number of parsed boxes is arbitrary. + ++*num_parsed_boxes; + AVIFINFO_CHECK(*num_parsed_boxes < AVIFINFO_MAX_NUM_BOXES, kAborted); + } box->version = 0; box->flags = 0; @@ -297,17 +360,22 @@ // See AV1 Image File Format (AVIF) 8.1 // at https://aomediacodec.github.io/av1-avif/#avif-boxes (available when // https://github.com/AOMediaCodec/av1-avif/pull/170 is merged). - uint32_t is_parsable = 1; - if (!memcmp(box->type, "meta", 4)) is_parsable = (box->version <= 0); - if (!memcmp(box->type, "pitm", 4)) is_parsable = (box->version <= 1); - if (!memcmp(box->type, "ipma", 4)) is_parsable = (box->version <= 1); - if (!memcmp(box->type, "ispe", 4)) is_parsable = (box->version <= 0); - if (!memcmp(box->type, "pixi", 4)) is_parsable = (box->version <= 0); - if (!memcmp(box->type, "iref", 4)) is_parsable = (box->version <= 1); - if (!memcmp(box->type, "auxC", 4)) is_parsable = (box->version <= 0); + const uint32_t is_parsable = + (!memcmp(box->type, "meta", 4) && box->version <= 0) || + (!memcmp(box->type, "pitm", 4) && box->version <= 1) || + (!memcmp(box->type, "ipma", 4) && box->version <= 1) || + (!memcmp(box->type, "ispe", 4) && box->version <= 0) || + (!memcmp(box->type, "pixi", 4) && box->version <= 0) || + (!memcmp(box->type, "iref", 4) && box->version <= 1) || + (!memcmp(box->type, "auxC", 4) && box->version <= 0) || + (!memcmp(box->type, "iinf", 4) && box->version <= 1) || + (!memcmp(box->type, "infe", 4) && box->version >= 2 && + box->version <= 3); // Instead of considering this file as invalid, skip unparsable boxes. - if (!is_parsable) memcpy(box->type, "\0skp", 4); // \0 so not a valid type + if (!is_parsable) memcpy(box->type, "skip", 4); // FreeSpaceBox } + AVIF_DEBUG_LOG("%*c", nesting_level * 2, ' '); + AVIF_DEBUG_LOG("Box type %.4s size %d\n", box->type, box->size); return kFound; } @@ -316,15 +384,16 @@ // Parses a 'stream' of an "ipco" box into 'features'. // "ispe" is used for width and height, "pixi" and "av1C" are used for bit depth // and number of channels, and "auxC" is used for alpha. -static AvifInfoInternalStatus ParseIpco(AvifInfoInternalStream* stream, +static AvifInfoInternalStatus ParseIpco(int nesting_level, + AvifInfoInternalStream* stream, uint32_t num_remaining_bytes, uint32_t* num_parsed_boxes, AvifInfoInternalFeatures* features) { uint32_t box_index = 1; // 1-based index. Used for iterating over properties. do { AvifInfoInternalBox box; - AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, num_remaining_bytes, - num_parsed_boxes, &box)); + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox( + nesting_level, stream, num_remaining_bytes, num_parsed_boxes, &box)); if (!memcmp(box.type, "ispe", 4)) { // See ISO/IEC 23008-12:2017(E) 6.5.3.2 @@ -407,21 +476,43 @@ // at https://aomediacodec.github.io/av1-avif/#auxiliary-images const char* kAlphaStr = "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha"; const uint32_t kAlphaStrLength = 44; // Includes terminating character. - if (box.content_size >= kAlphaStrLength) { + const char* kGainmapStr = "urn:com:photo:aux:hdrgainmap"; + const uint32_t kGainmapStrLength = 29; // Includes terminating character. + uint32_t num_read_bytes = 0; + // Check for a gain map or for an alpha plane. Start with the gain map + // since the identifier is shorter. + if (box.content_size >= kGainmapStrLength) { const uint8_t* data; AVIFINFO_CHECK_FOUND( - AvifInfoInternalRead(stream, kAlphaStrLength, &data)); + AvifInfoInternalRead(stream, kGainmapStrLength, &data)); + num_read_bytes = kGainmapStrLength; const char* const aux_type = (const char*)data; - if (strcmp(aux_type, kAlphaStr) == 0) { - // Note: It is unlikely but it is possible that this alpha plane does - // not belong to the primary item or a tile. Ignore this issue. - features->has_alpha = 1; + if (strcmp(aux_type, kGainmapStr) == 0) { + // Note: It is unlikely but it is possible that this gain map + // does not belong to the primary item or a tile. Ignore this issue. + if (box_index <= AVIFINFO_MAX_VALUE) { + features->gainmap_property_index = (uint8_t)box_index; + } else { + features->data_was_skipped = 1; + } + } else if (box.content_size >= kAlphaStrLength && + memcmp(aux_type, kAlphaStr, kGainmapStrLength) == 0) { + // The beginning of the aux type matches the alpha aux type string. + // Check the end as well. + const uint8_t* data2; + const uint32_t kEndLength = kAlphaStrLength - kGainmapStrLength; + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, kEndLength, &data2)); + num_read_bytes = kAlphaStrLength; + if (strcmp((const char*)data2, &kAlphaStr[kGainmapStrLength]) == 0) { + // Note: It is unlikely but it is possible that this alpha plane + // does not belong to the primary item or a tile. Ignore this issue. + features->has_alpha = 1; + } } - AVIFINFO_CHECK_FOUND( - AvifInfoInternalSkip(stream, box.content_size - kAlphaStrLength)); - } else { - AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); } + AVIFINFO_CHECK_FOUND( + AvifInfoInternalSkip(stream, box.content_size - num_read_bytes)); } else { AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); } @@ -431,20 +522,22 @@ AVIFINFO_RETURN(kNotFound); } -// Parses a 'stream' of an "iprp" box into 'features'. The "ipco" box contain +// Parses a 'stream' of an "iprp" box into 'features'. The "ipco" box contains // the properties which are linked to items by the "ipma" box. -static AvifInfoInternalStatus ParseIprp(AvifInfoInternalStream* stream, +static AvifInfoInternalStatus ParseIprp(int nesting_level, + AvifInfoInternalStream* stream, uint32_t num_remaining_bytes, uint32_t* num_parsed_boxes, AvifInfoInternalFeatures* features) { do { AvifInfoInternalBox box; - AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, num_remaining_bytes, - num_parsed_boxes, &box)); + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox( + nesting_level, stream, num_remaining_bytes, num_parsed_boxes, &box)); if (!memcmp(box.type, "ipco", 4)) { - AVIFINFO_CHECK_NOT_FOUND( - ParseIpco(stream, box.content_size, num_parsed_boxes, features)); + AVIFINFO_CHECK_NOT_FOUND(ParseIpco(nesting_level + 1, stream, + box.content_size, num_parsed_boxes, + features)); } else if (!memcmp(box.type, "ipma", 4)) { // See ISO/IEC 23008-12:2017(E) 9.3.2 uint32_t num_read_bytes = 4; @@ -503,6 +596,7 @@ AVIFINFO_CHECK_NOT_FOUND( AvifInfoInternalGetPrimaryItemFeatures(features)); + // Mostly if 'data_was_skipped'. AVIFINFO_CHECK_FOUND( AvifInfoInternalSkip(stream, box.content_size - num_read_bytes)); } else { @@ -519,14 +613,17 @@ // The "dimg" boxes contain links between tiles and their parent items, which // can be used to infer bit depth and number of channels for the primary item // when the latter does not have these properties. -static AvifInfoInternalStatus ParseIref(AvifInfoInternalStream* stream, +static AvifInfoInternalStatus ParseIref(int nesting_level, + AvifInfoInternalStream* stream, uint32_t num_remaining_bytes, uint32_t* num_parsed_boxes, AvifInfoInternalFeatures* features) { - do { + features->iref_parsed = 1; + + while (num_remaining_bytes > 0) { AvifInfoInternalBox box; - AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, num_remaining_bytes, - num_parsed_boxes, &box)); + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox( + nesting_level, stream, num_remaining_bytes, num_parsed_boxes, &box)); if (!memcmp(box.type, "dimg", 4)) { // See ISO/IEC 14496-12:2015(E) 8.11.12.2 @@ -557,6 +654,7 @@ features->num_tiles < AVIFINFO_MAX_TILES) { features->tiles[features->num_tiles].tile_item_id = to_item_id; features->tiles[features->num_tiles].parent_item_id = from_item_id; + features->tiles[features->num_tiles].dimg_idx = i; ++features->num_tiles; } else { features->data_was_skipped = 1; @@ -566,11 +664,77 @@ // If all features are available now, do not look further. AVIFINFO_CHECK_NOT_FOUND( AvifInfoInternalGetPrimaryItemFeatures(features)); + + // Mostly if 'data_was_skipped'. + AVIFINFO_CHECK_FOUND( + AvifInfoInternalSkip(stream, box.content_size - num_read_bytes)); } else { AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); } num_remaining_bytes -= box.size; - } while (num_remaining_bytes > 0); + } + AVIFINFO_RETURN(kNotFound); +} + +//------------------------------------------------------------------------------ + +// Parses a 'stream' of an "iinf" box into 'features'. +static AvifInfoInternalStatus ParseIinf(int nesting_level, + AvifInfoInternalStream* stream, + uint32_t num_remaining_bytes, + uint32_t box_version, + uint32_t* num_parsed_boxes, + AvifInfoInternalFeatures* features) { + features->iinf_parsed = 1; + + const uint32_t num_bytes_per_entry_count = box_version == 0 ? 2 : 4; + AVIFINFO_CHECK(num_bytes_per_entry_count <= num_remaining_bytes, kInvalid); + const uint8_t* data; + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, num_bytes_per_entry_count, &data)); + num_remaining_bytes -= num_bytes_per_entry_count; + const uint32_t entry_count = + AvifInfoInternalReadBigEndian(data, num_bytes_per_entry_count); + + for (int i = 0; i < entry_count; ++i) { + AvifInfoInternalBox box; + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox( + nesting_level, stream, num_remaining_bytes, num_parsed_boxes, &box)); + + if (!memcmp(box.type, "infe", 4)) { + // See ISO/IEC 14496-12:2015(E) 8.11.6.2 + const uint32_t num_bytes_per_id = (box.version == 2) ? 2 : 4; + const uint8_t* data; + // item_ID (16 or 32) + item_protection_index (16) + item_type (32). + AVIFINFO_CHECK(num_bytes_per_id + 2 + 4 <= box.content_size, kInvalid); + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, num_bytes_per_id, &data)); + const uint32_t item_id = + AvifInfoInternalReadBigEndian(data, num_bytes_per_id); + + // Skip item_protection_index. + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, 2)); + + const uint8_t* item_type; + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 4, &item_type)); + if (!memcmp(item_type, "tmap", 4)) { + // Tone Mapped Image: indicates the presence of a gain map. + if (item_id <= AVIFINFO_MAX_VALUE) { + features->tone_mapped_item_id = (uint8_t)item_id; + } else { + features->data_was_skipped = 1; + } + } + + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip( + stream, box.content_size - (num_bytes_per_id + 2 + 4))); + } else { + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); + } + + num_remaining_bytes -= box.size; + if (num_remaining_bytes == 0) break; // Ignore entry_count bigger than box. + } AVIFINFO_RETURN(kNotFound); } @@ -578,18 +742,19 @@ // Parses a 'stream' of a "meta" box. It looks for the primary item ID in the // "pitm" box and recurses into other boxes to find its 'features'. -static AvifInfoInternalStatus ParseMeta(AvifInfoInternalStream* stream, +static AvifInfoInternalStatus ParseMeta(int nesting_level, + AvifInfoInternalStream* stream, uint32_t num_remaining_bytes, uint32_t* num_parsed_boxes, AvifInfoInternalFeatures* features) { do { AvifInfoInternalBox box; - AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, num_remaining_bytes, - num_parsed_boxes, &box)); - + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox( + nesting_level, stream, num_remaining_bytes, num_parsed_boxes, &box)); if (!memcmp(box.type, "pitm", 4)) { // See ISO/IEC 14496-12:2015(E) 8.11.4.2 const uint32_t num_bytes_per_id = (box.version == 0) ? 2 : 4; + const uint64_t primary_item_id_location = stream->num_read_bytes; const uint8_t* data; AVIFINFO_CHECK(num_bytes_per_id <= num_remaining_bytes, kInvalid); AVIFINFO_CHECK_FOUND( @@ -599,14 +764,23 @@ AVIFINFO_CHECK(primary_item_id <= AVIFINFO_MAX_VALUE, kAborted); features->has_primary_item = 1; features->primary_item_id = primary_item_id; + features->primary_item_features.primary_item_id_location = + primary_item_id_location; + features->primary_item_features.primary_item_id_bytes = num_bytes_per_id; AVIFINFO_CHECK_FOUND( AvifInfoInternalSkip(stream, box.content_size - num_bytes_per_id)); } else if (!memcmp(box.type, "iprp", 4)) { - AVIFINFO_CHECK_NOT_FOUND( - ParseIprp(stream, box.content_size, num_parsed_boxes, features)); + AVIFINFO_CHECK_NOT_FOUND(ParseIprp(nesting_level + 1, stream, + box.content_size, num_parsed_boxes, + features)); } else if (!memcmp(box.type, "iref", 4)) { - AVIFINFO_CHECK_NOT_FOUND( - ParseIref(stream, box.content_size, num_parsed_boxes, features)); + AVIFINFO_CHECK_NOT_FOUND(ParseIref(nesting_level + 1, stream, + box.content_size, num_parsed_boxes, + features)); + } else if (!memcmp(box.type, "iinf", 4)) { + AVIFINFO_CHECK_NOT_FOUND(ParseIinf(nesting_level + 1, stream, + box.content_size, box.version, + num_parsed_boxes, features)); } else { AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); } @@ -622,8 +796,9 @@ static AvifInfoInternalStatus ParseFtyp(AvifInfoInternalStream* stream) { AvifInfoInternalBox box; uint32_t num_parsed_boxes = 0; - AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, AVIFINFO_MAX_SIZE, - &num_parsed_boxes, &box)); + const int nesting_level = 0; + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox( + nesting_level, stream, AVIFINFO_MAX_SIZE, &num_parsed_boxes, &box)); AVIFINFO_CHECK(!memcmp(box.type, "ftyp", 4), kInvalid); // Iterate over brands. See ISO/IEC 14496-12:2012(E) 4.3.1 AVIFINFO_CHECK(box.content_size >= 8, kInvalid); // major_brand,minor_version @@ -647,15 +822,16 @@ AvifInfoInternalFeatures* features) { while (1) { AvifInfoInternalBox box; - AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, AVIFINFO_MAX_SIZE, - num_parsed_boxes, &box)); + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox( + /*nesting_level=*/0, stream, AVIFINFO_MAX_SIZE, num_parsed_boxes, + &box)); if (!memcmp(box.type, "meta", 4)) { - return ParseMeta(stream, box.content_size, num_parsed_boxes, features); + return ParseMeta(/*nesting_level=*/1, stream, box.content_size, + num_parsed_boxes, features); } else { AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); } } - AVIFINFO_RETURN(kInvalid); // No "meta" no good. } //------------------------------------------------------------------------------ @@ -698,6 +874,11 @@ AvifInfoStatus AvifInfoGetFeatures(const uint8_t* data, size_t data_size, AvifInfoFeatures* features) { + const AvifInfoStatus status = AvifInfoIdentify(data, data_size); + if (status != kAvifInfoOk) { + if (features != NULL) memset(features, 0, sizeof(*features)); + return status; + } AvifInfoInternalForward stream; stream.data = data; stream.data_size = data_size; @@ -710,19 +891,20 @@ // Streamed input API AvifInfoStatus AvifInfoIdentifyStream(void* stream, read_stream_t read, - skip_stream_t skip) { + skip_stream_t skip) { if (read == NULL) return kAvifInfoNotEnoughData; AvifInfoInternalStream internal_stream; internal_stream.stream = stream; internal_stream.read = read; internal_stream.skip = skip; // Fallbacks to 'read' if null. + internal_stream.num_read_bytes = 0; return AvifInfoInternalConvertStatus(ParseFtyp(&internal_stream)); } AvifInfoStatus AvifInfoGetFeaturesStream(void* stream, read_stream_t read, - skip_stream_t skip, - AvifInfoFeatures* features) { + skip_stream_t skip, + AvifInfoFeatures* features) { if (features != NULL) memset(features, 0, sizeof(*features)); if (read == NULL) return kAvifInfoNotEnoughData; @@ -730,6 +912,7 @@ internal_stream.stream = stream; internal_stream.read = read; internal_stream.skip = skip; // Fallbacks to 'read' if null. + internal_stream.num_read_bytes = 0; uint32_t num_parsed_boxes = 0; AvifInfoInternalFeatures internal_features; memset(&internal_features, AVIFINFO_UNDEFINED, sizeof(internal_features)); diff '--color=auto' -Naur php-8.4.18/ext/standard/libavifinfo/avifinfo.h php-8.4.20RC1/ext/standard/libavifinfo/avifinfo.h --- php-8.4.18/ext/standard/libavifinfo/avifinfo.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/libavifinfo/avifinfo.h 2026-04-01 04:35:36.020720855 +0000 @@ -35,10 +35,22 @@ } AvifInfoStatus; typedef struct { - uint32_t width, height; // In number of pixels. Ignores mirror and rotation. - uint32_t bit_depth; // Likely 8, 10 or 12 bits per channel per pixel. - uint32_t num_channels; // Likely 1, 2, 3 or 4 channels: - // (1 monochrome or 3 colors) + (0 or 1 alpha) + uint32_t width, height; // In number of pixels. Ignores crop and rotation. + uint32_t bit_depth; // Likely 8, 10 or 12 bits per channel per pixel. + uint32_t num_channels; // Likely 1, 2, 3 or 4 channels: + // (1 monochrome or 3 colors) + (0 or 1 alpha) + uint8_t has_gainmap; // True if a gain map was found. + // Id of the gain map item. Assumes there is at most one. If there are several + // gain map items (e.g. because the main image is tiled and each tile has an + // independent gain map), then this is one of the ids, arbitrarily chosen. + uint8_t gainmap_item_id; + // Start location in bytes of the primary item id, relative to the beginning + // of the given payload. The primary item id is a big endian number stored on + // bytes primary_item_id_location to + // primary_item_id_location+primary_item_id_bytes-1 inclusive. + uint64_t primary_item_id_location; + // Number of bytes of the primary item id. + uint8_t primary_item_id_bytes; } AvifInfoFeatures; //------------------------------------------------------------------------------ @@ -46,13 +58,19 @@ // Use this API if a raw byte array of fixed size is available as input. // Parses the 'data' and returns kAvifInfoOk if it is identified as an AVIF. +// 'data' can be partial but must point to the beginning of the AVIF file. // The file type can be identified in the first 12 bytes of most AVIF files. AvifInfoStatus AvifInfoIdentify(const uint8_t* data, size_t data_size); -// Parses the identified AVIF 'data' and extracts its 'features'. +// Parses the 'data' and returns kAvifInfoOk and its 'features' if it is +// identified as an AVIF file. // 'data' can be partial but must point to the beginning of the AVIF file. // The 'features' can be parsed in the first 450 bytes of most AVIF files. // 'features' are set to 0 unless kAvifInfoOk is returned. +// There is no need to call AvifInfoIdentify() before AvifInfoGetFeatures(). +// AvifInfoGetFeatures() parses the file further than AvifInfoIdentify() so it +// is possible that AvifInfoGetFeatures() returns errors while +// AvifInfoIdentify() returns kAvifInfoOk on the same given input bytes. AvifInfoStatus AvifInfoGetFeatures(const uint8_t* data, size_t data_size, AvifInfoFeatures* features); @@ -78,7 +96,15 @@ // 'read' cannot be null. If 'skip' is null, 'read' is called instead. AvifInfoStatus AvifInfoIdentifyStream(void* stream, read_stream_t read, skip_stream_t skip); -// Can be called right after AvifInfoIdentifyStream() with the same 'stream'. + +// Can be called right after AvifInfoIdentifyStream() with the same 'stream' +// object if AvifInfoIdentifyStream() returned kAvifInfoOk. +// Any location-dependent feature such as 'primary_item_id_location' is relative +// to the given 'stream', and must be offset by the number of bytes read or +// skipped during AvifInfoIdentifyStream() if it was called prior to +// AvifInfoGetFeaturesStream() on the same 'stream' object. +// AvifInfoGetFeaturesStream() should only be called if AvifInfoIdentifyStream() +// returned kAvifInfoOk with the same input bytes. AvifInfoStatus AvifInfoGetFeaturesStream(void* stream, read_stream_t read, skip_stream_t skip, AvifInfoFeatures* features); diff '--color=auto' -Naur php-8.4.18/ext/standard/libavifinfo/README.md php-8.4.20RC1/ext/standard/libavifinfo/README.md --- php-8.4.18/ext/standard/libavifinfo/README.md 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/libavifinfo/README.md 2026-04-01 04:35:36.020377627 +0000 @@ -7,5 +7,5 @@ channel count without depending on the full libavif library. `avifinfo.h`, `avifinfo.c`, `LICENSE` and `PATENTS` were copied verbatim from: \ -https://aomedia.googlesource.com/libavifinfo/+/96f34d945ac7dac229feddfa94dbae66e202b838 \ +https://aomedia.googlesource.com/libavifinfo/+/2b924defa4c2cd227540efe164067a8cc913eeba \ They can easily be kept up-to-date the same way. diff '--color=auto' -Naur php-8.4.18/ext/standard/tests/file/bug52820.phpt php-8.4.20RC1/ext/standard/tests/file/bug52820.phpt --- php-8.4.18/ext/standard/tests/file/bug52820.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/tests/file/bug52820.phpt 2026-04-01 04:35:36.020825262 +0000 @@ -45,22 +45,18 @@ --EXPECTREGEX-- temp stream \(close after\): About to rewind! -(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/ -\* [Cc]losing connection( #?-?\d+)? +(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/(\n\* [Cc]losing connection( #?-?\d+)?)? memory stream \(close after\): About to rewind! -(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/ -\* [Cc]losing connection( #?-?\d+)? +(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/(\n\* [Cc]losing connection( #?-?\d+)?)? temp stream \(leak\): About to rewind! -(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/ -\* [Cc]losing connection( #?-?\d+)? +(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/(\n\* [Cc]losing connection( #?-?\d+)?)? memory stream \(leak\): About to rewind! -(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/ -\* [Cc]losing connection( #?-?\d+)? +(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/(\n\* [Cc]losing connection( #?-?\d+)?)? Done\. diff '--color=auto' -Naur php-8.4.18/ext/standard/tests/file/file_get_contents_file_put_contents_5gb.phpt php-8.4.20RC1/ext/standard/tests/file/file_get_contents_file_put_contents_5gb.phpt --- php-8.4.18/ext/standard/tests/file/file_get_contents_file_put_contents_5gb.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/tests/file/file_get_contents_file_put_contents_5gb.phpt 2026-04-01 04:35:36.020907498 +0000 @@ -2,6 +2,7 @@ Test file_put_contents() and file_get_contents() functions with 5GB string --SKIPIF-- --INI-- -zend.max_allowed_stack_size=128K +zend.max_allowed_stack_size=256K --FILE-- --INI-- -zend.max_allowed_stack_size=128K +zend.max_allowed_stack_size=256K --FILE-- $a]; } try { diff '--color=auto' -Naur php-8.4.18/ext/standard/tests/strings/gh15613.phpt php-8.4.20RC1/ext/standard/tests/strings/gh15613.phpt --- php-8.4.18/ext/standard/tests/strings/gh15613.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/tests/strings/gh15613.phpt 2026-04-01 04:35:36.021143594 +0000 @@ -2,6 +2,7 @@ GH-15613 overflow on hex strings repeater value --SKIPIF-- --INI-- diff '--color=auto' -Naur php-8.4.18/ext/standard/tests/strings/gh18976.phpt php-8.4.20RC1/ext/standard/tests/strings/gh18976.phpt --- php-8.4.18/ext/standard/tests/strings/gh18976.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/tests/strings/gh18976.phpt 2026-04-01 04:35:36.021239585 +0000 @@ -2,6 +2,10 @@ GH-18976 (pack overflow with h/H format) --INI-- memory_limit=-1 +--SKIPIF-- + --FILE-- getMessage(), "\n"; +} +?> +--EXPECTF-- +%a +Fatal error: php_strip_whitespace(): Cannot use output buffering in output buffering display handlers in %s on line %d diff '--color=auto' -Naur php-8.4.18/ext/standard/tests/strings/gh20906_2.phpt php-8.4.20RC1/ext/standard/tests/strings/gh20906_2.phpt --- php-8.4.18/ext/standard/tests/strings/gh20906_2.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/standard/tests/strings/gh20906_2.phpt 2026-04-01 04:35:36.021398395 +0000 @@ -0,0 +1,21 @@ +--TEST-- +GH-20906 (Assertion failure when messing up output buffers) - highlight_file +--CREDITS-- +vi3tL0u1s +--FILE-- + +--EXPECTF-- +%a +Fatal error: highlight_file(): Cannot use output buffering in output buffering display handlers in %s on line %d diff '--color=auto' -Naur php-8.4.18/ext/standard/tests/strings/gh20906_3.phpt php-8.4.20RC1/ext/standard/tests/strings/gh20906_3.phpt --- php-8.4.18/ext/standard/tests/strings/gh20906_3.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/standard/tests/strings/gh20906_3.phpt 2026-04-01 04:35:36.021495168 +0000 @@ -0,0 +1,21 @@ +--TEST-- +GH-20906 (Assertion failure when messing up output buffers) - highlight_string +--CREDITS-- +vi3tL0u1s +--FILE-- + +--EXPECTF-- +%a +Fatal error: highlight_string(): Cannot use output buffering in output buffering display handlers in %s on line %d diff '--color=auto' -Naur php-8.4.18/ext/standard/user_filters.c php-8.4.20RC1/ext/standard/user_filters.c --- php-8.4.18/ext/standard/user_filters.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/standard/user_filters.c 2026-04-01 04:35:36.021607741 +0000 @@ -259,8 +259,8 @@ len = strlen(filtername); /* determine the classname/class entry */ - if (NULL == (fdat = zend_hash_str_find_ptr(BG(user_filter_map), (char*)filtername, len))) { - char *period; + if (NULL == (fdat = zend_hash_str_find_ptr(BG(user_filter_map), filtername, len))) { + const char *period; /* Userspace Filters using ambiguous wildcards could cause problems. i.e.: myfilter.foo.bar will always call into myfilter.foo.* @@ -272,16 +272,16 @@ /* Search for wildcard matches instead */ memcpy(wildcard, filtername, len + 1); /* copy \0 */ - period = wildcard + (period - filtername); - while (period) { - ZEND_ASSERT(period[0] == '.'); - period[1] = '*'; - period[2] = '\0'; + char *new_period = wildcard + (period - filtername); + while (new_period) { + ZEND_ASSERT(new_period[0] == '.'); + new_period[1] = '*'; + new_period[2] = '\0'; if (NULL != (fdat = zend_hash_str_find_ptr(BG(user_filter_map), wildcard, strlen(wildcard)))) { - period = NULL; + new_period = NULL; } else { - *period = '\0'; - period = strrchr(wildcard, '.'); + *new_period = '\0'; + new_period = strrchr(wildcard, '.'); } } efree(wildcard); @@ -311,7 +311,7 @@ } /* filtername */ - add_property_string(&obj, "filtername", (char*)filtername); + add_property_string(&obj, "filtername", filtername); /* and the parameters, if any */ if (filterparams) { diff '--color=auto' -Naur php-8.4.18/ext/sysvshm/sysvshm.c php-8.4.20RC1/ext/sysvshm/sysvshm.c --- php-8.4.18/ext/sysvshm/sysvshm.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/sysvshm/sysvshm.c 2026-04-01 04:35:36.021721255 +0000 @@ -309,11 +309,13 @@ shm_data = &shm_var->mem; PHP_VAR_UNSERIALIZE_INIT(var_hash); - if (php_var_unserialize(return_value, (const unsigned char **) &shm_data, (unsigned char *) shm_data + shm_var->length, &var_hash) != 1) { + int res = php_var_unserialize(return_value, (const unsigned char **) &shm_data, (unsigned char *) shm_data + shm_var->length, &var_hash); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + if (res != 1) { php_error_docref(NULL, E_WARNING, "Variable data in shared memory is corrupted"); - RETVAL_FALSE; + zval_ptr_dtor(return_value); + RETURN_FALSE; } - PHP_VAR_UNSERIALIZE_DESTROY(var_hash); } /* }}} */ diff '--color=auto' -Naur php-8.4.18/ext/sysvshm/tests/shm_get_var_leak.phpt php-8.4.20RC1/ext/sysvshm/tests/shm_get_var_leak.phpt --- php-8.4.18/ext/sysvshm/tests/shm_get_var_leak.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/sysvshm/tests/shm_get_var_leak.phpt 2026-04-01 04:35:36.021805765 +0000 @@ -0,0 +1,37 @@ +--TEST-- +shm_get_var() leaks if variable is corrupted +--EXTENSIONS-- +sysvshm +ffi +--INI-- +ffi.enable=1 +--SKIPIF-- + +--FILE-- +shmat($ffi->shmget($key, 0, 0), $ffi->new('void *'), 0); + +$ptr[0x40 + 13] = 0; // Corrupt first byte of second element of serialized data + +var_dump(shm_get_var($s, 0)); + +shm_remove($s); + +?> +--EXPECTF-- +Warning: shm_get_var(): Variable data in shared memory is corrupted in %s on line %d +bool(false) diff '--color=auto' -Naur php-8.4.18/ext/tidy/tests/parsing_file_too_large.phpt php-8.4.20RC1/ext/tidy/tests/parsing_file_too_large.phpt --- php-8.4.18/ext/tidy/tests/parsing_file_too_large.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/tidy/tests/parsing_file_too_large.phpt 2026-04-01 04:35:36.021908479 +0000 @@ -4,6 +4,7 @@ tidy --SKIPIF-- documentElement->append($sheet->createElementNS('urn:test', 'test:dummy')); +$sheet->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:test', 'urn:test'); $input = Dom\XMLDocument::createFromString(<< diff '--color=auto' -Naur php-8.4.18/ext/xsl/tests/gh21357_1.phpt php-8.4.20RC1/ext/xsl/tests/gh21357_1.phpt --- php-8.4.18/ext/xsl/tests/gh21357_1.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/xsl/tests/gh21357_1.phpt 2026-04-01 04:35:36.022139876 +0000 @@ -0,0 +1,20 @@ +--TEST-- +GH-21357 (XSLTProcessor works with \DOMDocument, but fails with \Dom\XMLDocument) +--EXTENSIONS-- +dom +xsl +--CREDITS-- +jacekkow +--FILE-- + + + +XML; + +$dom = Dom\XMLDocument::createFromString($xml); +var_dump(new XSLTProcessor()->importStylesheet($dom)); +?> +--EXPECT-- +bool(true) diff '--color=auto' -Naur php-8.4.18/ext/xsl/tests/gh21357_2.phpt php-8.4.20RC1/ext/xsl/tests/gh21357_2.phpt --- php-8.4.18/ext/xsl/tests/gh21357_2.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/ext/xsl/tests/gh21357_2.phpt 2026-04-01 04:35:36.022198928 +0000 @@ -0,0 +1,35 @@ +--TEST-- +GH-21357 (XSLTProcessor works with \DOMDocument, but fails with \Dom\XMLDocument) +--EXTENSIONS-- +dom +xsl +--CREDITS-- +jacekkow +--FILE-- + + + + + + + + + + + + +'; +$dom = Dom\XMLDocument::createFromString($xsl); +$xsl = new XSLTProcessor(); +$xsl->importStylesheet($dom); +var_dump($xsl->transformToXml(\Dom\XMLDocument::createFromString(''))); +?> +--EXPECT-- +string(138) " + +" diff '--color=auto' -Naur php-8.4.18/ext/xsl/xsltprocessor.c php-8.4.20RC1/ext/xsl/xsltprocessor.c --- php-8.4.18/ext/xsl/xsltprocessor.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/xsl/xsltprocessor.c 2026-04-01 04:35:36.022329404 +0000 @@ -123,65 +123,38 @@ } } -static void xsl_add_ns_to_map(xmlHashTablePtr table, xsltStylesheetPtr sheet, const xmlNode *cur, const xmlChar *prefix, const xmlChar *uri) +static void xsl_add_ns_def(xmlNodePtr node) { - const xmlChar *existing_url = xmlHashLookup(table, prefix); - if (existing_url != NULL && !xmlStrEqual(existing_url, uri)) { - xsltTransformError(NULL, sheet, (xmlNodePtr) cur, "Namespaces prefix %s used for multiple namespaces\n", prefix); - sheet->warnings++; - } else if (existing_url == NULL) { - xmlHashUpdateEntry(table, prefix, (void *) uri, NULL); - } -} + if (node->type == XML_ELEMENT_NODE) { + for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) { + if (php_dom_ns_is_fast((const xmlNode *) attr, php_dom_ns_is_xmlns_magic_token)) { + xmlNsPtr ns = xmlMalloc(sizeof(*ns)); + if (!ns) { + return; + } -/* Adds all namespace declaration (not using nsDef) into a hash map that maps prefix to uri. Warns on conflicting declarations. */ -static void xsl_build_ns_map(xmlHashTablePtr table, xsltStylesheetPtr sheet, php_dom_libxml_ns_mapper *ns_mapper, const xmlDoc *doc) -{ - const xmlNode *cur = xmlDocGetRootElement(doc); + bool should_free; + xmlChar *attr_value = php_libxml_attr_value(attr, &should_free); - while (cur != NULL) { - if (cur->type == XML_ELEMENT_NODE) { - if (cur->ns != NULL && cur->ns->prefix != NULL) { - xsl_add_ns_to_map(table, sheet, cur, cur->ns->prefix, cur->ns->href); - } - - for (const xmlAttr *attr = cur->properties; attr != NULL; attr = attr->next) { - if (attr->ns != NULL && attr->ns->prefix != NULL && php_dom_ns_is_fast_ex(attr->ns, php_dom_ns_is_xmlns_magic_token) - && attr->children != NULL && attr->children->content != NULL) { - /* This attribute declares a namespace, get the relevant instance. - * The declared namespace is not the same as the namespace of this attribute (which is xmlns). */ - const xmlChar *prefix = attr->name; - xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, (const char *) prefix, (const char *) attr->children->content); - xsl_add_ns_to_map(table, sheet, cur, prefix, ns->href); - } + memset(ns, 0, sizeof(*ns)); + ns->type = XML_LOCAL_NAMESPACE; + ns->href = should_free ? attr_value : xmlStrdup(attr_value); + ns->prefix = attr->ns->prefix ? xmlStrdup(attr->name) : NULL; + ns->next = node->nsDef; + node->nsDef = ns; } } - - cur = php_dom_next_in_tree_order(cur, (const xmlNode *) doc); } } -/* Apply namespace corrections for new DOM */ -typedef enum { - XSL_NS_HASH_CORRECTION_NONE = 0, - XSL_NS_HASH_CORRECTION_APPLIED = 1, - XSL_NS_HASH_CORRECTION_FAILED = 2 -} xsl_ns_hash_correction_status; - -static zend_always_inline xsl_ns_hash_correction_status xsl_apply_ns_hash_corrections(xsltStylesheetPtr sheetp, xmlNodePtr nodep, xmlDocPtr doc) +static void xsl_add_ns_defs(xmlDocPtr doc) { - if (sheetp->nsHash == NULL) { - dom_object *node_intern = php_dom_object_get_data(nodep); - if (node_intern != NULL && php_dom_follow_spec_intern(node_intern)) { - sheetp->nsHash = xmlHashCreate(10); - if (UNEXPECTED(!sheetp->nsHash)) { - return XSL_NS_HASH_CORRECTION_FAILED; - } - xsl_build_ns_map(sheetp->nsHash, sheetp, php_dom_get_ns_mapper(node_intern), doc); - return XSL_NS_HASH_CORRECTION_APPLIED; - } + xmlNodePtr base = (xmlNodePtr) doc; + xmlNodePtr node = base->children; + while (node != NULL) { + xsl_add_ns_def(node); + node = php_dom_next_in_tree_order(node, base); } - return XSL_NS_HASH_CORRECTION_NONE; } /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html# @@ -190,11 +163,11 @@ PHP_METHOD(XSLTProcessor, importStylesheet) { zval *id, *docp = NULL; - xmlDoc *doc = NULL, *newdoc = NULL; + xmlDoc *newdoc = NULL; xsltStylesheetPtr sheetp; bool clone_docu = false; xmlNode *nodep = NULL; - zval *cloneDocu, rv; + zval *cloneDocu, rv, clone_zv; zend_string *member; id = ZEND_THIS; @@ -202,51 +175,59 @@ RETURN_THROWS(); } - nodep = php_libxml_import_node(docp); + /* libxslt uses _private, so we must copy the imported + * stylesheet document otherwise the node proxies will be a mess. + * We will clone the object and detach the libxml internals later. */ + zend_object *clone = Z_OBJ_HANDLER_P(docp, clone_obj)(Z_OBJ_P(docp)); + if (!clone) { + RETURN_THROWS(); + } + + ZVAL_OBJ(&clone_zv, clone); + nodep = php_libxml_import_node(&clone_zv); if (nodep) { - doc = nodep->doc; + newdoc = nodep->doc; } - if (doc == NULL) { + if (newdoc == NULL) { + OBJ_RELEASE(clone); zend_argument_type_error(1, "must be a valid XML node"); RETURN_THROWS(); } - /* libxslt uses _private, so we must copy the imported - stylesheet document otherwise the node proxies will be a mess */ - newdoc = xmlCopyDoc(doc, 1); - xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL); + php_libxml_node_object *clone_lxml_obj = Z_LIBXML_NODE_P(&clone_zv); + PHP_LIBXML_SANITIZE_GLOBALS(parse); ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; ZEND_DIAGNOSTIC_IGNORED_END + if (clone_lxml_obj->document->class_type == PHP_LIBXML_CLASS_MODERN) { + xsl_add_ns_defs(newdoc); + } + sheetp = xsltParseStylesheetDoc(newdoc); PHP_LIBXML_RESTORE_GLOBALS(parse); if (!sheetp) { - xmlFreeDoc(newdoc); + OBJ_RELEASE(clone); RETURN_FALSE; } xsl_object *intern = Z_XSL_P(id); - xsl_ns_hash_correction_status status = xsl_apply_ns_hash_corrections(sheetp, nodep, doc); - if (UNEXPECTED(status == XSL_NS_HASH_CORRECTION_FAILED)) { - xsltFreeStylesheet(sheetp); - xmlFreeDoc(newdoc); - RETURN_FALSE; - } else if (status == XSL_NS_HASH_CORRECTION_APPLIED) { - /* The namespace mappings need to be kept alive. - * This is stored in the ref obj outside of libxml2, but that means that the sheet won't keep it alive - * unlike with namespaces from old DOM. */ - if (intern->sheet_ref_obj) { - php_libxml_decrement_doc_ref_directly(intern->sheet_ref_obj); - } - intern->sheet_ref_obj = Z_LIBXML_NODE_P(docp)->document; - intern->sheet_ref_obj->refcount++; - } + /* Detach object */ + clone_lxml_obj->document->ptr = NULL; + /* The namespace mappings need to be kept alive. + * This is stored in the ref obj outside of libxml2, but that means that the sheet won't keep it alive + * unlike with namespaces from old DOM. */ + if (intern->sheet_ref_obj) { + php_libxml_decrement_doc_ref_directly(intern->sheet_ref_obj); + } + intern->sheet_ref_obj = clone_lxml_obj->document; + intern->sheet_ref_obj->refcount++; + OBJ_RELEASE(clone); member = ZSTR_INIT_LITERAL("cloneDocument", 0); cloneDocu = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_R, NULL, &rv); diff '--color=auto' -Naur php-8.4.18/ext/zip/php_zip.h php-8.4.20RC1/ext/zip/php_zip.h --- php-8.4.18/ext/zip/php_zip.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/zip/php_zip.h 2026-04-01 04:35:36.022464820 +0000 @@ -39,7 +39,7 @@ /* Additionnal flags not from libzip */ #define ZIP_FL_OPEN_FILE_NOW (1u<<30) -#define PHP_ZIP_VERSION "1.22.7" +#define PHP_ZIP_VERSION "1.22.8" #ifdef HAVE_LIBZIP_VERSION #define LIBZIP_VERSION_STR zip_libzip_version() diff '--color=auto' -Naur php-8.4.18/ext/zip/zip_stream.c php-8.4.20RC1/ext/zip/zip_stream.c --- php-8.4.18/ext/zip/zip_stream.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/ext/zip/zip_stream.c 2026-04-01 04:35:36.022537868 +0000 @@ -125,12 +125,11 @@ size_t path_len = strlen(stream->orig_path); char file_dirname[MAXPATHLEN]; struct zip *za; - char *fragment; size_t fragment_len; int err; zend_string *file_basename; - fragment = strchr(path, '#'); + const char *fragment = strchr(path, '#'); if (!fragment) { return -1; } @@ -286,14 +285,13 @@ struct zip *za; struct zip_file *zf = NULL; - char *fragment; size_t fragment_len; int err; php_stream *stream = NULL; struct php_zip_stream_data_t *self; - fragment = strchr(path, '#'); + const char *fragment = strchr(path, '#'); if (!fragment) { return NULL; } diff '--color=auto' -Naur php-8.4.18/EXTENSIONS php-8.4.20RC1/EXTENSIONS --- php-8.4.18/EXTENSIONS 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/EXTENSIONS 2026-04-01 04:35:35.982361296 +0000 @@ -170,57 +170,57 @@ PRIMARY MAINTAINER: Christian Stocker (2003 - 2011) Rob Richards (2003 - 2012) Marcus Börger (2003 - 2006) - Niels Dossche (2023 - 2025) -MAINTENANCE: Maintained + Nora Dossche (2023 - 2026) +MAINTENANCE: Odd fixes STATUS: Working SINCE: 5.0 ------------------------------------------------------------------------------- EXTENSION: simplexml PRIMARY MAINTAINER: Marcus Börger (2003 - 2008) - Niels Dossche (2023 - 2025) -MAINTENANCE: Maintained + Nora Dossche (2023 - 2026) +MAINTENANCE: Odd fixes STATUS: Working SINCE: 5.0 ------------------------------------------------------------------------------- EXTENSION: soap PRIMARY MAINTAINER: Dmitry Stogov (2004 - 2018) - Niels Dossche (2024 - 2025) + Nora Dossche (2024 - 2026) MAINTENANCE: Odd fixes STATUS: Working ------------------------------------------------------------------------------- EXTENSION: xml PRIMARY MAINTAINER: Thies C. Arntzen (1999 - 2002) Rob Richards (2003 - 2013) - Niels Dossche (2023 - 2025) -MAINTENANCE: Maintained + Nora Dossche (2023 - 2026) +MAINTENANCE: Odd fixes STATUS: Working ------------------------------------------------------------------------------- EXTENSION: libxml PRIMARY MAINTAINER: Rob Richards (2003 - 2009) Christian Stocker (2004 - 2011) - Niels Dossche (2023 - 2025) -MAINTENANCE: Maintained + Nora Dossche (2023 - 2026) +MAINTENANCE: Odd fixes STATUS: Working ------------------------------------------------------------------------------- EXTENSION: xmlreader PRIMARY MAINTAINER: Rob Richards (2004 - 2010) Christian Stocker (2004 - 2004) - Niels Dossche (2023 - 2025) -MAINTENANCE: Maintained + Nora Dossche (2023 - 2026) +MAINTENANCE: Odd fixes STATUS: Working ------------------------------------------------------------------------------- EXTENSION: xmlwriter PRIMARY MAINTAINER: Rob Richards (2004 - 2010) Pierre-Alain Joye (2005-2009) - Niels Dossche (2023 - 2025) -MAINTENANCE: Maintained + Nora Dossche (2023 - 2026) +MAINTENANCE: Odd fixes STATUS: Working ------------------------------------------------------------------------------- EXTENSION: xsl PRIMARY MAINTAINER: Christian Stocker (2003 - 2011) Rob Richards (2003 - 2010) - Niels Dossche (2023 - 2025) -MAINTENANCE: Maintained + Nora Dossche (2023 - 2026) +MAINTENANCE: Odd fixes STATUS: Working SINCE: 5.0 ------------------------------------------------------------------------------- @@ -486,8 +486,8 @@ PRIMARY MAINTAINER: John Coggeshall (2003 - 2006) Ilia Alshanetsky (2003 - 2009) Nuno Lopes (2006 - 2012) - Niels Dossche (2025 - 2025) -MAINTENANCE: Maintained + Nora Dossche (2025 - 2026) +MAINTENANCE: Odd fixes STATUS: Working ------------------------------------------------------------------------------- EXTENSION: tokenizer diff '--color=auto' -Naur php-8.4.18/.github/actions/brew/action.yml php-8.4.20RC1/.github/actions/brew/action.yml --- php-8.4.18/.github/actions/brew/action.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/actions/brew/action.yml 2026-04-01 04:35:35.980577746 +0000 @@ -13,11 +13,17 @@ # Some packages exist on x86 but not arm, or vice versa. # Install them with reinstall to avoid warnings. - brew reinstall autoconf webp tidy-html5 libzip libsodium icu4c - brew install \ + brew reinstall -v \ + autoconf \ + webp \ + tidy-html5 \ + libzip \ + libsodium \ + icu4c + brew install -v \ bison \ re2c - brew install \ + brew install -v \ bzip2 \ enchant \ libffi \ diff '--color=auto' -Naur php-8.4.18/.github/actions/ccache/action.yml php-8.4.20RC1/.github/actions/ccache/action.yml --- php-8.4.18/.github/actions/ccache/action.yml 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/.github/actions/ccache/action.yml 2026-04-01 04:35:35.980690659 +0000 @@ -0,0 +1,39 @@ +name: ccache +inputs: + name: + required: true + php_directory: + required: false + default: '.' + cc: + required: false + default: 'gcc' + cxx: + required: false + default: 'g++' +runs: + using: composite + steps: + - name: Get cache key + shell: bash + id: cache_key + run: | + major=$(cat ${{ inputs.php_directory }}/main/php_version.h | sed -En 's/^#define PHP_MAJOR_VERSION ([0-9]+)/\1/p') + minor=$(cat ${{ inputs.php_directory }}/main/php_version.h | sed -En 's/^#define PHP_MINOR_VERSION ([0-9]+)/\1/p') + release=$(cat ${{ inputs.php_directory }}/main/php_version.h | sed -En 's/^#define PHP_RELEASE_VERSION ([0-9]+)/\1/p') + week=$(date +"%Y-%W") + prefix="${{ inputs.name }}-$major.$minor.$release" + echo "key=$prefix-$week" >> $GITHUB_OUTPUT + echo "prefix=$prefix-" >> $GITHUB_OUTPUT + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: "${{ steps.cache_key.outputs.key }}" + append-timestamp: false + restore-keys: "${{ steps.cache_key.outputs.prefix }}" + save: ${{ github.event_name != 'pull_request' }} + - name: Export CC/CXX + shell: bash + run: | + echo "CC=ccache ${{ inputs.cc }}" >> $GITHUB_ENV + echo "CXX=ccache ${{ inputs.cxx }}" >> $GITHUB_ENV diff '--color=auto' -Naur php-8.4.18/.github/actions/freebsd/action.yml php-8.4.20RC1/.github/actions/freebsd/action.yml --- php-8.4.18/.github/actions/freebsd/action.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/actions/freebsd/action.yml 2026-04-01 04:35:35.980810085 +0000 @@ -15,6 +15,7 @@ release: '13.5' usesh: true copyback: false + disable-cache: true # Temporarily disable sqlite, as FreeBSD ships it with disabled double quotes. We'll need to fix our tests. # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=269889 prepare: | @@ -106,6 +107,7 @@ export SKIP_IO_CAPTURE_TESTS=1 export CI_NO_IPV6=1 export STACK_LIMIT_DEFAULTS_CHECK=1 + export RUN_RESOURCE_HEAVY_TESTS=1 sapi/cli/php run-tests.php \ -P -q -j2 \ -g FAIL,BORK,LEAK,XLEAK \ diff '--color=auto' -Naur php-8.4.18/.github/actions/solaris/action.yml php-8.4.20RC1/.github/actions/solaris/action.yml --- php-8.4.18/.github/actions/solaris/action.yml 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/.github/actions/solaris/action.yml 2026-04-01 04:35:35.980934700 +0000 @@ -0,0 +1,88 @@ +name: Solaris +inputs: + configurationParameters: + default: '' + required: false + runExtraTests: + default: false + required: false +runs: + using: composite + steps: + - name: Solaris + uses: vmactions/solaris-vm@v1 + with: + release: "11.4-gcc" + usesh: true + copyback: false + disable-cache: true + prepare: | + cd $GITHUB_WORKSPACE + pkg install bison developer/icu libzip oniguruma re2c + + ./buildconf -f + CC=gcc CXX=g++ \ + CFLAGS="-Wno-char-subscripts" \ + PATH=/usr/gnu/bin:/usr/bin \ + PKG_CONFIG_PATH=/usr/lib/amd64/pkgconfig \ + ./configure \ + --prefix=/usr/local \ + --enable-debug \ + --enable-werror \ + --enable-option-checking=fatal \ + --enable-fpm \ + --without-pear \ + --with-bz2 \ + --with-jpeg \ + --with-webp \ + --with-freetype \ + --enable-gd \ + --enable-exif \ + --with-zip \ + --with-zlib \ + --enable-soap \ + --enable-xmlreader \ + --with-xsl \ + --with-libxml \ + --enable-shmop \ + --enable-pcntl \ + --enable-mbstring \ + --with-curl \ + --enable-sockets \ + --with-openssl \ + --enable-bcmath \ + --enable-calendar \ + --enable-ftp \ + --enable-zend-test \ + --enable-dl-test=shared \ + --enable-intl \ + --with-mhash \ + --with-config-file-path=/etc \ + --with-config-file-scan-dir=/etc/php.d \ + ${{ inputs.configurationParameters }} + + gmake -j2 + mkdir /etc/php.d + gmake install > /dev/null + echo opcache.enable_cli=1 > /etc/php.d/opcache.ini + echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini + echo opcache.preload_user=root >> /etc/php.d/opcache.ini + run: | + cd $GITHUB_WORKSPACE + + export SKIP_IO_CAPTURE_TESTS=1 + export CI_NO_IPV6=1 + export STACK_LIMIT_DEFAULTS_CHECK=1 + PATH=/usr/gnu/bin:/usr/bin \ + sapi/cli/php run-tests.php \ + -P -q -j1 \ + -g FAIL,BORK,LEAK,XLEAK \ + --no-progress \ + --offline \ + --show-diff \ + --show-slow 1000 \ + --set-timeout 120 + + if test "${{ inputs.runExtraTests }}" = "true"; then + sapi/cli/php run-extra-tests.php + fi diff '--color=auto' -Naur php-8.4.18/.github/actions/test-alpine/action.yml php-8.4.20RC1/.github/actions/test-alpine/action.yml --- php-8.4.18/.github/actions/test-alpine/action.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/actions/test-alpine/action.yml 2026-04-01 04:35:35.981058945 +0000 @@ -3,6 +3,9 @@ runTestsParameters: default: '' required: false + enableOpcache: + default: 'false' + required: false jitType: default: 'disable' required: false @@ -15,6 +18,7 @@ export SKIP_IO_CAPTURE_TESTS=1 export STACK_LIMIT_DEFAULTS_CHECK=1 sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \ + ${{ inputs.enableOpcache == 'true' && '-d zend_extension=opcache.so -d opcache.enable_cli=1' || '' }} \ -d opcache.jit=${{ inputs.jitType }} \ -d opcache.jit_buffer_size=64M \ -j$(nproc) \ diff '--color=auto' -Naur php-8.4.18/.github/actions/test-gentoo/action.yml php-8.4.20RC1/.github/actions/test-gentoo/action.yml --- php-8.4.18/.github/actions/test-gentoo/action.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/actions/test-gentoo/action.yml 2026-04-01 04:35:35.981146921 +0000 @@ -25,6 +25,7 @@ # Slow tests criteron is doubled because this runner isn't as fast as others export SKIP_IO_CAPTURE_TESTS=1 export STACK_LIMIT_DEFAULTS_CHECK=1 + export RUN_RESOURCE_HEAVY_TESTS=1 sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \ -j$(nproc) \ -g FAIL,BORK,LEAK,XLEAK \ diff '--color=auto' -Naur php-8.4.18/.github/actions/test-libmysqlclient/action.yml php-8.4.20RC1/.github/actions/test-libmysqlclient/action.yml --- php-8.4.18/.github/actions/test-libmysqlclient/action.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/actions/test-libmysqlclient/action.yml 2026-04-01 04:35:35.981232172 +0000 @@ -9,6 +9,7 @@ export PDO_MYSQL_TEST_HOST=127.0.0.1 export PDO_MYSQL_TEST_USER=root export PDO_MYSQL_TEST_PASS=root + export RUN_RESOURCE_HEAVY_TESTS=1 sapi/cli/php run-tests.php -P -q \ -g FAIL,BORK,LEAK,XLEAK \ --no-progress --offline --show-diff --show-slow 1000 --set-timeout 120 \ diff '--color=auto' -Naur php-8.4.18/.github/actions/test-linux/action.yml php-8.4.20RC1/.github/actions/test-linux/action.yml --- php-8.4.18/.github/actions/test-linux/action.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/actions/test-linux/action.yml 2026-04-01 04:35:35.981298998 +0000 @@ -3,6 +3,9 @@ runTestsParameters: default: '' required: false + enableOpcache: + default: 'false' + required: false jitType: default: 'disable' required: false @@ -39,7 +42,9 @@ export PDO_ODBC_TEST_DSN="odbc:Driver={ODBC Driver 17 for SQL Server};Server=127.0.0.1;Database=pdo_odbc;uid=$ODBC_TEST_USER;pwd=$ODBC_TEST_PASS" export SKIP_IO_CAPTURE_TESTS=1 export STACK_LIMIT_DEFAULTS_CHECK=1 + export RUN_RESOURCE_HEAVY_TESTS=1 sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \ + ${{ inputs.enableOpcache == 'true' && '-d zend_extension=opcache.so -d opcache.enable_cli=1' || '' }} \ -d opcache.jit=${{ inputs.jitType }} \ -d opcache.protect_memory=1 \ -d opcache.jit_buffer_size=64M \ diff '--color=auto' -Naur php-8.4.18/.github/actions/test-macos/action.yml php-8.4.20RC1/.github/actions/test-macos/action.yml --- php-8.4.18/.github/actions/test-macos/action.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/actions/test-macos/action.yml 2026-04-01 04:35:35.981359793 +0000 @@ -3,6 +3,9 @@ runTestsParameters: default: '' required: false + enableOpcache: + default: 'false' + required: false jitType: default: 'disable' required: false @@ -15,7 +18,9 @@ export SKIP_IO_CAPTURE_TESTS=1 export CI_NO_IPV6=1 export STACK_LIMIT_DEFAULTS_CHECK=1 + export RUN_RESOURCE_HEAVY_TESTS=1 sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \ + ${{ inputs.enableOpcache == 'true' && '-d zend_extension=opcache.so -d opcache.enable_cli=1' || '' }} \ -d opcache.jit=${{ inputs.jitType }} \ -d opcache.protect_memory=1 \ -d opcache.jit_buffer_size=64M \ diff '--color=auto' -Naur php-8.4.18/.github/matrix.php php-8.4.20RC1/.github/matrix.php --- php-8.4.18/.github/matrix.php 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/.github/matrix.php 2026-04-01 04:35:35.981455755 +0000 @@ -0,0 +1,203 @@ + 'master', 'ref' => 'master', 'version' => [8, 6]], + ['name' => 'PHP-8.5', 'ref' => 'PHP-8.5', 'version' => [8, 5]], + ['name' => 'PHP-8.4', 'ref' => 'PHP-8.4', 'version' => [8, 4]], + ['name' => 'PHP-8.3', 'ref' => 'PHP-8.3', 'version' => [8, 3]], + ['name' => 'PHP-8.2', 'ref' => 'PHP-8.2', 'version' => [8, 2]], +]; + +function get_branch_commit_cache_file_path(): string { + return dirname(__DIR__) . '/branch-commit-cache.json'; +} + +function get_branches() { + $branch_commit_cache_file = get_branch_commit_cache_file_path(); + $branch_commit_map = []; + if (file_exists($branch_commit_cache_file)) { + $branch_commit_map = json_decode(file_get_contents($branch_commit_cache_file), JSON_THROW_ON_ERROR); + } + + $changed_branches = []; + foreach (BRANCHES as $branch) { + $previous_commit_hash = $branch_commit_map[$branch['ref']] ?? null; + $current_commit_hash = trim(shell_exec('git rev-parse origin/' . $branch['ref'])); + + if ($previous_commit_hash !== $current_commit_hash) { + $changed_branches[] = $branch; + } + + $branch_commit_map[$branch['ref']] = $current_commit_hash; + } + + file_put_contents($branch_commit_cache_file, json_encode($branch_commit_map)); + + return $changed_branches; +} + +function get_current_version(): array { + $file = dirname(__DIR__) . '/main/php_version.h'; + $content = file_get_contents($file); + preg_match('(^#define PHP_MAJOR_VERSION (?\d+)$)m', $content, $matches); + $major = (int) $matches['num']; + preg_match('(^#define PHP_MINOR_VERSION (?\d+)$)m', $content, $matches); + $minor = (int) $matches['num']; + return [$major, $minor]; +} + +function select_jobs($repository, $trigger, $nightly, $labels, $php_version, $ref, $all_variations) { + $no_jobs = in_array('CI: No jobs', $labels, true); + $all_jobs = in_array('CI: All jobs', $labels, true) || $nightly; + $test_alpine = in_array('CI: Alpine', $labels, true); + $test_benchmarking = in_array('CI: Benchmarking', $labels, true); + $test_community = in_array('CI: Community', $labels, true); + $test_coverage = in_array('CI: Coverage', $labels, true); + $test_freebsd = in_array('CI: FreeBSD', $labels, true); + $test_libmysqlclient = in_array('CI: libmysqlclient', $labels, true); + $test_linux_ppc64 = in_array('CI: Linux PPC64', $labels, true); + $test_linux_x32 = in_array('CI: Linux X32', $labels, true); + $test_linux_x64 = in_array('CI: Linux X64', $labels, true); + $test_macos = in_array('CI: macOS', $labels, true); + $test_msan = in_array('CI: MSAN', $labels, true); + $test_opcache_variation = in_array('CI: Opcache Variation', $labels, true); + $test_pecl = in_array('CI: PECL', $labels, true); + $test_solaris = in_array('CI: Solaris', $labels, true); + $test_windows = in_array('CI: Windows', $labels, true); + + $jobs = []; + if (version_compare($php_version, '8.4', '>=') && ($all_jobs || !$no_jobs || $test_alpine)) { + $jobs['ALPINE'] = true; + } + if (version_compare($php_version, '8.4', '>=') + && !$nightly + && ($all_jobs || !$no_jobs || $test_benchmarking) + // push trigger is restricted to official repository. + && ($repository === 'php/php-src' || $trigger === 'pull_request')) { + $jobs['BENCHMARKING']['config']['integrated_opcache'] = version_compare($php_version, '8.5', '>='); + } + if ($all_jobs || $test_community) { + $jobs['COMMUNITY']['matrix'] = version_compare($php_version, '8.4', '>=') + ? ['type' => ['asan', 'verify_type_inference']] + : ['type' => ['asan']]; + $jobs['COMMUNITY']['config']['symfony_version'] = match (true) { + version_compare($php_version, '8.3', '<=') => '7.4', + default => '', + }; + $jobs['COMMUNITY']['config']['laravel_version'] = match (true) { + version_compare($php_version, '8.2', '<=') => '12.x', + default => '', + }; + } + if (($all_jobs && $ref === 'master') || $test_coverage) { + $jobs['COVERAGE'] = true; + } + if ($all_jobs || $test_libmysqlclient) { + $jobs['LIBMYSQLCLIENT'] = true; + } + if (version_compare($php_version, '8.4', '>=') && ($all_jobs || $test_linux_ppc64)) { + $jobs['LINUX_PPC64'] = true; + } + if ($all_jobs || !$no_jobs || $test_linux_x64) { + $jobs['LINUX_X64']['matrix'] = $all_variations + ? [ + 'name' => [''], + 'asan' => [false], + 'debug' => [true, false], + 'repeat' => [false], + 'variation' => [false], + 'zts' => [true, false], + 'include' => [ + ['name' => '_ASAN', 'asan' => true, 'debug' => true, 'repeat' => false, 'variation' => false, 'zts' => true], + ['name' => '_REPEAT', 'asan' => false, 'debug' => true, 'repeat' => true, 'variation' => false, 'zts' => false], + ['name' => '_VARIATION', 'asan' => false, 'debug' => true, 'repeat' => false, 'variation' => true, 'zts' => true], + ], + ] + : ['include' => [ + ['name' => '', 'asan' => false, 'debug' => false, 'repeat' => false, 'variation' => false, 'zts' => false], + ['name' => '_ASAN', 'asan' => true, 'debug' => true, 'repeat' => false, 'variation' => false, 'zts' => true], + ]]; + $jobs['LINUX_X64']['config']['variation_enable_zend_max_execution_timers'] = version_compare($php_version, '8.3', '>='); + } + if ($all_jobs || !$no_jobs || $test_linux_x32) { + $jobs['LINUX_X32']['matrix'] = $all_variations + ? ['debug' => [true, false], 'zts' => [true, false]] + : ['debug' => [true], 'zts' => [true]]; + } + if ($all_jobs || !$no_jobs || $test_macos) { + $test_arm = version_compare($php_version, '8.4', '>='); + $jobs['MACOS']['matrix'] = $all_variations + ? ['arch' => $test_arm ? ['X64', 'ARM64'] : ['X64'], 'debug' => [true, false], 'zts' => [true, false]] + : ['include' => [['arch' => $test_arm ? 'ARM64' : 'X64', 'debug' => true, 'zts' => false]]]; + $jobs['MACOS']['config']['arm64_version'] = version_compare($php_version, '8.4', '>=') ? '15' : '14'; + } + if ($all_jobs || $test_msan) { + $jobs['MSAN'] = true; + } + if ($all_jobs || $test_opcache_variation) { + $jobs['OPCACHE_VARIATION'] = true; + } + if (($all_jobs && $ref === 'master') || $test_pecl) { + $jobs['PECL'] = true; + } + if (version_compare($php_version, '8.6', '>=') && ($all_jobs || $test_solaris)) { + $jobs['SOLARIS'] = true; + } + if ($all_jobs || !$no_jobs || $test_windows) { + $jobs['WINDOWS']['matrix'] = $all_variations + ? ['include' => [ + ['asan' => true, 'opcache' => true, 'x64' => true, 'zts' => true], + ['asan' => false, 'opcache' => false, 'x64' => false, 'zts' => false], + ]] + : ['include' => [['asan' => false, 'opcache' => true, 'x64' => true, 'zts' => true]]]; + $jobs['WINDOWS']['config'] = version_compare($php_version, '8.4', '>=') + ? ['vs_crt_version' => 'vs17'] + : ['vs_crt_version' => 'vs16']; + } + if ($all_jobs || !$no_jobs || $test_freebsd) { + $jobs['FREEBSD']['matrix'] = $all_variations && version_compare($php_version, '8.3', '>=') + ? ['zts' => [true, false]] + : ['zts' => [false]]; + } + return $jobs; +} + +$trigger = $argv[1] ?? 'schedule'; +$attempt = (int) ($argv[2] ?? 1); +$sunday = date('w', time()) === '0'; +$discard_cache = $sunday + || ($trigger === 'schedule' && $attempt !== 1) + || $trigger === 'workflow_dispatch'; +if ($discard_cache) { + @unlink(get_branch_commit_cache_file_path()); +} +$branch = $argv[3] ?? 'master'; +$nightly = $trigger === 'schedule' || $trigger === 'workflow_dispatch'; +$branches = $nightly && $branch === 'master' + ? get_branches() + : [['name' => 'Suite', 'ref' => $branch, 'version' => get_current_version()]]; + +$labels = json_decode($argv[4] ?? '[]', true) ?? []; +$labels = array_column($labels, 'name'); +$all_variations = $nightly || in_array('CI: All variations', $labels, true); + +$repository = $argv[5] ?? null; + +foreach ($branches as &$branch) { + $php_version = $branch['version'][0] . '.' . $branch['version'][1]; + $branch['jobs'] = select_jobs($repository, $trigger, $nightly, $labels, $php_version, $branch['ref'], $all_variations); + $branch['config']['ubuntu_version'] = version_compare($php_version, '8.5', '>=') ? '24.04' : '22.04'; +} + +echo "All variations:"; +echo json_encode($all_variations, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT); +echo "\n\nBranches:\n"; +echo json_encode($branches, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT); +echo "\n"; + +if (false !== ($github_output = getenv('GITHUB_OUTPUT'))) { + $f = fopen($github_output, 'a'); + fwrite($f, 'branches=' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n"); + fwrite($f, 'all_variations=' . json_encode($all_variations, JSON_UNESCAPED_SLASHES) . "\n"); + fclose($f); +} diff '--color=auto' -Naur php-8.4.18/.github/nightly_matrix.php php-8.4.20RC1/.github/nightly_matrix.php --- php-8.4.18/.github/nightly_matrix.php 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/nightly_matrix.php 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ - 'master', 'version' => [8, 6]], - ['ref' => 'PHP-8.5', 'version' => [8, 5]], - ['ref' => 'PHP-8.4', 'version' => [8, 4]], - ['ref' => 'PHP-8.3', 'version' => [8, 3]], - ['ref' => 'PHP-8.2', 'version' => [8, 2]], -]; - -function get_branch_commit_cache_file_path(): string { - return dirname(__DIR__) . '/branch-commit-cache.json'; -} - -function get_branches() { - $branch_commit_cache_file = get_branch_commit_cache_file_path(); - $branch_commit_map = []; - if (file_exists($branch_commit_cache_file)) { - $branch_commit_map = json_decode(file_get_contents($branch_commit_cache_file), JSON_THROW_ON_ERROR); - } - - $changed_branches = []; - foreach (BRANCHES as $branch) { - $previous_commit_hash = $branch_commit_map[$branch['ref']] ?? null; - $current_commit_hash = trim(shell_exec('git rev-parse origin/' . $branch['ref'])); - - if ($previous_commit_hash !== $current_commit_hash) { - $changed_branches[] = $branch; - } - - $branch_commit_map[$branch['ref']] = $current_commit_hash; - } - - file_put_contents($branch_commit_cache_file, json_encode($branch_commit_map)); - - return $changed_branches; -} - -function get_current_version(): array { - $file = dirname(__DIR__) . '/main/php_version.h'; - $content = file_get_contents($file); - preg_match('(^#define PHP_MAJOR_VERSION (?\d+)$)m', $content, $matches); - $major = (int) $matches['num']; - preg_match('(^#define PHP_MINOR_VERSION (?\d+)$)m', $content, $matches); - $minor = (int) $matches['num']; - return [$major, $minor]; -} - -$trigger = $argv[1] ?? 'schedule'; -$attempt = (int) ($argv[2] ?? 1); -$sunday = date('w', time()) === '0'; -$discard_cache = $sunday - || ($trigger === 'schedule' && $attempt !== 1) - || $trigger === 'workflow_dispatch'; -if ($discard_cache) { - @unlink(get_branch_commit_cache_file_path()); -} -$branch = $argv[3] ?? 'master'; -$branches = $branch === 'master' - ? get_branches() - : [['ref' => $branch, 'version' => get_current_version()]]; - -$f = fopen(getenv('GITHUB_OUTPUT'), 'a'); -fwrite($f, 'branches=' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n"); -fclose($f); diff '--color=auto' -Naur php-8.4.18/.github/workflows/nightly-results.yml php-8.4.20RC1/.github/workflows/nightly-results.yml --- php-8.4.18/.github/workflows/nightly-results.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/workflows/nightly-results.yml 2026-04-01 04:35:35.981645723 +0000 @@ -2,13 +2,13 @@ on: workflow_run: workflows: - - Nightly + - Test types: - completed jobs: on-failure: runs-on: ubuntu-latest - if: ${{ github.repository == 'php/php-src' && github.event.workflow_run.conclusion == 'failure' }} + if: ${{ github.repository == 'php/php-src' && github.event.workflow_run.event == 'schedule' && github.event.workflow_run.conclusion == 'failure' }} steps: - run: | export DEBIAN_FRONTEND=noninteractive diff '--color=auto' -Naur php-8.4.18/.github/workflows/nightly.yml php-8.4.20RC1/.github/workflows/nightly.yml --- php-8.4.18/.github/workflows/nightly.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/workflows/nightly.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,1042 +0,0 @@ -name: Test suite -on: - workflow_call: - inputs: - asan_ubuntu_version: - required: true - type: string - branch: - required: true - type: string - community_verify_type_inference: - required: true - type: boolean - run_alpine: - required: true - type: boolean - run_linux_ppc64: - required: true - type: boolean - run_macos_arm64: - required: true - type: boolean - run_freebsd_zts: - required: true - type: boolean - ubuntu_version: - required: true - type: string - windows_version: - required: true - type: string - vs_crt_version: - required: true - type: string - skip_laravel: - required: true - type: boolean - symfony_version: - required: true - type: string - skip_wordpress: - required: true - type: boolean - variation_enable_zend_max_execution_timers: - required: true - type: boolean -permissions: - contents: read -jobs: - LINUX_PPC64: - if: inputs.run_linux_ppc64 - name: LINUX_PPC64_ASAN_UBSAN_DEBUG_ZTS - # This runs on a self-hosted runner; see https://wiki.php.net/systems/ci - runs-on: [self-hosted, gentoo, ppc64] - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: System info - run: | - echo "::group::Show host CPU info" - lscpu - echo "::endgroup::" - echo "::group::Show installed packages" - cat /var/lib/portage/world - echo "::endgroup::" - - name: ./configure - uses: ./.github/actions/configure-gentoo - with: - configurationParameters: >- - CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" - LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" - CC=clang-17 - CXX=clang++-17 - --enable-debug - --enable-zts - skipSlow: false # FIXME: This should likely include slow extensions - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - # Skip an install action for now - - name: Tests - uses: ./.github/actions/test-gentoo - # There is no PPC JIT, so rip this out - with: - runTestsParameters: >- - --asan -x - - name: Extra tests - uses: ./.github/actions/extra-tests - ALPINE: - if: inputs.run_alpine - name: ALPINE_X64_ASAN_UBSAN_DEBUG_ZTS - runs-on: ubuntu-24.04 - container: - image: 'alpine:3.22' - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: apk - uses: ./.github/actions/apk - - name: System info - run: | - echo "::group::Show host CPU info" - lscpu - echo "::endgroup::" - echo "::group::Show installed package versions" - apk list - echo "::endgroup::" - - name: ./configure - uses: ./.github/actions/configure-alpine - with: - configurationParameters: >- - CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" - LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" - CC=clang-20 - CXX=clang++-20 - --enable-debug - --enable-zts - skipSlow: true # FIXME: This should likely include slow extensions - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-alpine - - name: Test Tracing JIT - uses: ./.github/actions/test-alpine - with: - jitType: tracing - runTestsParameters: >- - --asan -x - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Extra tests - uses: ./.github/actions/extra-tests - LINUX_X64: - services: - mysql: - image: mysql:8.3 - ports: - - 3306:3306 - env: - MYSQL_DATABASE: test - MYSQL_ROOT_PASSWORD: root - postgres: - image: postgres - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: test - firebird: - image: jacobalberty/firebird - ports: - - 3050:3050 - env: - ISC_PASSWORD: test - FIREBIRD_DATABASE: test.fdb - FIREBIRD_USER: test - FIREBIRD_PASSWORD: test - strategy: - fail-fast: false - matrix: - configuration_parameters: [''] - debug: [true, false] - name: [''] - run_tests_parameters: [''] - test_function_jit: [true] - zts: [true, false] - include: - - name: _ASAN_UBSAN - debug: true - zts: true - configuration_parameters: >- - CFLAGS="-fsanitize=undefined,address -DZEND_TRACK_ARENA_ALLOC" - LDFLAGS="-fsanitize=undefined,address" - run_tests_parameters: '--asan' - test_function_jit: false - asan: true - - name: _REPEAT - debug: true - zts: false - run_tests_parameters: --repeat 2 - timeout_minutes: 360 - test_function_jit: true - asan: false - - name: _VARIATION - debug: true - zts: true - configuration_parameters: >- - CFLAGS="-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1 -DZEND_VERIFY_TYPE_INFERENCE" - ${{ inputs.variation_enable_zend_max_execution_timers && '--enable-zend-max-execution-timers' || '' }} - run_tests_parameters: -d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0 - timeout_minutes: 360 - test_function_jit: true - asan: false - name: "LINUX_X64${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: ubuntu-${{ matrix.asan && inputs.asan_ubuntu_version || inputs.ubuntu_version }} - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: Create MSSQL container - uses: ./.github/actions/setup-mssql - - name: apt - uses: ./.github/actions/apt-x64 - with: - asan: ${{ matrix.asan && 'true' || 'false' }} - - name: System info - run: | - echo "::group::Show host CPU info" - lscpu - echo "::endgroup::" - echo "::group::Show installed package versions" - dpkg -l - echo "::endgroup::" - - name: ./configure - uses: ./.github/actions/configure-x64 - with: - configurationParameters: >- - ${{ matrix.configuration_parameters }} - --${{ matrix.debug && 'enable' || 'disable' }}-debug - --${{ matrix.zts && 'enable' || 'disable' }}-zts - asan: ${{ matrix.asan && 'true' || 'false' }} - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-linux - - name: Setup - uses: ./.github/actions/setup-x64 - - name: Test - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - idleCpu: ${{ matrix.asan && 'true' || 'false' }} - - name: Test Tracing JIT - uses: ./.github/actions/test-linux - with: - jitType: tracing - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Test OpCache - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Test Function JIT - # ASAN frequently timeouts. Each test run takes ~90 minutes, we can - # avoid running into the 6 hour timeout by skipping the function JIT. - if: matrix.test_function_jit - uses: ./.github/actions/test-linux - with: - jitType: function - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Extra tests - uses: ./.github/actions/extra-tests - - name: Verify generated files are up to date - uses: ./.github/actions/verify-generated-files - LINUX_X32: - strategy: - fail-fast: false - matrix: - debug: [true, false] - zts: [true, false] - name: "LINUX_X32_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: ubuntu-latest - container: - image: ubuntu:${{ inputs.ubuntu_version }} - env: - PDO_FIREBIRD_TEST_DSN: firebird:dbname=firebird:test.fdb - services: - mysql: - image: mysql:8.3 - ports: - - 3306:3306 - env: - MYSQL_DATABASE: test - MYSQL_ROOT_PASSWORD: root - firebird: - image: jacobalberty/firebird - ports: - - 3050:3050 - env: - ISC_PASSWORD: test - FIREBIRD_DATABASE: test.fdb - FIREBIRD_USER: test - FIREBIRD_PASSWORD: test - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: apt - uses: ./.github/actions/apt-x32 - - name: System info - run: | - echo "::group::Show host CPU info" - lscpu - echo "::endgroup::" - echo "::group::Show installed package versions" - dpkg -l - echo "::endgroup::" - - name: ./configure - uses: ./.github/actions/configure-x32 - with: - configurationParameters: >- - --${{ matrix.debug && 'enable' || 'disable' }}-debug - --${{ matrix.zts && 'enable' || 'disable' }}-zts - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-linux-x32 - - name: Test - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - - name: Test Tracing JIT - uses: ./.github/actions/test-linux - with: - jitType: tracing - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Test OpCache - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Test Function JIT - uses: ./.github/actions/test-linux - with: - jitType: function - runTestsParameters: >- - ${{ matrix.run_tests_parameters }} - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Extra tests - uses: ./.github/actions/extra-tests - MACOS: - strategy: - fail-fast: false - matrix: - debug: [true, false] - zts: [true, false] - os: ['13', '14'] - exclude: - - os: ${{ !inputs.run_macos_arm64 && '14' || '*never*' }} - name: "MACOS_${{ matrix.os == '13' && 'X64' || 'ARM64' }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: macos-${{ matrix.os }} - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: Update clang - uses: ./.github/actions/macos-update-clang - - name: brew - uses: ./.github/actions/brew - - name: ./configure - uses: ./.github/actions/configure-macos - with: - configurationParameters: >- - --${{ matrix.debug && 'enable' || 'disable' }}-debug - --${{ matrix.zts && 'enable' || 'disable' }}-zts - - name: make - run: |- - export PATH="$(brew --prefix)/opt/bison/bin:$PATH" - make -j$(sysctl -n hw.logicalcpu) >/dev/null - - name: make install - run: sudo make install - - name: Test - uses: ./.github/actions/test-macos - - name: Test Tracing JIT - if: matrix.os != '14' || !matrix.zts - uses: ./.github/actions/test-macos - with: - jitType: tracing - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Test OpCache - uses: ./.github/actions/test-macos - with: - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Test Function JIT - if: matrix.os != '14' || !matrix.zts - uses: ./.github/actions/test-macos - with: - jitType: function - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Extra tests - uses: ./.github/actions/extra-tests - - name: Verify generated files are up to date - uses: ./.github/actions/verify-generated-files - COVERAGE_DEBUG_NTS: - if: inputs.branch == 'master' - services: - mysql: - image: mysql:8.3 - ports: - - 3306:3306 - env: - MYSQL_DATABASE: test - MYSQL_ROOT_PASSWORD: root - postgres: - image: postgres - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: test - firebird: - image: jacobalberty/firebird - ports: - - 3050:3050 - env: - ISC_PASSWORD: test - FIREBIRD_DATABASE: test.fdb - FIREBIRD_USER: test - FIREBIRD_PASSWORD: test - runs-on: ubuntu-24.04 - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: Create MSSQL container - uses: ./.github/actions/setup-mssql - - name: apt - uses: ./.github/actions/apt-x64 - - name: Install gcovr - run: sudo -H pip install gcovr - - name: ./configure - uses: ./.github/actions/configure-x64 - with: - configurationParameters: --enable-debug --disable-zts --enable-gcov - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-linux - - name: Setup - uses: ./.github/actions/setup-x64 - # We only test with OpCache, the difference in coverage is negligible - - name: Test OpCache - uses: ./.github/actions/test-linux - with: - jitType: tracing - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - uses: codecov/codecov-action@v4 - if: ${{ !cancelled() }} - with: - fail_ci_if_error: true - token: ${{ secrets.CODECOV_TOKEN }} - verbose: true - COMMUNITY: - strategy: - fail-fast: false - matrix: - type: ['asan', 'verify_type_inference'] - exclude: - - type: ${{ !inputs.community_verify_type_inference && 'verify_type_inference' || '*never*' }} - name: "COMMUNITY_${{ matrix.type }}" - runs-on: ubuntu-${{ inputs.ubuntu_version }} - env: - ASAN_OPTIONS: exitcode=139 - UBSAN_OPTIONS: print_stacktrace=1 - USE_ZEND_ALLOC: 0 - USE_TRACKED_ALLOC: 1 - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: apt - uses: ./.github/actions/apt-x64 - - name: ./configure - uses: ./.github/actions/configure-x64 - with: - # CFLAGS removes O2, so we have to add it again... - configurationParameters: >- - --enable-zts - ${{ matrix.type == 'asan' && '--enable-debug CFLAGS="-fsanitize=undefined,address -fno-sanitize-recover -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address"' || '' }} - ${{ matrix.type == 'verify_type_inference' && 'CFLAGS="-DZEND_VERIFY_TYPE_INFERENCE -O2"' || '' }} - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-linux - - name: Setup - run: | - sudo service mysql start - mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test" - mysql -uroot -proot -e "SET GLOBAL local_infile = true" - - name: Enable Opcache - run: | - echo memory_limit=-1 >> /etc/php.d/opcache.ini - echo zend_extension=opcache.so > /etc/php.d/opcache.ini - echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini - echo opcache.enable=1 >> /etc/php.d/opcache.ini - echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini - echo opcache.memory_consumption=256M >> /etc/php.d/opcache.ini - echo opcache.file_update_protection=0 >> /etc/php.d/opcache.ini - echo opcache.interned_strings_buffer=64 >> /etc/php.d/opcache.ini - echo opcache.max_accelerated_files=100000 >> /etc/php.d/opcache.ini - - name: Enable JIT - if: matrix.type != 'verify_type_inference' - run: | - echo opcache.jit=tracing >> /etc/php.d/opcache.ini - echo opcache.jit_buffer_size=1G >> /etc/php.d/opcache.ini - echo opcache.jit_max_root_traces=100000 >> /etc/php.d/opcache.ini - echo opcache.jit_max_side_traces=100000 >> /etc/php.d/opcache.ini - echo opcache.jit_max_exit_counters=100000 >> /etc/php.d/opcache.ini - echo opcache.jit_hot_loop=1 >> /etc/php.d/opcache.ini - echo opcache.jit_hot_func=1 >> /etc/php.d/opcache.ini - echo opcache.jit_hot_return=1 >> /etc/php.d/opcache.ini - echo opcache.jit_hot_side_exit=1 >> /etc/php.d/opcache.ini - php -v - - name: Test AMPHP - if: ${{ !cancelled() }} - run: | - repositories="amp cache dns file http parallel parser pipeline process serialization socket sync websocket-client websocket-server" - X=0 - for repository in $repositories; do - echo "::group::$repository" - git clone "https://github.com/amphp/$repository.git" "amphp-$repository" --depth 1 - cd "amphp-$repository" - git rev-parse HEAD - php /usr/bin/composer install --no-progress --ignore-platform-req=php+ - EXIT_CODE=0 - vendor/bin/phpunit || EXIT_CODE=$? - echo -e "\n::endgroup::" - if [ ${EXIT_CODE:-0} -gt 128 ]; then - X=1; - echo "Failed" - fi - cd .. - done - exit $X - - name: Test Laravel - if: ${{ !cancelled() && !inputs.skip_laravel }} - run: | - git clone https://github.com/laravel/framework.git --depth=1 - cd framework - git rev-parse HEAD - php /usr/bin/composer install --no-progress --ignore-platform-req=php+ - # Hack to disable a test that hangs - php -r '$c = file_get_contents("tests/Filesystem/FilesystemTest.php"); $c = str_replace("public function testSharedGet()", "#[\\PHPUnit\\Framework\\Attributes\\Group('"'"'skip'"'"')]\n public function testSharedGet()", $c); file_put_contents("tests/Filesystem/FilesystemTest.php", $c);' - php vendor/bin/phpunit --exclude-group skip || EXIT_CODE=$? - if [ ${EXIT_CODE:-0} -gt 128 ]; then - exit 1 - fi - - name: Test ReactPHP - if: ${{ !cancelled() }} - run: | - repositories="async cache child-process datagram dns event-loop promise promise-stream promise-timer stream" - X=0 - for repository in $repositories; do - echo "::group::$repository" - git clone "https://github.com/reactphp/$repository.git" "reactphp-$repository" --depth 1 - cd "reactphp-$repository" - git rev-parse HEAD - php /usr/bin/composer install --no-progress --ignore-platform-req=php+ - EXIT_CODE=0 - vendor/bin/phpunit || EXIT_CODE=$? - echo -e "\n::endgroup::" - if [ $[EXIT_CODE:-0} -gt 128 ]; then - X=1; - echo "Failed" - fi - cd .. - done - exit $X - - name: Test Revolt PHP - if: ${{ !cancelled() }} - run: | - git clone https://github.com/revoltphp/event-loop.git --depth=1 - cd event-loop - git rev-parse HEAD - php /usr/bin/composer install --no-progress --ignore-platform-req=php+ - vendor/bin/phpunit || EXIT_CODE=$? - if [ ${EXIT_CODE:-0} -gt 128 ]; then - exit 1 - fi - - name: Test Symfony - if: ${{ !cancelled() && inputs.symfony_version != '' }} - run: | - git clone https://github.com/symfony/symfony.git --depth=1 --branch="${{ inputs.symfony_version }}" - cd symfony - git rev-parse HEAD - php /usr/bin/composer install --no-progress --ignore-platform-req=php+ - php ./phpunit install - # Test causes a heap-buffer-overflow but I cannot reproduce it locally... - php -r '$c = file_get_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php"); $c = str_replace("public function testSanitizeDeepNestedString()", "#[\\PHPUnit\\Framework\\Attributes\\Group('"'"'skip'"'"')]\n public function testSanitizeDeepNestedString()", $c); file_put_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php", $c);' - # Buggy FFI test in Symfony, see https://github.com/symfony/symfony/issues/47668 - php -r '$c = file_get_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php"); $c = str_replace("public function testCastNonTrailingCharPointer()", "#[\\PHPUnit\\Framework\\Attributes\\Group('"'"'skip'"'"')]\n public function testCastNonTrailingCharPointer()", $c); file_put_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php", $c);' - export SYMFONY_DEPRECATIONS_HELPER=max[total]=999 - X=0 - for component in $(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n'); do - echo "::group::$component" - EXIT_CODE=0 - php ./phpunit $component --exclude-group tty --exclude-group benchmark --exclude-group intl-data --exclude-group transient --exclude-group skip || EXIT_CODE=$? - echo -e "\n::endgroup::" - if [ ${EXIT_CODE:-0} -gt 128 ]; then - X=1; - echo "Failed" - fi - done - exit $X - - name: Test PHPUnit - if: ${{ !cancelled() }} - run: | - git clone https://github.com/sebastianbergmann/phpunit.git --branch=main --depth=1 - cd phpunit - git rev-parse HEAD - php /usr/bin/composer install --no-progress --ignore-platform-req=php+ - php ./phpunit || EXIT_CODE=$? - if [ ${EXIT_CODE:-0} -gt 128 ]; then - exit 1 - fi - - name: 'Symfony Preloading' - # composer create-project will automatically pick the right Symfony version for us. - if: ${{ !cancelled() && inputs.symfony_version != '' }} - run: | - php /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress --ignore-platform-req=php+ - cd symfony_demo - git rev-parse HEAD - sed -i 's/PHP_SAPI/"cli-server"/g' var/cache/dev/App_KernelDevDebugContainer.preload.php - php -d opcache.preload=var/cache/dev/App_KernelDevDebugContainer.preload.php public/index.php - - name: Test Wordpress - if: ${{ !cancelled() && !inputs.skip_wordpress }} - run: | - git clone https://github.com/WordPress/wordpress-develop.git wordpress --depth=1 - cd wordpress - git rev-parse HEAD - php /usr/bin/composer install --no-progress --ignore-platform-req=php+ - cp wp-tests-config-sample.php wp-tests-config.php - sed -i 's/youremptytestdbnamehere/test/g' wp-tests-config.php - sed -i 's/yourusernamehere/root/g' wp-tests-config.php - sed -i 's/yourpasswordhere/root/g' wp-tests-config.php - php vendor/bin/phpunit || EXIT_CODE=$? - if [ $EXIT_CODE -gt 128 ]; then - exit 1 - fi - OPCACHE_VARIATION: - services: - mysql: - image: mysql:8.3 - ports: - - 3306:3306 - env: - MYSQL_DATABASE: test - MYSQL_ROOT_PASSWORD: root - postgres: - image: postgres - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: test - firebird: - image: jacobalberty/firebird - ports: - - 3050:3050 - env: - ISC_PASSWORD: test - FIREBIRD_DATABASE: test.fdb - FIREBIRD_USER: test - FIREBIRD_PASSWORD: test - name: OPCACHE_VARIATION - runs-on: ubuntu-${{ inputs.ubuntu_version }} - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: Create MSSQL container - uses: ./.github/actions/setup-mssql - - name: apt - uses: ./.github/actions/apt-x64 - - name: ./configure - uses: ./.github/actions/configure-x64 - with: - configurationParameters: >- - --enable-debug --disable-zts - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-linux - - name: Setup - uses: ./.github/actions/setup-x64 - - name: Test File Cache (prime shm) - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - --file-cache-prime - - name: Test File Cache (prime shm, use shm) - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - --file-cache-use - - name: Test File Cache (prime shm, use file) - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - --file-cache-use - -d opcache.file_cache_only=1 - - name: Test File Cache Only (prime) - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - --file-cache-prime - -d opcache.file_cache_only=1 - - name: Test File Cache Only (use) - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - --file-cache-use - -d opcache.file_cache_only=1 - - name: Verify generated files are up to date - uses: ./.github/actions/verify-generated-files - MSAN: - name: MSAN - runs-on: ubuntu-${{ inputs.ubuntu_version }} - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: apt - uses: ./.github/actions/apt-x64 - - name: ./configure - run: | - export CC=clang - export CXX=clang++ - export CFLAGS="-DZEND_TRACK_ARENA_ALLOC" - ./buildconf --force - # msan requires all used libraries to be instrumented, - # so we should avoiding linking against anything but libc here - ./configure \ - --enable-debug \ - --enable-zts \ - --enable-option-checking=fatal \ - --prefix=/usr \ - --without-sqlite3 \ - --without-pdo-sqlite \ - --without-libxml \ - --disable-dom \ - --disable-simplexml \ - --disable-xml \ - --disable-xmlreader \ - --disable-xmlwriter \ - --without-pcre-jit \ - --disable-opcache-jit \ - --enable-phpdbg \ - --enable-fpm \ - --with-pdo-mysql=mysqlnd \ - --with-mysqli=mysqlnd \ - --disable-mysqlnd-compression-support \ - --without-pear \ - --enable-exif \ - --enable-sysvsem \ - --enable-sysvshm \ - --enable-shmop \ - --enable-pcntl \ - --enable-mbstring \ - --disable-mbregex \ - --enable-sockets \ - --enable-bcmath \ - --enable-calendar \ - --enable-ftp \ - --enable-zend-test \ - --enable-werror \ - --enable-memory-sanitizer \ - --with-config-file-path=/etc \ - --with-config-file-scan-dir=/etc/php.d \ - --enable-dl-test=shared - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - run: | - sudo make install - sudo mkdir -p /etc/php.d - sudo chmod 777 /etc/php.d - echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini - echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini - - name: Setup - run: | - set -x - sudo service mysql start - mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test" - # Ensure local_infile tests can run. - mysql -uroot -proot -e "SET GLOBAL local_infile = true" - sudo locale-gen de_DE - - name: Test - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - --msan - - name: Test Opcache - uses: ./.github/actions/test-linux - with: - runTestsParameters: >- - --msan - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Verify generated files are up to date - uses: ./.github/actions/verify-generated-files - LIBMYSQLCLIENT: - name: LIBMYSQLCLIENT - runs-on: ubuntu-${{ inputs.ubuntu_version }} - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: apt - run: | - sudo apt-get update -y | true - sudo apt install bison re2c - - name: Setup - run: | - sudo service mysql start - mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test" - # Ensure local_infile tests can run. - mysql -uroot -proot -e "SET GLOBAL local_infile = true" - - name: Build mysql-8.0 - uses: ./.github/actions/build-libmysqlclient - with: - configurationParameters: '--enable-werror' - libmysql: mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz - - name: Test mysql-8.0 - uses: ./.github/actions/test-libmysqlclient - - name: Build mysql-8.4 - uses: ./.github/actions/build-libmysqlclient - with: - configurationParameters: '--enable-werror' - libmysql: mysql-8.4.0-linux-glibc2.28-x86_64.tar.xz - - name: Test mysql-8.4 - uses: ./.github/actions/test-libmysqlclient - - name: Verify generated files are up to date - uses: ./.github/actions/verify-generated-files - PECL: - if: inputs.branch == 'master' - runs-on: ubuntu-24.04 - env: - CC: ccache gcc - CXX: ccache g++ - steps: - - name: git checkout PHP - uses: actions/checkout@v6 - with: - path: php - ref: ${{ inputs.branch }} - - name: git checkout apcu - uses: actions/checkout@v6 - with: - repository: krakjoe/apcu - path: apcu - - name: git checkout imagick - uses: actions/checkout@v6 - with: - repository: Imagick/imagick - path: imagick - - name: git checkout memcached - uses: actions/checkout@v6 - with: - repository: php-memcached-dev/php-memcached - path: memcached - - name: git checkout redis - uses: actions/checkout@v6 - with: - repository: phpredis/phpredis - path: redis - - name: git checkout xdebug - if: false - uses: actions/checkout@v6 - with: - repository: xdebug/xdebug - path: xdebug - - name: git checkout yaml - uses: actions/checkout@v6 - with: - repository: php/pecl-file_formats-yaml - path: yaml - - name: apt - run: | - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - ccache \ - libmemcached-dev \ - imagemagick \ - libmagickwand-dev \ - bison \ - re2c - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: "${{github.job}}-${{hashFiles('php/main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} - - name: build PHP - run: | - cd php - ./buildconf --force - ./configure \ - --enable-option-checking=fatal \ - --prefix=/opt/php \ - --enable-cli \ - --disable-all \ - --enable-session \ - --enable-werror - make -j$(/usr/bin/nproc) - sudo make install - - name: build apcu - run: | - cd apcu - /opt/php/bin/phpize - ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config - make -j$(/usr/bin/nproc) - - name: build imagick - run: | - cd imagick - /opt/php/bin/phpize - ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config - make -j$(/usr/bin/nproc) - - name: build memcached - run: | - cd memcached - /opt/php/bin/phpize - ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config - make -j$(/usr/bin/nproc) - - name: build redis - run: | - cd redis - /opt/php/bin/phpize - ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config - make -j$(/usr/bin/nproc) - - name: build xdebug - if: false - run: | - cd xdebug - /opt/php/bin/phpize - ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config - make -j$(/usr/bin/nproc) - - name: build yaml - run: | - cd yaml - /opt/php/bin/phpize - ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config - make -j$(/usr/bin/nproc) - WINDOWS: - strategy: - fail-fast: false - matrix: - include: - - x64: true - zts: true - opcache: true - asan: false - - x64: false - zts: false - opcache: false - asan: false - - x64: true - zts: true - opcache: true - asan: true - branch: 'master' - timeout: 120 - name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || ''}}" - runs-on: windows-${{ inputs.windows_version }} - env: - PHP_BUILD_CACHE_BASE_DIR: C:\build-cache - PHP_BUILD_OBJ_DIR: C:\obj - PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk - PHP_BUILD_SDK_BRANCH: php-sdk-2.3.0 - PHP_BUILD_CRT: ${{ inputs.vs_crt_version }} - PLATFORM: ${{ matrix.x64 && 'x64' || 'x86' }} - THREAD_SAFE: "${{ matrix.zts && '1' || '0' }}" - INTRINSICS: "${{ matrix.zts && 'AVX2' || '' }}" - PARALLEL: -j2 - OPCACHE: "${{ matrix.opcache && '1' || '0' }}" - ASAN: "${{ matrix.asan && '1' || '0' }}" - steps: - - name: git config - run: git config --global core.autocrlf false && git config --global core.eol lf - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: Setup - uses: ./.github/actions/setup-windows - - name: Build - run: .github/scripts/windows/build.bat - - name: Test - run: .github/scripts/windows/test.bat - FREEBSD: - strategy: - fail-fast: false - matrix: - zts: [true, false] - exclude: - - zts: ${{ !inputs.run_freebsd_zts && true || '*never*' }} - name: "FREEBSD_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: ubuntu-latest - timeout-minutes: 50 - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch }} - - name: FreeBSD - uses: ./.github/actions/freebsd - with: - configurationParameters: >- - --${{ matrix.zts && 'enable' || 'disable' }}-zts - runExtraTests: true diff '--color=auto' -Naur php-8.4.18/.github/workflows/push.yml php-8.4.20RC1/.github/workflows/push.yml --- php-8.4.18/.github/workflows/push.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/workflows/push.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,408 +0,0 @@ -name: Push -on: - push: - paths-ignore: - - docs/** - - NEWS - - UPGRADING - - UPGRADING.INTERNALS - - '**/README.*' - - CONTRIBUTING.md - - CODING_STANDARDS.md - - .cirrus.yml - - .circleci/** - branches: - - PHP-8.1 - - PHP-8.2 - - PHP-8.3 - - PHP-8.4 - - master - pull_request: - paths-ignore: - - docs/** - - NEWS - - UPGRADING - - UPGRADING.INTERNALS - - '**/README.*' - - CONTRIBUTING.md - - CODING_STANDARDS.md - - .cirrus.yml - - .circleci/** - branches: - - '**' - workflow_dispatch: ~ -permissions: - contents: read -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.url || github.run_id }} - cancel-in-progress: true -env: - CC: ccache gcc - CXX: ccache g++ -jobs: - ALPINE: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - name: ALPINE_X64_ASAN_UBSAN_DEBUG_ZTS - runs-on: ubuntu-24.04 - container: - image: 'alpine:3.22' - steps: - - name: git checkout - uses: actions/checkout@v6 - - name: apk - uses: ./.github/actions/apk - - name: System info - run: | - echo "::group::Show host CPU info" - lscpu - echo "::endgroup::" - echo "::group::Show installed package versions" - apk list - echo "::endgroup::" - - name: ./configure - uses: ./.github/actions/configure-alpine - with: - configurationParameters: >- - CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" - LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" - CC=clang-20 - CXX=clang++-20 - --enable-debug - --enable-zts - skipSlow: true # FIXME: This should likely include slow extensions - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-alpine - - name: Test Tracing JIT - uses: ./.github/actions/test-alpine - with: - jitType: tracing - runTestsParameters: >- - --asan -x - -d opcache.enable_cli=1 - LINUX_X64: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - services: - mysql: - image: mysql:8.3 - ports: - - 3306:3306 - env: - MYSQL_DATABASE: test - MYSQL_ROOT_PASSWORD: root - postgres: - image: postgres - ports: - - 5432:5432 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: test - firebird: - image: jacobalberty/firebird - ports: - - 3050:3050 - env: - ISC_PASSWORD: test - FIREBIRD_DATABASE: test.fdb - FIREBIRD_USER: test - FIREBIRD_PASSWORD: test - strategy: - fail-fast: false - matrix: - include: - - debug: false - zts: false - asan: false - - debug: true - zts: true - asan: true - name: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || '' }}" - runs-on: ubuntu-${{ !matrix.asan && '22' || '24' }}.04 - steps: - - name: git checkout - uses: actions/checkout@v6 - - name: apt - uses: ./.github/actions/apt-x64 - - name: System info - run: | - echo "::group::Show host CPU info" - lscpu - echo "::endgroup::" - echo "::group::Show installed package versions" - dpkg -l - echo "::endgroup::" - - name: Create MSSQL container - if: ${{ !matrix.asan }} - uses: ./.github/actions/setup-mssql - - name: Setup Caddy server - uses: ./.github/actions/setup-caddy - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - # This duplicates the "job.name" expression above because - # GitHub has no way to query the job name (github.job is the - # job id, not the job name) - key: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || '' }}-${{hashFiles('main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} - - name: ./configure - uses: ./.github/actions/configure-x64 - with: - configurationParameters: >- - --${{ matrix.debug && 'enable' || 'disable' }}-debug - --${{ matrix.zts && 'enable' || 'disable' }}-zts - ${{ matrix.asan && 'CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" CC=clang CXX=clang++' || '' }} - skipSlow: ${{ matrix.asan }} - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-linux - - name: Setup - if: ${{ !matrix.asan }} - uses: ./.github/actions/setup-x64 - - name: Test - if: matrix.asan == false - uses: ./.github/actions/test-linux - - name: Test Tracing JIT - uses: ./.github/actions/test-linux - with: - jitType: tracing - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - ${{ matrix.asan && '--asan -x' || '' }} - - name: Verify generated files are up to date - if: ${{ !matrix.asan }} - uses: ./.github/actions/verify-generated-files - LINUX_X32: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - name: LINUX_X32_DEBUG_ZTS - runs-on: ubuntu-latest - container: - image: ubuntu:22.04 - env: - MYSQL_TEST_HOST: mysql - PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test - PDO_MYSQL_TEST_HOST: mysql - services: - mysql: - image: mysql:8.3 - ports: - - 3306:3306 - env: - MYSQL_DATABASE: test - MYSQL_ROOT_PASSWORD: root - steps: - - name: git checkout - uses: actions/checkout@v6 - - name: apt - uses: ./.github/actions/apt-x32 - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: "${{github.job}}-${{hashFiles('main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} - - name: ./configure - uses: ./.github/actions/configure-x32 - with: - configurationParameters: >- - --enable-debug - --enable-zts - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - uses: ./.github/actions/install-linux-x32 - - name: Test Tracing JIT - uses: ./.github/actions/test-linux - with: - jitType: tracing - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - MACOS_DEBUG_NTS: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - strategy: - fail-fast: false - matrix: - include: - - os: 14 - arch: ARM64 - name: MACOS_${{ matrix.arch }}_DEBUG_NTS - runs-on: macos-${{ matrix.os }} - steps: - - name: git checkout - uses: actions/checkout@v6 - - name: Update clang - uses: ./.github/actions/macos-update-clang - - name: brew - uses: ./.github/actions/brew - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: "${{github.job}}-${{matrix.os}}-${{hashFiles('main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} - - name: ./configure - uses: ./.github/actions/configure-macos - with: - configurationParameters: --enable-debug --disable-zts - - name: make - run: |- - export PATH="$(brew --prefix)/opt/bison/bin:$PATH" - make -j$(sysctl -n hw.logicalcpu) >/dev/null - - name: make install - run: sudo make install - - name: Test Tracing JIT - uses: ./.github/actions/test-macos - with: - jitType: tracing - runTestsParameters: >- - -d zend_extension=opcache.so - -d opcache.enable_cli=1 - - name: Verify generated files are up to date - uses: ./.github/actions/verify-generated-files - WINDOWS: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - name: WINDOWS_X64_ZTS - runs-on: windows-2022 - env: - PHP_BUILD_CACHE_BASE_DIR: C:\build-cache - PHP_BUILD_OBJ_DIR: C:\obj - PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk - PHP_BUILD_SDK_BRANCH: php-sdk-2.3.0 - PHP_BUILD_CRT: vs17 - PLATFORM: x64 - THREAD_SAFE: "1" - INTRINSICS: AVX2 - PARALLEL: -j2 - OPCACHE: "1" - steps: - - name: git config - run: git config --global core.autocrlf false && git config --global core.eol lf - - name: git checkout - uses: actions/checkout@v6 - - name: Setup - uses: ./.github/actions/setup-windows - - name: Build - run: .github/scripts/windows/build.bat - - name: Test - run: .github/scripts/windows/test.bat - BENCHMARKING: - name: BENCHMARKING - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - runs-on: ubuntu-22.04 - steps: - - name: git checkout - uses: actions/checkout@v6 - with: - fetch-depth: 0 - # ASLR can cause a lot of noise due to missed sse opportunities for memcpy - # and other operations, so we disable it during benchmarking. - - name: Disable ASLR - run: echo 0 | sudo tee /proc/sys/kernel/randomize_va_space - - name: apt - run: | - set -x - sudo apt-get update - sudo apt-get install \ - bison \ - libgmp-dev \ - libonig-dev \ - libsqlite3-dev \ - openssl \ - re2c \ - valgrind - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: "${{github.job}}-${{hashFiles('main/php_version.h')}}" - append-timestamp: false - save: ${{ github.event_name != 'pull_request' }} - - name: ./configure - run: | - set -x - ./buildconf --force - ./configure \ - --disable-debug \ - --enable-mbstring \ - --enable-opcache \ - --enable-option-checking=fatal \ - --enable-sockets \ - --enable-werror \ - --prefix=/usr \ - --with-config-file-scan-dir=/etc/php.d \ - --with-gmp \ - --with-mysqli=mysqlnd \ - --with-openssl \ - --with-pdo-sqlite \ - --with-valgrind - - name: make - run: make -j$(/usr/bin/nproc) >/dev/null - - name: make install - run: | - set -x - sudo make install - sudo mkdir -p /etc/php.d - sudo chmod 777 /etc/php.d - echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini - echo zend_extension=opcache.so >> /etc/php.d/opcache.ini - echo opcache.enable=1 >> /etc/php.d/opcache.ini - echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini - - name: Setup - run: | - git config --global user.name "Benchmark" - git config --global user.email "benchmark@php.net" - sudo service mysql start - mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS wordpress" - mysql -uroot -proot -e "CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'wordpress'; FLUSH PRIVILEGES;" - mysql -uroot -proot -e "GRANT ALL PRIVILEGES ON *.* TO 'wordpress'@'localhost' WITH GRANT OPTION;" - - name: git checkout benchmarking-data - uses: actions/checkout@v6 - with: - repository: php/benchmarking-data - ssh-key: ${{ secrets.BENCHMARKING_DATA_DEPLOY_KEY }} - path: benchmark/repos/data - - name: Benchmark - run: php benchmark/benchmark.php true - - name: Store result - if: github.event_name == 'push' - run: | - set -x - cd benchmark/repos/data - git pull --autostash - if [ -e ".git/MERGE_HEAD" ]; then - echo "Merging, can't proceed" - exit 1 - fi - git add . - if git diff --cached --quiet; then - exit 0 - fi - git commit -m "Add result for ${{ github.repository }}@${{ github.sha }}" - git push - - name: Show diff - if: github.event_name == 'pull_request' - run: |- - set -x - php benchmark/generate_diff.php \ - ${{ github.sha }} \ - $(git merge-base ${{ github.event.pull_request.base.sha }} ${{ github.sha }}) \ - > $GITHUB_STEP_SUMMARY - - uses: actions/upload-artifact@v6 - with: - name: profiles - path: ${{ github.workspace }}/benchmark/profiles - retention-days: 30 - FREEBSD: - if: github.repository == 'php/php-src' || github.event_name == 'pull_request' - name: FREEBSD - runs-on: ubuntu-latest - timeout-minutes: 50 - steps: - - name: git checkout - uses: actions/checkout@v6 - - name: FreeBSD - uses: ./.github/actions/freebsd diff '--color=auto' -Naur php-8.4.18/.github/workflows/root.yml php-8.4.20RC1/.github/workflows/root.yml --- php-8.4.18/.github/workflows/root.yml 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/.github/workflows/root.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -name: Nightly -on: - schedule: - - cron: "0 1 * * *" - workflow_dispatch: ~ -permissions: - contents: read -jobs: - GENERATE_MATRIX: - name: Generate Matrix - if: github.repository == 'php/php-src' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest - outputs: - branches: ${{ steps.set-matrix.outputs.branches }} - steps: - - uses: actions/checkout@v6 - with: - # Set fetch-depth to 0 to clone the full repository - # including all branches. This is required to find - # the correct commit hashes. - fetch-depth: 0 - - name: Grab the commit mapping - uses: actions/cache@v5 - with: - path: branch-commit-cache.json - # The cache key needs to change every time for the - # cache to be updated after this job finishes. - key: nightly-${{ github.run_id }}-${{ github.run_attempt }} - restore-keys: | - nightly- - - name: Generate Matrix - id: set-matrix - run: php .github/nightly_matrix.php "${{ github.event_name }}" "${{ github.run_attempt }}" "${{ github.head_ref || github.ref_name }}" - NIGHTLY: - needs: GENERATE_MATRIX - name: ${{ matrix.branch.ref }} - if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} - uses: ./.github/workflows/nightly.yml - strategy: - fail-fast: false - matrix: - branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }} - with: - asan_ubuntu_version: ${{ - (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 5) || matrix.branch.version[0] >= 9) && '24.04') - || '22.04' }} - branch: ${{ matrix.branch.ref }} - community_verify_type_inference: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9 }} - run_alpine: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9 }} - run_linux_ppc64: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9 }} - run_macos_arm64: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9 }} - run_freebsd_zts: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 3) || matrix.branch.version[0] >= 9 }} - ubuntu_version: ${{ - (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 5) || matrix.branch.version[0] >= 9) && '24.04') - || '22.04' }} - windows_version: '2022' - vs_crt_version: ${{ ((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) && 'vs17') || 'vs16' }} - skip_laravel: false - symfony_version: ${{ (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9) && '8.1') || '7.4' }} - skip_wordpress: false - variation_enable_zend_max_execution_timers: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 3) || matrix.branch.version[0] >= 9 }} - secrets: inherit diff '--color=auto' -Naur php-8.4.18/.github/workflows/test-suite.yml php-8.4.20RC1/.github/workflows/test-suite.yml --- php-8.4.18/.github/workflows/test-suite.yml 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/.github/workflows/test-suite.yml 2026-04-01 04:35:35.982004181 +0000 @@ -0,0 +1,1103 @@ +name: Test suite +on: + workflow_call: + inputs: + all_variations: + required: true + type: boolean + branch: + required: true + type: string +permissions: + contents: read +jobs: + LINUX_PPC64: + if: ${{ fromJson(inputs.branch).jobs.LINUX_PPC64 }} + name: LINUX_PPC64_ASAN_DEBUG_ZTS + # This runs on a self-hosted runner; see https://wiki.php.net/systems/ci + runs-on: [self-hosted, gentoo, ppc64] + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: System info + run: | + echo "::group::Show host CPU info" + lscpu + echo "::endgroup::" + echo "::group::Show installed packages" + cat /var/lib/portage/world + echo "::endgroup::" + - name: ./configure + uses: ./.github/actions/configure-gentoo + with: + configurationParameters: >- + CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" + LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" + CC=clang-17 + CXX=clang++-17 + --enable-debug + --enable-zts + skipSlow: false # FIXME: This should likely include slow extensions + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + # Skip an install action for now + - name: Tests + uses: ./.github/actions/test-gentoo + # There is no PPC JIT, so rip this out + with: + runTestsParameters: >- + --asan -x + - name: Extra tests + uses: ./.github/actions/extra-tests + ALPINE: + if: ${{ fromJson(inputs.branch).jobs.ALPINE }} + name: ALPINE_X64_ASAN_DEBUG_ZTS + runs-on: ubuntu-24.04 + container: + image: 'alpine:3.22' + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: apk + uses: ./.github/actions/apk + - name: System info + run: | + echo "::group::Show host CPU info" + lscpu + echo "::endgroup::" + echo "::group::Show installed package versions" + apk list + echo "::endgroup::" + - name: ccache + uses: ./.github/actions/ccache + with: + name: "${{ github.job }}" + cc: clang-20 + cxx: clang++-20 + - name: ./configure + uses: ./.github/actions/configure-alpine + with: + configurationParameters: >- + CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" + LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" + --enable-debug + --enable-zts + skipSlow: true # FIXME: This should likely include slow extensions + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + uses: ./.github/actions/install-alpine + - name: Test Tracing JIT + uses: ./.github/actions/test-alpine + with: + enableOpcache: true + jitType: tracing + runTestsParameters: >- + --asan -x + - name: Extra tests + uses: ./.github/actions/extra-tests + LINUX_X64: + if: ${{ fromJson(inputs.branch).jobs.LINUX_X64 }} + services: + mysql: + image: mysql:8.4 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test + firebird: + image: jacobalberty/firebird + ports: + - 3050:3050 + env: + ISC_PASSWORD: test + FIREBIRD_DATABASE: test.fdb + FIREBIRD_USER: test + FIREBIRD_PASSWORD: test + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.branch).jobs.LINUX_X64.matrix }} + name: "LINUX_X64${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: Create MSSQL container + uses: ./.github/actions/setup-mssql + - name: apt + uses: ./.github/actions/apt-x64 + with: + asan: ${{ matrix.asan && 'true' || 'false' }} + - name: System info + run: | + echo "::group::Show host CPU info" + lscpu + echo "::endgroup::" + echo "::group::Show installed package versions" + dpkg -l + echo "::endgroup::" + - name: Setup Caddy server + uses: ./.github/actions/setup-caddy + - name: ccache + uses: ./.github/actions/ccache + with: + # This duplicates the "job.name" expression above because + # GitHub has no way to query the job name (github.job is the + # job id, not the job name) + name: "LINUX_X64${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + - name: ./configure + uses: ./.github/actions/configure-x64 + with: + configurationParameters: >- + ${{ matrix.asan && 'CFLAGS="-fsanitize=undefined,address -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address"' || '' }} + ${{ matrix.variation && 'CFLAGS="-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1 -DZEND_VERIFY_TYPE_INFERENCE"' || '' }} + ${{ (matrix.variation && fromJson(inputs.branch).jobs.LINUX_X64.config.variation_enable_zend_max_execution_timers) && '--enable-zend-max-execution-timers' || '' }} + --${{ matrix.debug && 'enable' || 'disable' }}-debug + ${{ matrix.debug && 'CXXFLAGS="-D_GLIBCXX_ASSERTIONS"' || '' }} + --${{ matrix.zts && 'enable' || 'disable' }}-zts + asan: ${{ matrix.asan && 'true' || 'false' }} + skipSlow: ${{ (matrix.asan && !inputs.all_variations) && 'true' || 'false' }} + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + uses: ./.github/actions/install-linux + - name: Setup + if: ${{ !matrix.asan || inputs.all_variations }} + uses: ./.github/actions/setup-x64 + - name: Test + if: ${{ inputs.all_variations || !matrix.asan }} + uses: ./.github/actions/test-linux + with: + runTestsParameters: >- + ${{ matrix.asan && '--asan' || '' }} + ${{ matrix.repeat && '--repeat 2' || '' }} + ${{ matrix.variation && '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0' || '' }} + idleCpu: ${{ matrix.asan && 'true' || 'false' }} + - name: Test Tracing JIT + if: ${{ inputs.all_variations || matrix.asan }} + uses: ./.github/actions/test-linux + with: + enableOpcache: true + jitType: tracing + runTestsParameters: >- + ${{ matrix.asan && '--asan' || '' }} + ${{ (matrix.asan && !inputs.all_variations) && '-x' || '' }} + ${{ matrix.repeat && '--repeat 2' || '' }} + ${{ matrix.variation && '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0' || '' }} + - name: Test OpCache + if: ${{ inputs.all_variations }} + uses: ./.github/actions/test-linux + with: + enableOpcache: true + runTestsParameters: >- + ${{ matrix.asan && '--asan' || '' }} + ${{ matrix.repeat && '--repeat 2' || '' }} + ${{ matrix.variation && '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0' || '' }} + - name: Test Function JIT + # ASAN frequently timeouts. Each test run takes ~90 minutes, we can + # avoid running into the 6 hour timeout by skipping the function JIT. + if: ${{ !matrix.asan }} + uses: ./.github/actions/test-linux + with: + enableOpcache: true + jitType: function + runTestsParameters: >- + ${{ matrix.repeat && '--repeat 2' || '' }} + ${{ matrix.variation && '-d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0' || '' }} + - name: Extra tests + uses: ./.github/actions/extra-tests + - name: Verify generated files are up to date + uses: ./.github/actions/verify-generated-files + LINUX_X32: + if: ${{ fromJson(inputs.branch).jobs.LINUX_X32 }} + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.branch).jobs.LINUX_X32.matrix }} + name: "LINUX_X32_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + runs-on: ubuntu-latest + container: + image: ubuntu:${{ fromJson(inputs.branch).config.ubuntu_version }} + env: + MYSQL_TEST_HOST: mysql + PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test + PDO_MYSQL_TEST_HOST: mysql + PDO_FIREBIRD_TEST_DSN: firebird:dbname=firebird:test.fdb + services: + mysql: + image: mysql:8.4 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + firebird: + image: jacobalberty/firebird + ports: + - 3050:3050 + env: + ISC_PASSWORD: test + FIREBIRD_DATABASE: test.fdb + FIREBIRD_USER: test + FIREBIRD_PASSWORD: test + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: apt + uses: ./.github/actions/apt-x32 + - name: ccache + uses: ./.github/actions/ccache + with: + name: "LINUX_X32_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + - name: System info + run: | + echo "::group::Show host CPU info" + lscpu + echo "::endgroup::" + echo "::group::Show installed package versions" + dpkg -l + echo "::endgroup::" + - name: ./configure + uses: ./.github/actions/configure-x32 + with: + configurationParameters: >- + --${{ matrix.debug && 'enable' || 'disable' }}-debug + --${{ matrix.zts && 'enable' || 'disable' }}-zts + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + uses: ./.github/actions/install-linux-x32 + - name: Test + if: ${{ inputs.all_variations }} + uses: ./.github/actions/test-linux + - name: Test Tracing JIT + uses: ./.github/actions/test-linux + with: + enableOpcache: true + jitType: tracing + - name: Test OpCache + if: ${{ inputs.all_variations }} + uses: ./.github/actions/test-linux + with: + enableOpcache: true + - name: Test Function JIT + if: ${{ inputs.all_variations }} + uses: ./.github/actions/test-linux + with: + enableOpcache: true + jitType: function + - name: Extra tests + uses: ./.github/actions/extra-tests + MACOS: + if: ${{ fromJson(inputs.branch).jobs.MACOS }} + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.branch).jobs.MACOS.matrix }} + name: "MACOS_${{ matrix.arch }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + runs-on: macos-${{ matrix.arch == 'X64' && '15-intel' || fromJson(inputs.branch).jobs.MACOS.config.arm64_version }} + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: Update clang + timeout-minutes: 10 + uses: ./.github/actions/macos-update-clang + - name: brew + timeout-minutes: 10 + uses: ./.github/actions/brew + - name: ccache + uses: ./.github/actions/ccache + with: + name: "MACOS_${{ matrix.arch }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + - name: ./configure + uses: ./.github/actions/configure-macos + with: + configurationParameters: >- + --${{ matrix.debug && 'enable' || 'disable' }}-debug + --${{ matrix.zts && 'enable' || 'disable' }}-zts + - name: make + run: |- + export PATH="$(brew --prefix)/opt/bison/bin:$PATH" + make -j$(sysctl -n hw.logicalcpu) >/dev/null + - name: make install + run: sudo make install + - name: Test + if: ${{ inputs.all_variations }} + uses: ./.github/actions/test-macos + - name: Test Tracing JIT + if: ${{ matrix.arch == 'X64' || !matrix.zts }} + uses: ./.github/actions/test-macos + with: + enableOpcache: true + jitType: tracing + - name: Test OpCache + if: ${{ inputs.all_variations || (matrix.arch == 'ARM64' && matrix.zts) }} + uses: ./.github/actions/test-macos + with: + enableOpcache: true + - name: Test Function JIT + if: ${{ inputs.all_variations && (matrix.arch == 'X64' || !matrix.zts) }} + uses: ./.github/actions/test-macos + with: + enableOpcache: true + jitType: function + - name: Extra tests + uses: ./.github/actions/extra-tests + - name: Verify generated files are up to date + uses: ./.github/actions/verify-generated-files + COVERAGE: + if: ${{ fromJson(inputs.branch).jobs.COVERAGE }} + services: + mysql: + image: mysql:8.4 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test + firebird: + image: jacobalberty/firebird + ports: + - 3050:3050 + env: + ISC_PASSWORD: test + FIREBIRD_DATABASE: test.fdb + FIREBIRD_USER: test + FIREBIRD_PASSWORD: test + runs-on: ubuntu-24.04 + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: Create MSSQL container + uses: ./.github/actions/setup-mssql + - name: apt + uses: ./.github/actions/apt-x64 + - name: Install gcovr + run: sudo -H pip install gcovr + - name: ./configure + uses: ./.github/actions/configure-x64 + with: + configurationParameters: --enable-debug --disable-zts --enable-gcov + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + uses: ./.github/actions/install-linux + - name: Setup + uses: ./.github/actions/setup-x64 + # We only test with OpCache, the difference in coverage is negligible + - name: Test OpCache + uses: ./.github/actions/test-linux + with: + enableOpcache: true + jitType: tracing + - uses: codecov/codecov-action@v5 + if: ${{ !cancelled() }} + with: + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + COMMUNITY: + if: ${{ fromJson(inputs.branch).jobs.COMMUNITY }} + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.branch).jobs.COMMUNITY.matrix }} + name: "COMMUNITY_${{ matrix.type }}" + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} + env: + ASAN_OPTIONS: exitcode=139 + UBSAN_OPTIONS: print_stacktrace=1 + USE_ZEND_ALLOC: 0 + USE_TRACKED_ALLOC: 1 + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: apt + uses: ./.github/actions/apt-x64 + - name: ccache + uses: ./.github/actions/ccache + with: + name: "COMMUNITY_${{ matrix.type }}" + - name: ./configure + uses: ./.github/actions/configure-x64 + with: + # CFLAGS removes O2, so we have to add it again... + configurationParameters: >- + --enable-zts + ${{ matrix.type == 'asan' && '--enable-debug CFLAGS="-fsanitize=undefined,address -fno-sanitize-recover -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address"' || '' }} + ${{ matrix.type == 'verify_type_inference' && 'CFLAGS="-DZEND_VERIFY_TYPE_INFERENCE -O2"' || '' }} + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + uses: ./.github/actions/install-linux + - name: Setup + run: | + sudo service mysql start + mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test" + mysql -uroot -proot -e "SET GLOBAL local_infile = true" + - name: Enable Opcache + run: | + echo memory_limit=-1 >> /etc/php.d/opcache.ini + echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini + echo opcache.enable=1 >> /etc/php.d/opcache.ini + echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini + echo opcache.memory_consumption=256M >> /etc/php.d/opcache.ini + echo opcache.file_update_protection=0 >> /etc/php.d/opcache.ini + echo opcache.interned_strings_buffer=64 >> /etc/php.d/opcache.ini + echo opcache.max_accelerated_files=100000 >> /etc/php.d/opcache.ini + - name: Enable JIT + if: ${{ matrix.type != 'verify_type_inference' }} + run: | + echo opcache.jit=tracing >> /etc/php.d/opcache.ini + echo opcache.jit_buffer_size=1G >> /etc/php.d/opcache.ini + echo opcache.jit_max_root_traces=100000 >> /etc/php.d/opcache.ini + echo opcache.jit_max_side_traces=100000 >> /etc/php.d/opcache.ini + echo opcache.jit_max_exit_counters=100000 >> /etc/php.d/opcache.ini + echo opcache.jit_hot_loop=1 >> /etc/php.d/opcache.ini + echo opcache.jit_hot_func=1 >> /etc/php.d/opcache.ini + echo opcache.jit_hot_return=1 >> /etc/php.d/opcache.ini + echo opcache.jit_hot_side_exit=1 >> /etc/php.d/opcache.ini + php -v + - name: Test AMPHP + if: ${{ !cancelled() }} + run: | + repositories="amp cache dns file http parallel parser pipeline process serialization socket sync websocket-client websocket-server" + X=0 + for repository in $repositories; do + echo "::group::$repository" + git clone "https://github.com/amphp/$repository.git" "amphp-$repository" --depth 1 + cd "amphp-$repository" + git rev-parse HEAD + php /usr/bin/composer install --no-progress --ignore-platform-req=php+ + EXIT_CODE=0 + vendor/bin/phpunit || EXIT_CODE=$? + echo -e "\n::endgroup::" + if [ ${EXIT_CODE:-0} -gt 128 ]; then + X=1; + echo "Failed" + fi + cd .. + done + exit $X + - name: Test Laravel + if: ${{ !cancelled() }} + run: | + branch=${{ fromJson(inputs.branch).jobs.COMMUNITY.config.laravel_version }} + git clone https://github.com/laravel/framework.git --depth=1 ${branch:+--branch="$branch"} + cd framework + git rev-parse HEAD + php /usr/bin/composer install --no-progress --ignore-platform-req=php+ + # Hack to disable a test that hangs + php -r '$c = file_get_contents("tests/Filesystem/FilesystemTest.php"); $c = str_replace("public function testSharedGet()", "#[\\PHPUnit\\Framework\\Attributes\\Group('"'"'skip'"'"')]\n public function testSharedGet()", $c); file_put_contents("tests/Filesystem/FilesystemTest.php", $c);' + php vendor/bin/phpunit --exclude-group skip || EXIT_CODE=$? + if [ ${EXIT_CODE:-0} -gt 128 ]; then + exit 1 + fi + - name: Test ReactPHP + if: ${{ !cancelled() }} + run: | + repositories="async cache child-process datagram dns event-loop promise promise-stream promise-timer stream" + X=0 + for repository in $repositories; do + echo "::group::$repository" + git clone "https://github.com/reactphp/$repository.git" "reactphp-$repository" --depth 1 + cd "reactphp-$repository" + git rev-parse HEAD + php /usr/bin/composer install --no-progress --ignore-platform-req=php+ + EXIT_CODE=0 + vendor/bin/phpunit || EXIT_CODE=$? + echo -e "\n::endgroup::" + if [ $[EXIT_CODE:-0} -gt 128 ]; then + X=1; + echo "Failed" + fi + cd .. + done + exit $X + - name: Test Revolt PHP + if: ${{ !cancelled() }} + run: | + git clone https://github.com/revoltphp/event-loop.git --depth=1 + cd event-loop + git rev-parse HEAD + php /usr/bin/composer install --no-progress --ignore-platform-req=php+ + vendor/bin/phpunit || EXIT_CODE=$? + if [ ${EXIT_CODE:-0} -gt 128 ]; then + exit 1 + fi + - name: Test Symfony + if: ${{ !cancelled() }} + run: | + branch=${{ fromJson(inputs.branch).jobs.COMMUNITY.config.symfony_version }} + git clone https://github.com/symfony/symfony.git --depth=1 ${branch:+--branch="$branch"} + cd symfony + git rev-parse HEAD + php /usr/bin/composer install --no-progress --ignore-platform-req=php+ + php ./phpunit install + # Test causes a heap-buffer-overflow but I cannot reproduce it locally... + php -r '$c = file_get_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php"); $c = str_replace("public function testSanitizeDeepNestedString()", "#[\\PHPUnit\\Framework\\Attributes\\Group('"'"'skip'"'"')]\n public function testSanitizeDeepNestedString()", $c); file_put_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php", $c);' + # Buggy FFI test in Symfony, see https://github.com/symfony/symfony/issues/47668 + php -r '$c = file_get_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php"); $c = str_replace("public function testCastNonTrailingCharPointer()", "#[\\PHPUnit\\Framework\\Attributes\\Group('"'"'skip'"'"')]\n public function testCastNonTrailingCharPointer()", $c); file_put_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php", $c);' + export SYMFONY_DEPRECATIONS_HELPER=max[total]=999 + X=0 + for component in $(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n'); do + echo "::group::$component" + EXIT_CODE=0 + php ./phpunit $component --exclude-group tty --exclude-group benchmark --exclude-group intl-data --exclude-group transient --exclude-group skip || EXIT_CODE=$? + echo -e "\n::endgroup::" + if [ ${EXIT_CODE:-0} -gt 128 ]; then + X=1; + echo "Failed" + fi + done + exit $X + - name: Test PHPUnit + if: ${{ !cancelled() }} + run: | + git clone https://github.com/sebastianbergmann/phpunit.git --branch=main --depth=1 + cd phpunit + git rev-parse HEAD + php /usr/bin/composer install --no-progress --ignore-platform-req=php+ + php ./phpunit || EXIT_CODE=$? + if [ ${EXIT_CODE:-0} -gt 128 ]; then + exit 1 + fi + - name: 'Symfony Preloading' + # composer create-project will automatically pick the right Symfony version for us. + if: ${{ !cancelled() }} + run: | + php /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress --ignore-platform-req=php+ + cd symfony_demo + git rev-parse HEAD + sed -i 's/PHP_SAPI/"cli-server"/g' var/cache/dev/App_KernelDevDebugContainer.preload.php + php -d opcache.preload=var/cache/dev/App_KernelDevDebugContainer.preload.php public/index.php + - name: Test Wordpress + if: ${{ !cancelled() }} + run: | + git clone https://github.com/WordPress/wordpress-develop.git wordpress --depth=1 + cd wordpress + git rev-parse HEAD + php /usr/bin/composer install --no-progress --ignore-platform-req=php+ + cp wp-tests-config-sample.php wp-tests-config.php + sed -i 's/youremptytestdbnamehere/test/g' wp-tests-config.php + sed -i 's/yourusernamehere/root/g' wp-tests-config.php + sed -i 's/yourpasswordhere/root/g' wp-tests-config.php + php vendor/bin/phpunit || EXIT_CODE=$? + if [ $EXIT_CODE -gt 128 ]; then + exit 1 + fi + OPCACHE_VARIATION: + if: ${{ fromJson(inputs.branch).jobs.OPCACHE_VARIATION }} + services: + mysql: + image: mysql:8.4 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test + firebird: + image: jacobalberty/firebird + ports: + - 3050:3050 + env: + ISC_PASSWORD: test + FIREBIRD_DATABASE: test.fdb + FIREBIRD_USER: test + FIREBIRD_PASSWORD: test + name: OPCACHE_VARIATION + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: Create MSSQL container + uses: ./.github/actions/setup-mssql + - name: apt + uses: ./.github/actions/apt-x64 + - name: ccache + uses: ./.github/actions/ccache + with: + name: "${{ github.job }}" + - name: ./configure + uses: ./.github/actions/configure-x64 + with: + configurationParameters: >- + --enable-debug --disable-zts + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + uses: ./.github/actions/install-linux + - name: Setup + uses: ./.github/actions/setup-x64 + - name: Test File Cache (prime shm) + uses: ./.github/actions/test-linux + with: + enableOpcache: true + runTestsParameters: >- + --file-cache-prime + - name: Test File Cache (prime shm, use shm) + uses: ./.github/actions/test-linux + with: + enableOpcache: true + runTestsParameters: >- + --file-cache-use + - name: Test File Cache (prime shm, use file) + uses: ./.github/actions/test-linux + with: + enableOpcache: true + runTestsParameters: >- + --file-cache-use + -d opcache.file_cache_only=1 + - name: Test File Cache Only (prime) + uses: ./.github/actions/test-linux + with: + enableOpcache: true + runTestsParameters: >- + --file-cache-prime + -d opcache.file_cache_only=1 + - name: Test File Cache Only (use) + uses: ./.github/actions/test-linux + with: + enableOpcache: true + runTestsParameters: >- + --file-cache-use + -d opcache.file_cache_only=1 + - name: Verify generated files are up to date + uses: ./.github/actions/verify-generated-files + MSAN: + if: ${{ fromJson(inputs.branch).jobs.MSAN }} + name: MSAN + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: apt + uses: ./.github/actions/apt-x64 + - name: ccache + uses: ./.github/actions/ccache + with: + name: "${{ github.job }}" + cc: clang + cxx: clang++ + - name: ./configure + run: | + export CFLAGS="-DZEND_TRACK_ARENA_ALLOC" + ./buildconf --force + # msan requires all used libraries to be instrumented, + # so we should avoiding linking against anything but libc here + ./configure \ + --enable-debug \ + --enable-zts \ + --enable-option-checking=fatal \ + --prefix=/usr \ + --without-sqlite3 \ + --without-pdo-sqlite \ + --without-libxml \ + --disable-dom \ + --disable-simplexml \ + --disable-xml \ + --disable-xmlreader \ + --disable-xmlwriter \ + --without-pcre-jit \ + --disable-opcache-jit \ + --enable-phpdbg \ + --enable-fpm \ + --with-pdo-mysql=mysqlnd \ + --with-mysqli=mysqlnd \ + --disable-mysqlnd-compression-support \ + --without-pear \ + --enable-exif \ + --enable-sysvsem \ + --enable-sysvshm \ + --enable-shmop \ + --enable-pcntl \ + --enable-mbstring \ + --disable-mbregex \ + --enable-sockets \ + --enable-bcmath \ + --enable-calendar \ + --enable-ftp \ + --enable-zend-test \ + --enable-werror \ + --enable-memory-sanitizer \ + --with-config-file-path=/etc \ + --with-config-file-scan-dir=/etc/php.d \ + --enable-dl-test=shared + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + run: | + sudo make install + sudo mkdir -p /etc/php.d + sudo chmod 777 /etc/php.d + echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini + echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini + - name: Setup + run: | + set -x + sudo service mysql start + mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test" + # Ensure local_infile tests can run. + mysql -uroot -proot -e "SET GLOBAL local_infile = true" + sudo locale-gen de_DE + - name: Test + uses: ./.github/actions/test-linux + with: + runTestsParameters: >- + --msan + - name: Test Opcache + uses: ./.github/actions/test-linux + with: + enableOpcache: true + runTestsParameters: >- + --msan + - name: Verify generated files are up to date + uses: ./.github/actions/verify-generated-files + LIBMYSQLCLIENT: + if: ${{ fromJson(inputs.branch).jobs.LIBMYSQLCLIENT }} + name: LIBMYSQLCLIENT + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: apt + run: | + sudo apt-get update -y | true + sudo apt install bison re2c + - name: Setup + run: | + sudo service mysql start + mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test" + # Ensure local_infile tests can run. + mysql -uroot -proot -e "SET GLOBAL local_infile = true" + - name: Build mysql-8.0 + uses: ./.github/actions/build-libmysqlclient + with: + configurationParameters: '--enable-werror' + libmysql: mysql-8.0.37-linux-glibc2.28-x86_64.tar.xz + - name: Test mysql-8.0 + uses: ./.github/actions/test-libmysqlclient + - name: Build mysql-8.4 + uses: ./.github/actions/build-libmysqlclient + with: + configurationParameters: '--enable-werror' + libmysql: mysql-8.4.0-linux-glibc2.28-x86_64.tar.xz + - name: Test mysql-8.4 + uses: ./.github/actions/test-libmysqlclient + - name: Verify generated files are up to date + uses: ./.github/actions/verify-generated-files + PECL: + if: ${{ fromJson(inputs.branch).jobs.PECL }} + runs-on: ubuntu-24.04 + steps: + - name: git checkout PHP + uses: actions/checkout@v6 + with: + path: php + ref: ${{ fromJson(inputs.branch).ref }} + # Used for ccache action + - name: Move .github + run: mv php/.github . + - name: git checkout apcu + uses: actions/checkout@v6 + with: + repository: krakjoe/apcu + path: apcu + - name: git checkout imagick + uses: actions/checkout@v6 + with: + repository: Imagick/imagick + path: imagick + - name: git checkout memcached + uses: actions/checkout@v6 + with: + repository: php-memcached-dev/php-memcached + path: memcached + - name: git checkout redis + if: ${{ false }} + uses: actions/checkout@v6 + with: + repository: phpredis/phpredis + path: redis + - name: git checkout xdebug + uses: actions/checkout@v6 + with: + repository: xdebug/xdebug + path: xdebug + - name: git checkout yaml + uses: actions/checkout@v6 + with: + repository: php/pecl-file_formats-yaml + path: yaml + - name: apt + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + ccache \ + libmemcached-dev \ + imagemagick \ + libmagickwand-dev \ + bison \ + re2c + - name: ccache + uses: ./.github/actions/ccache + with: + name: "${{ github.job }}" + php_directory: php + - name: build PHP + run: | + cd php + ./buildconf --force + ./configure \ + --enable-option-checking=fatal \ + --prefix=/opt/php \ + --enable-cli \ + --disable-all \ + --enable-session \ + --enable-werror + make -j$(/usr/bin/nproc) + sudo make install + - name: build apcu + run: | + cd apcu + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build imagick + run: | + cd imagick + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build memcached + run: | + cd memcached + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build redis + if: ${{ false }} + run: | + cd redis + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build xdebug + run: | + cd xdebug + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build yaml + run: | + cd yaml + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + WINDOWS: + if: ${{ fromJson(inputs.branch).jobs.WINDOWS }} + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.branch).jobs.WINDOWS.matrix }} + name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || ''}}" + runs-on: windows-2022 + env: + PHP_BUILD_CACHE_BASE_DIR: C:\build-cache + PHP_BUILD_OBJ_DIR: C:\obj + PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk + PHP_BUILD_SDK_BRANCH: php-sdk-2.5.0 + PHP_BUILD_CRT: ${{ fromJson(inputs.branch).jobs.WINDOWS.config.vs_crt_version }} + PLATFORM: ${{ matrix.x64 && 'x64' || 'x86' }} + THREAD_SAFE: "${{ matrix.zts && '1' || '0' }}" + INTRINSICS: "${{ matrix.zts && 'AVX2' || '' }}" + PARALLEL: -j2 + OPCACHE: "${{ matrix.opcache && '1' || '0' }}" + ASAN: "${{ matrix.asan && '1' || '0' }}" + steps: + - name: git config + run: git config --global core.autocrlf false && git config --global core.eol lf + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: Setup + uses: ./.github/actions/setup-windows + - name: Build + run: .github/scripts/windows/build.bat + - name: Test + run: .github/scripts/windows/test.bat + FREEBSD: + if: ${{ fromJson(inputs.branch).jobs.FREEBSD }} + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.branch).jobs.FREEBSD.matrix }} + name: "FREEBSD_${{ matrix.zts && 'ZTS' || 'NTS' }}" + runs-on: ubuntu-latest + timeout-minutes: 50 + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: FreeBSD + uses: ./.github/actions/freebsd + with: + configurationParameters: >- + --${{ matrix.zts && 'enable' || 'disable' }}-zts + runExtraTests: true + SOLARIS: + if: ${{ fromJson(inputs.branch).jobs.SOLARIS }} + name: "SOLARIS" + runs-on: ubuntu-latest + timeout-minutes: 50 + steps: + - name: git checkout + uses: actions/checkout@v5 + with: + ref: ${{ fromJson(inputs.branch).ref }} + - name: Solaris + uses: ./.github/actions/solaris + with: + configurationParameters: --disable-zts + runExtraTests: true + BENCHMARKING: + name: BENCHMARKING + if: ${{ fromJson(inputs.branch).jobs.BENCHMARKING }} + runs-on: ubuntu-${{ fromJson(inputs.branch).config.ubuntu_version }} + timeout-minutes: 50 + steps: + - name: git checkout + uses: actions/checkout@v6 + with: + ref: ${{ fromJson(inputs.branch).ref }} + fetch-depth: 0 + # ASLR can cause a lot of noise due to missed sse opportunities for memcpy + # and other operations, so we disable it during benchmarking. + - name: Disable ASLR + run: echo 0 | sudo tee /proc/sys/kernel/randomize_va_space + - name: apt + run: | + set -x + sudo apt-get update + sudo apt-get install \ + bison \ + libgmp-dev \ + libonig-dev \ + libsqlite3-dev \ + openssl \ + re2c \ + valgrind + - name: ccache + uses: ./.github/actions/ccache + with: + name: "${{ github.job }}" + - name: ./configure + run: | + set -x + ./buildconf --force + ./configure \ + --disable-debug \ + --enable-mbstring \ + --enable-option-checking=fatal \ + --enable-sockets \ + --enable-werror \ + --prefix=/usr \ + --with-config-file-scan-dir=/etc/php.d \ + --with-gmp \ + --with-mysqli=mysqlnd \ + --with-openssl \ + --with-pdo-sqlite \ + --with-valgrind + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + run: | + set -x + sudo make install + sudo mkdir -p /etc/php.d + sudo chmod 777 /etc/php.d + echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini + ${{ !fromJson(inputs.branch).jobs.BENCHMARKING.config.integrated_opcache && 'echo zend_extension=opcache.so >> /etc/php.d/opcache.ini' || '' }} + echo opcache.enable=1 >> /etc/php.d/opcache.ini + echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini + - name: Setup + run: | + git config --global user.name "Benchmark" + git config --global user.email "benchmark@php.net" + sudo service mysql start + mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS wordpress" + mysql -uroot -proot -e "CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'wordpress'; FLUSH PRIVILEGES;" + mysql -uroot -proot -e "GRANT ALL PRIVILEGES ON *.* TO 'wordpress'@'localhost' WITH GRANT OPTION;" + - name: git checkout benchmarking-data + uses: actions/checkout@v6 + with: + repository: php/benchmarking-data + ssh-key: ${{ secrets.BENCHMARKING_DATA_DEPLOY_KEY }} + path: benchmark/repos/data + - name: Benchmark + run: php benchmark/benchmark.php true + - name: Store result + if: github.event_name == 'push' + run: | + set -x + cd benchmark/repos/data + git pull --autostash + if [ -e ".git/MERGE_HEAD" ]; then + echo "Merging, can't proceed" + exit 1 + fi + git add . + if git diff --cached --quiet; then + exit 0 + fi + git commit -m "Add result for ${{ github.repository }}@${{ github.sha }}" + git push + - name: Show diff + if: github.event_name == 'pull_request' + run: |- + set -x + php benchmark/generate_diff.php \ + ${{ github.sha }} \ + ${{ github.event.pull_request.base.sha }} \ + > $GITHUB_STEP_SUMMARY + - uses: actions/upload-artifact@v6 + with: + name: profiles + path: ${{ github.workspace }}/benchmark/profiles + retention-days: 30 diff '--color=auto' -Naur php-8.4.18/.github/workflows/test.yml php-8.4.20RC1/.github/workflows/test.yml --- php-8.4.18/.github/workflows/test.yml 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/.github/workflows/test.yml 2026-04-01 04:35:35.982270023 +0000 @@ -0,0 +1,72 @@ +name: Test +on: + push: + paths-ignore: &ignore_paths + - docs/** + - NEWS + - UPGRADING + - UPGRADING.INTERNALS + - '**/README.*' + - CONTRIBUTING.md + - CODING_STANDARDS.md + - .cirrus.yml + - .circleci/** + branches: + - PHP-8.2 + - PHP-8.3 + - PHP-8.4 + - PHP-8.5 + - master + pull_request: + paths-ignore: *ignore_paths + branches: + - '**' + schedule: + - cron: "0 1 * * *" + workflow_dispatch: ~ +permissions: + contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.url || github.run_id }} + cancel-in-progress: true +jobs: + GENERATE_MATRIX: + name: Generate Matrix + if: github.repository == 'php/php-src' || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + outputs: + all_variations: ${{ steps.set-matrix.outputs.all_variations }} + branches: ${{ steps.set-matrix.outputs.branches }} + steps: + - uses: actions/checkout@v6 + with: + # When running nightly, set fetch-depth to 0 to clone the full + # repository including all branches. This is required to find the + # correct commit hashes. + fetch-depth: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && '0' || '1' }} + - name: Grab the commit mapping + if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + uses: actions/cache@v5 + with: + path: branch-commit-cache.json + # The cache key needs to change every time for the + # cache to be updated after this job finishes. + key: nightly-${{ github.run_id }}-${{ github.run_attempt }} + restore-keys: | + nightly- + - name: Generate Matrix + id: set-matrix + run: php .github/matrix.php "${{ github.event_name }}" "${{ github.run_attempt }}" "${{ github.event_name == 'pull_request' && github.ref || github.ref_name }}" '${{ toJSON(github.event.pull_request.labels) }}' "${{ github.repository }}" + TEST: + needs: GENERATE_MATRIX + if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} + name: ${{ matrix.branch.name }} + uses: ./.github/workflows/test-suite.yml + strategy: + fail-fast: false + matrix: + branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }} + with: + all_variations: ${{ needs.GENERATE_MATRIX.outputs.all_variations == 'true' }} + branch: ${{ toJSON(matrix.branch) }} + secrets: inherit diff '--color=auto' -Naur php-8.4.18/main/debug_gdb_scripts.c php-8.4.20RC1/main/debug_gdb_scripts.c --- php-8.4.18/main/debug_gdb_scripts.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/debug_gdb_scripts.c 2026-04-01 04:35:36.022662544 +0000 @@ -6,7 +6,7 @@ * * See https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html#dotdebug_005fgdb_005fscripts-section */ -asm( +__asm__( ".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n" ".byte 4 /* Python Text */\n" ".ascii \"gdb.inlined-script\\n\"\n" diff '--color=auto' -Naur php-8.4.18/main/fastcgi.c php-8.4.20RC1/main/fastcgi.c --- php-8.4.18/main/fastcgi.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/fastcgi.c 2026-04-01 04:35:36.022801286 +0000 @@ -641,7 +641,7 @@ int fcgi_listen(const char *path, int backlog) { - char *s; + const char *s; int tcp = 0; char host[MAXPATHLEN]; short port = 0; diff '--color=auto' -Naur php-8.4.18/main/main.c php-8.4.20RC1/main/main.c --- php-8.4.18/main/main.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/main.c 2026-04-01 04:35:36.022970596 +0000 @@ -995,7 +995,7 @@ { zend_string *replace_origin = NULL; char *docref_buf = NULL, *target = NULL; - char *docref_target = "", *docref_root = ""; + const char *docref_target = "", *docref_root = ""; char *p; const char *space = ""; const char *class_name = ""; diff '--color=auto' -Naur php-8.4.18/main/network.c php-8.4.20RC1/main/network.c --- php-8.4.18/main/network.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/network.c 2026-04-01 04:35:36.023155495 +0000 @@ -553,7 +553,7 @@ PHPAPI zend_result php_network_parse_network_address_with_port(const char *addr, size_t addrlen, struct sockaddr *sa, socklen_t *sl) { - char *colon; + const char *colon; char *tmp; zend_result ret = FAILURE; short port; diff '--color=auto' -Naur php-8.4.18/main/php_version.h php-8.4.20RC1/main/php_version.h --- php-8.4.18/main/php_version.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/php_version.h 2026-04-01 04:38:20.471143120 +0000 @@ -2,7 +2,8 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 4 -#define PHP_RELEASE_VERSION 18 +#define PHP_RELEASE_VERSION 20 #define PHP_EXTRA_VERSION "" -#define PHP_VERSION "8.4.18" -#define PHP_VERSION_ID 80418 +#define PHP_EXTRA_VERSION "RC1" +#define PHP_VERSION "8.4.20RC1" +#define PHP_VERSION_ID 80420 diff '--color=auto' -Naur php-8.4.18/main/php_version.h.orig php-8.4.20RC1/main/php_version.h.orig --- php-8.4.18/main/php_version.h.orig 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/main/php_version.h.orig 2026-02-10 17:48:03.000000000 +0000 @@ -0,0 +1,8 @@ +/* automatically generated by configure */ +/* edit configure.ac to change version number */ +#define PHP_MAJOR_VERSION 8 +#define PHP_MINOR_VERSION 4 +#define PHP_RELEASE_VERSION 18 +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.4.18" +#define PHP_VERSION_ID 80418 diff '--color=auto' -Naur php-8.4.18/main/streams/filter.c php-8.4.20RC1/main/streams/filter.c --- php-8.4.18/main/streams/filter.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/streams/filter.c 2026-04-01 04:35:36.023438721 +0000 @@ -224,7 +224,7 @@ const php_stream_filter_factory *factory = NULL; php_stream_filter *filter = NULL; size_t n; - char *period; + const char *period; n = strlen(filtername); @@ -236,17 +236,17 @@ wildname = safe_emalloc(1, n, 3); memcpy(wildname, filtername, n+1); - period = wildname + (period - filtername); - while (period && !filter) { - ZEND_ASSERT(period[0] == '.'); - period[1] = '*'; - period[2] = '\0'; + char *new_period = wildname + (period - filtername); + while (new_period && !filter) { + ZEND_ASSERT(new_period[0] == '.'); + new_period[1] = '*'; + new_period[2] = '\0'; if (NULL != (factory = zend_hash_str_find_ptr(filter_hash, wildname, strlen(wildname)))) { filter = factory->create_filter(filtername, filterparams, persistent); } - *period = '\0'; - period = strrchr(wildname, '.'); + *new_period = '\0'; + new_period = strrchr(wildname, '.'); } efree(wildname); } diff '--color=auto' -Naur php-8.4.18/main/streams/memory.c php-8.4.20RC1/main/streams/memory.c --- php-8.4.18/main/streams/memory.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/streams/memory.c 2026-04-01 04:35:36.023554028 +0000 @@ -615,7 +615,8 @@ { php_stream *stream; php_stream_temp_data *ts; - char *comma, *semi, *sep; + char *comma; + const char *semi, *sep; size_t mlen, dlen, plen, vlen, ilen; zend_off_t newoffs; zval meta; @@ -637,7 +638,7 @@ path += 2; } - if ((comma = memchr(path, ',', dlen)) == NULL) { + if ((comma = (char *) memchr(path, ',', dlen)) == NULL) { php_stream_wrapper_log_error(wrapper, options, "rfc2397: no comma in URL"); return NULL; } diff '--color=auto' -Naur php-8.4.18/main/streams/plain_wrapper.c php-8.4.20RC1/main/streams/plain_wrapper.c --- php-8.4.18/main/streams/plain_wrapper.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/streams/plain_wrapper.c 2026-04-01 04:35:36.023672212 +0000 @@ -1775,7 +1775,7 @@ ptr = pathbuf; while (ptr && *ptr) { - end = strchr(ptr, DEFAULT_DIR_SEPARATOR); + end = (char *) strchr(ptr, DEFAULT_DIR_SEPARATOR); if (end != NULL) { *end = '\0'; end++; diff '--color=auto' -Naur php-8.4.18/main/streams/xp_socket.c php-8.4.20RC1/main/streams/xp_socket.c --- php-8.4.18/main/streams/xp_socket.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/main/streams/xp_socket.c 2026-04-01 04:35:36.023811124 +0000 @@ -617,7 +617,7 @@ static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *portno, int get_err, zend_string **err) { - char *colon; + const char *colon; char *host = NULL; if (memchr(str, '\0', str_len)) { @@ -628,7 +628,7 @@ #ifdef HAVE_IPV6 if (*(str) == '[' && str_len > 1) { /* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */ - char *p = memchr(str + 1, ']', str_len - 2); + const char *p = memchr(str + 1, ']', str_len - 2); if (!p || *(p + 1) != ':') { if (get_err) { *err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str); diff '--color=auto' -Naur php-8.4.18/NEWS.orig php-8.4.20RC1/NEWS.orig --- php-8.4.18/NEWS.orig 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/NEWS.orig 2026-02-10 17:48:03.000000000 +0000 @@ -0,0 +1,2058 @@ +PHP NEWS +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +12 Feb 2026, PHP 8.4.18 + +- Core: + . Fixed bug GH-20837 (NULL dereference when calling ob_start() in shutdown + function triggered by bailout in php_output_lock_error()). (timwolla) + . Fix OSS-Fuzz #471533782 (Infinite loop in GC destructor fiber). (ilutov) + . Fix OSS-Fuzz #472563272 (Borked block_pass JMP[N]Z optimization). (ilutov) + . Fixed bug GH-GH-20914 (Internal enums can be cloned and compared). (Arnaud) + . Fix OSS-Fuzz #474613951 (Leaked parent property default value). (ilutov) + . Fixed bug GH-20766 (Use-after-free in FE_FREE with GC interaction). (Bob) + . Fix OSS-Fuzz #471486164 (Broken by-ref assignment to uninitialized hooked + backing value). (ilutov) + . Fix OSS-Fuzz #438780145 (Nested finally with repeated return type check may + uaf). (ilutov) + . Fixed bug GH-20905 (Lazy proxy bailing __clone assertion). (ilutov) + . Fixed bug GH-20479 (Hooked object properties overflow). (ndossche) + +- Date: + . Update timelib to 2022.16. (Derick) + +- DOM: + . Fixed GH-21041 (Dom\HTMLDocument corrupts closing tags within scripts). + (lexborisov) + +- MbString: + . Fixed bug GH-20833 (mb_str_pad() divide by zero if padding string is + invalid in the encoding). (ndossche) + . Fixed bug GH-20836 (Stack overflow in mb_convert_variables with + recursive array references). (alexandre-daubois) + +- Opcache: + . Fixed bug GH-20818 (Segfault in Tracing JIT with object reference). + (khasinski) + +- OpenSSL: + . Fix memory leaks when sk_X509_new_null() fails. (ndossche) + . Fix crash when in openssl_x509_parse() when i2s_ASN1_INTEGER() fails. + (ndossche) + . Fix crash in openssl_x509_parse() when X509_NAME_oneline() fails. + (ndossche) + +- Phar: + . Fixed bug GH-20882 (buildFromIterator breaks with missing base directory). + (ndossche) + +- PGSQL: + . Fixed INSERT/UPDATE queries building with PQescapeIdentifier() and possible + UB. (David Carlier) + +- Readline: + . Fixed bug GH-18139 (Memory leak when overriding some settings + via readline_info()). (ndossche) + +- SPL: + . Fixed bug GH-20856 (heap-use-after-free in SplDoublyLinkedList iterator + when modifying during iteration). (ndossche) + +- Standard: + . Fixed bug #74357 (lchown fails to change ownership of symlink with ZTS) + (Jakub Zelenka) + . Fixed bug GH-20843 (var_dump() crash with nested objects) + (David Carlier) + +15 Jan 2026, PHP 8.4.17 + +- Core: + . Fix OSS-Fuzz #465488618 (Wrong assumptions when dumping function signature + with dynamic class const lookup default argument). (ilutov) + . Fixed bug GH-20695 (Assertion failure in normalize_value() when parsing + malformed INI input via parse_ini_string()). (ndossche) + . Fixed bug GH-20714 (Uncatchable exception thrown in generator). (ilutov) + . Fixed bug GH-20352 (UAF in php_output_handler_free via re-entrant + ob_start() during error deactivation). (ndossche) + +- Bz2: + . Fixed bug GH-20620 (bzcompress overflow on large source size). + (David Carlier) + +- DOM: + . Fixed bug GH-20722 (Null pointer dereference in DOM namespace node cloning + via clone on malformed objects). (ndossche) + . Fixed bug GH-20444 (Dom\XMLDocument::C14N() seems broken compared + to DOMDocument::C14N()). (ndossche) + +- GD: + . Fixed bug GH-20622 (imagestring/imagestringup overflow). (David Carlier) + +- Intl: + . Fix leak in umsg_format_helper(). (ndossche) + +- LDAP: + . Fix memory leak in ldap_set_options(). (ndossche) + +- Mbstring: + . Fixed bug GH-20674 (mb_decode_mimeheader does not handle separator). + (Yuya Hamada) + +- OpenSSL: + . Fixed bug GH-20802 (undefined behavior with invalid SNI_server_certs + options). (David Carlier) + +- PCNTL: + . Fixed bug with pcntl_getcpuaffinity() on solaris regarding invalid + process ids handling. (David Carlier) + +- Phar: + . Fixed bug GH-20732 (Phar::LoadPhar undefined behavior when reading fails). + (ndossche) + . Fix SplFileInfo::openFile() in write mode. (ndossche) + . Fix build on legacy OpenSSL 1.1.0 systems. (Giovanni Giacobbi) + . Fixed bug #74154 (Phar extractTo creates empty files). (ndossche) + +- POSIX: + . Fixed crash on posix groups to php array creation on macos. + (David Carlier) + +- SPL: + . Fixed bug GH-20678 (resource created by GlobIterator crashes with fclose()). + (David Carlier) + +- Sqlite3: + . Fixed bug GH-20699 (SQLite3Result fetchArray return array|false, + null returned). (ndossche, plusminmax) + +- Standard: + . Fix error check for proc_open() command. (ndossche) + . Fix memory leak in mail() when header key is numeric. (Girgias) + . Fixed bug GH-20582 (Heap Buffer Overflow in iptcembed). (ndossche) + +- Zlib: + . Fix OOB gzseek() causing assertion failure. (ndossche) + +18 Dec 2025, PHP 8.4.16 + +- Core: + . Sync all boost.context files with release 1.86.0. (mvorisek) + . Fixed bug GH-20435 (SensitiveParameter doesn't work for named argument + passing to variadic parameter). (ndossche) + . Fixed bug GH-20286 (use-after-destroy during userland stream_close()). + (ndossche, David Carlier) + +- Bz2: + . Fix assertion failures resulting in crashes with stream filter + object parameters. (ndossche) + +- Date: + . Fix crashes when trying to instantiate uninstantiable classes via date + static constructors. (ndossche) + +- DOM: + . Fix memory leak when edge case is hit when registering xpath callback. + (ndossche) + . Fixed bug GH-20395 (querySelector and querySelectorAll requires elements + in $selectors to be lowercase). (ndossche) + . Fix missing NUL byte check on C14NFile(). (ndossche) + +- Fibers: + . Fixed bug GH-20483 (ASAN stack overflow with fiber.stack_size INI + small value). (David Carlier) + +- FTP: + . Fixed bug GH-20601 (ftp_connect overflow on timeout). (David Carlier) + +- GD: + . Fixed bug GH-20511 (imagegammacorrect out of range input/output values). + (David Carlier) + . Fixed bug GH-20602 (imagescale overflow with large height values). + (David Carlier) + +- Intl: + . Fixed bug GH-20426 (Spoofchecker::setRestrictionLevel() error message + suggests missing constants). (DanielEScherzer) + +- LibXML: + . Fix some deprecations on newer libxml versions regarding input + buffer/parser handling. (ndossche) + +- MbString: + . Fixed bug GH-20491 (SLES15 compile error with mbstring oniguruma). + (ndossche) + . Fixed bug GH-20492 (mbstring compile warning due to non-strings). + (ndossche) + +- mysqli: + . Make mysqli_begin_transaction() report errors properly. (Kamil Tekiela) + +- MySQLnd: + . Fixed bug GH-20528 (Regression breaks mysql connexion using an IPv6 address + enclosed in square brackets). (Remi) + +- Opcache: + . Fixed bug GH-20329 (opcache.file_cache broken with full interned string + buffer). (Arnaud) + +- PDO: + . Fixed GHSA-8xr5-qppj-gvwj (PDO quoting result null deref). (CVE-2025-14180) + (Jakub Zelenka) + +- Phar: + . Fixed bug GH-20442 (Phar does not respect case-insensitiveness of + __halt_compiler() when reading stub). (ndossche, TimWolla) + . Fix broken return value of fflush() for phar file entries. (ndossche) + . Fix assertion failure when fseeking a phar file out of bounds. (ndossche) + +- PHPDBG: + . Fixed ZPP type violation in phpdbg_get_executable() and phpdbg_end_oplog(). + (Girgias) + +- SPL: + . Fixed bug GH-20614 (SplFixedArray incorrectly handles references + in deserialization). (ndossche) + +- Standard: + . Fix memory leak in array_diff() with custom type checks. (ndossche) + . Fixed bug GH-20583 (Stack overflow in http_build_query + via deep structures). (ndossche) + . Fixed GHSA-www2-q4fc-65wf (Null byte termination in dns_get_record()). + (ndossche) + . Fixed GHSA-h96m-rvf9-jgm2 (Heap buffer overflow in array_merge()). + (CVE-2025-14178) (ndossche) + . Fixed GHSA-3237-qqm7-mfv7 (Information Leak of Memory in getimagesize). + (CVE-2025-14177) (ndossche) + +- Streams: + . Fixed bug GH-20370 (User stream filters could violate typed property + constraints). (alexandre-daubois) + +- Tidy: + . Fixed bug GH-20374 (PHP with tidy and custom-tags). (ndossche) + +- XML: + . Fixed bug GH-20439 (xml_set_default_handler() does not properly handle + special characters in attributes when passing data to callback). (ndossche) + +- Zip: + . Fix crash in property existence test. (ndossche) + . Don't truncate return value of zip_fread() with user sizes. (ndossche) + +- Zlib: + . Fix assertion failures resulting in crashes with stream filter + object parameters. (ndossche) + +20 Nov 2025, PHP 8.4.15 + +- Core: + . Fixed bug GH-19934 (CGI with auto_globals_jit=0 causes uouv). (ilutov) + . Fixed bug GH-20073 (Assertion failure in WeakMap offset operations on + reference). (nielsdos) + . Fixed bug GH-20085 (Assertion failure when combining lazy object + get_properties exception with foreach loop). (nielsdos) + . Fixed bug GH-19844 (Don't bail when closing resources on shutdown). (ilutov) + . Fixed bug GH-20177 (Accessing overridden private property in + get_object_vars() triggers assertion error). (ilutov) + . Fixed bug GH-20270 (Broken parent hook call with named arguments). (ilutov) + . Fixed bug GH-20183 (Stale EG(opline_before_exception) pointer through eval). + (ilutov) + +- DOM: + . Partially fixed bug GH-16317 (DOM classes do not allow + __debugInfo() overrides to work). (nielsdos) + . Fixed bug GH-20281 (\Dom\Document::getElementById() is inconsistent + after nodes are removed). (nielsdos) + +- Exif: + . Fix possible memory leak when tag is empty. (nielsdos) + +- FPM: + . Fixed bug GH-19974 (fpm_status_export_to_zval segfault for parallel + execution). (Jakub Zelenka, txuna) + +- FTP: + . Fixed bug GH-20240 (FTP with SSL: ftp_fput(): Connection timed out on + successful writes). (nielsdos) + +- GD: + . Fixed bug GH-20070 (Return type violation in imagefilter when an invalid + filter is provided). (Girgias) + +- Intl: + . Fix memory leak on error in locale_filter_matches(). (nielsdos) + +- LibXML: + . Fix not thread safe schema/relaxng calls. (SpencerMalone, nielsdos) + +- MySQLnd: + . Fixed bug GH-8978 (SSL certificate verification fails (port doubled)). + (nielsdos) + . Fixed bug GH-20122 (getColumnMeta() for JSON-column in MySQL). (nielsdos) + +- Opcache: + . Fixed bug GH-20081 (access to uninitialized vars in preload_load()). + (Arnaud) + . Fixed bug GH-20121 (JIT broken in ZTS builds on MacOS 15). + (Arnaud, Shivam Mathur) + . Fixed bug GH-19875 (JIT 1205 segfault on large file compiled in subprocess). + (Arnaud) + . Fixed bug GH-20012 (heap buffer overflow in jit). (Arnaud) + . Partially fixed bug GH-17733 (Avoid calling wrong function when reusing file + caches across differing environments). (ilutov) + +- PgSql: + . Fix memory leak when first string conversion fails. (nielsdos) + . Fix segfaults when attempting to fetch row into a non-instantiable class + name. (Girgias, nielsdos) + +- Phar: + . Fix memory leak of argument in webPhar. (nielsdos) + . Fix memory leak when setAlias() fails. (nielsdos) + . Fix a bunch of memory leaks in phar_parse_zipfile() error handling. + (nielsdos) + . Fix file descriptor/memory leak when opening central fp fails. (nielsdos) + . Fix memleak+UAF when opening temp stream in buildFromDirectory() fails. + (nielsdos) + . Fix potential buffer length truncation due to usage of type int instead + of type size_t. (Girgias) + . Fix memory leak when openssl polyfill returns garbage. (nielsdos) + . Fix file descriptor leak in phar_zip_flush() on failure. (nielsdos) + . Fix memory leak when opening temp file fails while trying to open + gzip-compressed archive. (nielsdos) + . Fixed bug GH-20302 (Freeing a phar alias may invalidate + PharFileInfo objects). (nielsdos) + +- Random: + . Fix Randomizer::__serialize() w.r.t. INDIRECTs. (nielsdos) + +- Reflection: + . Fixed bug GH-20217 (ReflectionClass::isIterable() incorrectly returns true + for classes with property hooks). (alexandre-daubois) + +- SimpleXML: + . Partially fixed bug GH-16317 (SimpleXML does not allow __debugInfo() overrides + to work). (nielsdos) + +- Streams: + . Fixed bug GH-19798: XP_SOCKET XP_SSL (Socket stream modules): Incorrect + condition for Win32/Win64. (Jakub Zelenka) + +- Tidy: + . Fixed GH-19021 (improved tidyOptGetCategory detection). + (arjendekorte, David Carlier, Peter Kokot) + . Fix UAF in tidy when tidySetErrorBuffer() fails. (nielsdos) + +- XMLReader: + . Fix arginfo/zpp violations when LIBXML_SCHEMAS_ENABLED is not available. + (nielsdos) + +- Windows: + . Fix GH-19722 (_get_osfhandle asserts in debug mode when given a socket). + (dktapps) + +09 Oct 2025, PHP 8.4.14 + +- Core: + . Fixed bug GH-19765 (object_properties_load() bypasses readonly property + checks). (timwolla) + . Fixed hard_timeout with --enable-zend-max-execution-timers. (Appla) + . Fixed bug GH-19792 (SCCP causes UAF for return value if both warning and + exception are triggered). (nielsdos) + . Fixed bug GH-19653 (Closure named argument unpacking between temporary + closures can cause a crash). (nielsdos, Arnaud, Bob) + . Fixed bug GH-19839 (Incorrect HASH_FLAG_HAS_EMPTY_IND flag on userland + array). (ilutov) + . Fixed bug GH-19480 (error_log php.ini cannot be unset when open_basedir is + configured). (nielsdos) + . Fixed bug GH-20002 (Broken build on *BSD with MSAN). (outtersg) + +- CLI: + . Fix useless "Failed to poll event" error logs due to EAGAIN in CLI server + with PHP_CLI_SERVER_WORKERS. (leotaku) + +- Curl: + . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead + of the curl_copy_handle() function to clone a CurlHandle. (timwolla) + . Fix curl build and test failures with version 8.16. + (nielsdos, ilutov, Jakub Zelenka) + +- Date: + . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. + (nielsdos) + +- DOM: + . Fix macro name clash on macOS. (Ruoyu Zhong) + . Fixed bug GH-20022 (docker-php-ext-install DOM failed). (nielsdos) + +- GD: + . Fixed GH-19955 (imagefttext() memory leak). (David Carlier) + +- MySQLnd: + . Fixed bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress + as parameter). (nielsdos) + +- Opcache: + . Fixed bug GH-19669 (assertion failure in zend_jit_trace_type_to_info_ex). + (Arnaud) + . Fixed bug GH-19831 (function JIT may not deref property value). (Arnaud) + . Fixed bug GH-19889 (race condition in zend_runtime_jit(), + zend_jit_hot_func()). (Arnaud) + +- Phar: + . Fix memory leak and invalid continuation after tar header writing fails. + (nielsdos) + . Fix memory leaks when creating temp file fails when applying zip signature. + (nielsdos) + +- SimpleXML: + . Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)). + (nielsdos) + +- Soap: + . Fixed bug GH-19784 (SoapServer memory leak). (nielsdos) + . Fixed bug GH-20011 (Array of SoapVar of unknown type causes crash). + (nielsdos) + +- Standard: + . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). + (nielsdos) + . Fixed bug GH-19701 (Serialize/deserialize loses some data). (nielsdos) + . Fixed bug GH-19801 (leaks in var_dump() and debug_zval_dump()). + (alexandre-daubois) + . Fixed bug GH-20043 (array_unique assertion failure with RC1 array + causing an exception on sort). (nielsdos) + . Fixed bug GH-19926 (reset internal pointer earlier while splicing array + while COW violation flag is still set). (alexandre-daubois) + . Fixed bug GH-19570 (unable to fseek in /dev/zero and /dev/null). + (nielsdos, divinity76) + +- Streams: + . Fixed bug GH-19248 (Use strerror_r instead of strerror in main). + (Jakub Zelenka) + . Fixed bug GH-17345 (Bug #35916 was not completely fixed). (nielsdos) + . Fixed bug GH-19705 (segmentation when attempting to flush on non seekable + stream. (bukka/David Carlier) + +- XMLReader: + . Fixed bug GH-20009 (XMLReader leak on RelaxNG schema failure). (nielsdos) + +- Zip: + . Fixed bug GH-19688 (Remove pattern overflow in zip addGlob()). (nielsdos) + . Fixed bug GH-19932 (Memory leak in zip setEncryptionName()/setEncryptionIndex()). + (David Carlier) + +25 Sep 2025, PHP 8.4.13 + +- Core: + . Fixed bug GH-18850 (Repeated inclusion of file with __halt_compiler() + triggers "Constant already defined" warning). (ilutov) + . Partially fixed bug GH-19542 (Scanning of string literals >=2GB will fail + due to signed int overflow). (ilutov) + . Fixed bug GH-19544 (GC treats ZEND_WEAKREF_TAG_MAP references as WeakMap + references). (Arnaud, timwolla) + . Fixed bug GH-19613 (Stale array iterator pointer). (ilutov) + . Fixed bug GH-19679 (zend_ssa_range_widening may fail to converge). (Arnaud) + . Fixed bug GH-19681 (PHP_EXPAND_PATH broken with bash 5.3.0). (Remi) + . Fixed bug GH-19720 (Assertion failure when error handler throws when + accessing a deprecated constant). (nielsdos) + +- CLI: + . Fixed bug GH-19461 (Improve error message on listening error with IPv6 + address). (alexandre-daubois) + +- Date: + . Fixed date_sunrise() and date_sunset() with partial-hour UTC offset. + (ilutov) + +- DBA: + . Fixed bug GH-19706 (dba stream resource mismanagement). (nielsdos) + +- DOM: + . Fixed bug GH-19612 (Mitigate libxml2 tree dictionary bug). (nielsdos) + +- FPM: + . Fixed failed debug assertion when php_admin_value setting fails. (ilutov) + +- Intl: + . Fixed bug GH-11952 (Fix locale strings canonicalization for IntlDateFormatter + and NumberFormatter). (alexandre-daubois) + +- Opcache: + . Fixed bug GH-19493 (JIT variable not stored before YIELD). (Arnaud) + +- OpenSSL: + . Fixed bug GH-19245 (Success error message on TLS stream accept failure). + (Jakub Zelenka) + +- PGSQL: + . Fixed bug GH-19485 (potential use after free when using persistent pgsql + connections). (Mark Karpeles) + +- Phar: + . Fixed memory leaks when verifying OpenSSL signature. (Girgias) + . Fix memory leak in phar tar temporary file error handling code. (nielsdos) + . Fix metadata leak when phar convert logic fails. (nielsdos) + . Fix memory leak on failure in phar_convert_to_other(). (nielsdos) + . Fixed bug GH-19752 (Phar decompression with invalid extension + can cause UAF). (nielsdos) + +- Standard: + . Fixed bug GH-16649 (UAF during array_splice). (alexandre-daubois) + . Fixed bug GH-19577 (Avoid integer overflow when using a small offset + and PHP_INT_MAX with LimitIterator). (alexandre-daubois) + +- Streams: + . Remove incorrect call to zval_ptr_dtor() in user_wrapper_metadata(). + (nielsdos) + . Fix OSS-Fuzz #385993744. (nielsdos) + +- Zip: + . Fix memory leak in zip when encountering empty glob result. (nielsdos) + +28 Aug 2025, PHP 8.4.12 + +- Core: + . Fixed GH-19169 build issue with C++17 and ZEND_STATIC_ASSERT macro. + (psumbera) + . Fixed bug GH-19053 (Duplicate property slot with hooks and interface + property). (ilutov) + . Fixed bug GH-19044 (Protected properties are not scoped according to their + prototype). (Bob) + . Fixed bug GH-18581 (Coerce numeric string keys from iterators when argument + unpacking). (ilutov) + . Fixed OSS-Fuzz #434346548 (Failed assertion with throwing __toString in + binary const expr). (ilutov) + . Fixed bug GH-19305 (Operands may be being released during comparison). + (Arnaud) + . Fixed bug GH-19303 (Unpacking empty packed array into uninitialized array + causes assertion failure). (nielsdos) + . Fixed bug GH-19306 (Generator can be resumed while fetching next value from + delegated Generator). (Arnaud) + . Fixed bug GH-19326 (Calling Generator::throw() on a running generator with + a non-Generator delegate crashes). (Arnaud) + . Fixed bug GH-19280 (Stale array iterator position on rehashing). (ilutov) + . Fixed bug GH-18736 (Circumvented type check with return by ref + finally). + (ilutov) + . Fixed bug GH-19065 (Long match statement can segfault compiler during + recursive SSA renaming). (nielsdos, Arnaud) + +- Calendar: + . Fixed bug GH-19371 (integer overflow in calendar.c). (nielsdos) + +- FTP: + . Fix theoretical issues with hrtime() not being available. (nielsdos) + +- GD: + . Fix incorrect comparison with result of php_stream_can_cast(). (Girgias) + +- Hash: + . Fix crash on clone failure. (nielsdos) + +- Intl: + . Fix memleak on failure in collator_get_sort_key(). (nielsdos) + . Fix return value on failure for resourcebundle count handler. (Girgias) + +- LDAP: + . Fixed bug GH-18529 (additional inheriting of TLS int options). + (Jakub Zelenka) + +- LibXML: + . Fixed bug GH-19098 (libxml<2.13 segmentation fault caused by + php_libxml_node_free). (nielsdos) + +- MbString: + . Fixed bug GH-19397 (mb_list_encodings() can cause crashes on shutdown). + (nielsdos) + +- Opcache: + . Reset global pointers to prevent use-after-free in zend_jit_status(). + (Florian Engelhardt) + . Fix issue with JIT restart and hooks. (nielsdos) + . Fix crash with dynamic function defs in hooks during preload. (nielsdos) + +- OpenSSL: + . Fixed bug GH-18986 (OpenSSL backend: incorrect RAND_{load,write}_file() + return value check). (nielsdos, botovq) + . Fix error return check of EVP_CIPHER_CTX_ctrl(). (nielsdos) + . Fixed bug GH-19428 (openssl_pkey_derive segfaults for DH derive with low + key_length param). (Jakub Zelenka) + +- PDO Pgsql: + . Fixed dangling pointer access on _pdo_pgsql_trim_message helper. + (dixyes) + +- SOAP: + . Fixed bug GH-18640 (heap-use-after-free ext/soap/php_encoding.c:299:32 + in soap_check_zval_ref). (nielsdos) + +- Sockets: + . Fix some potential crashes on incorrect argument value. (nielsdos) + +- Standard: + . Fixed OSS Fuzz #433303828 (Leak in failed unserialize() with opcache). + (ilutov) + . Fix theoretical issues with hrtime() not being available. (nielsdos) + . Fixed bug GH-19300 (Nested array_multisort invocation with error breaks). + (nielsdos) + +- Windows: + . Free opened_path when opened_path_len >= MAXPATHLEN. (dixyes) + +31 Jul 2025, PHP 8.4.11 + +- Calendar: + . Fixed jewishtojd overflow on year argument. (David Carlier) + +- Core: + . Fixed bug GH-18833 (Use after free with weakmaps dependent on destruction + order). (Daniil Gentili) + . Fixed bug GH-18907 (Leak when creating cycle in hook). (ilutov) + . Fix OSS-Fuzz #427814456. (nielsdos) + . Fix OSS-Fuzz #428983568 and #428760800. (nielsdos) + +- Curl: + . Fix memory leaks when returning refcounted value from curl callback. + (nielsdos) + . Remove incorrect string release. (nielsdos) + +- DOM: + . Fixed bug GH-18979 (Dom\XMLDocument::createComment() triggers undefined + behavior with null byte). (nielsdos) + +- LDAP: + . Fixed GH-18902 ldap_exop/ldap_exop_sync assert triggered on empty + request OID. (David Carlier) + +- MbString: + . Fixed bug GH-18901 (integer overflow mb_split). (nielsdos) + +- Opcache: + . Fixed bug GH-18639 (Internal class aliases can break preloading + JIT). + (nielsdos) + . Fixed bug GH-18899 (JIT function crash when emitting undefined variable + warning and opline is not set yet). (nielsdos) + . Fixed bug GH-14082 (Segmentation fault on unknown address 0x600000000018 + in ext/opcache/jit/zend_jit.c). (nielsdos) + . Fixed bug GH-18898 (SEGV zend_jit_op_array_hot with property hooks + and preloading). (nielsdos) + +- OpenSSL: + . Fixed bug #80770 (It is not possible to get client peer certificate with + stream_socket_server). (Jakub Zelenka) + +- PCNTL: + . Fixed bug GH-18958 (Fatal error during shutdown after pcntl_rfork() or + pcntl_forkx() with zend-max-execution-timers). (Arnaud) + +- Phar: + . Fix stream double free in phar. (nielsdos, dixyes) + . Fix phar crash and file corruption with SplFileObject. (nielsdos) + +- SOAP: + . Fixed bug GH-18990, bug #81029, bug #47314 (SOAP HTTP socket not closing + on object destruction). (nielsdos) + . Fix memory leak when URL parsing fails in redirect. (Girgias) + +- SPL: + . Fixed bug GH-19094 (Attaching class with no Iterator implementation to + MultipleIterator causes crash). (nielsdos) + +- Standard: + . Fix misleading errors in printf(). (nielsdos) + . Fix RCN violations in array functions. (nielsdos) + . Fixed GH-18976 pack() overflow with h/H format and INT_MAX repeater value. + (David Carlier) + +- Streams: + . Fixed GH-13264 (fgets() and stream_get_line() do not return false on filter + fatal error). (Jakub Zelenka) + +- Zip: + . Fix leak when path is too long in ZipArchive::extractTo(). (nielsdos) + +03 Jul 2025, PHP 8.4.10 + +- BcMath: + . Fixed bug GH-18641 (Accessing a BcMath\Number property by ref crashes). + (nielsdos) + +- Core: + . Fixed bugs GH-17711 and GH-18022 (Infinite recursion on deprecated attribute + evaluation) and GH-18464 (Recursion protection for deprecation constants not + released on bailout). (DanielEScherzer and ilutov) + . Fixed GH-18695 (zend_ast_export() - float number is not preserved). + (Oleg Efimov) + . Fix handling of references in zval_try_get_long(). (nielsdos) + . Do not delete main chunk in zend_gc. (danog, Arnaud) + . Fix compile issues with zend_alloc and some non-default options. (nielsdos) + +- Curl: + . Fix memory leak when setting a list via curl_setopt fails. (nielsdos) + +- Date: + . Fix leaks with multiple calls to DatePeriod iterator current(). (nielsdos) + +- DOM: + . Fixed bug GH-18744 (classList works not correctly if copy HTMLElement by + clone keyword). (nielsdos) + +- FPM: + . Fixed GH-18662 (fpm_get_status segfault). (txuna) + +- Hash: + . Fixed bug GH-14551 (PGO build fails with xxhash). (nielsdos) + +- Intl: + . Fix memory leak in intl_datetime_decompose() on failure. (nielsdos) + . Fix memory leak in locale lookup on failure. (nielsdos) + +- Opcache: + . Fixed bug GH-18743 (Incompatibility in Inline TLS Assembly on Alpine 3.22). + (nielsdos, Arnaud) + +- ODBC: + . Fix memory leak on php_odbc_fetch_hash() failure. (nielsdos) + +- OpenSSL: + . Fix memory leak of X509_STORE in php_openssl_setup_verify() on failure. + (nielsdos) + . Fixed bug #74796 (Requests through http proxy set peer name). + (Jakub Zelenka) + +- PDO ODBC: + . Fix memory leak if WideCharToMultiByte() fails. (nielsdos) + +- PDO Sqlite: + . Fixed memory leak with Pdo_Sqlite::createCollation when the callback + has an incorrect return type. (David Carlier) + +- Phar: + . Add missing filter cleanups on phar failure. (nielsdos) + . Fixed bug GH-18642 (Signed integer overflow in ext/phar fseek). (nielsdos) + +- PHPDBG: + . Fix 'phpdbg --help' segfault on shutdown with USE_ZEND_ALLOC=0. (nielsdos) + +- PGSQL: + . Fix warning not being emitted when failure to cancel a query with + pg_cancel_query(). (Girgias) + +- Random: + . Fix reference type confusion and leak in user random engine. + (nielsdos, timwolla) + +- Readline: + . Fix memory leak when calloc() fails in php_readline_completion_cb(). + (nielsdos) + +- SimpleXML: + . Fixed bug GH-18597 (Heap-buffer-overflow in zend_alloc.c when assigning + string with UTF-8 bytes). (nielsdos) + +- Soap: + . Fix memory leaks in php_http.c when call_user_function() fails. (nielsdos) + +- Tidy: + . Fix memory leak in tidy output handler on error. (nielsdos) + . Fix tidyOptIsReadonly deprecation, using tidyOptGetCategory. (David Carlier) + +06 Jun 2025, PHP 8.4.8 + +- Core: + . Fixed GH-18480 (array_splice with large values for offset/length arguments). + (nielsdos/David Carlier) + . Partially fixed GH-18572 (nested object comparisons leading to stack overflow). + (David Carlier) + . Fixed OSS-Fuzz #417078295. (nielsdos) + . Fixed OSS-Fuzz #418106144. (nielsdos) + +- Curl: + . Fixed GH-18460 (curl_easy_setopt with CURLOPT_USERPWD/CURLOPT_USERNAME/ + CURLOPT_PASSWORD set the Authorization header when set to NULL). + (David Carlier) + +- Date: + . Fixed bug GH-18076 (Since PHP 8, the date_sun_info() function returns + inaccurate sunrise and sunset times, but other calculated times are + correct) (JiriJozif). + . Fixed bug GH-18481 (date_sunrise with unexpected nan value for the offset). + (nielsdos/David Carlier) + +- DOM: + . Backport lexbor/lexbor#274. (nielsdos, alexpeattie) + +- Intl: + . Fix various reference issues. (nielsdos) + +- LDAP: + . Fixed bug GH-18529 (ldap no longer respects TLS_CACERT from ldaprc in + ldap_start_tls()). (Remi) + +- Opcache: + . Fixed bug GH-18417 (Windows SHM reattachment fails when increasing + memory_consumption or jit_buffer_size). (nielsdos) + . Fixed bug GH-18297 (Exception not handled when jit guard is triggered). + (Arnaud) + . Fixed bug GH-18408 (Snapshotted poly_func / poly_this may be spilled). + (Arnaud) + . Fixed bug GH-18567 (Preloading with internal class alias triggers assertion + failure). (nielsdos) + . Fixed bug GH-18534 (FPM exit code 70 with enabled opcache and hooked + properties in traits). (nielsdos) + . Fix leak of accel_globals->key. (nielsdos) + +- OpenSSL: + . Fix missing checks against php_set_blocking() in xp_ssl.c. (nielsdos) + +- SPL: + . Fixed bug GH-18421 (Integer overflow with large numbers in LimitIterator). + (nielsdos) + +- Standard: + . Fixed bug GH-17403 (Potential deadlock when putenv fails). (nielsdos) + . Fixed bug GH-18400 (http_build_query type error is inaccurate). (nielsdos) + . Fixed bug GH-18509 (Dynamic calls to assert() ignore zend.assertions). + (timwolla) + +- Windows: + . Fix leak+crash with sapi_windows_set_ctrl_handler(). (nielsdos) + +- Zip: + . Fixed bug GH-18431 (Registering ZIP progress callback twice doesn't work). + (nielsdos) + . Fixed bug GH-18438 (Handling of empty data and errors in + ZipArchive::addPattern). (nielsdos) + +24 Apr 2025, PHP 8.4.7 + +- Core: + . Fixed bug GH-18038 (Lazy proxy calls magic methods twice). (Arnaud) + . Fixed bug GH-18209 (Use-after-free in extract() with EXTR_REFS). (ilutov) + . Fixed bug GH-18268 (Segfault in array_walk() on object with added property + hooks). (ilutov) + . Fixed bug GH-18304 (Changing the properties of a DateInterval through + dynamic properties triggers a SegFault). (nielsdos) + . Fix some leaks in php_scandir. (nielsdos) + +- DBA: + . FIxed bug GH-18247 dba_popen() memory leak on invalid path. (David Carlier) + +- Filter: + . Fixed bug GH-18309 (ipv6 filter integer overflow). (nielsdos) + +- GD: + . Fixed imagecrop() overflow with rect argument with x/width y/heigh usage + in gdImageCrop(). (David Carlier) + . Fixed GH-18243 imagettftext() overflow/underflow on font size value. + (David Carlier) + +- Intl: + . Fix reference support for intltz_get_offset(). (nielsdos) + +- LDAP: + . Fixed bug GH-17776 (LDAP_OPT_X_TLS_* options can't be overridden). (Remi) + . Fix NULL deref on high modification key. (nielsdos) + +- libxml: + . Fixed custom external entity loader returning an invalid resource leading + to a confusing TypeError message. (Girgias) + +- Opcache: + . Fixed bug GH-18294 (assertion failure zend_jit_ir.c). (nielsdos) + . Fixed bug GH-18289 (Fix segfault in JIT). (Florian Engelhardt) + . Fixed bug GH-18136 (tracing JIT floating point register clobbering on + Windows and ARM64). (nielsdos) + +- OpenSSL: + . Fix memory leak in openssl_sign() when passing invalid algorithm. + (nielsdos) + . Fix potential leaks when writing to BIO fails. (nielsdos) + +- PDO Firebird: + . Fixed bug GH-18276 (persistent connection - "zend_mm_heap corrupted" + with setAttribute()) (SakiTakamachi). + . Fixed bug GH-17383 (PDOException has wrong code and message since PHP 8.4) + (SakiTakamachi). + +- PDO Sqlite: + . Fix memory leak on error return of collation callback. (nielsdos) + +- PgSql: + . Fix uouv in pg_put_copy_end(). (nielsdos) + +- SPL: + . Fixed bug GH-18322 (SplObjectStorage debug handler mismanages memory). + (nielsdos) + +- Standard: + . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). + (Jakub Zelenka) + . Fix resource leak in iptcembed() on error. (nielsdos) + +- Tests: + . Address deprecated PHP 8.4 session options to prevent test failures. + (willvar) + +- Zip: + . Fix uouv when handling empty options in ZipArchive::addGlob(). (nielsdos) + . Fix memory leak when handling a too long path in ZipArchive::addGlob(). + (nielsdos) + +10 Apr 2025, PHP 8.4.6 + +- BCMath: + . Fixed pointer subtraction for scale. (SakiTakamachi) + +- Core: + . Fixed property hook backing value access in multi-level inheritance. + (ilutov) + . Fixed accidentally inherited default value in overridden virtual properties. + (ilutov) + . Fixed bug GH-17376 (Broken JIT polymorphism for property hooks added to + child class). (ilutov) + . Fixed bug GH-17913 (ReflectionFunction::isDeprecated() returns incorrect + results for closures created from magic __call()). (timwolla) + . Fixed bug GH-17941 (Stack-use-after-return with lazy objects and hooks). + (nielsdos) + . Fixed bug GH-17988 (Incorrect handling of hooked props without get hook in + get_object_vars()). (ilutov) + . Fixed bug GH-17998 (Skipped lazy object initialization on primed + SIMPLE_WRITE cache). (ilutov) + . Fixed bug GH-17998 (Assignment to backing value in set hook of lazy proxy + calls hook again). (ilutov) + . Fixed bug GH-17961 (use-after-free during dl()'ed module class destruction). + (Arnaud) + . Fixed bug GH-15367 (dl() of module with aliased class crashes in shutdown). + (Arnaud) + . Fixed OSS-Fuzz #403308724. (nielsdos) + . Fixed bug GH-13193 again (Significant performance degradation in 'foreach'). + (nielsdos) + +- DBA: + . Fixed assertion violation when opening the same file with dba_open + multiple times. (chschneider) + +- DOM: + . Fixed bug GH-17991 (Assertion failure dom_attr_value_write). (nielsdos) + . Fix weird unpack behaviour in DOM. (nielsdos) + . Fixed bug GH-18090 (DOM: Svg attributes and tag names are being lowercased). + (nielsdos) + . Fix xinclude destruction of live attributes. (nielsdos) + +- Fuzzer: + . Fixed bug GH-18081 (Memory leaks in error paths of fuzzer SAPI). + (Lung-Alexandra) + +- GD: + . Fixed bug GH-17984 (calls with arguments as array with references). + (David Carlier) + +- LDAP: + . Fixed bug GH-18015 (Error messages for ldap_mod_replace are confusing). + (nielsdos) + +- Mbstring: + . Fixed bug GH-17989 (mb_output_handler crash with unset + http_output_conv_mimetypes). (nielsdos) + +- Opcache: + . Fixed bug GH-15834 (Segfault with hook "simple get" cache slot and minimal + JIT). (nielsdos) + . Fixed bug GH-17966 (Symfony JIT 1205 assertion failure). (nielsdos) + . Fixed bug GH-18037 (SEGV Zend/zend_execute.c). (nielsdos) + . Fixed bug GH-18050 (IN_ARRAY optimization in DFA pass is broken). (ilutov) + . Fixed bug GH-18113 (stack-buffer-overflow ext/opcache/jit/ir/ir_sccp.c). + (nielsdos) + . Fixed bug GH-18112 (NULL access with preloading and INI option). (nielsdos) + . Fixed bug GH-18107 (Opcache CFG jmp optimization with try-finally breaks + the exception table). (nielsdos) + +- PDO: + . Fix memory leak when destroying PDORow. (nielsdos) + +- PGSQL: + . Fixed bug GH-18148 (pg_copy_from() regression with explicit \n terminator + due to wrong offset check). (David Carlier) + +- Standard: + . Fix memory leaks in array_any() / array_all(). (nielsdos) + +- SOAP: + . Fixed bug #66049 (Typemap can break parsing in parse_packet_soap leading to + a segfault) . (Remi) + +- SPL: + . Fixed bug GH-18018 (RC1 data returned from offsetGet causes UAF in + ArrayObject). (nielsdos) + +- Treewide: + . Fixed bug GH-17736 (Assertion failure zend_reference_destroy()). (nielsdos) + +- Windows: + . Fixed bug GH-17836 (zend_vm_gen.php shouldn't break on Windows line + endings). (DanielEScherzer) + +27 Feb 2025, PHP 8.4.5 + +- BCMath: + . Fixed bug GH-17398 (bcmul memory leak). (SakiTakamachi) + +- Core: + . Fixed bug GH-17623 (Broken stack overflow detection for variable + compilation). (ilutov) + . Fixed bug GH-17618 (UnhandledMatchError does not take + zend.exception_ignore_args=1 into account). (timwolla) + . Fix fallback paths in fast_long_{add,sub}_function. (nielsdos) + . Fixed bug OSS-Fuzz #391975641 (Crash when accessing property backing value + by reference). (ilutov) + . Fixed bug GH-17718 (Calling static methods on an interface that has + `__callStatic` is allowed). (timwolla) + . Fixed bug GH-17713 (ReflectionProperty::getRawValue() and related methods + may call hooks of overridden properties). (Arnaud) + . Fixed bug GH-17916 (Final abstract properties should error). + (DanielEScherzer) + . Fixed bug GH-17866 (zend_mm_heap corrupted error after upgrading from + 8.4.3 to 8.4.4). (nielsdos) + . Fixed GHSA-rwp7-7vc6-8477 (Reference counting in php_request_shutdown + causes Use-After-Free). (CVE-2024-11235) (ilutov) + +- DOM: + . Fixed bug GH-17609 (Typo in error message: Dom\NO_DEFAULT_NS instead of + Dom\HTML_NO_DEFAULT_NS). (nielsdos) + . Fixed bug GH-17802 (\Dom\HTMLDocument querySelector attribute name is case + sensitive in HTML). (nielsdos) + . Fixed bug GH-17847 (xinclude destroys live node). (nielsdos) + . Fix using Dom\Node with Dom\XPath callbacks. (nielsdos) + +- FFI: + . Fix FFI Parsing of Pointer Declaration Lists. (davnotdev) + +- FPM: + . Fixed bug GH-17643 (FPM with httpd ProxyPass encoded PATH_INFO env). + (Jakub Zelenka) + +- GD: + . Fixed bug GH-17703 (imagescale with both width and height negative values + triggers only an Exception on width). (David Carlier) + . Fixed bug GH-17772 (imagepalettetotruecolor crash with memory_limit=2M). + (David Carlier) + +- LDAP: + . Fixed bug GH-17704 (ldap_search fails when $attributes contains a + non-packed array with numerical keys). (nielsdos, 7u83) + +- LibXML: + . Fixed GHSA-wg4p-4hqh-c3g9 (Reocurrence of #72714). (nielsdos) + . Fixed GHSA-p3x9-6h7p-cgfc (libxml streams use wrong `content-type` header + when requesting a redirected resource). (CVE-2025-1219) (timwolla) + +- MBString: + . Fixed bug GH-17503 (Undefined float conversion in mb_convert_variables). + (cmb) + +- Opcache: + . Fixed bug GH-17654 (Multiple classes using same trait causes function + JIT crash). (nielsdos) + . Fixed bug GH-17577 (JIT packed type guard crash). (nielsdos, Dmitry) + . Fixed bug GH-17747 (Exception on reading property in register-based + FETCH_OBJ_R breaks JIT). (Dmitry, nielsdos) + . Fixed bug GH-17715 (Null pointer deref in observer API when calling + cases() method on preloaded enum). (Bob) + . Fixed bug GH-17868 (Cannot allocate memory with tracing JIT on 8.4.4). + (nielsdos) + +- PDO_SQLite: + . Fixed GH-17837 ()::getColumnMeta() on unexecuted statement segfaults). + (cmb) + . Fix cycle leak in sqlite3 setAuthorizer(). (nielsdos) + . Fix memory leaks in pdo_sqlite callback registration. (nielsdos) + +- Phar: + . Fixed bug GH-17808: PharFileInfo refcount bug. (nielsdos) + +- PHPDBG: + . Partially fixed bug GH-17387 (Trivial crash in phpdbg lexer). (nielsdos) + . Fix memory leak in phpdbg calling registered function. (nielsdos) + +- Reflection: + . Fixed bug GH-15902 (Core dumped in ext/reflection/php_reflection.c). + (DanielEScherzer) + . Fixed missing final and abstract flags when dumping properties. + (DanielEScherzer) + +- Standard: + . Fixed bug #72666 (stat cache clearing inconsistent between file:// paths + and plain paths). (Jakub Zelenka) + +- Streams: + . Fixed bug GH-17650 (realloc with size 0 in user_filters.c). (nielsdos) + . Fix memory leak on overflow in _php_stream_scandir(). (nielsdos) + . Fixed GHSA-hgf5-96fm-v528 (Stream HTTP wrapper header check might omit + basic auth header). (CVE-2025-1736) (Jakub Zelenka) + . Fixed GHSA-52jp-hrpf-2jff (Stream HTTP wrapper truncate redirect location + to 1024 bytes). (CVE-2025-1861) (Jakub Zelenka) + . Fixed GHSA-pcmh-g36c-qc44 (Streams HTTP wrapper does not fail for headers + without colon). (CVE-2025-1734) (Jakub Zelenka) + . Fixed GHSA-v8xr-gpvj-cx9g (Header parser of `http` stream wrapper does not + handle folded headers). (CVE-2025-1217) (Jakub Zelenka) + +- Windows: + . Fixed phpize for Windows 11 (24H2). (bwoebi) + . Fixed GH-17855 (CURL_STATICLIB flag set even if linked with shared lib). + (cmb) + +- Zlib: + . Fixed bug GH-17745 (zlib extension incorrectly handles object arguments). + (nielsdos) + . Fix memory leak when encoding check fails. (nielsdos) + . Fix zlib support for large files. (nielsdos) + +13 Feb 2025, PHP 8.4.4 + +- Core: + . Fixed bug GH-17234 (Numeric parent hook call fails with assertion). + (nielsdos) + . Fixed bug GH-16892 (ini_parse_quantity() fails to parse inputs starting + with 0x0b). (nielsdos) + . Fixed bug GH-16886 (ini_parse_quantity() fails to emit warning for 0x+0). + (nielsdos) + . Fixed bug GH-17222 (__PROPERTY__ magic constant does not work in all + constant expression contexts). (ilutov) + . Fixed bug GH-17214 (Relax final+private warning for trait methods with + inherited final). (ilutov) + . Fixed NULL arithmetic during system program execution on Windows. (cmb, + nielsdos) + . Fixed potential OOB when checking for trailing spaces on Windows. (cmb) + . Fixed bug GH-17408 (Assertion failure Zend/zend_exceptions.c). + (nielsdos, ilutov) + . Fix may_have_extra_named_args flag for ZEND_AST_UNPACK. (nielsdos) + . Fix NULL arithmetic in System V shared memory emulation for Windows. (cmb) + . Fixed bug GH-17597 (#[\Deprecated] does not work for __call() and + __callStatic()). (timwolla) + +- DOM: + . Fixed bug GH-17397 (Assertion failure ext/dom/php_dom.c). (nielsdos) + . Fixed bug GH-17486 (Incorrect error line numbers reported in + Dom\HTMLDocument::createFromString). (nielsdos) + . Fixed bug GH-17481 (UTF-8 corruption in \Dom\HTMLDocument). (nielsdos) + . Fixed bug GH-17500 (Segfault with requesting nodeName on nameless doctype). + (nielsdos) + . Fixed bug GH-17485 (upstream fix, Self-closing tag on void elements + shouldn't be a parse error/warning in \Dom\HTMLDocument). (lexborisov) + . Fixed bug GH-17572 (getElementsByTagName returns collections with + tagName-based indexing). (nielsdos) + +- Enchant: + . Fix crashes in enchant when passing null bytes. (nielsdos) + +- FTP: + . Fixed bug GH-16800 (ftp functions can abort with EINTR). (nielsdos) + +- GD: + . Fixed bug GH-17349 (Tiled truecolor filling looses single color + transparency). (cmb) + . Fixed bug GH-17373 (imagefttext() ignores clipping rect for palette + images). (cmb) + . Ported fix for libgd 223 (gdImageRotateGeneric() does not properly + interpolate). (cmb) + . Added support for reading GIFs without colormap to bundled libgd. (Andrew + Burley, cmb) + +- Gettext: + . Fixed bug GH-17400 (bindtextdomain SEGV on invalid domain). + (David Carlier) + +- Intl: + . Fixed bug GH-11874 (intl causing segfault in docker images). (nielsdos) + +- Opcache: + . Fixed bug GH-15981 (Segfault with frameless jumps and minimal JIT). + (nielsdos) + . Fixed bug GH-17307 (Internal closure causes JIT failure). (nielsdos) + . Fixed bug GH-17428 (Assertion failure ext/opcache/jit/zend_jit_ir.c:8940). + (nielsdos) + . Fixed bug GH-17564 (Potential UB when reading from / writing to struct + padding). (ilutov) + +- PCNTL: + . Fixed pcntl_setcpuaffinity exception type from ValueError to TypeError for + the cpu mask argument with entries type different than int/string. + (David Carlier) + +- PCRE: + . Fixed bug GH-17122 (memory leak in regex). (nielsdos) + +- PDO: + . Fixed a memory leak when the GC is used to free a PDOStatment. (Girgias) + . Fixed a crash in the PDO Firebird Statement destructor. (nielsdos) + . Fixed UAFs when changing default fetch class ctor args. (Girgias, nielsdos) + +- PgSql: + . Fixed build failure when the constant PGRES_TUPLES_CHUNK is not present + in the system. (chschneider) + +- Phar: + . Fixed bug GH-17518 (offset overflow phar extractTo()). (nielsdos) + +- PHPDBG: + . Fix crashes in function registration + test. (nielsdos, Girgias) + +- Session: + . Fix type confusion with session SID constant. (nielsdos) + . Fixed bug GH-17541 (ext/session NULL pointer dereferencement during + ID reset). (Girgias) + +- SimpleXML: + . Fixed bug GH-17409 (Assertion failure Zend/zend_hash.c:1730). (nielsdos) + +- SNMP: + . Fixed bug GH-17330 (SNMP::setSecurity segfault on closed session). + (David Carlier) + +- SPL: + . Fixed bug GH-15833 (Segmentation fault (access null pointer) in + ext/spl/spl_array.c). (nielsdos) + . Fixed bug GH-17516 (SplFileTempObject::getPathInfo() Undefined behavior + on invalid class). (David Carlier) + +- Standard: + . Fixed bug GH-17447 (Assertion failure when array popping a self addressing + variable). (nielsdos) + +- Windows: + . Fixed clang compiler detection. (cmb) + +- Zip: + . Fixed bug GH-17139 (Fix zip_entry_name() crash on invalid entry). + (nielsdos) + +16 Jan 2025, PHP 8.4.3 + +- BcMath: + . Fixed bug GH-17049 (Correctly compare 0 and -0). (Saki Takamachi) + . Fixed bug GH-17061 (Now Number::round() does not remove trailing zeros). + (Saki Takamachi) + . Fixed bug GH-17064 (Correctly round rounding mode with zero edge case). + (Saki Takamachi) + . Fixed bug GH-17275 (Fixed the calculation logic of dividend scale). + (Saki Takamachi) + +- 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) + . Fixed bug GH-17106 (ZEND_MATCH_ERROR misoptimization). (ilutov) + . Fixed bug GH-17162 (zend_array_try_init() with dtor can cause engine UAF). + (nielsdos) + . Fixed bug GH-17101 (AST->string does not reproduce constructor property + promotion correctly). (nielsdos) + . Fixed bug GH-17200 (Incorrect dynamic prop offset in hooked prop iterator). + (ilutov) + . Fixed bug GH-17216 (Trampoline crash on error). (nielsdos) + +- DBA: + . Skip test if inifile is disabled. (orlitzky) + +- DOM: + . Fixed bug GH-17145 (DOM memory leak). (nielsdos) + . Fixed bug GH-17201 (Dom\TokenList issues with interned string replace). + (nielsdos) + . Fixed bug GH-17224 (UAF in importNode). (nielsdos) + +- Embed: + . Make build command for program using embed portable. (dunglas) + +- FFI: + . Fixed bug #79075 (FFI header parser chokes on comments). (nielsdos) + . Fix memory leak on ZEND_FFI_TYPE_CHAR conversion failure. (nielsdos) + . Fixed bug GH-16013 and bug #80857 (Big endian issues). (Dmitry, nielsdos) + +- Fileinfo: + . Fixed bug GH-17039 (PHP 8.4: Incorrect MIME content type). (nielsdos) + +- FPM: + . Fixed bug GH-13437 (FPM: ERROR: scoreboard: failed to lock (already + locked)). (Jakub Zelenka) + . Fixed bug GH-17112 (Macro redefinitions). (cmb, nielsdos) + . Fixed bug GH-17208 (bug64539-status-json-encoding.phpt fail on 32-bits). + (nielsdos) + +- GD: + . Fixed bug GH-16255 (Unexpected nan value in ext/gd/libgd/gd_filter.c). + (nielsdos, cmb) + . Ported fix for libgd bug 276 (Sometimes pixels are missing when storing + images as BMPs). (cmb) + +- Gettext: + . Fixed bug GH-17202 (Segmentation fault ext/gettext/gettext.c + bindtextdomain()). (Michael Orlitzky) + +- Iconv: + . Fixed bug GH-17047 (UAF on iconv filter failure). (nielsdos) + +- LDAP: + . Fixed bug GH-17280 (ldap_search() fails when $attributes array has holes). + (nielsdos) + +- LibXML: + . Fixed bug GH-17223 (Memory leak in libxml encoding handling). (nielsdos) + +- MBString: + . Fixed bug GH-17112 (Macro redefinitions). (nielsdos, cmb) + +- Opcache: + . opcache_get_configuration() properly reports jit_prof_threshold. (cmb) + . Fixed bug GH-17140 (Assertion failure in JIT trace exit with + ZEND_FETCH_DIM_FUNC_ARG). (nielsdos, Dmitry) + . Fixed bug GH-17151 (Incorrect RC inference of op1 of FETCH_OBJ and + INIT_METHOD_CALL). (Dmitry, ilutov) + . Fixed bug GH-17246 (GC during SCCP causes segfault). (Dmitry) + . Fixed bug GH-17257 (UBSAN warning in ext/opcache/jit/zend_jit_vm_helpers.c). + (nielsdos, Dmitry) + +- PCNTL: + . Fix memory leak in cleanup code of pcntl_exec() when a non stringable + value is encountered past the first entry. (Girgias) + +- PgSql: + . Fixed bug GH-17158 (pg_fetch_result Shows Incorrect ArgumentCountError + Message when Called With 1 Argument). (nielsdos) + . Fixed further ArgumentCountError for calls with flexible + number of arguments. (David Carlier) + +- Phar: + . Fixed bug GH-17137 (Segmentation fault ext/phar/phar.c). (nielsdos) + +- SimpleXML: + . Fixed bug GH-17040 (SimpleXML's unset can break DOM objects). (nielsdos) + . Fixed bug GH-17153 (SimpleXML crash when using autovivification on + document). (nielsdos) + +- Sockets: + . Fixed bug GH-16276 (socket_strerror overflow handling with INT_MIN). + (David Carlier / cmb) + . Fixed overflow on SO_LINGER values setting, strengthening values check + on SO_SNDTIMEO/SO_RCVTIMEO for socket_set_option(). + (David Carlier) + +- SPL: + . Fixed bug GH-17198 (SplFixedArray assertion failure with get_object_vars). + (nielsdos) + . Fixed bug GH-17225 (NULL deref in spl_directory.c). (nielsdos) + +- Streams: + . Fixed bug GH-17037 (UAF in user filter when adding existing filter name due + to incorrect error handling). (nielsdos) + . Fixed bug GH-16810 (overflow on fopen HTTP wrapper timeout value). + (David Carlier) + . Fixed bug GH-17067 (glob:// wrapper doesn't cater to CWD for ZTS builds). + (cmb) + +- Windows: + . Hardened proc_open() against cmd.exe hijacking. (cmb) + +- XML: + . Fixed bug GH-1718 (unreachable program point in zend_hash). (nielsdos) + +19 Dec 2024, PHP 8.4.2 + +- BcMath: + . Fixed bug GH-16978 (Avoid unnecessary padding with leading zeros). + (Saki Takamachi) + +- COM: + . Fixed bug GH-16991 (Getting typeinfo of non DISPATCH variant segfaults). + (cmb) + +- Core: + . Fixed bug GH-16344 (setRawValueWithoutLazyInitialization() and + skipLazyInitialization() may change initialized proxy). (Arnaud) + . Fix is_zend_ptr() huge block comparison. (nielsdos) + . Fixed potential OOB read in zend_dirname() on Windows. (cmb) + . Fixed bug GH-15964 (printf() can strip sign of -INF). (divinity76, cmb) + +- Curl: + . Fix various memory leaks in curl mime handling. (nielsdos) + +- DBA: + . Fixed bug GH-16990 (dba_list() is now zero-indexed instead of using + resource ids) (kocsismate) + +- DOM: + . Fixed bug GH-16906 (Reloading document can cause UAF in iterator). + (nielsdos) + +- FPM: + . Fixed bug GH-16932 (wrong FPM status output). (Jakub Zelenka, James Lucas) + +- GMP: + . Fixed bug GH-16890 (array_sum() with GMP can loose precision (LLP64)). + (cmb) + +- Opcache: + . Fixed bug GH-16851 (JIT_G(enabled) not set correctly on other threads). + (dktapps) + . Fixed bug GH-16902 (Set of opcache tests fail zts+aarch64). (nielsdos) + . Fixed bug GH-16879 (JIT dead code skipping does not update call_level). + (nielsdos) + +- SAPI: + . Fixed bug GH-16998 (UBSAN warning in rfc1867). (nielsdos) + +- PHPDBG: + . Fixed bug GH-15208 (Segfault with breakpoint map and phpdbg_clear()). + (nielsdos) + +- Standard: + . Fixed bug GH-16905 (Internal iterator functions can't handle UNDEF + properties). (nielsdos) + . Fixed bug GH-16957 (Assertion failure in array_shift with + self-referencing array). (nielsdos) + +- Streams: + . Fixed network connect poll interuption handling. (Jakub Zelenka) + +- Windows: + . Fixed bug GH-16849 (Error dialog causes process to hang). (cmb) + . Windows Server 2025 is now properly reported. (cmb) + +21 Nov 2024, PHP 8.4.1 + +- BcMath: + . [RFC] Add bcfloor, bcceil and bcround to BCMath. (Saki Takamachi) + . Improve performance. (Saki Takamachi, nielsdos) + . Adjust bcround()'s $mode parameter to only accept the RoundingMode + enum. (timwolla, saki) + . Fixed LONG_MAX in BCMath ext. (Saki Takamachi) + . Fixed bcdiv() div by one. (Saki Takamachi) + . [RFC] Support object types in BCMath. (Saki Takamachi) + . bcpow() performance improvement. (Jorg Sowa) + . ext/bcmath: Check for scale overflow. (SakiTakamachi) + . [RFC] ext/bcmath: Added bcdivmod. (SakiTakamachi) + . Fix GH-15968 (Avoid converting objects to strings in operator calculations). + (SakiTakamachi) + . Fixed bug GH-16265 (Added early return case when result is 0) + (Saki Takamachi). + . Fixed bug GH-16262 (Fixed a bug where size_t underflows) (Saki Takamachi). + . Fixed GH-16236 (Fixed a bug in BcMath\Number::pow() and bcpow() when + raising negative powers of 0) (Saki Takamachi). + +- Core: + . Added zend_call_stack_get implementation for NetBSD, DragonFlyBSD, + Solaris and Haiku. (David Carlier) + . Enabled ifunc checks on FreeBSD from the 12.x releases. (Freaky) + . Changed the type of PHP_DEBUG and PHP_ZTS constants to bool. (haszi) + . Fixed bug GH-13142 (Undefined variable name is shortened when contains \0). + (nielsdos) + . Fixed bug GH-13178 (Iterator positions incorrect when converting packed + array to hashed). (ilutov) + . Fixed zend fiber build for solaris default mode (32 bits). (David Carlier) + . Fixed zend call stack size for macOs/arm64. (David Carlier) + . Added support for Zend Max Execution Timers on FreeBSD. (Kévin Dunglas) + . Ensure fiber stack is not backed by THP. (crrodriguez) + . Implement GH-13609 (Dump wrapped object in WeakReference class). (nielsdos) + . Added sparc64 arch assembly support for zend fiber. (Claudio Jeker) + . Fixed GH-13581 no space available for TLS on NetBSD. (Paul Ripke) + . Added fiber Sys-V loongarch64 support. (qiangxuhui) + . Adjusted closure names to include the parent function's name. (timwolla) + . Improve randomness of uploaded file names and files created by tempnam(). + (Arnaud) + . Added gc and shutdown callbacks to zend_mm custom handlers. + (Florian Engelhardt) + . Fixed bug GH-14650 (Compute the size of pages before allocating memory). + (Julien Voisin) + . Fixed bug GH-11928 (The --enable-re2c-cgoto doesn't add the -g flag). + (Peter Kokot) + . Added the #[\Deprecated] attribute. (beberlei, timwolla) + . Fixed GH-11389 (Allow suspending fibers in destructors). (Arnaud, trowski) + . Fixed bug GH-14801 (Fix build for armv7). (andypost) + . Implemented property hooks RFC. (ilutov) + . Fix GH-14978 (The xmlreader extension phpize build). (Peter Kokot) + . Throw Error exception when encountering recursion during comparison, rather + than fatal error. (ilutov) + . Added missing cstddef include for C++ builds. (cmb) + . Updated build system scripts config.guess to 2024-07-27 and config.sub to + 2024-05-27. (Peter Kokot) + . Fixed bug GH-15240 (Infinite recursion in trait hook). (ilutov) + . Fixed bug GH-15140 (Missing variance check for abstract set with asymmetric + type). (ilutov) + . Fixed bug GH-15181 (Disabled output handler is flushed again). (cmb) + . Passing E_USER_ERROR to trigger_error() is now deprecated. (Girgias) + . Fixed bug GH-15292 (Dynamic AVX detection is broken for MSVC). (nielsdos) + . Using "_" as a class name is now deprecated. (Girgias) + . Exiting a namespace now clears seen symbols. (ilutov) + . The exit (and die) language constructs now behave more like a function. + They can be passed liked callables, are affected by the strict_types + declare statement, and now perform the usual type coercions instead of + casting any non-integer value to a string. + As such, passing invalid types to exit/die may now result in a TypeError + being thrown. (Girgias) + . Fixed bug GH-15438 (Hooks on constructor promoted properties without + visibility are ignored). (ilutov) + . Fixed bug GH-15419 (Missing readonly+hook incompatibility check for readonly + classes). (ilutov) + . Fixed bug GH-15187 (Various hooked object iterator issues). (ilutov) + . Fixed bug GH-15456 (Crash in get_class_vars() on virtual properties). + (ilutov) + . Fixed bug GH-15501 (Windows HAVE_
_H macros defined to 1 or + undefined). (Peter Kokot) + . Implemented asymmetric visibility for properties. (ilutov) + . Fixed bug GH-15644 (Asymmetric visibility doesn't work with hooks). (ilutov) + . Implemented lazy objects RFC. (Arnaud) + . Fixed bug GH-15686 (Building shared iconv with external iconv library). + (Peter Kokot, zeriyoshi) + . Fixed missing error when adding asymmetric visibility to unilateral virtual + property. (ilutov) + . Fixed bug GH-15693 (Unnecessary include in main.c bloats binary). + (nielsdos) + . Fixed bug GH-15731 (AllowDynamicProperties validation should error on + enums). (DanielEScherzer) + . Fixed bug GH-16040 (Use-after-free of object released in hook). (ilutov) + . Fixed bug GH-16026 (Reuse of dtor fiber during shutdown). (Arnaud) + . Fixed bug GH-15999 (zend_std_write_property() assertion failure with lazy + objects). (Arnaud) + . Fixed bug GH-15960 (Foreach edge cases with lazy objects). (Arnaud) + . Fixed bug GH-16185 (Various hooked object iterator issues). (ilutov) + . Fixed bug OSS-Fuzz #371445205 (Heap-use-after-free in attr_free). + (nielsdos) + . Fixed missing error when adding asymmetric visibility to static properties. + (ilutov) + . Fixed bug OSS-Fuzz #71407 (Null-dereference WRITE in + zend_lazy_object_clone). (Arnaud) + . Fixed bug GH-16574 (Incorrect error "undefined method" messages). + (nielsdos) + . Fixed bug GH-16577 (EG(strtod_state).freelist leaks with opcache.preload). + (nielsdos) + . Fixed bug GH-16615 (Assertion failure in zend_std_read_property). (Arnaud) + . Fixed bug GH-16342 (Added ReflectionProperty::isLazy()). (Arnaud) + . Fixed bug GH-16725 (Incorrect access check for non-hooked props in hooked + object iterator). (ilutov) + +- Curl: + . Deprecated the CURLOPT_BINARYTRANSFER constant. (divinity76) + . Bumped required libcurl version to 7.61.0. (Ayesh) + . Added feature_list key to the curl_version() return value. (Ayesh) + . Added constants CURL_HTTP_VERSION_3 (libcurl 7.66) and CURL_HTTP_VERSION_3ONLY + (libcurl 7.88) as options for CURLOPT_HTTP_VERSION (Ayesh Karunaratne) + . Added CURLOPT_TCP_KEEPCNT to set the number of probes to send before + dropping the connection. (David Carlier) + . Added CURLOPT_PREREQFUNCTION Curl option to set a custom callback + after the connection is established, but before the request is + performed. (Ayesh Karunaratne) + . Added CURLOPT_SERVER_RESPONSE_TIMEOUT, which was formerly known as + CURLOPT_FTP_RESPONSE_TIMEOUT. (Ayesh Karunaratne) + . The CURLOPT_DNS_USE_GLOBAL_CACHE option is now silently ignored. (Ayesh Karunaratne) + . Added CURLOPT_DEBUGFUNCTION as a Curl option. (Ayesh Karunaratne) + . Fixed bug GH-16359 (crash with curl_setopt* CURLOPT_WRITEFUNCTION + without null callback). (David Carlier) + . Fixed bug GH-16723 (CURLMOPT_PUSHFUNCTION issues). (cmb) + +- Date: + . Added DateTime[Immutable]::createFromTimestamp. (Marc Bennewitz) + . Added DateTime[Immutable]::[get|set]Microsecond. (Marc Bennewitz) + . Constants SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING, and SUNFUNCS_RET_DOUBLE + are now deprecated. (Jorg Sowa) + . Fixed bug GH-13773 (DatePeriod not taking into account microseconds for end + date). (Mark Bennewitz, Derick) + +- DBA: + . Passing null or false to dba_key_split() is deprecated. (Grigias) + +- Debugging: + . Fixed bug GH-15923 (GDB: Python Exception : + exceptions must derive from BaseException). (nielsdos) + +- DOM: + . Added DOMNode::compareDocumentPosition(). (nielsdos) + . Implement #53655 (Improve speed of DOMNode::C14N() on large XML documents). + (nielsdos) + . Fix cloning attribute with namespace disappearing namespace. (nielsdos) + . Implement DOM HTML5 parsing and serialization RFC. (nielsdos) + . Fix DOMElement->prefix with empty string creates bogus prefix. (nielsdos) + . Handle OOM more consistently. (nielsdos) + . Implemented "Improve callbacks in ext/dom and ext/xsl" RFC. (nielsdos) + . Added DOMXPath::quote() static method. (divinity76) + . Implemented opt-in ext/dom spec compliance RFC. (nielsdos) + . Fixed bug #79701 (getElementById does not correctly work with duplicate + definitions). (nielsdos) + . Implemented "New ext-dom features in PHP 8.4" RFC. (nielsdos) + . Fixed GH-14698 (segfault on DOM node dereference). (David Carlier) + . Improve support for template elements. (nielsdos) + . Fix trampoline leak in xpath callables. (nielsdos) + . Throw instead of silently failing when creating a too long text node in + (DOM)ParentNode and (DOM)ChildNode. (nielsdos) + . Fixed bug GH-15192 (Segmentation fault in dom extension + (html5_serializer)). (nielsdos) + . Deprecated DOM_PHP_ERR constant. (nielsdos) + . Removed DOMImplementation::getFeature(). (nielsdos) + . Fixed bug GH-15331 (Element::$substitutedNodeValue test failed). (nielsdos) + . Fixed bug GH-15570 (Segmentation fault (access null pointer) in + ext/dom/html5_serializer.c). (nielsdos) + . Fixed bug GH-13988 (Storing DOMElement consume 4 times more memory in + PHP 8.1 than in PHP 8.0). (nielsdos) + . Fix XML serializer errata: xmlns="" serialization should be allowed. + (nielsdos) + . Fixed bug GH-15910 (Assertion failure in ext/dom/element.c). (nielsdos) + . Fix unsetting DOM properties. (nielsdos) + . Fixed bug GH-16190 (Using reflection to call Dom\Node::__construct + causes assertion failure). (nielsdos) + . Fix edge-case in DOM parsing decoding. (nielsdos) + . Fixed bug GH-16465 (Heap buffer overflow in DOMNode->getElementByTagName). + (nielsdos) + . Fixed bug GH-16594 (Assertion failure in DOM -> before). (nielsdos) + +- Fileinfo: + . Update to libmagic 5.45. (nielsdos) + . Fixed bug #65106 (PHP fails to compile ext/fileinfo). (Guillaume Outters) + +- FPM: + . Implement GH-12385 (flush headers without body when calling flush()). + (nielsdos) + . Added DragonFlyBSD system to the list which set FPM_BACKLOG_DEFAULT + to SOMAXCONN. (David Carlier) + . /dev/poll events.mechanism for Solaris/Illumos setting had been retired. + (David Carlier) + . Added memory peak to the scoreboard / status page. (Flávio Heleno) + +- FTP: + . Removed the deprecated inet_ntoa call support. (David Carlier) + . Fixed bug #63937 (Upload speed 10 times slower with PHP). (nielsdos) + +- GD: + . Fix parameter numbers and missing alpha check for imagecolorset(). + (Giovanni Giacobbi) + . imagepng/imagejpeg/imagewep/imageavif now throw an exception on + invalid quality parameter. (David Carlier) + . Check overflow/underflow for imagescale/imagefilter. (David Carlier) + . Added gdImageClone to bundled libgd. (David Carlier) + +- Gettext: + . bind_textdomain_codeset, textdomain and d(*)gettext functions + now throw an exception on empty domain. (David Carlier) + +- GMP: + . The GMP class is now final and cannot be extended anymore. (Girgias) + . RFC: Change GMP bool cast behavior. (Saki Takamachi) + +- Hash: + . Changed return type of hash_update() to true. (nielsdos) + . Added HashContext::__debugInfo(). (timwolla) + . Deprecated passing incorrect data types for options to ext/hash functions. + (nielsdos) + . Added SSE2 and SHA-NI implementation of SHA-256. (timwolla, Colin Percival, + Graham Percival) + . Fix GH-15384 (Build fails on Alpine / Musl for amd64). (timwolla) + . Fixed bug GH-15742 (php_hash_sha.h incompatible with C++). (cmb) + +- IMAP: + . Moved to PECL. (Derick Rethans) + +- Intl: + . Added IntlDateFormatter::PATTERN constant. (David Carlier) + . Fixed Numberformatter::__construct when the locale is invalid, now + throws an exception. (David Carlier) + . Added NumberFormatter::ROUND_TOWARD_ZERO and ::ROUND_AWAY_FROM_ZERO as + aliases for ::ROUND_DOWN and ::ROUND_UP. (Jorg Sowa) + . Added NumberFormatter::ROUND_HALFODD. (Ayesh Karunaratne) + . Added PROPERTY_IDS_UNARY_OPERATOR, PROPERTY_ID_COMPAT_MATH_START and + PROPERTY_ID_COMPAT_MATH_CONTINUE constants. (David Carlier) + . Added IntlDateFormatter::getIanaID/intltz_get_iana_id method/function. + (David Carlier) + . Set to C++17 standard for icu 74 and onwards. (David Carlier) + . resourcebundle_get(), ResourceBundle::get(), and accessing offsets on a + ResourceBundle object now throw: + - TypeError for invalid offset types + - ValueError for an empty string + - ValueError if the integer index does not fit in a signed 32 bit integer + . ResourceBundle::get() now has a tentative return type of: + ResourceBundle|array|string|int|null + . Added the new Grapheme function grapheme_str_split. (youkidearitai) + . Added IntlDateFormatter::parseToCalendar. (David Carlier) + . Added SpoofChecker::setAllowedChars to set unicode chars ranges. + (David Carlier) + +- LDAP: + . Added LDAP_OPT_X_TLS_PROTOCOL_MAX/LDAP_OPT_X_TLS_PROTOCOL_TLS1_3 + constants. (StephenWall) + +- LibXML: + . Added LIBXML_RECOVER constant. (nielsdos) + . libxml_set_streams_context() now throws immediately on an invalid context + instead of at the use-site. (nielsdos) + . Added LIBXML_NO_XXE constant. (nielsdos) + +- MBString: + . Added mb_trim, mb_ltrim and mb_rtrim. (Yuya Hamada) + . Added mb_ucfirst and mb_lcfirst. (Yuya Hamada) + . Updated Unicode data tables to Unicode 15.1. (Ayesh Karunaratne) + . Fixed bug GH-15824 (mb_detect_encoding(): Argument $encodings contains + invalid encoding "UTF8"). (Yuya Hamada) + . Updated Unicode data tables to Unicode 16.0. (Ayesh Karunaratne) + +- Mysqli: + . The mysqli_ping() function and mysqli::ping() method are now deprecated, + as the reconnect feature was removed in PHP 8.2. (Kamil Tekiela) + . The mysqli_kill() function and mysqli::kill() method are now deprecated. + If this functionality is needed a SQL "KILL" command can be used instead. + (Kamil Tekiela) + . The mysqli_refresh() function and mysqli::refresh() method are now deprecated. + If this functionality is needed a SQL "FLUSH" command can be used instead. + (Kamil Tekiela) + . Passing explicitly the $mode parameter to mysqli_store_result() has been + deprecated. As the MYSQLI_STORE_RESULT_COPY_DATA constant was only used in + conjunction with this function it has also been deprecated. (Girgias) + +- MySQLnd: + . Fixed bug GH-13440 (PDO quote bottleneck). (nielsdos) + . Fixed bug GH-10599 (Apache crash on Windows when using a self-referencing + anonymous function inside a class with an active mysqli connection). + (nielsdos) + +- Opcache: + . Added large shared segments support for FreeBSD. (David Carlier) + . If JIT is enabled, PHP will now exit with a fatal error on startup in case + of JIT startup initialization issues. (danog) + . Increased the maximum value of opcache.interned_strings_buffer to 32767 on + 64bit archs. (Arnaud) + . Fixed bug GH-13834 (Applying non-zero offset 36 to null pointer in + zend_jit.c). (nielsdos) + . Fixed bug GH-14361 (Deep recursion in zend_cfg.c causes segfault). + (nielsdos) + . Fixed bug GH-14873 (PHP 8.4 min function fails on typed integer). + (nielsdos) + . Fixed bug GH-15490 (Building of callgraph modifies preloaded symbols). + (ilutov) + . Fixed bug GH-15178 (Assertion in tracing JIT on hooks). (ilutov) + . Fixed bug GH-15657 (Segmentation fault in dasm_x86.h). (nielsdos) + . Added opcache_jit_blacklist() function. (Bob) + . Fixed bug GH-16009 (Segmentation fault with frameless functions and + undefined CVs). (nielsdos) + . Fixed bug GH-16186 (Assertion failure in Zend/zend_operators.c). (Arnaud) + . Fixed bug GH-16572 (Incorrect result with reflection in low-trigger JIT). + (nielsdos) + . Fixed GH-16839 (Error on building Opcache JIT for Windows ARM64). (cmb) + +- OpenSSL: + . Fixed bug #80269 (OpenSSL sets Subject wrong with extraattribs parameter). + (Jakub Zelenka) + . Implement request #48520 (openssl_csr_new - allow multiple values in DN). + (Jakub Zelenka) + . Introduced new serial_hex parameter to openssl_csr_sign. (Jakub Zelenka, + Florian Sowade) + . Added X509_PURPOSE_OCSP_HELPER and X509_PURPOSE_TIMESTAMP_SIGN constants. + (Vincent Jardin) + . Bumped minimum required OpenSSL version to 1.1.1. (Ayesh Karunaratne) + . Added compile-time option --with-openssl-legacy-provider to enable legacy + provider. (Adam Saponara) + . Added support for Curve25519 + Curve448 based keys. (Manuel Mausz) + . Fixed bug GH-13343 (openssl_x509_parse should not allow omitted seconds in + UTCTimes). (Jakub Zelenka) + . Bumped minimum required OpenSSL version to 1.1.0. (cmb) + . Implement GH-13514 PASSWORD_ARGON2 from OpenSSL 3.2. (Remi) + +- Output: + . Clear output handler status flags during handler initialization. (haszi) + . Fixed bug with url_rewriter.hosts not used by output_add_rewrite_var(). + (haszi) + +- PCNTL: + . Added pcntl_setns for Linux. (David Carlier) + . Added pcntl_getcpuaffinity/pcntl_setcpuaffinity. (David Carlier) + . Updated pcntl_get_signal_handler signal id upper limit to be + more in line with platforms limits. (David Carlier) + . Added pcntl_getcpu for Linux/FreeBSD/Solaris/Illumos. (David Carlier) + . Added pcntl_getqos_class/pcntl_setqos_class for macOs. (David Carlier) + . Added SIGCKPT/SIGCKPTEXIT constants for DragonFlyBSD. (David Carlier) + . Added FreeBSD's SIGTRAP handling to pcntl_siginfo_to_zval. (David Carlier) + . Added POSIX pcntl_waitid. (Vladimir Vrzić) + . Fixed bug GH-16769: (pcntl_sigwaitinfo aborts on signal value + as reference). (David Carlier) + +- PCRE: + . Upgrade bundled pcre2lib to version 10.43. (nielsdos) + . Add "/r" modifier. (Ayesh) + . Upgrade bundled pcre2lib to version 10.44. (Ayesh) + . Fixed GH-16189 (underflow on offset argument). (David Carlier) + . Fix UAF issues with PCRE after request shutdown. (nielsdos) + +- PDO: + . Fixed setAttribute and getAttribute. (SakiTakamachi) + . Implemented PDO driver-specific subclasses RFC. (danack, kocsismate) + . Added support for PDO driver-specific SQL parsers. (Matteo Beccati) + . Fixed bug GH-14792 (Compilation failure on pdo_* extensions). + (Peter Kokot) + . mysqlnd: support ER_CLIENT_INTERACTION_TIMEOUT. (Appla) + . The internal header php_pdo_int.h is no longer installed; it is not + supposed to be used by PDO drivers. (cmb) + . Fixed bug GH-16167 (Prevent mixing PDO sub-classes with different DSN). + (kocsismate) + . Fixed bug GH-16314 ("Pdo\Mysql object is uninitialized" when opening a + persistent connection). (kocsismate) + +- PDO_DBLIB: + . Fixed setAttribute and getAttribute. (SakiTakamachi) + . Added class Pdo\DbLib. (danack, kocsismate) + +- PDO_Firebird: + . Fixed setAttribute and getAttribute. (SakiTakamachi) + . Feature: Add transaction isolation level and mode settings to pdo_firebird. + (SakiTakamachi) + . Added class Pdo\Firebird. (danack, kocsismate) + . Added Pdo\Firebird::ATTR_API_VERSION. (SakiTakamachi) + . Added getApiVersion() and removed from getAttribute(). + (SakiTakamachi) + . Supported Firebird 4.0 datatypes. (sim1984) + . Support proper formatting of time zone types. (sim1984) + . Fixed GH-15604 (Always make input parameters nullable). (sim1984) + +- PDO_MYSQL: + . Fixed setAttribute and getAttribute. (SakiTakamachi) + . Added class Pdo\Mysql. (danack, kocsismate) + . Added custom SQL parser. (Matteo Beccati) + . Fixed GH-15949 (PDO_MySQL not properly quoting PDO_PARAM_LOB binary + data). (mbeccati, lcobucci) + +- PDO_ODBC: + . Added class Pdo\Odbc. (danack, kocsismate) + +- PDO_PGSQL: + . Fixed GH-12423, DSN credentials being prioritized over the user/password + PDO constructor arguments. (SakiTakamachi) + . Fixed native float support with pdo_pgsql query results. (Yurunsoft) + . Added class Pdo\Pgsql. (danack, kocsismate) + . Retrieve the memory usage of the query result resource. (KentarouTakeda) + . Added Pdo\Pgsql::setNoticeCallBack method to receive DB notices. + (outtersg) + . Added custom SQL parser. (Matteo Beccati) + . Fixed GH-15986 (Double-free due to Pdo\Pgsql::setNoticeCallback()). (cmb, + nielsdos) + . Fixed GH-12940 (Using PQclosePrepared when available instead of + the DEALLOCATE command to free statements resources). (David Carlier) + . Remove PGSQL_ATTR_RESULT_MEMORY_SIZE constant as it is provided by + the new PDO Subclass as Pdo\Pgsql::ATTR_RESULT_MEMORY_SIZE. (Girgias) + +- PDO_SQLITE: + . Added class Pdo\Sqlite. (danack, kocsismate) + . Fixed bug #81227 (PDO::inTransaction reports false when in transaction). + (nielsdos) + . Added custom SQL parser. (Matteo Beccati) + +- PHPDBG: + . array out of bounds, stack overflow handled for segfault handler on windows. + (David Carlier) + . Fixed bug GH-16041 (Support stack limit in phpdbg). (Arnaud) + +- PGSQL: + . Added the possibility to have no conditions for pg_select. (OmarEmaraDev) + . Persistent connections support the PGSQL_CONNECT_FORCE_RENEW flag. + (David Carlier) + . Added pg_result_memory_size to get the query result memory usage. + (KentarouTakeda) + . Added pg_change_password to alter an user's password. (David Carlier) + . Added pg_put_copy_data/pg_put_copy_end to send COPY commands and signal + the end of the COPY. (David Carlier) + . Added pg_socket_poll to poll on the connection. (David Carlier) + . Added pg_jit to get infos on server JIT support. (David Carlier) + . Added pg_set_chunked_rows_size to fetch results per chunk. (David Carlier) + . pg_convert/pg_insert/pg_update/pg_delete ; regexes are now cached. + (David Carlier) + +- Phar: + . Fixed bug GH-12532 (PharData created from zip has incorrect timestamp). + (nielsdos) + +- POSIX: + . Added POSIX_SC_CHILD_MAX and POSIX_SC_CLK_TCK constants. (Jakub Zelenka) + . Updated posix_isatty to set the error number on file descriptors. + (David Carlier) + +- PSpell: + . Moved to PECL. (Derick Rethans) + +- Random: + . Fixed bug GH-15094 (php_random_default_engine() is not C++ conforming). + (cmb) + . lcg_value() is now deprecated. (timwolla) + +- Readline: + . Fixed readline_info, rl_line_buffer_length/rl_len globals on update. + (David Carlier) + . Fixed bug #51558 (Shared readline build fails). (Peter Kokot) + . Fixed UAF with readline_info(). (David Carlier) + +- Reflection: + . Implement GH-12908 (Show attribute name/class in ReflectionAttribute dump). + (nielsdos) + . Make ReflectionGenerator::getFunction() legal after generator termination. + (timwolla) + . Added ReflectionGenerator::isClosed(). (timwolla) + . Fixed bug GH-15718 (Segfault on ReflectionProperty::get{Hook,Hooks}() on + dynamic properties). (DanielEScherzer) + . Fixed bug GH-15694 (ReflectionProperty::isInitialized() is incorrect for + hooked properties). (ilutov) + . Add missing ReflectionProperty::hasHook[s]() methods. (ilutov) + . Add missing ReflectionProperty::isFinal() method. (ilutov) + . Fixed bug GH-16122 (The return value of ReflectionFunction::getNamespaceName() + and ReflectionFunction::inNamespace() for closures is incorrect). (timwolla) + . Fixed bug GH-16162 (No ReflectionProperty::IS_VIRTUAL) (DanielEScherzer) + . Fixed the name of the second parameter of + ReflectionClass::resetAsLazyGhost(). (Arnaud) + +- Session: + . INI settings session.sid_length and session.sid_bits_per_character are now + deprecated. (timwolla) + . Emit warnings for non-positive values of session.gc_divisor and negative values + of session.gc_probability. (Jorg Sowa) + . Fixed bug GH-16590 (UAF in session_encode()). (nielsdos) + +- SimpleXML: + . Fix signature of simplexml_import_dom(). (nielsdos) + +- SNMP: + . Removed the deprecated inet_ntoa call support. (David Carlier) + +- SOAP: + . Add support for clark notation for namespaces in class map. (lxShaDoWxl) + . Mitigate #51561 (SoapServer with a extented class and using sessions, + lost the setPersistence()). (nielsdos) + . Fixed bug #49278 (SoapClient::__getLastResponseHeaders returns NULL if + wsdl operation !has output). (nielsdos) + . Fixed bug #44383 (PHP DateTime not converted to xsd:datetime). (nielsdos) + . Fixed bug GH-11941 (soap with session persistence will silently fail when + "session" built as a shared object). (nielsdos) + . Passing an int to SoapServer::addFunction() is now deprecated. + If all PHP functions need to be provided flatten the array returned by + get_defined_functions(). (Girgias) + . The SOAP_FUNCTIONS_ALL constant is now deprecated. (Girgias) + . Fixed bug #61525 (SOAP functions require at least one space after HTTP + header colon). (nielsdos) + . Implement request #47317 (SoapServer::__getLastResponse()). (nielsdos) + +- Sockets: + . Removed the deprecated inet_ntoa call support. (David Carlier) + . Added the SO_EXECLUSIVEADDRUSE windows constant. (David Carlier) + . Added the SOCK_CONN_DGRAM/SOCK_DCCP netbsd constants. (David Carlier) + . Added multicast group support for ipv4 on FreeBSD. (jonathan@tangential.ca) + . Added the TCP_SYNCNT constant for Linux to set number of attempts to send + SYN packets from the client. (David Carlier) + . Added the SO_EXCLBIND constant for exclusive socket binding on illumos/solaris. + (David Carlier) + . Updated the socket_create_listen backlog argument default value to SOMAXCONN. + (David Carlier) + . Added the SO_NOSIGPIPE constant to control the generation of SIGPIPE for + macOs and FreeBSD. (David Carlier) + . Added SO_LINGER_SEC for macOs, true equivalent of SO_LINGER in other platforms. + (David Carlier) + . Add close-on-exec on socket created with socket_accept on unixes. (David Carlier) + . Added IP_PORTRANGE* constants for BSD systems to control ephemeral port + ranges. (David Carlier) + . Added SOCK_NONBLOCK/SOCK_CLOEXEC constants for socket_create and + socket_create_pair to apply O_NONBLOCK/O_CLOEXEC flags to the + newly created sockets. (David Carlier) + . Added SO_BINDTOIFINDEX to bind a socket to an interface index. + (David Carlier) + +- Sodium: + . Add support for AEGIS-128L and AEGIS-256. (jedisct1) + . Enable AES-GCM on aarch64 with the ARM crypto extensions. (jedisct1) + +- SPL: + . Implement SeekableIterator for SplObjectStorage. (nielsdos) + . The SplFixedArray::__wakeup() method has been deprecated as it implements + __serialize() and __unserialize() which need to be overwritten instead. + (TysonAndre) + . Passing a non-empty string for the $escape parameter of: + - SplFileObject::setCsvControl() + - SplFileObject::fputcsv() + - SplFileObject::fgetcsv() + is now deprecated. (Girgias) + +- Standard: + . Implement GH-12188 (Indication for the int size in phpinfo()). (timwolla) + . Partly fix GH-12143 (Incorrect round() result for 0.49999999999999994). + (timwolla) + . Fix GH-12252 (round(): Validate the rounding mode). (timwolla) + . Increase the default BCrypt cost to 12. (timwolla) + . Fixed bug GH-12592 (strcspn() odd behaviour with NUL bytes and empty mask). + (nielsdos) + . Removed the deprecated inet_ntoa call support. (David Carlier) + . Cast large floats that are within int range to int in number_format so + the precision is not lost. (Marc Bennewitz) + . Add support for 4 new rounding modes to the round() function. (Jorg Sowa) + . debug_zval_dump() now indicates whether an array is packed. (Max Semenik) + . Fix GH-12143 (Optimize round). (SakiTakamachi) + . Changed return type of long2ip to string from string|false. (Jorg Sowa) + . Fix GH-12143 (Extend the maximum precision round can handle by one digit). + (SakiTakamachi) + . Added the http_get_last_response_headers() and + http_clear_last_response_headers() that allows retrieving the same content + as the magic $http_response_header variable. + . Add php_base64_encode_ex() API. (Remi) + . Implemented "Raising zero to the power of negative number" RFC. (Jorg Sowa) + . Added array_find(), array_find_key(), array_all(), and array_any(). (josh) + . Change highlight_string() and print_r() return type to string|true. (Ayesh) + . Fix references in request_parse_body() options array. (nielsdos) + . Add RoundingMode enum. (timwolla, saki) + . Unserializing the uppercase 'S' tag is now deprecated. (timwolla) + . Enables crc32 auxiliary detection on OpenBSD. (David Carlier) + . Passing a non-empty string for the $escape parameter of: + - fputcsv() + - fgetcsv() + - str_getcsv() + is now deprecated. (Girgias) + . The str_getcsv() function now throws ValueErrors when the $separator and + $enclosure arguments are not one byte long, or if the $escape is not one + byte long or the empty string. This aligns the behaviour to be identical + to that of fputcsv() and fgetcsv(). (Girgias) + . php_uname() now throws ValueErrors on invalid inputs. (Girgias) + . The "allowed_classes" option for unserialize() now throws TypeErrors and + ValueErrors if it is not an array of class names. (Girgias) + . Implemented GH-15685 (improve proc_open error reporting on Windows). (cmb) + . Add support for backed enums in http_build_query(). (ilutov) + . Fixed bug GH-15982 (Assertion failure with array_find when references are + involved). (nielsdos) + . Fixed parameter names of fpow() to be identical to pow(). (Girgias) + +- Streams: + . Implemented GH-15155 (Stream context is lost when custom stream wrapper is + being filtered). (Quentin Dreyer) + +- Tidy: + . Failures in the constructor now throw exceptions rather than emitting + warnings and having a broken object. (nielsdos) + . Add tidyNode::getNextSibling() and tidyNode::getPreviousSibling(). + (nielsdos) + +- Windows: + . Update the icon of the Windows executables, e.g. php.exe. (Ayesh, + Nurudin Imširović) + . Fixed bug GH-16199 (GREP_HEADER() is broken). (Peter Kokot) + +- XML: + . Added XML_OPTION_PARSE_HUGE parser option. (nielsdos) + . Fixed bug #81481 (xml_get_current_byte_index limited to 32-bit numbers on + 64-bit builds). (nielsdos) + . The xml_set_object() function has been deprecated. (Girgias) + . Passing non-callable strings to the xml_set_*_handler() functions is now + deprecated. (Girgias) + +- XMLReader: + . Declares class constant types. (Ayesh) + . Add XMLReader::fromStream(), XMLReader::fromUri(), XMLReader::fromString(). (nielsdos) + . Fixed bug GH-15123 (var_dump doesn't actually work on XMLReader). + (nielsdos) + +- XMLWriter: + . Add XMLWriter::toStream(), XMLWriter::toUri(), XMLWriter::toMemory(). (nielsdos) + +- XSL: + . Implement request #64137 (XSLTProcessor::setParameter() should allow both + quotes to be used). (nielsdos) + . Implemented "Improve callbacks in ext/dom and ext/xsl" RFC. (nielsdos) + . Added XSLTProcessor::$maxTemplateDepth and XSLTProcessor::$maxTemplateVars. + (nielsdos) + . Fix trampoline leak in xpath callables. (nielsdos) + +- Zip: + . Added ZipArchive::ER_TRUNCATED_ZIP added in libzip 1.11. (Remi) diff '--color=auto' -Naur php-8.4.18/sapi/cgi/Makefile.frag php-8.4.20RC1/sapi/cgi/Makefile.frag --- php-8.4.18/sapi/cgi/Makefile.frag 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/sapi/cgi/Makefile.frag 2026-04-01 04:35:36.023945498 +0000 @@ -6,7 +6,7 @@ install-cgi: $(SAPI_CGI_PATH) @echo "Installing PHP CGI binary: $(INSTALL_ROOT)$(bindir)/" @$(mkinstalldirs) $(INSTALL_ROOT)$(bindir) - @$(INSTALL) -m 0755 $(SAPI_CGI_PATH) $(INSTALL_ROOT)$(bindir)/$(program_prefix)php-cgi$(program_suffix)$(EXEEXT) + @$(LIBTOOL) --mode=install $(INSTALL) -m 0755 $(SAPI_CGI_PATH) $(INSTALL_ROOT)$(bindir)/$(program_prefix)php-cgi$(program_suffix)$(EXEEXT) @echo "Installing PHP CGI man page: $(INSTALL_ROOT)$(mandir)/man1/" @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 @$(INSTALL_DATA) sapi/cgi/php-cgi.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)php-cgi$(program_suffix).1 diff '--color=auto' -Naur php-8.4.18/sapi/cli/Makefile.frag php-8.4.20RC1/sapi/cli/Makefile.frag --- php-8.4.18/sapi/cli/Makefile.frag 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/sapi/cli/Makefile.frag 2026-04-01 04:35:36.024028806 +0000 @@ -6,7 +6,7 @@ install-cli: $(SAPI_CLI_PATH) @echo "Installing PHP CLI binary: $(INSTALL_ROOT)$(bindir)/" @$(mkinstalldirs) $(INSTALL_ROOT)$(bindir) - @$(INSTALL) -m 0755 $(SAPI_CLI_PATH) $(INSTALL_ROOT)$(bindir)/$(program_prefix)php$(program_suffix)$(EXEEXT) + @$(LIBTOOL) --mode=install $(INSTALL) -m 0755 $(SAPI_CLI_PATH) $(INSTALL_ROOT)$(bindir)/$(program_prefix)php$(program_suffix)$(EXEEXT) @echo "Installing PHP CLI man page: $(INSTALL_ROOT)$(mandir)/man1/" @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 @$(INSTALL_DATA) sapi/cli/php.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)php$(program_suffix).1 diff '--color=auto' -Naur php-8.4.18/sapi/fpm/Makefile.frag php-8.4.20RC1/sapi/fpm/Makefile.frag --- php-8.4.18/sapi/fpm/Makefile.frag 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/sapi/fpm/Makefile.frag 2026-04-01 04:35:36.024117563 +0000 @@ -8,7 +8,7 @@ @$(mkinstalldirs) $(INSTALL_ROOT)$(sbindir) @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run - @$(INSTALL) -m 0755 $(SAPI_FPM_PATH) $(INSTALL_ROOT)$(sbindir)/$(program_prefix)php-fpm$(program_suffix)$(EXEEXT) + @$(LIBTOOL) --mode=install $(INSTALL) -m 0755 $(SAPI_FPM_PATH) $(INSTALL_ROOT)$(sbindir)/$(program_prefix)php-fpm$(program_suffix)$(EXEEXT) @if test -f "$(INSTALL_ROOT)$(sysconfdir)/php-fpm.conf"; then \ echo "Installing PHP FPM defconfig: skipping"; \ diff '--color=auto' -Naur php-8.4.18/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt php-8.4.20RC1/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt --- php-8.4.18/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt 2026-04-01 04:35:36.024195120 +0000 @@ -6,7 +6,7 @@ --FILE-- diff '--color=auto' -Naur php-8.4.18/sapi/fpm/tests/proc-idle-timeout.phpt php-8.4.20RC1/sapi/fpm/tests/proc-idle-timeout.phpt --- php-8.4.18/sapi/fpm/tests/proc-idle-timeout.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/sapi/fpm/tests/proc-idle-timeout.phpt 2026-04-01 04:35:36.024264511 +0000 @@ -3,7 +3,7 @@ --SKIPIF-- --FILE-- diff '--color=auto' -Naur php-8.4.18/sapi/litespeed/Makefile.frag php-8.4.20RC1/sapi/litespeed/Makefile.frag --- php-8.4.18/sapi/litespeed/Makefile.frag 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/sapi/litespeed/Makefile.frag 2026-04-01 04:35:36.024338942 +0000 @@ -6,4 +6,4 @@ install-litespeed: $(SAPI_LITESPEED_PATH) @echo "Installing PHP LiteSpeed binary: $(INSTALL_ROOT)$(bindir)/" @$(mkinstalldirs) $(INSTALL_ROOT)$(bindir) - @$(INSTALL) -m 0755 $(SAPI_LITESPEED_PATH) $(INSTALL_ROOT)$(bindir)/$(program_prefix)lsphp$(program_suffix) + @$(LIBTOOL) --mode=install $(INSTALL) -m 0755 $(SAPI_LITESPEED_PATH) $(INSTALL_ROOT)$(bindir)/$(program_prefix)lsphp$(program_suffix) diff '--color=auto' -Naur php-8.4.18/sapi/phpdbg/Makefile.frag php-8.4.20RC1/sapi/phpdbg/Makefile.frag --- php-8.4.18/sapi/phpdbg/Makefile.frag 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/sapi/phpdbg/Makefile.frag 2026-04-01 04:35:36.024411639 +0000 @@ -25,7 +25,7 @@ @$(mkinstalldirs) $(INSTALL_ROOT)$(bindir) @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run - @$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT) + @$(LIBTOOL) --mode=install $(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT) @echo "Installing phpdbg man page: $(INSTALL_ROOT)$(mandir)/man1/" @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 @$(INSTALL_DATA) sapi/phpdbg/phpdbg.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)phpdbg$(program_suffix).1 diff '--color=auto' -Naur php-8.4.18/sapi/phpdbg/phpdbg_utils.c php-8.4.20RC1/sapi/phpdbg/phpdbg_utils.c --- php-8.4.18/sapi/phpdbg/phpdbg_utils.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/sapi/phpdbg/phpdbg_utils.c 2026-04-01 04:35:36.024539501 +0000 @@ -111,7 +111,7 @@ PHPDBG_API int phpdbg_is_class_method(const char *str, size_t len, char **class, char **method) /* {{{ */ { - char *sep = NULL; + const char *sep = NULL; if (strstr(str, "#") != NULL) return 0; diff '--color=auto' -Naur php-8.4.18/scripts/gdb/debug_gdb_scripts_gen.php php-8.4.20RC1/scripts/gdb/debug_gdb_scripts_gen.php --- php-8.4.18/scripts/gdb/debug_gdb_scripts_gen.php 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/scripts/gdb/debug_gdb_scripts_gen.php 2026-04-01 04:35:36.024705825 +0000 @@ -27,7 +27,7 @@ * * See https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html#dotdebug_005fgdb_005fscripts-section */ - asm( + __asm__( ".pushsection \".debug_gdb_scripts\", \"MS\",%%progbits,1\n" ".byte 4 /* Python Text */\n" ".ascii \"gdb.inlined-script\\n\"\n" diff '--color=auto' -Naur php-8.4.18/Zend/Optimizer/sccp.c php-8.4.20RC1/Zend/Optimizer/sccp.c --- php-8.4.18/Zend/Optimizer/sccp.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/Optimizer/sccp.c 2026-04-01 04:35:35.982880787 +0000 @@ -965,7 +965,7 @@ SET_RESULT(op1, &zv); } else if (ct_eval_assign_dim(&zv, data, op2) == SUCCESS) { /* Mark array containing partial array as partial */ - if (IS_PARTIAL_ARRAY(data)) { + if (IS_PARTIAL_ARRAY(data) || IS_PARTIAL_OBJECT(data)) { MAKE_PARTIAL_ARRAY(&zv); } SET_RESULT(result, data); @@ -1165,7 +1165,7 @@ /* We can't add NEXT element into partial array (skip it) */ SET_RESULT(result, &zv); } else if (ct_eval_add_array_elem(&zv, op1, op2) == SUCCESS) { - if (IS_PARTIAL_ARRAY(op1)) { + if (IS_PARTIAL_ARRAY(op1) || IS_PARTIAL_OBJECT(op1)) { MAKE_PARTIAL_ARRAY(&zv); } SET_RESULT(result, &zv); diff '--color=auto' -Naur php-8.4.18/Zend/Optimizer/zend_optimizer.c php-8.4.20RC1/Zend/Optimizer/zend_optimizer.c --- php-8.4.18/Zend/Optimizer/zend_optimizer.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/Optimizer/zend_optimizer.c 2026-04-01 04:35:35.983065166 +0000 @@ -799,6 +799,9 @@ zend_class_entry *ce = Z_PTR_P(ce_zv); if (ce->ce_flags & ZEND_ACC_PRELOADED) { + if (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE) { + return true; + } Bucket *ce_bucket = (Bucket*)((uintptr_t)ce_zv - XtOffsetOf(Bucket, val)); size_t offset = ce_bucket - EG(class_table)->arData; if (offset < EG(persistent_classes_count)) { @@ -817,6 +820,9 @@ return false; } else if (fbc->type == ZEND_USER_FUNCTION) { if (fbc->op_array.fn_flags & ZEND_ACC_PRELOADED) { + if (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE) { + return true; + } Bucket *fbc_bucket = (Bucket*)((uintptr_t)fbc_zv - XtOffsetOf(Bucket, val)); size_t offset = fbc_bucket - EG(function_table)->arData; if (offset < EG(persistent_functions_count)) { diff '--color=auto' -Naur php-8.4.18/Zend/tests/bug55509.phpt php-8.4.20RC1/Zend/tests/bug55509.phpt --- php-8.4.18/Zend/tests/bug55509.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/bug55509.phpt 2026-04-01 04:35:35.983230999 +0000 @@ -2,6 +2,7 @@ Bug #55509 (segfault on x86_64 using more than 2G memory) --SKIPIF-- --EXPECTF-- diff '--color=auto' -Naur php-8.4.18/Zend/tests/bug78010.phpt php-8.4.20RC1/Zend/tests/bug78010.phpt --- php-8.4.18/Zend/tests/bug78010.phpt 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/bug78010.phpt 2026-04-01 04:35:35.983380571 +0000 @@ -2,6 +2,7 @@ Bug #78010: Segmentation fault during GC --SKIPIF-- --INI-- diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20504-001.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-001.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20504-001.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-001.phpt 2026-04-01 04:35:35.983491441 +0000 @@ -0,0 +1,24 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - isset +--CREDITS-- +vi3tL0u1s +--FILE-- +$name['']); + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +var_dump(isset($obj->name[''])); + +?> +--EXPECT-- +bool(false) diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20504-002.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-002.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20504-002.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-002.phpt 2026-04-01 04:35:35.983562555 +0000 @@ -0,0 +1,23 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - get +--FILE-- +$name; + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +var_dump($obj->name); + +?> +--EXPECTF-- +Warning: Undefined property: RealInstance::$name in %s on line %d +NULL diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20504-003.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-003.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20504-003.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-003.phpt 2026-04-01 04:35:35.983634261 +0000 @@ -0,0 +1,33 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - set +--FILE-- +$name = $value; + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +$obj->name = 0; + +var_dump($obj); + +?> +--EXPECTF-- +lazy proxy object(Proxy)#%d (1) { + ["instance"]=> + object(RealInstance)#%d (2) { + ["_"]=> + NULL + ["name"]=> + int(0) + } +} diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20504-004.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-004.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20504-004.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-004.phpt 2026-04-01 04:35:35.983709773 +0000 @@ -0,0 +1,28 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - proxy defines __isset(), both have guards +--FILE-- +$name['']); + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +var_dump(isset($obj->name[''])); + +?> +--EXPECT-- +Proxy::__isset +Proxy::__get +bool(false) diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20504-005.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-005.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20504-005.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20504-005.phpt 2026-04-01 04:35:35.983795125 +0000 @@ -0,0 +1,30 @@ +--TEST-- +GH-20504: Assertion failure in zend_get_property_guard() when lazy proxy adds magic method - unset +--FILE-- +$name); + } +} +$rc = new ReflectionClass(Proxy::class); +$obj = $rc->newLazyProxy(function () { + return new RealInstance; +}); +unset($obj->name); + +var_dump($obj); + +?> +--EXPECTF-- +lazy proxy object(Proxy)#%d (1) { + ["instance"]=> + object(RealInstance)#%d (1) { + ["_"]=> + NULL + } +} diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20657-001.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20657-001.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20657-001.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20657-001.phpt 2026-04-01 04:35:35.983869375 +0000 @@ -0,0 +1,32 @@ +--TEST-- +GH-20657: GC during zend_lazy_object_realize() +--CREDITS-- +vi3tL0u1s +--FILE-- +newLazyGhost(function ($obj) {}); + + // Add to roots + $obj2 = $obj; + unset($obj2); + + // Initialize all props to mark object non-lazy. Also create a cycle. + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $obj); +} + +var_dump($obj); + +?> +--EXPECTF-- +object(C)#%d (1) { + ["a"]=> + *RECURSION* +} diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20657-002.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20657-002.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20657-002.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20657-002.phpt 2026-04-01 04:35:35.983948214 +0000 @@ -0,0 +1,43 @@ +--TEST-- +GH-20657 002: GC during zend_lazy_object_realize() - reset as lazy during realize() +--FILE-- +self = $this; + } + public function __destruct() { + global $obj, $reflector; + $reflector->resetAsLazyGhost($obj, function () {}); + } +} + +new D(); + +$reflector = new ReflectionClass(C::class); + +for ($i = 0; $i < 10000; $i++) { + $obj = $reflector->newLazyGhost(function ($obj) {}); + + // Add to roots + $obj2 = $obj; + unset($obj2); + + // Initialize all props to mark object non-lazy. Also create a cycle. + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $obj); +} + +var_dump($obj); + +?> +--EXPECTF-- +object(C)#%d (1) { + ["a"]=> + *RECURSION* +} diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20854.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20854.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20854.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20854.phpt 2026-04-01 04:35:35.984026121 +0000 @@ -0,0 +1,22 @@ +--TEST-- +GH-20854 (Assertion in ZEND_RETURN_BY_REF with lazy proxy and return-by-ref __get) +--FILE-- +x; + } +} + +$rc = new ReflectionClass(C::class); +$obj = $rc->newLazyProxy(function () { + return new C; +}); +$obj->x; +echo "Done\n"; +?> +--EXPECTF-- +Deprecated: Creation of dynamic property C::$x is deprecated in %s on line %d +Done diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20873.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20873.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20873.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20873.phpt 2026-04-01 04:35:35.984096614 +0000 @@ -0,0 +1,30 @@ +--TEST-- +GH-20873 (Assertion failure in _zendi_try_convert_scalar_to_number with lazy proxy) +--FILE-- +x =& $this->_; + static $a = $a; + $e =& $this->_ - $a; + } +} +$rc = new ReflectionClass(A::class); +$obj = $rc->newLazyProxy(fn() => new A); +$rc->initializeLazyObject($obj); +var_dump($obj->p); +?> +--EXPECTF-- +Deprecated: Creation of dynamic property A::$x is deprecated in %s on line %d + +Warning: Undefined variable $a in %s on line %d + +Notice: Indirect modification of overloaded property A::$x has no effect in %s on line %d + +Fatal error: Uncaught Error: Cannot assign by reference to overloaded object in %s:%d +Stack trace: +#0 %s(%d): A->__get('p') +#1 {main} + thrown in %s on line %d diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20875.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20875.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20875.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20875.phpt 2026-04-01 04:35:35.984172899 +0000 @@ -0,0 +1,49 @@ +--TEST-- +GH-20875 (Assertion failure in _get_zval_ptr_tmp with lazy proxy) +--FILE-- +f =& $this->b - $x > $y = new StdClass; + static $a = $a; + $t = 'x'; + foreach (get_defined_vars() as $key => $e) {} + if ($v ==!1) $x = $a ?: $t = "ok"; + } +} +$rc = new ReflectionClass(A::class); +$obj = $rc->newLazyProxy(function () { return new A; }); +$real = $rc->initializeLazyObject($obj); +var_dump($real->prop); +?> +--EXPECTF-- +Deprecated: Creation of dynamic property A::$b is deprecated in %s on line %d + +Deprecated: Creation of dynamic property A::$f is deprecated in %s on line %d + +Warning: Undefined variable $x in %s on line %d + +Notice: Object of class stdClass could not be converted to int in %s on line %d + +Warning: Undefined variable $a in %s on line %d + +Warning: Undefined variable $v in %s on line %d + +Notice: Indirect modification of overloaded property A::$b has no effect in %s on line %d + +Warning: Undefined variable $x in %s on line %d + +Notice: Object of class stdClass could not be converted to int in %s on line %d + +Warning: Undefined variable $v in %s on line %d + +Notice: Indirect modification of overloaded property A::$f has no effect in %s on line %d + +Fatal error: Uncaught Error: Cannot assign by reference to overloaded object in %s:%d +Stack trace: +#0 %s(%d): A->__get('b') +#1 %s(%d): A->__get('prop') +#2 {main} + thrown in %s on line %d diff '--color=auto' -Naur php-8.4.18/Zend/tests/lazy_objects/gh20875_proxy_get_no_init.phpt php-8.4.20RC1/Zend/tests/lazy_objects/gh20875_proxy_get_no_init.phpt --- php-8.4.18/Zend/tests/lazy_objects/gh20875_proxy_get_no_init.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/lazy_objects/gh20875_proxy_get_no_init.phpt 2026-04-01 04:35:35.984249393 +0000 @@ -0,0 +1,23 @@ +--TEST-- +GH-20875 (Lazy proxy should not initialize when __get handles dynamic property access) +--FILE-- +newLazyProxy(function () { + echo "init\n"; + return new Foo(); +}); +$x = &$proxy->x; + +?> +--EXPECT-- +__get diff '--color=auto' -Naur php-8.4.18/Zend/tests/oss-fuzz-478009707.phpt php-8.4.20RC1/Zend/tests/oss-fuzz-478009707.phpt --- php-8.4.18/Zend/tests/oss-fuzz-478009707.phpt 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/tests/oss-fuzz-478009707.phpt 2026-04-01 04:35:35.984358299 +0000 @@ -0,0 +1,27 @@ +--TEST-- +OSS-Fuzz #478009707: Assign-op/inc/dec on untyped hooked property backing value +--FILE-- +prop = $value; + $this->prop += 1; + $this->prop++; + ++$this->prop; + } + } +} + +$c = new C(1); +$c->prop = 1; +var_dump($c->prop); + +$c->prop = PHP_INT_MAX; +var_dump($c->prop); + +?> +--EXPECTF-- +int(4) +float(%s) diff '--color=auto' -Naur php-8.4.18/Zend/zend_call_stack.h php-8.4.20RC1/Zend/zend_call_stack.h --- php-8.4.18/Zend/zend_call_stack.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/zend_call_stack.h 2026-04-01 04:35:35.984654058 +0000 @@ -21,6 +21,9 @@ #include "zend.h" #include "zend_portability.h" +#ifdef _MSC_VER +# include +#endif #ifdef __APPLE__ # include #endif diff '--color=auto' -Naur php-8.4.18/Zend/zend.h php-8.4.20RC1/Zend/zend.h --- php-8.4.18/Zend/zend.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/zend.h 2026-04-01 04:35:59.692545423 +0000 @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.4.18" +#define ZEND_VERSION "4.4.20RC1" #define ZEND_ENGINE_3 diff '--color=auto' -Naur php-8.4.18/Zend/zend_hash.c php-8.4.20RC1/Zend/zend_hash.c --- php-8.4.18/Zend/zend_hash.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/zend_hash.c 2026-04-01 04:35:35.984785777 +0000 @@ -169,7 +169,7 @@ void *data; uint32_t nSize = ht->nTableSize; - ZEND_ASSERT(HT_SIZE_TO_MASK(nSize)); + ZEND_ASSERT(HT_SIZE_TO_MASK(nSize) != 0); if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) { data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1); @@ -351,7 +351,7 @@ uint32_t i; uint32_t nSize = ht->nTableSize; - ZEND_ASSERT(HT_SIZE_TO_MASK(nSize)); + ZEND_ASSERT(HT_SIZE_TO_MASK(nSize) != 0); HT_ASSERT_RC1(ht); // Alloc before assign to avoid inconsistencies on OOM @@ -399,7 +399,7 @@ if (nSize == 0) return; - ZEND_ASSERT(HT_SIZE_TO_MASK(nSize)); + ZEND_ASSERT(HT_SIZE_TO_MASK(nSize) != 0); if (UNEXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) { if (nSize > ht->nTableSize) { @@ -1318,7 +1318,7 @@ uint32_t nSize = ht->nTableSize + ht->nTableSize; Bucket *old_buckets = ht->arData; - ZEND_ASSERT(HT_SIZE_TO_MASK(nSize)); + ZEND_ASSERT(HT_SIZE_TO_MASK(nSize) != 0); new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); ht->nTableSize = nSize; diff '--color=auto' -Naur php-8.4.18/Zend/zend.h.orig php-8.4.20RC1/Zend/zend.h.orig --- php-8.4.18/Zend/zend.h.orig 1970-01-01 00:00:00.000000000 +0000 +++ php-8.4.20RC1/Zend/zend.h.orig 2026-02-10 17:48:03.000000000 +0000 @@ -0,0 +1,456 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Andi Gutmans | + | Zeev Suraski | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_H +#define ZEND_H + +#define ZEND_VERSION "4.4.18" + +#define ZEND_ENGINE_3 + +#include "zend_types.h" +#include "zend_map_ptr.h" +#include "zend_errors.h" +#include "zend_alloc.h" +#include "zend_llist.h" +#include "zend_string.h" +#include "zend_hash.h" +#include "zend_ast.h" +#include "zend_gc.h" +#include "zend_variables.h" +#include "zend_iterators.h" +#include "zend_stream.h" +#include "zend_smart_str_public.h" +#include "zend_smart_string_public.h" +#include "zend_signal.h" +#include "zend_max_execution_timer.h" + +#define zend_sprintf sprintf + +#define HANDLE_BLOCK_INTERRUPTIONS() ZEND_SIGNAL_BLOCK_INTERRUPTIONS() +#define HANDLE_UNBLOCK_INTERRUPTIONS() ZEND_SIGNAL_UNBLOCK_INTERRUPTIONS() + +#define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value +#define INTERNAL_FUNCTION_PARAM_PASSTHRU execute_data, return_value + +#define USED_RET() \ + (!EX(prev_execute_data) || \ + !ZEND_USER_CODE(EX(prev_execute_data)->func->common.type) || \ + (EX(prev_execute_data)->opline->result_type != IS_UNUSED)) + +#ifdef ZEND_ENABLE_STATIC_TSRMLS_CACHE +#define ZEND_TSRMG TSRMG_STATIC +#define ZEND_TSRMG_FAST TSRMG_FAST_STATIC +#define ZEND_TSRMLS_CACHE_EXTERN() TSRMLS_CACHE_EXTERN() +#define ZEND_TSRMLS_CACHE_DEFINE() TSRMLS_CACHE_DEFINE() +#define ZEND_TSRMLS_CACHE_UPDATE() TSRMLS_CACHE_UPDATE() +#define ZEND_TSRMLS_CACHE TSRMLS_CACHE +#else +#define ZEND_TSRMG TSRMG +#define ZEND_TSRMG_FAST TSRMG_FAST +#define ZEND_TSRMLS_CACHE_EXTERN() +#define ZEND_TSRMLS_CACHE_DEFINE() +#define ZEND_TSRMLS_CACHE_UPDATE() +#define ZEND_TSRMLS_CACHE +#endif + +#ifndef ZEND_COMPILE_DL_EXT +TSRMLS_MAIN_CACHE_EXTERN() +#else +ZEND_TSRMLS_CACHE_EXTERN() +#endif + +struct _zend_serialize_data; +struct _zend_unserialize_data; + +typedef struct _zend_serialize_data zend_serialize_data; +typedef struct _zend_unserialize_data zend_unserialize_data; + +typedef struct _zend_class_name { + zend_string *name; + zend_string *lc_name; +} zend_class_name; + +typedef struct _zend_trait_method_reference { + zend_string *method_name; + zend_string *class_name; +} zend_trait_method_reference; + +typedef struct _zend_trait_precedence { + zend_trait_method_reference trait_method; + uint32_t num_excludes; + zend_string *exclude_class_names[1]; +} zend_trait_precedence; + +typedef struct _zend_trait_alias { + zend_trait_method_reference trait_method; + + /** + * name for method to be added + */ + zend_string *alias; + + /** + * modifiers to be set on trait method + */ + uint32_t modifiers; +} zend_trait_alias; + +typedef struct _zend_class_mutable_data { + zval *default_properties_table; + HashTable *constants_table; + uint32_t ce_flags; + HashTable *backed_enum_table; +} zend_class_mutable_data; + +typedef struct _zend_class_dependency { + zend_string *name; + zend_class_entry *ce; +} zend_class_dependency; + +typedef struct _zend_inheritance_cache_entry zend_inheritance_cache_entry; + +typedef struct _zend_error_info { + int type; + uint32_t lineno; + zend_string *filename; + zend_string *message; +} zend_error_info; + +struct _zend_inheritance_cache_entry { + zend_inheritance_cache_entry *next; + zend_class_entry *ce; + zend_class_entry *parent; + zend_class_dependency *dependencies; + uint32_t dependencies_count; + uint32_t num_warnings; + zend_error_info **warnings; + zend_class_entry *traits_and_interfaces[1]; +}; + +struct _zend_class_entry { + char type; + zend_string *name; + /* class_entry or string depending on ZEND_ACC_LINKED */ + union { + zend_class_entry *parent; + zend_string *parent_name; + }; + int refcount; + uint32_t ce_flags; + + int default_properties_count; + int default_static_members_count; + zval *default_properties_table; + zval *default_static_members_table; + ZEND_MAP_PTR_DEF(zval *, static_members_table); + HashTable function_table; + HashTable properties_info; + HashTable constants_table; + + ZEND_MAP_PTR_DEF(zend_class_mutable_data*, mutable_data); + zend_inheritance_cache_entry *inheritance_cache; + + struct _zend_property_info **properties_info_table; + + zend_function *constructor; + zend_function *destructor; + zend_function *clone; + zend_function *__get; + zend_function *__set; + zend_function *__unset; + zend_function *__isset; + zend_function *__call; + zend_function *__callstatic; + zend_function *__tostring; + zend_function *__debugInfo; + zend_function *__serialize; + zend_function *__unserialize; + + const zend_object_handlers *default_object_handlers; + + /* allocated only if class implements Iterator or IteratorAggregate interface */ + zend_class_iterator_funcs *iterator_funcs_ptr; + /* allocated only if class implements ArrayAccess interface */ + zend_class_arrayaccess_funcs *arrayaccess_funcs_ptr; + + /* handlers */ + union { + zend_object* (*create_object)(zend_class_entry *class_type); + int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type); /* a class implements this interface */ + }; + zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref); + zend_function *(*get_static_method)(zend_class_entry *ce, zend_string* method); + + /* serializer callbacks */ + int (*serialize)(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data); + int (*unserialize)(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data); + + uint32_t num_interfaces; + uint32_t num_traits; + uint32_t num_hooked_props; + uint32_t num_hooked_prop_variance_checks; + + /* class_entry or string(s) depending on ZEND_ACC_LINKED */ + union { + zend_class_entry **interfaces; + zend_class_name *interface_names; + }; + + zend_class_name *trait_names; + zend_trait_alias **trait_aliases; + zend_trait_precedence **trait_precedences; + HashTable *attributes; + + uint32_t enum_backing_type; + HashTable *backed_enum_table; + + zend_string *doc_comment; + + union { + struct { + zend_string *filename; + uint32_t line_start; + uint32_t line_end; + } user; + struct { + const struct _zend_function_entry *builtin_functions; + struct _zend_module_entry *module; + } internal; + } info; +}; + +typedef union { + zend_max_align_t align; + uint64_t opaque[5]; +} zend_random_bytes_insecure_state; + +typedef struct _zend_utility_functions { + void (*error_function)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message); + size_t (*printf_function)(const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 1, 2); + size_t (*write_function)(const char *str, size_t str_length); + FILE *(*fopen_function)(zend_string *filename, zend_string **opened_path); + void (*message_handler)(zend_long message, const void *data); + zval *(*get_configuration_directive)(zend_string *name); + void (*ticks_function)(int ticks); + void (*on_timeout)(int seconds); + zend_result (*stream_open_function)(zend_file_handle *handle); + void (*printf_to_smart_string_function)(smart_string *buf, const char *format, va_list ap); + void (*printf_to_smart_str_function)(smart_str *buf, const char *format, va_list ap); + char *(*getenv_function)(const char *name, size_t name_len); + zend_string *(*resolve_path_function)(zend_string *filename); + zend_result (*random_bytes_function)(void *bytes, size_t size, char *errstr, size_t errstr_size); + void (*random_bytes_insecure_function)(zend_random_bytes_insecure_state *state, void *bytes, size_t size); +} zend_utility_functions; + +typedef struct _zend_utility_values { + bool html_errors; +} zend_utility_values; + +typedef size_t (*zend_write_func_t)(const char *str, size_t str_length); + +#define zend_bailout() _zend_bailout(__FILE__, __LINE__) + +#define zend_try \ + { \ + JMP_BUF *__orig_bailout = EG(bailout); \ + JMP_BUF __bailout; \ + \ + EG(bailout) = &__bailout; \ + if (SETJMP(__bailout)==0) { +#define zend_catch \ + } else { \ + EG(bailout) = __orig_bailout; +#define zend_end_try() \ + } \ + EG(bailout) = __orig_bailout; \ + } +#define zend_first_try EG(bailout)=NULL; zend_try + +BEGIN_EXTERN_C() +void zend_startup(zend_utility_functions *utility_functions); +void zend_shutdown(void); +void zend_register_standard_ini_entries(void); +zend_result zend_post_startup(void); +void zend_set_utility_values(zend_utility_values *utility_values); +void zend_unload_modules(void); + +ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32_t lineno); +ZEND_API size_t zend_get_page_size(void); + +ZEND_API size_t zend_vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap); +ZEND_API size_t zend_spprintf(char **message, size_t max_len, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 3, 4); +ZEND_API zend_string *zend_vstrpprintf(size_t max_len, const char *format, va_list ap); +ZEND_API zend_string *zend_strpprintf(size_t max_len, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); + +/* Same as zend_spprintf and zend_strpprintf, without checking of format validity. + * For use with custom printf specifiers such as %H. */ +ZEND_API size_t zend_spprintf_unchecked(char **message, size_t max_len, const char *format, ...); +ZEND_API zend_string *zend_strpprintf_unchecked(size_t max_len, const char *format, ...); + +ZEND_API const char *get_zend_version(void); +ZEND_API bool zend_make_printable_zval(zval *expr, zval *expr_copy); +ZEND_API size_t zend_print_zval(zval *expr, int indent); +ZEND_API void zend_print_zval_r(zval *expr, int indent); +ZEND_API zend_string *zend_print_zval_r_to_str(zval *expr, int indent); +ZEND_API void zend_print_flat_zval_r(zval *expr); +void zend_print_flat_zval_r_to_buf(smart_str *str, zval *expr); + +static zend_always_inline size_t zend_print_variable(zval *var) { + return zend_print_zval(var, 0); +} + +ZEND_API ZEND_COLD void zend_output_debug_string(bool trigger_break, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); + +ZEND_API void zend_activate(void); +ZEND_API void zend_deactivate(void); +ZEND_API void zend_call_destructors(void); +ZEND_API void zend_activate_modules(void); +ZEND_API void zend_deactivate_modules(void); +ZEND_API void zend_post_deactivate_modules(void); + +ZEND_API void free_estring(char **str_p); + +END_EXTERN_C() + +/* output support */ +#define ZEND_WRITE(str, str_len) zend_write((str), (str_len)) +#define ZEND_WRITE_EX(str, str_len) write_func((str), (str_len)) +#define ZEND_PUTS(str) zend_write((str), strlen((str))) +#define ZEND_PUTS_EX(str) write_func((str), strlen((str))) +#define ZEND_PUTC(c) zend_write(&(c), 1) + +BEGIN_EXTERN_C() +extern ZEND_API size_t (*zend_printf)(const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 1, 2); +extern ZEND_API zend_write_func_t zend_write; +extern ZEND_API FILE *(*zend_fopen)(zend_string *filename, zend_string **opened_path); +extern ZEND_API void (*zend_ticks_function)(int ticks); + +/* Called by the VM in certain places like at the loop header, user function + * entry, and after internal function calls, if EG(vm_interrupt) has been set. + * + * If this is used to switch the EG(current_execute_data), such as implementing + * a coroutine scheduler, then it needs to check the top frame to see if it's + * an internal function. If an internal function is on top, then the frame + * shouldn't be switched away. + * + * Prior to PHP 8.0, this check was not necessary. In PHP 8.0, + * zend_call_function started calling zend_interrupt_function, and in 8.4 the + * DO_*CALL* opcodes started calling the zend_interrupt_function while the + * internal frame is still on top. + */ +extern ZEND_API void (*zend_interrupt_function)(zend_execute_data *execute_data); + +extern ZEND_API void (*zend_error_cb)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message); +extern ZEND_API void (*zend_on_timeout)(int seconds); +extern ZEND_API zend_result (*zend_stream_open_function)(zend_file_handle *handle); +extern void (*zend_printf_to_smart_string)(smart_string *buf, const char *format, va_list ap); +extern void (*zend_printf_to_smart_str)(smart_str *buf, const char *format, va_list ap); +extern ZEND_API char *(*zend_getenv)(const char *name, size_t name_len); +extern ZEND_API zend_string *(*zend_resolve_path)(zend_string *filename); +/* Generate 'size' random bytes into 'bytes' with the OS CSPRNG. */ +extern ZEND_ATTRIBUTE_NONNULL ZEND_API zend_result (*zend_random_bytes)( + void *bytes, size_t size, char *errstr, size_t errstr_size); +/* Generate 'size' random bytes into 'bytes' with a general purpose PRNG (not + * crypto safe). 'state' must be zeroed before the first call and can be reused. + */ +extern ZEND_ATTRIBUTE_NONNULL ZEND_API void (*zend_random_bytes_insecure)( + zend_random_bytes_insecure_state *state, void *bytes, size_t size); + +/* These two callbacks are especially for opcache */ +extern ZEND_API zend_result (*zend_post_startup_cb)(void); +extern ZEND_API void (*zend_post_shutdown_cb)(void); + +extern ZEND_API void (*zend_accel_schedule_restart_hook)(int reason); + +ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...); +/* For custom format specifiers like H */ +ZEND_API ZEND_COLD void zend_error_unchecked(int type, const char *format, ...); +/* If filename is NULL the default filename is used. */ +ZEND_API ZEND_COLD void zend_error_at(int type, zend_string *filename, uint32_t lineno, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 4, 5); +ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn(int type, zend_string *filename, uint32_t lineno, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 4, 5); +ZEND_API ZEND_COLD void zend_error_zstr(int type, zend_string *message); +ZEND_API ZEND_COLD void zend_error_zstr_at(int type, zend_string *filename, uint32_t lineno, zend_string *message); + +ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +ZEND_API ZEND_COLD void zend_type_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); +ZEND_API ZEND_COLD void zend_argument_count_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); +ZEND_API ZEND_COLD void zend_value_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); +/* type should be one of the BP_VAR_* constants, only special messages happen for isset/empty and unset */ +ZEND_API ZEND_COLD void zend_illegal_container_offset(const zend_string *container, const zval *offset, int type); + +ZEND_COLD void zenderror(const char *error); + +/* For internal C errors */ +ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message); + +/* The following #define is used for code duality in PHP for Engine 1 & 2 */ +#define ZEND_STANDARD_CLASS_DEF_PTR zend_standard_class_def +extern ZEND_API zend_class_entry *zend_standard_class_def; +extern ZEND_API zend_utility_values zend_uv; + +/* If DTrace is available and enabled */ +extern ZEND_API bool zend_dtrace_enabled; +END_EXTERN_C() + +#define ZEND_UV(name) (zend_uv.name) + +BEGIN_EXTERN_C() +ZEND_API void zend_message_dispatcher(zend_long message, const void *data); + +ZEND_API zval *zend_get_configuration_directive(zend_string *name); +END_EXTERN_C() + +/* Messages for applications of Zend */ +#define ZMSG_FAILED_INCLUDE_FOPEN 1L +#define ZMSG_FAILED_REQUIRE_FOPEN 2L +#define ZMSG_FAILED_HIGHLIGHT_FOPEN 3L +#define ZMSG_MEMORY_LEAK_DETECTED 4L +#define ZMSG_MEMORY_LEAK_REPEATED 5L +#define ZMSG_LOG_SCRIPT_NAME 6L +#define ZMSG_MEMORY_LEAKS_GRAND_TOTAL 7L + +typedef enum { + EH_NORMAL = 0, + EH_THROW +} zend_error_handling_t; + +typedef struct { + zend_error_handling_t handling; + zend_class_entry *exception; +} zend_error_handling; + +BEGIN_EXTERN_C() +ZEND_API void zend_save_error_handling(zend_error_handling *current); +ZEND_API void zend_replace_error_handling(zend_error_handling_t error_handling, zend_class_entry *exception_class, zend_error_handling *current); +ZEND_API void zend_restore_error_handling(zend_error_handling *saved); +ZEND_API void zend_begin_record_errors(void); +ZEND_API void zend_emit_recorded_errors(void); +ZEND_API void zend_free_recorded_errors(void); +END_EXTERN_C() + +#define DEBUG_BACKTRACE_PROVIDE_OBJECT (1<<0) +#define DEBUG_BACKTRACE_IGNORE_ARGS (1<<1) + +#include "zend_object_handlers.h" +#include "zend_operators.h" + +#endif /* ZEND_H */ diff '--color=auto' -Naur php-8.4.18/Zend/zend_lazy_objects.c php-8.4.20RC1/Zend/zend_lazy_objects.c --- php-8.4.18/Zend/zend_lazy_objects.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/zend_lazy_objects.c 2026-04-01 04:35:35.984980484 +0000 @@ -678,8 +678,6 @@ ZEND_ASSERT(zend_object_is_lazy(obj)); ZEND_ASSERT(!zend_lazy_object_initialized(obj)); - zend_lazy_object_del_info(obj); - #if ZEND_DEBUG for (int i = 0; i < obj->ce->default_properties_count; i++) { ZEND_ASSERT(!(Z_PROP_FLAG_P(&obj->properties_table[i]) & IS_PROP_LAZY)); @@ -687,6 +685,7 @@ #endif OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED | IS_OBJ_LAZY_PROXY); + zend_lazy_object_del_info(obj); } ZEND_API HashTable *zend_lazy_object_get_properties(zend_object *object) diff '--color=auto' -Naur php-8.4.18/Zend/zend_multiply.h php-8.4.20RC1/Zend/zend_multiply.h --- php-8.4.18/Zend/zend_multiply.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/zend_multiply.h 2026-04-01 04:35:35.985082387 +0000 @@ -267,7 +267,8 @@ : "=&r"(res), "=&r"(m_overflow) : "r"(nmemb), "r"(size), - "r"(offset)); + "r"(offset) + : "cc"); if (UNEXPECTED(m_overflow)) { *overflow = 1; @@ -291,7 +292,8 @@ : "=&r"(res), "=&r"(m_overflow) : "r"(nmemb), "r"(size), - "r"(offset)); + "r"(offset) + : "xer"); if (UNEXPECTED(m_overflow)) { *overflow = 1; diff '--color=auto' -Naur php-8.4.18/Zend/zend_object_handlers.c php-8.4.20RC1/Zend/zend_object_handlers.c --- php-8.4.18/Zend/zend_object_handlers.c 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/zend_object_handlers.c 2026-04-01 04:35:35.985227661 +0000 @@ -956,25 +956,27 @@ uninit_error: if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { if (!prop_info || (Z_PROP_FLAG_P(retval) & IS_PROP_LAZY)) { - zobj = zend_lazy_object_init(zobj); - if (!zobj) { + zend_object *instance = zend_lazy_object_init(zobj); + if (!instance) { retval = &EG(uninitialized_zval); goto exit; } - if (UNEXPECTED(guard)) { + if (UNEXPECTED(guard && (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS))) { + /* Find which guard was used on zobj, so we can set the same + * guard on instance. */ uint32_t guard_type = (type == BP_VAR_IS) && zobj->ce->__isset ? IN_ISSET : IN_GET; - guard = zend_get_property_guard(zobj, name); + guard = zend_get_property_guard(instance, name); if (!((*guard) & guard_type)) { (*guard) |= guard_type; - retval = zend_std_read_property(zobj, name, type, cache_slot, rv); + retval = zend_std_read_property(instance, name, type, cache_slot, rv); (*guard) &= ~guard_type; return retval; } } - return zend_std_read_property(zobj, name, type, cache_slot, rv); + return zend_std_read_property(instance, name, type, cache_slot, rv); } } if (type != BP_VAR_IS) { @@ -1013,7 +1015,7 @@ return &EG(error_zval); } - if (UNEXPECTED(guarded)) { + if (UNEXPECTED(guarded && (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS))) { uint32_t *guard = zend_get_property_guard(instance, name); if (!((*guard) & IN_SET)) { (*guard) |= IN_SET; @@ -1399,12 +1401,24 @@ UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET) || UNEXPECTED(prop_info && (Z_PROP_FLAG_P(retval) & IS_PROP_UNINIT))) { if (UNEXPECTED(zend_lazy_object_must_init(zobj) && (Z_PROP_FLAG_P(retval) & IS_PROP_LAZY))) { - zobj = zend_lazy_object_init(zobj); - if (!zobj) { + bool guarded = zobj->ce->__get + && (*zend_get_property_guard(zobj, name) & IN_GET); + zend_object *instance = zend_lazy_object_init(zobj); + if (!instance) { return &EG(error_zval); } - return zend_std_get_property_ptr_ptr(zobj, name, type, cache_slot); + if (guarded && (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS)) { + uint32_t *guard = zend_get_property_guard(instance, name); + if (!(*guard & IN_GET)) { + (*guard) |= IN_GET; + retval = zend_std_get_property_ptr_ptr(instance, name, type, cache_slot); + (*guard) &= ~IN_GET; + return retval; + } + } + + return zend_std_get_property_ptr_ptr(instance, name, type, cache_slot); } if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) { if (prop_info) { @@ -1447,6 +1461,25 @@ } if (EXPECTED(!zobj->ce->__get) || UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET)) { + if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { + bool guarded = (zobj->ce->__get != NULL); + zend_object *instance = zend_lazy_object_init(zobj); + if (!instance) { + return &EG(error_zval); + } + + if (guarded && (instance->ce->ce_flags & ZEND_ACC_USE_GUARDS)) { + uint32_t *guard = zend_get_property_guard(instance, name); + if (!(*guard & IN_GET)) { + (*guard) |= IN_GET; + retval = zend_std_get_property_ptr_ptr(instance, name, type, cache_slot); + (*guard) &= ~IN_GET; + return retval; + } + } + + return zend_std_get_property_ptr_ptr(instance, name, type, cache_slot); + } if (UNEXPECTED(zobj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { zend_forbidden_dynamic_property(zobj->ce, name); return &EG(error_zval); @@ -1456,14 +1489,6 @@ return &EG(error_zval); } } - if (UNEXPECTED(zend_lazy_object_must_init(zobj))) { - zobj = zend_lazy_object_init(zobj); - if (!zobj) { - return &EG(error_zval); - } - - return zend_std_get_property_ptr_ptr(zobj, name, type, cache_slot); - } if (UNEXPECTED(!zobj->properties)) { rebuild_object_properties_internal(zobj); } @@ -1597,7 +1622,7 @@ return; } - if (UNEXPECTED(guard)) { + if (UNEXPECTED(guard && zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS)) { guard = zend_get_property_guard(zobj, name); if (!((*guard) & IN_UNSET)) { (*guard) |= IN_UNSET; diff '--color=auto' -Naur php-8.4.18/Zend/zend_vm_def.h php-8.4.20RC1/Zend/zend_vm_def.h --- php-8.4.18/Zend/zend_vm_def.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/zend_vm_def.h 2026-04-01 04:35:35.985779264 +0000 @@ -1070,7 +1070,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -1326,7 +1326,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -1394,7 +1395,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); diff '--color=auto' -Naur php-8.4.18/Zend/zend_vm_execute.h php-8.4.20RC1/Zend/zend_vm_execute.h --- php-8.4.18/Zend/zend_vm_execute.h 2026-02-10 17:48:03.000000000 +0000 +++ php-8.4.20RC1/Zend/zend_vm_execute.h 2026-04-01 04:35:35.989935998 +0000 @@ -23590,7 +23590,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -23798,7 +23798,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -23860,7 +23861,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -26591,7 +26593,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -26801,7 +26803,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -26864,7 +26867,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -30951,7 +30955,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -31159,7 +31163,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -31221,7 +31226,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -33621,7 +33627,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -33699,7 +33705,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -33761,7 +33768,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -35807,7 +35815,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -35885,7 +35893,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -35948,7 +35957,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -38457,7 +38467,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -38535,7 +38545,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -38597,7 +38608,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -42612,7 +42624,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -42820,7 +42832,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -42882,7 +42895,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -46566,7 +46580,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -46776,7 +46790,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -46839,7 +46854,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -52071,7 +52087,7 @@ } prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - if (prop_info) { + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { /* special case for typed properties */ zend_binary_assign_op_typed_prop(prop_info, zptr, value OPLINE_CC EXECUTE_DATA_CC); } else { @@ -52279,7 +52295,8 @@ } } else { prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2); - zend_pre_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_pre_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_pre_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC); @@ -52341,7 +52358,8 @@ ZVAL_NULL(EX_VAR(opline->result.var)); } else { prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2); - zend_post_incdec_property_zval(zptr, prop_info OPLINE_CC EXECUTE_DATA_CC); + zend_post_incdec_property_zval(zptr, + prop_info && ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); } } else { zend_post_incdec_overloaded_property(zobj, name, cache_slot OPLINE_CC EXECUTE_DATA_CC);