diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000000000..2320d2baca9c2
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,197 @@
+version: 2.1
+
+jobs:
+ arm:
+ resource_class: arm.medium
+ docker:
+ - image: cimg/base:current-22.04
+ - image: mysql:8
+ environment:
+ MYSQL_ALLOW_EMPTY_PASSWORD: true
+ MYSQL_ROOT_PASSWORD: ''
+ MYSQL_DATABASE: test
+ - image: postgres:16
+ environment:
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: test
+ environment:
+ LANGUAGE: ''
+ LANG: en_US.UTF-8
+ MYSQL_TEST_HOST: '127.0.0.1'
+ MYSQL_TEST_PASSWD: ''
+ MYSQL_TEST_USER: root
+ PDO_MYSQL_TEST_DSN: 'mysql:host=127.0.0.1;dbname=test'
+ PDO_MYSQL_TEST_PASS: ''
+ PDO_MYSQL_TEST_USER: root
+ PDO_PGSQL_TEST_DSN: 'pgsql:host=127.0.0.1 port=5432 dbname=test user=postgres password=postgres'
+ steps:
+ - checkout
+ - run:
+ name: apt
+ command: |
+ export DEBIAN_FRONTEND=noninteractive
+ sudo apt-get update -y
+ sudo apt-get install -y \
+ gcc \
+ g++ \
+ autoconf \
+ bison \
+ re2c \
+ locales \
+ locales-all \
+ ldap-utils \
+ openssl \
+ slapd \
+ libgmp-dev \
+ libicu-dev \
+ libtidy-dev \
+ libenchant-2-dev \
+ libaspell-dev \
+ libpspell-dev \
+ libsasl2-dev \
+ libxpm-dev \
+ libzip-dev \
+ libbz2-dev \
+ libsqlite3-dev \
+ libwebp-dev \
+ libonig-dev \
+ libkrb5-dev \
+ libgssapi-krb5-2 \
+ libcurl4-openssl-dev \
+ libxml2-dev \
+ libxslt1-dev \
+ libpq-dev \
+ libreadline-dev \
+ libldap2-dev \
+ libsodium-dev \
+ libargon2-0-dev \
+ libmm-dev \
+ libsnmp-dev \
+ snmpd \
+ `#snmp-mibs-downloader` \
+ freetds-dev \
+ `#unixodbc-dev` \
+ libc-client-dev \
+ dovecot-core \
+ dovecot-pop3d \
+ dovecot-imapd \
+ sendmail \
+ firebird-dev \
+ liblmdb-dev \
+ libtokyocabinet-dev \
+ libdb-dev \
+ libqdbm-dev \
+ libjpeg-dev \
+ libpng-dev \
+ libfreetype6-dev
+ - run:
+ name: ./configure
+ command: |
+ ./buildconf -f
+ ./configure \
+ --enable-debug \
+ --enable-zts \
+ --enable-option-checking=fatal \
+ --prefix=/usr \
+ --enable-phpdbg \
+ --enable-fpm \
+ --enable-opcache \
+ --with-pdo-mysql=mysqlnd \
+ --with-mysqli=mysqlnd \
+ --with-pgsql \
+ --with-pdo-pgsql \
+ --with-pdo-sqlite \
+ --enable-intl \
+ --without-pear \
+ --enable-gd \
+ --with-jpeg \
+ --with-webp \
+ --with-freetype \
+ --with-xpm \
+ --enable-exif \
+ --with-zip \
+ --with-zlib \
+ --with-zlib-dir=/usr \
+ --enable-soap \
+ --enable-xmlreader \
+ --with-xsl \
+ --with-tidy \
+ --enable-sysvsem \
+ --enable-sysvshm \
+ --enable-shmop \
+ --enable-pcntl \
+ --with-readline \
+ --enable-mbstring \
+ --with-curl \
+ --with-gettext \
+ --enable-sockets \
+ --with-bz2 \
+ --with-openssl \
+ --with-gmp \
+ --enable-bcmath \
+ --enable-calendar \
+ --enable-ftp \
+ --with-pspell=/usr \
+ --with-enchant=/usr \
+ --with-kerberos \
+ --enable-sysvmsg \
+ --with-ffi \
+ --enable-zend-test \
+ --enable-dl-test=shared \
+ --with-ldap \
+ --with-ldap-sasl \
+ --with-password-argon2 \
+ --with-mhash \
+ --with-sodium \
+ --enable-dba \
+ --with-cdb \
+ --enable-flatfile \
+ --enable-inifile \
+ --with-tcadb \
+ --with-lmdb \
+ --with-qdbm \
+ --with-snmp \
+ `#--with-unixODBC` \
+ --with-imap \
+ --with-kerberos \
+ --with-imap-ssl \
+ `#--with-pdo-odbc=unixODBC,/usr` \
+ `#--with-pdo-oci=shared,instantclient,/opt/oracle/instantclient` \
+ `#--with-oci8=shared,instantclient,/opt/oracle/instantclient` \
+ --with-config-file-path=/etc \
+ --with-config-file-scan-dir=/etc/php.d \
+ --with-pdo-firebird \
+ `#--with-pdo-dblib` \
+ --disable-phpdbg \
+ `#--enable-werror`
+ - run:
+ name: make
+ command: make -j2 > /dev/null
+ - run:
+ name: make install
+ command: |
+ sudo make install
+ sudo mkdir -p /etc/php.d
+ sudo chmod 777 /etc/php.d
+ echo opcache.enable_cli=1 > /etc/php.d/opcache.ini
+ echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini
+ - run:
+ name: Test
+ command: |
+ sapi/cli/php run-tests.php \
+ -d zend_extension=opcache.so \
+ -d opcache.enable_cli=1 \
+ -d opcache.jit_buffer_size=16M \
+ -d opcache.jit=tracing \
+ -P -q -x -j2 \
+ -g FAIL,BORK,LEAK,XLEAK \
+ --offline \
+ --show-diff \
+ --show-slow 1000 \
+ --set-timeout 120 \
+ --repeat 2
+
+workflows:
+ push-workflow:
+ jobs:
+ - arm
diff --git a/.cirrus.yml b/.cirrus.yml
index 9ef70fb59191c..b04d91b9d45b2 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -3,7 +3,6 @@ env:
freebsd_task:
name: FREEBSD_DEBUG_NTS
- only_if: $CIRRUS_CRON == 'nightly' || $CIRRUS_CHANGE_TITLE =~ '.*\[ci freebsd\].*'
freebsd_instance:
image_family: freebsd-13-2
env:
@@ -27,203 +26,3 @@ freebsd_task:
- export SKIP_IO_CAPTURE_TESTS=1
- export CI_NO_IPV6=1
- sapi/cli/php run-tests.php -P -q -j2 -g FAIL,XFAIL,BORK,WARN,LEAK,XLEAK,SKIP --offline --show-diff --show-slow 1000 --set-timeout 120 -d zend_extension=opcache.so
-
-arm_task:
- name: ARM_DEBUG_NTS
- only_if: $CIRRUS_CRON == 'nightly' || $CIRRUS_CHANGE_TITLE =~ '.*\[ci arm\].*'
- arm_container:
- image: debian:11
- additional_containers:
- - name: mysql
- image: mysql:8
- port: 3306
- cpu: 1.0
- memory: 1G
- env:
- MYSQL_ALLOW_EMPTY_PASSWORD: true
- MYSQL_ROOT_PASSWORD: ""
- MYSQL_DATABASE: "test"
- - name: postgres
- image: postgres:latest
- port: 5432
- env:
- POSTGRES_PASSWORD: "postgres"
- POSTGRES_DB: "test"
- install_script:
- - export DEBIAN_FRONTEND=noninteractive
- - apt-get update -y
- - >-
- apt-get install -y
- gcc
- g++
- autoconf
- bison
- re2c
- locales
- locales-all
- ldap-utils
- openssl
- slapd
- libgmp-dev
- libicu-dev
- libtidy-dev
- libenchant-2-dev
- libaspell-dev
- libpspell-dev
- libsasl2-dev
- libxpm-dev
- libzip-dev
- libbz2-dev
- libsqlite3-dev
- libwebp-dev
- libonig-dev
- libkrb5-dev
- libgssapi-krb5-2
- libcurl4-openssl-dev
- libxml2-dev
- libxslt1-dev
- libpq-dev
- libreadline-dev
- libldap2-dev
- libsodium-dev
- libargon2-0-dev
- libmm-dev
- libsnmp-dev
- snmpd
- `#snmp-mibs-downloader`
- freetds-dev
- `#unixodbc-dev`
- libc-client-dev
- dovecot-core
- dovecot-pop3d
- dovecot-imapd
- sendmail
- firebird-dev
- liblmdb-dev
- libtokyocabinet-dev
- libdb-dev
- libqdbm-dev
- libjpeg-dev
- libpng-dev
- libfreetype6-dev
- build_script:
- - ./buildconf -f
- - >-
- ./configure
- --enable-debug
- --enable-zts
- --enable-option-checking=fatal
- --prefix=/usr
- --enable-phpdbg
- --enable-fpm
- --enable-opcache
- --with-pdo-mysql=mysqlnd
- --with-mysqli=mysqlnd
- --with-pgsql
- --with-pdo-pgsql
- --with-pdo-sqlite
- --enable-intl
- --without-pear
- --enable-gd
- --with-jpeg
- --with-webp
- --with-freetype
- --with-xpm
- --enable-exif
- --with-zip
- --with-zlib
- --with-zlib-dir=/usr
- --enable-soap
- --enable-xmlreader
- --with-xsl
- --with-tidy
- --enable-sysvsem
- --enable-sysvshm
- --enable-shmop
- --enable-pcntl
- --with-readline
- --enable-mbstring
- --with-curl
- --with-gettext
- --enable-sockets
- --with-bz2
- --with-openssl
- --with-gmp
- --enable-bcmath
- --enable-calendar
- --enable-ftp
- --with-pspell=/usr
- --with-enchant=/usr
- --with-kerberos
- --enable-sysvmsg
- --with-ffi
- --enable-zend-test
- --enable-dl-test=shared
- --with-ldap
- --with-ldap-sasl
- --with-password-argon2
- --with-mhash
- --with-sodium
- --enable-dba
- --with-cdb
- --enable-flatfile
- --enable-inifile
- --with-tcadb
- --with-lmdb
- --with-qdbm
- --with-snmp
- `#--with-unixODBC`
- --with-imap
- --with-kerberos
- --with-imap-ssl
- `#--with-pdo-odbc=unixODBC,/usr`
- `#--with-pdo-oci=shared,instantclient,/opt/oracle/instantclient`
- `#--with-oci8=shared,instantclient,/opt/oracle/instantclient`
- --with-config-file-path=/etc
- --with-config-file-scan-dir=/etc/php.d
- --with-pdo-firebird
- `#--with-pdo-dblib`
- --disable-phpdbg
- `#--enable-werror`
- - make -j2 > /dev/null
- - make install
- - mkdir -p /etc/php.d
- - echo opcache.enable_cli=1 > /etc/php.d/opcache.ini
- - echo opcache.protect_memory=1 >> /etc/php.d/opcache.ini
- # Specify opcache.preload_user as we're running as root.
- - echo opcache.preload_user=root >> /etc/php.d/opcache.ini
- tests_script:
- - export SKIP_IO_CAPTURE_TESTS=1
- - export CI_NO_IPV6=1
- - export MYSQL_TEST_HOST=127.0.0.1
- - export MYSQL_TEST_USER=root
- - export MYSQL_TEST_PASSWD=
- - export PDO_MYSQL_TEST_DSN="mysql:host=127.0.0.1;dbname=test"
- - export PDO_MYSQL_TEST_USER=root
- - export PDO_MYSQL_TEST_PASS=
- - export PDO_PGSQL_TEST_DSN="pgsql:host=127.0.0.1 port=5432 dbname=test user=postgres password=postgres"
- - >-
- sapi/cli/php run-tests.php
- -d zend_extension=opcache.so
- -d opcache.enable_cli=1
- -d opcache.jit_buffer_size=16M
- -d opcache.jit=function
- -P -q -x -j2
- -g FAIL,BORK,LEAK,XLEAK
- --offline
- --show-diff
- --show-slow 1000
- --set-timeout 120
- - >-
- sapi/cli/php run-tests.php
- -d zend_extension=opcache.so
- -d opcache.enable_cli=1
- -d opcache.jit_buffer_size=16M
- -d opcache.jit=tracing
- -P -q -x -j2
- -g FAIL,BORK,LEAK,XLEAK
- --offline
- --show-diff
- --show-slow 1000
- --set-timeout 120
- --repeat 2
diff --git a/.github/actions/test-linux/action.yml b/.github/actions/test-linux/action.yml
index 7d66d2235208d..1dfba39478740 100644
--- a/.github/actions/test-linux/action.yml
+++ b/.github/actions/test-linux/action.yml
@@ -31,6 +31,7 @@ runs:
export SKIP_IO_CAPTURE_TESTS=1
sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \
-d opcache.jit=${{ inputs.jitType }} \
+ -d opcache.jit_buffer_size=16M \
-j$(/usr/bin/nproc) \
-g FAIL,XFAIL,BORK,WARN,LEAK,XLEAK,SKIP \
--offline \
diff --git a/.github/actions/test-macos/action.yml b/.github/actions/test-macos/action.yml
index 6036ce1e5a9b6..3bf0fdb7097af 100644
--- a/.github/actions/test-macos/action.yml
+++ b/.github/actions/test-macos/action.yml
@@ -16,6 +16,7 @@ runs:
export CI_NO_IPV6=1
sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \
-d opcache.jit=${{ inputs.jitType }} \
+ -d opcache.jit_buffer_size=16M \
-j$(sysctl -n hw.ncpu) \
-g FAIL,XFAIL,BORK,WARN,LEAK,XLEAK,SKIP \
--offline \
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 7283f10672da3..f945ec23c9e3e 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -89,7 +89,6 @@ jobs:
${{ matrix.run_tests_parameters }}
-d zend_extension=opcache.so
-d opcache.enable_cli=1
- -d opcache.jit_buffer_size=16M
- name: Test OpCache
uses: ./.github/actions/test-linux
with:
@@ -108,7 +107,6 @@ jobs:
${{ matrix.run_tests_parameters }}
-d zend_extension=opcache.so
-d opcache.enable_cli=1
- -d opcache.jit_buffer_size=16M
- name: Verify generated files are up to date
uses: ./.github/actions/verify-generated-files
- name: Notify Slack
@@ -171,7 +169,6 @@ jobs:
${{ matrix.run_tests_parameters }}
-d zend_extension=opcache.so
-d opcache.enable_cli=1
- -d opcache.jit_buffer_size=16M
- name: Test OpCache
uses: ./.github/actions/test-linux
with:
@@ -187,7 +184,6 @@ jobs:
${{ matrix.run_tests_parameters }}
-d zend_extension=opcache.so
-d opcache.enable_cli=1
- -d opcache.jit_buffer_size=16M
- name: Notify Slack
if: failure()
uses: ./.github/actions/notify-slack
@@ -233,7 +229,6 @@ jobs:
-d zend_extension=opcache.so
-d opcache.enable_cli=1
-d opcache.protect_memory=1
- -d opcache.jit_buffer_size=16M
- name: Test OpCache
uses: ./.github/actions/test-macos
with:
@@ -249,7 +244,6 @@ jobs:
-d zend_extension=opcache.so
-d opcache.enable_cli=1
-d opcache.protect_memory=1
- -d opcache.jit_buffer_size=16M
- name: Verify generated files are up to date
uses: ./.github/actions/verify-generated-files
- name: Notify Slack
@@ -347,7 +341,7 @@ jobs:
git rev-parse HEAD
php /usr/bin/composer install --no-progress --ignore-platform-reqs
# Hack to disable a test that hangs
- php -r '$c = file_get_contents("tests/Filesystem/FilesystemTest.php"); $c = str_replace("*/\n public function testSharedGet()", "* @group skip\n */\n public function testSharedGet()", $c); file_put_contents("tests/Filesystem/FilesystemTest.php", $c);'
+ 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);'
export ASAN_OPTIONS=exitcode=139
php vendor/bin/phpunit --exclude-group skip || EXIT_CODE=$?
if [ $EXIT_CODE -gt 128 ]; then
@@ -625,7 +619,7 @@ jobs:
- name: Build mysql-5.7
uses: ./.github/actions/build-libmysqlclient
with:
- libmysql: mysql-5.7.41-linux-glibc2.12-x86_64.tar.gz
+ libmysql: mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz
withMysqli: ${{ matrix.branch.ref == 'PHP-8.1' }}
- name: Test mysql-5.7
uses: ./.github/actions/test-libmysqlclient
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 37bdccd884a90..52f70f809e9ce 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -12,6 +12,7 @@ on:
- .cirrus.yml
- .travis.yml
- travis/*
+ - .circleci/*
branches:
- PHP-7.4
- PHP-8.0
@@ -29,6 +30,7 @@ on:
- .cirrus.yml
- .travis.yml
- travis/*
+ - .circleci/*
branches:
- '**'
concurrency:
@@ -89,7 +91,6 @@ jobs:
runTestsParameters: >-
-d zend_extension=opcache.so
-d opcache.enable_cli=1
- -d opcache.jit_buffer_size=16M
- name: Verify generated files are up to date
uses: ./.github/actions/verify-generated-files
MACOS_DEBUG_NTS:
@@ -122,7 +123,6 @@ jobs:
-d zend_extension=opcache.so
-d opcache.enable_cli=1
-d opcache.protect_memory=1
- -d opcache.jit_buffer_size=16M
- name: Verify generated files are up to date
uses: ./.github/actions/verify-generated-files
WINDOWS:
diff --git a/NEWS b/NEWS
index 694493cca265a..8a17587c29fc7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,71 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-?? ??? ????, PHP 8.1.25
+23 Nov 2023, PHP 8.1.26
+
+- Core:
+ . Fixed bug GH-12468 (Double-free of doc_comment when overriding static
+ property via trait). (ilutov)
+ . Fixed segfault caused by weak references to FFI objects. (sj-i)
+ . Fixed max_execution_time: don't delete an unitialized timer. (Kévin Dunglas)
+
+- DOM:
+ . Fix registerNodeClass with abstract class crashing. (nielsdos)
+ . Add missing NULL pointer error check. (icy17)
+ . Fix validation logic of php:function() callbacks. (nielsdos)
+
+- Fiber:
+ . Fixed bug GH-11121 (ReflectionFiber segfault). (danog, trowski, bwoebi)
+
+- FPM:
+ . Fixed bug GH-9921 (Loading ext in FPM config does not register module
+ handlers). (Jakub Zelenka)
+ . Fixed bug GH-12232 (FPM: segfault dynamically loading extension without
+ opcache). (Jakub Zelenka)
+
+- Intl:
+ . Removed the BC break on IntlDateFormatter::construct which threw an
+ exception with an invalid locale. (David Carlier)
+
+- Opcache:
+ . Added warning when JIT cannot be enabled. (danog)
+ . Fixed bug GH-8143 (Crashes in zend_accel_inheritance_cache_find since
+ upgrading to 8.1.3 due to corrupt on-disk file cache). (turchanov)
+
+- OpenSSL:
+ . Fixed bug GH-12489 (Missing sigbio creation checking in openssl_cms_verify).
+ (Jakub Zelenka)
+
+- PCRE:
+ . Fixed bug GH-11374 (Backport upstream fix, Different preg_match result
+ with -d pcre.jit=0). (mvorisek)
+
+- SOAP:
+ . Fixed bug GH-12392 (Segmentation fault on SoapClient::__getTypes).
+ (nielsdos)
+ . Fixed bug #66150 (SOAP WSDL cache race condition causes Segmentation
+ Fault). (nielsdos)
+ . Fixed bug #67617 (SOAP leaves incomplete cache file on ENOSPC). (nielsdos)
+ . Fix incorrect uri check in SOAP caching. (nielsdos)
+ . Fix segfault and assertion failure with refcounted props and arrays.
+ (nielsdos)
+ . Fix potential crash with an edge case of persistent encoders. (nielsdos)
+ . Fixed bug #75306 (Memleak in SoapClient). (nielsdos)
+
+- Streams:
+ . Fixed bug #75708 (getimagesize with "&$imageinfo" fails on StreamWrappers).
+ (Jakub Zelenka)
+
+- XMLReader:
+ . Add missing NULL pointer error check. (icy17)
+
+- XMLWriter:
+ . Add missing NULL pointer error check. (icy17)
+
+- XSL:
+ . Add missing module dependency. (nielsdos)
+ . Fix validation logic of php:function() callbacks. (nielsdos)
+
+26 Oct 2023, PHP 8.1.25
- Core:
. Fixed bug GH-12207 (memory leak when class using trait with doc block).
diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c
index 72441c000e660..f0aaeb229351b 100644
--- a/Zend/Optimizer/block_pass.c
+++ b/Zend/Optimizer/block_pass.c
@@ -172,6 +172,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
&& opline->opcode != ZEND_SWITCH_LONG
&& opline->opcode != ZEND_SWITCH_STRING
&& opline->opcode != ZEND_MATCH
+ && opline->opcode != ZEND_MATCH_ERROR
&& zend_optimizer_update_op1_const(op_array, opline, &c)) {
VAR_SOURCE(op1) = NULL;
if (opline->opcode != ZEND_JMP_NULL
diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c
index 4cc9f70c27f05..084a7abf9f7a7 100644
--- a/Zend/Optimizer/zend_inference.c
+++ b/Zend/Optimizer/zend_inference.c
@@ -77,11 +77,12 @@
#define CHECK_SCC_VAR(var2) \
do { \
if (!ssa->vars[var2].no_val) { \
- if (dfs[var2] < 0) { \
- zend_ssa_check_scc_var(op_array, ssa, var2, index, dfs, root, stack); \
+ if (ssa->vars[var2].scc < 0) { \
+ zend_ssa_check_scc_var(op_array, ssa, var2, index, stack); \
} \
- if (ssa->vars[var2].scc < 0 && dfs[root[var]] >= dfs[root[var2]]) { \
- root[var] = root[var2]; \
+ if (ssa->vars[var2].scc < ssa->vars[var].scc) { \
+ ssa->vars[var].scc = ssa->vars[var2].scc; \
+ is_root = 0; \
} \
} \
} while (0)
@@ -172,15 +173,17 @@ static inline bool sub_will_overflow(zend_long a, zend_long b) {
}
#endif
-static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa, int var, int *index, int *dfs, int *root, zend_worklist_stack *stack) /* {{{ */
+#if 0
+/* Recursive Pearce's SCC algorithm implementation */
+static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa, int var, int *index, zend_worklist_stack *stack) /* {{{ */
{
+ int is_root = 1;
#ifdef SYM_RANGE
zend_ssa_phi *p;
#endif
- dfs[var] = *index;
+ ssa->vars[var].scc = *index;
(*index)++;
- root[var] = var;
FOR_EACH_VAR_USAGE(var, CHECK_SCC_VAR);
@@ -193,17 +196,20 @@ static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa,
}
#endif
- if (root[var] == var) {
- ssa->vars[var].scc = ssa->sccs;
+ if (is_root) {
+ ssa->sccs--;
while (stack->len > 0) {
int var2 = zend_worklist_stack_peek(stack);
- if (dfs[var2] <= dfs[var]) {
+ if (ssa->vars[var2].scc < ssa->vars[var].scc) {
break;
}
zend_worklist_stack_pop(stack);
ssa->vars[var2].scc = ssa->sccs;
+ (*index)--;
}
- ssa->sccs++;
+ ssa->vars[var].scc = ssa->sccs;
+ ssa->vars[var].scc_entry = 1;
+ (*index)--;
} else {
zend_worklist_stack_push(stack, var);
}
@@ -212,50 +218,277 @@ static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa,
ZEND_API int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
{
- int index = 0, *dfs, *root;
+ int index = 0;
zend_worklist_stack stack;
int j;
- ALLOCA_FLAG(dfs_use_heap)
- ALLOCA_FLAG(root_use_heap)
ALLOCA_FLAG(stack_use_heap)
- dfs = do_alloca(sizeof(int) * ssa->vars_count, dfs_use_heap);
- memset(dfs, -1, sizeof(int) * ssa->vars_count);
- root = do_alloca(sizeof(int) * ssa->vars_count, root_use_heap);
ZEND_WORKLIST_STACK_ALLOCA(&stack, ssa->vars_count, stack_use_heap);
- /* Find SCCs using Tarjan's algorithm. */
+ /* Find SCCs using Pearce's algorithm. */
+ ssa->sccs = ssa->vars_count;
for (j = 0; j < ssa->vars_count; j++) {
- if (!ssa->vars[j].no_val && dfs[j] < 0) {
- zend_ssa_check_scc_var(op_array, ssa, j, &index, dfs, root, &stack);
+ if (!ssa->vars[j].no_val && ssa->vars[j].scc < 0) {
+ zend_ssa_check_scc_var(op_array, ssa, j, &index, &stack);
}
}
- /* Revert SCC order. This results in a topological order. */
+ if (ssa->sccs) {
+ /* Shift SCC indexes. */
+ for (j = 0; j < ssa->vars_count; j++) {
+ if (ssa->vars[j].scc >= 0) {
+ ssa->vars[j].scc -= ssa->sccs;
+ }
+ }
+ }
+ ssa->sccs = ssa->vars_count - ssa->sccs;
+
for (j = 0; j < ssa->vars_count; j++) {
if (ssa->vars[j].scc >= 0) {
- ssa->vars[j].scc = ssa->sccs - (ssa->vars[j].scc + 1);
+ int var = j;
+ FOR_EACH_VAR_USAGE(var, CHECK_SCC_ENTRY);
+ }
+ }
+
+ ZEND_WORKLIST_STACK_FREE_ALLOCA(&stack, stack_use_heap);
+ return SUCCESS;
+}
+/* }}} */
+
+#else
+/* Iterative Pearce's SCC algorithm implementation */
+
+typedef struct _zend_scc_iterator {
+ int state;
+ int last;
+ union {
+ int use;
+ zend_ssa_phi *phi;
+ };
+} zend_scc_iterator;
+
+static int zend_scc_next(const zend_op_array *op_array, zend_ssa *ssa, int var, zend_scc_iterator *iterator) /* {{{ */
+{
+ zend_ssa_phi *phi;
+ int use, var2;
+
+ switch (iterator->state) {
+ case 0: goto state_0;
+ case 1: use = iterator->use; goto state_1;
+ case 2: use = iterator->use; goto state_2;
+ case 3: use = iterator->use; goto state_3;
+ case 4: use = iterator->use; goto state_4;
+ case 5: use = iterator->use; goto state_5;
+ case 6: use = iterator->use; goto state_6;
+ case 7: use = iterator->use; goto state_7;
+ case 8: use = iterator->use; goto state_8;
+ case 9: phi = iterator->phi; goto state_9;
+#ifdef SYM_RANGE
+ case 10: phi = iterator->phi; goto state_10;
+#endif
+ case 11: goto state_11;
+ }
+
+state_0:
+ use = ssa->vars[var].use_chain;
+ while (use >= 0) {
+ iterator->use = use;
+ var2 = ssa->ops[use].op1_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 1;
+ return var2;
+ }
+state_1:
+ var2 = ssa->ops[use].op2_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 2;
+ return var2;
+ }
+state_2:
+ var2 = ssa->ops[use].result_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 3;
+ return var2;
+ }
+state_3:
+ if (op_array->opcodes[use].opcode == ZEND_OP_DATA) {
+ var2 = ssa->ops[use-1].op1_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 4;
+ return var2;
+ }
+state_4:
+ var2 = ssa->ops[use-1].op2_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 5;
+ return var2;
+ }
+state_5:
+ var2 = ssa->ops[use-1].result_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 8;
+ return var2;
+ }
+ } else if ((uint32_t)use+1 < op_array->last &&
+ op_array->opcodes[use+1].opcode == ZEND_OP_DATA) {
+ var2 = ssa->ops[use+1].op1_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 6;
+ return var2;
+ }
+state_6:
+ var2 = ssa->ops[use+1].op2_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 7;
+ return var2;
+ }
+state_7:
+ var2 = ssa->ops[use+1].result_def;
+ if (var2 >= 0 && !ssa->vars[var2].no_val) {
+ iterator->state = 8;
+ return var2;
+ }
+ }
+state_8:
+ use = zend_ssa_next_use(ssa->ops, var, use);
+ }
+
+ phi = ssa->vars[var].phi_use_chain;
+ while (phi) {
+ var2 = phi->ssa_var;
+ if (!ssa->vars[var2].no_val) {
+ iterator->state = 9;
+ iterator->phi = phi;
+ return var2;
+ }
+state_9:
+ phi = zend_ssa_next_use_phi(ssa, var, phi);
+ }
+
+#ifdef SYM_RANGE
+ /* Process symbolic control-flow constraints */
+ phi = ssa->vars[var].sym_use_chain;
+ while (phi) {
+ var2 = phi->ssa_var;
+ if (!ssa->vars[var2].no_val) {
+ iterator->state = 10;
+ iterator->phi = phi;
+ return var2;
+ }
+state_10:
+ phi = phi->sym_use_chain;
+ }
+#endif
+
+ iterator->state = 11;
+state_11:
+ return -1;
+}
+/* }}} */
+
+static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa, int var, int *index, zend_worklist_stack *stack, zend_worklist_stack *vstack, zend_scc_iterator *iterators) /* {{{ */
+{
+restart:
+ zend_worklist_stack_push(vstack, var);
+ iterators[var].state = 0;
+ iterators[var].last = -1;
+ ssa->vars[var].scc_entry = 1;
+ ssa->vars[var].scc = *index;
+ (*index)++;
+
+ while (vstack->len > 0) {
+ var = zend_worklist_stack_peek(vstack);
+ while (1) {
+ int var2;
+
+ if (iterators[var].last >= 0) {
+ /* finish edge */
+ var2 = iterators[var].last;
+ if (ssa->vars[var2].scc < ssa->vars[var].scc) {
+ ssa->vars[var].scc = ssa->vars[var2].scc;
+ ssa->vars[var].scc_entry = 0;
+ }
+ }
+ var2 = zend_scc_next(op_array, ssa, var, iterators + var);
+ iterators[var].last = var2;
+ if (var2 < 0) break;
+ /* begin edge */
+ if (ssa->vars[var2].scc < 0) {
+ var = var2;
+ goto restart;
+ }
+ }
+
+ /* finish visiting */
+ zend_worklist_stack_pop(vstack);
+ if (ssa->vars[var].scc_entry) {
+ ssa->sccs--;
+ while (stack->len > 0) {
+ int var2 = zend_worklist_stack_peek(stack);
+ if (ssa->vars[var2].scc < ssa->vars[var].scc) {
+ break;
+ }
+ zend_worklist_stack_pop(stack);
+ ssa->vars[var2].scc = ssa->sccs;
+ (*index)--;
+ }
+ ssa->vars[var].scc = ssa->sccs;
+ (*index)--;
+ } else {
+ zend_worklist_stack_push(stack, var);
+ }
+ }
+}
+/* }}} */
+
+ZEND_API int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
+{
+ int index = 0;
+ zend_worklist_stack stack, vstack;
+ zend_scc_iterator *iterators;
+ int j;
+ ALLOCA_FLAG(stack_use_heap)
+ ALLOCA_FLAG(vstack_use_heap)
+ ALLOCA_FLAG(iterators_use_heap)
+
+ iterators = do_alloca(sizeof(zend_scc_iterator) * ssa->vars_count, iterators_use_heap);
+ ZEND_WORKLIST_STACK_ALLOCA(&vstack, ssa->vars_count, vstack_use_heap);
+ ZEND_WORKLIST_STACK_ALLOCA(&stack, ssa->vars_count, stack_use_heap);
+
+ /* Find SCCs using Pearce's algorithm. */
+ ssa->sccs = ssa->vars_count;
+ for (j = 0; j < ssa->vars_count; j++) {
+ if (!ssa->vars[j].no_val && ssa->vars[j].scc < 0) {
+ zend_ssa_check_scc_var(op_array, ssa, j, &index, &stack, &vstack, iterators);
}
}
+ if (ssa->sccs) {
+ /* Shift SCC indexes. */
+ for (j = 0; j < ssa->vars_count; j++) {
+ if (ssa->vars[j].scc >= 0) {
+ ssa->vars[j].scc -= ssa->sccs;
+ }
+ }
+ }
+ ssa->sccs = ssa->vars_count - ssa->sccs;
+
for (j = 0; j < ssa->vars_count; j++) {
if (ssa->vars[j].scc >= 0) {
int var = j;
- if (root[j] == j) {
- ssa->vars[j].scc_entry = 1;
- }
FOR_EACH_VAR_USAGE(var, CHECK_SCC_ENTRY);
}
}
ZEND_WORKLIST_STACK_FREE_ALLOCA(&stack, stack_use_heap);
- free_alloca(root, root_use_heap);
- free_alloca(dfs, dfs_use_heap);
-
+ ZEND_WORKLIST_STACK_FREE_ALLOCA(&vstack, vstack_use_heap);
+ free_alloca(iterators, iterators_use_heap);
return SUCCESS;
}
/* }}} */
+#endif
+
ZEND_API int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
{
zend_ssa_var *ssa_vars = ssa->vars;
@@ -1746,6 +1979,12 @@ static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) {
} \
if (__var >= 0) { \
zend_ssa_var *__ssa_var = &ssa_vars[__var]; \
+ if (__ssa_var->var < op_array->num_args) { \
+ if (__type & MAY_BE_RC1) { \
+ /* TODO: may be captured by exception backtreace */ \
+ __type |= MAY_BE_RCN; \
+ } \
+ } \
if (__ssa_var->var < op_array->last_var) { \
if (__type & (MAY_BE_REF|MAY_BE_RCN)) { \
__type |= MAY_BE_RC1 | MAY_BE_RCN; \
@@ -2291,7 +2530,8 @@ static zend_always_inline int _zend_update_type_info(
* unreachable code. Propagate the empty result early, so that that the following
* code may assume that operands have at least one type. */
if (!(t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))
- || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))) {
+ || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))
+ || (ssa_op->result_use >= 0 && !(RES_USE_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS)))) {
tmp = 0;
if (ssa_op->result_def >= 0 && !(ssa_var_info[ssa_op->result_def].type & MAY_BE_REF)) {
UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
@@ -3306,10 +3546,18 @@ static zend_always_inline int _zend_update_type_info(
zend_uchar opcode;
if (!ssa_opcodes) {
- ZEND_ASSERT(j == (opline - op_array->opcodes) + 1 && "Use must be in next opline");
+ if (j != (opline - op_array->opcodes) + 1) {
+ /* Use must be in next opline */
+ tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
+ break;
+ }
opcode = op_array->opcodes[j].opcode;
} else {
- ZEND_ASSERT(ssa_opcodes[j] == opline + 1 && "Use must be in next opline");
+ if (ssa_opcodes[j] != opline + 1) {
+ /* Use must be in next opline */
+ tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
+ break;
+ }
opcode = ssa_opcodes[j]->opcode;
}
switch (opcode) {
@@ -3368,7 +3616,10 @@ static zend_always_inline int _zend_update_type_info(
EMPTY_SWITCH_DEFAULT_CASE()
}
j = zend_ssa_next_use(ssa->ops, ssa_op->result_def, j);
- ZEND_ASSERT(j < 0 && "There should only be one use");
+ if (j >= 0) {
+ tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
+ break;
+ }
}
}
if (((tmp & MAY_BE_ARRAY) && (tmp & MAY_BE_ARRAY_KEY_ANY))
@@ -3415,7 +3666,9 @@ static zend_always_inline int _zend_update_type_info(
UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
break;
case ZEND_FETCH_THIS:
- UPDATE_SSA_OBJ_TYPE(op_array->scope, 1, ssa_op->result_def);
+ if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
+ UPDATE_SSA_OBJ_TYPE(op_array->scope, 1, ssa_op->result_def);
+ }
UPDATE_SSA_TYPE(MAY_BE_RCN|MAY_BE_OBJECT, ssa_op->result_def);
break;
case ZEND_FETCH_OBJ_R:
diff --git a/Zend/tests/fibers/negative_stack_size.phpt b/Zend/tests/fibers/negative_stack_size.phpt
new file mode 100644
index 0000000000000..591a8f28878d1
--- /dev/null
+++ b/Zend/tests/fibers/negative_stack_size.phpt
@@ -0,0 +1,16 @@
+--TEST--
+fiber.stack_size must be a positive number
+--FILE--
+start();
+} catch (Throwable $e) {
+ echo "Exception: " . $e->getMessage()."\n";
+}
+?>
+DONE
+--EXPECTF--
+Warning: fiber.stack_size must be a positive number in %snegative_stack_size.php on line 2
+DONE
diff --git a/Zend/tests/gc_047.phpt b/Zend/tests/gc_047.phpt
new file mode 100644
index 0000000000000..08403d1e99bc9
--- /dev/null
+++ b/Zend/tests/gc_047.phpt
@@ -0,0 +1,20 @@
+--TEST--
+GC 047: Leak after GC inside a foreach loop
+--INI--
+zend.enable_gc=1
+--FILE--
+
+--EXPECT--
+int(2)
diff --git a/Zend/tests/gh12468_1.phpt b/Zend/tests/gh12468_1.phpt
new file mode 100644
index 0000000000000..a02a28c3e354c
--- /dev/null
+++ b/Zend/tests/gh12468_1.phpt
@@ -0,0 +1,18 @@
+--TEST--
+GH-12468: Double-free of doc_comment when overriding static property via trait
+--FILE--
+
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/tests/gh12468_2.phpt b/Zend/tests/gh12468_2.phpt
new file mode 100644
index 0000000000000..3097cf532e22c
--- /dev/null
+++ b/Zend/tests/gh12468_2.phpt
@@ -0,0 +1,19 @@
+--TEST--
+GH-12468: Double-free of doc_comment when overriding static property via trait
+--FILE--
+
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/zend.c b/Zend/zend.c
index 351e9ac5eea75..e6f92410c0881 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -177,7 +177,12 @@ static ZEND_INI_MH(OnSetExceptionStringParamMaxLen) /* {{{ */
static ZEND_INI_MH(OnUpdateFiberStackSize) /* {{{ */
{
if (new_value) {
- EG(fiber_stack_size) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
+ zend_long tmp = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
+ if (tmp < 0) {
+ zend_error(E_WARNING, "fiber.stack_size must be a positive number");
+ return FAILURE;
+ }
+ EG(fiber_stack_size) = tmp;
} else {
EG(fiber_stack_size) = ZEND_FIBER_DEFAULT_C_STACK_SIZE;
}
diff --git a/Zend/zend.h b/Zend/zend.h
index bc9862de9f687..b971a1fbb103c 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -20,7 +20,7 @@
#ifndef ZEND_H
#define ZEND_H
-#define ZEND_VERSION "4.1.25-dev"
+#define ZEND_VERSION "4.1.26"
#define ZEND_ENGINE_3
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 1178133046679..5fd38a25c8b78 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2271,7 +2271,8 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
post_deactivate_count++;
}
} ZEND_HASH_FOREACH_END();
- module_request_startup_handlers = (zend_module_entry**)malloc(
+ module_request_startup_handlers = (zend_module_entry**)realloc(
+ module_request_startup_handlers,
sizeof(zend_module_entry*) *
(startup_count + 1 +
shutdown_count + 1 +
@@ -2303,7 +2304,8 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
}
} ZEND_HASH_FOREACH_END();
- class_cleanup_handlers = (zend_class_entry**)malloc(
+ class_cleanup_handlers = (zend_class_entry**)realloc(
+ class_cleanup_handlers,
sizeof(zend_class_entry*) *
(class_count + 1));
class_cleanup_handlers[class_count] = NULL;
@@ -2329,7 +2331,9 @@ ZEND_API void zend_startup_modules(void) /* {{{ */
ZEND_API void zend_destroy_modules(void) /* {{{ */
{
free(class_cleanup_handlers);
+ class_cleanup_handlers = NULL;
free(module_request_startup_handlers);
+ module_request_startup_handlers = NULL;
zend_hash_graceful_reverse_destroy(&module_registry);
}
/* }}} */
@@ -4120,7 +4124,7 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
(property_info_ptr->flags & ZEND_ACC_STATIC) != 0) {
property_info->offset = property_info_ptr->offset;
zval_ptr_dtor(&ce->default_static_members_table[property_info->offset]);
- if (property_info_ptr->doc_comment) {
+ if (property_info_ptr->doc_comment && property_info_ptr->ce == ce) {
zend_string_release(property_info_ptr->doc_comment);
}
zend_hash_del(&ce->properties_info, name);
@@ -4145,7 +4149,7 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
(property_info_ptr->flags & ZEND_ACC_STATIC) == 0) {
property_info->offset = property_info_ptr->offset;
zval_ptr_dtor(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)]);
- if (property_info_ptr->doc_comment) {
+ if (property_info_ptr->doc_comment && property_info_ptr->ce == ce) {
zend_string_release_ex(property_info_ptr->doc_comment, 1);
}
zend_hash_del(&ce->properties_info, name);
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index 7fd41f3b1ab96..c41f6118607e2 100644
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@ -1914,7 +1914,7 @@ static zend_mm_heap *zend_mm_init(void)
heap->peak = 0;
#endif
#if ZEND_MM_LIMIT
- heap->limit = ((size_t)Z_L(-1) >> (size_t)Z_L(1));
+ heap->limit = (size_t)Z_L(-1) >> 1;
heap->overflow = 0;
#endif
#if ZEND_MM_CUSTOM
@@ -2859,7 +2859,7 @@ static void alloc_globals_ctor(zend_alloc_globals *alloc_globals)
zend_mm_heap *mm_heap = alloc_globals->mm_heap = malloc(sizeof(zend_mm_heap));
memset(mm_heap, 0, sizeof(zend_mm_heap));
mm_heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_STD;
- mm_heap->limit = ((size_t)Z_L(-1) >> (size_t)Z_L(1));
+ mm_heap->limit = (size_t)Z_L(-1) >> 1;
mm_heap->overflow = 0;
if (!tracked) {
@@ -3048,7 +3048,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
heap->peak = 0;
#endif
#if ZEND_MM_LIMIT
- heap->limit = (Z_L(-1) >> Z_L(1));
+ heap->limit = (size_t)Z_L(-1) >> 1;
heap->overflow = 0;
#endif
#if ZEND_MM_CUSTOM
diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c
index 59aa63ba21b43..c80d65868d37e 100644
--- a/Zend/zend_fibers.c
+++ b/Zend/zend_fibers.c
@@ -554,6 +554,10 @@ static zend_always_inline zend_fiber_transfer zend_fiber_resume(zend_fiber *fibe
{
zend_fiber *previous = EG(active_fiber);
+ if (previous) {
+ previous->execute_data = EG(current_execute_data);
+ }
+
fiber->caller = EG(current_fiber_context);
EG(active_fiber) = fiber;
@@ -571,6 +575,7 @@ static zend_always_inline zend_fiber_transfer zend_fiber_suspend(zend_fiber *fib
zend_fiber_context *caller = fiber->caller;
fiber->previous = EG(current_fiber_context);
fiber->caller = NULL;
+ fiber->execute_data = EG(current_execute_data);
return zend_fiber_switch_to(caller, value, false);
}
@@ -741,7 +746,6 @@ ZEND_METHOD(Fiber, suspend)
ZEND_ASSERT(fiber->context.status == ZEND_FIBER_STATUS_RUNNING || fiber->context.status == ZEND_FIBER_STATUS_SUSPENDED);
- fiber->execute_data = EG(current_execute_data);
fiber->stack_bottom->prev_execute_data = NULL;
zend_fiber_transfer transfer = zend_fiber_suspend(fiber, value);
diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c
index f062747eaeb63..c9034ba5e34c6 100644
--- a/Zend/zend_gc.c
+++ b/Zend/zend_gc.c
@@ -1696,7 +1696,7 @@ static void zend_gc_root_tmpvars(void) {
}
uint32_t kind = range->var & ZEND_LIVE_MASK;
- if (kind == ZEND_LIVE_TMPVAR) {
+ if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) {
uint32_t var_num = range->var & ~ZEND_LIVE_MASK;
zval *var = ZEND_CALL_VAR(ex, var_num);
if (Z_REFCOUNTED_P(var)) {
diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c
index 1b4710eb503a0..866e1b9c2097c 100644
--- a/Zend/zend_ini.c
+++ b/Zend/zend_ini.c
@@ -211,7 +211,6 @@ ZEND_API zend_result zend_register_ini_entries_ex(const zend_ini_entry_def *ini_
* lead to death.
*/
if (directives != EG(ini_directives)) {
- ZEND_ASSERT(module_type == MODULE_TEMPORARY);
directives = EG(ini_directives);
} else {
ZEND_ASSERT(module_type == MODULE_PERSISTENT);
diff --git a/Zend/zend_list.c b/Zend/zend_list.c
index b3409e33ce845..369eb08d16107 100644
--- a/Zend/zend_list.c
+++ b/Zend/zend_list.c
@@ -275,6 +275,7 @@ ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_fu
ZVAL_PTR(&zv, lde);
if (zend_hash_next_index_insert(&list_destructors, &zv) == NULL) {
+ free(lde);
return FAILURE;
}
return list_destructors.nNextFreeElement-1;
diff --git a/Zend/zend_max_execution_timer.c b/Zend/zend_max_execution_timer.c
index b1c83e9cbb3a6..480631dcb169a 100644
--- a/Zend/zend_max_execution_timer.c
+++ b/Zend/zend_max_execution_timer.c
@@ -41,12 +41,13 @@ ZEND_API void zend_max_execution_timer_init(void) /* {{{ */
sev.sigev_signo = SIGRTMIN;
sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid);
- EG(pid) = getpid();
// Measure wall time instead of CPU time as originally planned now that it is possible https://github.com/php/php-src/pull/6504#issuecomment-1370303727
if (timer_create(CLOCK_BOOTTIME, &sev, &EG(max_execution_timer_timer)) != 0) {
zend_strerror_noreturn(E_ERROR, errno, "Could not create timer");
}
+ EG(pid) = getpid();
+
# ifdef MAX_EXECUTION_TIMERS_DEBUG
fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(max_execution_timer_timer), sev.sigev_notify_thread_id);
# endif
diff --git a/configure.ac b/configure.ac
index 07fdab313cd4b..782c61d951b1c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice.
dnl ----------------------------------------------------------------------------
AC_PREREQ([2.68])
-AC_INIT([PHP],[8.1.25-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net])
+AC_INIT([PHP],[8.1.26],[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 --git a/ext/dl_test/dl_test.c b/ext/dl_test/dl_test.c
index 88a298b0ec88a..fed881b2e994c 100644
--- a/ext/dl_test/dl_test.c
+++ b/ext/dl_test/dl_test.c
@@ -69,6 +69,10 @@ PHP_MINIT_FUNCTION(dl_test)
REGISTER_INI_ENTRIES();
}
+ if (getenv("PHP_DL_TEST_MODULE_DEBUG")) {
+ fprintf(stderr, "DL TEST MINIT\n");
+ }
+
return SUCCESS;
}
/* }}} */
@@ -83,6 +87,10 @@ static PHP_MSHUTDOWN_FUNCTION(dl_test)
UNREGISTER_INI_ENTRIES();
}
+ if (getenv("PHP_DL_TEST_MODULE_DEBUG")) {
+ fprintf(stderr, "DL TEST MSHUTDOWN\n");
+ }
+
return SUCCESS;
}
/* }}} */
@@ -94,6 +102,21 @@ PHP_RINIT_FUNCTION(dl_test)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
+ if (getenv("PHP_DL_TEST_MODULE_DEBUG")) {
+ fprintf(stderr, "DL TEST RINIT\n");
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RSHUTDOWN_FUNCTION */
+PHP_RSHUTDOWN_FUNCTION(dl_test)
+{
+ if (getenv("PHP_DL_TEST_MODULE_DEBUG")) {
+ fprintf(stderr, "DL TEST RSHUTDOWN\n");
+ }
+
return SUCCESS;
}
/* }}} */
@@ -127,7 +150,7 @@ zend_module_entry dl_test_module_entry = {
PHP_MINIT(dl_test),
PHP_MSHUTDOWN(dl_test),
PHP_RINIT(dl_test),
- NULL,
+ PHP_RSHUTDOWN(dl_test),
PHP_MINFO(dl_test),
PHP_DL_TEST_VERSION,
PHP_MODULE_GLOBALS(dl_test),
diff --git a/ext/dom/document.c b/ext/dom/document.c
index 64da4f051be2c..59f00897a69aa 100644
--- a/ext/dom/document.c
+++ b/ext/dom/document.c
@@ -1148,6 +1148,9 @@ char *_dom_get_valid_file_path(char *source, char *resolved_path, int resolved_p
int isFileUri = 0;
uri = xmlCreateURI();
+ if (uri == NULL) {
+ return NULL;
+ }
escsource = xmlURIEscapeStr((xmlChar *) source, (xmlChar *) ":");
xmlParseURIReference(uri, (char *) escsource);
xmlFree(escsource);
@@ -2096,6 +2099,10 @@ PHP_METHOD(DOMDocument, registerNodeClass)
}
if (ce == NULL || instanceof_function(ce, basece)) {
+ if (UNEXPECTED(ce != NULL && (ce->ce_flags & ZEND_ACC_ABSTRACT))) {
+ zend_argument_value_error(2, "must not be an abstract class");
+ RETURN_THROWS();
+ }
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
dom_set_doc_classmap(intern->document, basece, ce);
RETURN_TRUE;
diff --git a/ext/dom/tests/php_function_edge_cases.phpt b/ext/dom/tests/php_function_edge_cases.phpt
new file mode 100644
index 0000000000000..1091b50ce19bd
--- /dev/null
+++ b/ext/dom/tests/php_function_edge_cases.phpt
@@ -0,0 +1,27 @@
+--TEST--
+php:function() edge cases
+--EXTENSIONS--
+dom
+--FILE--
+loadHTML('hello');
+$xpath = new DOMXpath($doc);
+$xpath->registerNamespace("php", "http://php.net/xpath");
+$xpath->registerPHPFunctions();
+try {
+ $xpath->query("//a[php:function(3)]");
+} catch (TypeError $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ $xpath->query("//a[php:function()]");
+} catch (Throwable $e) {
+ echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+Handler name must be a string
+Function name must be passed as the first argument
diff --git a/ext/dom/tests/registerNodeClass_abstract_class.phpt b/ext/dom/tests/registerNodeClass_abstract_class.phpt
new file mode 100644
index 0000000000000..24124d712ea09
--- /dev/null
+++ b/ext/dom/tests/registerNodeClass_abstract_class.phpt
@@ -0,0 +1,24 @@
+--TEST--
+registerNodeClass() with an abstract class should fail
+--EXTENSIONS--
+dom
+--FILE--
+registerNodeClass("DOMElement", "Test");
+} catch (ValueError $e) {
+ echo "ValueError: ", $e->getMessage(), "\n";
+}
+
+$dom->createElement("foo");
+
+?>
+--EXPECT--
+ValueError: DOMDocument::registerNodeClass(): Argument #2 ($extendedClass) must not be an abstract class
diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c
index 62e11f6b99bfb..73ceb49362781 100644
--- a/ext/dom/xpath.c
+++ b/ext/dom/xpath.c
@@ -70,12 +70,17 @@ static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs,
return;
}
+ if (UNEXPECTED(nargs == 0)) {
+ zend_throw_error(NULL, "Function name must be passed as the first argument");
+ return;
+ }
+
fci.param_count = nargs - 1;
if (fci.param_count > 0) {
fci.params = safe_emalloc(fci.param_count, sizeof(zval), 0);
}
/* Reverse order to pop values off ctxt stack */
- for (i = nargs - 2; i >= 0; i--) {
+ for (i = fci.param_count - 1; i >= 0; i--) {
obj = valuePop(ctxt);
switch (obj->type) {
case XPATH_STRING:
@@ -128,11 +133,12 @@ static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs,
fci.size = sizeof(fci);
+ /* Last element of the stack is the function name */
obj = valuePop(ctxt);
if (obj->stringval == NULL) {
zend_type_error("Handler name must be a string");
xmlXPathFreeObject(obj);
- goto cleanup;
+ goto cleanup_no_callable;
}
ZVAL_STRING(&fci.function_name, (char *) obj->stringval);
xmlXPathFreeObject(obj);
@@ -177,6 +183,7 @@ static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs,
cleanup:
zend_string_release_ex(callable, 0);
zval_ptr_dtor_nogc(&fci.function_name);
+cleanup_no_callable:
if (fci.param_count > 0) {
for (i = 0; i < nargs - 1; i++) {
zval_ptr_dtor(&fci.params[i]);
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index efb4524c76b1a..a2779b65b120c 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -24,6 +24,7 @@
#include "php_scandir.h"
#include "zend_exceptions.h"
#include "zend_closures.h"
+#include "zend_weakrefs.h"
#include "main/SAPI.h"
#include "ffi_arginfo.h"
@@ -2143,6 +2144,10 @@ static void zend_ffi_ctype_free_obj(zend_object *object) /* {{{ */
zend_ffi_ctype *ctype = (zend_ffi_ctype*)object;
zend_ffi_type_dtor(ctype->type);
+
+ if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) {
+ zend_weakrefs_notify(object);
+ }
}
/* }}} */
@@ -2369,6 +2374,10 @@ static void zend_ffi_free_obj(zend_object *object) /* {{{ */
zend_hash_destroy(ffi->tags);
efree(ffi->tags);
}
+
+ if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) {
+ zend_weakrefs_notify(object);
+ }
}
/* }}} */
@@ -2377,6 +2386,10 @@ static void zend_ffi_cdata_free_obj(zend_object *object) /* {{{ */
zend_ffi_cdata *cdata = (zend_ffi_cdata*)object;
zend_ffi_cdata_dtor(cdata);
+
+ if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) {
+ zend_weakrefs_notify(object);
+ }
}
/* }}} */
diff --git a/ext/ffi/tests/weak_reference_001.phpt b/ext/ffi/tests/weak_reference_001.phpt
new file mode 100644
index 0000000000000..56f0be981f629
--- /dev/null
+++ b/ext/ffi/tests/weak_reference_001.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Weak reference to \FFI
+--EXTENSIONS--
+ffi
+--INI--
+ffi.enable=1
+--FILE--
+get() === $ffi);
+unset($ffi);
+var_dump($ref->get() === null);
+?>
+--EXPECTF--
+bool(true)
+bool(true)
diff --git a/ext/ffi/tests/weak_reference_002.phpt b/ext/ffi/tests/weak_reference_002.phpt
new file mode 100644
index 0000000000000..5c36cfa703455
--- /dev/null
+++ b/ext/ffi/tests/weak_reference_002.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Weak reference to \FFI\CData
+--EXTENSIONS--
+ffi
+--INI--
+ffi.enable=1
+--FILE--
+get() === $cdata_value);
+var_dump($ref_array->get() === $cdata_array);
+var_dump($ref_free->get() === $cdata_free);
+
+unset($cdata_value);
+unset($cdata_array);
+unset($cdata_free);
+
+var_dump($ref_value->get() === null);
+var_dump($ref_array->get() === null);
+var_dump($ref_free->get() === null);
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/ffi/tests/weak_reference_003.phpt b/ext/ffi/tests/weak_reference_003.phpt
new file mode 100644
index 0000000000000..15b9397a6856b
--- /dev/null
+++ b/ext/ffi/tests/weak_reference_003.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Weak reference to \FFI\CType
+--EXTENSIONS--
+ffi
+--INI--
+ffi.enable=1
+--FILE--
+get() === $ctype);
+unset($ctype);
+var_dump($ref->get() === null);
+?>
+--EXPECTF--
+bool(true)
+bool(true)
diff --git a/ext/ffi/tests/weak_reference_004.phpt b/ext/ffi/tests/weak_reference_004.phpt
new file mode 100644
index 0000000000000..500776fa21865
--- /dev/null
+++ b/ext/ffi/tests/weak_reference_004.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Using FFI Types for keys of a WeakMap
+--EXTENSIONS--
+ffi
+--INI--
+ffi.enable=1
+--FILE--
+
+--EXPECTF--
+bool(true)
+bool(true)
diff --git a/ext/intl/dateformat/dateformat_create.cpp b/ext/intl/dateformat/dateformat_create.cpp
index e14eb4f1a2f8a..5c96f41fadf35 100644
--- a/ext/intl/dateformat/dateformat_create.cpp
+++ b/ext/intl/dateformat/dateformat_create.cpp
@@ -113,8 +113,7 @@ static zend_result datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_error_handlin
locale = Locale::createFromName(locale_str);
/* get*Name accessors being set does not preclude being bogus */
if (locale.isBogus() || strlen(locale.getISO3Language()) == 0) {
- intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: invalid locale", 0);
- return FAILURE;
+ goto error;
}
/* process calendar */
diff --git a/ext/intl/tests/gh12282.phpt b/ext/intl/tests/gh12282.phpt
index 62d090ba6166b..a30899a08c7d0 100644
--- a/ext/intl/tests/gh12282.phpt
+++ b/ext/intl/tests/gh12282.phpt
@@ -5,17 +5,18 @@ intl
--FILE--
getMessage();
-}
+));
+Locale::setDefault('xx');
+var_dump(new IntlDateFormatter(Locale::getDefault()));
--EXPECT--
-datefmt_create: invalid locale: U_ILLEGAL_ARGUMENT_ERROR
+object(IntlDateFormatter)#1 (0) {
+}
+object(IntlDateFormatter)#1 (0) {
+}
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 429eadf023eb0..530620f6259ff 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -3270,6 +3270,11 @@ static zend_result accel_post_startup(void)
|| zend_jit_startup(ZSMMG(reserved), jit_size, reattached) != SUCCESS) {
JIT_G(enabled) = 0;
JIT_G(on) = 0;
+ /* The JIT is implicitly disabled with opcache.jit_buffer_size=0, so we don't want to
+ * emit a warning here. */
+ if (JIT_G(buffer_size) != 0) {
+ zend_accel_error(ACCEL_LOG_WARNING, "Could not enable JIT!");
+ }
}
}
#endif
diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c
index d969f744e6b4b..4d2baddb90090 100644
--- a/ext/opcache/jit/zend_jit.c
+++ b/ext/opcache/jit/zend_jit.c
@@ -5113,7 +5113,7 @@ ZEND_EXT_API void zend_jit_activate(void)
ZEND_EXT_API void zend_jit_deactivate(void)
{
- if (zend_jit_profile_counter) {
+ if (zend_jit_profile_counter && !CG(unclean_shutdown)) {
zend_class_entry *ce;
zend_shared_alloc_lock();
@@ -5131,9 +5131,9 @@ ZEND_EXT_API void zend_jit_deactivate(void)
zend_jit_protect();
SHM_PROTECT();
zend_shared_alloc_unlock();
-
- zend_jit_profile_counter = 0;
}
+
+ zend_jit_profile_counter = 0;
}
static void zend_jit_restart_preloaded_op_array(zend_op_array *op_array)
diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc
index 0a0bd23c3160a..1583706855d41 100644
--- a/ext/opcache/jit/zend_jit_arm64.dasc
+++ b/ext/opcache/jit/zend_jit_arm64.dasc
@@ -14932,6 +14932,7 @@ static bool zend_jit_fetch_indirect_var(dasm_State **Dst, const zend_op *opline,
if (opline->op1_type != IS_VAR ||
(opline-1)->result_type != IS_VAR ||
(opline-1)->result.var != opline->op1.var ||
+ (opline-1)->op1_type == IS_VAR ||
(opline-1)->op2_type == IS_VAR ||
(opline-1)->op2_type == IS_TMP_VAR) {
| GET_ZVAL_PTR FCARG1x, var_addr, TMP1
diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c
index 447e2269aa3d0..fc52986ea197e 100644
--- a/ext/opcache/jit/zend_jit_helpers.c
+++ b/ext/opcache/jit/zend_jit_helpers.c
@@ -1938,7 +1938,7 @@ static void ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic(zend_object *zobj, intpt
if (EXPECTED(retval)) {
intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
- ZVAL_COPY(result, retval);
+ ZVAL_COPY_DEREF(result, retval);
return;
}
}
diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c
index 0e103c83570a8..4a57986130666 100644
--- a/ext/opcache/jit/zend_jit_trace.c
+++ b/ext/opcache/jit/zend_jit_trace.c
@@ -4935,14 +4935,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
}
op2_addr = OP2_REG_ADDR();
op2_info = OP2_INFO();
- if (ra
- && ssa_op->op2_def >= 0
- && (!ssa->vars[ssa_op->op2_def].no_val
- || (zend_jit_trace_type_to_info(STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var))) & MAY_BE_ANY) !=
- (op2_info & MAY_BE_ANY))) {
- op2_def_addr = OP2_DEF_REG_ADDR();
- } else {
+
+ if (ssa_op->op2_def < 0 || (Z_MODE(op2_addr) == IS_REG && ssa->vars[ssa_op->op2_def].no_val)) {
op2_def_addr = op2_addr;
+ } else {
+ op2_def_addr = OP2_DEF_REG_ADDR();
}
CHECK_OP2_TRACE_TYPE();
op1_info = OP1_INFO();
@@ -5038,12 +5035,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
ZEND_FALLTHROUGH;
case ZEND_QM_ASSIGN:
op1_addr = OP1_REG_ADDR();
- if (ra
- && ssa_op->op1_def >= 0
- && !ssa->vars[ssa_op->op1_def].no_val) {
- op1_def_addr = OP1_DEF_REG_ADDR();
- } else {
+ if (ssa_op->op1_def < 0 || (Z_MODE(op1_addr) == IS_REG && ssa->vars[ssa_op->op1_def].no_val)) {
op1_def_addr = op1_addr;
+ } else {
+ op1_def_addr = OP1_DEF_REG_ADDR();
}
op1_info = OP1_INFO();
CHECK_OP1_TRACE_TYPE();
@@ -5134,12 +5129,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
break;
}
op1_addr = OP1_REG_ADDR();
- if (ra
- && ssa_op->op1_def >= 0
- && !ssa->vars[ssa_op->op1_def].no_val) {
- op1_def_addr = OP1_DEF_REG_ADDR();
- } else {
+ if (ssa_op->op1_def < 0 || (Z_MODE(op1_addr) == IS_REG && ssa->vars[ssa_op->op1_def].no_val)) {
op1_def_addr = op1_addr;
+ } else {
+ op1_def_addr = OP1_DEF_REG_ADDR();
}
op1_info = OP1_INFO();
CHECK_OP1_TRACE_TYPE();
@@ -6353,7 +6346,14 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
(gen_handler || type == IS_UNKNOWN || !ra ||
(!ra[ssa_op->op1_def] &&
- (opline->opcode == ZEND_ASSIGN || !ssa->vars[ssa_op->op1_def].no_val))));
+ !(ssa->vars[ssa_op->op1_def].no_val &&
+ Z_MODE(OP1_REG_ADDR()) == IS_REG &&
+ (opline->opcode == ZEND_QM_ASSIGN ||
+ opline->opcode == ZEND_SEND_VAR ||
+ opline->opcode == ZEND_SEND_VAR_EX ||
+ opline->opcode == ZEND_SEND_VAR_NO_REF ||
+ opline->opcode == ZEND_SEND_VAR_NO_REF_EX ||
+ opline->opcode == ZEND_SEND_FUNC_ARG)))));
if (type != IS_UNKNOWN) {
ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
if (ra && ra[ssa_op->op1_def]) {
@@ -6399,7 +6399,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
}
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), type,
(gen_handler || type == IS_UNKNOWN || !ra ||
- (!ra[ssa_op->op2_def] && !ssa->vars[ssa_op->op2_def].no_val)));
+ (!ra[ssa_op->op2_def] &&
+ !(ssa->vars[ssa_op->op2_def].no_val &&
+ Z_MODE(OP2_REG_ADDR()) == IS_REG &&
+ opline->opcode == ZEND_ASSIGN))));
if (type != IS_UNKNOWN) {
ssa->var_info[ssa_op->op2_def].type &= ~MAY_BE_GUARD;
if (ra && ra[ssa_op->op2_def]) {
diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc
index dcb32d92b5e8b..b3989a4ae254d 100644
--- a/ext/opcache/jit/zend_jit_x86.dasc
+++ b/ext/opcache/jit/zend_jit_x86.dasc
@@ -5157,7 +5157,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
result_reg = ZREG_R0;
} else {
/* ASSIGN_DIM_OP */
- if (sizeof(void*) == 4
+ if (ZREG_FCARG1 == ZREG_RCX
&& (opcode == ZEND_SL || opcode == ZEND_SR)
&& Z_MODE(op2_addr) != IS_CONST_ZVAL) {
result_reg = ZREG_R2;
@@ -15885,6 +15885,7 @@ static bool zend_jit_fetch_indirect_var(dasm_State **Dst, const zend_op *opline,
if (opline->op1_type != IS_VAR ||
(opline-1)->result_type != IS_VAR ||
(opline-1)->result.var != opline->op1.var ||
+ (opline-1)->op1_type == IS_VAR ||
(opline-1)->op2_type == IS_VAR ||
(opline-1)->op2_type == IS_TMP_VAR) {
| GET_ZVAL_PTR FCARG1a, var_addr
diff --git a/ext/opcache/tests/jit/assign_dim_017.phpt b/ext/opcache/tests/jit/assign_dim_017.phpt
new file mode 100644
index 0000000000000..cc5eef1265c59
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_dim_017.phpt
@@ -0,0 +1,20 @@
+--TEST--
+JIT ASSIGN_DIM: 017
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--FILE--
+
+DONE
+--EXPECT--
+DONE
\ No newline at end of file
diff --git a/ext/opcache/tests/jit/gh11917.phpt b/ext/opcache/tests/jit/gh11917.phpt
new file mode 100644
index 0000000000000..a66105d7a8f7a
--- /dev/null
+++ b/ext/opcache/tests/jit/gh11917.phpt
@@ -0,0 +1,61 @@
+--TEST--
+GH-11917: primitives seem to be passed via reference instead of by value under some conditions when JIT is enabled on windows
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+--FILE--
+>= $split;
+ if (!$overflow) {
+ $remaining -= $split;
+ $overflow = $split <= $remaining ? 0 : $split - $remaining;
+
+ if (!$remaining) {
+ $i++;
+ $remaining = 31;
+ $overflow = 0;
+ }
+ } elseif (++$i != $len) {
+ $tempmask = (1 << $overflow) - 1;
+ $digit |= ($val[$i] & $tempmask) << $remaining;
+ $val[$i] >>= $overflow;
+ $remaining = 31 - $overflow;
+ $overflow = $split <= $remaining ? 0 : $split - $remaining;
+ }
+
+ $vals[] = $digit;
+ }
+
+ while ($vals[count($vals) - 1] == 0) {
+ unset($vals[count($vals) - 1]);
+ }
+
+ return array_reverse($vals);
+}
+?>
+--EXPECT--
+48207660
+48207660
+48207660
+48207660
diff --git a/ext/opcache/tests/jit/gh12428.phpt b/ext/opcache/tests/jit/gh12428.phpt
new file mode 100644
index 0000000000000..48c6a30fc1b88
--- /dev/null
+++ b/ext/opcache/tests/jit/gh12428.phpt
@@ -0,0 +1,22 @@
+--TEST--
+GH-12428: Assertion with function/tracing JIT
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+--FILE--
+a;
+ $value->a ?? null;
+ }
+}
+
+validate((object) []);
+validate((object) []);
+validate((object) ['b' => 0]);
+?>
+DONE
+--EXPECT--
+DONE
diff --git a/ext/opcache/tests/jit/gh12482.phpt b/ext/opcache/tests/jit/gh12482.phpt
new file mode 100644
index 0000000000000..021f7ce4526a3
--- /dev/null
+++ b/ext/opcache/tests/jit/gh12482.phpt
@@ -0,0 +1,57 @@
+--TEST--
+GH-12482: Invalid type inference
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.jit_hot_func=2
+--FILE--
+x = 42;
+ return $cloned;
+ }
+}
+class A {
+ use T;
+ public $a = 1;
+ public $b = 2;
+ public $c = 3;
+ public $x = 4;
+}
+class B {
+ use T;
+ public $x = 5;
+}
+$a = new A;
+var_dump($a->foo());
+var_dump($a->foo());
+$b = new B;
+var_dump($b->foo());
+?>
+--EXPECT--
+object(A)#2 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["x"]=>
+ int(42)
+}
+object(A)#2 (4) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ ["x"]=>
+ int(42)
+}
+object(B)#3 (1) {
+ ["x"]=>
+ int(42)
+}
diff --git a/ext/opcache/tests/jit/gh12509.phpt b/ext/opcache/tests/jit/gh12509.phpt
new file mode 100644
index 0000000000000..ae8bdee661967
--- /dev/null
+++ b/ext/opcache/tests/jit/gh12509.phpt
@@ -0,0 +1,28 @@
+--TEST--
+GH-12509: JIT assertion when running php-parser tests
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+--FILE--
+
+--EXPECT--
+array(3) {
+ [1]=>
+ int(1)
+ [2]=>
+ int(2)
+ [3]=>
+ int(3)
+}
\ No newline at end of file
diff --git a/ext/opcache/tests/jit_warning_with_zero_buffer.phpt b/ext/opcache/tests/jit_warning_with_zero_buffer.phpt
new file mode 100644
index 0000000000000..1b791e2f1ae8a
--- /dev/null
+++ b/ext/opcache/tests/jit_warning_with_zero_buffer.phpt
@@ -0,0 +1,16 @@
+--TEST--
+JIT should not emit warning with opcache.jit_buffer_size=0
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.jit=tracing
+opcache.jit_buffer_size=0
+opcache.log_verbosity_level=2
+--EXTENSIONS--
+opcache
+--FILE--
+
+--EXPECT--
+bool(false)
diff --git a/ext/opcache/tests/opt/block_pass_006.phpt b/ext/opcache/tests/opt/block_pass_006.phpt
new file mode 100644
index 0000000000000..e70689c65abc1
--- /dev/null
+++ b/ext/opcache/tests/opt/block_pass_006.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Block Pass 006: Inorrect QM_ASSIGN elimination
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--FILE--
+''}){}
+?>
+--EXPECTF--
+Fatal error: Uncaught Error: Undefined constant "c" in %sblock_pass_006.php:2
+Stack trace:
+#0 {main}
+ thrown in %sblock_pass_006.php on line 2
diff --git a/ext/opcache/tests/opt/gh10008.phpt b/ext/opcache/tests/opt/gh10008.phpt
new file mode 100644
index 0000000000000..02f6feff9b023
--- /dev/null
+++ b/ext/opcache/tests/opt/gh10008.phpt
@@ -0,0 +1,26 @@
+--TEST--
+GH-10008: Narrowing occurred during type inference of ZEND_ADD_ARRAY_ELEMENT
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+--EXTENSIONS--
+opcache
+--FILE--
+ $bool_or_int, $string_key => 123];
+ }
+
+ $bool_or_int = 0;
+ }
+}
+?>
+DONE
+--EXPECT--
+DONE
diff --git a/ext/opcache/tests/opt/inference_022.phpt b/ext/opcache/tests/opt/inference_022.phpt
new file mode 100644
index 0000000000000..b745499f6021a
--- /dev/null
+++ b/ext/opcache/tests/opt/inference_022.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Type inference 022: FETCH_DIM_W
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--FILE--
+
+DONE
+--EXPECT--
+DONE
diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c
index 3d4a9f8c68750..2c6f14f9ea588 100644
--- a/ext/opcache/zend_accelerator_module.c
+++ b/ext/opcache/zend_accelerator_module.c
@@ -71,7 +71,7 @@ static ZEND_INI_MH(OnUpdateMemoryConsumption)
return FAILURE;
}
if (UNEXPECTED(memsize > ZEND_LONG_MAX / (1024 * 1024))) {
- *p = ZEND_LONG_MAX;
+ *p = ZEND_LONG_MAX & ~(1024 * 1024 - 1);
} else {
*p = memsize * (1024 * 1024);
}
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
index bcee38079b353..7b4b4cbb12112 100644
--- a/ext/opcache/zend_file_cache.c
+++ b/ext/opcache/zend_file_cache.c
@@ -867,6 +867,8 @@ static void zend_file_cache_serialize_class(zval *zv,
ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
+
+ ce->inheritance_cache = NULL;
}
static void zend_file_cache_serialize_warnings(
diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c
index 37f6fea9199a7..f8644121572b5 100644
--- a/ext/opcache/zend_shared_alloc.c
+++ b/ext/opcache/zend_shared_alloc.c
@@ -252,7 +252,7 @@ int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size)
free(ZSMMG(shared_segments));
ZSMMG(shared_segments) = tmp_shared_segments;
- ZSMMG(shared_memory_state).positions = (int *)zend_shared_alloc(sizeof(int) * ZSMMG(shared_segments_count));
+ ZSMMG(shared_memory_state).positions = (size_t *)zend_shared_alloc(sizeof(size_t) * ZSMMG(shared_segments_count));
if (!ZSMMG(shared_memory_state).positions) {
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
return ALLOC_FAILURE;
diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h
index 4e090b98ddadf..3b2da46cb3b33 100644
--- a/ext/opcache/zend_shared_alloc.h
+++ b/ext/opcache/zend_shared_alloc.h
@@ -95,7 +95,7 @@ typedef struct _handler_entry {
} zend_shared_memory_handler_entry;
typedef struct _zend_shared_memory_state {
- int *positions; /* current positions for each segment */
+ size_t *positions; /* current positions for each segment */
size_t shared_free; /* amount of free shared memory */
} zend_shared_memory_state;
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 10af453c89519..31baa2d0e0250 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -5900,12 +5900,15 @@ PHP_FUNCTION(openssl_cms_verify)
goto clean_exit;
}
if (sigfile && (flags & CMS_DETACHED)) {
- sigbio = php_openssl_bio_new_file(sigfile, sigfile_len, 1, PHP_OPENSSL_BIO_MODE_R(flags));
if (encoding == ENCODING_SMIME) {
php_error_docref(NULL, E_WARNING,
"Detached signatures not possible with S/MIME encoding");
goto clean_exit;
}
+ sigbio = php_openssl_bio_new_file(sigfile, sigfile_len, 1, PHP_OPENSSL_BIO_MODE_R(flags));
+ if (sigbio == NULL) {
+ goto clean_exit;
+ }
} else {
sigbio = in; /* non-detached signature */
}
diff --git a/ext/openssl/tests/gh12489.phpt b/ext/openssl/tests/gh12489.phpt
new file mode 100644
index 0000000000000..4ebeb09784db9
--- /dev/null
+++ b/ext/openssl/tests/gh12489.phpt
@@ -0,0 +1,36 @@
+--TEST--
+GH-12489: Missing sigbio creation checking in openssl_cms_verify
+--EXTENSIONS--
+openssl
+--FILE--
+ "test@test", "Subject" => "testing openssl_cms_sign()");
+$headers = array("test@test", "testing openssl_cms_sign()");
+
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers,
+ OPENSSL_CMS_DETACHED|OPENSSL_CMS_BINARY,OPENSSL_ENCODING_PEM));
+ini_set('open_basedir', __DIR__);
+var_dump(openssl_cms_verify($infile,OPENSSL_CMS_NOVERIFY|OPENSSL_CMS_DETACHED|OPENSSL_CMS_BINARY,
+ NULL, array(), NULL, $vout, NULL, "../test.cms", OPENSSL_ENCODING_PEM));
+var_dump(openssl_error_string());
+?>
+--CLEAN--
+
+--EXPECTF--
+bool(true)
+
+Warning: openssl_cms_verify(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (%s) in %s on line %d
+bool(false)
+bool(false)
diff --git a/ext/pcre/pcre2lib/pcre2_match.c b/ext/pcre/pcre2lib/pcre2_match.c
index f28cdbb47a515..e62659a556145 100644
--- a/ext/pcre/pcre2lib/pcre2_match.c
+++ b/ext/pcre/pcre2lib/pcre2_match.c
@@ -5640,7 +5640,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
{
P = (heapframe *)((char *)N - frame_size);
memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
- P->offset_top * sizeof(PCRE2_SIZE));
+ Foffset_top * sizeof(PCRE2_SIZE));
Foffset_top = P->offset_top;
Fcapture_last = P->capture_last;
Fcurrent_recurse = P->current_recurse;
diff --git a/ext/pcre/tests/gh11374.phpt b/ext/pcre/tests/gh11374.phpt
new file mode 100644
index 0000000000000..07f8f4bccfd0a
--- /dev/null
+++ b/ext/pcre/tests/gh11374.phpt
@@ -0,0 +1,60 @@
+--TEST--
+GH-11374 (PCRE regular expression without JIT enabled gives different result)
+--FILE--
+
+ (?:
+ (?:\{ (?&types) \})
+ | (a)
+ )
+ (\*?)
+ )
+';
+
+ini_set('pcre.jit', '0');
+$res = preg_match('{^' . $regex . '$}x', '{a}', $matches, PREG_OFFSET_CAPTURE);
+ini_set('pcre.jit', '1');
+// regex must be different to prevent regex cache, so just add 2nd "x" modifier
+$res2 = preg_match('{^' . $regex . '$}xx', '{a}', $matches2, PREG_OFFSET_CAPTURE);
+
+var_dump($matches === $matches2);
+print_r($matches);
+
+?>
+--EXPECT--
+bool(true)
+Array
+(
+ [0] => Array
+ (
+ [0] => {a}
+ [1] => 0
+ )
+
+ [types] => Array
+ (
+ [0] => {a}
+ [1] => 0
+ )
+
+ [1] => Array
+ (
+ [0] => {a}
+ [1] => 0
+ )
+
+ [2] => Array
+ (
+ [0] =>
+ [1] => -1
+ )
+
+ [3] => Array
+ (
+ [0] =>
+ [1] => 3
+ )
+
+)
diff --git a/ext/pdo_mysql/tests/pdo_mysql___construct.phpt b/ext/pdo_mysql/tests/pdo_mysql___construct.phpt
index 1f009185267c5..aa52764dea2c7 100644
--- a/ext/pdo_mysql/tests/pdo_mysql___construct.phpt
+++ b/ext/pdo_mysql/tests/pdo_mysql___construct.phpt
@@ -6,7 +6,7 @@ pdo_mysql
--FILE--
getTrace());
+ }))->start();
+}
+
+$f = new Fiber(function() { f(); max(...[1,2,3,4,5,6,7,8,9,10,11,12]); g(); });
+$f->start();
+$f->resume();
+
+?>
+--EXPECTF--
+array(3) {
+ [0]=>
+ array(7) {
+ ["file"]=>
+ string(%d) "%sReflectionFiber_bug_gh11121_1.php"
+ ["line"]=>
+ int(10)
+ ["function"]=>
+ string(5) "start"
+ ["class"]=>
+ string(5) "Fiber"
+ ["object"]=>
+ object(Fiber)#3 (0) {
+ }
+ ["type"]=>
+ string(2) "->"
+ ["args"]=>
+ array(0) {
+ }
+ }
+ [1]=>
+ array(4) {
+ ["file"]=>
+ string(%d) "%sReflectionFiber_bug_gh11121_1.php"
+ ["line"]=>
+ int(13)
+ ["function"]=>
+ string(1) "g"
+ ["args"]=>
+ array(0) {
+ }
+ }
+ [2]=>
+ array(2) {
+ ["function"]=>
+ string(9) "{closure}"
+ ["args"]=>
+ array(0) {
+ }
+ }
+}
diff --git a/ext/reflection/tests/ReflectionFiber_bug_gh11121_2.phpt b/ext/reflection/tests/ReflectionFiber_bug_gh11121_2.phpt
new file mode 100644
index 0000000000000..b7affb2ca0b1c
--- /dev/null
+++ b/ext/reflection/tests/ReflectionFiber_bug_gh11121_2.phpt
@@ -0,0 +1,63 @@
+--TEST--
+GH-11121: Segfault when using ReflectionFiber
+--FILE--
+getTrace());
+ }))->start();
+}
+
+$f = new Fiber(function() { f(); g(); });
+$f->start();
+$f->resume();
+
+?>
+--EXPECTF--
+array(3) {
+ [0]=>
+ array(7) {
+ ["file"]=>
+ string(%d) "%sReflectionFiber_bug_gh11121_2.php"
+ ["line"]=>
+ int(11)
+ ["function"]=>
+ string(5) "start"
+ ["class"]=>
+ string(5) "Fiber"
+ ["object"]=>
+ object(Fiber)#3 (0) {
+ }
+ ["type"]=>
+ string(2) "->"
+ ["args"]=>
+ array(0) {
+ }
+ }
+ [1]=>
+ array(4) {
+ ["file"]=>
+ string(%d) "%sReflectionFiber_bug_gh11121_2.php"
+ ["line"]=>
+ int(14)
+ ["function"]=>
+ string(1) "g"
+ ["args"]=>
+ array(0) {
+ }
+ }
+ [2]=>
+ array(2) {
+ ["function"]=>
+ string(9) "{closure}"
+ ["args"]=>
+ array(0) {
+ }
+ }
+}
diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
index 3a4626aa5beee..a5fbd3df9dd9c 100644
--- a/ext/soap/php_encoding.c
+++ b/ext/soap/php_encoding.c
@@ -1561,10 +1561,12 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z
if (Z_TYPE_P(prop) != IS_ARRAY) {
/* Convert into array */
array_init(&arr);
- Z_ADDREF_P(prop);
+ Z_TRY_ADDREF_P(prop);
add_next_index_zval(&arr, prop);
set_zval_property(ret, (char*)trav->name, &arr);
prop = &arr;
+ } else {
+ SEPARATE_ARRAY(prop);
}
/* Add array element */
add_next_index_zval(prop, &tmpVal);
diff --git a/ext/soap/php_schema.c b/ext/soap/php_schema.c
index e93679a55ea39..521c5d0f1d9ed 100644
--- a/ext/soap/php_schema.c
+++ b/ext/soap/php_schema.c
@@ -2261,17 +2261,23 @@ static void schema_type_fixup(sdlCtx *ctx, sdlTypePtr type)
schema_content_model_fixup(ctx, type->model);
}
if (type->attributes) {
- zend_string *str_key;
- zend_ulong index;
+ HashPosition pos;
+ zend_hash_internal_pointer_reset_ex(type->attributes, &pos);
- ZEND_HASH_FOREACH_KEY_PTR(type->attributes, index, str_key, attr) {
- if (str_key) {
+ while ((attr = zend_hash_get_current_data_ptr_ex(type->attributes, &pos)) != NULL) {
+ zend_string *str_key;
+ zend_ulong index;
+
+ if (zend_hash_get_current_key_ex(type->attributes, &str_key, &index, &pos) == HASH_KEY_IS_STRING) {
schema_attribute_fixup(ctx, attr);
+ zend_result result = zend_hash_move_forward_ex(type->attributes, &pos);
+ ZEND_ASSERT(result == SUCCESS);
} else {
schema_attributegroup_fixup(ctx, attr, type->attributes);
- zend_hash_index_del(type->attributes, index);
+ zend_result result = zend_hash_index_del(type->attributes, index);
+ ZEND_ASSERT(result == SUCCESS);
}
- } ZEND_HASH_FOREACH_END();
+ }
}
}
diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c
index 3dd8e6c5d76e4..651eab23b7aad 100644
--- a/ext/soap/php_sdl.c
+++ b/ext/soap/php_sdl.c
@@ -22,6 +22,7 @@
#include "ext/standard/md5.h"
#include "zend_virtual_cwd.h"
+#include "main/php_open_temporary_file.h"
#include
#include
@@ -154,7 +155,7 @@ encodePtr get_encoder(sdlPtr sdl, const char *ns, const char *type)
}
if (sdl->encoders == NULL) {
sdl->encoders = pemalloc(sizeof(HashTable), sdl->is_persistent);
- zend_hash_init(sdl->encoders, 0, NULL, delete_encoder, sdl->is_persistent);
+ zend_hash_init(sdl->encoders, 0, NULL, sdl->is_persistent ? delete_encoder_persistent : delete_encoder, sdl->is_persistent);
}
zend_hash_str_update_ptr(sdl->encoders, nscat, len, new_enc);
enc = new_enc;
@@ -1536,7 +1537,7 @@ static HashTable* sdl_deserialize_parameters(encodePtr *encoders, sdlTypePtr *ty
return ht;
}
-static sdlPtr get_sdl_from_cache(const char *fn, const char *uri, time_t t, time_t *cached)
+static sdlPtr get_sdl_from_cache(const char *fn, const char *uri, size_t uri_len, time_t t, time_t *cached)
{
sdlPtr sdl;
time_t old_t;
@@ -1583,7 +1584,7 @@ static sdlPtr get_sdl_from_cache(const char *fn, const char *uri, time_t t, time
*cached = old_t;
WSDL_CACHE_GET_INT(i, &in);
- if (i == 0 && strncmp(in, uri, i) != 0) {
+ if (i != uri_len || strncmp(in, uri, i) != 0) {
unlink(fn);
efree(buf);
return NULL;
@@ -2119,7 +2120,10 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
HashTable tmp_bindings;
HashTable tmp_functions;
- f = open(fn,O_CREAT|O_WRONLY|O_EXCL|O_BINARY,S_IREAD|S_IWRITE);
+ /* To avoid race conditions, we first create a temporary file and then rename it atomically
+ * at the end of the function. (see bug #66150) */
+ zend_string *temp_file_path;
+ f = php_open_temporary_fd_ex(SOAP_GLOBAL(cache_dir), "tmp.wsdl.", &temp_file_path, PHP_TMP_FILE_SILENT);
if (f < 0) {return;}
@@ -2371,13 +2375,21 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
} ZEND_HASH_FOREACH_END();
}
- php_ignore_value(write(f, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)));
+ bool valid_file = write(f, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)) == ZSTR_LEN(buf.s);
close(f);
+
+ /* Make sure that incomplete files (e.g. due to disk space issues, see bug #66150) are not utilised. */
+ if (valid_file) {
+ /* This is allowed to fail, this means that another process was raced to create the file. */
+ (void) VCWD_RENAME(ZSTR_VAL(temp_file_path), fn);
+ }
+
smart_str_free(&buf);
zend_hash_destroy(&tmp_functions);
zend_hash_destroy(&tmp_bindings);
zend_hash_destroy(&tmp_encoders);
zend_hash_destroy(&tmp_types);
+ zend_string_release_ex(temp_file_path, false);
}
@@ -3232,7 +3244,7 @@ sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl)
}
memcpy(key+len,md5str,sizeof(md5str));
- if ((sdl = get_sdl_from_cache(key, uri, t-SOAP_GLOBAL(cache_ttl), &cached)) != NULL) {
+ if ((sdl = get_sdl_from_cache(key, uri, uri_len, t-SOAP_GLOBAL(cache_ttl), &cached)) != NULL) {
t = cached;
efree(key);
goto cache_in_memory;
@@ -3243,6 +3255,9 @@ sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl)
tmp = Z_CLIENT_STREAM_CONTEXT_P(this_ptr);
if (Z_TYPE_P(tmp) == IS_RESOURCE) {
context = php_stream_context_from_zval(tmp, 0);
+ /* Share a reference with new_context down below.
+ * For new contexts, the reference is only in new_context so that doesn't need extra refcounting. */
+ GC_ADDREF(context->res);
}
tmp = Z_CLIENT_USER_AGENT_P(this_ptr);
@@ -3311,7 +3326,7 @@ sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl)
}
if (context) {
- php_stream_context_to_zval(context, &new_context);
+ ZVAL_RES(&new_context, context->res);
php_libxml_switch_context(&new_context, &orig_context);
}
diff --git a/ext/soap/tests/bug75306.phpt b/ext/soap/tests/bug75306.phpt
new file mode 100644
index 0000000000000..7501fde59e6b8
--- /dev/null
+++ b/ext/soap/tests/bug75306.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #75306 (Memleak in SoapClient)
+--EXTENSIONS--
+soap
+--FILE--
+ WSDL_CACHE_NONE);
+// Need a warm-up for globals
+for ($i = 0; $i < 10; $i++) {
+ $client = new SoapClient("ext/soap/tests/test.wsdl", $options);
+}
+$usage = memory_get_usage();
+for ($i = 0; $i < 10; $i++) {
+ $client = new SoapClient("ext/soap/tests/test.wsdl", $options);
+}
+$usage_delta = memory_get_usage() - $usage;
+var_dump($usage_delta);
+?>
+--EXPECT--
+int(0)
diff --git a/ext/soap/tests/bugs/segfault_assertion_props.phpt b/ext/soap/tests/bugs/segfault_assertion_props.phpt
new file mode 100644
index 0000000000000..9d496d72967b0
--- /dev/null
+++ b/ext/soap/tests/bugs/segfault_assertion_props.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Segfault and assertion failure with refcounted props and arrays
+--INI--
+soap.wsdl_cache_enabled=0
+--EXTENSIONS--
+soap
+--FILE--
+
+
+
+ Hello
+ World
+
+
+EOF;
+ }
+}
+
+trait A {
+ public $a = [self::class . 'a'];
+ public $b = self::class . 'b';
+}
+
+class DummyClass {
+ use A;
+}
+
+$client = new TestSoapClient(__DIR__."/../classmap.wsdl", ['classmap' => ['Struct' => 'DummyClass']]);
+var_dump($client->dotest2("???"));
+?>
+--EXPECT--
+object(DummyClass)#2 (2) {
+ ["a"]=>
+ array(2) {
+ [0]=>
+ string(11) "DummyClassa"
+ [1]=>
+ string(5) "Hello"
+ }
+ ["b"]=>
+ array(2) {
+ [0]=>
+ string(11) "DummyClassb"
+ [1]=>
+ string(5) "World"
+ }
+}
diff --git a/ext/soap/tests/gh12392.phpt b/ext/soap/tests/gh12392.phpt
new file mode 100644
index 0000000000000..8a234ba025be9
--- /dev/null
+++ b/ext/soap/tests/gh12392.phpt
@@ -0,0 +1,28 @@
+--TEST--
+GH-12392 (Segmentation fault on SoapClient::__getTypes)
+--EXTENSIONS--
+soap
+--FILE--
+ WSDL_CACHE_NONE]);
+echo 'Client created!' . "\n";
+
+$types = $client->__getTypes();
+echo 'Got types!' . "\n";
+
+var_dump($types);
+
+?>
+--EXPECT--
+Client created!
+Got types!
+array(1) {
+ [0]=>
+ string(62) "struct dummy {
+ string foo;
+ string a;
+ string b;
+ string c;
+}"
+}
diff --git a/ext/soap/tests/gh12392.wsdl b/ext/soap/tests/gh12392.wsdl
new file mode 100644
index 0000000000000..5e9a7ea094fb8
--- /dev/null
+++ b/ext/soap/tests/gh12392.wsdl
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ext/standard/image.c b/ext/standard/image.c
index 85ecda2f3d70b..5200295f3af28 100644
--- a/ext/standard/image.c
+++ b/ext/standard/image.c
@@ -425,6 +425,20 @@ static int php_skip_variable(php_stream * stream)
}
/* }}} */
+static size_t php_read_stream_all_chunks(php_stream *stream, char *buffer, size_t length)
+{
+ size_t read_total = 0;
+ do {
+ ssize_t read_now = php_stream_read(stream, buffer, length - read_total);
+ read_total += read_now;
+ if (read_now < stream->chunk_size && read_total != length) {
+ return 0;
+ }
+ } while (read_total < length);
+
+ return read_total;
+}
+
/* {{{ php_read_APP */
static int php_read_APP(php_stream * stream, unsigned int marker, zval *info)
{
@@ -441,7 +455,7 @@ static int php_read_APP(php_stream * stream, unsigned int marker, zval *info)
buffer = emalloc(length);
- if (php_stream_read(stream, buffer, (size_t) length) != length) {
+ if (php_read_stream_all_chunks(stream, buffer, length) != length) {
efree(buffer);
return 0;
}
diff --git a/ext/standard/tests/file/bug52820.phpt b/ext/standard/tests/file/bug52820.phpt
index 78cfeb61fa988..ff816178cef67 100644
--- a/ext/standard/tests/file/bug52820.phpt
+++ b/ext/standard/tests/file/bug52820.phpt
@@ -12,7 +12,7 @@ curl_setopt($handle, CURLOPT_VERBOSE, true);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
if (!@curl_setopt($handle, CURLOPT_STDERR, fopen("php://memory", "w+")))
die("skip fopencookie not supported on this platform");
-if (getenv('CIRRUS_CI')) die('xfail Broken on Cirrus+ARM');
+if (getenv('CIRCLECI')) die('xfail Broken on CircleCI');
?>
--FILE--
handle = fopen(str_replace('fs://', __DIR__ . '/', $file), $mode);
+ return true;
+ }
+ function stream_read($count) {
+ return fread($this->handle, $count);
+ }
+ function stream_eof() {
+ return feof($this->handle);
+ }
+ function stream_seek($offset, $whence) {
+ return fseek($this->handle, $offset, $whence) === 0;
+ }
+ function stream_stat() {
+ return fstat($this->handle);
+ }
+ function url_stat($file) {
+ return stat(str_replace('fs://', '', $file));
+ }
+ function stream_tell() {
+ return ftell($this->handle);
+ }
+ function stream_close() {
+ fclose($this->handle);
+ }
+}
+
+stream_register_wrapper('fs', 'FSStreamWrapper');
+
+var_dump(getimagesize('fs://bug75708.jpg', $info));
+
+?>
+--EXPECT--
+array(7) {
+ [0]=>
+ int(10)
+ [1]=>
+ int(10)
+ [2]=>
+ int(2)
+ [3]=>
+ string(22) "width="10" height="10""
+ ["bits"]=>
+ int(8)
+ ["channels"]=>
+ int(3)
+ ["mime"]=>
+ string(10) "image/jpeg"
+}
+
diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c
index 12be9ada01194..3484cbdc5d9aa 100644
--- a/ext/xmlreader/php_xmlreader.c
+++ b/ext/xmlreader/php_xmlreader.c
@@ -211,6 +211,9 @@ char *_xmlreader_get_valid_file_path(char *source, char *resolved_path, int reso
int isFileUri = 0;
uri = xmlCreateURI();
+ if (uri == NULL) {
+ return NULL;
+ }
escsource = xmlURIEscapeStr((xmlChar *)source, (xmlChar *)":");
xmlParseURIReference(uri, (const char *)escsource);
xmlFree(escsource);
diff --git a/ext/xmlwriter/php_xmlwriter.c b/ext/xmlwriter/php_xmlwriter.c
index 24ce414034af5..2966747fc52da 100644
--- a/ext/xmlwriter/php_xmlwriter.c
+++ b/ext/xmlwriter/php_xmlwriter.c
@@ -110,6 +110,9 @@ static char *_xmlwriter_get_valid_file_path(char *source, char *resolved_path, i
int isFileUri = 0;
uri = xmlCreateURI();
+ if (uri == NULL) {
+ return NULL;
+ }
escsource = xmlURIEscapeStr((xmlChar *)source, (xmlChar *) ":");
xmlParseURIReference(uri, (char *)escsource);
xmlFree(escsource);
diff --git a/ext/xsl/php_xsl.c b/ext/xsl/php_xsl.c
index 1e98a6ce88bbe..6330ea5906535 100644
--- a/ext/xsl/php_xsl.c
+++ b/ext/xsl/php_xsl.c
@@ -29,6 +29,7 @@ static zend_object_handlers xsl_object_handlers;
static const zend_module_dep xsl_deps[] = {
ZEND_MOD_REQUIRED("libxml")
+ ZEND_MOD_REQUIRED("dom")
ZEND_MOD_END
};
diff --git a/ext/xsl/tests/php_function_edge_cases.phpt b/ext/xsl/tests/php_function_edge_cases.phpt
new file mode 100644
index 0000000000000..23a06b111bb50
--- /dev/null
+++ b/ext/xsl/tests/php_function_edge_cases.phpt
@@ -0,0 +1,45 @@
+--TEST--
+php:function() edge cases
+--EXTENSIONS--
+xsl
+--FILE--
+loadXML('
+
+
+
+
+ ');
+
+ $inputdom = new DomDocument();
+ $inputdom->loadXML('
+ ');
+
+ $proc = new XsltProcessor();
+ $proc->registerPhpFunctions();
+ $xsl = $proc->importStylesheet($xsl);
+ try {
+ $proc->transformToDoc($inputdom);
+ } catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+ }
+}
+
+try {
+ test("");
+} catch (Throwable $e) {
+ echo $e->getMessage(), "\n";
+}
+
+test("3");
+
+?>
+--EXPECTF--
+Function name must be passed as the first argument
+
+Warning: XSLTProcessor::transformToDoc(): Handler name must be a string in %s on line %d
diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c
index 0ddef864f050f..22d56c41faebc 100644
--- a/ext/xsl/xsltprocessor.c
+++ b/ext/xsl/xsltprocessor.c
@@ -141,12 +141,17 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t
return;
}
+ if (UNEXPECTED(nargs == 0)) {
+ zend_throw_error(NULL, "Function name must be passed as the first argument");
+ return;
+ }
+
fci.param_count = nargs - 1;
if (fci.param_count > 0) {
args = safe_emalloc(fci.param_count, sizeof(zval), 0);
}
/* Reverse order to pop values off ctxt stack */
- for (i = nargs - 2; i >= 0; i--) {
+ for (i = fci.param_count - 1; i >= 0; i--) {
obj = valuePop(ctxt);
if (obj == NULL) {
ZVAL_NULL(&args[i]);
@@ -221,7 +226,7 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t
fci.params = NULL;
}
-
+ /* Last element of the stack is the function name */
obj = valuePop(ctxt);
if (obj == NULL || obj->stringval == NULL) {
php_error_docref(NULL, E_WARNING, "Handler name must be a string");
diff --git a/main/php_version.h b/main/php_version.h
index 35782be060ad3..f6efeacd7ea6f 100644
--- a/main/php_version.h
+++ b/main/php_version.h
@@ -2,7 +2,7 @@
/* edit configure.ac to change version number */
#define PHP_MAJOR_VERSION 8
#define PHP_MINOR_VERSION 1
-#define PHP_RELEASE_VERSION 25
-#define PHP_EXTRA_VERSION "-dev"
-#define PHP_VERSION "8.1.25-dev"
-#define PHP_VERSION_ID 80125
+#define PHP_RELEASE_VERSION 26
+#define PHP_EXTRA_VERSION ""
+#define PHP_VERSION "8.1.26"
+#define PHP_VERSION_ID 80126
diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c
index 92b189668206e..dae98bdfc08f9 100644
--- a/sapi/fpm/fpm/fpm_php.c
+++ b/sapi/fpm/fpm/fpm_php.c
@@ -77,6 +77,11 @@ static void fpm_php_disable(char *value, int (*zend_disable)(const char *, size_
}
/* }}} */
+#define FPM_PHP_INI_ALTERING_ERROR -1
+#define FPM_PHP_INI_APPLIED 1
+#define FPM_PHP_INI_EXTENSION_FAILED 0
+#define FPM_PHP_INI_EXTENSION_LOADED 2
+
int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode) /* {{{ */
{
@@ -87,46 +92,60 @@ int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode) /* {{{ */
if (!strcmp(name, "extension") && *value) {
zval zv;
+ zend_interned_strings_switch_storage(0);
php_dl(value, MODULE_PERSISTENT, &zv, 1);
- return Z_TYPE(zv) == IS_TRUE;
+ zend_interned_strings_switch_storage(1);
+ return Z_TYPE(zv) == IS_TRUE ? FPM_PHP_INI_EXTENSION_LOADED : FPM_PHP_INI_EXTENSION_FAILED;
}
if (fpm_php_zend_ini_alter_master(name, name_len, value, value_len, mode, PHP_INI_STAGE_ACTIVATE) == FAILURE) {
- return -1;
+ return FPM_PHP_INI_ALTERING_ERROR;
}
if (!strcmp(name, "disable_functions") && *value) {
zend_disable_functions(value);
- return 1;
+ return FPM_PHP_INI_APPLIED;
}
if (!strcmp(name, "disable_classes") && *value) {
char *v = strdup(value);
PG(disable_classes) = v;
fpm_php_disable(v, zend_disable_class);
- return 1;
+ return FPM_PHP_INI_APPLIED;
}
- return 1;
+ return FPM_PHP_INI_APPLIED;
}
/* }}} */
static int fpm_php_apply_defines(struct fpm_worker_pool_s *wp) /* {{{ */
{
struct key_value_s *kv;
+ int apply_result;
+ bool extension_loaded = false;
for (kv = wp->config->php_values; kv; kv = kv->next) {
- if (fpm_php_apply_defines_ex(kv, ZEND_INI_USER) == -1) {
+ apply_result = fpm_php_apply_defines_ex(kv, ZEND_INI_USER);
+ if (apply_result == FPM_PHP_INI_ALTERING_ERROR) {
zlog(ZLOG_ERROR, "Unable to set php_value '%s'", kv->key);
+ } else if (apply_result == FPM_PHP_INI_EXTENSION_LOADED) {
+ extension_loaded = true;
}
}
for (kv = wp->config->php_admin_values; kv; kv = kv->next) {
- if (fpm_php_apply_defines_ex(kv, ZEND_INI_SYSTEM) == -1) {
+ apply_result = fpm_php_apply_defines_ex(kv, ZEND_INI_SYSTEM);
+ if (apply_result == FPM_PHP_INI_ALTERING_ERROR) {
zlog(ZLOG_ERROR, "Unable to set php_admin_value '%s'", kv->key);
+ } else if (apply_result == FPM_PHP_INI_EXTENSION_LOADED) {
+ extension_loaded = true;
}
}
+ if (extension_loaded) {
+ zend_collect_module_handlers();
+ }
+
return 0;
}
/* }}} */
diff --git a/sapi/fpm/tests/gh12232-php-value-extension.phpt b/sapi/fpm/tests/gh12232-php-value-extension.phpt
new file mode 100644
index 0000000000000..207bd7a677974
--- /dev/null
+++ b/sapi/fpm/tests/gh12232-php-value-extension.phpt
@@ -0,0 +1,51 @@
+--TEST--
+FPM: gh12232 - loading shared ext in FPM config
+--SKIPIF--
+
+--FILE--
+start();
+$tester->expectLogStartNotices();
+$tester->request()->expectBody(['bool(true)', 'string(5) "hello"', 'string(4) "test"']);
+$tester->request()->expectBody(['bool(true)', 'string(5) "hello"', 'string(4) "test"']);
+$tester->terminate();
+$tester->expectLogTerminatingNotices();
+$tester->close();
+
+?>
+Done
+--EXPECT--
+Done
+--CLEAN--
+
+
+--FILE--
+start();
+$tester->expectLogStartNotices();
+$tester->request()->expectBody('bool(true)');
+$tester->expectLogPattern('/DL TEST MINIT/');
+$tester->expectLogPattern('/DL TEST RINIT/');
+$tester->expectLogPattern('/DL TEST RSHUTDOWN/');
+$tester->request()->expectBody('bool(true)');
+$tester->expectLogPattern('/DL TEST RINIT/');
+$tester->expectLogPattern('/DL TEST RSHUTDOWN/');
+$tester->terminate();
+$tester->expectLogTerminatingNotices();
+$tester->close();
+
+?>
+Done
+--EXPECT--
+Done
+--CLEAN--
+
+