From b4ac6e658cd6ee3d1cc586fab204688d4a610050 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 05:37:40 +0000 Subject: [PATCH 1/9] Update unstable PHP tag to 8.6.0beta1 Keep apcu's from-source build for PHP 8.6: apcu's latest tagged release (v5.1.28, still current) calls php_verror() with the old 5-argument signature, and PHP 8.6's php_verror() (unchanged in 8.6.0beta1) only takes 4 arguments, so pie/pecl-installing the tagged release would still fail to compile. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- unstable-tag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unstable-tag b/unstable-tag index fb100c5..cad4a77 100644 --- a/unstable-tag +++ b/unstable-tag @@ -1 +1 @@ -8.6.0alpha3 +8.6.0beta1 From 53cb892444d32640c3e0d393e5174d40c3cbd91f Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 05:50:34 +0000 Subject: [PATCH 2/9] Experiment: try pie's apcu on PHP 8.6.0beta1 again Reverts the from-source apcu build to confirm whether it's still needed against 8.6.0beta1, or whether apcu/PHP has since caught up. Revert this commit if CI shows the build still fails. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- php-install.sh | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/php-install.sh b/php-install.sh index cde3181..7b33461 100644 --- a/php-install.sh +++ b/php-install.sh @@ -158,20 +158,9 @@ case $PHP_VERSION in esac case $PHP_VERSION in - 8.6*) - # apcu's latest tagged release (pie/pecl install this) predates the - # upstream fix for PHP 8.6's php_verror() signature change, so build - # from the default branch instead, same as the other 8.6 workarounds - # below. - php -m | grep -q '^apcu$' || ( - git clone --depth=1 https://github.com/krakjoe/apcu.git /usr/src/apcu && - cd /usr/src/apcu && - phpize && ./configure --enable-apcu && make -j"$(nproc)" && make install && - echo "extension=apcu.so" > /usr/local/etc/php/conf.d/apcu.ini - ) - rm -rf /usr/src/apcu - ;; - 8.1*|8.2*|8.3*|8.4*|8.5*) + 8.1*|8.2*|8.3*|8.4*|8.5*|8.6*) + # todo: experiment, revert if CI shows apcu still fails to build + # against PHP 8.6.0beta1 via pie's tagged release. pie install apcu/apcu ;; *) @@ -393,7 +382,7 @@ docker-php-ext-install gmp ldap xsl mysqli calendar gd pdo_mysql pdo_pgsql zip b case $PHP_VERSION in 8.1*|8.2*|8.3*|8.4*|8.5*|8.6*) - echo "rdkafka was already enabled by pie, and apcu by pie or its own install step, for PHP $PHP_VERSION" + echo "rdkafka and apcu were already enabled by pie for PHP $PHP_VERSION" ;; *) docker-php-ext-enable rdkafka apcu From 60e7038efc5b371b76d85bac1be0d7bc4b8bc5aa Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 05:52:01 +0000 Subject: [PATCH 3/9] Surface real ext-ds build error on PHP 8.6 CI php-ds/ext-ds now fails to build against 8.6.0beta1 too (a new regression, since it wasn't failing on alpha3), and pie hides the actual compiler/make error the same way it did for apcu. Add -v here as well so the real error shows up in the CI log. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- php-install.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php-install.sh b/php-install.sh index 7b33461..56d6fef 100644 --- a/php-install.sh +++ b/php-install.sh @@ -99,7 +99,13 @@ case $PHP_VERSION in # php-ds/ext-ds has no pie-installable release below PHP 8.2; keep pecl for 8.1. yes | pecl install ds-1.6.0 ;; - 8.2*|8.3*|8.4*|8.5*|8.6*) + 8.6*) + # todo: -v surfaces the real compiler/make error in the CI log; pie + # otherwise buffers build output and, on failure, dumps it to a + # temp file inside the (already-gone) build container instead. + pie install -v php-ds/ext-ds + ;; + 8.2*|8.3*|8.4*|8.5*) pie install php-ds/ext-ds ;; *) From 9c4f07f34b84a3a74c78613040f549806ac9a758 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 05:56:12 +0000 Subject: [PATCH 4/9] Patch and build php-ds/ext-ds from source on PHP 8.6 php-ds/ext-ds calls zend_parse_parameter(), which PHP 8.6 removed entirely (present through 8.5, gone on master/8.6.0beta1). Its built-in "l" spec handling was just a thin wrapper over the still public zend_parse_arg_long() inline helper, so patch the one call site to use that directly instead of pie-installing the (currently unbuildable) tagged release. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- php-install.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/php-install.sh b/php-install.sh index 56d6fef..edcea0c 100644 --- a/php-install.sh +++ b/php-install.sh @@ -100,10 +100,19 @@ case $PHP_VERSION in yes | pecl install ds-1.6.0 ;; 8.6*) - # todo: -v surfaces the real compiler/make error in the CI log; pie - # otherwise buffers build output and, on failure, dumps it to a - # temp file inside the (already-gone) build container instead. - pie install -v php-ds/ext-ds + # php-ds/ext-ds calls the removed zend_parse_parameter() (the + # single-argument variant; zend_parse_parameters() is unrelated and + # still exists). Patch it to use the still-available + # zend_parse_arg_long() inline helper instead, which is what + # zend_parse_parameter() used internally for the "l" spec anyway. + php -m | grep -q '^ds$' || ( + git clone --depth=1 https://github.com/php-ds/ext-ds.git /usr/src/ext-ds && + cd /usr/src/ext-ds && + sed -i 's/zend_parse_parameter(ZEND_PARSE_PARAMS_QUIET, 1, offset, "l", \&index) == FAILURE/!zend_parse_arg_long(offset, \&index, NULL, false, 1)/' src/php/handlers/php_seq_handlers.c && + phpize && ./configure --enable-ds && make -j"$(nproc)" && make install && + echo "extension=ds.so" > /usr/local/etc/php/conf.d/ds.ini + ) + rm -rf /usr/src/ext-ds ;; 8.2*|8.3*|8.4*|8.5*) pie install php-ds/ext-ds From a3f4569dd40c3ac02ea5399a4d66031cb6cdf7fc Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 06:08:36 +0000 Subject: [PATCH 5/9] Patch igbinary for PHP 8.6's unserialize_callback_func type change PHP 8.6 changed the unserialize_callback_func INI global from char* to zend_string* (OnUpdateString -> OnUpdateStr in main.c), breaking igbinary's two direct reads of it in igbinary_unserialize_object(). Patch both call sites to pull the C string via ZSTR_VAL() instead. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- php-install.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php-install.sh b/php-install.sh index edcea0c..03835bb 100644 --- a/php-install.sh +++ b/php-install.sh @@ -134,9 +134,14 @@ case $PHP_VERSION in rm -rf /usr/src/igbinary ;; 8.6*) + # PHP 8.6 also changed the unserialize_callback_func INI global from + # char* to zend_string*, so patch igbinary's two remaining direct + # reads of it. php -m | grep -q '^igbinary$' || ( git clone --depth=1 https://github.com/igbinary/igbinary.git /usr/src/igbinary && cd /usr/src/igbinary && + sed -i 's/user_func_name = PG(unserialize_callback_func);/user_func_name = PG(unserialize_callback_func) ? ZSTR_VAL(PG(unserialize_callback_func)) : NULL;/' src/php7/igbinary.c && + sed -i "s/\"Function %s() hasn't defined the class it was called for\", PG(unserialize_callback_func));/\"Function %s() hasn't defined the class it was called for\", user_func_name);/" src/php7/igbinary.c && export CFLAGS="${CFLAGS:-} -DXtOffsetOf=offsetof -Dzval_dtor=zval_ptr_dtor_nogc" && phpize && ./configure && make -j"$(nproc)" && make install && echo "extension=igbinary.so" > /usr/local/etc/php/conf.d/igbinary.ini From 75b04e53969b66b2bf8ce838bdbfa33a40c6f028 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 06:10:45 +0000 Subject: [PATCH 6/9] Use upstream's igbinary fix instead of a hand-rolled patch My previous sed-based fix kept a raw char* into PG(unserialize_callback_func)'s zend_string and re-read it later in the same function, after invoking arbitrary user PHP code via the unserialize callback -- if that callback reassigns unserialize_callback_func, the original zend_string can be freed, making the later read a use-after-free. igbinary/igbinary#419 already fixes this upstream (not yet merged) by taking an owned copy of the string up front. Cherry-pick that commit instead of carrying a subtly unsafe patch of our own. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- php-install.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/php-install.sh b/php-install.sh index 03835bb..969ffe2 100644 --- a/php-install.sh +++ b/php-install.sh @@ -135,13 +135,16 @@ case $PHP_VERSION in ;; 8.6*) # PHP 8.6 also changed the unserialize_callback_func INI global from - # char* to zend_string*, so patch igbinary's two remaining direct - # reads of it. + # char* to zend_string*, breaking igbinary's two direct reads of it. + # Cherry-pick upstream's own fix (igbinary/igbinary#419) rather than + # patching it ourselves: their fix also takes its own owned copy of + # the string, since the naive fix is a use-after-free if the + # unserialize callback itself reassigns unserialize_callback_func. php -m | grep -q '^igbinary$' || ( git clone --depth=1 https://github.com/igbinary/igbinary.git /usr/src/igbinary && cd /usr/src/igbinary && - sed -i 's/user_func_name = PG(unserialize_callback_func);/user_func_name = PG(unserialize_callback_func) ? ZSTR_VAL(PG(unserialize_callback_func)) : NULL;/' src/php7/igbinary.c && - sed -i "s/\"Function %s() hasn't defined the class it was called for\", PG(unserialize_callback_func));/\"Function %s() hasn't defined the class it was called for\", user_func_name);/" src/php7/igbinary.c && + git fetch --depth=5 origin pull/419/head && + git cherry-pick d4a6ded9ca6b3d7eec069de1891d03c5bc14c233 --no-commit && export CFLAGS="${CFLAGS:-} -DXtOffsetOf=offsetof -Dzval_dtor=zval_ptr_dtor_nogc" && phpize && ./configure && make -j"$(nproc)" && make install && echo "extension=igbinary.so" > /usr/local/etc/php/conf.d/igbinary.ini From 9d846b867b91474a15212b8308860bffed8ecb22 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 06:46:19 +0000 Subject: [PATCH 7/9] Restore apcu from-source build: still needed on 8.6.0beta1 CI confirmed the build now reaches apcu/apcu (past the ext-ds and igbinary fixes) and fails there exactly as it did on alpha3: apcu's latest tagged release still calls the removed php_verror() with the old 5-argument signature. Restore the from-source build. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- php-install.sh | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/php-install.sh b/php-install.sh index 969ffe2..e36d4fa 100644 --- a/php-install.sh +++ b/php-install.sh @@ -181,9 +181,20 @@ case $PHP_VERSION in esac case $PHP_VERSION in - 8.1*|8.2*|8.3*|8.4*|8.5*|8.6*) - # todo: experiment, revert if CI shows apcu still fails to build - # against PHP 8.6.0beta1 via pie's tagged release. + 8.6*) + # Confirmed still needed against 8.6.0beta1: apcu's latest tagged + # release still calls the removed php_verror() with the old + # 5-argument signature. Fixed upstream on the default branch + # (unreleased), so build from there instead. + php -m | grep -q '^apcu$' || ( + git clone --depth=1 https://github.com/krakjoe/apcu.git /usr/src/apcu && + cd /usr/src/apcu && + phpize && ./configure --enable-apcu && make -j"$(nproc)" && make install && + echo "extension=apcu.so" > /usr/local/etc/php/conf.d/apcu.ini + ) + rm -rf /usr/src/apcu + ;; + 8.1*|8.2*|8.3*|8.4*|8.5*) pie install apcu/apcu ;; *) @@ -405,7 +416,7 @@ docker-php-ext-install gmp ldap xsl mysqli calendar gd pdo_mysql pdo_pgsql zip b case $PHP_VERSION in 8.1*|8.2*|8.3*|8.4*|8.5*|8.6*) - echo "rdkafka and apcu were already enabled by pie for PHP $PHP_VERSION" + echo "rdkafka was already enabled by pie, and apcu by pie or its own install step, for PHP $PHP_VERSION" ;; *) docker-php-ext-enable rdkafka apcu From 36ef3513c9a121257b03d36a0d88f85f03469291 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 07:06:32 +0000 Subject: [PATCH 8/9] Surface real msgpack build error on PHP 8.6 CI msgpack/msgpack-php now fails to build against 8.6.0beta1 too (a new regression, past the ext-ds/igbinary/apcu breaks already fixed). Split it out and add -v to see the real compiler/make error. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- php-install.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/php-install.sh b/php-install.sh index e36d4fa..e467158 100644 --- a/php-install.sh +++ b/php-install.sh @@ -207,10 +207,24 @@ case $PHP_VERSION in pie install rdkafka/rdkafka pie install pecl/yaml pie install pecl/uuid + ;; + *) + yes | pecl install rdkafka yaml uuid + ;; +esac + +case $PHP_VERSION in + 8.6*) + # todo: -v surfaces the real compiler/make error in the CI log; pie + # otherwise buffers build output and, on failure, dumps it to a + # temp file inside the (already-gone) build container instead. + pie install -v msgpack/msgpack-php + ;; + 8.1*|8.2*|8.3*|8.4*|8.5*) pie install msgpack/msgpack-php ;; *) - yes | pecl install rdkafka yaml uuid msgpack + yes | pecl install msgpack ;; esac From fb97a275a90e7d0b90c5443aefcd78fcb1f1590d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 15 Aug 2026 07:12:18 +0000 Subject: [PATCH 9/9] Patch and build msgpack from source on PHP 8.6 msgpack-php reads PG(unserialize_callback_func) as a char*, which PHP 8.6 changed to zend_string*. No upstream fix exists yet, so patch the two call sites ourselves. Unlike igbinary, msgpack reads the global only once, before invoking the callback (never re-reads it after), so a direct ZSTR_VAL/ZVAL_STR_COPY swap is safe -- there's no window for the callback to free the string out from under a held pointer. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_012KziZyXrwQuJyZeFPm1aQ6 --- php-install.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/php-install.sh b/php-install.sh index e467158..42100a1 100644 --- a/php-install.sh +++ b/php-install.sh @@ -215,10 +215,19 @@ esac case $PHP_VERSION in 8.6*) - # todo: -v surfaces the real compiler/make error in the CI log; pie - # otherwise buffers build output and, on failure, dumps it to a - # temp file inside the (already-gone) build container instead. - pie install -v msgpack/msgpack-php + # msgpack-php also reads unserialize_callback_func as a char* (now + # zend_string* on PHP 8.6). Unlike igbinary, it only reads the + # global once, before invoking the callback, so a plain ZSTR_VAL / + # ZVAL_STR_COPY swap is safe here -- no owned-copy dance needed. + php -m | grep -q '^msgpack$' || ( + git clone --depth=1 https://github.com/msgpack/msgpack-php.git /usr/src/msgpack-php && + cd /usr/src/msgpack-php && + sed -i "s/(PG(unserialize_callback_func)\[0\] == '\\\\0')) {/(ZSTR_LEN(PG(unserialize_callback_func)) == 0)) {/" msgpack_unpack.c && + sed -i 's/ZVAL_STRING(&user_func, PG(unserialize_callback_func));/ZVAL_STR_COPY(\&user_func, PG(unserialize_callback_func));/' msgpack_unpack.c && + phpize && ./configure --with-msgpack && make -j"$(nproc)" && make install && + echo "extension=msgpack.so" > /usr/local/etc/php/conf.d/msgpack.ini + ) + rm -rf /usr/src/msgpack-php ;; 8.1*|8.2*|8.3*|8.4*|8.5*) pie install msgpack/msgpack-php