diff --git a/.appveyor.yml b/.appveyor.yml index 7567578af258d..350fac2c026bb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -28,6 +28,7 @@ environment: #PDO_MYSQL_TEST_PASS: Password12! #PGSQL_TEST_CONNSTR: "host=127.0.0.1 dbname=test port=5432 user=postgres password=Password12!" #PDO_PGSQL_TEST_DSN: "pgsql:host=127.0.0.1 port=5432 dbname=test user=postgres password=Password12!" + STACK_LIMIT_DEFAULTS_CHECK: 1 #build permutations matrix: - THREAD_SAFE: 0 diff --git a/.cirrus.yml b/.cirrus.yml index 10558901ad167..0b5c8c0ad361a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -7,8 +7,10 @@ asan_task: image: gcc:latest additional_containers: - name: mysql - image: mysql:latest + image: mysql:8 port: 3306 + cpu: 1.0 + memory: 1G env: MYSQL_ROOT_PASSWORD: "root" MYSQL_DATABASE: "test" @@ -160,10 +162,10 @@ asan_task: tests_script: - export SKIP_IO_CAPTURE_TESTS=1 - export CI_NO_IPV6=1 - - export MYSQL_TEST_HOST=mysql + - export MYSQL_TEST_HOST=127.0.0.1 - export MYSQL_TEST_USER=root - export MYSQL_TEST_PASSWD=root - - export PDO_MYSQL_TEST_DSN="mysql:host=mysql;dbname=test" + - export PDO_MYSQL_TEST_DSN="mysql:host=127.0.0.1;dbname=test" - export PDO_MYSQL_TEST_USER=root - export PDO_MYSQL_TEST_PASS=root - >- @@ -182,7 +184,9 @@ asan_task: freebsd_task: name: FREEBSD_DEBUG_NTS freebsd_instance: - image_family: freebsd-13-0 + image_family: freebsd-13-2 + env: + ARCH: amd64 install_script: #- sed -i -e 's/quarterly/latest/g' /etc/pkg/FreeBSD.conf #- pkg upgrade -y @@ -201,4 +205,200 @@ freebsd_task: tests_script: - export SKIP_IO_CAPTURE_TESTS=1 - export CI_NO_IPV6=1 + - export STACK_LIMIT_DEFAULTS_CHECK=1 - sapi/cli/php run-tests.php -P -q -j2 -g FAIL,BORK,LEAK,XLEAK --no-progress --offline --show-diff --show-slow 1000 --set-timeout 120 -d zend_extension=opcache.so + +arm_task: + name: ARM_DEBUG_NTS + arm_container: + image: gcc:12 + 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 + 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 + 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/.gdbinit b/.gdbinit index 6117922621068..d3b456239e375 100644 --- a/.gdbinit +++ b/.gdbinit @@ -482,7 +482,7 @@ end define print_pi set $pi = (zend_property_info *)$arg0 - set $initial_offset = ((uint32_t)(zend_uintptr_t)(&((zend_object*)0)->properties_table[(0)])) + set $initial_offset = ((uint32_t)(uintptr_t)(&((zend_object*)0)->properties_table[(0)])) set $ptr_to_val = (zval*)((char*)$pi->ce->default_properties_table + $pi->offset - $initial_offset) printf "[%p] {\n", $pi printf " offset = %p\n", $pi->offset diff --git a/.gitattributes b/.gitattributes index d71a50b7b135b..f8b91505bc983 100644 --- a/.gitattributes +++ b/.gitattributes @@ -23,3 +23,6 @@ **/*_arginfo.h linguist-generated /Zend/zend_vm_execute.h linguist-generated /Zend/zend_vm_opcodes.{h,c} linguist-generated + +# The OSS fuzz files are bunary +/ext/date/tests/ossfuzz*.txt binary diff --git a/.github/actions/apt-x32/action.yml b/.github/actions/apt-x32/action.yml index 2cde60fce55b0..879300f992747 100644 --- a/.github/actions/apt-x32/action.yml +++ b/.github/actions/apt-x32/action.yml @@ -13,6 +13,7 @@ runs: apt-get install -y \ autoconf \ bison \ + curl \ g++-multilib \ gcc-multilib \ language-pack-de \ diff --git a/.github/actions/brew/action.yml b/.github/actions/brew/action.yml index 8bdbeec7ab6b8..51d37aa56d470 100644 --- a/.github/actions/brew/action.yml +++ b/.github/actions/brew/action.yml @@ -12,6 +12,7 @@ runs: re2c brew install \ openssl@1.1 \ + curl \ krb5 \ bzip2 \ enchant \ diff --git a/.github/actions/configure-macos/action.yml b/.github/actions/configure-macos/action.yml index 57a9b63a06ea2..317d705645985 100644 --- a/.github/actions/configure-macos/action.yml +++ b/.github/actions/configure-macos/action.yml @@ -11,6 +11,7 @@ runs: set -x export PATH="/usr/local/opt/bison/bin:$PATH" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/openssl@1.1/lib/pkgconfig" + export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/curl/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/krb5/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libffi/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/libxml2/lib/pkgconfig" diff --git a/.github/actions/notify-slack/action.yml b/.github/actions/notify-slack/action.yml new file mode 100644 index 0000000000000..1ff425b51c6ac --- /dev/null +++ b/.github/actions/notify-slack/action.yml @@ -0,0 +1,10 @@ +name: Notify Slack +inputs: + token: + required: true +runs: + using: composite + steps: + - shell: bash + run: >- + curl -X POST -H 'Content-type: application/json' --data '{"attachments": [{"text": "Job in *nightly* failed", "footer": "", "color": "danger", "mrkdwn_in": ["text"]}]}' ${{ inputs.token }} diff --git a/.github/actions/setup-x64/action.yml b/.github/actions/setup-x64/action.yml index bb014bfe9de11..91cf7ea51c356 100644 --- a/.github/actions/setup-x64/action.yml +++ b/.github/actions/setup-x64/action.yml @@ -7,17 +7,14 @@ runs: set -x sudo service mysql start - sudo service postgresql start sudo service slapd start mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS test" # Ensure local_infile tests can run. mysql -uroot -proot -e "SET GLOBAL local_infile = true" - sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'postgres';" - sudo -u postgres psql -c "CREATE DATABASE test;" docker exec sql1 /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U SA -P "" -Q "create login pdo_test with password='password', check_policy=off; create user pdo_test for login pdo_test; grant alter, control to pdo_test;" sudo locale-gen de_DE - ./.github/scripts/setup-slapd.sh &>/dev/null + ./.github/scripts/setup-slapd.sh sudo cp ext/snmp/tests/snmpd.conf /etc/snmp sudo cp ext/snmp/tests/bigtest /etc/snmp diff --git a/.github/actions/test-linux/action.yml b/.github/actions/test-linux/action.yml index 2c1d53f4d6da5..9b7d0d100608f 100644 --- a/.github/actions/test-linux/action.yml +++ b/.github/actions/test-linux/action.yml @@ -28,8 +28,11 @@ runs: export PDO_OCI_TEST_USER="system" export PDO_OCI_TEST_PASS="pass" export PDO_OCI_TEST_DSN="oci:dbname=localhost/XEPDB1;charset=AL32UTF8" + export PGSQL_TEST_CONNSTR="host=postgres dbname=test port=5432 user=postgres password=postgres" + export PDO_PGSQL_TEST_DSN="host=postgres dbname=test port=5432 user=postgres password=postgres" export SKIP_IO_CAPTURE_TESTS=1 export TEST_PHP_JUNIT=junit.out.xml + export STACK_LIMIT_DEFAULTS_CHECK=1 sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \ -j$(/usr/bin/nproc) \ -g FAIL,BORK,LEAK,XLEAK \ diff --git a/.github/actions/test-macos/action.yml b/.github/actions/test-macos/action.yml index 3deafde06200c..8284b8905ef74 100644 --- a/.github/actions/test-macos/action.yml +++ b/.github/actions/test-macos/action.yml @@ -15,6 +15,7 @@ runs: export SKIP_IO_CAPTURE_TESTS=1 export CI_NO_IPV6=1 export TEST_PHP_JUNIT=junit.out.xml + export STACK_LIMIT_DEFAULTS_CHECK=1 sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \ -j$(sysctl -n hw.ncpu) \ -g FAIL,BORK,LEAK,XLEAK \ diff --git a/.github/lsan-suppressions.txt b/.github/lsan-suppressions.txt index 5c2ee76e4607a..b8f863ce603b0 100644 --- a/.github/lsan-suppressions.txt +++ b/.github/lsan-suppressions.txt @@ -1 +1,3 @@ leak:acommon::DictInfoList::elements +leak:timer_create +leak:netsnmp_init_mib_internals diff --git a/.github/nightly_matrix.php b/.github/nightly_matrix.php index 4a8dd1648fc60..5c89c0e8986dc 100644 --- a/.github/nightly_matrix.php +++ b/.github/nightly_matrix.php @@ -53,6 +53,7 @@ function get_matrix_include(array $branches) { 'configuration_parameters' => "CFLAGS='-fsanitize=undefined,address -DZEND_TRACK_ARENA_ALLOC' LDFLAGS='-fsanitize=undefined,address'", 'run_tests_parameters' => '--asan', 'test_function_jit' => false, + 'asan' => true, ]; if ($branch['ref'] !== 'PHP-8.0') { $jobs[] = [ @@ -63,6 +64,7 @@ function get_matrix_include(array $branches) { 'run_tests_parameters' => '--repeat 2', 'timeout_minutes' => 360, 'test_function_jit' => true, + 'asan' => false, ]; $jobs[] = [ 'name' => '_VARIATION', @@ -72,6 +74,7 @@ function get_matrix_include(array $branches) { 'configuration_parameters' => "CFLAGS='-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1'", 'timeout_minutes' => 360, 'test_function_jit' => true, + 'asan' => false, ]; } } @@ -88,5 +91,7 @@ function get_matrix_include(array $branches) { $branches = get_branches(); $matrix_include = get_matrix_include($branches); -echo '::set-output name=branches::' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n"; -echo '::set-output name=matrix-include::' . json_encode($matrix_include, JSON_UNESCAPED_SLASHES) . "\n"; +$f = fopen(getenv('GITHUB_OUTPUT'), 'a'); +fwrite($f, 'branches=' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n"); +fwrite($f, 'matrix-include=' . json_encode($matrix_include, JSON_UNESCAPED_SLASHES) . "\n"); +fclose($f); diff --git a/.github/scripts/setup-slapd.sh b/.github/scripts/setup-slapd.sh index b9cb1a4ff7a95..5539d7f6272f3 100755 --- a/.github/scripts/setup-slapd.sh +++ b/.github/scripts/setup-slapd.sh @@ -1,5 +1,5 @@ #!/bin/sh -set -ex +set -e # Create TLS certificate sudo mkdir -p /etc/ldap/ssl @@ -42,7 +42,9 @@ sudo sed -e 's|^\s*SLAPD_SERVICES\s*=.*$|SLAPD_SERVICES="ldap:/// ldaps:/// ldap # Configure LDAP database. DBDN=`sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(&(olcRootDN=*)(olcSuffix=*))' dn | grep -i '^dn:' | sed -e 's/^dn:\s*//'`; -sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif +if test -f "/etc/ldap/schema/ppolicy.ldif"; then + sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif +fi sudo service slapd restart diff --git a/.github/scripts/windows/build.bat b/.github/scripts/windows/build.bat index cb85f605c610e..9aec8f5c2b791 100644 --- a/.github/scripts/windows/build.bat +++ b/.github/scripts/windows/build.bat @@ -1,5 +1,10 @@ @echo off +if /i "%APPVEYOR%%GITHUB_ACTIONS%" neq "True" ( + echo for CI only + exit /b 3 +) + set SDK_REMOTE=https://github.com/php/php-sdk-binary-tools.git set SDK_BRANCH=%PHP_BUILD_SDK_BRANCH% set SDK_RUNNER=%PHP_BUILD_CACHE_SDK_DIR%\phpsdk-%PHP_BUILD_CRT%-%PLATFORM%.bat @@ -38,7 +43,7 @@ if not exist "%SDK_RUNNER%" ( exit /b 3 ) -cmd /c %SDK_RUNNER% -t %APPVEYOR_BUILD_FOLDER%\.github\scripts\windows\build_task.bat +cmd /c %SDK_RUNNER% -t .github\scripts\windows\build_task.bat if %errorlevel% neq 0 exit /b 3 exit /b 0 diff --git a/.github/scripts/windows/build_task.bat b/.github/scripts/windows/build_task.bat index 61e3042fadd28..166712675ae5f 100644 --- a/.github/scripts/windows/build_task.bat +++ b/.github/scripts/windows/build_task.bat @@ -1,5 +1,10 @@ @echo off +if /i "%APPVEYOR%%GITHUB_ACTIONS%" neq "True" ( + echo for CI only + exit /b 3 +) + if "%APPVEYOR%" equ "True" rmdir /s /q C:\cygwin >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 if "%APPVEYOR%" equ "True" rmdir /s /q C:\cygwin64 >NUL 2>NUL @@ -18,19 +23,12 @@ if "%APPVEYOR%" equ "True" rmdir /s /q c:\OpenSSL-v11-Win32 >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 if "%APPVEYOR%" equ "True" rmdir /s /q c:\OpenSSL-v11-Win64 >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 -if "%APPVEYOR%" equ "True" del /f /q C:\Windows\System32\libcrypto-1_1-x64.dll >NUL 2>NUL +del /f /q C:\Windows\System32\libcrypto-1_1-x64.dll >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 -if "%APPVEYOR%" equ "True" del /f /q C:\Windows\System32\libssl-1_1-x64.dll >NUL 2>NUL -if %errorlevel% neq 0 exit /b 3 - -cd /D %APPVEYOR_BUILD_FOLDER% +del /f /q C:\Windows\System32\libssl-1_1-x64.dll >NUL 2>NUL if %errorlevel% neq 0 exit /b 3 -if /i "%APPVEYOR_REPO_BRANCH:~0,4%" equ "php-" ( - set BRANCH=%APPVEYOR_REPO_BRANCH:~4,3% -) else ( - set BRANCH=master -) +call %~dp0find-target-branch.bat set STABILITY=staging set DEPS_DIR=%PHP_BUILD_CACHE_BASE_DIR%\deps-%BRANCH%-%PHP_SDK_VS%-%PHP_SDK_ARCH% rem SDK is cached, deps info is cached as well @@ -51,7 +49,12 @@ if %errorlevel% neq 0 exit /b 3 if "%THREAD_SAFE%" equ "0" set ADD_CONF=%ADD_CONF% --disable-zts if "%INTRINSICS%" neq "" set ADD_CONF=%ADD_CONF% --enable-native-intrinsics=%INTRINSICS% -set CFLAGS=/W1 /WX +rem Some undefined behavior is reported on 32-bit, this should be fixed +if "%PLATFORM%" == "x86" ( + set CFLAGS=/W1 +) else ( + set CFLAGS=/W1 /WX +) cmd /c configure.bat ^ --enable-snapshot-build ^ diff --git a/.github/scripts/windows/find-target-branch.bat b/.github/scripts/windows/find-target-branch.bat new file mode 100644 index 0000000000000..43b285214971c --- /dev/null +++ b/.github/scripts/windows/find-target-branch.bat @@ -0,0 +1,8 @@ +@echo off + +for /f "usebackq tokens=3" %%i in (`findstr PHP_MAJOR_VERSION main\php_version.h`) do set BRANCH=%%i +for /f "usebackq tokens=3" %%i in (`findstr PHP_MINOR_VERSION main\php_version.h`) do set BRANCH=%BRANCH%.%%i + +if /i "%BRANCH%" equ "8.3" ( + set BRANCH=master +) diff --git a/.github/scripts/windows/test.bat b/.github/scripts/windows/test.bat index f51a14b9dc64c..7e2b869db8c1f 100644 --- a/.github/scripts/windows/test.bat +++ b/.github/scripts/windows/test.bat @@ -1,12 +1,17 @@ @echo off +if /i "%APPVEYOR%%GITHUB_ACTIONS%" neq "True" ( + echo for CI only + exit /b 3 +) + set SDK_RUNNER=%PHP_BUILD_CACHE_SDK_DIR%\phpsdk-%PHP_BUILD_CRT%-%PLATFORM%.bat if not exist "%SDK_RUNNER%" ( echo "%SDK_RUNNER%" doesn't exist exit /b 3 ) -cmd /c %SDK_RUNNER% -t %APPVEYOR_BUILD_FOLDER%\.github\scripts\windows\test_task.bat +cmd /c %SDK_RUNNER% -t .github\scripts\windows\test_task.bat if %errorlevel% neq 0 exit /b 3 exit /b 0 diff --git a/.github/scripts/windows/test_task.bat b/.github/scripts/windows/test_task.bat index 65b3ea0e9de80..64976b4bbd91f 100644 --- a/.github/scripts/windows/test_task.bat +++ b/.github/scripts/windows/test_task.bat @@ -1,14 +1,18 @@ @echo off +if /i "%APPVEYOR%%GITHUB_ACTIONS%" neq "True" ( + echo for CI only + exit /b 3 +) + set NO_INTERACTION=1 set REPORT_EXIT_STATUS=1 set SKIP_IO_CAPTURE_TESTS=1 -if /i "%APPVEYOR_REPO_BRANCH:~0,4%" equ "php-" ( - set BRANCH=%APPVEYOR_REPO_BRANCH:~4,3% +call %~dp0find-target-branch.bat +if "%BRANCH%" neq "master" ( set STABILITY=stable ) else ( - set BRANCH=master set STABILITY=staging ) set DEPS_DIR=%PHP_BUILD_CACHE_BASE_DIR%\deps-%BRANCH%-%PHP_SDK_VS%-%PHP_SDK_ARCH% @@ -28,7 +32,12 @@ set PDO_MYSQL_TEST_PASS=%MYSQL_PWD% set PDO_MYSQL_TEST_HOST=%MYSQL_TEST_HOST% set PDO_MYSQL_TEST_PORT=%MYSQL_TEST_PORT% set PDO_MYSQL_TEST_DSN=mysql:host=%PDO_MYSQL_TEST_HOST%;port=%PDO_MYSQL_TEST_PORT%;dbname=test -"C:\Program Files\MySql\MySQL Server 5.7\bin\mysql.exe" --user=%MYSQL_TEST_USER% -e "CREATE DATABASE IF NOT EXISTS test" +if /i "%APPVEYOR%" equ "True" ( + set TMP_MYSQL_BIN=%ProgramFiles%\MySql\MySQL Server 5.7\bin +) else ( + set TMP_MYSQL_BIN=C:\mysql\bin +) +"%TMP_MYSQL_BIN%\mysql.exe" --host=%PDO_MYSQL_TEST_HOST% --port=%MYSQL_TEST_PORT% --user=%MYSQL_TEST_USER% --password=%MYSQL_TEST_PASSWD% -e "CREATE DATABASE IF NOT EXISTS test" if %errorlevel% neq 0 exit /b 3 rem setup PostgreSQL related exts @@ -37,13 +46,22 @@ set PGPASSWORD=Password12! rem set PGSQL_TEST_CONNSTR=host=127.0.0.1 dbname=test port=5432 user=postgres password=Password12! echo ^ >> "./ext/pgsql/tests/config.inc" set PDO_PGSQL_TEST_DSN=pgsql:host=127.0.0.1 port=5432 dbname=test user=%PGUSER% password=%PGPASSWORD% -"C:\Program Files\PostgreSQL\10\bin\createdb.exe" test +if /i "%APPVEYOR%" equ "True" ( + set TMP_POSTGRESQL_BIN=%ProgramFiles%\PostgreSQL\10\bin +) else ( + set TMP_POSTGRESQL_BIN=%PGBIN% +) +"%TMP_POSTGRESQL_BIN%\createdb.exe" test if %errorlevel% neq 0 exit /b 3 rem setup ODBC related exts set ODBC_TEST_USER=sa set ODBC_TEST_PASS=Password12! -set ODBC_TEST_DSN=Driver={ODBC Driver 13 for SQL Server};Server=(local)\SQL2017;Database=master;uid=%ODBC_TEST_USER%;pwd=%ODBC_TEST_PASS% +if /i "%APPVEYOR%" equ "True" ( + set ODBC_TEST_DSN=Driver={ODBC Driver 13 for SQL Server};Server=^(local^)\SQL2017;Database=master;uid=%ODBC_TEST_USER%;pwd=%ODBC_TEST_PASS% +) else ( + set ODBC_TEST_DSN=Driver={ODBC Driver 17 for SQL Server};Server=^(local^)\SQLEXPRESS;Database=master;uid=%ODBC_TEST_USER%;pwd=%ODBC_TEST_PASS% +) set PDOTEST_DSN=odbc:%ODBC_TEST_DSN% rem setup Firebird related exts @@ -61,13 +79,16 @@ if %errorlevel% neq 0 exit /b 3 path C:\Firebird;%PATH% rem prepare for ext/openssl -if "%APPVEYOR%" equ "True" rmdir /s /q C:\OpenSSL-Win32 >NUL 2>NUL -if "%APPVEYOR%" equ "True" rmdir /s /q C:\OpenSSL-Win64 >NUL 2>NUL +rmdir /s /q C:\OpenSSL-Win32 >NUL 2>NUL +rmdir /s /q C:\OpenSSL-Win64 >NUL 2>NUL if "%PLATFORM%" == "x64" ( set OPENSSLDIR="C:\Program Files\Common Files\SSL" ) else ( set OPENSSLDIR="C:\Program Files (x86)\Common Files\SSL" ) +if /i "%GITHUB_ACTIONS%" equ "True" ( + rmdir /s /q %OPENSSLDIR% >nul 2>&1 +) mkdir %OPENSSLDIR% if %errorlevel% neq 0 exit /b 3 copy %DEPS_DIR%\template\ssl\openssl.cnf %OPENSSLDIR% @@ -82,28 +103,18 @@ rem work-around for failing to dl(mysqli) with OPcache (https://github.com/php/p if "%OPCACHE%" equ "1" set OPCACHE_OPTS=%OPCACHE_OPTS% -d extension=mysqli rem prepare for enchant -mkdir C:\usr\local\lib\enchant-2 +mkdir %~d0\usr\local\lib\enchant-2 if %errorlevel% neq 0 exit /b 3 -copy %DEPS_DIR%\bin\libenchant2_hunspell.dll C:\usr\local\lib\enchant-2 +copy %DEPS_DIR%\bin\libenchant2_hunspell.dll %~d0\usr\local\lib\enchant-2 if %errorlevel% neq 0 exit /b 3 -reg add HKEY_CURRENT_USER\SOFTWARE\Enchant\Config /v Module_Dir /t REG_SZ /d c:\enchant_plugins +mkdir %~d0\usr\local\share\enchant\hunspell if %errorlevel% neq 0 exit /b 3 -set PHP_BUILD_CACHE_ENCHANT_DICT_DIR=%PHP_BUILD_CACHE_BASE_DIR%\enchant_dict -if not exist "%PHP_BUILD_CACHE_ENCHANT_DICT_DIR%" ( - echo Creating %PHP_BUILD_CACHE_ENCHANT_DICT_DIR% - mkdir "%PHP_BUILD_CACHE_ENCHANT_DICT_DIR%" -) -if not exist "%PHP_BUILD_CACHE_ENCHANT_DICT_DIR%\en_US.aff" ( - echo Fetching enchant dicts - pushd %PHP_BUILD_CACHE_ENCHANT_DICT_DIR% - del /q * - powershell -Command wget http://windows.php.net/downloads/qa/appveyor/ext/enchant/dict.zip -OutFile dict.zip - unzip dict.zip - del /q dict.zip - popd -) -mkdir %LOCALAPPDATA%\enchant\hunspell -copy %PHP_BUILD_CACHE_ENCHANT_DICT_DIR%\* %LOCALAPPDATA%\enchant\hunspell +echo Fetching enchant dicts +pushd %~d0\usr\local\share\enchant\hunspell +powershell -Command wget http://windows.php.net/downloads/qa/appveyor/ext/enchant/dict.zip -OutFile dict.zip +unzip dict.zip +del /q dict.zip +popd rem prepare for snmp set MIBDIRS=%DEPS_DIR%\share\mibs @@ -137,19 +148,22 @@ mkdir c:\tests_tmp set TEST_PHP_JUNIT=c:\junit.out.xml -cd "%APPVEYOR_BUILD_FOLDER%" nmake test TESTS="%OPCACHE_OPTS% -g FAIL,BORK,LEAK,XLEAK --no-progress -q --offline --show-diff --show-slow 1000 --set-timeout 120 --temp-source c:\tests_tmp --temp-target c:\tests_tmp --bless %PARALLEL%" set EXIT_CODE=%errorlevel% taskkill /f /im snmpd.exe -appveyor PushArtifact %TEST_PHP_JUNIT% - if %EXIT_CODE% GEQ 1 ( git checkout ext\pgsql\tests\config.inc git diff > bless_tests.patch - appveyor PushArtifact bless_tests.patch +) + +if /i "%APPVEYOR%" equ "True" ( + appveyor PushArtifact %TEST_PHP_JUNIT% + if %EXIT_CODE% GEQ 1 ( + appveyor PushArtifact bless_tests.patch + ) ) exit /b %EXIT_CODE% diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5b8a1687c9db0..4617343647410 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -32,9 +32,21 @@ jobs: - name: Generate Matrix id: set-matrix run: php .github/nightly_matrix.php "${{ github.event_name }}" "${{ github.run_attempt }}" + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} LINUX_X64: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} + services: + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test strategy: fail-fast: false matrix: @@ -47,7 +59,7 @@ jobs: zts: [true, false] include: ${{ fromJson(needs.GENERATE_MATRIX.outputs.matrix-include) }} name: "${{ matrix.branch.name }}_LINUX_X64${{ matrix.name }}_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: ubuntu-20.04 + runs-on: ubuntu-${{ (matrix.branch.ref == 'master' && !matrix.asan) && '22.04' || '20.04' }} steps: - name: git checkout uses: actions/checkout@v3 @@ -110,6 +122,11 @@ jobs: -d opcache.jit=1205 - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} LINUX_X32: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} @@ -122,7 +139,7 @@ jobs: name: "${{ matrix.branch.name }}_LINUX_X32_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" runs-on: ubuntu-latest container: - image: ubuntu:20.04 + image: ubuntu:${{ matrix.branch.ref == 'master' && '22.04' || '20.04' }} env: MYSQL_TEST_HOST: mysql PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test @@ -181,6 +198,11 @@ jobs: -d opcache.enable_cli=1 -d opcache.jit_buffer_size=16M -d opcache.jit=1205 + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} MACOS: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} @@ -244,9 +266,21 @@ jobs: -d opcache.jit=1205 - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} COVERAGE_DEBUG_NTS: if: github.repository_owner == 'php' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-20.04 + services: + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test + runs-on: ubuntu-22.04 steps: - name: git checkout uses: actions/checkout@v3 @@ -278,6 +312,11 @@ jobs: - name: Upload Test Coverage to Codecov.io if: always() run: bash <(curl -s https://codecov.io/bash) + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} COMMUNITY: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} @@ -286,7 +325,7 @@ jobs: matrix: branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }} name: "${{ matrix.branch.name }}_COMMUNITY" - runs-on: ubuntu-20.04 + runs-on: ubuntu-${{ matrix.branch.ref == 'master' && '22.04' || '20.04' }} env: UBSAN_OPTIONS: print_stacktrace=1 USE_ZEND_ALLOC: 0 @@ -393,15 +432,27 @@ jobs: if [ $EXIT_CODE -gt 128 ]; then exit 1 fi + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} OPCACHE_VARIATION: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} + services: + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test strategy: fail-fast: false matrix: branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }} name: "${{ matrix.branch.name }}_OPCACHE_VARIATION" - runs-on: ubuntu-20.04 + runs-on: ubuntu-${{ matrix.branch.ref == 'master' && '22.04' || '20.04' }} steps: - name: git checkout uses: actions/checkout@v3 @@ -464,6 +515,11 @@ jobs: -d opcache.file_cache_only=1 - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} MSAN: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} @@ -472,7 +528,7 @@ jobs: matrix: branch: ${{ fromJson(needs.GENERATE_MATRIX.outputs.branches) }} name: "${{ matrix.branch.name }}_MSAN" - runs-on: ubuntu-22.04 + runs-on: ubuntu-${{ matrix.branch.ref == 'master' && '22.04' || '20.04' }} steps: - name: git checkout uses: actions/checkout@v3 @@ -557,6 +613,11 @@ jobs: -d opcache.enable_cli=1 - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} LIBMYSQLCLIENT: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} @@ -567,7 +628,7 @@ jobs: exclude: - branch: { name: 'PHP-80', ref: 'PHP-8.0' } name: "${{ matrix.branch.name }}_LIBMYSQLCLIENT" - runs-on: ubuntu-20.04 + runs-on: ubuntu-${{ matrix.branch.ref == 'master' && '22.04' || '20.04' }} steps: - name: git checkout uses: actions/checkout@v3 @@ -593,7 +654,7 @@ jobs: - name: Build mysql-5.7 uses: ./.github/actions/build-libmysqlclient with: - libmysql: mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz + libmysql: mysql-5.7.41-linux-glibc2.12-x86_64.tar.gz withMysqli: ${{ matrix.branch.ref == 'PHP-8.1' }} - name: Test mysql-5.7 uses: ./.github/actions/test-libmysqlclient @@ -604,7 +665,7 @@ jobs: with: # FIXME: There are new warnings # configurationParameters: --enable-werror - libmysql: mysql-8.0.30-linux-glibc2.12-x86_64.tar.xz + libmysql: mysql-8.0.33-linux-glibc2.12-x86_64.tar.xz withMysqli: ${{ matrix.branch.ref == 'PHP-8.1' }} - name: Test mysql-8.0 uses: ./.github/actions/test-libmysqlclient @@ -612,3 +673,116 @@ jobs: withMysqli: ${{ matrix.branch.ref == 'PHP-8.1' }} - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} + PECL: + if: github.repository_owner == 'php' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-22.04 + env: + CC: ccache gcc + CXX: ccache g++ + steps: + - name: git checkout PHP + uses: actions/checkout@v3 + with: + path: php + - name: git checkout apcu + uses: actions/checkout@v3 + with: + repository: krakjoe/apcu + path: apcu + - name: git checkout imagick + uses: actions/checkout@v3 + with: + repository: Imagick/imagick + path: imagick + - name: git checkout memcached + uses: actions/checkout@v3 + with: + repository: php-memcached-dev/php-memcached + path: memcached + - name: git checkout redis + uses: actions/checkout@v3 + with: + repository: phpredis/phpredis + path: redis + - name: git checkout xdebug + uses: actions/checkout@v3 + with: + repository: xdebug/xdebug + path: xdebug + - name: git checkout yaml + uses: actions/checkout@v3 + with: + repository: php/pecl-file_formats-yaml + path: yaml + - name: apt + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + ccache \ + libmemcached-dev \ + bison \ + re2c + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: "${{github.job}}-${{hashFiles('php/main/php_version.h')}}" + append-timestamp: false + - name: build PHP + run: | + cd php + ./buildconf --force + ./configure \ + --enable-option-checking=fatal \ + --prefix=/opt/php \ + --enable-cli \ + --disable-all \ + --enable-session \ + --enable-werror + make -j$(/usr/bin/nproc) + sudo make install + - name: build apcu + run: | + cd apcu + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build imagick + run: | + cd imagick + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build memcached + run: | + cd memcached + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build redis + run: | + cd redis + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build xdebug + run: | + cd xdebug + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: build yaml + run: | + cd yaml + /opt/php/bin/phpize + ./configure --prefix=/opt/php --with-php-config=/opt/php/bin/php-config + make -j$(/usr/bin/nproc) + - name: Notify Slack + if: failure() + uses: ./.github/actions/notify-slack + with: + token: ${{ secrets.ACTION_MONITORING_SLACK }} diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 40daccd183485..19a7985e5b7e0 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -20,8 +20,21 @@ on: - '**' permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.url || github.run_id }} + cancel-in-progress: true +env: + CC: ccache gcc + CXX: ccache g++ jobs: LINUX_X64: + services: + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test strategy: fail-fast: false matrix: @@ -31,7 +44,7 @@ jobs: - debug: false zts: true name: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: git checkout uses: actions/checkout@v3 @@ -41,6 +54,14 @@ jobs: uses: ./.github/actions/setup-oracle - name: apt uses: ./.github/actions/apt-x64 + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + # This duplicates the "job.name" expression above because + # GitHub has no way to query the job name (github.job is the + # job id, not the job name) + key: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}-${{hashFiles('main/php_version.h')}}" + append-timestamp: false - name: ./configure uses: ./.github/actions/configure-x64 with: @@ -71,7 +92,7 @@ jobs: name: LINUX_X32_DEBUG_ZTS runs-on: ubuntu-latest container: - image: ubuntu:20.04 + image: ubuntu:22.04 env: MYSQL_TEST_HOST: mysql PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test @@ -89,6 +110,11 @@ jobs: uses: actions/checkout@v3 - name: apt uses: ./.github/actions/apt-x32 + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: "${{github.job}}-${{hashFiles('main/php_version.h')}}" + append-timestamp: false - name: ./configure uses: ./.github/actions/configure-x32 with: @@ -115,6 +141,11 @@ jobs: uses: actions/checkout@v3 - name: brew uses: ./.github/actions/brew + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: "${{github.job}}-${{hashFiles('main/php_version.h')}}" + append-timestamp: false - name: ./configure uses: ./.github/actions/configure-macos with: @@ -140,3 +171,142 @@ jobs: -d opcache.jit_buffer_size=16M - name: Verify generated files are up to date uses: ./.github/actions/verify-generated-files + WINDOWS: + strategy: + fail-fast: false + matrix: + include: + - x64: true + zts: false + opcache: true + - x64: false + zts: true + opcache: false + name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + runs-on: windows-2019 + env: + PHP_BUILD_CACHE_BASE_DIR: C:\build-cache + PHP_BUILD_OBJ_DIR: C:\obj + PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk + PHP_BUILD_SDK_BRANCH: php-sdk-2.2.0 + PHP_BUILD_CRT: vs16 + PLATFORM: ${{ matrix.x64 && 'x64' || 'x86' }} + THREAD_SAFE: "${{ matrix.zts && '1' || '0' }}" + INTRINSICS: "${{ matrix.zts && 'AVX2' || '' }}" + PARALLEL: -j2 + OPCACHE: "${{ matrix.opcache && '1' || '0' }}" + steps: + - name: git config + run: git config --global core.autocrlf false && git config --global core.eol lf + - name: git checkout + uses: actions/checkout@v3 + - name: Setup MySQL + run: | + choco install mysql -y --no-progress --params="/port:3306" + mysql.exe --port=3306 --user=root --password="" -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'Password12!'; FLUSH PRIVILEGES;" + - name: Setup MSSQL + run: | + choco install sql-server-express -y --no-progress --install-arguments="/SECURITYMODE=SQL /SAPWD=Password12!" + - name: Setup PostgreSQL + run: | + Set-Service -Name "postgresql-x64-14" -StartupType manual -Status Running + pwsh -Command { $env:PGPASSWORD="root"; & "$env:PGBIN\psql" -U postgres -c "ALTER USER postgres WITH PASSWORD 'Password12!';" } + - name: Build + run: .github/scripts/windows/build.bat + - name: Test + run: .github/scripts/windows/test.bat + BENCHMARKING: + name: BENCHMARKING + if: github.repository_owner == 'php' || github.event_name == 'pull_request' + runs-on: ubuntu-22.04 + steps: + - name: git checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: apt + run: | + set -x + sudo apt-get update + sudo apt-get install \ + bison \ + libgmp-dev \ + libonig-dev \ + libsqlite3-dev \ + openssl \ + re2c \ + valgrind + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: "${{github.job}}-${{hashFiles('main/php_version.h')}}" + append-timestamp: false + - name: ./configure + run: | + set -x + ./buildconf --force + ./configure \ + --disable-debug \ + --enable-mbstring \ + --enable-opcache \ + --enable-option-checking=fatal \ + --enable-sockets \ + --enable-werror \ + --prefix=/usr \ + --with-config-file-scan-dir=/etc/php.d \ + --with-gmp \ + --with-mysqli=mysqlnd \ + --with-openssl \ + --with-pdo-sqlite \ + --with-valgrind + - name: make + run: make -j$(/usr/bin/nproc) >/dev/null + - name: make install + run: | + set -x + sudo make install + sudo mkdir -p /etc/php.d + sudo chmod 777 /etc/php.d + echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini + echo zend_extension=opcache.so >> /etc/php.d/opcache.ini + echo opcache.enable=1 >> /etc/php.d/opcache.ini + echo opcache.enable_cli=1 >> /etc/php.d/opcache.ini + - name: Setup + run: | + git config --global user.name "Benchmark" + git config --global user.email "benchmark@php.net" + sudo service mysql start + mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS wordpress" + mysql -uroot -proot -e "CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'wordpress'; FLUSH PRIVILEGES;" + mysql -uroot -proot -e "GRANT ALL PRIVILEGES ON *.* TO 'wordpress'@'localhost' WITH GRANT OPTION;" + - name: git checkout benchmarking-data + uses: actions/checkout@v3 + with: + repository: php/benchmarking-data + ssh-key: ${{ secrets.BENCHMARKING_DATA_DEPLOY_KEY }} + path: benchmark/repos/data + - name: Benchmark + run: php benchmark/benchmark.php true + - name: Store result + if: github.event_name == 'push' + run: | + set -x + cd benchmark/repos/data + git pull --autostash + if [ -e ".git/MERGE_HEAD" ]; then + echo "Merging, can't proceed" + exit 1 + fi + git add . + if git diff --cached --quiet; then + exit 0 + fi + git commit -m "Add result for ${{ github.repository }}@${{ github.sha }}" + git push + - name: Show diff + if: github.event_name == 'pull_request' + run: |- + php benchmark/generate_diff.php \ + ${{ github.sha }} \ + $(git merge-base ${{ github.event.pull_request.base.sha }} ${{ github.sha }}) \ + > $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore index 7a4ba0e0222ba..49acc9f2e1788 100644 --- a/.gitignore +++ b/.gitignore @@ -169,6 +169,7 @@ php # Miscellaneous extensions files /ext/opcache/jit/zend_jit_x86.c +/ext/opcache/jit/zend_jit_arm64.c /ext/opcache/minilua # Generated by `cd ext/name && phpize && ./configure` @@ -285,6 +286,7 @@ tmp-php.ini # ------------------------------------------------------------------------------ /branch-commit-cache.json /junit.out.xml +/.ccache/ # ------------------------------------------------------------------------------ # Special cases to invert previous ignore patterns diff --git a/.travis.yml b/.travis.yml index c90dcdeabf71b..cd861303fc3a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ git: quiet: true -dist: bionic +dist: focal language: c os: linux addons: @@ -68,8 +68,6 @@ env: jobs: include: - - env: ENABLE_ZTS=1 ENABLE_DEBUG=1 ARM64=1 - arch: arm64 - env: ENABLE_ZTS=1 ENABLE_DEBUG=1 S390X=1 arch: s390x @@ -88,8 +86,6 @@ before_script: # Run PHPs run-tests.php script: - travis_wait ./travis/test.sh -d opcache.jit_buffer_size=16M -d opcache.jit=tracing - - if [[ "$ARM64" == 1 ]]; then travis_wait ./travis/test.sh -d opcache.jit_buffer_size=16M -d opcache.jit=function; fi - - if [[ "$ARM64" == 1 ]]; then travis_wait ./travis/test.sh -d opcache.jit_buffer_size=16M -d opcache.jit=tracing --repeat 2; fi - sapi/cli/php -d extension_dir=`pwd`/modules -r 'dl("zend_test");' after_success: diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000000..befcdd6fce863 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,49 @@ +# The following volunteers have self-identified as subject matter experts +# or interested parties over a particular area of the php-src source code. +# While requesting a review from someone does not obligate that person to +# review a pull request, these reviewers might have valuable knowledge of +# the problem area and could aid in deciding whether a pull request is ready +# for merging. +# +# For more information, see the GitHub CODEOWNERS documentation: +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +*.stub.php @kocsismate +/.github @iluuu1994 @TimWolla +/build/gen_stub.php @kocsismate +/ext/curl @adoy +/ext/date @derickr +/ext/dba @Girgias +/ext/ffi @dstogov +/ext/gmp @Girgias +/ext/imap @Girgias +/ext/json @bukka +/ext/mbstring @alexdowad +/ext/opcache @dstogov @iluuu1994 +/ext/openssl @bukka +/ext/pgsql @devnexen +/ext/random @TimWolla @zeriyoshi +/ext/session @Girgias +/ext/sockets @devnexen +/ext/spl @Girgias +/main @bukka +/sapi/fpm @bukka +/Zend @iluuu1994 +/Zend/Optimizer @dstogov +/Zend/zend.* @dstogov +/Zend/zend_alloc.* @dstogov +/Zend/zend_API.* @dstogov +/Zend/zend_closures.* @dstogov +/Zend/zend_execute.* @dstogov +/Zend/zend_execute_API.c @dstogov +/Zend/zend_gc.* @dstogov +/Zend/zend_hash.* @dstogov +/Zend/zend_inheritance.* @dstogov +/Zend/zend_object_handlers.* @dstogov +/Zend/zend_objects.* @dstogov +/Zend/zend_objects_API.* @dstogov +/Zend/zend_opcode.* @dstogov +/Zend/zend_string.* @dstogov +/Zend/zend_type*.h @dstogov +/Zend/zend_variables.* @dstogov +/Zend/zend_vm* @dstogov diff --git a/CODING_STANDARDS.md b/CODING_STANDARDS.md index 25ecd75cb07bc..8615892279c92 100644 --- a/CODING_STANDARDS.md +++ b/CODING_STANDARDS.md @@ -9,6 +9,10 @@ rewritten to comply with these rules. 1. Document your code in source files and the manual. (tm) +1. PHP is implemented in C99. The optional fixed-width integers from + stdint.h (int8_t, int16_t, int32_t, int64_t and their unsigned + counterparts) must be available. + 1. Functions that are given pointers to resources should not free them. For instance, `function int mail(char *to, char *from)` should NOT free `to` @@ -74,6 +78,11 @@ rewritten to comply with these rules. may need to control or free the memory, or when the memory in question needs to survive between multiple requests. +1. The return type of "is" or "has" style functions should be `bool`, + which return a "yes"/"no" answer. `zend_result` is an appropriate + return value for functions that perform some operation that may + succeed or fail. + ## User functions/methods naming conventions 1. Function names for user-level functions should be enclosed with in the diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aa12fe0366aee..56df41053c35e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,7 @@ had several contributions accepted, commit privileges are often quickly granted. * [Pull requests](#pull-requests) * [Filing bugs](#filing-bugs) * [Feature requests](#feature-requests) +* [Technical resources](#technical-resources) * [Writing tests](#writing-tests) * [Writing documentation](#writing-documentation) * [Getting help](#getting-help) @@ -85,6 +86,30 @@ You may also want to read [The Mysterious PHP RFC Process](https://blogs.oracle.com/opal/post/the-mysterious-php-rfc-process-and-how-you-can-change-the-web) for additional notes on the best way to approach submitting an RFC. +## Technical resources + +There are a number of technical resources on php-src. Unfortunately, they are +scattered across different websites, and often outdated. Nonetheless, they can +provide a good starting point for learning about the fundamentals of the code +base. + +* https://www.phpinternalsbook.com/ +* https://www.npopov.com/ + * [Internal value representation](https://www.npopov.com/2015/05/05/Internal-value-representation-in-PHP-7-part-1.html), [part 2](https://www.npopov.com/2015/06/19/Internal-value-representation-in-PHP-7-part-2.html) + * [HashTable implementation](https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html) + * [Zend Virtual Machine](https://www.npopov.com/2017/04/14/PHP-7-Virtual-machine.html) + * [How opcache works](https://www.npopov.com/2021/10/13/How-opcache-works.html) + * [The opcache optimizer](https://www.npopov.com/2022/05/22/The-opcache-optimizer.html) +* https://wiki.php.net/internals + * [Objects](https://wiki.php.net/internals/engine/objects) +* https://qa.php.net/ + * [Writing tests](https://qa.php.net/write-test.php) + * [Running tests](https://qa.php.net/running-tests.php) + * [PHPT structure](https://qa.php.net/phpt_details.php) +* https://phpinternals.net/ + * [Implementing new operator](https://phpinternals.net/articles/implementing_a_range_operator_into_php), [part 2](https://phpinternals.net/articles/a_reimplementation_of_the_range_operator) + * [Opcode extending](https://phpinternals.net/articles/implementing_new_language_constructs_via_opcode_extending) + ## Writing tests We love getting new tests! PHP is a huge project and improving test coverage is @@ -185,9 +210,6 @@ locations. └─ pcre/ ├─ pcre2lib/ # https://www.pcre.org/ └─ ... - └─ pdo_mysql/ - ├─ php_pdo_mysql_sqlstate.h # Generated by `ext/pdo_mysql/get_error_codes.php` - └─ ... └─ skeleton/ # Skeleton for developing new extensions with `ext/ext_skel.php` └─ ... └─ standard/ @@ -334,8 +356,8 @@ Currently we have the following branches in use: | master | Active development branch for PHP 8.3, which is open for backwards incompatible changes and major internal API changes. | | PHP-8.2 | Is used to release the PHP 8.2.x series. This is a current stable version and is open for bugfixes only. | | PHP-8.1 | Is used to release the PHP 8.1.x series. This is a current stable version and is open for bugfixes only. | -| PHP-8.0 | Is used to release the PHP 8.0.x series. This is a current stable version and is open for bugfixes only. | -| PHP-7.4 | Is used to release the PHP 7.4.x series. This is an old stable version and is open for security fixes only. | +| PHP-8.0 | Is used to release the PHP 8.0.x series. This is an old stable version and is open for security fixes only. | +| PHP-7.4 | This branch is closed. | | PHP-7.3 | This branch is closed. | | PHP-7.2 | This branch is closed. | | PHP-7.1 | This branch is closed. | diff --git a/EXTENSIONS b/EXTENSIONS index 1d07c1c2e9516..4e480854a8fdd 100644 --- a/EXTENSIONS +++ b/EXTENSIONS @@ -428,7 +428,7 @@ SINCE: 4.0.2 ------------------------------------------------------------------------------- EXTENSION: random PRIMARY MAINTAINER Go Kudo (2022 - 2022) - Tim Düsterhus (2022 - 2022) + Tim Düsterhus (2022 - 2023) MAINTENANCE: Maintained STATUS: Working SINCE: 8.2.0 diff --git a/LICENSE b/LICENSE index dffd7eab225d7..47a594e38a4d2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ -------------------------------------------------------------------- The PHP License, version 3.01 -Copyright (c) 1999 - 2022 The PHP Group. All rights reserved. +Copyright (c) 1999 - 2023 The PHP Group. All rights reserved. -------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without diff --git a/NEWS b/NEWS index 03fa5acc2a4eb..92fe365e3ab6b 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ PHP NEWS - CLI: . Added pdeathsig to builtin server to terminate workers when the master process is killed. (ilutov) + . Fixed bug GH-11104 (STDIN/STDOUT/STDERR is not available for CLI without + a script). (nielsdos) - Core: . Fixed bug GH-9388 (Improve unset property and __get type incompatibility @@ -18,6 +20,27 @@ PHP NEWS . Added shadow stack support for fibers. (Chen Hu) . Fix bug GH-9965 (Fix accidental caching of default arguments with side effects). (ilutov) + . Implement GH-10217 (Use strlen() for determining the class_name length). + (Dennis Buteyn) + . Fix bug GH-8821 (Improve line numbers for errors in constant expressions). + (ilutov) + . Fix bug GH-10083 (Allow comments between & and parameter). (ilutov) + . Zend Max Execution Timers is now enabled by default for ZTS builds on + Linux. (Kévin Dunglas) + . Fix bug GH-10469 (Disallow .. in open_basedir paths set at runtime). + (ilutov) + . Fix bug GH-10168, GH-10582 (Various segfaults with destructors and VM return + values). (dstogov, nielsdos, ilutov) + . Fix bug GH-10935 (Use of trait doesn't redeclare static property if class + has inherited it from its parent). (ilutov) + . Fix bug GH-11154 (Negative indices on empty array don't affect next chosen + index). (ColinHDev) + +- Date: + . Implement More Appropriate Date/Time Exceptions RFC. (Derick) + +- Exif: + . Removed unneeded codepaths in exif_process_TIFF_in_JPEG(). (nielsdos) - Fileinfo: . Upgrade bundled libmagic to 5.43. (Anatol) @@ -35,12 +58,51 @@ PHP NEWS (CVE-2022-37454) (nicky at mouha dot be) - Intl: - . Added pattern format error infos for msgfmt_set_pattern. (David Carlier) . Added pattern format error infos for numfmt_set_pattern. (David Carlier) + . Added MIXED_NUMBERS and HIDDEN_OVERLAY constants for + the Spoofchecker's class. (David Carlier) + . Updated datefmt_set_timezone/IntlDateformatter::setTimezone returns type. + (David Carlier). + . Updated IntlBreakInterator::setText return type. (David Carlier) + . Updated IntlChar::enumCharNames return type. (David Carlier) - JSON: . Added json_validate(). (Juan Morales) +- MBString: + . mb_detect_encoding is better able to identify the correct encoding for + Turkish text. (Alex Dowad) + . mb_detect_encoding's "non-strict" mode now behaves as described in the + documentation. Previously, it would return false if the same byte + (for example, the first byte) of the input string was invalid in all + candidate encodings. More generally, it would eliminate candidate + encodings from consideration when an invalid byte was seen, and if the + same input byte eliminated all remaining encodings still under + consideration, it would return false. On the other hand, if all candidate + encodings but one were eliminated from consideration, it would return the + last remaining one without regard for how many encoding errors might be + encountered later in the string. This is different from the behavior + described in the documentation, which says: "If strict is set to false, + the closest matching encoding will be returned." (Alex Dowad) + . mb_strtolower, mb_strtotitle, and mb_convert_case implement conditional + casing rules for the Greek letter sigma. For mb_convert_case, conditional + casing only applies to MB_CASE_LOWER and MB_CASE_TITLE modes, not to + MB_CASE_LOWER_SIMPLE and MB_CASE_TITLE_SIMPLE. (Alex Dowad) + . mb_detect_encoding is better able to identify UTF-8 and UTF-16 strings + with a byte-order mark. (Alex Dowad) + . mb_decode_mimeheader interprets underscores in QPrint-encoded MIME + encoded words as required by RFC 2047; they are converted to spaces. + Underscores must be encoded as "=5F" in such MIME encoded words. + (Alex Dowad) + . mb_encode_mimeheader no longer drops NUL (zero) bytes when + QPrint-encoding the input string. This previously caused strings in + certain text encodings, especially UTF-16 and UTF-32, to be + corrupted by mb_encode_mimeheader. (Alex Dowad) + +- mysqli: + . mysqli_fetch_object raises a ValueError instead of an Exception. + (David Carlier) + - Opcache: . Added start, restart and force restart time to opcache's phpinfo section. (Mikhail Galanin) @@ -50,32 +112,84 @@ PHP NEWS (Arnaud) . Allows W/X bits on page creation on FreeBSD despite system settings. (David Carlier) + . Added memfd api usage, on Linux, for zend_shared_alloc_create_lock() + to create an abstract anonymous file for the opcache's lock. (Max Kellermann) - PCNTL: . SA_ONSTACK is now set for pcntl_signal. (Kévin Dunglas) . Added SIGINFO constant. (David Carlier) +- PGSQL: + . pg_fetch_object raises a ValueError instead of an Exception. + (David Carlier) + . Added GH-9344, pipeline mode support. (David Carlier) + . pg_cancel use thread safe PQcancel api instead. (David Carlier) + . pg_trace new PGSQL_TRACE_SUPPRESS_TIMESTAMPS/PGSQL_TRACE_REGRESS_MODE + contants support. (David Carlier) + +- Phar: + . Fix memory leak in phar_rename_archive(). (stkeke) + - Posix: . Added posix_sysconf. (David Carlier) + . Added posix_pathconf. (David Carlier) + . Added posix_fpathconf. (David Carlier) + . Fixed zend_parse_arg_long's bool pointer argument assignment. (Cristian Rodriguez) + . Added posix_eaccess. (David Carlier) - Random: . Added Randomizer::getBytesFromString(). (Joshua Rüsweg) + . Added Randomizer::nextFloat(), ::getFloat(), and IntervalBoundary. (timwolla) + . Fix GH-10292 (Made the default value of the first param of srand() and + mt_srand() nullable). (kocsismate) + . Enable getrandom() for NetBSD (from 10.x). (David Carlier) - Reflection: . Fix GH-9470 (ReflectionMethod constructor should not find private parent method). (ilutov) + . Fix GH-10259 (ReflectionClass::getStaticProperties doesn't need null return + type). (kocsismate) + . Fix Segfault when using ReflectionFiber suspended by an internal function. + (danog) - Sockets: . Added SO_ATTACH_REUSEPORT_CBPF socket option, to give tighter control over socket binding for a cpu core. (David Carlier) . Added SKF_AD_QUEUE for cbpf filters. (David Carlier) . Added socket_atmark if send/recv needs using MSG_OOB. (David Carlier) + . Added TCP_QUICKACK constant, to give tigher control over + ACK delays. (David Carlier) + . Added DONTFRAGMENT support for path MTU discovery purpose. (David Carlier) + . Added AF_DIVERT for raw socket for divert ports. (David Carlier) + . Added SOL_UPDLITE, UDPLITE_RECV_CSCOV and UDPLITE_SEND_CSCOV for updlite + protocol support. (David Carlier) + . Added SO_RERROR, SO_ZEROIZE and SO_SPLICE netbsd and openbsd constants. + (David Carlier) + . Added TCP_REPAIR for quietly close a connection. (David Carlier) + . Added SO_REUSEPORT_LB freebsd constant. (David Carlier) + . Added IP_BIND_ADDRESS_NO_PORT. (David Carlier) - Standard: - . E_NOTICEs emitted by unserialized() have been promoted to E_WARNING. (timwolla) + . E_NOTICEs emitted by unserialize() have been promoted to E_WARNING. (timwolla) + . unserialize() now emits a new E_WARNING if the input contains unconsumed + bytes. (timwolla) + . Make array_pad's $length warning less confusing. (nielsdos) + . E_WARNING emitted by strtok in the caase both arguments are not provided when + starting tokenisation. (David Carlier) + . password_hash() will now chain the original RandomException to the ValueError + on salt generation failure. (timwolla) + . Fix GH-10239 (proc_close after proc_get_status always returns -1). (nielsdos) + . Improve the warning message for unpack() in case not enough values were + provided. (nielsdos) + . Fix GH-11010 (parse_ini_string() now preserves formatting of unquoted + strings starting with numbers when the INI_SCANNER_TYPED flag is + specified). (ilutov) - Streams: . Fixed bug #51056: blocking fread() will block even if data is available. (Jakub Zelenka) +- XSLTProcessor: + . Fixed bug #69168 (DomNode::getNodePath() returns invalid path). (nielsdos) + <<< NOTE: Insert NEWS from last stable release here prior to actual release! >>> diff --git a/README.md b/README.md index f98feb78823cb..85cdf6c333b23 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ blog to the most popular websites in the world. PHP is distributed under the [![Push](https://github.com/php/php-src/actions/workflows/push.yml/badge.svg)](https://github.com/php/php-src/actions/workflows/push.yml) [![Build status](https://travis-ci.com/php/php-src.svg?branch=master)](https://travis-ci.com/github/php/php-src) [![Build status](https://ci.appveyor.com/api/projects/status/meyur6fviaxgdwdy/branch/master?svg=true)](https://ci.appveyor.com/project/php/php-src) -[![Build Status](https://dev.azure.com/phpazuredevops/php/_apis/build/status/php.php-src?branchName=master)](https://dev.azure.com/phpazuredevops/php/_build/latest?definitionId=1&branchName=master) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/php.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:php) ## Documentation diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000000..161e0810b5862 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,168 @@ +# Vulnerability Disclosure Policy + +*This document was originally published at .* + +## Introduction + +For the sake of our users, we classify some of the issues found in PHP +as "security issues". This document is intended to explain which issues +are thus classified, how we handle those issues and how to report them. + +## Classification + +We classify as security issues bugs that: + +- allow users to execute unauthorized actions +- cross security boundaries +- access data that is not intended to be accessible +- severely impact accessibility or performance of the system + +The purpose of this classification is to alert the users and the +developers about the bugs that need to be prioritized in their handling. + +We define three categories of security issues, by their severity, +described below. Please note that this categorization is in many aspects +subjective, so it ultimately relies on the judgement of the PHP +developers. + +### High severity + +These issues may allow: + +- third party to compromise any, or most installations of PHP +- the execution of arbitrary code +- disabling the system completely +- access to any file a local PHP user can access. + +The issue can be triggered on any, or on most typical installations, and +does not require exotic and non-recommended settings to be triggered. + +This category also includes issues that can be triggered in code or +functions known to be frequently used (session, json, mysql, openssl, +etc.) during typical usage, and that require settings or configurations +that may not be strictly the best practice, but are commonly used. + +This category also may include issues that require special code or code +pattern if such code or pattern is present in many popular libraries. + +This kind of issues usually requires a CVE report. + +### Medium severity + +These issues may have the same potential to compromise an installation +as a high severity issue, but may also require: + +- an extension that is not commonly used +- a particular type of configuration that is used only in narrow + specific circumstances +- relies on old version of a third-party library being used +- code, or patterns of code, that are known to be used infrequently +- code that is very old, or extremely uncommon (and so is used + infrequently) + +This kind of issues usually will have a CVE number, unless the required +configuration is particularly exotic to the point it's not practically +usable. + +### Low severity + +This issue allows theoretical compromise of security, but practical +attack is usually impossible or extremely hard due to common practices +or limitations that are virtually always present or imposed. + +This also includes problems with configuration, documentation, and other +non-code parts of the PHP project that may mislead users, or cause them +to make their system, or their code less secure. + +Issues that can trigger unauthorized actions that do not seem to be +useful for any practical attack can also be categorized as low severity. + +Security issues, that are present only in unstable branches, belong to +this category, too. Any branch that has no stable release, is per se not +intended for the production use. + +Low severity issues usually do not need to have CVE and may, at the +discretion of the PHP developers, be disclosed publicly before the fix +is released or available. + +### Not a security issue + +We do not classify as a security issue any issue that: + +- requires invocation of specific code, which may be valid but is + obviously malicious +- requires invocation of functions with specific arguments, which may + be valid but are obviously malicious +- requires specific actions to be performed on the server, which are + not commonly performed, or are not commonly permissible for the user + (uid) executing PHP +- requires privileges superior to that of the user (uid) executing PHP +- requires the use of debugging facilities - ex. xdebug, var_dump +- requires the use of settings not recommended for production - ex. + error reporting to output +- requires the use of non-standard environment variables - ex. + USE_ZEND_ALLOC +- requires the use of non-standard builds - ex. obscure embedded + platform, not commonly used compiler +- requires the use of code or settings known to be insecure +- requires the use of FFI +- requires an open_basedir bypass + +## Handling issues + +High and medium severity fixes are merged into a private security repository, +and then merged to the main repository before the release is tagged. + +Low severity fixes are merged immediately after the fix is available and +handled like all regular bugs are handled consequently. However, release +managers may choose to pull those fixes into the RC branch after the +branch is created, and also backport them into a security-only release +branch. + +## FAQ + +### How do I report a security issue? + +Please report security vulnerabilities on GitHub at: + + +If for some reason you cannot use the form at GitHub, or you need to talk to +somebody about a PHP security issue that might not be a bug report, please write +to . + +Vulnerability reports remain private until published. When published, you will +be credited as a contributor, and your contribution will reflect the MITRE +Credit System. + +### What do you consider a responsible disclosure? + +Please report the issue as described above. Please communicate with +the developers about when the fix will be released - usually it's the +next monthly release after the bug was reported. Some issues can take +longer. After the fix is released (releases usually happen on Thursdays) +please feel free to disclose the issue as you see fit. + +### What if I think it's a security issue but the developers disagree? + +Please read the above and try to explain to us why it fits the +description. + +### What if the developers still don't think it's a security issue? + +We'll have to agree to disagree. + +### The bug I submitted was classified as "not a security issue." You don't believe it's real? + +It has nothing to do with the bug being real or its importance to +you. It just means it does not fit our specific definitions for issues +that we will handle in a special way. We fix a lot of non-security bugs +and pull requests are always welcome. + +### But you classified bug #424242 as a security issue, but not this one?! + +Each bug usually has its aspects, if a short discussion does not +yield agreement we'd rather do more fixing and less arguing. + +### Do you pay bounties for security issues? + +PHP is a volunteer project. We have no money, thus we can't pay bounties. diff --git a/TSRM/TSRM.c b/TSRM/TSRM.c index 76ffe3fb3376f..09ff8cc49279e 100644 --- a/TSRM/TSRM.c +++ b/TSRM/TSRM.c @@ -161,6 +161,23 @@ TSRM_API bool tsrm_startup(int expected_threads, int expected_resources, int deb return 1; }/*}}}*/ +static void ts_free_resources(tsrm_tls_entry *thread_resources) +{ + /* Need to destroy in reverse order to respect dependencies. */ + for (int i = thread_resources->count - 1; i >= 0; i--) { + if (!resource_types_table[i].done) { + if (resource_types_table[i].dtor) { + resource_types_table[i].dtor(thread_resources->storage[i]); + } + + if (!resource_types_table[i].fast_offset) { + free(thread_resources->storage[i]); + } + } + } + + free(thread_resources->storage); +} /* Shutdown TSRM (call once for the entire process) */ TSRM_API void tsrm_shutdown(void) @@ -182,22 +199,12 @@ TSRM_API void tsrm_shutdown(void) while (p) { next_p = p->next; - for (int j=0; jcount; j++) { - if (p->storage[j]) { - if (resource_types_table) { - if (!resource_types_table[j].done) { - if (resource_types_table[j].dtor) { - resource_types_table[j].dtor(p->storage[j]); - } - - if (!resource_types_table[j].fast_offset) { - free(p->storage[j]); - } - } - } - } + if (resource_types_table) { + /* This call will already free p->storage for us */ + ts_free_resources(p); + } else { + free(p->storage); } - free(p->storage); free(p); p = next_p; } @@ -361,7 +368,13 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, siz return *rsrc_id; }/*}}}*/ +static void set_thread_local_storage_resource_to(tsrm_tls_entry *thread_resource) +{ + tsrm_tls_set(thread_resource); + TSRMLS_CACHE = thread_resource; +} +/* Must be called with tsmm_mutex held */ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id) {/*{{{*/ TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Creating data structures for thread %x", thread_id)); @@ -375,8 +388,7 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_ (*thread_resources_ptr)->next = NULL; /* Set thread local storage to this new thread resources structure */ - tsrm_tls_set(*thread_resources_ptr); - TSRMLS_CACHE = *thread_resources_ptr; + set_thread_local_storage_resource_to(*thread_resources_ptr); if (tsrm_new_thread_begin_handler) { tsrm_new_thread_begin_handler(thread_id); @@ -399,17 +411,14 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_ if (tsrm_new_thread_end_handler) { tsrm_new_thread_end_handler(thread_id); } - - tsrm_mutex_unlock(tsmm_mutex); }/*}}}*/ - /* fetches the requested resource for the current thread */ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id) {/*{{{*/ THREAD_T thread_id; int hash_value; - tsrm_tls_entry *thread_resources; + tsrm_tls_entry *thread_resources, **last_thread_resources; if (!th_id) { /* Fast path for looking up the resources for the current @@ -440,25 +449,55 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id) if (!thread_resources) { allocate_new_resource(&tsrm_tls_table[hash_value], thread_id); + tsrm_mutex_unlock(tsmm_mutex); return ts_resource_ex(id, &thread_id); } else { - do { - if (thread_resources->thread_id == thread_id) { - break; - } + last_thread_resources = &tsrm_tls_table[hash_value]; + while (thread_resources->thread_id != thread_id) { + last_thread_resources = &thread_resources->next; if (thread_resources->next) { thread_resources = thread_resources->next; } else { allocate_new_resource(&thread_resources->next, thread_id); + tsrm_mutex_unlock(tsmm_mutex); return ts_resource_ex(id, &thread_id); - /* - * thread_resources = thread_resources->next; - * break; - */ } - } while (thread_resources); + } + } + + /* It's possible that the current thread resources are requested, and that we get here. + * This means that the TSRM key pointer and cached pointer are NULL, but there is still + * a thread resource associated with this ID in the hashtable. This can occur if a thread + * goes away, but its resources are never cleaned up, and then that thread ID is reused. + * Since we don't always have a way to know when a thread goes away, we can't clean up + * the thread's resources before the new thread spawns. + * To solve this issue, we'll free up the old thread resources gracefully (gracefully + * because there might still be resources open like database connection which need to + * be shut down cleanly). After freeing up, we'll create the new resources for this thread + * as if the stale resources never existed in the first place. From that point forward, + * it is as if that situation never occurred. + * The fact that this situation happens isn't that bad because a child process containing + * threads will eventually be respawned anyway by the SAPI, so the stale threads won't last + * forever. */ + TSRM_ASSERT(thread_resources->thread_id == thread_id); + if (thread_id == tsrm_thread_id() && !tsrm_tls_get()) { + tsrm_tls_entry *next = thread_resources->next; + /* In case that extensions don't use the pointer passed from the dtor, but incorrectly + * use the global pointer, we need to setup the global pointer temporarily here. */ + set_thread_local_storage_resource_to(thread_resources); + /* Free up the old resource from the old thread instance */ + ts_free_resources(thread_resources); + free(thread_resources); + /* Allocate a new resource at the same point in the linked list, and relink the next pointer */ + allocate_new_resource(last_thread_resources, thread_id); + thread_resources = *last_thread_resources; + thread_resources->next = next; + /* We don't have to tail-call ts_resource_ex, we can take the fast path to the return + * because we already have the correct pointer. */ } + tsrm_mutex_unlock(tsmm_mutex); + /* Read a specific resource from the thread's resources. * This is called outside of a mutex, so have to be aware about external * changes to the structure as we read it. @@ -483,17 +522,7 @@ void ts_free_thread(void) while (thread_resources) { if (thread_resources->thread_id == thread_id) { - for (int i=0; icount; i++) { - if (resource_types_table[i].dtor) { - resource_types_table[i].dtor(thread_resources->storage[i]); - } - } - for (int i=0; icount; i++) { - if (!resource_types_table[i].fast_offset) { - free(thread_resources->storage[i]); - } - } - free(thread_resources->storage); + ts_free_resources(thread_resources); if (last) { last->next = thread_resources->next; } else { @@ -779,7 +808,7 @@ TSRM_API const char *tsrm_api_name(void) #endif }/*}}}*/ -TSRM_API bool tsrm_is_managed_thread() +TSRM_API bool tsrm_is_managed_thread(void) {/*{{{*/ return tsrm_tls_get() ? true : false; }/*}}}*/ diff --git a/TSRM/threads.m4 b/TSRM/threads.m4 index dc5719bbec056..c42b328dd6651 100644 --- a/TSRM/threads.m4 +++ b/TSRM/threads.m4 @@ -73,7 +73,7 @@ void *thread_routine(void *data) { return data; } -int main() { +int main(void) { pthread_t thd; pthread_mutexattr_t mattr; int data = 1; diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 241ac708e1bc8..dc8f9fefa3ab1 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -89,7 +89,7 @@ static void tsrm_win32_dtor(tsrm_win32_globals *globals) TSRM_API void tsrm_win32_startup(void) {/*{{{*/ #ifdef ZTS - ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor); + ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_dtor)tsrm_win32_dtor); #else tsrm_win32_ctor(&win32_globals); #endif diff --git a/UPGRADING b/UPGRADING index fb40184c7d54d..a3f6a12f3dc09 100644 --- a/UPGRADING +++ b/UPGRADING @@ -19,22 +19,66 @@ PHP 8.3 UPGRADE NOTES 1. Backward Incompatible Changes ======================================== +- Core: + . Programs that were very close to overflowing the call stack may now throw an + Error when using more than + `zend.max_allowed_stack_size-zend.reserved_stack_size` bytes of stack + (`fiber.stack_size-zend.reserved_stack_size` for fibers). + . Class constants can now be accessed dynamically using the C::{$name} syntax. + RFC: https://wiki.php.net/rfc/dynamic_class_constant_fetch + . Executing proc_get_status() multiple times will now always return the right + value on posix systems. Previously, only the first call of the function + returned the right value. Executing proc_close() after proc_get_status() will + now also return the right exit code. Previously this would return -1. + Internally, this works by caching the result on posix systems. If you want + the old behaviour, you can check the "cached" key in the array returned by + proc_get_status() to check whether the result was cached. + . Zend Max Execution Timers is now enabled by default for ZTS builds on + Linux. + . Uses of traits with static properties will now redeclare static properties + inherited from the parent class. This will create a separate static property + storage for the current class. This is analogous to adding the static + property to the class directly without traits. + . Assigning a negative index n to an empty array will now make sure that the + next index is n+1 instead of 0. + +- FFI: + . C functions that have a return type of void now return null instead of + returning the following object object(FFI\CData:void) { } + ======================================== 2. New Features ======================================== +- Core + . Anonymous classes may now be marked as readonly. + . Readonly properties can now be reinitialized during cloning. + RFC: https://wiki.php.net/rfc/readonly_amendments + . Class, interface, trait, and enum constants now support type + declarations. RFC: https://wiki.php.net/rfc/typed_class_constants + - Posix . posix_getrlimit() now takes an optional $res parameter to allow fetching a single resource limit. + . posix_isatty() now raises type warnings for integers following the usual ZPP semantics + . posix_ttyname() now raises type warnings for integers following the usual ZPP semantics + and value warnings for invalid file descriptor integers. ======================================== 3. Changes in SAPI modules ======================================== +- $_SERVER['SERVER_SOFTWARE'] value from the built-in CLI server changed + to make it compliant with RFC3875. + ======================================== 4. Deprecated Functionality ======================================== +- Intl + . The U_MULTIPLE_DECIMAL_SEP*E*RATORS constant had been deprecated, using + the U_MULTIPLE_DECIMAL_SEP*A*RATORS instead is recommended. + ======================================== 5. Changed Functions ======================================== @@ -46,10 +90,78 @@ PHP 8.3 UPGRADE NOTES "full" => bool "buffer_size" => int See GH-9336 + . class_alias() now supports creating an alias of an internal class. + . Setting `open_basedir` at runtime using `ini_set('open_basedir', ...);` no + longer accepts paths containing the parent directory (`..`). Previously, + only paths starting with `..` were disallowed. This could easily be + circumvented by prepending `./` to the path. + +- Dom: + . Changed DOMCharacterData::appendData() tentative return type to true. + +- Intl: + . datefmt_set_timezone (and its alias IntlDateformatter::setTimeZone) + now returns true on success, previously null was returned. + . IntlBreakiterator::setText() now returns false on failure, previously + null was returned. + now returns true on sucess, previously null was returned. + . IntlChar::enumCharNames is now returning a boolean. + Previously it returned null on success and false on failure. + +- MBString: + . mb_strtolower, mb_strtotitle, and mb_convert_case implement conditional + casing rules for the Greek letter sigma. For mb_convert_case, conditional + casing only applies to MB_CASE_LOWER and MB_CASE_TITLE modes, not to + MB_CASE_LOWER_SIMPLE and MB_CASE_TITLE_SIMPLE. + . mb_decode_mimeheader interprets underscores in QPrint-encoded MIME + encoded words as required by RFC 2047; they are converted to spaces. + Underscores must be encoded as "=5F" in such MIME encoded words. + . In rare cases, mb_encode_mimeheader will transfer-encode its input + string where it would pass it through as raw ASCII in PHP 8.2. + . mb_encode_mimeheader no longer drops NUL (zero) bytes when + QPrint-encoding the input string. This previously caused strings in + certain text encodings, especially UTF-16 and UTF-32, to be + corrupted by mb_encode_mimeheader. + . mb_detect_encoding's "non-strict" mode now behaves as described in the + documentation. Previously, it would return false if the same byte + (for example, the first byte) of the input string was invalid in all + candidate encodings. More generally, it would eliminate candidate + encodings from consideration when an invalid byte was seen, and if the + same input byte eliminated all remaining encodings still under + consideration, it would return false. On the other hand, if all candidate + encodings but one were eliminated from consideration, it would return the + last remaining one without regard for how many encoding errors might be + encountered later in the string. This is different from the behavior + described in the documentation, which says: "If strict is set to false, + the closest matching encoding will be returned." + +- mysqli: + . mysqli_fetch_object now raises a ValueError instead of an Exception when the constructor_args + argument is non empty with the class not having constructor. + . mysqli_poll now raises a ValueError when the read nor error arguments are passed. + +- PGSQL: + . pg_fetch_object now raises a ValueError instead of an Exception when the constructor_args + argument is non empty with the class not having constructor. + . pg_insert now raises a ValueError instead of a WARNING when the table specified is invalid. - Standard: - . E_NOTICEs emitted by unserialized() have been promoted to E_WARNING. + . E_NOTICEs emitted by unserialize() have been promoted to E_WARNING. RFC: https://wiki.php.net/rfc/improve_unserialize_error_handling + . unserialize() now emits a new E_WARNING if the input contains unconsumed + bytes. + RFC: https://wiki.php.net/rfc/unserialize_warn_on_trailing_data + . array_pad() is now only limited by the maximum number of elements an array + can have. Before, it was only possible to add at most 1048576 elements at a + time. + . strtok() raises a warning in the case token is not provided when starting tokenization. + . password_hash() will now chain the underlying Random\RandomException + as the ValueError’s $previous Exception when salt generation fails. + . proc_open() $command array must now have at least one non empty element. + . array_sum() and array_product() now warn when values in the array cannot be converted to int/float. + Previously arrays and objects where ignored whilst every other value was cast to int. + Moreover, objects that define a numeric cast (e.g. GMP) are now casted instead of ignored. + RFC: https://wiki.php.net/rfc/saner-array-sum-product ======================================== 6. New Functions @@ -62,10 +174,22 @@ PHP 8.3 UPGRADE NOTES - Posix: . Added posix_sysconf call to get runtime informations. + . Added posix_pathconf call to get configuration value from a directory/file. + . Added posix_fpathconf call to get configuration value from a file descriptor. + . Added posix_eaccess call to check the effective user id's permission for a path. - Random: . Added Randomizer::getBytesFromString(). RFC: https://wiki.php.net/rfc/randomizer_additions + . Added Randomizer::nextFloat(), ::getFloat(), and IntervalBoundary. + RFC: https://wiki.php.net/rfc/randomizer_additions + . Changed mt_srand() and srand() to not check the number of arguments to + determine whether a random seed should be used. Passing null will generate + a random seed, 0 will use zero as the seed. The functions are now consistent + with Mt19937::__construct(). + +- Reflection: + . Return type of ReflectionClass::getStaticProperties() is no longer nullable. - Sockets: . Added socket_atmark to checks if the socket is OOB marked. @@ -86,22 +210,69 @@ PHP 8.3 UPGRADE NOTES 10. New Global Constants ======================================== +- Intl: + . MIXED_NUMBERS (Spoofchecker). + . HIDDEN_OVERLAY (Spoofchecker). + - PCNTL: . SIGINFO +- PGSQL: + . PGSQL_TRACE_SUPPRESS_TIMESTAMPS. + . PGSQL_TRACE_REGRESS_MODE. + - Posix: - . POSIX_SC_ARG_MAX - . POSIX_SC_PAGESIZE - . POSIX_SC_NPROCESSORS_CONF - . POSIX_SC_NPROCESSORS_ONLN + . POSIX_SC_ARG_MAX. + . POSIX_SC_PAGESIZE. + . POSIX_SC_NPROCESSORS_CONF. + . POSIX_SC_NPROCESSORS_ONLN. - Sockets: . SO_ATTACH_REUSEPORT_CBPF (Linux only). + . TCP_QUICKACK (Linux only). + . IP_DONTFRAG (FreeBSD only). + . IP_MTU_DISCOVER (Linux only). + . IP_PMTUDISC_DO (Linux only). + . IP_PMTUDISC_DONT (Linux only). + . IP_PMTUDISC_WANT (Linux only). + . IP_PMTUDISC_PROBE (Linux only). + . IP_PMTUDISC_INTERFACE (Linux only). + . IP_PMTUDISC_OMIT (Linux only). + . AF_DIVERT (FreeBSD only). + . SOL_UDPLITE. + . UDPLITE_RECV_CSCOV. + . UDPLITE_SEND_CSCOV. + . SO_RERROR (NetBSD only). + . SO_ZEROIZE (OpenBSD only). + . SO_SPLICE (OpenBSD only). + . TCP_REPAIR (Linux only). + . SO_REUSEPORT_LB (FreeBSD only). + . IP_BIND_ADDRESS_NO_PORT (Linux only). ======================================== 11. Changes to INI File Handling ======================================== +- zend.max_allowed_stack_size + . New INI directive to set the maximum allowed stack size. Possible + values are `0` (detect the process or thread maximum stack size), `-1` + (no limit), or a positive number of bytes. The default is `0`. When it + is not possible to detect the the process or thread maximum stack size, + a known system default is used. Setting this value too high has the same + effect as disabling the stack size limit. Fibers use fiber.stack_size + as maximum allowed stack size. An Error is thrown when the process call + stack exceeds `zend.max_allowed_stack_size-zend.reserved_stack_size` + bytes, to prevent stack-overflow-induced segmentation faults, with + the goal of making debugging easier. The stack size increases during + uncontrolled recursions involving internal functions or the magic methods + __toString, __clone, __sleep, __destruct. This is not related to stack + buffer overflows, and is not a security feature. + +- zend.reserved_stack_size + . New INI directive to set the reserved stack size, in bytes. This is + subtracted from the max allowed stack size, as a buffer, when checking the + stack size. + ======================================== 12. Windows Support ======================================== @@ -110,6 +281,13 @@ PHP 8.3 UPGRADE NOTES 13. Other Changes ======================================== +- Core: + . An Error is now thrown when the process call stack exceeds a certain size, + to prevent stack-overflow-induced segmentation faults, with the goal of + making debugging easier. The maximum allowed stack size is controlled + by the INI directives zend.max_allowed_stack_size, zend.reserved_stack_size, + and fiber.stack_size. + - FFI: . FFI::load() is now allowed during preloading when opcache.preload_user is the current system user. Previously, calling FFI::load() was not possible during diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 47f37cf1c92cf..b4675e22215e9 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -16,11 +16,68 @@ PHP 8.3 INTERNALS UPGRADE NOTES * zend_class_entry now possesses a default_object_handlers field, which provides a default object handler when create_object() is not overriding it. +* Custom Fiber implementations have to initialize EG(stack_limit) and + EG(stack_base). +* EG(opline_before_exception) may now be null if the VM throws an exception + before executing any opline. +* Many C header files have been cleaned up and include dependencies + have been reduced. Many headers which used to be always included by + Zend headers (e.g. "errno.h") are no longer implied, and this may + break the build of third-party extensions which relied on this + implementation detail. Those extensions may need to add the missing + #include lines. +* Since version 8, PHP requires a C99 compiler. Configure-time checks + for C99 features have been removed and therefore macro definitions + from php_config.h have disappeared. Do not use those feature + macros. +* Internal class aliases created during request time can now exist in + the class table. zend_register_class_alias_ex() will not increase + the refcount for class aliases and the cleanup function takes this + into account. +* The return types of the following functions have been changed from + `bool` to `zend_result`: + - zend_fiber_init_context() +* The fast_add_function() has been removed, use add_function() that will + call the static inline add_function_fast() instead. +* The order of members of zend_op_array, zend_ssa_var, zend_ssa_var_info, + zend_executor_globals and php_core_globals have changed to improve + struct packing which reduces their size. +* The name field have been removed from the zend_constant struct. Now, + constant names are only stored as keys of the global constants table. + That's why the `zend_register_constant()` function now expects the + constant name as its first parameter. +* Many calls to zend_assign_to_variable have been replaced with + zend_assign_to_variable_ex which allows delaying the releasing of the old + variable value. This avoids side-effects through destructors between the + assignment of the variable and the assignment to the result zval in the VM + (i.e. it may free the new value). See GH-10168 for details. +* The return types of the following functions were changed from int to + zend_result: + - open_file_for_scanning + - php_rfc1867_callback + - virtual_chdir + - zend_execute_scripts + - zend_get_module_started + - zend_handle_undef_args + - zend_list_delete + - zend_multibyte_parse_encoding_list + - zend_multibyte_set_internal_encoding + - zend_parse_ini_file + - zend_parse_ini_string + - zend_set_user_opcode_handler + - zend_ssa_inference +* Removed unused macros PHP_FNV1_32A_INIT and PHP_FNV1A_64_INIT. See GH-11114. ======================== 2. Build system changes ======================== +* Removed the HAVE_DEV_URANDOM compile time check. HAVE_DEV_URANDOM will + now never be defined. Any checks relying on HAVE_DEV_URANDOM should be + removed. Even with HAVE_DEV_URANDOM it was not guaranteed that + /dev/urandom is actually available at run time and thus a runtime + check needs to happen in all cases. + ======================== 3. Module changes ======================== @@ -28,6 +85,37 @@ PHP 8.3 INTERNALS UPGRADE NOTES a. ext/json - A new function php_json_validate_ex has been added to check if the provided C string is valid for the given depth and options. + + b. ext/standard + - The PHPAPI php_url_encode_hash_ex() function has had its signature change + from: + PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, + const char *num_prefix, size_t num_prefix_len, + const char *key_prefix, size_t key_prefix_len, + const char *key_suffix, size_t key_suffix_len, + zval *type, const char *arg_sep, int enc_type); + to: + PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, + const char *num_prefix, size_t num_prefix_len, + const zend_string *key_prefix, + zval *type, const zend_string *arg_sep, int enc_type); + The change to use zend_string prevent the computation of the arg_sep + length at each call. The key_suffix parameter was dropped as it was a + constant value and depended on the key_prefix parameter to not be NULL. + + c. ext/mysqlnd + - The function mysqlnd_shutdown and its corresponding internal methods + mysqlnd_command::shutdown & mysqlnd_conn_data::shutdown have been removed. + These functions are deprecated by MySQL in favour of SHUTDOWN SQL statement. + + d. ext/pcre + - The function pcre_get_compiled_regex_ex has been removed. + Use pcre_get_compiled_regex instead. + + e. ext/spl + - The PHPAPI spl_iterator_apply() function now returns zend_result instead of int. + There are no functional changes. + ======================== 4. OpCode changes ======================== @@ -35,3 +123,6 @@ PHP 8.3 INTERNALS UPGRADE NOTES ======================== 5. SAPI changes ======================== + +* SAPIs that may execute in alternative stacks have to set EG(stack_limit) and + EG(stack_base) diff --git a/Zend/Makefile.frag b/Zend/Makefile.frag index 1e0dc92803da8..054a63bf60af5 100644 --- a/Zend/Makefile.frag +++ b/Zend/Makefile.frag @@ -5,7 +5,7 @@ $(builddir)/zend_language_scanner.lo: $(srcdir)/zend_language_parser.h $(builddir)/zend_ini_scanner.lo: $(srcdir)/zend_ini_parser.h -$(srcdir)/zend_language_scanner.c: $(srcdir)/zend_language_scanner.l +$(srcdir)/zend_language_scanner.c $(srcdir)/zend_language_scanner_defs.h: $(srcdir)/zend_language_scanner.l @(cd $(top_srcdir); $(RE2C) $(RE2C_FLAGS) --no-generation-date --case-inverted -cbdFt Zend/zend_language_scanner_defs.h -oZend/zend_language_scanner.c Zend/zend_language_scanner.l) $(srcdir)/zend_language_parser.h: $(srcdir)/zend_language_parser.c diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c index b176ba2704e26..22dd3c7f7b6e1 100644 --- a/Zend/Optimizer/block_pass.c +++ b/Zend/Optimizer/block_pass.c @@ -256,6 +256,13 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array } break; + case ZEND_MATCH_ERROR: + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + src = VAR_SOURCE(opline->op1); + VAR_SOURCE(opline->op1) = NULL; + } + break; + case ZEND_FREE: if (opline->op1_type == IS_TMP_VAR) { src = VAR_SOURCE(opline->op1); @@ -512,7 +519,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array break; case ZEND_IS_SMALLER: if (opline->opcode == ZEND_BOOL_NOT) { - zend_uchar tmp_type; + uint8_t tmp_type; uint32_t tmp; src->opcode = ZEND_IS_SMALLER_OR_EQUAL; @@ -530,7 +537,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array break; case ZEND_IS_SMALLER_OR_EQUAL: if (opline->opcode == ZEND_BOOL_NOT) { - zend_uchar tmp_type; + uint8_t tmp_type; uint32_t tmp; src->opcode = ZEND_IS_SMALLER; @@ -624,13 +631,13 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array case ZEND_JMPNZ_EX: while (1) { if (opline->op1_type == IS_CONST) { - if (zend_is_true(&ZEND_OP1_LITERAL(opline)) == - (opline->opcode == ZEND_JMPZ_EX)) { + bool is_jmpz_ex = opline->opcode == ZEND_JMPZ_EX; + if (zend_is_true(&ZEND_OP1_LITERAL(opline)) == is_jmpz_ex) { ++(*opt_count); opline->opcode = ZEND_QM_ASSIGN; zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline)); - ZVAL_BOOL(&ZEND_OP1_LITERAL(opline), opline->opcode == ZEND_JMPZ_EX); + ZVAL_BOOL(&ZEND_OP1_LITERAL(opline), is_jmpz_ex); opline->op2.num = 0; block->successors_count = 1; block->successors[0] = block->successors[1]; diff --git a/Zend/Optimizer/compact_literals.c b/Zend/Optimizer/compact_literals.c index 8b571c6d848a2..9248f0b822441 100644 --- a/Zend/Optimizer/compact_literals.c +++ b/Zend/Optimizer/compact_literals.c @@ -211,7 +211,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx if (opline->op1_type == IS_CONST) { LITERAL_INFO(opline->op1.constant, 2); } - LITERAL_INFO(opline->op2.constant, 1); + if (opline->op2_type == IS_CONST) { + LITERAL_INFO(opline->op2.constant, 1); + } break; case ZEND_ASSIGN_STATIC_PROP: case ZEND_ASSIGN_STATIC_PROP_REF: @@ -668,7 +670,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx } break; case ZEND_FETCH_CLASS_CONSTANT: - if (opline->op1_type == IS_CONST) { + if (opline->op1_type == IS_CONST + && opline->op2_type == IS_CONST + && Z_TYPE(op_array->literals[opline->op2.constant]) == IS_STRING) { // op1/op2 class_const opline->extended_value = add_static_slot(&hash, op_array, opline->op1.constant, diff --git a/Zend/Optimizer/dce.c b/Zend/Optimizer/dce.c index 4aca34c943ca7..15c9cf5e6e22a 100644 --- a/Zend/Optimizer/dce.c +++ b/Zend/Optimizer/dce.c @@ -413,7 +413,7 @@ static inline bool is_free_of_live_var(context *ctx, zend_op *opline, zend_ssa_o static bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) { zend_ssa *ssa = ctx->ssa; int free_var = -1; - zend_uchar free_var_type; + uint8_t free_var_type; if (opline->opcode == ZEND_NOP) { return 0; diff --git a/Zend/Optimizer/dfa_pass.c b/Zend/Optimizer/dfa_pass.c index 970557daf9a22..3ed507c35b070 100644 --- a/Zend/Optimizer/dfa_pass.c +++ b/Zend/Optimizer/dfa_pass.c @@ -847,7 +847,7 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa) goto optimize_jmpz; } else if (opline->op1_type == IS_CONST) { if (zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) { - opline->opcode = ZEND_QM_ASSIGN; + opline->opcode = ZEND_BOOL; take_successor_1(ssa, block_num, block); } } @@ -861,7 +861,7 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa) goto optimize_jmpnz; } else if (opline->op1_type == IS_CONST) { if (!zend_is_true(CT_CONSTANT_EX(op_array, opline->op1.constant))) { - opline->opcode = ZEND_QM_ASSIGN; + opline->opcode = ZEND_BOOL; take_successor_1(ssa, block_num, block); } } @@ -932,38 +932,47 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa) case ZEND_MATCH: if (opline->op1_type == IS_CONST) { zval *zv = CT_CONSTANT_EX(op_array, opline->op1.constant); - zend_uchar type = Z_TYPE_P(zv); + uint8_t type = Z_TYPE_P(zv); bool correct_type = (opline->opcode == ZEND_SWITCH_LONG && type == IS_LONG) || (opline->opcode == ZEND_SWITCH_STRING && type == IS_STRING) || (opline->opcode == ZEND_MATCH && (type == IS_LONG || type == IS_STRING)); - if (!correct_type) { + /* Switch statements have a fallback chain for loose comparison. In those + * cases the SWITCH_* instruction is a NOP. Match does strict comparison and + * thus jumps to the default branch on mismatched types, so we need to + * convert MATCH to a jmp. */ + if (!correct_type && opline->opcode != ZEND_MATCH) { removed_ops++; MAKE_NOP(opline); opline->extended_value = 0; take_successor_ex(ssa, block_num, block, block->successors[block->successors_count - 1]); goto optimize_nop; - } else { + } + + uint32_t target; + if (correct_type) { HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant)); zval *jmp_zv = type == IS_LONG ? zend_hash_index_find(jmptable, Z_LVAL_P(zv)) : zend_hash_find(jmptable, Z_STR_P(zv)); - uint32_t target; if (jmp_zv) { target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv)); } else { target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value); } - opline->opcode = ZEND_JMP; - opline->extended_value = 0; - SET_UNUSED(opline->op1); - ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + target); - SET_UNUSED(opline->op2); - take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]); - goto optimize_jmp; + } else { + ZEND_ASSERT(opline->opcode == ZEND_MATCH); + target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value); } + opline->opcode = ZEND_JMP; + opline->extended_value = 0; + SET_UNUSED(opline->op1); + ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + target); + SET_UNUSED(opline->op2); + take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]); + goto optimize_jmp; } break; case ZEND_NOP: @@ -1647,7 +1656,7 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx && Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) == IS_LONG && Z_LVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) == 1 && ssa->ops[op_1].op1_use >= 0 - && !(ssa->var_info[ssa->ops[op_1].op1_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { + && !(ssa->var_info[ssa->ops[op_1].op1_use].type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { // op_1: ASSIGN_SUB #?.CV [undef,null,int,foat] -> #v.CV, int(1) => PRE_DEC #?.CV ->#v.CV diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c index 9373ad2adc63d..f6144f87b4fac 100644 --- a/Zend/Optimizer/sccp.c +++ b/Zend/Optimizer/sccp.c @@ -83,10 +83,10 @@ typedef struct _sccp_ctx { zval bot; } sccp_ctx; -#define TOP ((zend_uchar)-1) -#define BOT ((zend_uchar)-2) -#define PARTIAL_ARRAY ((zend_uchar)-3) -#define PARTIAL_OBJECT ((zend_uchar)-4) +#define TOP ((uint8_t)-1) +#define BOT ((uint8_t)-2) +#define PARTIAL_ARRAY ((uint8_t)-3) +#define PARTIAL_OBJECT ((uint8_t)-4) #define IS_TOP(zv) (Z_TYPE_P(zv) == TOP) #define IS_BOT(zv) (Z_TYPE_P(zv) == BOT) #define IS_PARTIAL_ARRAY(zv) (Z_TYPE_P(zv) == PARTIAL_ARRAY) @@ -122,7 +122,7 @@ static void empty_partial_array(zval *zv) Z_ARR_P(zv) = zend_new_array(8); } -static void dup_partial_array(zval *dst, zval *src) +static void dup_partial_array(zval *dst, const zval *src) { MAKE_PARTIAL_ARRAY(dst); Z_ARR_P(dst) = zend_array_dup(Z_ARR_P(src)); @@ -134,7 +134,7 @@ static void empty_partial_object(zval *zv) Z_ARR_P(zv) = zend_new_array(8); } -static void dup_partial_object(zval *dst, zval *src) +static void dup_partial_object(zval *dst, const zval *src) { MAKE_PARTIAL_OBJECT(dst); Z_ARR_P(dst) = zend_array_dup(Z_ARR_P(src)); @@ -146,7 +146,7 @@ static inline bool value_known(zval *zv) { /* Sets new value for variable and ensures that it is lower or equal * the previous one in the constant propagation lattice. */ -static void set_value(scdf_ctx *scdf, sccp_ctx *ctx, int var, zval *new) { +static void set_value(scdf_ctx *scdf, sccp_ctx *ctx, int var, const zval *new) { zval *value = &ctx->values[var]; if (IS_BOT(value) || IS_TOP(new)) { return; @@ -186,7 +186,7 @@ static void set_value(scdf_ctx *scdf, sccp_ctx *ctx, int var, zval *new) { #endif } -static zval *get_op1_value(sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op) { +static zval *get_op1_value(sccp_ctx *ctx, zend_op *opline, const zend_ssa_op *ssa_op) { if (opline->op1_type == IS_CONST) { return CT_CONSTANT_EX(ctx->scdf.op_array, opline->op1.constant); } else if (ssa_op->op1_use != -1) { @@ -196,7 +196,7 @@ static zval *get_op1_value(sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op) } } -static zval *get_op2_value(sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op) { +static zval *get_op2_value(sccp_ctx *ctx, const zend_op *opline, const zend_ssa_op *ssa_op) { if (opline->op2_type == IS_CONST) { return CT_CONSTANT_EX(ctx->scdf.op_array, opline->op2.constant); } else if (ssa_op->op2_use != -1) { @@ -207,7 +207,7 @@ static zval *get_op2_value(sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op) } static bool can_replace_op1( - const zend_op_array *op_array, zend_op *opline, zend_ssa_op *ssa_op) { + const zend_op_array *op_array, const zend_op *opline, const zend_ssa_op *ssa_op) { switch (opline->opcode) { case ZEND_PRE_INC: case ZEND_PRE_DEC: @@ -314,7 +314,7 @@ static bool try_replace_op2( return 0; } -static inline zend_result ct_eval_binary_op(zval *result, zend_uchar binop, zval *op1, zval *op2) { +static inline zend_result ct_eval_binary_op(zval *result, uint8_t binop, zval *op1, zval *op2) { /* TODO: We could implement support for evaluation of + on partial arrays. */ if (IS_PARTIAL_ARRAY(op1) || IS_PARTIAL_ARRAY(op2)) { return FAILURE; @@ -441,7 +441,7 @@ static inline zend_result ct_eval_isset_dim(zval *result, uint32_t extended_valu } } -static inline zend_result ct_eval_del_array_elem(zval *result, zval *key) { +static inline zend_result ct_eval_del_array_elem(zval *result, const zval *key) { ZEND_ASSERT(IS_PARTIAL_ARRAY(result)); switch (Z_TYPE_P(key)) { @@ -475,7 +475,7 @@ static inline zend_result ct_eval_del_array_elem(zval *result, zval *key) { return SUCCESS; } -static inline zend_result ct_eval_add_array_elem(zval *result, zval *value, zval *key) { +static inline zend_result ct_eval_add_array_elem(zval *result, zval *value, const zval *key) { if (!key) { SEPARATE_ARRAY(result); if ((value = zend_hash_next_index_insert(Z_ARR_P(result), value))) { @@ -546,7 +546,7 @@ static inline zend_result ct_eval_add_array_unpack(zval *result, zval *array) { return SUCCESS; } -static inline zend_result ct_eval_assign_dim(zval *result, zval *value, zval *key) { +static inline zend_result ct_eval_assign_dim(zval *result, zval *value, const zval *key) { switch (Z_TYPE_P(result)) { case IS_NULL: case IS_FALSE: @@ -622,7 +622,7 @@ static inline zend_result ct_eval_isset_obj(zval *result, uint32_t extended_valu } } -static inline zend_result ct_eval_del_obj_prop(zval *result, zval *key) { +static inline zend_result ct_eval_del_obj_prop(zval *result, const zval *key) { ZEND_ASSERT(IS_PARTIAL_OBJECT(result)); switch (Z_TYPE_P(key)) { @@ -636,7 +636,7 @@ static inline zend_result ct_eval_del_obj_prop(zval *result, zval *key) { return SUCCESS; } -static inline zend_result ct_eval_add_obj_prop(zval *result, zval *value, zval *key) { +static inline zend_result ct_eval_add_obj_prop(zval *result, zval *value, const zval *key) { switch (Z_TYPE_P(key)) { case IS_STRING: value = zend_symtable_update(Z_ARR_P(result), Z_STR_P(key), value); @@ -649,7 +649,7 @@ static inline zend_result ct_eval_add_obj_prop(zval *result, zval *value, zval * return SUCCESS; } -static inline zend_result ct_eval_assign_obj(zval *result, zval *value, zval *key) { +static inline zend_result ct_eval_assign_obj(zval *result, zval *value, const zval *key) { switch (Z_TYPE_P(result)) { case IS_NULL: case IS_FALSE: @@ -662,7 +662,7 @@ static inline zend_result ct_eval_assign_obj(zval *result, zval *value, zval *ke } } -static inline zend_result ct_eval_incdec(zval *result, zend_uchar opcode, zval *op1) { +static inline zend_result ct_eval_incdec(zval *result, uint8_t opcode, zval *op1) { if (Z_TYPE_P(op1) == IS_ARRAY || IS_PARTIAL_ARRAY(op1)) { return FAILURE; } @@ -1646,8 +1646,9 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o break; } - /* We're only interested in functions with up to three arguments right now */ - if (call->num_args > 3 || call->send_unpack || call->is_prototype) { + /* We're only interested in functions with up to three arguments right now. + * Note that named arguments with the argument in declaration order will still work. */ + if (call->num_args > 3 || call->send_unpack || call->is_prototype || call->named_args) { SET_RESULT_BOT(result); break; } @@ -1843,7 +1844,7 @@ static void sccp_mark_feasible_successors( case ZEND_MATCH: { bool strict_comparison = opline->opcode == ZEND_MATCH; - zend_uchar type = Z_TYPE_P(op1); + uint8_t type = Z_TYPE_P(op1); bool correct_type = (opline->opcode == ZEND_SWITCH_LONG && type == IS_LONG) || (opline->opcode == ZEND_SWITCH_STRING && type == IS_STRING) @@ -2134,7 +2135,7 @@ static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var, && opline->opcode != ZEND_ADD_ARRAY_ELEMENT && opline->opcode != ZEND_ADD_ARRAY_UNPACK) { /* Replace with QM_ASSIGN */ - zend_uchar old_type = opline->result_type; + uint8_t old_type = opline->result_type; uint32_t old_var = opline->result.var; ssa_op->result_def = -1; diff --git a/Zend/Optimizer/scdf.h b/Zend/Optimizer/scdf.h index 840a99065bcb0..0d90147e84cb1 100644 --- a/Zend/Optimizer/scdf.h +++ b/Zend/Optimizer/scdf.h @@ -53,8 +53,8 @@ uint32_t scdf_remove_unreachable_blocks(scdf_ctx *scdf); /* Add uses to worklist */ static inline void scdf_add_to_worklist(scdf_ctx *scdf, int var_num) { - zend_ssa *ssa = scdf->ssa; - zend_ssa_var *var = &ssa->vars[var_num]; + const zend_ssa *ssa = scdf->ssa; + const zend_ssa_var *var = &ssa->vars[var_num]; int use; zend_ssa_phi *phi; FOREACH_USE(var, use) { @@ -67,7 +67,7 @@ static inline void scdf_add_to_worklist(scdf_ctx *scdf, int var_num) { /* This should usually not be necessary, however it's used for type narrowing. */ static inline void scdf_add_def_to_worklist(scdf_ctx *scdf, int var_num) { - zend_ssa_var *var = &scdf->ssa->vars[var_num]; + const zend_ssa_var *var = &scdf->ssa->vars[var_num]; if (var->definition >= 0) { zend_bitset_incl(scdf->instr_worklist, var->definition); } else if (var->definition_phi) { @@ -75,8 +75,8 @@ static inline void scdf_add_def_to_worklist(scdf_ctx *scdf, int var_num) { } } -static inline uint32_t scdf_edge(zend_cfg *cfg, int from, int to) { - zend_basic_block *to_block = cfg->blocks + to; +static inline uint32_t scdf_edge(const zend_cfg *cfg, int from, int to) { + const zend_basic_block *to_block = cfg->blocks + to; int i; for (i = 0; i < to_block->predecessors_count; i++) { @@ -89,7 +89,7 @@ static inline uint32_t scdf_edge(zend_cfg *cfg, int from, int to) { ZEND_UNREACHABLE(); } -static inline bool scdf_is_edge_feasible(scdf_ctx *scdf, int from, int to) { +static inline bool scdf_is_edge_feasible(const scdf_ctx *scdf, int from, int to) { uint32_t edge = scdf_edge(&scdf->ssa->cfg, from, to); return zend_bitset_in(scdf->feasible_edges, edge); } diff --git a/Zend/Optimizer/ssa_integrity.c b/Zend/Optimizer/ssa_integrity.c index 779edd2934843..69c6e6e901a72 100644 --- a/Zend/Optimizer/ssa_integrity.c +++ b/Zend/Optimizer/ssa_integrity.c @@ -85,7 +85,7 @@ static inline bool is_in_successors(zend_basic_block *block, int check) { return 0; } -static inline bool is_var_type(zend_uchar type) { +static inline bool is_var_type(uint8_t type) { return (type & (IS_CV|IS_VAR|IS_TMP_VAR)) != 0; } diff --git a/Zend/Optimizer/zend_call_graph.h b/Zend/Optimizer/zend_call_graph.h index 5b1634d561dc3..3a02425084d58 100644 --- a/Zend/Optimizer/zend_call_graph.h +++ b/Zend/Optimizer/zend_call_graph.h @@ -38,7 +38,7 @@ struct _zend_call_info { bool send_unpack; /* Parameters passed by SEND_UNPACK or SEND_ARRAY */ bool named_args; /* Function has named arguments */ bool is_prototype; /* An overridden child method may be called */ - int num_args; + int num_args; /* Number of arguments, excluding named and variadic arguments */ zend_send_arg_info arg_info[1]; }; diff --git a/Zend/Optimizer/zend_cfg.c b/Zend/Optimizer/zend_cfg.c index 6d538f71316cc..219738e6f692b 100644 --- a/Zend/Optimizer/zend_cfg.c +++ b/Zend/Optimizer/zend_cfg.c @@ -41,7 +41,7 @@ static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_bloc zend_basic_block *succ = blocks + b->successors[i]; if (b->len != 0) { - zend_uchar opcode = opcodes[b->start + b->len - 1].opcode; + uint8_t opcode = opcodes[b->start + b->len - 1].opcode; if (opcode == ZEND_MATCH) { succ->flags |= ZEND_BB_TARGET; } else if (opcode == ZEND_SWITCH_LONG || opcode == ZEND_SWITCH_STRING) { diff --git a/Zend/Optimizer/zend_dump.c b/Zend/Optimizer/zend_dump.c index 41146bdad97ec..bc697ba8ba9e5 100644 --- a/Zend/Optimizer/zend_dump.c +++ b/Zend/Optimizer/zend_dump.c @@ -132,7 +132,7 @@ static void zend_dump_unused_op(const zend_op *opline, znode_op op, uint32_t fla } } -ZEND_API void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_num) +ZEND_API void zend_dump_var(const zend_op_array *op_array, uint8_t var_type, int var_num) { if (var_type == IS_CV && var_num < op_array->last_var) { fprintf(stderr, "CV%d($%s)", var_num, op_array->vars[var_num]->val); @@ -348,7 +348,7 @@ static void zend_dump_ssa_var_info(const zend_ssa *ssa, int ssa_var_num, uint32_ dump_flags); } -ZEND_API void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int ssa_var_num, zend_uchar var_type, int var_num, uint32_t dump_flags) +ZEND_API void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int ssa_var_num, uint8_t var_type, int var_num, uint32_t dump_flags) { if (ssa_var_num >= 0) { fprintf(stderr, "#%d.", ssa_var_num); diff --git a/Zend/Optimizer/zend_dump.h b/Zend/Optimizer/zend_dump.h index 57f0be0f97fb7..8eba47641575b 100644 --- a/Zend/Optimizer/zend_dump.h +++ b/Zend/Optimizer/zend_dump.h @@ -22,6 +22,8 @@ #include "zend_ssa.h" #include "zend_dfg.h" +#include + #define ZEND_DUMP_HIDE_UNREACHABLE (1<<0) #define ZEND_DUMP_RC_INFERENCE (1<<1) #define ZEND_DUMP_CFG (1<<2) @@ -39,8 +41,8 @@ void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zen void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa); void zend_dump_variables(const zend_op_array *op_array); void zend_dump_ssa_variables(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t dump_flags); -ZEND_API void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int ssa_var_num, zend_uchar var_type, int var_num, uint32_t dump_flags); -ZEND_API void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_num); +ZEND_API void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int ssa_var_num, uint8_t var_type, int var_num, uint32_t dump_flags); +ZEND_API void zend_dump_var(const zend_op_array *op_array, uint8_t var_type, int var_num); void zend_dump_op_array_name(const zend_op_array *op_array); void zend_dump_const(const zval *zv); void zend_dump_ht(HashTable *ht); diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 1010c83938d27..a3475fab6cc8f 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -688,7 +688,7 @@ static const func_info_t func_infos[] = { F1("var_export", MAY_BE_STRING|MAY_BE_NULL), F1("serialize", MAY_BE_STRING), F1("xml_error_string", MAY_BE_STRING|MAY_BE_NULL), - F1("xml_parser_get_option", MAY_BE_STRING|MAY_BE_LONG), + F1("xml_parser_get_option", MAY_BE_STRING|MAY_BE_LONG|MAY_BE_BOOL), FN("zip_open", MAY_BE_RESOURCE|MAY_BE_LONG|MAY_BE_FALSE), FN("zip_read", MAY_BE_RESOURCE|MAY_BE_FALSE), F1("ob_gzhandler", MAY_BE_STRING|MAY_BE_FALSE), diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 257a4324c7f91..afe1c2339ed3a 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -432,7 +432,7 @@ static void zend_ssa_range_or(zend_long a, zend_long b, zend_long c, zend_long d int x = ((a < 0) ? 8 : 0) | ((b < 0) ? 4 : 0) | ((c < 0) ? 2 : 0) | - ((d < 0) ? 2 : 0); + ((d < 0) ? 1 : 0); switch (x) { case 0x0: case 0x3: @@ -480,7 +480,7 @@ static void zend_ssa_range_and(zend_long a, zend_long b, zend_long c, zend_long int x = ((a < 0) ? 8 : 0) | ((b < 0) ? 4 : 0) | ((c < 0) ? 2 : 0) | - ((d < 0) ? 2 : 0); + ((d < 0) ? 1 : 0); switch (x) { case 0x0: case 0x3: @@ -561,8 +561,8 @@ static void float_div(zend_long a, zend_long b, zend_long *r1, zend_long *r2) { } static bool zend_inference_calc_binary_op_range( - const zend_op_array *op_array, zend_ssa *ssa, - zend_op *opline, zend_ssa_op *ssa_op, zend_uchar opcode, zend_ssa_range *tmp) { + const zend_op_array *op_array, const zend_ssa *ssa, + const zend_op *opline, const zend_ssa_op *ssa_op, uint8_t opcode, zend_ssa_range *tmp) { zend_long op1_min, op2_min, op1_max, op2_max, t1, t2, t3, t4; switch (opcode) { @@ -845,14 +845,14 @@ static bool zend_inference_calc_binary_op_range( return 0; } -static bool zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp) +static bool zend_inference_calc_range(const zend_op_array *op_array, const zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp) { uint32_t line; - zend_op *opline; - zend_ssa_op *ssa_op; + const zend_op *opline; + const zend_ssa_op *ssa_op; if (ssa->vars[var].definition_phi) { - zend_ssa_phi *p = ssa->vars[var].definition_phi; + const zend_ssa_phi *p = ssa->vars[var].definition_phi; int i; tmp->underflow = 0; @@ -860,7 +860,7 @@ static bool zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *s tmp->max = ZEND_LONG_MIN; tmp->overflow = 0; if (p->pi >= 0 && p->has_range_constraint) { - zend_ssa_range_constraint *constraint = &p->constraint.range; + const zend_ssa_range_constraint *constraint = &p->constraint.range; if (constraint->negative) { int src1 = p->sources[0]; @@ -879,7 +879,7 @@ static bool zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *s case ZEND_PRE_DEC: case ZEND_POST_DEC: if (!tmp->underflow) { - zend_ssa_phi *p = ssa->vars[ssa->ops[line].op1_use].definition_phi; + const zend_ssa_phi *p = ssa->vars[ssa->ops[line].op1_use].definition_phi; if (p && p->pi < 0 && ssa->cfg.blocks[p->block].predecessors_count == 2 @@ -893,7 +893,7 @@ static bool zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *s case ZEND_PRE_INC: case ZEND_POST_INC: if (!tmp->overflow) { - zend_ssa_phi *p = ssa->vars[ssa->ops[line].op1_use].definition_phi; + const zend_ssa_phi *p = ssa->vars[ssa->ops[line].op1_use].definition_phi; if (p && p->pi < 0 && ssa->cfg.blocks[p->block].predecessors_count == 2 @@ -1026,7 +1026,7 @@ static bool zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *s return zend_inference_propagate_range(op_array, ssa, opline, ssa_op, var, tmp); } -ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp) +ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp) { tmp->underflow = 0; tmp->overflow = 0; @@ -1326,8 +1326,8 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, zend case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: if (ssa_op->result_def == var) { - zend_func_info *func_info = ZEND_FUNC_INFO(op_array); - zend_call_info *call_info; + const zend_func_info *func_info = ZEND_FUNC_INFO(op_array); + const zend_call_info *call_info; if (!func_info || !func_info->call_map) { break; } @@ -1499,7 +1499,7 @@ static bool zend_check_inner_cycles(const zend_op_array *op_array, zend_ssa *ssa } #endif -static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ssa, int *scc_var, int *next_scc_var, int scc) +static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ssa, const int *scc_var, const int *next_scc_var, int scc) { int worklist_len = zend_bitset_len(ssa->vars_count); int j, n; @@ -1881,7 +1881,7 @@ ZEND_API uint32_t ZEND_FASTCALL zend_array_type_info(const zval *zv) } -ZEND_API uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int write, int insert) +ZEND_API uint32_t zend_array_element_type(uint32_t t1, uint8_t op_type, int write, int insert) { uint32_t tmp = 0; @@ -1943,7 +1943,7 @@ ZEND_API uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int w } static uint32_t assign_dim_array_result_type( - uint32_t arr_type, uint32_t dim_type, uint32_t value_type, zend_uchar dim_op_type) { + uint32_t arr_type, uint32_t dim_type, uint32_t value_type, uint8_t dim_op_type) { uint32_t tmp = 0; /* Only add key type if we have a value type. We want to maintain the invariant that a * key type exists iff a value type exists even in dead code that may use empty types. */ @@ -1987,7 +1987,7 @@ static uint32_t assign_dim_array_result_type( } static uint32_t assign_dim_result_type( - uint32_t arr_type, uint32_t dim_type, uint32_t value_type, zend_uchar dim_op_type) { + uint32_t arr_type, uint32_t dim_type, uint32_t value_type, uint8_t dim_op_type) { uint32_t tmp = arr_type & ~(MAY_BE_RC1|MAY_BE_RCN); if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) { @@ -2008,7 +2008,7 @@ static uint32_t assign_dim_result_type( /* For binary ops that have compound assignment operators */ static uint32_t binary_op_result_type( - zend_ssa *ssa, zend_uchar opcode, uint32_t t1, uint32_t t2, int result_var, + zend_ssa *ssa, uint8_t opcode, uint32_t t1, uint32_t t2, int result_var, zend_long optimization_level) { uint32_t tmp = 0; uint32_t t1_type = (t1 & MAY_BE_ANY) | (t1 & MAY_BE_UNDEF ? MAY_BE_NULL : 0); @@ -2153,13 +2153,13 @@ static uint32_t zend_convert_type(const zend_script *script, zend_type type, zen return tmp; } -ZEND_API uint32_t zend_fetch_arg_info_type(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce) +ZEND_API uint32_t zend_fetch_arg_info_type(const zend_script *script, const zend_arg_info *arg_info, zend_class_entry **pce) { return zend_convert_type(script, arg_info->type, pce); } -static zend_property_info *lookup_prop_info(zend_class_entry *ce, zend_string *name, zend_class_entry *scope) { - zend_property_info *prop_info; +static const zend_property_info *lookup_prop_info(const zend_class_entry *ce, zend_string *name, zend_class_entry *scope) { + const zend_property_info *prop_info; /* If the class is linked, reuse the precise runtime logic. */ if ((ce->ce_flags & ZEND_ACC_LINKED) @@ -2185,11 +2185,11 @@ static zend_property_info *lookup_prop_info(zend_class_entry *ce, zend_string *n return NULL; } -static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op) +static const zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) { - zend_property_info *prop_info = NULL; + const zend_property_info *prop_info = NULL; if (opline->op2_type == IS_CONST) { - zend_class_entry *ce = NULL; + const zend_class_entry *ce = NULL; if (opline->op1_type == IS_UNUSED) { ce = op_array->scope; @@ -2208,9 +2208,9 @@ static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, z return prop_info; } -static zend_property_info *zend_fetch_static_prop_info(const zend_script *script, const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline) +static const zend_property_info *zend_fetch_static_prop_info(const zend_script *script, const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) { - zend_property_info *prop_info = NULL; + const zend_property_info *prop_info = NULL; if (opline->op1_type == IS_CONST) { zend_class_entry *ce = NULL; if (opline->op2_type == IS_UNUSED) { @@ -2244,7 +2244,7 @@ static zend_property_info *zend_fetch_static_prop_info(const zend_script *script return prop_info; } -static uint32_t zend_fetch_prop_type(const zend_script *script, zend_property_info *prop_info, zend_class_entry **pce) +static uint32_t zend_fetch_prop_type(const zend_script *script, const zend_property_info *prop_info, zend_class_entry **pce) { if (!prop_info) { if (pce) { @@ -2264,7 +2264,7 @@ static bool result_may_be_separated(zend_ssa *ssa, zend_ssa_op *ssa_op) && !ssa->vars[tmp_var].phi_use_chain) { zend_ssa_op *use_op = &ssa->ops[ssa->vars[tmp_var].use_chain]; - /* TODO: analize instructions between ssa_op and use_op */ + /* TODO: analyze instructions between ssa_op and use_op */ if (use_op == ssa_op + 1) { if ((use_op->op1_use == tmp_var && use_op->op1_use_chain < 0) || (use_op->op2_use == tmp_var && use_op->op2_use_chain < 0)) { @@ -2280,7 +2280,7 @@ static zend_always_inline zend_result _zend_update_type_info( zend_ssa *ssa, const zend_script *script, zend_bitset worklist, - zend_op *opline, + const zend_op *opline, zend_ssa_op *ssa_op, const zend_op **ssa_opcodes, zend_long optimization_level, @@ -2490,13 +2490,13 @@ static zend_always_inline zend_result _zend_update_type_info( case ZEND_ASSIGN_OBJ_OP: case ZEND_ASSIGN_STATIC_PROP_OP: { - zend_property_info *prop_info = NULL; + const zend_property_info *prop_info = NULL; orig = 0; tmp = 0; if (opline->opcode == ZEND_ASSIGN_OBJ_OP) { prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op); orig = t1; - t1 = zend_fetch_prop_type(script, prop_info, &ce); + t1 = zend_fetch_prop_type(script, prop_info, NULL); t2 = OP1_DATA_INFO(); } else if (opline->opcode == ZEND_ASSIGN_DIM_OP) { if (t1 & MAY_BE_ARRAY_OF_REF) { @@ -2507,7 +2507,7 @@ static zend_always_inline zend_result _zend_update_type_info( t2 = OP1_DATA_INFO(); } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) { prop_info = zend_fetch_static_prop_info(script, op_array, ssa, opline); - t1 = zend_fetch_prop_type(script, prop_info, &ce); + t1 = zend_fetch_prop_type(script, prop_info, NULL); t2 = OP1_DATA_INFO(); } else { if (t1 & MAY_BE_REF) { @@ -2537,7 +2537,7 @@ static zend_always_inline zend_result _zend_update_type_info( UPDATE_SSA_TYPE(orig, ssa_op->op1_def); COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } - } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP) { + } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) { /* Nothing to do */ } else { if (opline->opcode == ZEND_ASSIGN_OP && ssa_op->result_def >= 0 && (tmp & MAY_BE_RC1)) { @@ -2569,12 +2569,26 @@ static zend_always_inline zend_result _zend_update_type_info( } else if (opline->opcode == ZEND_ASSIGN_OBJ_OP) { /* The return value must also satisfy the property type */ if (prop_info) { - tmp &= zend_fetch_prop_type(script, prop_info, NULL); + t1 = zend_fetch_prop_type(script, prop_info, &ce); + if ((t1 & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_LONG + && (tmp & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_DOUBLE) { + /* DOUBLE may be auto-converted to LONG */ + tmp |= MAY_BE_LONG; + tmp &= ~MAY_BE_DOUBLE; + } + tmp &= t1; } } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) { /* The return value must also satisfy the property type */ if (prop_info) { - tmp &= zend_fetch_prop_type(script, prop_info, NULL); + t1 = zend_fetch_prop_type(script, prop_info, &ce); + if ((t1 & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_LONG + && (tmp & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_DOUBLE) { + /* DOUBLE may be auto-converted to LONG */ + tmp |= MAY_BE_LONG; + tmp &= ~MAY_BE_DOUBLE; + } + tmp &= t1; } } else { if (tmp & MAY_BE_REF) { @@ -3321,7 +3335,7 @@ static zend_always_inline zend_result _zend_update_type_info( tmp |= key_type | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_NULL; } while (j >= 0) { - zend_uchar opcode; + uint8_t opcode; if (!ssa_opcodes) { ZEND_ASSERT(j == (opline - op_array->opcodes) + 1 && "Use must be in next opline"); @@ -3454,29 +3468,28 @@ static zend_always_inline zend_result _zend_update_type_info( tmp |= MAY_BE_NULL; } if (opline->op1_type == IS_UNUSED || (t1 & MAY_BE_OBJECT)) { - zend_property_info *prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op); + const zend_property_info *prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op); tmp |= zend_fetch_prop_type(script, prop_info, &ce); if (opline->opcode != ZEND_FETCH_OBJ_R && opline->opcode != ZEND_FETCH_OBJ_IS) { tmp |= MAY_BE_REF | MAY_BE_INDIRECT; + if ((opline->extended_value & ZEND_FETCH_OBJ_FLAGS) == ZEND_FETCH_DIM_WRITE) { + tmp |= MAY_BE_UNDEF; + } ce = NULL; } else if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || !(t1 & MAY_BE_RC1)) { - zend_class_entry *ce = NULL; + const zend_class_entry *ce = NULL; if (opline->op1_type == IS_UNUSED) { ce = op_array->scope; } else if (ssa_op->op1_use >= 0 && !ssa->var_info[ssa_op->op1_use].is_instanceof) { ce = ssa->var_info[ssa_op->op1_use].ce; } - if (prop_info) { - /* FETCH_OBJ_R/IS for plain property increments reference counter, - so it can't be 1 */ - if (ce && !ce->create_object && !result_may_be_separated(ssa, ssa_op)) { - tmp &= ~MAY_BE_RC1; - } - } else { - if (ce && !ce->create_object && !ce->__get && !result_may_be_separated(ssa, ssa_op)) { - tmp &= ~MAY_BE_RC1; - } + /* Unset properties will resort back to __get/__set */ + if (ce + && !ce->create_object + && !ce->__get + && !result_may_be_separated(ssa, ssa_op)) { + tmp &= ~MAY_BE_RC1; } if (opline->opcode == ZEND_FETCH_OBJ_IS) { /* IS check may return null for uninitialized typed property. */ @@ -3501,6 +3514,9 @@ static zend_always_inline zend_result _zend_update_type_info( if (opline->opcode != ZEND_FETCH_STATIC_PROP_R && opline->opcode != ZEND_FETCH_STATIC_PROP_IS) { tmp |= MAY_BE_REF | MAY_BE_INDIRECT; + if ((opline->extended_value & ZEND_FETCH_OBJ_FLAGS) == ZEND_FETCH_DIM_WRITE) { + tmp |= MAY_BE_UNDEF; + } ce = NULL; } else { if (!result_may_be_separated(ssa, ssa_op)) { @@ -3964,7 +3980,7 @@ static bool can_convert_to_double( return 0; } } else { - zend_uchar opcode = opline->opcode; + uint8_t opcode = opline->opcode; if (opcode == ZEND_ASSIGN_OP) { opcode = opline->extended_value; @@ -4487,7 +4503,7 @@ ZEND_API zend_result zend_ssa_inference(zend_arena **arena, const zend_op_array } /* }}} */ -ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, uint32_t t1, uint32_t t2) +ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa, uint32_t t1, uint32_t t2) { if (opline->op1_type == IS_CV) { if (t1 & MAY_BE_UNDEF) { @@ -4765,8 +4781,8 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op } } if (ssa_op->op1_use) { - zend_ssa_var_info *var_info = ssa->var_info + ssa_op->op1_use; - zend_class_entry *ce = var_info->ce; + const zend_ssa_var_info *var_info = ssa->var_info + ssa_op->op1_use; + const zend_class_entry *ce = var_info->ce; if (var_info->is_instanceof || !ce || ce->create_object || ce->__get || ce->__set || ce->parent) { @@ -4813,7 +4829,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op } if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { uint32_t arg_num = opline->op1.num; - zend_arg_info *cur_arg_info; + const zend_arg_info *cur_arg_info; if (EXPECTED(arg_num <= op_array->num_args)) { cur_arg_info = &op_array->arg_info[arg_num-1]; @@ -4889,7 +4905,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op } } -ZEND_API bool zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa) +ZEND_API bool zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa) { return zend_may_throw_ex(opline, ssa_op, op_array, ssa, OP1_INFO(), OP2_INFO()); } diff --git a/Zend/Optimizer/zend_inference.h b/Zend/Optimizer/zend_inference.h index 42dcd50920a5e..4e768c4f6d524 100644 --- a/Zend/Optimizer/zend_inference.h +++ b/Zend/Optimizer/zend_inference.h @@ -26,6 +26,8 @@ /* Bitmask for type inference (zend_ssa_var_info.type) */ #include "zend_type_info.h" +#include + #define MAY_BE_PACKED_GUARD (1<<27) /* needs packed array guard */ #define MAY_BE_CLASS_GUARD (1<<27) /* needs class guard */ #define MAY_BE_GUARD (1<<28) /* needs type guard */ @@ -218,22 +220,22 @@ BEGIN_EXTERN_C() ZEND_API void zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa); ZEND_API void zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa); -ZEND_API int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level); +ZEND_API zend_result zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level); -ZEND_API uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int write, int insert); +ZEND_API uint32_t zend_array_element_type(uint32_t t1, uint8_t op_type, int write, int insert); -ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp); +ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp); ZEND_API uint32_t zend_fetch_arg_info_type( - const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce); + const zend_script *script, const zend_arg_info *arg_info, zend_class_entry **pce); ZEND_API void zend_init_func_return_info( const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret); uint32_t zend_get_return_info_from_signature_only( const zend_function *func, const zend_script *script, zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info); -ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, uint32_t t1, uint32_t t2); -ZEND_API bool zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa); +ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa, uint32_t t1, uint32_t t2); +ZEND_API bool zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa); ZEND_API zend_result zend_update_type_info( const zend_op_array *op_array, zend_ssa *ssa, const zend_script *script, diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c index b5841159bf12c..956a13d658399 100644 --- a/Zend/Optimizer/zend_optimizer.c +++ b/Zend/Optimizer/zend_optimizer.c @@ -54,7 +54,7 @@ void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* } } -zend_result zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zval *op2) /* {{{ */ +zend_result zend_optimizer_eval_binary_op(zval *result, uint8_t opcode, zval *op1, zval *op2) /* {{{ */ { if (zend_binary_op_produces_error(opcode, op1, op2)) { return FAILURE; @@ -65,7 +65,7 @@ zend_result zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval } /* }}} */ -zend_result zend_optimizer_eval_unary_op(zval *result, zend_uchar opcode, zval *op1) /* {{{ */ +zend_result zend_optimizer_eval_unary_op(zval *result, uint8_t opcode, zval *op1) /* {{{ */ { unary_op_type unary_op = get_unary_op(opcode); @@ -113,7 +113,7 @@ zend_result zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1) /* } /* }}} */ -zend_result zend_optimizer_eval_strlen(zval *result, zval *op1) /* {{{ */ +zend_result zend_optimizer_eval_strlen(zval *result, const zval *op1) /* {{{ */ { if (Z_TYPE_P(op1) != IS_STRING) { return FAILURE; @@ -231,7 +231,7 @@ void zend_optimizer_convert_to_free_op1(zend_op_array *op_array, zend_op *opline } } -int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv) +int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv) { int i = op_array->last_literal; op_array->last_literal++; @@ -620,7 +620,7 @@ bool zend_optimizer_update_op2_const(zend_op_array *op_array, bool zend_optimizer_replace_by_const(zend_op_array *op_array, zend_op *opline, - zend_uchar type, + uint8_t type, uint32_t var, zval *val) { @@ -891,16 +891,19 @@ zend_function *zend_optimizer_get_called_func( &op_array->scope->function_table, method_name); if (fbc) { bool is_private = (fbc->common.fn_flags & ZEND_ACC_PRIVATE) != 0; - bool is_final = (fbc->common.fn_flags & ZEND_ACC_FINAL) != 0; - bool same_scope = fbc->common.scope == op_array->scope; if (is_private) { /* Only use private method if in the same scope. We can't even use it * as a prototype, as it may be overridden with changed signature. */ + bool same_scope = fbc->common.scope == op_array->scope; return same_scope ? fbc : NULL; } - /* If the method is non-final, it may be overridden, - * but only with a compatible method signature. */ - *is_prototype = !is_final; + /* Prototype methods are potentially overridden. fbc still contains useful type information. + * Some optimizations may not be applied, like inlining or inferring the send-mode of superfluous args. + * A method cannot be overridden if the class or method is final. */ + if ((fbc->common.fn_flags & ZEND_ACC_FINAL) == 0 && + (fbc->common.scope->ce_flags & ZEND_ACC_FINAL) == 0) { + *is_prototype = true; + } return fbc; } } @@ -1416,8 +1419,7 @@ static void zend_foreach_op_array_helper( void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void *context) { - zend_class_entry *ce; - zend_string *key; + zval *zv; zend_op_array *op_array; zend_foreach_op_array_helper(&script->main_op_array, func, context); @@ -1426,10 +1428,11 @@ void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void zend_foreach_op_array_helper(op_array, func, context); } ZEND_HASH_FOREACH_END(); - ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) { - if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) { + ZEND_HASH_MAP_FOREACH_VAL(&script->class_table, zv) { + if (Z_TYPE_P(zv) == IS_ALIAS_PTR) { continue; } + zend_class_entry *ce = Z_CE_P(zv); ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) { if (op_array->scope == ce && op_array->type == ZEND_USER_FUNCTION @@ -1465,11 +1468,10 @@ static void zend_optimizer_call_registered_passes(zend_script *script, void *ctx ZEND_API void zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level) { - zend_class_entry *ce; - zend_string *key; zend_op_array *op_array; zend_string *name; zend_optimizer_ctx ctx; + zval *zv; ctx.arena = zend_arena_create(64 * 1024); ctx.script = script; @@ -1596,10 +1598,11 @@ ZEND_API void zend_optimize_script(zend_script *script, zend_long optimization_l } } - ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) { - if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) { + ZEND_HASH_MAP_FOREACH_VAL(&script->class_table, zv) { + if (Z_TYPE_P(zv) == IS_ALIAS_PTR) { continue; } + zend_class_entry *ce = Z_CE_P(zv); ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) { if (op_array->scope != ce && op_array->type == ZEND_USER_FUNCTION) { zend_op_array *orig_op_array = diff --git a/Zend/Optimizer/zend_optimizer_internal.h b/Zend/Optimizer/zend_optimizer_internal.h index 92410c18bf86b..2f708471ab1d5 100644 --- a/Zend/Optimizer/zend_optimizer_internal.h +++ b/Zend/Optimizer/zend_optimizer_internal.h @@ -25,6 +25,8 @@ #include "zend_ssa.h" #include "zend_func_info.h" +#include + #define ZEND_OP1_LITERAL(opline) (op_array)->literals[(opline)->op1.constant] #define ZEND_OP1_JMP_ADDR(opline) OP_JMP_ADDR(opline, (opline)->op1) #define ZEND_OP2_LITERAL(opline) (op_array)->literals[(opline)->op2.constant] @@ -77,14 +79,14 @@ static inline bool zend_optimizer_is_loop_var_free(const zend_op *opline) { } void zend_optimizer_convert_to_free_op1(zend_op_array *op_array, zend_op *opline); -int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv); +int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv); bool zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy); void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value); bool zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value); -zend_result zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zval *op2); -zend_result zend_optimizer_eval_unary_op(zval *result, zend_uchar opcode, zval *op1); +zend_result zend_optimizer_eval_binary_op(zval *result, uint8_t opcode, zval *op1, zval *op2); +zend_result zend_optimizer_eval_unary_op(zval *result, uint8_t opcode, zval *op1); zend_result zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1); -zend_result zend_optimizer_eval_strlen(zval *result, zval *op1); +zend_result zend_optimizer_eval_strlen(zval *result, const zval *op1); zend_result zend_optimizer_eval_special_func_call( zval *result, zend_string *name, zend_string *arg); bool zend_optimizer_update_op1_const(zend_op_array *op_array, @@ -95,7 +97,7 @@ bool zend_optimizer_update_op2_const(zend_op_array *op_array, zval *val); bool zend_optimizer_replace_by_const(zend_op_array *op_array, zend_op *opline, - zend_uchar type, + uint8_t type, uint32_t var, zval *val); zend_op *zend_optimizer_get_loop_var_def(const zend_op_array *op_array, zend_op *free_opline); diff --git a/Zend/Optimizer/zend_ssa.c b/Zend/Optimizer/zend_ssa.c index d6d0e70eae8a5..67165a9b26d7a 100644 --- a/Zend/Optimizer/zend_ssa.c +++ b/Zend/Optimizer/zend_ssa.c @@ -57,9 +57,9 @@ static bool will_rejoin( return 0; } -static bool needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa, int from, int to, int var) /* {{{ */ +static bool needs_pi(const zend_op_array *op_array, const zend_dfg *dfg, const zend_ssa *ssa, int from, int to, int var) /* {{{ */ { - zend_basic_block *from_block, *to_block; + const zend_basic_block *from_block, *to_block; int other_successor; if (!DFG_ISSET(dfg->in, dfg->size, to, var)) { diff --git a/Zend/Optimizer/zend_ssa.h b/Zend/Optimizer/zend_ssa.h index 9fde352c79cc1..5a6fce38d2f81 100644 --- a/Zend/Optimizer/zend_ssa.h +++ b/Zend/Optimizer/zend_ssa.h @@ -109,8 +109,8 @@ typedef struct _zend_ssa_var { int var; /* original var number; op.var for CVs and following numbers for VARs and TMP_VARs */ int scc; /* strongly connected component */ int definition; /* opcode that defines this value */ - zend_ssa_phi *definition_phi; /* phi that defines this value */ int use_chain; /* uses of this value, linked through opN_use_chain */ + zend_ssa_phi *definition_phi; /* phi that defines this value */ zend_ssa_phi *phi_use_chain; /* uses of this value in Phi, linked through use_chain */ zend_ssa_phi *sym_use_chain; /* uses of this value in Pi constraints */ unsigned int no_val : 1; /* value doesn't matter (used as op1 in ZEND_ASSIGN) */ @@ -121,16 +121,16 @@ typedef struct _zend_ssa_var { typedef struct _zend_ssa_var_info { uint32_t type; /* inferred type (see zend_inference.h) */ + bool has_range : 1; + bool is_instanceof : 1; /* 0 - class == "ce", 1 - may be child of "ce" */ + bool recursive : 1; + bool use_as_double : 1; + bool delayed_fetch_this : 1; + bool avoid_refcounting : 1; + bool guarded_reference : 1; + bool indirect_reference : 1; /* IS_INDIRECT returned by FETCH_DIM_W/FETCH_OBJ_W */ zend_ssa_range range; zend_class_entry *ce; - unsigned int has_range : 1; - unsigned int is_instanceof : 1; /* 0 - class == "ce", 1 - may be child of "ce" */ - unsigned int recursive : 1; - unsigned int use_as_double : 1; - unsigned int delayed_fetch_this : 1; - unsigned int avoid_refcounting : 1; - unsigned int guarded_reference : 1; - unsigned int indirect_reference : 1; /* IS_INDIRECT returned by FETCH_DIM_W/FETCH_OBJ_W */ } zend_ssa_var_info; typedef struct _zend_ssa { diff --git a/Zend/Optimizer/zend_worklist.h b/Zend/Optimizer/zend_worklist.h index 69cc41c437af7..f47d01bd1579b 100644 --- a/Zend/Optimizer/zend_worklist.h +++ b/Zend/Optimizer/zend_worklist.h @@ -52,7 +52,7 @@ static inline void zend_worklist_stack_push(zend_worklist_stack *stack, int i) stack->buf[stack->len++] = i; } -static inline int zend_worklist_stack_peek(zend_worklist_stack *stack) +static inline int zend_worklist_stack_peek(const zend_worklist_stack *stack) { ZEND_ASSERT(stack->len); return stack->buf[stack->len - 1]; @@ -87,7 +87,7 @@ static inline void zend_worklist_prepare(zend_arena **arena, zend_worklist *work zend_worklist_stack_prepare(arena, &worklist->stack, len); } -static inline int zend_worklist_len(zend_worklist *worklist) +static inline int zend_worklist_len(const zend_worklist *worklist) { return worklist->stack.len; } @@ -105,7 +105,7 @@ static inline bool zend_worklist_push(zend_worklist *worklist, int i) return 1; } -static inline int zend_worklist_peek(zend_worklist *worklist) +static inline int zend_worklist_peek(const zend_worklist *worklist) { return zend_worklist_stack_peek(&worklist->stack); } diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index fd00dc7270de5..951f593973575 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -146,7 +146,37 @@ _LT_AC_TRY_DLOPEN_SELF([ ]) dnl Checks for library functions. -AC_CHECK_FUNCS(getpid kill sigsetjmp) +AC_CHECK_FUNCS(getpid kill sigsetjmp pthread_getattr_np pthread_attr_get_np pthread_get_stackaddr_np pthread_attr_getstack gettid) + +dnl Test whether the stack grows downwards +dnl Assumes contiguous stack +AC_MSG_CHECKING(whether the stack grows downwards) + +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include + +int (*volatile f)(uintptr_t); + +int stack_grows_downwards(uintptr_t arg) { + int local; + return (uintptr_t)&local < arg; +} + +int main(void) { + int local; + + f = stack_grows_downwards; + return f((uintptr_t)&local) ? 0 : 1; +} +]])], [ + AC_DEFINE([ZEND_STACK_GROWS_DOWNWARDS], 1, [Define if the stack grows downwards]) + AC_DEFINE([ZEND_CHECK_STACK_LIMIT], 1, [Define if checking the stack limit is supported]) + AC_MSG_RESULT(yes) +], [ + AC_MSG_RESULT(no) +], [ + AC_MSG_RESULT(no) +]) ZEND_CHECK_FLOAT_PRECISION ]) @@ -172,7 +202,7 @@ else AC_DEFINE(ZEND_DEBUG,0,[ ]) fi -test -n "$GCC" && CFLAGS="-Wall -Wextra -Wno-strict-aliasing -Wno-unused-parameter -Wno-sign-compare $CFLAGS" +test -n "$GCC" && CFLAGS="-Wall -Wextra -Wno-unused-parameter -Wno-sign-compare $CFLAGS" dnl Check if compiler supports -Wno-clobbered (only GCC) AX_CHECK_COMPILE_FLAG([-Wno-clobbered], CFLAGS="-Wno-clobbered $CFLAGS", , [-Werror]) dnl Check for support for implicit fallthrough level 1, also add after previous CFLAGS as level 3 is enabled in -Wextra @@ -220,7 +250,7 @@ typedef union _mm_align_test { #define ZEND_MM_ALIGNMENT (sizeof(mm_align_test)) #endif -int main() +int main(void) { size_t i = ZEND_MM_ALIGNMENT; int zeros = 0; @@ -272,16 +302,30 @@ fi AC_MSG_CHECKING(whether to enable zend signal handling) AC_MSG_RESULT($ZEND_SIGNALS) -]) +dnl Don't enable Zend Max Execution Timers by default until PHP 8.3 to not break the ABI +AC_ARG_ENABLE([zend-max-execution-timers], + [AS_HELP_STRING([--enable-zend-max-execution-timers], + [whether to enable zend max execution timers])], + [ZEND_MAX_EXECUTION_TIMERS=$enableval], + [ZEND_MAX_EXECUTION_TIMERS=$ZEND_ZTS]) -AC_MSG_CHECKING(whether /dev/urandom exists) -if test -r "/dev/urandom" && test -c "/dev/urandom"; then - AC_DEFINE([HAVE_DEV_URANDOM], 1, [Define if the target system has /dev/urandom device]) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) +AS_CASE(["$host_alias"], [*linux*], [], [ZEND_MAX_EXECUTION_TIMERS='no']) + +PHP_CHECK_FUNC(timer_create, rt) +if test "$ac_cv_func_timer_create" != "yes"; then + ZEND_MAX_EXECUTION_TIMERS='no' +fi + +if test "$ZEND_MAX_EXECUTION_TIMERS" = "yes"; then + AC_DEFINE(ZEND_MAX_EXECUTION_TIMERS, 1, [Use zend max execution timers]) + CFLAGS="$CFLAGS -DZEND_MAX_EXECUTION_TIMERS" fi +AC_MSG_CHECKING(whether to enable zend max execution timers) +AC_MSG_RESULT($ZEND_MAX_EXECUTION_TIMERS) + +]) + AC_ARG_ENABLE([gcc-global-regs], [AS_HELP_STRING([--disable-gcc-global-regs], [whether to enable GCC global register variables])], diff --git a/Zend/asm/jump_i386_sysv_elf_gas.S b/Zend/asm/jump_i386_sysv_elf_gas.S index b96d4b5c0e70e..47be9e77822e0 100644 --- a/Zend/asm/jump_i386_sysv_elf_gas.S +++ b/Zend/asm/jump_i386_sysv_elf_gas.S @@ -12,14 +12,14 @@ * ---------------------------------------------------------------------------------- * * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * * ---------------------------------------------------------------------------------- * - * | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | hidden | * + * | fc_mxcsr|fc_x87_cw| guard | EDI | ESI | EBX | EBP | EIP | * * ---------------------------------------------------------------------------------- * * ---------------------------------------------------------------------------------- * * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * * ---------------------------------------------------------------------------------- * - * | 0x20 | 0x24 | | * + * | 0x20 | 0x24 | 0x28 | | * * ---------------------------------------------------------------------------------- * - * | to | data | | * + * | hidden | to | data | | * * ---------------------------------------------------------------------------------- * * * ****************************************************************************************/ @@ -30,50 +30,60 @@ .align 2 .type jump_fcontext,@function jump_fcontext: - leal -0x18(%esp), %esp /* prepare stack */ + leal -0x1c(%esp), %esp /* prepare stack */ #if !defined(BOOST_USE_TSX) stmxcsr (%esp) /* save MMX control- and status-word */ fnstcw 0x4(%esp) /* save x87 control-word */ #endif - movl %edi, 0x8(%esp) /* save EDI */ - movl %esi, 0xc(%esp) /* save ESI */ - movl %ebx, 0x10(%esp) /* save EBX */ - movl %ebp, 0x14(%esp) /* save EBP */ +#if defined(BOOST_CONTEXT_TLS_STACK_PROTECTOR) + movl %gs:0x14, %ecx /* read stack guard from TLS record */ + movl %ecx, 0x8(%esp) /* save stack guard */ +#endif + + movl %edi, 0xc(%esp) /* save EDI */ + movl %esi, 0x10(%esp) /* save ESI */ + movl %ebx, 0x14(%esp) /* save EBX */ + movl %ebp, 0x18(%esp) /* save EBP */ /* store ESP (pointing to context-data) in ECX */ movl %esp, %ecx /* first arg of jump_fcontext() == fcontext to jump to */ - movl 0x20(%esp), %eax + movl 0x24(%esp), %eax /* second arg of jump_fcontext() == data to be transferred */ - movl 0x24(%esp), %edx + movl 0x28(%esp), %edx /* restore ESP (pointing to context-data) from EAX */ movl %eax, %esp /* address of returned transport_t */ - movl 0x1c(%esp), %eax + movl 0x20(%esp), %eax /* return parent fcontext_t */ movl %ecx, (%eax) /* return data */ movl %edx, 0x4(%eax) - movl 0x18(%esp), %ecx /* restore EIP */ + movl 0x1c(%esp), %ecx /* restore EIP */ #if !defined(BOOST_USE_TSX) ldmxcsr (%esp) /* restore MMX control- and status-word */ fldcw 0x4(%esp) /* restore x87 control-word */ #endif - movl 0x8(%esp), %edi /* restore EDI */ - movl 0xc(%esp), %esi /* restore ESI */ - movl 0x10(%esp), %ebx /* restore EBX */ - movl 0x14(%esp), %ebp /* restore EBP */ +#if defined(BOOST_CONTEXT_TLS_STACK_PROTECTOR) + movl 0x8(%esp), %edx /* load stack guard */ + movl %edx, %gs:0x14 /* restore stack guard to TLS record */ +#endif + + movl 0xc(%esp), %edi /* restore EDI */ + movl 0x10(%esp), %esi /* restore ESI */ + movl 0x14(%esp), %ebx /* restore EBX */ + movl 0x18(%esp), %ebp /* restore EBP */ - leal 0x20(%esp), %esp /* prepare stack */ + leal 0x24(%esp), %esp /* prepare stack */ /* jump to context */ jmp *%ecx diff --git a/Zend/asm/jump_ppc32_sysv_macho_gas.S b/Zend/asm/jump_ppc32_sysv_macho_gas.S index c555237afa2e9..fef90c295f8c9 100644 --- a/Zend/asm/jump_ppc32_sysv_macho_gas.S +++ b/Zend/asm/jump_ppc32_sysv_macho_gas.S @@ -80,122 +80,122 @@ _jump_fcontext: ; reserve space on stack subi r1, r1, 244 - stfd f14, 0(r1) # save F14 - stfd f15, 8(r1) # save F15 - stfd f16, 16(r1) # save F16 - stfd f17, 24(r1) # save F17 - stfd f18, 32(r1) # save F18 - stfd f19, 40(r1) # save F19 - stfd f20, 48(r1) # save F20 - stfd f21, 56(r1) # save F21 - stfd f22, 64(r1) # save F22 - stfd f23, 72(r1) # save F23 - stfd f24, 80(r1) # save F24 - stfd f25, 88(r1) # save F25 - stfd f26, 96(r1) # save F26 - stfd f27, 104(r1) # save F27 - stfd f28, 112(r1) # save F28 - stfd f29, 120(r1) # save F29 - stfd f30, 128(r1) # save F30 - stfd f31, 136(r1) # save F31 - mffs f0 # load FPSCR - stfd f0, 144(r1) # save FPSCR + stfd f14, 0(r1) ; save F14 + stfd f15, 8(r1) ; save F15 + stfd f16, 16(r1) ; save F16 + stfd f17, 24(r1) ; save F17 + stfd f18, 32(r1) ; save F18 + stfd f19, 40(r1) ; save F19 + stfd f20, 48(r1) ; save F20 + stfd f21, 56(r1) ; save F21 + stfd f22, 64(r1) ; save F22 + stfd f23, 72(r1) ; save F23 + stfd f24, 80(r1) ; save F24 + stfd f25, 88(r1) ; save F25 + stfd f26, 96(r1) ; save F26 + stfd f27, 104(r1) ; save F27 + stfd f28, 112(r1) ; save F28 + stfd f29, 120(r1) ; save F29 + stfd f30, 128(r1) ; save F30 + stfd f31, 136(r1) ; save F31 + mffs f0 ; load FPSCR + stfd f0, 144(r1) ; save FPSCR - stw r13, 152(r1) # save R13 - stw r14, 156(r1) # save R14 - stw r15, 160(r1) # save R15 - stw r16, 164(r1) # save R16 - stw r17, 168(r1) # save R17 - stw r18, 172(r1) # save R18 - stw r19, 176(r1) # save R19 - stw r20, 180(r1) # save R20 - stw r21, 184(r1) # save R21 - stw r22, 188(r1) # save R22 - stw r23, 192(r1) # save R23 - stw r24, 196(r1) # save R24 - stw r25, 200(r1) # save R25 - stw r26, 204(r1) # save R26 - stw r27, 208(r1) # save R27 - stw r28, 212(r1) # save R28 - stw r29, 216(r1) # save R29 - stw r30, 220(r1) # save R30 - stw r31, 224(r1) # save R31 - stw r3, 228(r1) # save hidden + stw r13, 152(r1) ; save R13 + stw r14, 156(r1) ; save R14 + stw r15, 160(r1) ; save R15 + stw r16, 164(r1) ; save R16 + stw r17, 168(r1) ; save R17 + stw r18, 172(r1) ; save R18 + stw r19, 176(r1) ; save R19 + stw r20, 180(r1) ; save R20 + stw r21, 184(r1) ; save R21 + stw r22, 188(r1) ; save R22 + stw r23, 192(r1) ; save R23 + stw r24, 196(r1) ; save R24 + stw r25, 200(r1) ; save R25 + stw r26, 204(r1) ; save R26 + stw r27, 208(r1) ; save R27 + stw r28, 212(r1) ; save R28 + stw r29, 216(r1) ; save R29 + stw r30, 220(r1) ; save R30 + stw r31, 224(r1) ; save R31 + stw r3, 228(r1) ; save hidden - # save CR + ; save CR mfcr r0 stw r0, 232(r1) - # save LR + ; save LR mflr r0 stw r0, 236(r1) - # save LR as PC + ; save LR as PC stw r0, 240(r1) - # store RSP (pointing to context-data) in R6 + ; store RSP (pointing to context-data) in R6 mr r6, r1 - # restore RSP (pointing to context-data) from R4 + ; restore RSP (pointing to context-data) from R4 mr r1, r4 - lfd f14, 0(r1) # restore F14 - lfd f15, 8(r1) # restore F15 - lfd f16, 16(r1) # restore F16 - lfd f17, 24(r1) # restore F17 - lfd f18, 32(r1) # restore F18 - lfd f19, 40(r1) # restore F19 - lfd f20, 48(r1) # restore F20 - lfd f21, 56(r1) # restore F21 - lfd f22, 64(r1) # restore F22 - lfd f23, 72(r1) # restore F23 - lfd f24, 80(r1) # restore F24 - lfd f25, 88(r1) # restore F25 - lfd f26, 96(r1) # restore F26 - lfd f27, 104(r1) # restore F27 - lfd f28, 112(r1) # restore F28 - lfd f29, 120(r1) # restore F29 - lfd f30, 128(r1) # restore F30 - lfd f31, 136(r1) # restore F31 - lfd f0, 144(r1) # load FPSCR - mtfsf 0xff, f0 # restore FPSCR + lfd f14, 0(r1) ; restore F14 + lfd f15, 8(r1) ; restore F15 + lfd f16, 16(r1) ; restore F16 + lfd f17, 24(r1) ; restore F17 + lfd f18, 32(r1) ; restore F18 + lfd f19, 40(r1) ; restore F19 + lfd f20, 48(r1) ; restore F20 + lfd f21, 56(r1) ; restore F21 + lfd f22, 64(r1) ; restore F22 + lfd f23, 72(r1) ; restore F23 + lfd f24, 80(r1) ; restore F24 + lfd f25, 88(r1) ; restore F25 + lfd f26, 96(r1) ; restore F26 + lfd f27, 104(r1) ; restore F27 + lfd f28, 112(r1) ; restore F28 + lfd f29, 120(r1) ; restore F29 + lfd f30, 128(r1) ; restore F30 + lfd f31, 136(r1) ; restore F31 + lfd f0, 144(r1) ; load FPSCR + mtfsf 0xff, f0 ; restore FPSCR - lwz r13, 152(r1) # restore R13 - lwz r14, 156(r1) # restore R14 - lwz r15, 160(r1) # restore R15 - lwz r16, 164(r1) # restore R16 - lwz r17, 168(r1) # restore R17 - lwz r18, 172(r1) # restore R18 - lwz r19, 176(r1) # restore R19 - lwz r20, 180(r1) # restore R20 - lwz r21, 184(r1) # restore R21 - lwz r22, 188(r1) # restore R22 - lwz r23, 192(r1) # restore R23 - lwz r24, 196(r1) # restore R24 - lwz r25, 200(r1) # restore R25 - lwz r26, 204(r1) # restore R26 - lwz r27, 208(r1) # restore R27 - lwz r28, 212(r1) # restore R28 - lwz r29, 216(r1) # restore R29 - lwz r30, 220(r1) # restore R30 - lwz r31, 224(r1) # restore R31 - lwz r3, 228(r1) # restore hidden + lwz r13, 152(r1) ; restore R13 + lwz r14, 156(r1) ; restore R14 + lwz r15, 160(r1) ; restore R15 + lwz r16, 164(r1) ; restore R16 + lwz r17, 168(r1) ; restore R17 + lwz r18, 172(r1) ; restore R18 + lwz r19, 176(r1) ; restore R19 + lwz r20, 180(r1) ; restore R20 + lwz r21, 184(r1) ; restore R21 + lwz r22, 188(r1) ; restore R22 + lwz r23, 192(r1) ; restore R23 + lwz r24, 196(r1) ; restore R24 + lwz r25, 200(r1) ; restore R25 + lwz r26, 204(r1) ; restore R26 + lwz r27, 208(r1) ; restore R27 + lwz r28, 212(r1) ; restore R28 + lwz r29, 216(r1) ; restore R29 + lwz r30, 220(r1) ; restore R30 + lwz r31, 224(r1) ; restore R31 + lwz r3, 228(r1) ; restore hidden - # restore CR + ; restore CR lwz r0, 232(r1) mtcr r0 - # restore LR + ; restore LR lwz r0, 236(r1) mtlr r0 - # load PC + ; load PC lwz r0, 240(r1) - # restore CTR + ; restore CTR mtctr r0 - # adjust stack + ; adjust stack addi r1, r1, 244 - # return transfer_t + ; return transfer_t stw r6, 0(r3) stw r5, 4(r3) - # jump to context + ; jump to context bctr diff --git a/Zend/asm/jump_ppc64_sysv_macho_gas.S b/Zend/asm/jump_ppc64_sysv_macho_gas.S index 74fcb2ab3528f..dcc6c645db619 100644 --- a/Zend/asm/jump_ppc64_sysv_macho_gas.S +++ b/Zend/asm/jump_ppc64_sysv_macho_gas.S @@ -12,7 +12,7 @@ * ------------------------------------------------- * * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * * ------------------------------------------------- * - * | TOC | R14 | R15 | R16 | * + * | R13 | R14 | R15 | R16 | * * ------------------------------------------------- * * ------------------------------------------------- * * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * @@ -61,7 +61,7 @@ * ------------------------------------------------- * * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * * ------------------------------------------------- * - * | TOC saved | FCTX | DATA | | * + * | FCTX | DATA | | | * * ------------------------------------------------- * * * *******************************************************/ @@ -138,27 +138,27 @@ _jump_fcontext: ; load PC ld r12, 176(r1) - # restore CTR + ; restore CTR mtctr r12 - # adjust stack + ; adjust stack addi r1, r1, 184 - # zero in r3 indicates first jump to context-function + ; zero in r3 indicates first jump to context-function cmpdi r3, 0 beq use_entry_arg - # return transfer_t + ; return transfer_t std r6, 0(r3) std r5, 8(r3) - # jump to context + ; jump to context bctr use_entry_arg: - # copy transfer_t into transfer_fn arg registers + ; copy transfer_t into transfer_fn arg registers mr r3, r6 mr r4, r5 - # jump to context + ; jump to context bctr diff --git a/Zend/asm/jump_x86_64_sysv_elf_gas.S b/Zend/asm/jump_x86_64_sysv_elf_gas.S index 1a7709d93d7c8..40f8734daeeb1 100644 --- a/Zend/asm/jump_x86_64_sysv_elf_gas.S +++ b/Zend/asm/jump_x86_64_sysv_elf_gas.S @@ -12,14 +12,21 @@ * ---------------------------------------------------------------------------------- * * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * * ---------------------------------------------------------------------------------- * - * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | * + * | fc_mxcsr|fc_x87_cw| guard | R12 | R13 | * * ---------------------------------------------------------------------------------- * * ---------------------------------------------------------------------------------- * * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * * ---------------------------------------------------------------------------------- * * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * * ---------------------------------------------------------------------------------- * - * | R15 | RBX | RBP | RIP | * + * | R14 | R15 | RBX | RBP | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ---------------------------------------------------------------------------------- * + * | 0x40 | 0x44 | | * + * ---------------------------------------------------------------------------------- * + * | RIP | | * * ---------------------------------------------------------------------------------- * * * ****************************************************************************************/ @@ -38,19 +45,32 @@ .align 16 jump_fcontext: _CET_ENDBR - leaq -0x38(%rsp), %rsp /* prepare stack */ + leaq -0x40(%rsp), %rsp /* prepare stack */ #if !defined(BOOST_USE_TSX) stmxcsr (%rsp) /* save MMX control- and status-word */ fnstcw 0x4(%rsp) /* save x87 control-word */ #endif - movq %r12, 0x8(%rsp) /* save R12 */ - movq %r13, 0x10(%rsp) /* save R13 */ - movq %r14, 0x18(%rsp) /* save R14 */ - movq %r15, 0x20(%rsp) /* save R15 */ - movq %rbx, 0x28(%rsp) /* save RBX */ - movq %rbp, 0x30(%rsp) /* save RBP */ +#if defined(BOOST_CONTEXT_TLS_STACK_PROTECTOR) + movq %fs:0x28, %rcx /* read stack guard from TLS record */ + movq %rcx, 0x8(%rsp) /* save stack guard */ +#endif + + movq %r12, 0x10(%rsp) /* save R12 */ + movq %r13, 0x18(%rsp) /* save R13 */ + movq %r14, 0x20(%rsp) /* save R14 */ + movq %r15, 0x28(%rsp) /* save R15 */ + movq %rbx, 0x30(%rsp) /* save RBX */ + movq %rbp, 0x38(%rsp) /* save RBP */ + +#if BOOST_CONTEXT_SHADOW_STACK + /* grow the stack to reserve space for shadow stack pointer(SSP) */ + leaq -0x8(%rsp), %rsp + /* read the current SSP and store it */ + rdsspq %rcx + movq %rcx, (%rsp) +#endif #if BOOST_CONTEXT_SHADOW_STACK /* grow the stack to reserve space for shadow stack pointer(SSP) */ @@ -82,23 +102,28 @@ jump_fcontext: /* shadow stack accordingly. Otherwise mismatch occur */ movq $1, %rcx incsspq %rcx -# endif +#endif - movq 0x38(%rsp), %r8 /* restore return-address */ + movq 0x40(%rsp), %r8 /* restore return-address */ #if !defined(BOOST_USE_TSX) ldmxcsr (%rsp) /* restore MMX control- and status-word */ fldcw 0x4(%rsp) /* restore x87 control-word */ #endif - movq 0x8(%rsp), %r12 /* restore R12 */ - movq 0x10(%rsp), %r13 /* restore R13 */ - movq 0x18(%rsp), %r14 /* restore R14 */ - movq 0x20(%rsp), %r15 /* restore R15 */ - movq 0x28(%rsp), %rbx /* restore RBX */ - movq 0x30(%rsp), %rbp /* restore RBP */ +#if defined(BOOST_CONTEXT_TLS_STACK_PROTECTOR) + movq 0x8(%rsp), %rdx /* load stack guard */ + movq %rdx, %fs:0x28 /* restore stack guard to TLS record */ +#endif + + movq 0x10(%rsp), %r12 /* restore R12 */ + movq 0x18(%rsp), %r13 /* restore R13 */ + movq 0x20(%rsp), %r14 /* restore R14 */ + movq 0x28(%rsp), %r15 /* restore R15 */ + movq 0x30(%rsp), %rbx /* restore RBX */ + movq 0x38(%rsp), %rbp /* restore RBP */ - leaq 0x40(%rsp), %rsp /* prepare stack */ + leaq 0x48(%rsp), %rsp /* prepare stack */ /* return transfer_t from jump */ #if !defined(_ILP32) diff --git a/Zend/asm/make_i386_sysv_elf_gas.S b/Zend/asm/make_i386_sysv_elf_gas.S index b76de260d211f..9261e566c0d45 100644 --- a/Zend/asm/make_i386_sysv_elf_gas.S +++ b/Zend/asm/make_i386_sysv_elf_gas.S @@ -12,14 +12,14 @@ * ---------------------------------------------------------------------------------- * * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * * ---------------------------------------------------------------------------------- * - * | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | hidden | * + * | fc_mxcsr|fc_x87_cw| guard | EDI | ESI | EBX | EBP | EIP | * * ---------------------------------------------------------------------------------- * * ---------------------------------------------------------------------------------- * * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * * ---------------------------------------------------------------------------------- * - * | 0x20 | 0x24 | | * + * | 0x20 | 0x24 | 0x28 | | * * ---------------------------------------------------------------------------------- * - * | to | data | | * + * | hidden | to | data | | * * ---------------------------------------------------------------------------------- * * * ****************************************************************************************/ @@ -40,23 +40,29 @@ make_fcontext: /* shift address in EAX to lower 16 byte boundary */ andl $-16, %eax - /* reserve space for context-data on context-stack */ - leal -0x28(%eax), %eax + /* reserve space for context-data on context-stack, and align the stack */ + leal -0x34(%eax), %eax /* third arg of make_fcontext() == address of context-function */ /* stored in EBX */ movl 0xc(%esp), %ecx - movl %ecx, 0x10(%eax) + movl %ecx, 0x14(%eax) /* save MMX control- and status-word */ stmxcsr (%eax) /* save x87 control-word */ fnstcw 0x4(%eax) +#if defined(BOOST_CONTEXT_TLS_STACK_PROTECTOR) + /* save stack guard */ + movl %gs:0x14, %ecx /* read stack guard from TLS record */ + movl %ecx, 0x8(%eax) /* save stack guard */ +#endif + /* return transport_t */ /* FCTX == EDI, DATA == ESI */ - leal 0x8(%eax), %ecx - movl %ecx, 0x1c(%eax) + leal 0xc(%eax), %ecx + movl %ecx, 0x20(%eax) /* compute abs address of label trampoline */ call 1f @@ -66,7 +72,7 @@ make_fcontext: addl $trampoline-1b, %ecx /* save address of trampoline as return address */ /* will be entered after calling jump_fcontext() first time */ - movl %ecx, 0x18(%eax) + movl %ecx, 0x1c(%eax) /* compute abs address of label finish */ call 2f @@ -76,7 +82,7 @@ make_fcontext: addl $finish-2b, %ecx /* save address of finish as return-address for context-function */ /* will be entered after context-function returns */ - movl %ecx, 0x14(%eax) + movl %ecx, 0x18(%eax) ret /* return pointer to context-data */ diff --git a/Zend/asm/make_i386_sysv_macho_gas.S b/Zend/asm/make_i386_sysv_macho_gas.S index fdcdb7c80fbff..519e406248bb2 100644 --- a/Zend/asm/make_i386_sysv_macho_gas.S +++ b/Zend/asm/make_i386_sysv_macho_gas.S @@ -38,8 +38,8 @@ _make_fcontext: /* shift address in EAX to lower 16 byte boundary */ andl $-16, %eax - /* reserve space for context-data on context-stack */ - leal -0x2c(%eax), %eax + /* reserve space for context-data on context-stack, and align the stack */ + leal -0x34(%eax), %eax /* third arg of make_fcontext() == address of context-function */ /* stored in EBX */ diff --git a/Zend/asm/make_ppc32_sysv_macho_gas.S b/Zend/asm/make_ppc32_sysv_macho_gas.S index 8f35eff9abbff..1102ee90ef076 100644 --- a/Zend/asm/make_ppc32_sysv_macho_gas.S +++ b/Zend/asm/make_ppc32_sysv_macho_gas.S @@ -77,61 +77,78 @@ .globl _make_fcontext .align 2 _make_fcontext: - # save return address into R6 + ; save return address into R6 mflr r6 - # first arg of make_fcontext() == top address of context-function - # shift address in R3 to lower 16 byte boundary + ; first arg of make_fcontext() == top address of context-function + ; shift address in R3 to lower 16 byte boundary clrrwi r3, r3, 4 - # reserve space for context-data on context-stack - # including 64 byte of linkage + parameter area (R1 16 == 0) + ; reserve space for context-data on context-stack + ; including 64 byte of linkage + parameter area (R1 % 16 == 0) subi r3, r3, 336 - # third arg of make_fcontext() == address of context-function - stw r5, 240(r3) + ; third arg of make_fcontext() == address of context-function + ; store as trampoline's R31 + stw r5, 224(r3) - # set back-chain to zero + ; set back-chain to zero li r0, 0 stw r0, 244(r3) - mffs f0 # load FPSCR - stfd f0, 144(r3) # save FPSCR + mffs f0 ; load FPSCR + stfd f0, 144(r3) ; save FPSCR - # compute address of returned transfer_t + ; compute address of returned transfer_t addi r0, r3, 252 mr r4, r0 stw r4, 228(r3) - # load LR + ; load LR mflr r0 - # jump to label 1 - bl 1f -1: - # load LR into R4 + ; jump to label 1 + bcl 20, 31, L1 +L1: + ; load LR into R4 mflr r4 - # compute abs address of label finish - addi r4, r4, finish - 1b - # restore LR + ; compute abs address of trampoline, use as PC + addi r5, r4, lo16(Ltrampoline - L1) + stw r5, 240(r3) + ; compute abs address of label finish + addi r4, r4, lo16(Lfinish - L1) + ; restore LR mtlr r0 - # save address of finish as return-address for context-function - # will be entered after context-function returns + ; save address of finish as return-address for context-function + ; will be entered after context-function returns stw r4, 236(r3) - # restore return address from R6 + ; restore return address from R6 mtlr r6 - blr # return pointer to context-data + blr ; return pointer to context-data -finish: - # save return address into R0 - mflr r0 - # save return address on stack, set up stack frame - stw r0, 4(r1) - # allocate stack space, R1 16 == 0 - stwu r1, -16(r1) +Ltrampoline: + ; We get R31 = context-function, R3 = address of transfer_t, + ; but we need to pass R3:R4 = transfer_t. + mtctr r31 + lwz r4, 4(r3) + lwz r3, 0(r3) + bctr - # exit code is zero +Lfinish: + ; load address of _exit into CTR + bcl 20, 31, L2 +L2: + mflr r4 + addis r4, r4, ha16(Lexitp - L2) + lwz r4, lo16(Lexitp - L2)(r4) + mtctr r4 + ; exit code is zero li r3, 0 - # exit application - bl _exit@plt + ; exit application + bctr + +.const_data +.align 2 +Lexitp: + .long __exit diff --git a/Zend/asm/make_ppc64_sysv_macho_gas.S b/Zend/asm/make_ppc64_sysv_macho_gas.S index 7b947bb6b030b..fb5cada265a64 100644 --- a/Zend/asm/make_ppc64_sysv_macho_gas.S +++ b/Zend/asm/make_ppc64_sysv_macho_gas.S @@ -12,7 +12,7 @@ * ------------------------------------------------- * * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * * ------------------------------------------------- * - * | TOC | R14 | R15 | R16 | * + * | R13 | R14 | R15 | R16 | * * ------------------------------------------------- * * ------------------------------------------------- * * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * @@ -61,7 +61,7 @@ * ------------------------------------------------- * * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * * ------------------------------------------------- * - * | TOC saved | FCTX | DATA | | * + * | FCTX | DATA | | | * * ------------------------------------------------- * * * @@ -77,19 +77,19 @@ _make_fcontext: ; reserve space for context-data on context-stack ; including 64 byte of linkage + parameter area (R1 16 == 0) - subi r3, r3, 248 + subi r3, r3, 240 ; third arg of make_fcontext() == address of context-function stw r5, 176(r3) ; set back-chain to zero - li %r0, 0 - std %r0, 184(%r3) + li r0, 0 + std r0, 184(r3) ; compute address of returned transfer_t - addi %r0, %r3, 232 - mr %r4, %r0 - std %r4, 152(%r3) + addi r0, r3, 224 + mr r4, r0 + std r4, 152(r3) ; load LR mflr r0 diff --git a/Zend/asm/make_x86_64_sysv_elf_gas.S b/Zend/asm/make_x86_64_sysv_elf_gas.S index 110c2d3d4a66d..3358a27d844df 100644 --- a/Zend/asm/make_x86_64_sysv_elf_gas.S +++ b/Zend/asm/make_x86_64_sysv_elf_gas.S @@ -12,14 +12,21 @@ * ---------------------------------------------------------------------------------- * * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * * ---------------------------------------------------------------------------------- * - * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | * + * | fc_mxcsr|fc_x87_cw| guard | R12 | R13 | * * ---------------------------------------------------------------------------------- * * ---------------------------------------------------------------------------------- * * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * * ---------------------------------------------------------------------------------- * * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * * ---------------------------------------------------------------------------------- * - * | R15 | RBX | RBP | RIP | * + * | R14 | R15 | RBX | RBP | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ---------------------------------------------------------------------------------- * + * | 0x40 | 0x44 | | * + * ---------------------------------------------------------------------------------- * + * | RIP | | * * ---------------------------------------------------------------------------------- * * * ****************************************************************************************/ @@ -52,28 +59,63 @@ make_fcontext: /* reserve space for context-data on context-stack */ /* on context-function entry: (RSP -0x8) % 16 == 0 */ - leaq -0x40(%rax), %rax + leaq -0x48(%rax), %rax /* third arg of make_fcontext() == address of context-function */ /* stored in RBX */ - movq %rdx, 0x28(%rax) + movq %rdx, 0x30(%rax) /* save MMX control- and status-word */ stmxcsr (%rax) /* save x87 control-word */ fnstcw 0x4(%rax) +#if defined(BOOST_CONTEXT_TLS_STACK_PROTECTOR) + /* save stack guard */ + movq %fs:0x28, %rcx /* read stack guard from TLS record */ + movq %rcx, 0x8(%rsp) /* save stack guard */ +#endif + /* compute abs address of label trampoline */ leaq trampoline(%rip), %rcx /* save address of trampoline as return-address for context-function */ /* will be entered after calling jump_fcontext() first time */ - movq %rcx, 0x38(%rax) + movq %rcx, 0x40(%rax) /* compute abs address of label finish */ leaq finish(%rip), %rcx /* save address of finish as return-address for context-function */ /* will be entered after context-function returns */ - movq %rcx, 0x30(%rax) + movq %rcx, 0x38(%rax) + +#if BOOST_CONTEXT_SHADOW_STACK + /* Populate the shadow stack and normal stack */ + /* get original SSP */ + rdsspq %r8 + /* restore new shadow stack */ + rstorssp -0x8(%r9) + /* save the restore token on the original shadow stack */ + saveprevssp + /* push the address of "jmp trampoline" to the new shadow stack */ + /* as well as the stack */ + call 1f + jmp trampoline +1: + /* save address of "jmp trampoline" as return-address */ + /* for context-function */ + pop 0x38(%rax) + /* Get the new SSP. */ + rdsspq %r9 + /* restore original shadow stack */ + rstorssp -0x8(%r8) + /* save the restore token on the new shadow stack. */ + saveprevssp + + /* reserve space for the new SSP */ + leaq -0x8(%rax), %rax + /* save the new SSP to this fcontext */ + movq %r9, (%rax) +#endif #if BOOST_CONTEXT_SHADOW_STACK /* Populate the shadow stack */ diff --git a/Zend/tests/011.phpt b/Zend/tests/011.phpt index 0a7e3fd90a11e..8412699e026bf 100644 --- a/Zend/tests/011.phpt +++ b/Zend/tests/011.phpt @@ -89,7 +89,7 @@ bool(false) property_exists(): Argument #1 ($object_or_class) must be of type object|string, array given property_exists(): Argument #1 ($object_or_class) must be of type object|string, int given property_exists(): Argument #1 ($object_or_class) must be of type object|string, float given -property_exists(): Argument #1 ($object_or_class) must be of type object|string, bool given +property_exists(): Argument #1 ($object_or_class) must be of type object|string, true given property_exists(): Argument #1 ($object_or_class) must be of type object|string, null given bool(true) bool(true) diff --git a/Zend/tests/024.phpt b/Zend/tests/024.phpt index 22d93483fed87..0077113ad1400 100644 --- a/Zend/tests/024.phpt +++ b/Zend/tests/024.phpt @@ -17,14 +17,14 @@ var_dump($a->$b->{$c[1]}); --EXPECTF-- Warning: Undefined variable $a in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL Warning: Undefined variable $a in %s on line %d Warning: Undefined variable $c in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL Warning: Undefined variable $a in %s on line %d @@ -49,7 +49,7 @@ NULL Warning: Undefined variable $c in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Warning: Attempt to read property "1" on int in %s on line %d diff --git a/Zend/tests/033.phpt b/Zend/tests/033.phpt index 22e4b6a12097f..6593d6ba4ad44 100644 --- a/Zend/tests/033.phpt +++ b/Zend/tests/033.phpt @@ -27,39 +27,39 @@ try { --EXPECTF-- Warning: Undefined variable $arr in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Warning: Undefined variable $arr in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Warning: Undefined variable $arr in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Warning: Attempt to read property "foo" on null in %s on line %d Attempt to assign property "foo" on null diff --git a/Zend/tests/036.phpt b/Zend/tests/036.phpt index 8f74bccc075f0..4037d3d0e3d21 100644 --- a/Zend/tests/036.phpt +++ b/Zend/tests/036.phpt @@ -11,4 +11,4 @@ try { ?> --EXPECT-- -Illegal offset type +Cannot access offset of type object on array diff --git a/Zend/tests/038.phpt b/Zend/tests/038.phpt index e55757bbcd417..4f822a6f5a154 100644 --- a/Zend/tests/038.phpt +++ b/Zend/tests/038.phpt @@ -11,4 +11,4 @@ try { ?> --EXPECT-- -Illegal offset type +Cannot access offset of type object on array diff --git a/Zend/tests/arginfo_zpp_mismatch.inc b/Zend/tests/arginfo_zpp_mismatch.inc index 221c347aaa915..023bfefa5d501 100644 --- a/Zend/tests/arginfo_zpp_mismatch.inc +++ b/Zend/tests/arginfo_zpp_mismatch.inc @@ -9,6 +9,7 @@ function skipFunction($function): bool { /* intentionally violate invariants */ || $function === 'zend_create_unterminated_string' || $function === 'zend_test_array_return' + || $function === 'zend_test_crash' || $function === 'zend_leak_bytes' /* mess with output */ || (is_string($function) && str_starts_with($function, 'ob_')) diff --git a/Zend/tests/assign_dim_obj_null_return.phpt b/Zend/tests/assign_dim_obj_null_return.phpt index b046a865137aa..02e709818669e 100644 --- a/Zend/tests/assign_dim_obj_null_return.phpt +++ b/Zend/tests/assign_dim_obj_null_return.phpt @@ -72,12 +72,12 @@ test(); ?> --EXPECT-- Cannot add element to the array as the next element is already occupied -Illegal offset type -Illegal offset type +Cannot access offset of type array on array +Cannot access offset of type object on array Cannot use a scalar value as an array Cannot add element to the array as the next element is already occupied -Illegal offset type -Illegal offset type +Cannot access offset of type array on array +Cannot access offset of type object on array Cannot use a scalar value as an array -Attempt to assign property "foo" on bool -Attempt to assign property "foo" on bool +Attempt to assign property "foo" on true +Attempt to assign property "foo" on true diff --git a/Zend/tests/assign_to_var_003.phpt b/Zend/tests/assign_to_var_003.phpt index 3ecf89e172561..9cbcc66776ab1 100644 --- a/Zend/tests/assign_to_var_003.phpt +++ b/Zend/tests/assign_to_var_003.phpt @@ -13,7 +13,7 @@ var_dump($var1); echo "Done\n"; ?> --EXPECTF-- -Warning: Trying to access array offset on value of type float in %s on line %d +Warning: Trying to access array offset on float in %s on line %d NULL NULL Done diff --git a/Zend/tests/bug39542.phpt b/Zend/tests/bug39542.phpt index 79c1c56e9185b..d2023673ef0b5 100644 --- a/Zend/tests/bug39542.phpt +++ b/Zend/tests/bug39542.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #39542 (Behaviour of require_once/include_once different to < 5.2.0) +--INI-- +error_log= --FILE-- --FILE-- --EXPECT-- diff --git a/Zend/tests/bug41633_2.phpt b/Zend/tests/bug41633_2.phpt index bb768c0e11743..998610d291cdf 100644 --- a/Zend/tests/bug41633_2.phpt +++ b/Zend/tests/bug41633_2.phpt @@ -10,5 +10,6 @@ echo Foo::A."\n"; --EXPECTF-- Fatal error: Uncaught Error: Undefined constant self::B in %s:%d Stack trace: -#0 {main} +#0 %s(%d): [constant expression]() +#1 {main} thrown in %sbug41633_2.php on line 3 diff --git a/Zend/tests/bug41633_3.phpt b/Zend/tests/bug41633_3.phpt index 4f78194a7e7a1..84f4c0c146760 100644 --- a/Zend/tests/bug41633_3.phpt +++ b/Zend/tests/bug41633_3.phpt @@ -11,5 +11,6 @@ echo Foo::A; --EXPECTF-- Fatal error: Uncaught Error: Cannot declare self-referencing constant Foo::B in %s:%d Stack trace: -#0 {main} +#0 %s(%d): [constant expression]() +#1 {main} thrown in %sbug41633_3.php on line %d diff --git a/Zend/tests/bug44660.phpt b/Zend/tests/bug44660.phpt index 1d81677f127e9..02588c44b9d11 100644 --- a/Zend/tests/bug44660.phpt +++ b/Zend/tests/bug44660.phpt @@ -48,22 +48,22 @@ var_dump($a); ?> --EXPECTF-- --> read access: -Warning: Attempt to read property "p" on bool in %s on line %d +Warning: Attempt to read property "p" on true in %s on line %d --> direct assignment: -Attempt to assign property "p" on bool +Attempt to assign property "p" on true --> increment: -Attempt to increment/decrement property "p" on bool +Attempt to increment/decrement property "p" on true --> reference assignment: -Attempt to modify property "p" on bool +Attempt to modify property "p" on true --> reference assignment: -Attempt to modify property "p" on bool +Attempt to modify property "p" on true --> indexed assignment: -Attempt to modify property "p" on bool +Attempt to modify property "p" on true --> Confirm assignments have had no impact: bool(true) diff --git a/Zend/tests/bug47572.phpt b/Zend/tests/bug47572.phpt index 1e424b350c4e9..4e3a99ccd5cad 100644 --- a/Zend/tests/bug47572.phpt +++ b/Zend/tests/bug47572.phpt @@ -16,5 +16,6 @@ $foo = new Foo(); --EXPECTF-- Fatal error: Uncaught Error: Undefined constant "FOO" in %s:%d Stack trace: -#0 {main} +#0 %s(%d): [constant expression]() +#1 {main} thrown in %s on line %d diff --git a/Zend/tests/bug60978.phpt b/Zend/tests/bug60978.phpt index 5dc6fe31e7166..2d83d2a213e61 100644 --- a/Zend/tests/bug60978.phpt +++ b/Zend/tests/bug60978.phpt @@ -2,8 +2,7 @@ Bug #60978 (exit code incorrect) --FILE-- --EXPECT-- diff --git a/Zend/tests/bug74657.phpt b/Zend/tests/bug74657.phpt index 055501066b9f2..b024833f28a8b 100644 --- a/Zend/tests/bug74657.phpt +++ b/Zend/tests/bug74657.phpt @@ -21,5 +21,6 @@ var_dump((new C)->options); --EXPECTF-- Fatal error: Uncaught Error: Undefined constant I::FOO in %s:%d Stack trace: -#0 {main} +#0 %s(%d): [constant expression]() +#1 {main} thrown in %sbug74657.php on line %d diff --git a/Zend/tests/bug79790.phpt b/Zend/tests/bug79790.phpt index 4fce25291bcb5..0d34e2be0fc1e 100644 --- a/Zend/tests/bug79790.phpt +++ b/Zend/tests/bug79790.phpt @@ -8,7 +8,7 @@ function b($a = array()[array ()]) { } ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Illegal offset type in %s:%d +Fatal error: Uncaught TypeError: Cannot access offset of type array on array in %s:%d Stack trace: #0 %s(%d): b() #1 {main} diff --git a/Zend/tests/bug79919.phpt b/Zend/tests/bug79919.phpt index dbe791c32db27..4407bdc1b8eae 100644 --- a/Zend/tests/bug79919.phpt +++ b/Zend/tests/bug79919.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #79919 (Stack use-after-scope in define()) +--INI-- +error_log= --EXTENSIONS-- simplexml --FILE-- diff --git a/Zend/tests/bug79947.phpt b/Zend/tests/bug79947.phpt index 906f58144b41d..0593eacfd6c48 100644 --- a/Zend/tests/bug79947.phpt +++ b/Zend/tests/bug79947.phpt @@ -12,6 +12,6 @@ try { var_dump($array); ?> --EXPECT-- -Illegal offset type +Cannot access offset of type array on array array(0) { } diff --git a/Zend/tests/bug80781.phpt b/Zend/tests/bug80781.phpt index eb5109add9f6c..0dc004fb9d74c 100644 --- a/Zend/tests/bug80781.phpt +++ b/Zend/tests/bug80781.phpt @@ -25,7 +25,7 @@ if (isset($array[$data]) or getPlugin($data)) { ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Illegal offset type in isset or empty in %s:%d +Fatal error: Uncaught TypeError: Cannot access offset of type array in isset or empty in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/Zend/tests/bug81631.phpt b/Zend/tests/bug81631.phpt index 191ea951274d2..4542f1fba13f7 100644 --- a/Zend/tests/bug81631.phpt +++ b/Zend/tests/bug81631.phpt @@ -8,7 +8,7 @@ var_dump($b::class); --EXPECTF-- Warning: Undefined variable $b in %s on line 3 -Fatal error: Uncaught TypeError: Cannot use "::class" on value of type null in %s:3 +Fatal error: Uncaught TypeError: Cannot use "::class" on null in %s:3 Stack trace: #0 {main} thrown in %s on line 3 diff --git a/Zend/tests/call_user_func_007.phpt b/Zend/tests/call_user_func_007.phpt index 08083e71a9461..1a36f2f19fbb9 100644 --- a/Zend/tests/call_user_func_007.phpt +++ b/Zend/tests/call_user_func_007.phpt @@ -13,7 +13,7 @@ var_dump($a); --EXPECTF-- Warning: Undefined array key 0 in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Warning: foo(): Argument #1 ($ref) must be passed by reference, value given in %s on line %d array(0) { diff --git a/Zend/tests/class_alias_006.phpt b/Zend/tests/class_alias_006.phpt index 8fe2ac509aeea..2548d8f143aeb 100644 --- a/Zend/tests/class_alias_006.phpt +++ b/Zend/tests/class_alias_006.phpt @@ -3,12 +3,11 @@ Testing creation of alias to an internal class --FILE-- getMessage() . "\n"; -} +class_alias('stdclass', 'foo'); +$foo = new foo(); +var_dump($foo); ?> --EXPECT-- -class_alias(): Argument #1 ($class) must be a user-defined class name, internal class name given +object(stdClass)#1 (0) { +} diff --git a/Zend/tests/class_constants_007.phpt b/Zend/tests/class_constants_007.phpt new file mode 100644 index 0000000000000..d09a12e8c17b8 --- /dev/null +++ b/Zend/tests/class_constants_007.phpt @@ -0,0 +1,13 @@ +--TEST-- +Ownership of constant expression inhereted from immutable class should be transfered to class +--FILE-- + +--EXPECT-- +string(2) " " diff --git a/Zend/tests/class_on_constant_evaluated_expression.phpt b/Zend/tests/class_on_constant_evaluated_expression.phpt index c70262c20d7bb..9129d739c4198 100644 --- a/Zend/tests/class_on_constant_evaluated_expression.phpt +++ b/Zend/tests/class_on_constant_evaluated_expression.phpt @@ -7,4 +7,4 @@ An error should be generated when using ::class on a constant evaluated expressi ?> --EXPECTF-- -Fatal error: Cannot use "::class" on value of type int in %s on line %d +Fatal error: Cannot use "::class" on int in %s on line %d diff --git a/Zend/tests/class_on_object.phpt b/Zend/tests/class_on_object.phpt index c316eff3e467d..dab09872901ba 100644 --- a/Zend/tests/class_on_object.phpt +++ b/Zend/tests/class_on_object.phpt @@ -25,4 +25,4 @@ try { string(8) "stdClass" string(8) "stdClass" string(8) "stdClass" -Cannot use "::class" on value of type null +Cannot use "::class" on null diff --git a/Zend/tests/const_expr_dim_on_null_warning.phpt b/Zend/tests/const_expr_dim_on_null_warning.phpt index 9bea754446ffb..3efa4b9c5243d 100644 --- a/Zend/tests/const_expr_dim_on_null_warning.phpt +++ b/Zend/tests/const_expr_dim_on_null_warning.phpt @@ -6,5 +6,5 @@ const C = (null)['foo']; var_dump(C); ?> --EXPECTF-- -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL diff --git a/Zend/tests/constant_expressions_invalid_offset_type_error.phpt b/Zend/tests/constant_expressions_invalid_offset_type_error.phpt index 649c3a325a0c2..1a0ef52dce082 100644 --- a/Zend/tests/constant_expressions_invalid_offset_type_error.phpt +++ b/Zend/tests/constant_expressions_invalid_offset_type_error.phpt @@ -8,7 +8,7 @@ const C2 = [C1, [] => 1]; ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Illegal offset type in %s:%d +Fatal error: Uncaught TypeError: Cannot access offset of type array on array in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/Zend/tests/constant_expressions_self_referencing_array.phpt b/Zend/tests/constant_expressions_self_referencing_array.phpt index 214862071d74a..0c0436a456326 100644 --- a/Zend/tests/constant_expressions_self_referencing_array.phpt +++ b/Zend/tests/constant_expressions_self_referencing_array.phpt @@ -11,5 +11,6 @@ var_dump(A::FOO); --EXPECTF-- Fatal error: Uncaught Error: Cannot declare self-referencing constant self::BAR in %s:%d Stack trace: -#0 {main} +#0 %s(%d): [constant expression]() +#1 {main} thrown in %s on line %d diff --git a/Zend/tests/dereference_002.phpt b/Zend/tests/dereference_002.phpt index 6c8339bb1321a..135b7432f12f1 100644 --- a/Zend/tests/dereference_002.phpt +++ b/Zend/tests/dereference_002.phpt @@ -70,7 +70,7 @@ array(2) { } int(1) -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL Warning: Undefined array key 4 in %s on line %d diff --git a/Zend/tests/dereference_010.phpt b/Zend/tests/dereference_010.phpt index 191da8f3488f3..53f27322a2e45 100644 --- a/Zend/tests/dereference_010.phpt +++ b/Zend/tests/dereference_010.phpt @@ -21,10 +21,10 @@ var_dump(b()[1]); ?> --EXPECTF-- -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL Fatal error: Uncaught Error: Cannot use object of type stdClass as array in %s:%d diff --git a/Zend/tests/dereference_014.phpt b/Zend/tests/dereference_014.phpt index 35affdf3caeed..82b9d91f3d46c 100644 --- a/Zend/tests/dereference_014.phpt +++ b/Zend/tests/dereference_014.phpt @@ -27,12 +27,12 @@ var_dump($h); ?> --EXPECTF-- -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Warning: Attempt to read property "a" on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Warning: Attempt to read property "b" on null in %s on line %d NULL diff --git a/Zend/tests/dynamic_class_const_fetch.phpt b/Zend/tests/dynamic_class_const_fetch.phpt new file mode 100644 index 0000000000000..1924536b964e6 --- /dev/null +++ b/Zend/tests/dynamic_class_const_fetch.phpt @@ -0,0 +1,64 @@ +--TEST-- +Dynamic class constant fetch +--FILE-- +getMessage(), "\n"; + } +} + +$const_names = [ + ['', '"BAR"'], + ['$bar = "BAR";', '$bar'], + ['$ba = "BA"; $r = "R";', '$ba . $r'], + ['', 'strtoupper("bar")'], + ['', '$barr'], + ['$bar = "BAR"; $barRef = &$bar;', '$barRef'], + ['', 'strtolower("CLASS")'], + ['', '42'], + ['$bar = 42;', '$bar'], + ['', '[]'], + ['$bar = [];', '$bar'], +]; + +foreach ($const_names as [$prolog, $const_name]) { + test("$prolog return Foo::{{$const_name}};"); + test("\$foo = 'Foo'; $prolog return \$foo::{{$const_name}};"); +} + +?> +--EXPECTF-- +string(3) "bar" +string(3) "bar" +string(3) "bar" +string(3) "bar" +string(3) "bar" +string(3) "bar" +string(3) "bar" +string(3) "bar" + +Warning: Undefined variable $barr in %s : eval()'d code on line %d +Cannot use value of type null as class constant name + +Warning: Undefined variable $barr in %s : eval()'d code on line %d +Cannot use value of type null as class constant name +string(3) "bar" +string(3) "bar" +string(3) "Foo" +string(3) "Foo" +Cannot use value of type int as class constant name +Cannot use value of type int as class constant name +Cannot use value of type int as class constant name +Cannot use value of type int as class constant name +Cannot use value of type array as class constant name +Cannot use value of type array as class constant name +Cannot use value of type array as class constant name +Cannot use value of type array as class constant name diff --git a/Zend/tests/dynamic_class_const_fetch_cache_slot.phpt b/Zend/tests/dynamic_class_const_fetch_cache_slot.phpt new file mode 100644 index 0000000000000..3ddedfca763a1 --- /dev/null +++ b/Zend/tests/dynamic_class_const_fetch_cache_slot.phpt @@ -0,0 +1,61 @@ +--TEST-- +Dynamic class constant fetch +--FILE-- +bindTo(null, Foo::class)('BAR'); +$c->bindTo(null, Bar::class)('BAZ'); +$c->bindTo(null, Foo::class)('class'); +$c->bindTo(null, Bar::class)('class'); + +?> +--EXPECT-- +bar +bar +baz child +baz child +bar +bar +bar +baz 2 child +baz 2 child +baz 2 +Foo +Foo +FooParent +Bar +Bar +BarParent diff --git a/Zend/tests/dynamic_class_const_fetch_const_expr.phpt b/Zend/tests/dynamic_class_const_fetch_const_expr.phpt new file mode 100644 index 0000000000000..371f31e7f1ced --- /dev/null +++ b/Zend/tests/dynamic_class_const_fetch_const_expr.phpt @@ -0,0 +1,24 @@ +--TEST-- +Dynamic class constant fetch in constant expressions +--FILE-- + +--EXPECT-- +string(3) "bar" +string(3) "bar" +string(3) "bar" diff --git a/Zend/tests/dynamic_class_const_fetch_order.phpt b/Zend/tests/dynamic_class_const_fetch_order.phpt new file mode 100644 index 0000000000000..4003c7db928c7 --- /dev/null +++ b/Zend/tests/dynamic_class_const_fetch_order.phpt @@ -0,0 +1,37 @@ +--TEST-- +Dynamic class constant fetch DIM order +--FILE-- +getMessage(), "\n"; + } +} + +test(fn() => Foo::{foo()}::{bar()}); +test(fn() => Foo::{bar()}::{foo()}); + +?> +--EXPECT-- +foo() +bar() +Undefined constant Foo::BAR +bar() +Undefined constant Foo::BAR diff --git a/Zend/tests/enum/offsetGet-in-const-expr.phpt b/Zend/tests/enum/offsetGet-in-const-expr.phpt index 0928235ac2e8b..bd74f6b564b21 100644 --- a/Zend/tests/enum/offsetGet-in-const-expr.phpt +++ b/Zend/tests/enum/offsetGet-in-const-expr.phpt @@ -25,5 +25,6 @@ var_dump(X::FOO_BAR); --EXPECTF-- Fatal error: Uncaught Error: Cannot use [] on objects in constant expression in %s:%d Stack trace: -#0 {main} +#0 %s(%d): [constant expression]() +#1 {main} thrown in %s on line %d diff --git a/Zend/tests/fibers/get-return-after-bailout.phpt b/Zend/tests/fibers/get-return-after-bailout.phpt index 0f004070251b5..04bd464cfab0e 100644 --- a/Zend/tests/fibers/get-return-after-bailout.phpt +++ b/Zend/tests/fibers/get-return-after-bailout.phpt @@ -1,5 +1,12 @@ --TEST-- Fiber::getReturn() after bailout +--SKIPIF-- + --FILE-- = page_size + 1 * page_size' failed.) +--FILE-- +start(); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECTF-- +Fiber stack size is too small, it needs to be at least %d bytes diff --git a/Zend/tests/fibers/gh10340-001.phpt b/Zend/tests/fibers/gh10340-001.phpt new file mode 100644 index 0000000000000..0c34b4a787bce --- /dev/null +++ b/Zend/tests/fibers/gh10340-001.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug GH-10340 001 (Assertion in zend_fiber_object_gc()) +--FILE-- +start(); +gc_collect_cycles(); +?> +==DONE== +--EXPECTF-- +Warning: Undefined variable $y in %s on line %d +==DONE== diff --git a/Zend/tests/fibers/gh10340-002.phpt b/Zend/tests/fibers/gh10340-002.phpt new file mode 100644 index 0000000000000..6c8f8016cbf12 --- /dev/null +++ b/Zend/tests/fibers/gh10340-002.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug GH-10340 002 (Assertion in zend_fiber_object_gc()) +--FILE-- +start(); +gc_collect_cycles(); +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/fibers/gh10340-003.phpt b/Zend/tests/fibers/gh10340-003.phpt new file mode 100644 index 0000000000000..6e59223a2a9c9 --- /dev/null +++ b/Zend/tests/fibers/gh10340-003.phpt @@ -0,0 +1,38 @@ +--TEST-- +Bug GH-10340 003 (Assertion in zend_fiber_object_gc()) +--FILE-- +start(); + +print "1\n"; + +$fiber = null; +gc_collect_cycles(); + +print "2\n"; +?> +==DONE== +--EXPECT-- +1 +C::__destruct +2 +==DONE== diff --git a/Zend/tests/fibers/gh10437.phpt b/Zend/tests/fibers/gh10437.phpt new file mode 100644 index 0000000000000..5c793c986ee29 --- /dev/null +++ b/Zend/tests/fibers/gh10437.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-10437 (Segfault/assertion when using fibers in shutdown function after bailout) +--FILE-- +start(); + +?> +--EXPECTF-- +Fatal error: Bailout in fiber in %sgh10437.php on line %d +NULL diff --git a/Zend/tests/fibers/gh10496-001.phpt b/Zend/tests/fibers/gh10496-001.phpt new file mode 100644 index 0000000000000..9ca371fa2a6c5 --- /dev/null +++ b/Zend/tests/fibers/gh10496-001.phpt @@ -0,0 +1,33 @@ +--TEST-- +Bug GH-10496 001 (Segfault when garbage collector is invoked inside of fiber) +--FILE-- +start(); +unset($f); +gc_collect_cycles(); +print "Collected\n"; + +?> +--EXPECT-- +Cleaned +Dtor x() +Collected diff --git a/Zend/tests/fibers/gh10496-002.phpt b/Zend/tests/fibers/gh10496-002.phpt new file mode 100644 index 0000000000000..04ec43c7730bc --- /dev/null +++ b/Zend/tests/fibers/gh10496-002.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug GH-10496 002 (Segfault when garbage collector is invoked inside of fiber) +--FILE-- +start(); + })(); + })(); +}); +$f->start(); +$f->resume(); + +?> +--EXPECT-- +Success diff --git a/Zend/tests/fibers/gh9735-001.phpt b/Zend/tests/fibers/gh9735-001.phpt new file mode 100644 index 0000000000000..327e74323924a --- /dev/null +++ b/Zend/tests/fibers/gh9735-001.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bug GH-9735 001 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECT-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/fibers/gh9735-002.phpt b/Zend/tests/fibers/gh9735-002.phpt new file mode 100644 index 0000000000000..9a56c65f0abd9 --- /dev/null +++ b/Zend/tests/fibers/gh9735-002.phpt @@ -0,0 +1,41 @@ +--TEST-- +Bug GH-9735 002 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECT-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/fibers/gh9735-003.phpt b/Zend/tests/fibers/gh9735-003.phpt new file mode 100644 index 0000000000000..03ea973b61dd4 --- /dev/null +++ b/Zend/tests/fibers/gh9735-003.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug GH-9735 003 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECT-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/fibers/gh9735-004.phpt b/Zend/tests/fibers/gh9735-004.phpt new file mode 100644 index 0000000000000..cfcf381d83d08 --- /dev/null +++ b/Zend/tests/fibers/gh9735-004.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug GH-9735 004 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECT-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/fibers/gh9735-005.phpt b/Zend/tests/fibers/gh9735-005.phpt new file mode 100644 index 0000000000000..c18a42fc37082 --- /dev/null +++ b/Zend/tests/fibers/gh9735-005.phpt @@ -0,0 +1,44 @@ +--TEST-- +Bug GH-9735 005 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECTF-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/fibers/gh9735-006.phpt b/Zend/tests/fibers/gh9735-006.phpt new file mode 100644 index 0000000000000..59bb79d2404bc --- /dev/null +++ b/Zend/tests/fibers/gh9735-006.phpt @@ -0,0 +1,47 @@ +--TEST-- +Bug GH-9735 006 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECTF-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/fibers/gh9735-007.phpt b/Zend/tests/fibers/gh9735-007.phpt new file mode 100644 index 0000000000000..dbb6a33821119 --- /dev/null +++ b/Zend/tests/fibers/gh9735-007.phpt @@ -0,0 +1,47 @@ +--TEST-- +Bug GH-9735 007 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECTF-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/fibers/gh9735-008.phpt b/Zend/tests/fibers/gh9735-008.phpt new file mode 100644 index 0000000000000..ec6f29fb79de4 --- /dev/null +++ b/Zend/tests/fibers/gh9735-008.phpt @@ -0,0 +1,42 @@ +--TEST-- +Bug GH-9735 008 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECTF-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/fibers/gh9735-009.phpt b/Zend/tests/fibers/gh9735-009.phpt new file mode 100644 index 0000000000000..c471499443bd4 --- /dev/null +++ b/Zend/tests/fibers/gh9735-009.phpt @@ -0,0 +1,42 @@ +--TEST-- +Bug GH-9735 009 (Fiber stack variables do not participate in cycle collector) +--FILE-- +start(); +gc_collect_cycles(); + +print "2\n"; + +$fiber = null; +gc_collect_cycles(); + +print "3\n"; + +?> +--EXPECTF-- +1 +2 +C::__destruct +3 diff --git a/Zend/tests/generators/gh11028_1.phpt b/Zend/tests/generators/gh11028_1.phpt new file mode 100644 index 0000000000000..e1e7aa5019e54 --- /dev/null +++ b/Zend/tests/generators/gh11028_1.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-11028 (Heap Buffer Overflow in zval_undefined_cv with generators) - other types variant +--FILE-- + 0; + } finally { + return []; + } +} + +function test($msg, $x) { + echo "yield $msg\n"; + try { + var_dump([...generator($x)]); + } catch (Throwable $e) { + echo $e->getMessage(), "\n"; + } +} + +test("null", null); +test("false", false); +test("true", true); +test("object", new stdClass); +?> +--EXPECT-- +yield null +Keys must be of type int|string during array unpacking +yield false +Keys must be of type int|string during array unpacking +yield true +Keys must be of type int|string during array unpacking +yield object +Keys must be of type int|string during array unpacking diff --git a/Zend/tests/generators/gh11028_2.phpt b/Zend/tests/generators/gh11028_2.phpt new file mode 100644 index 0000000000000..27b36c711f5c1 --- /dev/null +++ b/Zend/tests/generators/gh11028_2.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-11028 (Heap Buffer Overflow in zval_undefined_cv with generators) - original variant +--FILE-- + 0; + } finally { + return []; + } + })()), + ]; +})()[0]; +?> +--EXPECTF-- +Warning: Undefined variable $a in %s on line %d + +Fatal error: Uncaught Error: Keys must be of type int|string during array unpacking in %s:%d +Stack trace: +#0 %s(%d): {closure}() +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/generators/gh11028_3.phpt b/Zend/tests/generators/gh11028_3.phpt new file mode 100644 index 0000000000000..7ea1aac6f6cfc --- /dev/null +++ b/Zend/tests/generators/gh11028_3.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-11028 (Heap Buffer Overflow in zval_undefined_cv with generators) - throw in finally variant +--FILE-- + 0; + } finally { + throw new Exception("exception"); + return []; + } +} + +try { + var_dump([...generator()]); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +exception diff --git a/Zend/tests/generators/gh9801.phpt b/Zend/tests/generators/gh9801.phpt index cc229ab0db89c..0d5990f9ba442 100644 --- a/Zend/tests/generators/gh9801.phpt +++ b/Zend/tests/generators/gh9801.phpt @@ -2,6 +2,13 @@ Bug GH-9801 (Crash when memory limit is exceeded during generator initialization) --INI-- memory_limit=16m +--SKIPIF-- + --FILE-- +--EXPECT-- +Trampoline for shutdown diff --git a/Zend/tests/gh10072.phpt b/Zend/tests/gh10072.phpt new file mode 100644 index 0000000000000..95a0d43450525 --- /dev/null +++ b/Zend/tests/gh10072.phpt @@ -0,0 +1,106 @@ +--TEST-- +GH-10072 (PHP crashes when execute_ex is overridden and a trampoline is used from internal code) +--EXTENSIONS-- +zend_test +--INI-- +zend_test.replace_zend_execute_ex=1 +opcache.jit=disable +--FILE-- +handle; + } + + + public function stream_close(): void + { + } + + public function stream_open(string $path, string $mode, int $options = 0, ?string &$openedPath = null): bool + { + return true; + } + + + public function stream_read(int $count) + { + return 0; + } + + + public function stream_seek(int $offset, int $whence = SEEK_SET): bool + { + return true; + } + + + public function stream_set_option(int $option, int $arg1, ?int $arg2): bool + { + return false; + } + + + public function stream_stat() + { + return []; + } + + + public function stream_tell() + { + return []; + } + + + public function stream_truncate(int $newSize): bool + { + return true; + } + + + public function stream_write(string $data) + { + } + + + public function unlink(string $path): bool + { + return false; + } +} + +class TrampolineTest { + /** @var resource|null */ + public $context; + + /** @var object|null */ + private $wrapper; + + public function __call(string $name, array $arguments) { + if (!$this->wrapper) { + $this->wrapper = new DummyStreamWrapper(); + } + echo 'Trampoline for ', $name, PHP_EOL; + return $this->wrapper->$name(...$arguments); + } + +} + +stream_wrapper_register('custom', TrampolineTest::class); + + +$fp = fopen("custom://myvar", "r+"); +?> +--EXPECT-- +Trampoline for stream_open +Trampoline for stream_close diff --git a/Zend/tests/gh10168/assign.phpt b/Zend/tests/gh10168/assign.phpt new file mode 100644 index 0000000000000..3c6740165d4a4 --- /dev/null +++ b/Zend/tests/gh10168/assign.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-10168: Assign +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_dim.phpt b/Zend/tests/gh10168/assign_dim.phpt new file mode 100644 index 0000000000000..1a31cfdde3b7d --- /dev/null +++ b/Zend/tests/gh10168/assign_dim.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-10168: Assign dim +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_dim_ref.phpt b/Zend/tests/gh10168/assign_dim_ref.phpt new file mode 100644 index 0000000000000..40ae4485d2cfb --- /dev/null +++ b/Zend/tests/gh10168/assign_dim_ref.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-10168: Assign dim ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_dim_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_dim_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..8415df433686a --- /dev/null +++ b/Zend/tests/gh10168/assign_dim_ref_with_prop_ref.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10168: Assign dim ref with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_dim_with_prop_ref.phpt b/Zend/tests/gh10168/assign_dim_with_prop_ref.phpt new file mode 100644 index 0000000000000..764d10d34658b --- /dev/null +++ b/Zend/tests/gh10168/assign_dim_with_prop_ref.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168: Assign dim with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_prop.phpt b/Zend/tests/gh10168/assign_prop.phpt new file mode 100644 index 0000000000000..ad7bb762f555b --- /dev/null +++ b/Zend/tests/gh10168/assign_prop.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168: Assign prop +--FILE-- +value = null; + } +} + +function test($box) { + var_dump($box->value = new Test); +} + +$box = new Box(); +$box->value = new Test; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} diff --git a/Zend/tests/gh10168/assign_prop_ref.phpt b/Zend/tests/gh10168/assign_prop_ref.phpt new file mode 100644 index 0000000000000..606542fbd6c6d --- /dev/null +++ b/Zend/tests/gh10168/assign_prop_ref.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168: Assign prop ref +--FILE-- +value = null; + } +} + +function test($box) { + $tmp = new Test; + var_dump($box->value = &$tmp); +} + +$box = new Box(); +$box->value = new Test; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +NULL +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..f887acbc1d06e --- /dev/null +++ b/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168: Assign prop ref with prop ref +--FILE-- +value = null; + } +} + +function test($box) { + $tmp = new Test; + var_dump($box->value = &$tmp); +} + +$box = new Box(); +$box->value = new Test; +Test::$test = &$box->value; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +NULL diff --git a/Zend/tests/gh10168/assign_prop_with_prop_ref.phpt b/Zend/tests/gh10168/assign_prop_with_prop_ref.phpt new file mode 100644 index 0000000000000..a08386e74565c --- /dev/null +++ b/Zend/tests/gh10168/assign_prop_with_prop_ref.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168: Assign prop with prop ref +--FILE-- +value = null; + } +} + +function test($box) { + var_dump($box->value = new Test); +} + +$box = new Box(); +$box->value = new Test; +Test::$test = &$box->value; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} diff --git a/Zend/tests/gh10168/assign_ref.phpt b/Zend/tests/gh10168/assign_ref.phpt new file mode 100644 index 0000000000000..9f3be5619d1ae --- /dev/null +++ b/Zend/tests/gh10168/assign_ref.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-10168: Assign ref +--FILE-- + +--EXPECT-- +NULL diff --git a/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..42ce94b3f83e1 --- /dev/null +++ b/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign ref with prop ref +--FILE-- + +--EXPECT-- +NULL diff --git a/Zend/tests/gh10168/assign_static_prop.phpt b/Zend/tests/gh10168/assign_static_prop.phpt new file mode 100644 index 0000000000000..900a69ae40aa5 --- /dev/null +++ b/Zend/tests/gh10168/assign_static_prop.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign static prop +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_prop_ref.phpt b/Zend/tests/gh10168/assign_static_prop_ref.phpt new file mode 100644 index 0000000000000..2e90be884dedd --- /dev/null +++ b/Zend/tests/gh10168/assign_static_prop_ref.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign static prop ref +--FILE-- + +--EXPECT-- +NULL diff --git a/Zend/tests/gh10168/assign_static_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_static_prop_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..df11b17e27819 --- /dev/null +++ b/Zend/tests/gh10168/assign_static_prop_ref_with_prop_ref.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-10168: Assign static prop ref with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_prop_with_prop_ref.phpt b/Zend/tests/gh10168/assign_static_prop_with_prop_ref.phpt new file mode 100644 index 0000000000000..c98233589c41f --- /dev/null +++ b/Zend/tests/gh10168/assign_static_prop_with_prop_ref.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10168: Assign static prop with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_untyped_prop.phpt b/Zend/tests/gh10168/assign_static_untyped_prop.phpt new file mode 100644 index 0000000000000..cf1736b6c58df --- /dev/null +++ b/Zend/tests/gh10168/assign_static_untyped_prop.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign static prop +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt b/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt new file mode 100644 index 0000000000000..dfef8ead26f6e --- /dev/null +++ b/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign static prop ref +--FILE-- + +--EXPECT-- +NULL diff --git a/Zend/tests/gh10168/assign_static_untyped_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_static_untyped_prop_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..337c9a8f1475f --- /dev/null +++ b/Zend/tests/gh10168/assign_static_untyped_prop_ref_with_prop_ref.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-10168: Assign static prop ref with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_untyped_prop_with_prop_ref.phpt b/Zend/tests/gh10168/assign_static_untyped_prop_with_prop_ref.phpt new file mode 100644 index 0000000000000..1b46cafaa0407 --- /dev/null +++ b/Zend/tests/gh10168/assign_static_untyped_prop_with_prop_ref.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10168: Assign static prop with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_untyped_prop.phpt b/Zend/tests/gh10168/assign_untyped_prop.phpt new file mode 100644 index 0000000000000..b13df3afbd87f --- /dev/null +++ b/Zend/tests/gh10168/assign_untyped_prop.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168: Assign prop +--FILE-- +value = null; + } +} + +function test($box) { + var_dump($box->value = new Test); +} + +$box = new Box(); +$box->value = new Test; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} diff --git a/Zend/tests/gh10168/assign_untyped_prop_ref.phpt b/Zend/tests/gh10168/assign_untyped_prop_ref.phpt new file mode 100644 index 0000000000000..a28395d43bbbc --- /dev/null +++ b/Zend/tests/gh10168/assign_untyped_prop_ref.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168: Assign prop ref +--FILE-- +value = null; + } +} + +function test($box) { + $tmp = new Test; + var_dump($box->value = &$tmp); +} + +$box = new Box(); +$box->value = new Test; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +NULL +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..79ff5fefc07ed --- /dev/null +++ b/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168: Assign prop ref with prop ref +--FILE-- +value = null; + } +} + +function test($box) { + $tmp = new Test; + var_dump($box->value = &$tmp); +} + +$box = new Box(); +$box->value = new Test; +Test::$test = &$box->value; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +NULL diff --git a/Zend/tests/gh10168/assign_untyped_prop_with_prop_ref.phpt b/Zend/tests/gh10168/assign_untyped_prop_with_prop_ref.phpt new file mode 100644 index 0000000000000..7e77ddf7da83f --- /dev/null +++ b/Zend/tests/gh10168/assign_untyped_prop_with_prop_ref.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168: Assign prop with prop ref +--FILE-- +value = null; + } +} + +function test($box) { + var_dump($box->value = new Test); +} + +$box = new Box(); +$box->value = new Test; +Test::$test = &$box->value; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} diff --git a/Zend/tests/gh10168/assign_with_prop_ref.phpt b/Zend/tests/gh10168/assign_with_prop_ref.phpt new file mode 100644 index 0000000000000..f3e8756514502 --- /dev/null +++ b/Zend/tests/gh10168/assign_with_prop_ref.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168: Assign with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/wrong_assign_to_variable.phpt b/Zend/tests/gh10168/wrong_assign_to_variable.phpt new file mode 100644 index 0000000000000..36fdecdfefcd5 --- /dev/null +++ b/Zend/tests/gh10168/wrong_assign_to_variable.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168: Wrong assign to variable +--FILE-- + +--EXPECTF-- +Notice: Only variables should be assigned by reference in %s on line %d +int(42) diff --git a/Zend/tests/gh10169.phpt b/Zend/tests/gh10169.phpt new file mode 100644 index 0000000000000..674122ac59359 --- /dev/null +++ b/Zend/tests/gh10169.phpt @@ -0,0 +1,37 @@ +--TEST-- +GH-10169: Fix use-after-free when releasing object during property assignment +--FILE-- +prop = new B(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$a = new A(); +$a->prop = ''; +try { + $a->prop = new B(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Object was released while assigning to property A::$prop +Object was released while assigning to property A::$prop diff --git a/Zend/tests/gh10251.phpt b/Zend/tests/gh10251.phpt new file mode 100644 index 0000000000000..da8d8767a3656 --- /dev/null +++ b/Zend/tests/gh10251.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-10251 (Assertion `(flag & (1<<3)) == 0' failed.) +--FILE-- +$p = $v; + } +} +$a = new A(); +$pp = ""; +$op = $pp & ""; +// Bitwise operators on strings don't compute the hash. +// The code below previously assumed a hash was actually computed, leading to a crash. +$a->$op = 0; +echo "Done\n"; +?> +--EXPECTF-- +Warning: Undefined variable $v in %s on line %d + +Warning: Undefined variable $p in %s on line %d +Done diff --git a/Zend/tests/gh10346.phpt b/Zend/tests/gh10346.phpt new file mode 100644 index 0000000000000..74fce28e2307c --- /dev/null +++ b/Zend/tests/gh10346.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-10346 (Observer: enum tryFrom() run_time_cache properly assigned) +--CREDITS-- +Florian Sowade +--EXTENSIONS-- +zend_test +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.observe_all=1 +--FILE-- + +--EXPECTF-- + + + + + + + +enum(Card::HEART) + + diff --git a/Zend/tests/gh10356.phpt b/Zend/tests/gh10356.phpt new file mode 100644 index 0000000000000..2a5418bc98e09 --- /dev/null +++ b/Zend/tests/gh10356.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10356: Incorrect line number of constant in constant expression +--FILE-- + DOES_NOT_EXIST, + ]; +} + +new Foo(); + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Undefined constant "DOES_NOT_EXIST" in %s:5 +Stack trace: +#0 %s(%d): [constant expression]() +#1 {main} + thrown in %s on line 5 diff --git a/Zend/tests/gh10377.phpt b/Zend/tests/gh10377.phpt new file mode 100644 index 0000000000000..c9e902ae739da --- /dev/null +++ b/Zend/tests/gh10377.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-10377 (Unable to have an anonymous readonly class) +--FILE-- +field = 2; + } +}; + +$anon = new class { + public int $field; + function __construct() { + $this->field = 2; + } +}; + +var_dump($readonly_anon->field); +try { + $readonly_anon->field = 123; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +var_dump($readonly_anon->field); + +var_dump($anon->field); +try { + $anon->field = 123; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +var_dump($anon->field); + +?> +--EXPECT-- +int(2) +Cannot modify readonly property class@anonymous::$field +int(2) +int(2) +int(123) diff --git a/Zend/tests/gh10377_1.phpt b/Zend/tests/gh10377_1.phpt new file mode 100644 index 0000000000000..ac421cb8a5171 --- /dev/null +++ b/Zend/tests/gh10377_1.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-10377 (Unable to have an anonymous readonly class) - usage variation: dynamic properties attribute +--FILE-- +field = 2; + } +}; + +?> +--EXPECTF-- +Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class class@anonymous in %s on line %d diff --git a/Zend/tests/gh10377_2.phpt b/Zend/tests/gh10377_2.phpt new file mode 100644 index 0000000000000..e2e5d4cf3d8d0 --- /dev/null +++ b/Zend/tests/gh10377_2.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-10377 (Unable to have an anonymous readonly class) - usage variation: abstract modifier +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use the abstract modifier on an anonymous class in %s on line %d diff --git a/Zend/tests/gh10377_3.phpt b/Zend/tests/gh10377_3.phpt new file mode 100644 index 0000000000000..d777eed5809c5 --- /dev/null +++ b/Zend/tests/gh10377_3.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-10377 (Unable to have an anonymous readonly class) - usage variation: final modifier +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use the final modifier on an anonymous class in %s on line %d diff --git a/Zend/tests/gh10377_4.phpt b/Zend/tests/gh10377_4.phpt new file mode 100644 index 0000000000000..730b15b6c53f5 --- /dev/null +++ b/Zend/tests/gh10377_4.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-10377 (Unable to have an anonymous readonly class) - usage variation: multiple readonly modifiers +--FILE-- + +--EXPECTF-- +Fatal error: Multiple readonly modifiers are not allowed in %s on line %d diff --git a/Zend/tests/gh10469.phpt b/Zend/tests/gh10469.phpt new file mode 100644 index 0000000000000..7a47afacdca98 --- /dev/null +++ b/Zend/tests/gh10469.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-10469: Disallow open_basedir() with parent dir components (..) +--FILE-- + +--CLEAN-- + +--EXPECTF-- +string(%d) "%stests" diff --git a/Zend/tests/gh10486.phpt b/Zend/tests/gh10486.phpt new file mode 100644 index 0000000000000..83dff538926d3 --- /dev/null +++ b/Zend/tests/gh10486.phpt @@ -0,0 +1,11 @@ +--TEST-- +Assertion error when attempting comp-time eval of dynamic class constant fetch +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Class "y" not found in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/gh10486_2.phpt b/Zend/tests/gh10486_2.phpt new file mode 100644 index 0000000000000..d62215a7771a5 --- /dev/null +++ b/Zend/tests/gh10486_2.phpt @@ -0,0 +1,11 @@ +--TEST-- +Assertion error when attempting constant eval of dynamic class constant fetch +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Undefined constant "y" in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/gh10570.phpt b/Zend/tests/gh10570.phpt new file mode 100644 index 0000000000000..edd35c1ca30ec --- /dev/null +++ b/Zend/tests/gh10570.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-10570 (Assertion `(key)->h != 0 && "Hash must be known"' failed.): constant variation +--FILE-- +{90}; + $a->{0} = 0; +} +?> +--EXPECTF-- +Warning: Undefined property: stdClass::$90 in %s on line %d + +Warning: Undefined property: stdClass::$90 in %s on line %d diff --git a/Zend/tests/gh10634.phpt b/Zend/tests/gh10634.phpt new file mode 100644 index 0000000000000..41407bf307d7f --- /dev/null +++ b/Zend/tests/gh10634.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-10634 (Lexing memory corruption) +--FILE-- +getMessage()); + } +} + +test_input("y&/*"); +test_input("y&/**"); +test_input("y&#"); +test_input("y&# "); +test_input("y&//"); +?> +--EXPECT-- +string(36) "Unterminated comment starting line 1" +string(36) "Unterminated comment starting line 1" +string(36) "syntax error, unexpected end of file" +string(36) "syntax error, unexpected end of file" +string(36) "syntax error, unexpected end of file" diff --git a/Zend/tests/gh10709.phpt b/Zend/tests/gh10709.phpt new file mode 100644 index 0000000000000..f394e1a7882db --- /dev/null +++ b/Zend/tests/gh10709.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10709: Recursive class constant evaluation +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +string(2) "AB" diff --git a/Zend/tests/gh10709_2.phpt b/Zend/tests/gh10709_2.phpt new file mode 100644 index 0000000000000..723fa29cc94bc --- /dev/null +++ b/Zend/tests/gh10709_2.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-10709: Recursive class constant evaluation +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +object(B)#2 (1) { + ["prop"]=> + string(1) "A" +} +object(B)#2 (1) { + ["prop"]=> + string(1) "A" +} diff --git a/Zend/tests/gh10709_3.phpt b/Zend/tests/gh10709_3.phpt new file mode 100644 index 0000000000000..1b0ccb5f8f276 --- /dev/null +++ b/Zend/tests/gh10709_3.phpt @@ -0,0 +1,43 @@ +--TEST-- +GH-10709: Recursive class constant evaluation with outer call failing +--FILE-- + +--EXPECTF-- +object(B)#3 (1) { + ["prop"]=> + string(2) "AS" +} + +Fatal error: Uncaught Exception: Thrown from S in %s:%d +Stack trace: +#0 %s(%d): [constant expression]() +#1 %s(%d): S->__toString() +#2 {main} + thrown in %s on line %d diff --git a/Zend/tests/gh10810.phpt b/Zend/tests/gh10810.phpt new file mode 100644 index 0000000000000..2539d5c7b40d6 --- /dev/null +++ b/Zend/tests/gh10810.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-10810: Fix NUL byte terminating Exception::__toString() +--FILE-- + +--EXPECTF-- +Exception: Hello%0World in %s:%d +Stack trace: +#0 {main} diff --git a/Zend/tests/gh10935.phpt b/Zend/tests/gh10935.phpt new file mode 100644 index 0000000000000..e84a9e5fdd26f --- /dev/null +++ b/Zend/tests/gh10935.phpt @@ -0,0 +1,83 @@ +--TEST-- +GH-1093: Add separate static property through trait if parent already declares it +--FILE-- + +--EXPECT-- +A::$test: A +A::getASelf(): A +A::getAStatic(): A +A::getFooSelf(): A +A::getFooStatic(): A +B::$test: B +B::getASelf(): A +B::getAStatic(): B +B::getBSelf(): B +B::getBStatic(): B +B::getFooSelf(): B +B::getFooStatic(): B +B::getBarSelf(): A +B::getBarStatic(): B diff --git a/Zend/tests/gh11016.phpt b/Zend/tests/gh11016.phpt new file mode 100644 index 0000000000000..7946166b176d3 --- /dev/null +++ b/Zend/tests/gh11016.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-11016 (Heap buffer overflow in ZEND_ADD_ARRAY_UNPACK_SPEC_HANDLER) +--FILE-- + 0, ...[1, 1, 1]]; +print_r($x); +?> +--EXPECT-- +Array +( + [6] => 0 + [7] => 1 + [8] => 1 + [9] => 1 +) diff --git a/Zend/tests/gh11108.phpt b/Zend/tests/gh11108.phpt new file mode 100644 index 0000000000000..efbd12dc367fa --- /dev/null +++ b/Zend/tests/gh11108.phpt @@ -0,0 +1,11 @@ +--TEST-- +GH-11108: Incorrect CG(memoize_mode) state after bailout in ??= +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use [] for reading in %s on line %d diff --git a/Zend/tests/gh11108_shutdown.inc b/Zend/tests/gh11108_shutdown.inc new file mode 100644 index 0000000000000..34f8131d4a840 --- /dev/null +++ b/Zend/tests/gh11108_shutdown.inc @@ -0,0 +1,5 @@ + +--CLEAN-- + +--EXPECT-- +bool(true) +foo diff --git a/Zend/tests/gh11152.phpt b/Zend/tests/gh11152.phpt new file mode 100644 index 0000000000000..4f0b7d9cbb031 --- /dev/null +++ b/Zend/tests/gh11152.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-11152: Allow aliasing namespaces containing reserved class names +--FILE-- + +--EXPECT-- +string(8) "string\C" diff --git a/Zend/tests/gh11171.phpt b/Zend/tests/gh11171.phpt new file mode 100644 index 0000000000000..8bda7da0b7b41 --- /dev/null +++ b/Zend/tests/gh11171.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-11171: Test +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + &string(4) "test" +} diff --git a/Zend/tests/gh11189.phpt b/Zend/tests/gh11189.phpt new file mode 100644 index 0000000000000..f1c877f20ee47 --- /dev/null +++ b/Zend/tests/gh11189.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-11189: Exceeding memory limit in zend_hash_do_resize leaves the array in an invalid state (packed array) +--SKIPIF-- + +--INI-- +memory_limit=2M +--FILE-- + 0; --$i) { + $a[] = 2; + } + fwrite(STDOUT, "Success"); +}); + +$a = []; +// trigger OOM in a resize operation +while (1) { + $a[] = 1; +} + +?> +--EXPECTF-- +Success +Fatal error: Allowed memory size of %s bytes exhausted%s(tried to allocate %s bytes) in %s on line %d diff --git a/Zend/tests/gh11189_1.phpt b/Zend/tests/gh11189_1.phpt new file mode 100644 index 0000000000000..53727908e5e2a --- /dev/null +++ b/Zend/tests/gh11189_1.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-11189: Exceeding memory limit in zend_hash_do_resize leaves the array in an invalid state (not packed array) +--SKIPIF-- + +--INI-- +memory_limit=2M +--FILE-- + 0; --$i) { + $a[] = 2; + } + fwrite(STDOUT, "Success"); +}); + +$a = ["not packed" => 1]; +// trigger OOM in a resize operation +while (1) { + $a[] = 1; +} + +?> +--EXPECTF-- +Success +Fatal error: Allowed memory size of %s bytes exhausted%s(tried to allocate %s bytes) in %s on line %d diff --git a/Zend/tests/gh7771_1.phpt b/Zend/tests/gh7771_1.phpt index dc24b4041c716..eee6379e15f28 100644 --- a/Zend/tests/gh7771_1.phpt +++ b/Zend/tests/gh7771_1.phpt @@ -11,5 +11,6 @@ new Foo(); --EXPECTF-- Fatal error: Uncaught Error: Class "NonExistent" not found in %sgh7771_1_definition.inc:4 Stack trace: -#0 {main} +#0 %sgh7771_1.php(5): [constant expression]() +#1 {main} thrown in %sgh7771_1_definition.inc on line 4 diff --git a/Zend/tests/gh7771_2.phpt b/Zend/tests/gh7771_2.phpt index 780c970407715..c8d865ee106d5 100644 --- a/Zend/tests/gh7771_2.phpt +++ b/Zend/tests/gh7771_2.phpt @@ -11,5 +11,6 @@ new Foo(); --EXPECTF-- Fatal error: Uncaught Error: Class "NonExistent" not found in %sgh7771_2_definition.inc:6 Stack trace: -#0 {main} +#0 %sgh7771_2.php(5): [constant expression]() +#1 {main} thrown in %sgh7771_2_definition.inc on line 6 diff --git a/Zend/tests/gh8821.phpt b/Zend/tests/gh8821.phpt new file mode 100644 index 0000000000000..e6abf5c1c4f1a --- /dev/null +++ b/Zend/tests/gh8821.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-8821: Fix reported line number of constant expression +--FILE-- + 3]; +} + +new Bravo(); + +?> +--EXPECTF-- +Fatal error: Uncaught TypeError: Cannot access offset of type object on array in %sgh8821.php:8 +Stack trace: +#0 %sgh8821.php(11): [constant expression]() +#1 {main} + thrown in %sgh8821.php on line 8 diff --git a/Zend/tests/gh8841.phpt b/Zend/tests/gh8841.phpt new file mode 100644 index 0000000000000..d99ca62c28773 --- /dev/null +++ b/Zend/tests/gh8841.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-8841 (php-cli core dump calling a badly formed function) +--FILE-- + +--EXPECTF-- +Fatal error: A void function must not return a value in %s on line %d +Before calling g() +After calling g() +Before calling f() + +Fatal error: Uncaught Error: Call to undefined function f() in %s:%d +Stack trace: +#0 [internal function]: {closure}() +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/gh9775_1.phpt b/Zend/tests/gh9775_1.phpt new file mode 100644 index 0000000000000..e2ea5287f5df9 --- /dev/null +++ b/Zend/tests/gh9775_1.phpt @@ -0,0 +1,56 @@ +--TEST-- +GH-9775: Backed enum in array_unique() +--FILE-- + +--EXPECT-- +array(8) { + [0]=> + enum(Test::COURSES_ADMIN) + [1]=> + enum(Test::COURSES_REPORTING_ACCESS) + [2]=> + enum(Test::BUNDLES_ADMIN) + [3]=> + enum(Test::USERS_ADMIN) + [4]=> + enum(Test::B2B_DASHBOARD_ACCESS) + [6]=> + enum(Test::INSTRUCTORS_ADMIN) + [8]=> + enum(Test::COUPONS_ADMIN) + [9]=> + enum(Test::AUTHENTICATED) +} diff --git a/Zend/tests/gh9775_2.phpt b/Zend/tests/gh9775_2.phpt new file mode 100644 index 0000000000000..94ef0029fa93d --- /dev/null +++ b/Zend/tests/gh9775_2.phpt @@ -0,0 +1,56 @@ +--TEST-- +GH-9775: Pure enum in array_unique() +--FILE-- + +--EXPECT-- +array(8) { + [0]=> + enum(Test::COURSES_ADMIN) + [1]=> + enum(Test::COURSES_REPORTING_ACCESS) + [2]=> + enum(Test::BUNDLES_ADMIN) + [3]=> + enum(Test::USERS_ADMIN) + [4]=> + enum(Test::B2B_DASHBOARD_ACCESS) + [6]=> + enum(Test::INSTRUCTORS_ADMIN) + [8]=> + enum(Test::COUPONS_ADMIN) + [9]=> + enum(Test::AUTHENTICATED) +} diff --git a/Zend/tests/gh9916-001.phpt b/Zend/tests/gh9916-001.phpt new file mode 100644 index 0000000000000..3e518807238bc --- /dev/null +++ b/Zend/tests/gh9916-001.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug GH-9916 001 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); + print "Not executed"; +}); +$fiber->start(); +?> +==DONE== +--EXPECT-- +Before suspend +==DONE== +Finally diff --git a/Zend/tests/gh9916-002.phpt b/Zend/tests/gh9916-002.phpt new file mode 100644 index 0000000000000..6f0b81cf3e91a --- /dev/null +++ b/Zend/tests/gh9916-002.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug GH-9916 002 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); + print "Not executed"; +}); +$fiber->start(); +?> +==DONE== +--EXPECT-- +Before suspend +==DONE== diff --git a/Zend/tests/gh9916-003.phpt b/Zend/tests/gh9916-003.phpt new file mode 100644 index 0000000000000..c4bfb815118bc --- /dev/null +++ b/Zend/tests/gh9916-003.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug GH-9916 003 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); + print "Not executed"; +}); +$fiber->start(); +?> +==DONE== +--EXPECT-- +Before suspend +==DONE== +Finally (inner) +Finally diff --git a/Zend/tests/gh9916-004.phpt b/Zend/tests/gh9916-004.phpt new file mode 100644 index 0000000000000..1a51a841e8bb6 --- /dev/null +++ b/Zend/tests/gh9916-004.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug GH-9916 004 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); + print "Not executed"; +}); +$fiber->start(); +?> +==DONE== +--EXPECT-- +Before suspend +==DONE== diff --git a/Zend/tests/gh9916-005.phpt b/Zend/tests/gh9916-005.phpt new file mode 100644 index 0000000000000..f84c756919cd0 --- /dev/null +++ b/Zend/tests/gh9916-005.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug GH-9916 005 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +send($fiber); + $gen->current(); +}); +$fiber->start(); + +$gen = null; +$fiber = null; +gc_collect_cycles(); +?> +==DONE== +--EXPECT-- +Before suspend +==DONE== diff --git a/Zend/tests/gh9916-006.phpt b/Zend/tests/gh9916-006.phpt new file mode 100644 index 0000000000000..28c57105c7b1f --- /dev/null +++ b/Zend/tests/gh9916-006.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bug GH-9916 006 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); + print "Fiber return\n"; +}); +$fiber->start(); +$fiber->resume(); +$gen->next(); +$gen->current(); +?> +==DONE== +--EXPECT-- +Before suspend +After suspend +Fiber return +Before exit diff --git a/Zend/tests/gh9916-007.phpt b/Zend/tests/gh9916-007.phpt new file mode 100644 index 0000000000000..e1ec3fb19f32b --- /dev/null +++ b/Zend/tests/gh9916-007.phpt @@ -0,0 +1,57 @@ +--TEST-- +Bug GH-9916 007 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); + print "Not executed"; +}); +$fiber->start(); +?> +==DONE== +--EXPECT-- +Before suspend +==DONE== +Finally (iterator) +Finally diff --git a/Zend/tests/gh9916-008.phpt b/Zend/tests/gh9916-008.phpt new file mode 100644 index 0000000000000..84521d69e2120 --- /dev/null +++ b/Zend/tests/gh9916-008.phpt @@ -0,0 +1,47 @@ +--TEST-- +Bug GH-9916 008 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); + print "Not executed"; +}); +$fiber->start(); +?> +==DONE== +--EXPECT-- +Before suspend +==DONE== diff --git a/Zend/tests/gh9916-009.phpt b/Zend/tests/gh9916-009.phpt new file mode 100644 index 0000000000000..75643d871dea0 --- /dev/null +++ b/Zend/tests/gh9916-009.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug GH-9916 009 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- + new stdClass]; + print "Not executed\n"; + } +})(); +$fiber = new Fiber(function() use ($gen, &$fiber) { + $gen->current(); + print "Not executed\n"; +}); +$fiber->start(); +?> +==DONE== +--EXPECTF-- +Before suspend +==DONE== +Finally + +Fatal error: Uncaught Error: Cannot use "yield from" in a force-closed generator in %s:%d +Stack trace: +#0 [internal function]: {closure}() +#1 %s(%d): Generator->current() +#2 [internal function]: {closure}() +#3 {main} + thrown in %s on line %d diff --git a/Zend/tests/gh9916-010.phpt b/Zend/tests/gh9916-010.phpt new file mode 100644 index 0000000000000..d3a841d7ceb31 --- /dev/null +++ b/Zend/tests/gh9916-010.phpt @@ -0,0 +1,34 @@ +--TEST-- +Bug GH-9916 010 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); + print "Before next\n"; + $gen->next(); + print "Not executed\n"; +}); + +$fiber->start(); +?> +==DONE== +--EXPECT-- +Before current +Before yield +Before yield 2 +Before next +Before suspend +==DONE== diff --git a/Zend/tests/gh9916-011.phpt b/Zend/tests/gh9916-011.phpt new file mode 100644 index 0000000000000..05fa884c29337 --- /dev/null +++ b/Zend/tests/gh9916-011.phpt @@ -0,0 +1,41 @@ +--TEST-- +Bug GH-9916 011 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +next(); + } +})(); + +$fiber = new Fiber(function () use ($gen, &$fiber) { + print "Before current\n"; + $gen->current(); + print "Before next\n"; + $gen->next(); + print "Not executed\n"; +}); + +$fiber->start(); +?> +==DONE== +--EXPECT-- +Before current +Before yield +Before yield 2 +Before next +Before suspend +==DONE== diff --git a/Zend/tests/gh9916-012.phpt b/Zend/tests/gh9916-012.phpt new file mode 100644 index 0000000000000..cd31ea1215b64 --- /dev/null +++ b/Zend/tests/gh9916-012.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug GH-9916 012 (Entering shutdown sequence with a fiber suspended in a Generator emits an unavoidable fatal error or crashes) +--FILE-- +current(); +}); +$fiber->start(); + +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/illegal_offset_unset_isset_empty.phpt b/Zend/tests/illegal_offset_unset_isset_empty.phpt index 9005053e67ed8..a09613748281b 100644 --- a/Zend/tests/illegal_offset_unset_isset_empty.phpt +++ b/Zend/tests/illegal_offset_unset_isset_empty.phpt @@ -22,6 +22,6 @@ try { ?> --EXPECT-- -Illegal offset type in unset -Illegal offset type in isset or empty -Illegal offset type in isset or empty +Cannot access offset of type array in unset +Cannot access offset of type array in isset or empty +Cannot access offset of type array in isset or empty diff --git a/Zend/tests/init_array_illegal_offset_type.phpt b/Zend/tests/init_array_illegal_offset_type.phpt index 2243ca2905ea0..2e5a0401d6e4a 100644 --- a/Zend/tests/init_array_illegal_offset_type.phpt +++ b/Zend/tests/init_array_illegal_offset_type.phpt @@ -12,4 +12,4 @@ try { } ?> --EXPECT-- -Illegal offset type +Cannot access offset of type object on array diff --git a/Zend/tests/isset_003.phpt b/Zend/tests/isset_003.phpt index 6979a847af74d..9a0d201fa5341 100644 --- a/Zend/tests/isset_003.phpt +++ b/Zend/tests/isset_003.phpt @@ -33,7 +33,7 @@ Warning: Undefined variable $c in %s on line %d Warning: Undefined variable $d in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Warning: Attempt to read property "" on string in %s on line %d bool(false) diff --git a/Zend/tests/isset_array.phpt b/Zend/tests/isset_array.phpt index 4a0652ae39d5f..792483294805d 100644 --- a/Zend/tests/isset_array.phpt +++ b/Zend/tests/isset_array.phpt @@ -46,5 +46,5 @@ bool(false) Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d bool(false) -Illegal offset type in isset or empty -Illegal offset type in isset or empty +Cannot access offset of type array in isset or empty +Cannot access offset of type object in isset or empty diff --git a/Zend/tests/match/gh11134.phpt b/Zend/tests/match/gh11134.phpt new file mode 100644 index 0000000000000..94e3223d2a07a --- /dev/null +++ b/Zend/tests/match/gh11134.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-11134: Incorrect match optimization +--FILE-- + 'foo', + 'bar' => 'bar', + default => 'baz', + }; +} + +function testSwitch() { + switch ($unset ?? null) { + case 'foo': return 'foo'; + case 'bar': return 'bar'; + default: return 'baz'; + } +} + +var_dump(testMatch()); +var_dump(testSwitch()); + +?> +--EXPECT-- +string(3) "baz" +string(3) "baz" diff --git a/Zend/tests/nullsafe_operator/002.phpt b/Zend/tests/nullsafe_operator/002.phpt index 46c1bb623f6e5..87642bdcb5f08 100644 --- a/Zend/tests/nullsafe_operator/002.phpt +++ b/Zend/tests/nullsafe_operator/002.phpt @@ -35,7 +35,7 @@ try { ?> --EXPECT-- -string(39) "Call to a member function bar() on bool" +string(40) "Call to a member function bar() on false" string(40) "Call to a member function bar() on array" string(38) "Call to a member function bar() on int" string(40) "Call to a member function bar() on float" diff --git a/Zend/tests/offset_array.phpt b/Zend/tests/offset_array.phpt index 0109950cde848..e44244511fcf1 100644 --- a/Zend/tests/offset_array.phpt +++ b/Zend/tests/offset_array.phpt @@ -48,6 +48,6 @@ int(1) Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d int(%d) -Illegal offset type -Illegal offset type +Cannot access offset of type object on array +Cannot access offset of type array on array Done diff --git a/Zend/tests/offset_bool.phpt b/Zend/tests/offset_bool.phpt index ae8df6d2b5b40..2cb2ccf47b6eb 100644 --- a/Zend/tests/offset_bool.phpt +++ b/Zend/tests/offset_bool.phpt @@ -25,30 +25,30 @@ var_dump($bool[$arr]); echo "Done\n"; ?> --EXPECTF-- -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL -Warning: Trying to access array offset on value of type bool in %s on line %d +Warning: Trying to access array offset on true in %s on line %d NULL Done diff --git a/Zend/tests/offset_long.phpt b/Zend/tests/offset_long.phpt index 17dfe0d29bf74..1d217c32b95f4 100644 --- a/Zend/tests/offset_long.phpt +++ b/Zend/tests/offset_long.phpt @@ -25,30 +25,30 @@ var_dump($long[$arr]); echo "Done\n"; ?> --EXPECTF-- -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL -Warning: Trying to access array offset on value of type int in %s on line %d +Warning: Trying to access array offset on int in %s on line %d NULL Done diff --git a/Zend/tests/offset_null.phpt b/Zend/tests/offset_null.phpt index ae02eece77ca3..bde9407539729 100644 --- a/Zend/tests/offset_null.phpt +++ b/Zend/tests/offset_null.phpt @@ -25,30 +25,30 @@ var_dump($null[$arr]); echo "Done\n"; ?> --EXPECTF-- -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL Done diff --git a/Zend/tests/oss_fuzz_57821.phpt b/Zend/tests/oss_fuzz_57821.phpt new file mode 100644 index 0000000000000..5c6e9fab9a8e9 --- /dev/null +++ b/Zend/tests/oss_fuzz_57821.phpt @@ -0,0 +1,12 @@ +--TEST-- +oss-fuzz #57821: Unevaluated rhs of class constant fetch in constant expression +--FILE-- + +--EXPECT-- +string(3) "foo" diff --git a/Zend/tests/oss_fuzz_58181.phpt b/Zend/tests/oss_fuzz_58181.phpt new file mode 100644 index 0000000000000..36a0ba16d623e --- /dev/null +++ b/Zend/tests/oss_fuzz_58181.phpt @@ -0,0 +1,14 @@ +--TEST-- +oss-fuzz #58181: Fix unexpected reference returned from CallbackFilterIterator::accept() +--FILE-- + true); + $iterator->rewind(); +} + +test(['a', 'b']); +?> +--EXPECTF-- +Notice: Only variable references should be returned by reference in %s on line %d diff --git a/Zend/tests/prop_const_expr/basic_nullsafe.phpt b/Zend/tests/prop_const_expr/basic_nullsafe.phpt index da870c0328b0a..6601f362c826b 100644 --- a/Zend/tests/prop_const_expr/basic_nullsafe.phpt +++ b/Zend/tests/prop_const_expr/basic_nullsafe.phpt @@ -39,7 +39,7 @@ Warning: Attempt to read property "test" on null in %s on line %d NULL NULL -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL NULL Printer diff --git a/Zend/tests/readonly_props/readonly_assign_no_sideeffect.phpt b/Zend/tests/readonly_props/readonly_assign_no_sideeffect.phpt new file mode 100644 index 0000000000000..29218d837d7fb --- /dev/null +++ b/Zend/tests/readonly_props/readonly_assign_no_sideeffect.phpt @@ -0,0 +1,33 @@ +--TEST-- +Test that there can be no side-effect when a readonly property modification fails +--FILE-- +bar = new S(); + } +} + +class S { + public function __toString() { + var_dump("Side-effect in __toString()"); + return ""; + } +} + +$foo = new Foo(""); + +try { + $foo->write(); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot modify readonly property Foo::$bar diff --git a/Zend/tests/readonly_props/readonly_clone_error1.phpt b/Zend/tests/readonly_props/readonly_clone_error1.phpt new file mode 100644 index 0000000000000..98829d175765d --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_error1.phpt @@ -0,0 +1,36 @@ +--TEST-- +Readonly property cannot be reset twice during cloning +--FILE-- +bar = 2; + var_dump($this); + $this->bar = 3; + } +} + +$foo = new Foo(1); + +try { + clone $foo; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +echo "done"; + +?> +--EXPECT-- +object(Foo)#2 (1) { + ["bar"]=> + int(2) +} +Cannot modify readonly property Foo::$bar +done diff --git a/Zend/tests/readonly_props/readonly_clone_error2.phpt b/Zend/tests/readonly_props/readonly_clone_error2.phpt new file mode 100644 index 0000000000000..e1e42abad074c --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_error2.phpt @@ -0,0 +1,42 @@ +--TEST-- +Readonly property cannot be reset after cloning when there is no custom clone handler +--FILE-- +bar++; + } + + public function wrongCloneNew() + { + $instance = clone $this; + $instance->baz++; + } +} + +$foo = new Foo(1, 1); + +try { + $foo->wrongCloneOld(); +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $foo->wrongCloneNew(); +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot modify readonly property Foo::$bar +Cannot modify readonly property Foo::$baz diff --git a/Zend/tests/readonly_props/readonly_clone_error3.phpt b/Zend/tests/readonly_props/readonly_clone_error3.phpt new file mode 100644 index 0000000000000..a51ec165c68c3 --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_error3.phpt @@ -0,0 +1,44 @@ +--TEST-- +Readonly property cannot be reset after cloning when there is a custom clone handler +--FILE-- +bar++; + } + + public function wrongCloneNew() + { + $instance = clone $this; + $instance->baz++; + } +} + +$foo = new Foo(1, 1); + +try { + $foo->wrongCloneOld(); +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + $foo->wrongCloneNew(); +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot modify readonly property Foo::$bar +Cannot modify readonly property Foo::$baz diff --git a/Zend/tests/readonly_props/readonly_clone_error4.phpt b/Zend/tests/readonly_props/readonly_clone_error4.phpt new file mode 100644 index 0000000000000..f9edcbcbaa18e --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_error4.phpt @@ -0,0 +1,44 @@ +--TEST-- +Readonly property cannot be op-assigned twice during cloning +--FILE-- +bar += 2; + var_dump($this); + $this->bar += 3; + } +} + +$foo = new Foo(1); + +try { + clone $foo; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + clone $foo; +} catch (Error $exception) { + echo $exception->getMessage() . "\n"; +} + +?> +--EXPECT-- +object(Foo)#2 (1) { + ["bar"]=> + int(3) +} +Cannot modify readonly property Foo::$bar +object(Foo)#2 (1) { + ["bar"]=> + int(3) +} +Cannot modify readonly property Foo::$bar diff --git a/Zend/tests/readonly_props/readonly_clone_error5.phpt b/Zend/tests/readonly_props/readonly_clone_error5.phpt new file mode 100644 index 0000000000000..c6651b54edb85 --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_error5.phpt @@ -0,0 +1,76 @@ +--TEST-- +Readonly property clone indirect variation for JIT +--FILE-- +prop[] = 1; + } +} + +trait CloneSetTwiceTrait { + public function __clone() { + $this->prop[] = 1; + $this->prop[] = 2; + } +} + +class TestSetOnce { + use CloneSetOnceTrait; + public readonly array $prop; + public function __construct() { + $this->prop = []; + } +} + +class TestSetTwice { + use CloneSetTwiceTrait; + public readonly array $prop; + public function __construct() { + $this->prop = []; + } +} + +try { + var_dump(clone (new TestSetOnce())); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + var_dump(clone (new TestSetOnce())); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + var_dump(clone (new TestSetTwice())); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + var_dump(clone (new TestSetTwice())); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +object(TestSetOnce)#2 (1) { + ["prop"]=> + array(1) { + [0]=> + int(1) + } +} +object(TestSetOnce)#1 (1) { + ["prop"]=> + array(1) { + [0]=> + int(1) + } +} +Cannot modify readonly property TestSetTwice::$prop +Cannot modify readonly property TestSetTwice::$prop diff --git a/Zend/tests/readonly_props/readonly_clone_error6.phpt b/Zend/tests/readonly_props/readonly_clone_error6.phpt new file mode 100644 index 0000000000000..16a04d802a11f --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_error6.phpt @@ -0,0 +1,47 @@ +--TEST-- +Test that readonly properties cannot be reassigned by invoking the __clone() method directly +--FILE-- +bar = 1; + } +} + +$foo = new Foo(0); + +var_dump($foo); + +try { + $foo->__clone(); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $foo->__clone(); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +var_dump($foo); + +?> +--EXPECTF-- +object(Foo)#%d (%d) { + ["bar"]=> + int(0) +} +Cannot modify readonly property Foo::$bar +Cannot modify readonly property Foo::$bar +object(Foo)#%d (%d) { + ["bar"]=> + int(0) +} diff --git a/Zend/tests/readonly_props/readonly_clone_success1.phpt b/Zend/tests/readonly_props/readonly_clone_success1.phpt new file mode 100644 index 0000000000000..72cd9e9622b33 --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_success1.phpt @@ -0,0 +1,39 @@ +--TEST-- +Readonly property can be reset once during cloning +--FILE-- +bar++; + } +} + +$foo = new Foo(1); + +var_dump(clone $foo); + +$foo2 = clone $foo; +var_dump($foo2); + +var_dump(clone $foo2); + +?> +--EXPECTF-- +object(Foo)#%d (%d) { + ["bar"]=> + int(2) +} +object(Foo)#%d (%d) { + ["bar"]=> + int(2) +} +object(Foo)#%d (%d) { + ["bar"]=> + int(3) +} diff --git a/Zend/tests/readonly_props/readonly_clone_success2.phpt b/Zend/tests/readonly_props/readonly_clone_success2.phpt new file mode 100644 index 0000000000000..98faba3909518 --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_success2.phpt @@ -0,0 +1,46 @@ +--TEST-- +Test that __clone() unset and reassign properties +--FILE-- +bar); + var_dump($this); + $this->bar = new stdClass(); + } +} + +$foo = new Foo(new stdClass()); +var_dump($foo); +$foo2 = clone $foo; + +var_dump($foo); +var_dump($foo2); + +?> +--EXPECTF-- +object(Foo)#1 (%d) { + ["bar"]=> + object(stdClass)#2 (%d) { + } +} +object(Foo)#3 (%d) { + ["bar"]=> + uninitialized(stdClass) +} +object(Foo)#1 (%d) { + ["bar"]=> + object(stdClass)#2 (%d) { + } +} +object(Foo)#3 (%d) { + ["bar"]=> + object(stdClass)#4 (%d) { + } +} diff --git a/Zend/tests/readonly_props/readonly_clone_success3.phpt b/Zend/tests/readonly_props/readonly_clone_success3.phpt new file mode 100644 index 0000000000000..93c3bd8f47f62 --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_success3.phpt @@ -0,0 +1,37 @@ +--TEST-- +__clone() can indirectly modify unlocked readonly properties +--FILE-- +bar['bar'] = 'bar'; + } +} + +$foo = new Foo([]); +// First call fills the cache slot +var_dump(clone $foo); +var_dump(clone $foo); + +?> +--EXPECTF-- +object(Foo)#2 (%d) { + ["bar"]=> + array(1) { + ["bar"]=> + string(3) "bar" + } +} +object(Foo)#2 (%d) { + ["bar"]=> + array(1) { + ["bar"]=> + string(3) "bar" + } +} diff --git a/Zend/tests/readonly_props/readonly_clone_success4.phpt b/Zend/tests/readonly_props/readonly_clone_success4.phpt new file mode 100644 index 0000000000000..40b7a29e31265 --- /dev/null +++ b/Zend/tests/readonly_props/readonly_clone_success4.phpt @@ -0,0 +1,39 @@ +--TEST-- +Readonly property can be reset once during cloning even after a type error +--FILE-- +bar = "foo"; + } catch (Error $e) { + echo $e->getMessage() . "\n"; + } + + $this->bar = 2; + } +} + +$foo = new Foo(1); + +var_dump(clone $foo); +var_dump(clone $foo); + +?> +--EXPECTF-- +Cannot assign string to property Foo::$bar of type int +object(Foo)#%d (%d) { + ["bar"]=> + int(2) +} +Cannot assign string to property Foo::$bar of type int +object(Foo)#%d (%d) { + ["bar"]=> + int(2) +} diff --git a/Zend/tests/readonly_props/readonly_coercion_type_error.phpt b/Zend/tests/readonly_props/readonly_coercion_type_error.phpt new file mode 100644 index 0000000000000..d41211d8e9981 --- /dev/null +++ b/Zend/tests/readonly_props/readonly_coercion_type_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test failing readonly assignment with coercion +--FILE-- +bar = 'bar'; + try { + $this->bar = 42; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + } +} + +new Foo(); + +?> +--EXPECTF-- +Cannot modify readonly property Foo::$bar diff --git a/Zend/tests/stack_limit/stack_limit_001.phpt b/Zend/tests/stack_limit/stack_limit_001.phpt new file mode 100644 index 0000000000000..ca185635c39c8 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_001.phpt @@ -0,0 +1,82 @@ +--TEST-- +Stack limit 001 - Stack limit checks with max_allowed_stack_size detection +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +; The test may use a large amount of memory on systems with a large stack limit +memory_limit=2G +--FILE-- +getMessage(), "\n"; +} + +try { + clone new Test2; +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + serialize(new Test3); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + replace(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? diff --git a/Zend/tests/stack_limit/stack_limit_002.phpt b/Zend/tests/stack_limit/stack_limit_002.phpt new file mode 100644 index 0000000000000..309de9bf6a2a3 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_002.phpt @@ -0,0 +1,85 @@ +--TEST-- +Stack limit 002 - Stack limit checks with max_allowed_stack_size detection (fibers) +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +fiber.stack_size=512k +--FILE-- +getMessage(), "\n"; + } + + try { + clone new Test2; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + + try { + serialize(new Test3); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + + try { + replace(); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } +}); + +$fiber->start(); + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? diff --git a/Zend/tests/stack_limit/stack_limit_003.phpt b/Zend/tests/stack_limit/stack_limit_003.phpt new file mode 100644 index 0000000000000..9eb94a971636f --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_003.phpt @@ -0,0 +1,66 @@ +--TEST-- +Stack limit 003 - Stack limit checks with fixed max_allowed_stack_size +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +getMessage(), "\n"; +} + +try { + clone new Test2; +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + replace(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? diff --git a/Zend/tests/stack_limit/stack_limit_004.phpt b/Zend/tests/stack_limit/stack_limit_004.phpt new file mode 100644 index 0000000000000..141a24babb961 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_004.phpt @@ -0,0 +1,54 @@ +--TEST-- +Stack limit 004 - Stack limit checks with fixed max_allowed_stack_size (fibers) +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--FILE-- +getTrace()); + } + + throw new \Exception(); +}; + +ini_set('fiber.stack_size', '400K'); +$fiber = new Fiber($callback); +$fiber->start(); +$depth1 = $fiber->getReturn(); + +ini_set('fiber.stack_size', '200K'); +$fiber = new Fiber($callback); +$fiber->start(); +$depth2 = $fiber->getReturn(); + +var_dump($depth1 > $depth2); + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +bool(true) diff --git a/Zend/tests/stack_limit/stack_limit_005.phpt b/Zend/tests/stack_limit/stack_limit_005.phpt new file mode 100644 index 0000000000000..3fcd5d5728276 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_005.phpt @@ -0,0 +1,68 @@ +--TEST-- +Stack limit 005 - Internal stack limit check in zend_compile_expr() +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() +; + +--EXPECTF-- +Fatal error: Maximum call stack size of %d bytes reached during compilation. Try splitting expression in %s on line %d diff --git a/Zend/tests/stack_limit/stack_limit_006.phpt b/Zend/tests/stack_limit/stack_limit_006.phpt new file mode 100644 index 0000000000000..0b51fabb4babd --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_006.phpt @@ -0,0 +1,325 @@ +--TEST-- +Stack limit 006 - env size affects __libc_stack_end +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +; TODO +memory_limit=2G +--ENV-- +ENV001=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV002=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV003=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV004=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV005=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV006=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV007=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV008=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV009=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV010=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV011=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV012=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV013=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV014=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV015=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV016=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV017=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV018=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV019=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV020=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV021=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV022=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV023=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV024=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV025=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV026=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV027=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV028=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV029=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV030=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV031=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV032=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV033=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV034=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV035=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV036=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV037=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV038=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV039=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV040=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV041=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV042=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV043=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV044=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV045=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV046=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV047=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV048=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV049=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV050=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV051=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV052=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV053=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV054=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV055=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV056=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV057=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV058=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV059=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV060=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV061=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV062=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV063=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV064=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV065=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV066=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV067=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV068=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV069=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV070=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV071=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV072=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV073=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV074=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV075=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV076=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV077=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV078=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV079=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV080=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV081=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV082=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV083=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV084=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV085=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV086=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV087=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV088=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV089=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV090=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV091=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV092=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV093=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV094=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV095=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV096=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV097=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV098=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV099=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV100=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV101=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV102=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV103=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV104=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV105=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV106=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV107=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV108=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV109=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV110=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV111=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV112=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV113=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV114=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV115=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV116=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV117=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV118=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV119=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV120=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV121=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV122=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV123=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV124=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV125=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV126=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV127=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV128=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV129=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV130=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV131=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV132=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV133=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV134=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV135=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV136=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV137=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV138=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV139=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV140=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV141=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV142=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV143=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV144=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV145=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV146=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV147=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV148=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV149=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV150=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV151=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV152=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV153=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV154=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV155=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV156=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV157=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV158=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV159=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV160=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV161=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV162=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV163=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV164=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV165=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV166=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV167=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV168=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV169=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV170=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV171=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV172=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV173=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV174=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV175=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV176=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV177=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV178=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV179=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV180=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV181=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV182=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV183=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV184=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV185=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV186=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV187=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV188=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV189=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV190=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV191=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV192=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV193=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV194=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV195=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV196=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV197=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV198=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV199=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV200=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV201=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV202=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV203=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV204=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV205=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV206=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV207=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV208=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV209=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV210=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV211=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV212=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV213=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV214=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV215=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV216=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV217=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV218=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV219=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV220=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV221=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV222=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV223=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV224=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV225=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV226=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV227=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV228=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV229=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV230=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV231=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV232=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV233=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV234=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV235=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV236=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV237=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV238=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV239=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV240=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV241=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV242=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV243=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV244=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV245=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV246=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV247=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV248=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV249=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV250=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV251=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV252=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV253=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV254=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV255=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV256=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +--FILE-- +getMessage(), "\n"; +} + +try { + clone new Test2; +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +try { + replace(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? +Maximum call stack size of %d bytes reached. Infinite recursion? diff --git a/Zend/tests/stack_limit/stack_limit_007.phpt b/Zend/tests/stack_limit/stack_limit_007.phpt new file mode 100644 index 0000000000000..411af1d2c6894 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_007.phpt @@ -0,0 +1,45 @@ +--TEST-- +Stack limit 007 - Exception handling +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +getMessage(), "\n"; + // We should not enter the catch block if we haven't executed at + // least one op in the try block + printf("Try executed: %d\n", $tryExecuted ?? 0); + } + }, 'x'); +} + +replace(); + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +Maximum call stack size of %d bytes reached. Infinite recursion? +Try executed: 1 diff --git a/Zend/tests/stack_limit/stack_limit_008.phpt b/Zend/tests/stack_limit/stack_limit_008.phpt new file mode 100644 index 0000000000000..56ff6f18bdce6 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_008.phpt @@ -0,0 +1,58 @@ +--TEST-- +Stack limit 008 - Exception handling +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +getMessage(); + } + } + }, 'x'); +} + +function replace2() { + return preg_replace_callback('#.#', function () { + try { + return ''; + } finally { + // We should not enter the finally block if we haven't executed at + // least one op in the try block + echo "Finally block: This should not execute\n"; + } + }, 'x'); +} + +replace(); + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +Will throw: +Maximum call stack size of %d bytes reached. Infinite recursion? diff --git a/Zend/tests/stack_limit/stack_limit_009.phpt b/Zend/tests/stack_limit/stack_limit_009.phpt new file mode 100644 index 0000000000000..f17ecb5ede2e8 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_009.phpt @@ -0,0 +1,29 @@ +--TEST-- +Stack limit 009 - Check that we can actually use all the stack +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +int(%d) diff --git a/Zend/tests/stack_limit/stack_limit_010.phpt b/Zend/tests/stack_limit/stack_limit_010.phpt new file mode 100644 index 0000000000000..312c2cf551696 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_010.phpt @@ -0,0 +1,49 @@ +--TEST-- +Stack limit 010 - Check stack size detection against known defaults +--EXTENSIONS-- +zend_test +--SKIPIF-- + +--FILE-- + 8*1024*1024, + 'FreeBSD' => match(php_uname('m')) { + 'amd64' => 512*1024*1024 - 4096, + 'i386' => 64*1024*1024 - 4096, + }, + 'Linux' => match (getenv('GITHUB_ACTIONS')) { + 'true' => 16*1024*1024, // https://github.com/actions/runner-images/pull/3328 + default => 8*1024*1024, + }, + 'Windows NT' => 67108864 - 4*4096, // Set by sapi/cli/config.w32 +}; + +printf("Expected max_size: 0x%x\n", $expectedMaxSize); +printf("Actual max_size: %s\n", $stack['max_size']); + +var_dump($stack['max_size'] === sprintf('0x%x', $expectedMaxSize)); + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +Expected max_size: 0x%x +Actual max_size: 0x%x +bool(true) diff --git a/Zend/tests/stack_limit/stack_limit_011.phpt b/Zend/tests/stack_limit/stack_limit_011.phpt new file mode 100644 index 0000000000000..6155525675c32 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_011.phpt @@ -0,0 +1,52 @@ +--TEST-- +Stack limit 011 - Stack limit exhaustion during unwinding +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +getMessage(), "\n"; + echo 'Previous: ', $e->getPrevious()->getMessage(), "\n"; +} + +?> +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} +Maximum call stack size of %d bytes reached. Infinite recursion? +Previous: Maximum call stack size of %d bytes reached. Infinite recursion? diff --git a/Zend/tests/stack_limit/stack_limit_012.inc b/Zend/tests/stack_limit/stack_limit_012.inc new file mode 100644 index 0000000000000..f6ad9c7428a90 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_012.inc @@ -0,0 +1,54 @@ +f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() +; diff --git a/Zend/tests/stack_limit/stack_limit_012.phpt b/Zend/tests/stack_limit/stack_limit_012.phpt new file mode 100644 index 0000000000000..ed5189f37cad3 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_012.phpt @@ -0,0 +1,41 @@ +--TEST-- +Stack limit 012 - Stack limit exhaustion during unwinding +--SKIPIF-- + +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- + +--EXPECTF-- +array(4) { + ["base"]=> + string(%d) "0x%x" + ["max_size"]=> + string(%d) "0x%x" + ["position"]=> + string(%d) "0x%x" + ["EG(stack_limit)"]=> + string(%d) "0x%x" +} + +Fatal error: Maximum call stack size of %d bytes reached during compilation. Try splitting expression in %s on line %d diff --git a/Zend/tests/traits/constant_016.phpt b/Zend/tests/traits/constant_016.phpt index 9cb2b29bcc095..0754c15716377 100644 --- a/Zend/tests/traits/constant_016.phpt +++ b/Zend/tests/traits/constant_016.phpt @@ -2,6 +2,8 @@ Compatibility of values of same name trait constants is checked after their constant expressions are evaluated --ENV-- ENSURE_CONSTANT_IS_DEFINED_AT_RUNTIME=1 +--INI-- +variables_order=EGPCS --FILE-- +--EXPECTF-- +Parse error: syntax error, unexpected token "#[" in %s on line %d diff --git a/Zend/tests/type_declarations/intersection_types/parsing_comment.phpt b/Zend/tests/type_declarations/intersection_types/parsing_comment.phpt new file mode 100644 index 0000000000000..6f8cd74e3bb73 --- /dev/null +++ b/Zend/tests/type_declarations/intersection_types/parsing_comment.phpt @@ -0,0 +1,26 @@ +--TEST-- +Intersection type and by-ref parameter parsing with comments +--FILE-- + +--EXPECT-- diff --git a/Zend/tests/type_declarations/scalar_strict.phpt b/Zend/tests/type_declarations/scalar_strict.phpt index 6d838848e902a..51bb8fac1678f 100644 --- a/Zend/tests/type_declarations/scalar_strict.phpt +++ b/Zend/tests/type_declarations/scalar_strict.phpt @@ -84,10 +84,10 @@ int(2147483647) *** Caught {closure}(): Argument #1 ($i) must be of type int, float given, called in %s on line %d *** Trying bool(true) -*** Caught {closure}(): Argument #1 ($i) must be of type int, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($i) must be of type int, true given, called in %s on line %d *** Trying bool(false) -*** Caught {closure}(): Argument #1 ($i) must be of type int, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($i) must be of type int, false given, called in %s on line %d *** Trying NULL *** Caught {closure}(): Argument #1 ($i) must be of type int, null given, called in %s on line %d @@ -137,10 +137,10 @@ float(2147483647) float(NAN) *** Trying bool(true) -*** Caught {closure}(): Argument #1 ($f) must be of type float, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($f) must be of type float, true given, called in %s on line %d *** Trying bool(false) -*** Caught {closure}(): Argument #1 ($f) must be of type float, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($f) must be of type float, false given, called in %s on line %d *** Trying NULL *** Caught {closure}(): Argument #1 ($f) must be of type float, null given, called in %s on line %d @@ -190,10 +190,10 @@ string(0) "" *** Caught {closure}(): Argument #1 ($s) must be of type string, float given, called in %s on line %d *** Trying bool(true) -*** Caught {closure}(): Argument #1 ($s) must be of type string, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($s) must be of type string, true given, called in %s on line %d *** Trying bool(false) -*** Caught {closure}(): Argument #1 ($s) must be of type string, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($s) must be of type string, false given, called in %s on line %d *** Trying NULL *** Caught {closure}(): Argument #1 ($s) must be of type string, null given, called in %s on line %d diff --git a/Zend/tests/type_declarations/scalar_strict_64bit.phpt b/Zend/tests/type_declarations/scalar_strict_64bit.phpt index 4705fa81dbd70..5d4dd0edeb682 100644 --- a/Zend/tests/type_declarations/scalar_strict_64bit.phpt +++ b/Zend/tests/type_declarations/scalar_strict_64bit.phpt @@ -84,10 +84,10 @@ int(9223372036854775807) *** Caught {closure}(): Argument #1 ($i) must be of type int, float given, called in %s on line %d *** Trying bool(true) -*** Caught {closure}(): Argument #1 ($i) must be of type int, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($i) must be of type int, true given, called in %s on line %d *** Trying bool(false) -*** Caught {closure}(): Argument #1 ($i) must be of type int, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($i) must be of type int, false given, called in %s on line %d *** Trying NULL *** Caught {closure}(): Argument #1 ($i) must be of type int, null given, called in %s on line %d @@ -137,10 +137,10 @@ float(9.223372036854776E+18) float(NAN) *** Trying bool(true) -*** Caught {closure}(): Argument #1 ($f) must be of type float, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($f) must be of type float, true given, called in %s on line %d *** Trying bool(false) -*** Caught {closure}(): Argument #1 ($f) must be of type float, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($f) must be of type float, false given, called in %s on line %d *** Trying NULL *** Caught {closure}(): Argument #1 ($f) must be of type float, null given, called in %s on line %d @@ -190,10 +190,10 @@ string(0) "" *** Caught {closure}(): Argument #1 ($s) must be of type string, float given, called in %s on line %d *** Trying bool(true) -*** Caught {closure}(): Argument #1 ($s) must be of type string, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($s) must be of type string, true given, called in %s on line %d *** Trying bool(false) -*** Caught {closure}(): Argument #1 ($s) must be of type string, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($s) must be of type string, false given, called in %s on line %d *** Trying NULL *** Caught {closure}(): Argument #1 ($s) must be of type string, null given, called in %s on line %d diff --git a/Zend/tests/type_declarations/scalar_strict_basic.phpt b/Zend/tests/type_declarations/scalar_strict_basic.phpt index f02649b8b55fc..296e8f7ad63a8 100644 --- a/Zend/tests/type_declarations/scalar_strict_basic.phpt +++ b/Zend/tests/type_declarations/scalar_strict_basic.phpt @@ -63,10 +63,10 @@ int(1) *** Caught {closure}(): Argument #1 ($i) must be of type int, string given, called in %s on line %d *** Trying true value -*** Caught {closure}(): Argument #1 ($i) must be of type int, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($i) must be of type int, true given, called in %s on line %d *** Trying false value -*** Caught {closure}(): Argument #1 ($i) must be of type int, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($i) must be of type int, false given, called in %s on line %d *** Trying null value *** Caught {closure}(): Argument #1 ($i) must be of type int, null given, called in %s on line %d @@ -92,10 +92,10 @@ float(1) *** Caught {closure}(): Argument #1 ($f) must be of type float, string given, called in %s on line %d *** Trying true value -*** Caught {closure}(): Argument #1 ($f) must be of type float, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($f) must be of type float, true given, called in %s on line %d *** Trying false value -*** Caught {closure}(): Argument #1 ($f) must be of type float, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($f) must be of type float, false given, called in %s on line %d *** Trying null value *** Caught {closure}(): Argument #1 ($f) must be of type float, null given, called in %s on line %d @@ -121,10 +121,10 @@ Testing 'string' type: string(1) "1" *** Trying true value -*** Caught {closure}(): Argument #1 ($s) must be of type string, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($s) must be of type string, true given, called in %s on line %d *** Trying false value -*** Caught {closure}(): Argument #1 ($s) must be of type string, bool given, called in %s on line %d +*** Caught {closure}(): Argument #1 ($s) must be of type string, false given, called in %s on line %d *** Trying null value *** Caught {closure}(): Argument #1 ($s) must be of type string, null given, called in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_diamond_error1.phpt b/Zend/tests/type_declarations/typed_class_constants_diamond_error1.phpt new file mode 100644 index 0000000000000..059c3cb2005b7 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_diamond_error1.phpt @@ -0,0 +1,16 @@ +--TEST-- +Typed class constants (diamond error with self) +--FILE-- +getMessage() . "\n"; +} +?> +--EXPECT-- +Undefined constant "C" diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_error1.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_error1.phpt new file mode 100644 index 0000000000000..d4bbe98d6f5ce --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_error1.phpt @@ -0,0 +1,14 @@ +--TEST-- +Typed class constants (incompatible inheritance; simple) +--FILE-- + +--EXPECTF-- +Fatal error: Type of B::CONST1 must be compatible with A::CONST1 of type int in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_error2.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_error2.phpt new file mode 100644 index 0000000000000..72fc4da0ffe2e --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_error2.phpt @@ -0,0 +1,14 @@ +--TEST-- +Typed class constants (incompatible inheritance; missing type in child) +--FILE-- + +--EXPECTF-- +Fatal error: Type of B::CONST1 must be compatible with A::CONST1 of type int in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_error3.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_error3.phpt new file mode 100644 index 0000000000000..82c3154e9bfba --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_error3.phpt @@ -0,0 +1,18 @@ +--TEST-- +Typed class constants (incompatible composition; traits) +--FILE-- + +--EXPECTF-- +Fatal error: C and T define the same constant (CONST1) in the composition of C. However, the definition differs and is considered incompatible. Class was composed in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_error4.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_error4.phpt new file mode 100644 index 0000000000000..55929d8953119 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_error4.phpt @@ -0,0 +1,18 @@ +--TEST-- +Typed class constants (incompatible covariant composition; traits) +--FILE-- + +--EXPECTF-- +Fatal error: C and T define the same constant (CONST1) in the composition of C. However, the definition differs and is considered incompatible. Class was composed in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_error5.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_error5.phpt new file mode 100644 index 0000000000000..7068d9df7cbb7 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_error5.phpt @@ -0,0 +1,18 @@ +--TEST-- +Typed class constants (incompatible contravariant composition; traits) +--FILE-- + +--EXPECTF-- +Fatal error: C and T define the same constant (CONST1) in the composition of C. However, the definition differs and is considered incompatible. Class was composed in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_success1.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_success1.phpt new file mode 100644 index 0000000000000..0dbd3a3385bc8 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_success1.phpt @@ -0,0 +1,29 @@ +--TEST-- +Typed class constants (inheritance success) +--FILE-- + +--EXPECT-- +int(0) +int(0) +int(0) +array(0) { +} diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_success2.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_success2.phpt new file mode 100644 index 0000000000000..40e079c3596e7 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_success2.phpt @@ -0,0 +1,48 @@ +--TEST-- +Typed class constants (inheritance success - object types) +--FILE-- + +--EXPECTF-- +object(Z)#%d (%d) { +} +object(Z)#%d (%d) { +} +object(Z)#%d (%d) { +} +object(Z)#%d (%d) { +} +object(Z)#%d (%d) { +} \ No newline at end of file diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_success3.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_success3.phpt new file mode 100644 index 0000000000000..dfcc5742d2b43 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_success3.phpt @@ -0,0 +1,16 @@ +--TEST-- +Typed class constants (inheritance; private constants) +--FILE-- + +--EXPECT-- +string(1) "a" diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_success4.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_success4.phpt new file mode 100644 index 0000000000000..faacb0d55e49c --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_success4.phpt @@ -0,0 +1,39 @@ +--TEST-- +Typed class constants (composition; traits) +--FILE-- + +--EXPECT-- +int(1) +array(0) { +} +enum(E::Case1) +object(stdClass)#1 (0) { +} diff --git a/Zend/tests/type_declarations/typed_class_constants_inheritance_success5.phpt b/Zend/tests/type_declarations/typed_class_constants_inheritance_success5.phpt new file mode 100644 index 0000000000000..7f59dc1be35aa --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_inheritance_success5.phpt @@ -0,0 +1,26 @@ +--TEST-- +Typed class constants (redefinition; interfaces and traits) +--FILE-- + +--EXPECT-- +enum(E::Case1) diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error1.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error1.phpt new file mode 100644 index 0000000000000..8f70043091fda --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error1.phpt @@ -0,0 +1,10 @@ +--TEST-- +Typed class constants (type mismatch; simple) +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use int as value for class constant A::CONST1 of type string in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error10.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error10.phpt new file mode 100644 index 0000000000000..805edd9854f43 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error10.phpt @@ -0,0 +1,15 @@ +--TEST-- +Typed class constants (type error) +--FILE-- + +--EXPECTF-- +Fatal error: Type of A2::C must be compatible with A1::C of type ?B1 in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error11.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error11.phpt new file mode 100644 index 0000000000000..714e5a00995cf --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error11.phpt @@ -0,0 +1,21 @@ +--TEST-- +Typed class constants (static type error) +--FILE-- +getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot assign E2 to class constant E1::C of type static diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error12.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error12.phpt new file mode 100644 index 0000000000000..fddc1bca0bae9 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error12.phpt @@ -0,0 +1,15 @@ +--TEST-- +Typed class constants with static in union +--FILE-- + +--EXPECT-- +object(A)#2 (0) { +} diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error2.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error2.phpt new file mode 100644 index 0000000000000..8acffaa38399f --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error2.phpt @@ -0,0 +1,26 @@ +--TEST-- +Typed class constants (type mismatch; runtime simple) +--FILE-- +getMessage() . "\n"; +} + +try { + var_dump(A::CONST1); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot assign string to class constant A::CONST1 of type int +Cannot assign string to class constant A::CONST1 of type int diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error3.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error3.phpt new file mode 100644 index 0000000000000..1e6ab277dec8b --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error3.phpt @@ -0,0 +1,25 @@ +--TEST-- +Typed class constants (type mismatch; runtime object) +--FILE-- +getMessage() . "\n"; +} + +try { + var_dump(A::CONST1); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} +?> +--EXPECT-- +Cannot assign stdClass to class constant A::CONST1 of type string +Cannot assign stdClass to class constant A::CONST1 of type string diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error4.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error4.phpt new file mode 100644 index 0000000000000..7e41b602cf8b3 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error4.phpt @@ -0,0 +1,10 @@ +--TEST-- +Typed class constants (type not allowed; callable) +--FILE-- + +--EXPECTF-- +Fatal error: Class constant A::CONST1 cannot have type callable in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error5.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error5.phpt new file mode 100644 index 0000000000000..c083c738989cc --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error5.phpt @@ -0,0 +1,10 @@ +--TEST-- +Typed class constants (type not allowed; void) +--FILE-- + +--EXPECTF-- +Fatal error: Class constant A::CONST1 cannot have type void in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error6.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error6.phpt new file mode 100644 index 0000000000000..cbb96588f5cc3 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error6.phpt @@ -0,0 +1,10 @@ +--TEST-- +Typed class constants (type not allowed; never) +--FILE-- + +--EXPECTF-- +Fatal error: Class constant A::CONST1 cannot have type never in %s on line %d diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error7.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error7.phpt new file mode 100644 index 0000000000000..6fce750166305 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error7.phpt @@ -0,0 +1,25 @@ +--TEST-- +Typed class constants (type mismatch; runtime) +--FILE-- +getMessage() . "\n"; +} + +try { + var_dump(A::CONST1); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} +?> +--EXPECT-- +Cannot assign stdClass to class constant A::CONST1 of type stdClass&Stringable +Cannot assign stdClass to class constant A::CONST1 of type stdClass&Stringable diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error8.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error8.phpt new file mode 100644 index 0000000000000..cbd3720a5ea4e --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error8.phpt @@ -0,0 +1,40 @@ +--TEST-- +Typed class constants (type mismatch; runtime) +--FILE-- +getMessage() . "\n"; +} + +try { + var_dump(A::CONST2); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + var_dump(A::CONST1); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + var_dump(A::CONST1); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} +?> +--EXPECT-- +Cannot assign stdClass to class constant A::CONST1 of type stdClass&Stringable +Cannot assign stdClass to class constant A::CONST1 of type stdClass&Stringable +Cannot assign stdClass to class constant A::CONST1 of type stdClass&Stringable +Cannot assign stdClass to class constant A::CONST1 of type stdClass&Stringable diff --git a/Zend/tests/type_declarations/typed_class_constants_type_error9.phpt b/Zend/tests/type_declarations/typed_class_constants_type_error9.phpt new file mode 100644 index 0000000000000..b0f42b2078a5b --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_error9.phpt @@ -0,0 +1,25 @@ +--TEST-- +Typed class constants (type coercion is unsupported) +--FILE-- +getMessage() . "\n"; +} +?> +--EXPECT-- +Cannot assign S to class constant A::S of type string diff --git a/Zend/tests/type_declarations/typed_class_constants_type_success1.phpt b/Zend/tests/type_declarations/typed_class_constants_type_success1.phpt new file mode 100644 index 0000000000000..61e82637d9ada --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_success1.phpt @@ -0,0 +1,66 @@ +--TEST-- +Typed class constants (declaration; compile-type simple) +--FILE-- + +--EXPECT-- +NULL +NULL +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +int(0) +int(0) +float(3.14) +float(3.14) +float(3) +float(3) +string(0) "" +string(0) "" +array(0) { +} +array(0) { +} +string(0) "" +string(0) "" +NULL +NULL diff --git a/Zend/tests/type_declarations/typed_class_constants_type_success2.phpt b/Zend/tests/type_declarations/typed_class_constants_type_success2.phpt new file mode 100644 index 0000000000000..1359624452355 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_success2.phpt @@ -0,0 +1,52 @@ +--TEST-- +Typed class constants (declaration; runtime) +--FILE-- + +--EXPECTF-- +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} +object(B)#%d (%d) { +} diff --git a/Zend/tests/type_declarations/typed_class_constants_type_success3.phpt b/Zend/tests/type_declarations/typed_class_constants_type_success3.phpt new file mode 100644 index 0000000000000..cf3d7c9557202 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_type_success3.phpt @@ -0,0 +1,52 @@ +--TEST-- +Typed enum constants (self/static) +--FILE-- + +--EXPECT-- +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) +enum(E::Foo) diff --git a/Zend/tests/type_declarations/typed_properties_022.phpt b/Zend/tests/type_declarations/typed_properties_022.phpt index aeed60dcacca9..d6712df55f6cd 100644 --- a/Zend/tests/type_declarations/typed_properties_022.phpt +++ b/Zend/tests/type_declarations/typed_properties_022.phpt @@ -11,5 +11,6 @@ $foo = new Foo(); --EXPECTF-- Fatal error: Uncaught Error: Class "BAR" not found in %s:%d Stack trace: -#0 {main} +#0 %s(%d): [constant expression]() +#1 {main} thrown in %s on line %d diff --git a/Zend/tests/type_declarations/typed_properties_111.phpt b/Zend/tests/type_declarations/typed_properties_111.phpt index c23fb72e5d657..20236e8a19bb3 100644 --- a/Zend/tests/type_declarations/typed_properties_111.phpt +++ b/Zend/tests/type_declarations/typed_properties_111.phpt @@ -17,4 +17,4 @@ try { ?> --EXPECT-- -Cannot assign bool to property Foo::$value of type false +Cannot assign true to property Foo::$value of type false diff --git a/Zend/tests/type_declarations/typed_properties_112.phpt b/Zend/tests/type_declarations/typed_properties_112.phpt index 5d54aa3234fe6..8b1157759fec3 100644 --- a/Zend/tests/type_declarations/typed_properties_112.phpt +++ b/Zend/tests/type_declarations/typed_properties_112.phpt @@ -16,4 +16,4 @@ try { ?> --EXPECT-- -Cannot assign bool to property Foo::$value of type true +Cannot assign false to property Foo::$value of type true diff --git a/Zend/tests/type_declarations/typed_properties_113.phpt b/Zend/tests/type_declarations/typed_properties_113.phpt new file mode 100644 index 0000000000000..cb5c0f9276453 --- /dev/null +++ b/Zend/tests/type_declarations/typed_properties_113.phpt @@ -0,0 +1,26 @@ +--TEST-- +Typed property type coercion through ArrayIterator +--FILE-- + &$v) { + $v = 42; +} + +var_dump($obj); +?> +--EXPECT-- +object(A)#1 (1) { + ["foo"]=> + &string(2) "42" +} diff --git a/Zend/tests/type_declarations/typed_properties_114.phpt b/Zend/tests/type_declarations/typed_properties_114.phpt new file mode 100644 index 0000000000000..e771f4c1c1f84 --- /dev/null +++ b/Zend/tests/type_declarations/typed_properties_114.phpt @@ -0,0 +1,39 @@ +--TEST-- +Typed property type error through ArrayIterator +--FILE-- + &$v) { + try { + $v = []; + } catch (Throwable $e) { + echo $e->getMessage(), "\n"; + } +} +foreach ($obj as $k => &$v) { + try { + $v = []; + } catch (Throwable $e) { + echo $e->getMessage(), "\n"; + } +} + +var_dump($obj); +?> +--EXPECT-- +Cannot assign array to reference held by property A::$foo of type string +Cannot assign array to reference held by property A::$foo of type string +object(A)#1 (1) { + ["foo"]=> + &string(3) "bar" +} diff --git a/Zend/tests/type_declarations/typed_properties_115.phpt b/Zend/tests/type_declarations/typed_properties_115.phpt new file mode 100644 index 0000000000000..eb96b3ee88641 --- /dev/null +++ b/Zend/tests/type_declarations/typed_properties_115.phpt @@ -0,0 +1,30 @@ +--TEST-- +Readonly property modification error through ArrayIterator +--FILE-- + &$v) {} +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} + +var_dump($obj); +?> +--EXPECT-- +Cannot acquire reference to readonly property A::$foo +object(A)#1 (1) { + ["foo"]=> + string(3) "bar" +} diff --git a/Zend/tests/type_declarations/union_types/type_checking_strict.phpt b/Zend/tests/type_declarations/union_types/type_checking_strict.phpt index 7054a7cc19127..31460f5d5719c 100644 --- a/Zend/tests/type_declarations/union_types/type_checking_strict.phpt +++ b/Zend/tests/type_declarations/union_types/type_checking_strict.phpt @@ -71,8 +71,8 @@ INF => INF "42x" => Argument ... must be of type int|float, string given "x" => Argument ... must be of type int|float, string given "" => Argument ... must be of type int|float, string given -true => Argument ... must be of type int|float, bool given -false => Argument ... must be of type int|float, bool given +true => Argument ... must be of type int|float, true given +false => Argument ... must be of type int|float, false given null => Argument ... must be of type int|float, null given [] => Argument ... must be of type int|float, array given new stdClass => Argument ... must be of type int|float, stdClass given @@ -87,7 +87,7 @@ INF => INF "42x" => Argument ... must be of type int|float|false, string given "x" => Argument ... must be of type int|float|false, string given "" => Argument ... must be of type int|float|false, string given -true => Argument ... must be of type int|float|false, bool given +true => Argument ... must be of type int|float|false, true given false => false null => Argument ... must be of type int|float|false, null given [] => Argument ... must be of type int|float|false, array given @@ -135,8 +135,8 @@ INF => Argument ... must be of type string|int|null, float given "42x" => "42x" "x" => "x" "" => "" -true => Argument ... must be of type string|int|null, bool given -false => Argument ... must be of type string|int|null, bool given +true => Argument ... must be of type string|int|null, true given +false => Argument ... must be of type string|int|null, false given null => null [] => Argument ... must be of type string|int|null, array given new stdClass => Argument ... must be of type string|int|null, stdClass given @@ -167,8 +167,8 @@ INF => INF "42x" => Argument ... must be of type array|float, string given "x" => Argument ... must be of type array|float, string given "" => Argument ... must be of type array|float, string given -true => Argument ... must be of type array|float, bool given -false => Argument ... must be of type array|float, bool given +true => Argument ... must be of type array|float, true given +false => Argument ... must be of type array|float, false given null => Argument ... must be of type array|float, null given [] => [] new stdClass => Argument ... must be of type array|float, stdClass given @@ -183,8 +183,8 @@ INF => Argument ... must be of type array|string, float given "42x" => "42x" "x" => "x" "" => "" -true => Argument ... must be of type array|string, bool given -false => Argument ... must be of type array|string, bool given +true => Argument ... must be of type array|string, true given +false => Argument ... must be of type array|string, false given null => Argument ... must be of type array|string, null given [] => [] new stdClass => Argument ... must be of type array|string, stdClass given diff --git a/Zend/tests/unary_minus_const_expr_consistency.phpt b/Zend/tests/unary_minus_const_expr_consistency.phpt new file mode 100644 index 0000000000000..c8175df8bed3a --- /dev/null +++ b/Zend/tests/unary_minus_const_expr_consistency.phpt @@ -0,0 +1,16 @@ +--TEST-- +Unary minus constant expression consistency +--FILE-- + +--EXPECT-- +float(-0) +float(-0) diff --git a/Zend/tests/use_statement/aliasing_builtin_types.phpt b/Zend/tests/use_statement/aliasing_builtin_types.phpt deleted file mode 100644 index 681a77c24b28a..0000000000000 --- a/Zend/tests/use_statement/aliasing_builtin_types.phpt +++ /dev/null @@ -1,10 +0,0 @@ ---TEST-- -Aliasing built-in types ---FILE-- - ---EXPECTF-- -Fatal error: Cannot alias 'bool' as it is a built-in type in %s on line %d diff --git a/Zend/zend.c b/Zend/zend.c index 46a0e1b4c0ea3..bbddd4597042b 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -35,6 +35,8 @@ #include "zend_attributes.h" #include "zend_observer.h" #include "zend_fibers.h" +#include "zend_call_stack.h" +#include "zend_max_execution_timer.h" #include "Optimizer/zend_optimizer.h" static size_t global_map_ptr_last = 0; @@ -173,10 +175,56 @@ static ZEND_INI_MH(OnSetExceptionStringParamMaxLen) /* {{{ */ } /* }}} */ +#ifdef ZEND_CHECK_STACK_LIMIT +static ZEND_INI_MH(OnUpdateMaxAllowedStackSize) /* {{{ */ +{ + zend_long size = zend_ini_parse_quantity_warn(new_value, entry->name); + + if (size < ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED) { + zend_error(E_WARNING, "Invalid \"%s\" setting. Value must be >= %d, but got " ZEND_LONG_FMT, + ZSTR_VAL(entry->name), ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED, size); + return FAILURE; + } + + EG(max_allowed_stack_size) = size; + + return SUCCESS; +} +/* }}} */ + +static ZEND_INI_MH(OnUpdateReservedStackSize) /* {{{ */ +{ + zend_ulong size = zend_ini_parse_uquantity_warn(new_value, entry->name); + + /* Min value accounts for alloca, PCRE2 START_FRAMES_SIZE, and some buffer + * for normal function calls. + * We could reduce this on systems without alloca if we also add stack size + * checks before pcre2_match(). */ +#ifdef ZEND_ALLOCA_MAX_SIZE + zend_ulong min = ZEND_ALLOCA_MAX_SIZE + 16*1024; +#else + zend_ulong min = 32*1024; +#endif + + if (size == 0) { + size = min; + } else if (size < min) { + zend_error(E_WARNING, "Invalid \"%s\" setting. Value must be >= " ZEND_ULONG_FMT ", but got " ZEND_ULONG_FMT "\n", + ZSTR_VAL(entry->name), min, size); + return FAILURE; + } + + EG(reserved_stack_size) = size; + + return SUCCESS; +} +/* }}} */ +#endif /* ZEND_CHECK_STACK_LIMIT */ + static ZEND_INI_MH(OnUpdateFiberStackSize) /* {{{ */ { if (new_value) { - EG(fiber_stack_size) = zend_ini_parse_quantity_warn(new_value, entry->name); + EG(fiber_stack_size) = zend_ini_parse_uquantity_warn(new_value, entry->name); } else { EG(fiber_stack_size) = ZEND_FIBER_DEFAULT_C_STACK_SIZE; } @@ -203,6 +251,12 @@ ZEND_INI_BEGIN() STD_ZEND_INI_BOOLEAN("zend.exception_ignore_args", "0", ZEND_INI_ALL, OnUpdateBool, exception_ignore_args, zend_executor_globals, executor_globals) STD_ZEND_INI_ENTRY("zend.exception_string_param_max_len", "15", ZEND_INI_ALL, OnSetExceptionStringParamMaxLen, exception_string_param_max_len, zend_executor_globals, executor_globals) STD_ZEND_INI_ENTRY("fiber.stack_size", NULL, ZEND_INI_ALL, OnUpdateFiberStackSize, fiber_stack_size, zend_executor_globals, executor_globals) +#ifdef ZEND_CHECK_STACK_LIMIT + /* The maximum allowed call stack size. 0: auto detect, -1: no limit. For fibers, this is fiber.stack_size. */ + STD_ZEND_INI_ENTRY("zend.max_allowed_stack_size", "0", ZEND_INI_SYSTEM, OnUpdateMaxAllowedStackSize, max_allowed_stack_size, zend_executor_globals, executor_globals) + /* Substracted from the max allowed stack size, as a buffer, when checking for overflow. 0: auto detect. */ + STD_ZEND_INI_ENTRY("zend.reserved_stack_size", "0", ZEND_INI_SYSTEM, OnUpdateReservedStackSize, reserved_stack_size, zend_executor_globals, executor_globals) +#endif ZEND_INI_END() @@ -621,69 +675,6 @@ static void auto_global_dtor(zval *zv) /* {{{ */ /* }}} */ #ifdef ZTS -static void function_copy_ctor(zval *zv) /* {{{ */ -{ - zend_function *old_func = Z_FUNC_P(zv); - zend_function *func; - - if (old_func->type == ZEND_USER_FUNCTION) { - ZEND_ASSERT(old_func->op_array.fn_flags & ZEND_ACC_IMMUTABLE); - return; - } - func = pemalloc(sizeof(zend_internal_function), 1); - Z_FUNC_P(zv) = func; - memcpy(func, old_func, sizeof(zend_internal_function)); - function_add_ref(func); - if ((old_func->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) - && old_func->common.arg_info) { - uint32_t i; - uint32_t num_args = old_func->common.num_args + 1; - zend_arg_info *arg_info = old_func->common.arg_info - 1; - zend_arg_info *new_arg_info; - - if (old_func->common.fn_flags & ZEND_ACC_VARIADIC) { - num_args++; - } - new_arg_info = pemalloc(sizeof(zend_arg_info) * num_args, 1); - memcpy(new_arg_info, arg_info, sizeof(zend_arg_info) * num_args); - for (i = 0 ; i < num_args; i++) { - if (ZEND_TYPE_HAS_LIST(arg_info[i].type)) { - zend_type_list *old_list = ZEND_TYPE_LIST(arg_info[i].type); - zend_type_list *new_list = pemalloc(ZEND_TYPE_LIST_SIZE(old_list->num_types), 1); - memcpy(new_list, old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types)); - ZEND_TYPE_SET_PTR(new_arg_info[i].type, new_list); - - zend_type *list_type; - ZEND_TYPE_LIST_FOREACH(new_list, list_type) { - zend_string *name = zend_string_dup(ZEND_TYPE_NAME(*list_type), 1); - ZEND_TYPE_SET_PTR(*list_type, name); - } ZEND_TYPE_LIST_FOREACH_END(); - } else if (ZEND_TYPE_HAS_NAME(arg_info[i].type)) { - zend_string *name = zend_string_dup(ZEND_TYPE_NAME(arg_info[i].type), 1); - ZEND_TYPE_SET_PTR(new_arg_info[i].type, name); - } - } - func->common.arg_info = new_arg_info + 1; - } - if (old_func->common.attributes) { - zend_attribute *old_attr; - - func->common.attributes = NULL; - - ZEND_HASH_PACKED_FOREACH_PTR(old_func->common.attributes, old_attr) { - uint32_t i; - zend_attribute *attr; - - attr = zend_add_attribute(&func->common.attributes, old_attr->name, old_attr->argc, old_attr->flags, old_attr->offset, old_attr->lineno); - - for (i = 0 ; i < old_attr->argc; i++) { - ZVAL_DUP(&attr->args[i].value, &old_attr->args[i].value); - } - } ZEND_HASH_FOREACH_END(); - } -} -/* }}} */ - static void auto_global_copy_ctor(zval *zv) /* {{{ */ { zend_auto_global *old_ag = (zend_auto_global *) Z_PTR_P(zv); @@ -703,7 +694,8 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{ compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); zend_hash_init(compiler_globals->function_table, 1024, NULL, ZEND_FUNCTION_DTOR, 1); - zend_hash_copy(compiler_globals->function_table, global_function_table, function_copy_ctor); + zend_hash_copy(compiler_globals->function_table, global_function_table, NULL); + compiler_globals->copied_functions_count = zend_hash_num_elements(compiler_globals->function_table); compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); zend_hash_init(compiler_globals->class_table, 64, NULL, ZEND_CLASS_DTOR, 1); @@ -737,6 +729,21 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{{ */ { if (compiler_globals->function_table != GLOBAL_FUNCTION_TABLE) { + uint32_t n = compiler_globals->copied_functions_count; + + /* Prevent destruction of functions copied from the main process context */ + if (zend_hash_num_elements(compiler_globals->function_table) <= n) { + compiler_globals->function_table->nNumUsed = 0; + } else { + Bucket *p = compiler_globals->function_table->arData; + + compiler_globals->function_table->nNumOfElements -= n; + while (n != 0) { + ZVAL_UNDEF(&p->val); + p++; + n--; + } + } zend_hash_destroy(compiler_globals->function_table); free(compiler_globals->function_table); } @@ -796,6 +803,14 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{ executor_globals->record_errors = false; executor_globals->num_errors = 0; executor_globals->errors = NULL; +#ifdef ZEND_CHECK_STACK_LIMIT + executor_globals->stack_limit = (void*)0; + executor_globals->stack_base = (void*)0; +#endif +#ifdef ZEND_MAX_EXECUTION_TIMERS + executor_globals->pid = 0; + executor_globals->oldact = (struct sigaction){0}; +#endif } /* }}} */ @@ -817,6 +832,10 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ { zend_copy_ini_directives(); zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); +#ifdef ZEND_CHECK_STACK_LIMIT + zend_call_stack_init(); +#endif + zend_max_execution_timer_init(); } /* }}} */ #endif @@ -982,7 +1001,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(NULL); CG(map_ptr_size) = 0; CG(map_ptr_last) = 0; -#endif +#endif /* ZTS */ EG(error_reporting) = E_ALL & ~E_NOTICE; zend_interned_strings_init(); @@ -1077,6 +1096,10 @@ zend_result zend_post_startup(void) /* {{{ */ global_map_ptr_last = CG(map_ptr_last); #endif +#ifdef ZEND_CHECK_STACK_LIMIT + zend_call_stack_init(); +#endif + return SUCCESS; } /* }}} */ @@ -1167,6 +1190,7 @@ ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32 CG(unclean_shutdown) = 1; CG(active_class_entry) = NULL; CG(in_compilation) = 0; + CG(memoize_mode) = 0; EG(current_execute_data) = NULL; LONGJMP(*EG(bailout), FAILURE); } @@ -1262,17 +1286,36 @@ ZEND_API void zend_deactivate(void) /* {{{ */ zend_destroy_rsrc_list(&EG(regular_list)); + /* See GH-8646: https://github.com/php/php-src/issues/8646 + * + * Interned strings that hold class entries can get a corresponding slot in map_ptr for the CE cache. + * map_ptr works like a bump allocator: there is a counter which increases to allocate the next slot in the map. + * + * For class name strings in non-opcache we have: + * - on startup: permanent + interned + * - on request: interned + * For class name strings in opcache we have: + * - on startup: permanent + interned + * - on request: either not interned at all, which we can ignore because they won't get a CE cache entry + * or they were already permanent + interned + * or we get a new permanent + interned string in the opcache persistence code + * + * Notice that the map_ptr layout always has the permanent strings first, and the request strings after. + * In non-opcache, a request string may get a slot in map_ptr, and that interned request string + * gets destroyed at the end of the request. The corresponding map_ptr slot can thereafter never be used again. + * This causes map_ptr to keep reallocating to larger and larger sizes. + * + * We solve it as follows: + * We can check whether we had any interned request strings, which only happens in non-opcache. + * If we have any, we reset map_ptr to the last permanent string. + * We can't lose any permanent strings because of map_ptr's layout. + */ + if (zend_hash_num_elements(&CG(interned_strings)) > 0) { + zend_map_ptr_reset(); + } + #if GC_BENCH - fprintf(stderr, "GC Statistics\n"); - fprintf(stderr, "-------------\n"); - fprintf(stderr, "Runs: %d\n", GC_G(gc_runs)); - fprintf(stderr, "Collected: %d\n", GC_G(collected)); - fprintf(stderr, "Root buffer length: %d\n", GC_G(root_buf_length)); - fprintf(stderr, "Root buffer peak: %d\n\n", GC_G(root_buf_peak)); - fprintf(stderr, " Possible Remove from Marked\n"); - fprintf(stderr, " Root Buffered buffer grey\n"); - fprintf(stderr, " -------- -------- ----------- ------\n"); - fprintf(stderr, "ZVAL %8d %8d %9d %8d\n", GC_G(zval_possible_root), GC_G(zval_buffered), GC_G(zval_remove_from_buffer), GC_G(zval_marked_grey)); + gc_bench_print(); #endif } /* }}} */ @@ -1594,6 +1637,18 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char * abort(); } +ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message) +{ +#ifdef HAVE_STR_ERROR_R + char buf[1024]; + strerror_r(errn, buf, sizeof(buf)); +#else + char *buf = strerror(errn); +#endif + + zend_error_noreturn(type, "%s: %s (%d)", message, buf, errn); +} + ZEND_API ZEND_COLD void zend_error_zstr(int type, zend_string *message) { zend_string *filename; uint32_t lineno; diff --git a/Zend/zend.h b/Zend/zend.h index 3eaf62ace1157..fd21cbfeb93cf 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -39,6 +39,7 @@ #include "zend_smart_str_public.h" #include "zend_smart_string_public.h" #include "zend_signal.h" +#include "zend_max_execution_timer.h" #define zend_sprintf sprintf @@ -359,6 +360,9 @@ ZEND_API ZEND_COLD void zend_value_error(const char *format, ...) ZEND_ATTRIBUTE ZEND_COLD void zenderror(const char *error); +/* For internal C errors */ +ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message); + /* The following #define is used for code duality in PHP for Engine 1 & 2 */ #define ZEND_STANDARD_CLASS_DEF_PTR zend_standard_class_def extern ZEND_API zend_class_entry *zend_standard_class_def; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index b74fa0fc7a0e1..e9058f3e43db9 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -101,7 +101,7 @@ ZEND_API ZEND_COLD void zend_wrong_property_read(zval *object, zval *property) { zend_string *tmp_property_name; zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name); - zend_error(E_WARNING, "Attempt to read property \"%s\" on %s", ZSTR_VAL(property_name), zend_zval_type_name(object)); + zend_error(E_WARNING, "Attempt to read property \"%s\" on %s", ZSTR_VAL(property_name), zend_zval_value_name(object)); zend_tmp_string_release(tmp_property_name); } @@ -136,13 +136,32 @@ ZEND_API const char *zend_get_type_by_const(int type) /* {{{ */ case IS_MIXED: return "mixed"; case _IS_NUMBER: - return "number"; + return "int|float"; EMPTY_SWITCH_DEFAULT_CASE() } } /* }}} */ -ZEND_API const char *zend_zval_type_name(const zval *arg) /* {{{ */ +ZEND_API const char *zend_zval_value_name(const zval *arg) +{ + ZVAL_DEREF(arg); + + if (Z_ISUNDEF_P(arg)) { + return "null"; + } + + if (Z_TYPE_P(arg) == IS_OBJECT) { + return ZSTR_VAL(Z_OBJCE_P(arg)->name); + } else if (Z_TYPE_P(arg) == IS_FALSE) { + return "false"; + } else if (Z_TYPE_P(arg) == IS_TRUE) { + return "true"; + } + + return zend_get_type_by_const(Z_TYPE_P(arg)); +} + +ZEND_API const char *zend_zval_type_name(const zval *arg) { ZVAL_DEREF(arg); @@ -156,7 +175,6 @@ ZEND_API const char *zend_zval_type_name(const zval *arg) /* {{{ */ return zend_get_type_by_const(Z_TYPE_P(arg)); } -/* }}} */ /* This API exists *only* for use in gettype(). * For anything else, you likely want zend_zval_type_name(). */ @@ -277,7 +295,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(uint32_t n return; } - zend_argument_type_error(num, "must be %s, %s given", expected_error[expected_type], zend_zval_type_name(arg)); + zend_argument_type_error(num, "must be %s, %s given", expected_error[expected_type], zend_zval_value_name(arg)); } /* }}} */ @@ -287,7 +305,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(uint32_t return; } - zend_argument_type_error(num, "must be of type %s, %s given", name, zend_zval_type_name(arg)); + zend_argument_type_error(num, "must be of type %s, %s given", name, zend_zval_value_name(arg)); } /* }}} */ @@ -297,7 +315,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(u return; } - zend_argument_type_error(num, "must be of type ?%s, %s given", name, zend_zval_type_name(arg)); + zend_argument_type_error(num, "must be of type ?%s, %s given", name, zend_zval_value_name(arg)); } /* }}} */ @@ -307,7 +325,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_error(u return; } - zend_argument_type_error(num, "must be of type %s|int, %s given", name, zend_zval_type_name(arg)); + zend_argument_type_error(num, "must be of type %s|int, %s given", name, zend_zval_value_name(arg)); } /* }}} */ @@ -317,7 +335,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_or_null return; } - zend_argument_type_error(num, "must be of type %s|int|null, %s given", name, zend_zval_type_name(arg)); + zend_argument_type_error(num, "must be of type %s|int|null, %s given", name, zend_zval_value_name(arg)); } /* }}} */ @@ -327,7 +345,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_string_error return; } - zend_argument_type_error(num, "must be of type %s|string, %s given", name, zend_zval_type_name(arg)); + zend_argument_type_error(num, "must be of type %s|string, %s given", name, zend_zval_value_name(arg)); } /* }}} */ @@ -337,7 +355,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_string_or_nu return; } - zend_argument_type_error(num, "must be of type %s|string|null, %s given", name, zend_zval_type_name(arg)); + zend_argument_type_error(num, "must be of type %s|string|null, %s given", name, zend_zval_value_name(arg)); } /* }}} */ @@ -389,6 +407,16 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_en } /* }}} */ +ZEND_API ZEND_COLD void zend_illegal_array_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s on array", zend_get_type_by_const(Z_TYPE_P(offset))); +} + +ZEND_API ZEND_COLD void zend_illegal_empty_or_isset_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s in isset or empty", zend_get_type_by_const(Z_TYPE_P(offset))); +} + ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t arg_num, const char *format, ...) /* {{{ */ { va_list va; @@ -477,7 +505,7 @@ static ZEND_COLD bool zend_null_arg_deprecated(const char *fallback_type, uint32 return !EG(exception); } -ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest, uint32_t arg_num) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(const zval *arg, bool *dest, uint32_t arg_num) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) <= IS_STRING)) { if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("bool", arg_num)) { @@ -491,7 +519,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest, uint } /* }}} */ -ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, bool *dest, uint32_t arg_num) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(const zval *arg, bool *dest, uint32_t arg_num) /* {{{ */ { if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) { return 0; @@ -500,7 +528,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, bool *dest, uint } /* }}} */ -ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(const zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) { if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) { @@ -524,7 +552,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest, } } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { double d; - zend_uchar type; + uint8_t type; if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), dest, &d)) != IS_LONG)) { if (EXPECTED(type != 0)) { @@ -570,7 +598,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest, } /* }}} */ -ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(const zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */ { if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) { return 0; @@ -579,13 +607,13 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest, } /* }}} */ -ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest, uint32_t arg_num) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(const zval *arg, double *dest, uint32_t arg_num) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) { *dest = (double)Z_LVAL_P(arg); } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) { zend_long l; - zend_uchar type; + uint8_t type; if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), &l, dest)) != IS_DOUBLE)) { if (EXPECTED(type != 0)) { @@ -611,7 +639,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest, } /* }}} */ -ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest, uint32_t arg_num) /* {{{ */ +ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(const zval *arg, double *dest, uint32_t arg_num) /* {{{ */ { if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) { /* SSTH Exception: IS_LONG may be accepted instead as IS_DOUBLE */ @@ -632,7 +660,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest, u zend_string *str = Z_STR_P(arg); zend_long lval; double dval; - zend_uchar type = is_numeric_str_function(str, &lval, &dval); + uint8_t type = is_numeric_str_function(str, &lval, &dval); if (type == IS_LONG) { ZVAL_LONG(arg, lval); } else if (type == IS_DOUBLE) { @@ -884,7 +912,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec if (!zend_parse_arg_object(arg, p, ce, check_null)) { if (ce) { if (check_null) { - zend_spprintf(error, 0, "must be of type ?%s, %s given", ZSTR_VAL(ce->name), zend_zval_type_name(arg)); + zend_spprintf(error, 0, "must be of type ?%s, %s given", ZSTR_VAL(ce->name), zend_zval_value_name(arg)); return ""; } else { return ZSTR_VAL(ce->name); @@ -1004,7 +1032,7 @@ static zend_result zend_parse_arg(uint32_t arg_num, zval *arg, va_list *va, cons } efree(error); } else { - zend_argument_type_error(arg_num, "must be of type %s, %s given", expected_type, zend_zval_type_name(arg)); + zend_argument_type_error(arg_num, "must be of type %s, %s given", expected_type, zend_zval_value_name(arg)); } } else if (error) { efree(error); @@ -1384,6 +1412,34 @@ static zend_result update_property(zval *val, zend_property_info *prop_info) { return zval_update_constant_ex(val, prop_info->ce); } +ZEND_API zend_result zend_update_class_constant(zend_class_constant *c, const zend_string *name, zend_class_entry *scope) +{ + ZEND_ASSERT(Z_TYPE(c->value) == IS_CONSTANT_AST); + + if (EXPECTED(!ZEND_TYPE_IS_SET(c->type) || ZEND_TYPE_PURE_MASK(c->type) == MAY_BE_ANY)) { + return zval_update_constant_ex(&c->value, scope); + } + + zval tmp; + + ZVAL_COPY(&tmp, &c->value); + zend_result result = zval_update_constant_ex(&tmp, scope); + if (result == FAILURE) { + zval_ptr_dtor(&tmp); + return FAILURE; + } + + if (UNEXPECTED(!zend_verify_class_constant_type(c, name, &tmp))) { + zval_ptr_dtor(&tmp); + return FAILURE; + } + + zval_ptr_dtor(&c->value); + ZVAL_COPY_VALUE(&c->value, &tmp); + + return SUCCESS; +} + ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /* {{{ */ { zend_class_mutable_data *mutable_data = NULL; @@ -1442,7 +1498,7 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) / } val = &c->value; - if (UNEXPECTED(zval_update_constant_ex(val, c->ce) != SUCCESS)) { + if (UNEXPECTED(zend_update_class_constant(c, name, c->ce) != SUCCESS)) { return FAILURE; } } @@ -2056,7 +2112,7 @@ ZEND_API zend_result array_set_zval_key(HashTable *ht, zval *key, zval *value) / result = zend_hash_index_update(ht, zend_dval_to_lval_safe(Z_DVAL_P(key)), value); break; default: - zend_type_error("Illegal offset type"); + zend_illegal_array_offset(key); result = NULL; } @@ -2684,8 +2740,8 @@ ZEND_END_ARG_INFO() ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type) /* {{{ */ { const zend_function_entry *ptr = functions; - zend_function function, *reg_function; - zend_internal_function *internal_function = (zend_internal_function *)&function; + zend_function function; + zend_internal_function *reg_function, *internal_function = (zend_internal_function *)&function; int count=0, unload=0; HashTable *target_function_table = function_table; int error_type; @@ -2714,14 +2770,14 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend internal_function->prototype = NULL; internal_function->attributes = NULL; if (EG(active)) { // at run-time: this ought to only happen if registered with dl() or somehow temporarily at runtime - ZEND_MAP_PTR_INIT(internal_function->run_time_cache, zend_arena_alloc(&CG(arena), zend_internal_run_time_cache_reserved_size())); + ZEND_MAP_PTR_INIT(internal_function->run_time_cache, zend_arena_calloc(&CG(arena), 1, zend_internal_run_time_cache_reserved_size())); } else { ZEND_MAP_PTR_NEW(internal_function->run_time_cache); } if (ptr->flags) { if (!(ptr->flags & ZEND_ACC_PPP_MASK)) { if (ptr->flags != ZEND_ACC_DEPRECATED && scope) { - zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); + zend_error(error_type, "Invalid access level for %s::%s() - access must be exactly one of public, protected or private", ZSTR_VAL(scope->name), ptr->fname); } internal_function->fn_flags = ZEND_ACC_PUBLIC | ptr->flags; } else { @@ -2736,7 +2792,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend internal_function->arg_info = (zend_internal_arg_info*)ptr->arg_info+1; internal_function->num_args = ptr->num_args; /* Currently you cannot denote that the function can accept less arguments than num_args */ - if (info->required_num_args == (zend_uintptr_t)-1) { + if (info->required_num_args == (uintptr_t)-1) { internal_function->required_num_args = ptr->num_args; } else { internal_function->required_num_args = info->required_num_args; @@ -2818,23 +2874,23 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend } /* Get parameter count including variadic parameter. */ - uint32_t num_args = reg_function->common.num_args; - if (reg_function->common.fn_flags & ZEND_ACC_VARIADIC) { + uint32_t num_args = reg_function->num_args; + if (reg_function->fn_flags & ZEND_ACC_VARIADIC) { num_args++; } /* If types of arguments have to be checked */ - if (reg_function->common.arg_info && num_args) { + if (reg_function->arg_info && num_args) { uint32_t i; for (i = 0; i < num_args; i++) { - zend_internal_arg_info *arg_info = ®_function->internal_function.arg_info[i]; + zend_internal_arg_info *arg_info = ®_function->arg_info[i]; ZEND_ASSERT(arg_info->name && "Parameter must have a name"); if (ZEND_TYPE_IS_SET(arg_info->type)) { - reg_function->common.fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; + reg_function->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; } #if ZEND_DEBUG for (uint32_t j = 0; j < i; j++) { - if (!strcmp(arg_info->name, reg_function->internal_function.arg_info[j].name)) { + if (!strcmp(arg_info->name, reg_function->arg_info[j].name)) { zend_error_noreturn(E_CORE_ERROR, "Duplicate parameter name $%s for function %s%s%s()", arg_info->name, scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); @@ -2845,18 +2901,18 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend } /* Rebuild arginfos if parameter/property types and/or a return type are used */ - if (reg_function->common.arg_info && - (reg_function->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { + if (reg_function->arg_info && + (reg_function->fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { /* convert "const char*" class type names into "zend_string*" */ uint32_t i; - zend_arg_info *arg_info = reg_function->common.arg_info - 1; - zend_arg_info *new_arg_info; + zend_internal_arg_info *arg_info = reg_function->arg_info - 1; + zend_internal_arg_info *new_arg_info; /* Treat return type as an extra argument */ num_args++; - new_arg_info = malloc(sizeof(zend_arg_info) * num_args); - memcpy(new_arg_info, arg_info, sizeof(zend_arg_info) * num_args); - reg_function->common.arg_info = new_arg_info + 1; + new_arg_info = malloc(sizeof(zend_internal_arg_info) * num_args); + memcpy(new_arg_info, arg_info, sizeof(zend_internal_arg_info) * num_args); + reg_function->arg_info = new_arg_info + 1; for (i = 0; i < num_args; i++) { if (ZEND_TYPE_IS_COMPLEX(new_arg_info[i].type)) { ZEND_ASSERT(ZEND_TYPE_HAS_NAME(new_arg_info[i].type) @@ -2910,8 +2966,8 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend if (scope) { zend_check_magic_method_implementation( - scope, reg_function, lowercase_name, E_CORE_ERROR); - zend_add_magic_method(scope, reg_function, lowercase_name); + scope, (zend_function *)reg_function, lowercase_name, E_CORE_ERROR); + zend_add_magic_method(scope, (zend_function *)reg_function, lowercase_name); } ptr++; count++; @@ -3274,13 +3330,15 @@ ZEND_API zend_result zend_register_class_alias_ex(const char *name, size_t name_ lcname = zend_new_interned_string(lcname); + /* We cannot increase the refcount of an internal class during request time. + * Instead of having to deal with differentiating between class types and lifetimes, + * we simply don't increase the refcount of a class entry for aliases. + */ ZVAL_ALIAS_PTR(&zv, ce); + ret = zend_hash_add(CG(class_table), lcname, &zv); zend_string_release_ex(lcname, 0); if (ret) { - if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) { - ce->refcount++; - } // avoid notifying at MINIT time if (ce->type == ZEND_USER_CLASS) { zend_observer_class_linked_notify(ce, lcname); @@ -3767,9 +3825,9 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_ } } else if (error) { if (fcc->calling_scope) { - if (error) zend_spprintf(error, 0, "class %s does not have a method \"%s\"", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(mname)); + zend_spprintf(error, 0, "class %s does not have a method \"%s\"", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(mname)); } else { - if (error) zend_spprintf(error, 0, "function %s() does not exist", ZSTR_VAL(mname)); + zend_spprintf(error, 0, "function %s() does not exist", ZSTR_VAL(mname)); } } zend_string_release_ex(lmname, 0); @@ -4191,6 +4249,10 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z if (ZEND_TYPE_IS_SET(type)) { ce->ce_flags |= ZEND_ACC_HAS_TYPE_HINTS; + + if (access_type & ZEND_ACC_READONLY) { + ce->ce_flags |= ZEND_ACC_HAS_READONLY_PROPS; + } } if (ce->type == ZEND_INTERNAL_CLASS) { @@ -4498,7 +4560,7 @@ ZEND_API void zend_declare_property_stringl(zend_class_entry *ce, const char *na } /* }}} */ -ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int flags, zend_string *doc_comment) /* {{{ */ +ZEND_API zend_class_constant *zend_declare_typed_class_constant(zend_class_entry *ce, zend_string *name, zval *value, int flags, zend_string *doc_comment, zend_type type) /* {{{ */ { zend_class_constant *c; @@ -4527,6 +4589,8 @@ ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *c c->doc_comment = doc_comment; c->attributes = NULL; c->ce = ce; + c->type = type; + if (Z_TYPE_P(value) == IS_CONSTANT_AST) { ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS; @@ -4542,7 +4606,11 @@ ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *c return c; } -/* }}} */ + +ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int flags, zend_string *doc_comment) +{ + return zend_declare_typed_class_constant(ce, name, value, flags, doc_comment, (zend_type) ZEND_TYPE_INIT_NONE(0)); +} ZEND_API void zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value) /* {{{ */ { @@ -4723,7 +4791,7 @@ ZEND_API zend_result zend_update_static_property_ex(zend_class_entry *scope, zen zend_class_entry *old_scope = EG(fake_scope); if (UNEXPECTED(!(scope->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) { - if (UNEXPECTED(zend_update_class_constants(scope)) != SUCCESS) { + if (UNEXPECTED(zend_update_class_constants(scope) != SUCCESS)) { return FAILURE; } } @@ -4755,7 +4823,7 @@ ZEND_API zend_result zend_update_static_property_ex(zend_class_entry *scope, zen ZEND_API zend_result zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value) /* {{{ */ { zend_string *key = zend_string_init(name, name_length, 0); - bool retval = zend_update_static_property_ex(scope, key, value); + zend_result retval = zend_update_static_property_ex(scope, key, value); zend_string_efree(key); return retval; } @@ -4904,7 +4972,7 @@ ZEND_API ZEND_COLD const char *zend_get_object_type_case(const zend_class_entry } /* }}} */ -ZEND_API bool zend_is_iterable(zval *iterable) /* {{{ */ +ZEND_API bool zend_is_iterable(const zval *iterable) /* {{{ */ { switch (Z_TYPE_P(iterable)) { case IS_ARRAY: @@ -4917,7 +4985,7 @@ ZEND_API bool zend_is_iterable(zval *iterable) /* {{{ */ } /* }}} */ -ZEND_API bool zend_is_countable(zval *countable) /* {{{ */ +ZEND_API bool zend_is_countable(const zval *countable) /* {{{ */ { switch (Z_TYPE_P(countable)) { case IS_ARRAY: diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 635fbdeb60584..7c13c5e860b25 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -129,6 +129,7 @@ typedef struct _zend_fcall_info_cache { { #name, ZEND_TYPE_INIT_NONE(_ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), default_value }, #define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) \ { #name, ZEND_TYPE_INIT_NONE(_ZEND_ARG_INFO_FLAGS(pass_by_ref, 1, 0)), NULL }, + /* Arginfo structures with simple type information */ #define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) \ { #name, ZEND_TYPE_INIT_CODE(type_hint, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), NULL }, @@ -136,18 +137,23 @@ typedef struct _zend_fcall_info_cache { { #name, ZEND_TYPE_INIT_CODE(type_hint, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), default_value }, #define ZEND_ARG_VARIADIC_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) \ { #name, ZEND_TYPE_INIT_CODE(type_hint, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1, 0)), NULL }, + /* Arginfo structures with complex type information */ #define ZEND_ARG_TYPE_MASK(pass_by_ref, name, type_mask, default_value) \ { #name, ZEND_TYPE_INIT_MASK(type_mask | _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), default_value }, #define ZEND_ARG_OBJ_TYPE_MASK(pass_by_ref, name, class_name, type_mask, default_value) \ { #name, ZEND_TYPE_INIT_CLASS_CONST_MASK(#class_name, type_mask | _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), default_value }, +#define ZEND_ARG_VARIADIC_OBJ_TYPE_MASK(pass_by_ref, name, class_name, type_mask) \ + { #name, ZEND_TYPE_INIT_CLASS_CONST_MASK(#class_name, type_mask | _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1, 0)), NULL }, + /* Arginfo structures with object type information */ -#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) \ - { #name, ZEND_TYPE_INIT_CLASS_CONST(#classname, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), NULL }, -#define ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, classname, allow_null, default_value) \ - { #name, ZEND_TYPE_INIT_CLASS_CONST(#classname, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), default_value }, -#define ZEND_ARG_VARIADIC_OBJ_INFO(pass_by_ref, name, classname, allow_null) \ - { #name, ZEND_TYPE_INIT_CLASS_CONST(#classname, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1, 0)), NULL }, +#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, class_name, allow_null) \ + { #name, ZEND_TYPE_INIT_CLASS_CONST(#class_name, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), NULL }, +#define ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, class_name, allow_null, default_value) \ + { #name, ZEND_TYPE_INIT_CLASS_CONST(#class_name, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), default_value }, +#define ZEND_ARG_VARIADIC_OBJ_INFO(pass_by_ref, name, class_name, allow_null) \ + { #name, ZEND_TYPE_INIT_CLASS_CONST(#class_name, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1, 0)), NULL }, + /* Legacy arginfo structures */ #define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) \ { #name, ZEND_TYPE_INIT_CODE(IS_ARRAY, allow_null, _ZEND_ARG_INFO_FLAGS(pass_by_ref, 0, 0)), NULL }, @@ -156,7 +162,7 @@ typedef struct _zend_fcall_info_cache { #define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX2(name, return_reference, required_num_args, class_name, allow_null, is_tentative_return_type) \ static const zend_internal_arg_info name[] = { \ - { (const char*)(zend_uintptr_t)(required_num_args), \ + { (const char*)(uintptr_t)(required_num_args), \ ZEND_TYPE_INIT_CLASS_CONST(#class_name, allow_null, _ZEND_ARG_INFO_FLAGS(return_reference, 0, is_tentative_return_type)), NULL }, #define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \ @@ -170,7 +176,7 @@ typedef struct _zend_fcall_info_cache { #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX2(name, return_reference, required_num_args, type, is_tentative_return_type) \ static const zend_internal_arg_info name[] = { \ - { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_MASK(type | _ZEND_ARG_INFO_FLAGS(return_reference, 0, is_tentative_return_type)), NULL }, + { (const char*)(uintptr_t)(required_num_args), ZEND_TYPE_INIT_MASK(type | _ZEND_ARG_INFO_FLAGS(return_reference, 0, is_tentative_return_type)), NULL }, #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(name, return_reference, required_num_args, type) \ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX2(name, return_reference, required_num_args, type, 0) @@ -180,7 +186,7 @@ typedef struct _zend_fcall_info_cache { #define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX2(name, return_reference, required_num_args, class_name, type, is_tentative_return_type) \ static const zend_internal_arg_info name[] = { \ - { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CLASS_CONST_MASK(#class_name, type | _ZEND_ARG_INFO_FLAGS(return_reference, 0, is_tentative_return_type)), NULL }, + { (const char*)(uintptr_t)(required_num_args), ZEND_TYPE_INIT_CLASS_CONST_MASK(#class_name, type | _ZEND_ARG_INFO_FLAGS(return_reference, 0, is_tentative_return_type)), NULL }, #define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(name, return_reference, required_num_args, class_name, type) \ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX2(name, return_reference, required_num_args, class_name, type, 0) @@ -190,7 +196,7 @@ typedef struct _zend_fcall_info_cache { #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX2(name, return_reference, required_num_args, type, allow_null, is_tentative_return_type) \ static const zend_internal_arg_info name[] = { \ - { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_CODE(type, allow_null, _ZEND_ARG_INFO_FLAGS(return_reference, 0, is_tentative_return_type)), NULL }, + { (const char*)(uintptr_t)(required_num_args), ZEND_TYPE_INIT_CODE(type, allow_null, _ZEND_ARG_INFO_FLAGS(return_reference, 0, is_tentative_return_type)), NULL }, #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX2(name, return_reference, required_num_args, type, allow_null, 0) @@ -203,7 +209,7 @@ typedef struct _zend_fcall_info_cache { #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) \ static const zend_internal_arg_info name[] = { \ - { (const char*)(zend_uintptr_t)(required_num_args), ZEND_TYPE_INIT_NONE(_ZEND_ARG_INFO_FLAGS(return_reference, 0, 0)), NULL }, + { (const char*)(uintptr_t)(required_num_args), ZEND_TYPE_INIT_NONE(_ZEND_ARG_INFO_FLAGS(return_reference, 0, 0)), NULL }, #define ZEND_BEGIN_ARG_INFO(name, _unused) \ ZEND_BEGIN_ARG_INFO_EX(name, {}, ZEND_RETURN_VALUE, -1) #define ZEND_END_ARG_INFO() }; @@ -267,7 +273,7 @@ typedef struct _zend_fcall_info_cache { #endif #define INIT_CLASS_ENTRY(class_container, class_name, functions) \ - INIT_CLASS_ENTRY_EX(class_container, class_name, sizeof(class_name)-1, functions) + INIT_CLASS_ENTRY_EX(class_container, class_name, strlen(class_name), functions) #define INIT_CLASS_ENTRY_EX(class_container, class_name, class_name_len, functions) \ { \ @@ -355,6 +361,7 @@ ZEND_API zend_result zend_parse_parameters_ex(int flags, uint32_t num_args, cons #define zend_parse_parameters_throw(num_args, ...) \ zend_parse_parameters(num_args, __VA_ARGS__) ZEND_API const char *zend_zval_type_name(const zval *arg); +ZEND_API const char *zend_zval_value_name(const zval *arg); ZEND_API zend_string *zend_zval_get_legacy_type(const zval *arg); ZEND_API zend_result zend_parse_method_parameters(uint32_t num_args, zval *this_ptr, const char *type_spec, ...); @@ -409,7 +416,7 @@ ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t ZEND_API bool zend_is_callable(zval *callable, uint32_t check_flags, zend_string **callable_name); ZEND_API bool zend_make_callable(zval *callable, zend_string **callable_name); ZEND_API const char *zend_get_module_version(const char *module_name); -ZEND_API int zend_get_module_started(const char *module_name); +ZEND_API zend_result zend_get_module_started(const char *module_name); ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type); @@ -422,6 +429,7 @@ ZEND_API void zend_declare_property_double(zend_class_entry *ce, const char *nam ZEND_API void zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type); ZEND_API void zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type); +ZEND_API zend_class_constant *zend_declare_typed_class_constant(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment, zend_type type); ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int access_type, zend_string *doc_comment); ZEND_API void zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value); ZEND_API void zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length); @@ -431,6 +439,7 @@ ZEND_API void zend_declare_class_constant_double(zend_class_entry *ce, const cha ZEND_API void zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length); ZEND_API void zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value); +ZEND_API zend_result zend_update_class_constant(zend_class_constant *c, const zend_string *name, zend_class_entry *scope); ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type); ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_type); @@ -904,9 +913,9 @@ static zend_always_inline const char *zend_get_object_type_uc(const zend_class_e return zend_get_object_type_case(ce, true); } -ZEND_API bool zend_is_iterable(zval *iterable); +ZEND_API bool zend_is_iterable(const zval *iterable); -ZEND_API bool zend_is_countable(zval *countable); +ZEND_API bool zend_is_countable(const zval *countable); ZEND_API zend_result zend_get_default_from_internal_arg_info( zval *default_value_zval, zend_internal_arg_info *arg_info); @@ -2127,18 +2136,18 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char * /* Inlined implementations shared by new and old parameter parsing APIs */ ZEND_API bool ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **pce, uint32_t num, bool check_null); -ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, bool *dest, uint32_t arg_num); -ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest, uint32_t arg_num); -ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest, uint32_t arg_num); -ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest, uint32_t arg_num); -ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest, uint32_t arg_num); -ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest, uint32_t arg_num); +ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(const zval *arg, bool *dest, uint32_t arg_num); +ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(const zval *arg, bool *dest, uint32_t arg_num); +ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(const zval *arg, zend_long *dest, uint32_t arg_num); +ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(const zval *arg, zend_long *dest, uint32_t arg_num); +ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(const zval *arg, double *dest, uint32_t arg_num); +ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(const zval *arg, double *dest, uint32_t arg_num); ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest, uint32_t arg_num); ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest, uint32_t arg_num); ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest, uint32_t arg_num); ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_string **dest_str, zend_long *dest_long, uint32_t arg_num); -static zend_always_inline bool zend_parse_arg_bool(zval *arg, bool *dest, bool *is_null, bool check_null, uint32_t arg_num) +static zend_always_inline bool zend_parse_arg_bool(const zval *arg, bool *dest, bool *is_null, bool check_null, uint32_t arg_num) { if (check_null) { *is_null = 0; @@ -2172,7 +2181,7 @@ static zend_always_inline bool zend_parse_arg_long(zval *arg, zend_long *dest, b return 1; } -static zend_always_inline bool zend_parse_arg_double(zval *arg, double *dest, bool *is_null, bool check_null, uint32_t arg_num) +static zend_always_inline bool zend_parse_arg_double(const zval *arg, double *dest, bool *is_null, bool check_null, uint32_t arg_num) { if (check_null) { *is_null = 0; @@ -2283,7 +2292,7 @@ static zend_always_inline bool zend_parse_arg_array(zval *arg, zval **dest, bool return 1; } -static zend_always_inline bool zend_parse_arg_array_ht(zval *arg, HashTable **dest, bool check_null, bool or_object, bool separate) +static zend_always_inline bool zend_parse_arg_array_ht(const zval *arg, HashTable **dest, bool check_null, bool or_object, bool separate) { if (EXPECTED(Z_TYPE_P(arg) == IS_ARRAY)) { *dest = Z_ARRVAL_P(arg); @@ -2342,7 +2351,7 @@ static zend_always_inline bool zend_parse_arg_object(zval *arg, zval **dest, zen return 1; } -static zend_always_inline bool zend_parse_arg_obj(zval *arg, zend_object **dest, zend_class_entry *ce, bool check_null) +static zend_always_inline bool zend_parse_arg_obj(const zval *arg, zend_object **dest, zend_class_entry *ce, bool check_null) { if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT) && (!ce || EXPECTED(instanceof_function(Z_OBJCE_P(arg), ce) != 0))) { diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 5f11f49b07157..7335baf849d5e 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -396,8 +396,7 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, } #ifdef _WIN32 -void -stderr_last_error(char *msg) +static void stderr_last_error(char *msg) { DWORD err = GetLastError(); char *buf = php_win32_error_to_msg(err); @@ -774,7 +773,7 @@ static void *zend_mm_chunk_alloc(zend_mm_heap *heap, size_t size, size_t alignme #if ZEND_MM_STORAGE if (UNEXPECTED(heap->storage)) { void *ptr = heap->storage->handlers.chunk_alloc(heap->storage, size, alignment); - ZEND_ASSERT(((zend_uintptr_t)((char*)ptr + (alignment-1)) & (alignment-1)) == (zend_uintptr_t)ptr); + ZEND_ASSERT(((uintptr_t)((char*)ptr + (alignment-1)) & (alignment-1)) == (uintptr_t)ptr); return ptr; } #endif @@ -2171,7 +2170,7 @@ static void zend_mm_check_leaks(zend_mm_heap *heap) repeated = zend_mm_find_leaks_huge(heap, list); total += 1 + repeated; if (repeated) { - zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(zend_uintptr_t)repeated); + zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(uintptr_t)repeated); } heap->huge_list = list = list->next; @@ -2210,7 +2209,7 @@ static void zend_mm_check_leaks(zend_mm_heap *heap) zend_mm_find_leaks(heap, p, i + bin_pages[bin_num], &leak); total += 1 + repeated; if (repeated) { - zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(zend_uintptr_t)repeated); + zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(uintptr_t)repeated); } } dbg = (zend_mm_debug_info*)((char*)dbg + bin_data_size[bin_num]); @@ -2236,7 +2235,7 @@ static void zend_mm_check_leaks(zend_mm_heap *heap) repeated = zend_mm_find_leaks(heap, p, i + pages_count, &leak); total += 1 + repeated; if (repeated) { - zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(zend_uintptr_t)repeated); + zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(uintptr_t)repeated); } i += pages_count; } @@ -2291,7 +2290,10 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent) #if ZEND_DEBUG if (!silent) { - zend_mm_check_leaks(heap); + char *tmp = getenv("ZEND_ALLOC_PRINT_LEAKS"); + if (!tmp || ZEND_ATOL(tmp)) { + zend_mm_check_leaks(heap); + } } #endif diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 816caae12a7d6..6d5c5aaa44635 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -121,7 +121,6 @@ ZEND_API zend_ast *zend_ast_create_decl( ast->start_lineno = start_lineno; ast->end_lineno = CG(zend_lineno); ast->flags = flags; - ast->lex_pos = LANG_SCNG(yy_text); ast->doc_comment = doc_comment; ast->name = name; ast->child[0] = child0; @@ -497,12 +496,43 @@ zend_class_entry *zend_ast_fetch_class(zend_ast *ast, zend_class_entry *scope) return zend_fetch_class_with_scope(zend_ast_get_str(ast), (ast->attr >> ZEND_CONST_EXPR_NEW_FETCH_TYPE_SHIFT) | ZEND_FETCH_CLASS_EXCEPTION, scope); } +ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner( + zval *result, + zend_ast *ast, + zend_class_entry *scope, + bool *short_circuited_ptr, + zend_ast_evaluate_ctx *ctx +); + ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex( zval *result, zend_ast *ast, zend_class_entry *scope, bool *short_circuited_ptr, zend_ast_evaluate_ctx *ctx +) { + zend_string *previous_filename; + zend_long previous_lineno; + if (scope) { + previous_filename = EG(filename_override); + previous_lineno = EG(lineno_override); + EG(filename_override) = scope->info.user.filename; + EG(lineno_override) = zend_ast_get_lineno(ast); + } + zend_result r = zend_ast_evaluate_inner(result, ast, scope, short_circuited_ptr, ctx); + if (scope) { + EG(filename_override) = previous_filename; + EG(lineno_override) = previous_lineno; + } + return r; +} + +ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner( + zval *result, + zend_ast *ast, + zend_class_entry *scope, + bool *short_circuited_ptr, + zend_ast_evaluate_ctx *ctx ) { zval op1, op2; zend_result ret = SUCCESS; @@ -682,8 +712,8 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex( if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[0], scope, &short_circuited, ctx) != SUCCESS)) { ret = FAILURE; } else { - ZVAL_LONG(&op1, 0); - ret = sub_function(result, &op1, &op2); + ZVAL_LONG(&op1, -1); + ret = mul_function(result, &op1, &op2); zval_ptr_dtor_nogc(&op2); } break; @@ -804,7 +834,15 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex( case ZEND_AST_CLASS_CONST: { zend_string *class_name = zend_ast_get_str(ast->child[0]); - zend_string *const_name = zend_ast_get_str(ast->child[1]); + if (UNEXPECTED(zend_ast_evaluate_ex(&op2, ast->child[1], scope, &short_circuited, ctx) != SUCCESS)) { + return FAILURE; + } + if (UNEXPECTED(Z_TYPE(op2) != IS_STRING)) { + zend_invalid_class_constant_type_error(Z_TYPE(op2)); + zval_ptr_dtor_nogc(&op2); + return FAILURE; + } + zend_string *const_name = Z_STR(op2); zend_string *previous_filename; zend_long previous_lineno; @@ -822,9 +860,11 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex( if (UNEXPECTED(zv == NULL)) { ZVAL_UNDEF(result); + zval_ptr_dtor_nogc(&op2); return FAILURE; } ZVAL_COPY_OR_DUP(result, zv); + zval_ptr_dtor_nogc(&op2); break; } case ZEND_AST_NEW: @@ -1024,11 +1064,13 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf) new->attr = ast->attr; ZVAL_COPY(&new->val, zend_ast_get_zval(ast)); buf = (void*)((char*)buf + sizeof(zend_ast_zval)); + // Lineno gets copied with ZVAL_COPY } else if (ast->kind == ZEND_AST_CONSTANT) { zend_ast_zval *new = (zend_ast_zval*)buf; new->kind = ZEND_AST_CONSTANT; new->attr = ast->attr; ZVAL_STR_COPY(&new->val, zend_ast_get_constant_name(ast)); + Z_LINENO(new->val) = zend_ast_get_lineno(ast); buf = (void*)((char*)buf + sizeof(zend_ast_zval)); } else if (zend_ast_is_list(ast)) { zend_ast_list *list = zend_ast_get_list(ast); @@ -1037,6 +1079,7 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf) new->kind = list->kind; new->attr = list->attr; new->children = list->children; + new->lineno = list->lineno; buf = (void*)((char*)buf + zend_ast_list_size(list->children)); for (i = 0; i < list->children; i++) { if (list->child[i]) { diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 77c277f960115..73e4fed7a997a 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -161,7 +161,6 @@ enum _zend_ast_kind { ZEND_AST_CATCH, ZEND_AST_PROP_GROUP, ZEND_AST_PROP_ELEM, - ZEND_AST_CONST_ELEM, // Pseudo node for initializing enums ZEND_AST_CONST_ENUM_INIT, @@ -170,6 +169,7 @@ enum _zend_ast_kind { ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_FOREACH, ZEND_AST_ENUM_CASE, + ZEND_AST_CONST_ELEM, /* 5 child nodes */ ZEND_AST_PARAM = 5 << ZEND_AST_NUM_CHILDREN_SHIFT, @@ -208,7 +208,6 @@ typedef struct _zend_ast_decl { uint32_t start_lineno; uint32_t end_lineno; uint32_t flags; - unsigned char *lex_pos; zend_string *doc_comment; zend_string *name; zend_ast *child[5]; @@ -353,6 +352,9 @@ static zend_always_inline uint32_t zend_ast_get_lineno(zend_ast *ast) { if (ast->kind == ZEND_AST_ZVAL) { zval *zv = zend_ast_get_zval(ast); return Z_LINENO_P(zv); + } else if (ast->kind == ZEND_AST_CONSTANT) { + zval *zv = &((zend_ast_zval *) ast)->val; + return Z_LINENO_P(zv); } else { return ast->lineno; } diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c index b34092be038a2..2dbcb47392e9a 100644 --- a/Zend/zend_attributes.c +++ b/Zend/zend_attributes.c @@ -50,7 +50,7 @@ void validate_attribute(zend_attribute *attr, uint32_t target, zend_class_entry if (Z_TYPE(flags) != IS_LONG) { zend_error_noreturn(E_ERROR, "Attribute::__construct(): Argument #1 ($flags) must be of type int, %s given", - zend_zval_type_name(&flags) + zend_zval_value_name(&flags) ); } diff --git a/Zend/zend_bitset.h b/Zend/zend_bitset.h index fdb6ab79a1e86..262fab24a5ebe 100644 --- a/Zend/zend_bitset.h +++ b/Zend/zend_bitset.h @@ -19,6 +19,13 @@ #ifndef _ZEND_BITSET_H_ #define _ZEND_BITSET_H_ +#include +#include +#include + +#include "zend_portability.h" +#include "zend_long.h" + typedef zend_ulong *zend_bitset; #define ZEND_BITSET_ELM_SIZE sizeof(zend_ulong) diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index b3103393b833d..b8cd96c480282 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -110,7 +110,7 @@ ZEND_FUNCTION(gc_enable) ZEND_PARSE_PARAMETERS_NONE(); - key = zend_string_init("zend.enable_gc", sizeof("zend.enable_gc")-1, 0); + key = ZSTR_INIT_LITERAL("zend.enable_gc", 0); zend_alter_ini_entry_chars(key, "1", sizeof("1")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); zend_string_release_ex(key, 0); } @@ -123,7 +123,7 @@ ZEND_FUNCTION(gc_disable) ZEND_PARSE_PARAMETERS_NONE(); - key = zend_string_init("zend.enable_gc", sizeof("zend.enable_gc")-1, 0); + key = ZSTR_INIT_LITERAL("zend.enable_gc", 0); zend_alter_ini_entry_chars(key, "0", sizeof("0")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); zend_string_release_ex(key, 0); } @@ -511,8 +511,7 @@ ZEND_FUNCTION(define) register_constant: /* non persistent */ ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT); - c.name = zend_string_copy(name); - if (zend_register_constant(&c) == SUCCESS) { + if (zend_register_constant(name, &c) == SUCCESS) { RETURN_TRUE; } else { RETURN_FALSE; @@ -764,7 +763,7 @@ ZEND_FUNCTION(get_object_vars) } else { array_init_size(return_value, zend_hash_num_elements(properties)); - ZEND_HASH_MAP_FOREACH_KEY_VAL(properties, num_key, key, value) { + ZEND_HASH_FOREACH_KEY_VAL(properties, num_key, key, value) { bool is_dynamic = 1; if (Z_TYPE_P(value) == IS_INDIRECT) { value = Z_INDIRECT_P(value); @@ -868,6 +867,7 @@ ZEND_FUNCTION(method_exists) zend_class_entry *ce; zend_function *func; + /* We do not use Z_PARAM_OBJ_OR_STR here to be able to exclude int, float, and bool which are bogus class names */ ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ZVAL(klass) Z_PARAM_STR(method_name) @@ -880,7 +880,7 @@ ZEND_FUNCTION(method_exists) RETURN_FALSE; } } else { - zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(klass)); + zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_value_name(klass)); RETURN_THROWS(); } @@ -930,6 +930,7 @@ ZEND_FUNCTION(property_exists) zend_class_entry *ce; zend_property_info *property_info; + /* We do not use Z_PARAM_OBJ_OR_STR here to be able to exclude int, float, and bool which are bogus class names */ if (zend_parse_parameters(ZEND_NUM_ARGS(), "zS", &object, &property) == FAILURE) { RETURN_THROWS(); } @@ -942,7 +943,7 @@ ZEND_FUNCTION(property_exists) } else if (Z_TYPE_P(object) == IS_OBJECT) { ce = Z_OBJCE_P(object); } else { - zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(object)); + zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_value_name(object)); RETURN_THROWS(); } @@ -1074,16 +1075,11 @@ ZEND_FUNCTION(class_alias) ce = zend_lookup_class_ex(class_name, NULL, !autoload ? ZEND_FETCH_CLASS_NO_AUTOLOAD : 0); if (ce) { - if (ce->type == ZEND_USER_CLASS) { - if (zend_register_class_alias_ex(ZSTR_VAL(alias_name), ZSTR_LEN(alias_name), ce, 0) == SUCCESS) { - RETURN_TRUE; - } else { - zend_error(E_WARNING, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(alias_name)); - RETURN_FALSE; - } + if (zend_register_class_alias_ex(ZSTR_VAL(alias_name), ZSTR_LEN(alias_name), ce, false) == SUCCESS) { + RETURN_TRUE; } else { - zend_argument_value_error(1, "must be a user-defined class name, internal class name given"); - RETURN_THROWS(); + zend_error(E_WARNING, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(alias_name)); + RETURN_FALSE; } } else { zend_error(E_WARNING, "Class \"%s\" not found", ZSTR_VAL(class_name)); @@ -1483,6 +1479,7 @@ ZEND_FUNCTION(get_defined_constants) zend_constant *val; int module_number; zval *modules, const_val; + zend_string *const_name; char **module_names; zend_module_entry *module; int i = 1; @@ -1497,12 +1494,7 @@ ZEND_FUNCTION(get_defined_constants) } ZEND_HASH_FOREACH_END(); module_names[i] = "user"; - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), val) { - if (!val->name) { - /* skip special constants */ - continue; - } - + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(zend_constants), const_name, val) { if (ZEND_CONSTANT_MODULE_NUMBER(val) == PHP_USER_CONSTANT) { module_number = i; } else if (ZEND_CONSTANT_MODULE_NUMBER(val) > i) { @@ -1518,22 +1510,19 @@ ZEND_FUNCTION(get_defined_constants) } ZVAL_COPY_OR_DUP(&const_val, &val->value); - zend_hash_add_new(Z_ARRVAL(modules[module_number]), val->name, &const_val); + zend_hash_add_new(Z_ARRVAL(modules[module_number]), const_name, &const_val); } ZEND_HASH_FOREACH_END(); efree(module_names); efree(modules); } else { zend_constant *constant; + zend_string *const_name; zval const_val; - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) { - if (!constant->name) { - /* skip special constants */ - continue; - } + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(zend_constants), const_name, constant) { ZVAL_COPY_OR_DUP(&const_val, &constant->value); - zend_hash_add_new(Z_ARRVAL_P(return_value), constant->name, &const_val); + zend_hash_add_new(Z_ARRVAL_P(return_value), const_name, &const_val); } ZEND_HASH_FOREACH_END(); } } @@ -1724,6 +1713,32 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int return; } + if (EG(filename_override)) { + // Add the current execution point to the frame so we don't lose it + zend_string *filename_override = EG(filename_override); + zend_long lineno_override = EG(lineno_override); + EG(filename_override) = NULL; + EG(lineno_override) = -1; + + zend_string *filename = zend_get_executed_filename_ex(); + zend_long lineno = zend_get_executed_lineno(); + if (filename && (!zend_string_equals(filename, filename_override) || lineno != lineno_override)) { + stack_frame = zend_new_array(8); + zend_hash_real_init_mixed(stack_frame); + ZVAL_STR_COPY(&tmp, filename); + _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1); + ZVAL_LONG(&tmp, lineno); + _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1); + ZVAL_STR_COPY(&tmp, ZSTR_KNOWN(ZEND_STR_CONST_EXPR_PLACEHOLDER)); + _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1); + ZVAL_ARR(&tmp, stack_frame); + zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp); + } + + EG(filename_override) = filename_override; + EG(lineno_override) = lineno_override; + } + if (skip_last) { /* skip debug_backtrace() */ call = call->prev_execute_data; diff --git a/Zend/zend_call_stack.c b/Zend/zend_call_stack.c new file mode 100644 index 0000000000000..dadaa60dcb208 --- /dev/null +++ b/Zend/zend_call_stack.c @@ -0,0 +1,457 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Arnaud Le Blanc | + +----------------------------------------------------------------------+ +*/ + +/* Inspired from Chromium's stack_util.cc */ + +#include "zend.h" +#include "zend_globals.h" +#include "zend_portability.h" +#include "zend_call_stack.h" +#include +#ifdef ZEND_WIN32 +# include +# include +#else /* ZEND_WIN32 */ +# include +# ifdef HAVE_UNISTD_H +# include +# endif +# ifdef HAVE_SYS_TYPES_H +# include +# endif +#endif /* ZEND_WIN32 */ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) +# include +#endif +#ifdef __FreeBSD__ +# include +# include +# include +# include +#endif +#ifdef __linux__ +#include +#endif + +#ifdef ZEND_CHECK_STACK_LIMIT + +/* Called once per process or thread */ +ZEND_API void zend_call_stack_init(void) { + if (!zend_call_stack_get(&EG(call_stack))) { + EG(call_stack) = (zend_call_stack){0}; + } + + switch (EG(max_allowed_stack_size)) { + case ZEND_MAX_ALLOWED_STACK_SIZE_DETECT: { + void *base = EG(call_stack).base; + size_t size = EG(call_stack).max_size; + if (UNEXPECTED(base == (void*)0)) { + base = zend_call_stack_position(); + size = zend_call_stack_default_size(); + /* base is not the actual stack base */ + size -= 32 * 1024; + } + EG(stack_base) = base; + EG(stack_limit) = zend_call_stack_limit(base, size, EG(reserved_stack_size)); + break; + } + case ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED: { + EG(stack_base) = (void*)0; + EG(stack_limit) = (void*)0; + break; + } + default: { + ZEND_ASSERT(EG(max_allowed_stack_size) > 0); + void *base = EG(call_stack).base; + if (UNEXPECTED(base == (void*)0)) { + base = zend_call_stack_position(); + } + EG(stack_base) = base; + EG(stack_limit) = zend_call_stack_limit(base, EG(max_allowed_stack_size), EG(reserved_stack_size)); + break; + } + } +} + +#ifdef __linux__ +static bool zend_call_stack_is_main_thread(void) { +# ifdef HAVE_GETTID + return getpid() == gettid(); +# else + return getpid() == syscall(SYS_gettid); +# endif +} + +# ifdef HAVE_PTHREAD_GETATTR_NP +static bool zend_call_stack_get_linux_pthread(zend_call_stack *stack) +{ + pthread_attr_t attr; + int error; + void *addr; + size_t max_size; + + /* pthread_getattr_np() will return bogus values for the main thread with + * musl or with some old glibc versions */ + ZEND_ASSERT(!zend_call_stack_is_main_thread()); + + error = pthread_getattr_np(pthread_self(), &attr); + if (error) { + return false; + } + + error = pthread_attr_getstack(&attr, &addr, &max_size); + if (error) { + return false; + } + +# if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8)) + { + size_t guard_size; + /* In glibc prior to 2.8, addr and size include the guard pages */ + error = pthread_attr_getguardsize(&attr, &guard_size); + if (error) { + return false; + } + + addr = (int8_t*)addr + guard_size; + max_size -= guard_size; + } +# endif /* glibc < 2.8 */ + + stack->base = (int8_t*)addr + max_size; + stack->max_size = max_size; + + return true; +} +# else /* HAVE_PTHREAD_GETATTR_NP */ +static bool zend_call_stack_get_linux_pthread(zend_call_stack *stack) +{ + return false; +} +# endif /* HAVE_PTHREAD_GETATTR_NP */ + +static bool zend_call_stack_get_linux_proc_maps(zend_call_stack *stack) +{ + FILE *f; + char buffer[4096]; + uintptr_t addr_on_stack = (uintptr_t)&buffer; + uintptr_t start, end, prev_end = 0; + size_t max_size; + bool found = false; + struct rlimit rlim; + int error; + + /* This method is relevant only for the main thread */ + ZEND_ASSERT(zend_call_stack_is_main_thread()); + + /* Scan the process memory mappings to find the one containing the stack. + * + * The end of the stack mapping is the base of the stack. The start is + * adjusted by the kernel as the stack grows. The maximum stack size is + * determined by RLIMIT_STACK and the previous mapping. + * + * + * ^ Higher addresses ^ + * : : + * : : + * Mapping end --> |-------------------| <-- Stack base (stack start) + * | | ^ + * | Stack Mapping | | Stack size + * | | v + * Mapping start --> |-------------------| <-- Current stack end + * (adjusted : : + * downwards as the . . + * stack grows) : : + * |-------------------| + * | Some Mapping | The previous mapping may prevent + * |-------------------| stack growth + * : : + * : : + * v Lower addresses v + */ + + f = fopen("/proc/self/maps", "r"); + if (!f) { + return false; + } + + while (fgets(buffer, sizeof(buffer), f) && sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR, &start, &end) == 2) { + if (start <= addr_on_stack && end >= addr_on_stack) { + found = true; + break; + } + prev_end = end; + } + + fclose(f); + + if (!found) { + return false; + } + + error = getrlimit(RLIMIT_STACK, &rlim); + if (error || rlim.rlim_cur == RLIM_INFINITY) { + return false; + } + + max_size = rlim.rlim_cur; + + /* Previous mapping may prevent the stack from growing */ + if (end - max_size < prev_end) { + max_size = prev_end - end; + } + + stack->base = (void*)end; + stack->max_size = max_size; + + return true; +} + +static bool zend_call_stack_get_linux(zend_call_stack *stack) +{ + if (zend_call_stack_is_main_thread()) { + return zend_call_stack_get_linux_proc_maps(stack); + } + + return zend_call_stack_get_linux_pthread(stack); +} +#else /* __linux__ */ +static bool zend_call_stack_get_linux(zend_call_stack *stack) +{ + return false; +} +#endif /* __linux__ */ + +#ifdef __FreeBSD__ +static bool zend_call_stack_is_main_thread(void) +{ + int is_main = pthread_main_np(); + return is_main == -1 || is_main == 1; +} + +# if defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GET_STACK) +static bool zend_call_stack_get_freebsd_pthread(zend_call_stack *stack) +{ + pthread_attr_t attr; + int error; + void *addr; + size_t max_size; + size_t guard_size; + + /* pthread will return bogus values for the main thread */ + ZEND_ASSERT(!zend_call_stack_is_main_thread()); + + pthread_attr_init(&attr); + + error = pthread_attr_get_np(pthread_self(), &attr); + if (error) { + goto fail; + } + + error = pthread_attr_getstack(&attr, &addr, &max_size); + if (error) { + goto fail; + } + + stack->base = (int8_t*)addr + max_size; + stack->max_size = max_size; + + pthread_attr_destroy(&attr); + return true; + +fail: + pthread_attr_destroy(&attr); + return false; +} +# else /* defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GET_STACK) */ +static bool zend_call_stack_get_freebsd_pthread(zend_call_stack *stack) +{ + return false; +} +# endif /* defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GET_STACK) */ + +static bool zend_call_stack_get_freebsd_sysctl(zend_call_stack *stack) +{ + void *stack_base; + int mib[2] = {CTL_KERN, KERN_USRSTACK}; + size_t len = sizeof(stack_base); + struct rlimit rlim; + + /* This method is relevant only for the main thread */ + ZEND_ASSERT(zend_call_stack_is_main_thread()); + + if (sysctl(mib, sizeof(mib)/sizeof(*mib), &stack_base, &len, NULL, 0) != 0) { + return false; + } + + if (getrlimit(RLIMIT_STACK, &rlim) != 0) { + return false; + } + + if (rlim.rlim_cur == RLIM_INFINITY) { + return false; + } + + size_t guard_size = getpagesize(); + + stack->base = stack_base; + stack->max_size = rlim.rlim_cur - guard_size; + + return true; +} + +static bool zend_call_stack_get_freebsd(zend_call_stack *stack) +{ + if (zend_call_stack_is_main_thread()) { + return zend_call_stack_get_freebsd_sysctl(stack); + } + + return zend_call_stack_get_freebsd_pthread(stack); +} +#else +static bool zend_call_stack_get_freebsd(zend_call_stack *stack) +{ + return false; +} +#endif /* __FreeBSD__ */ + +#ifdef ZEND_WIN32 +static bool zend_call_stack_get_win32(zend_call_stack *stack) +{ + ULONG_PTR low_limit, high_limit; + ULONG size; + MEMORY_BASIC_INFORMATION guard_region = {0}, uncommitted_region = {0}; + size_t result_size, page_size; + + /* The stack consists of three regions: committed, guard, and uncommitted. + * Memory is committed when the guard region is accessed. If only one page + * is left in the uncommitted region, a stack overflow error is raised + * instead. + * + * The total useable stack size is the size of the committed and uncommitted + * regions less one page. + * + * http://blogs.msdn.com/b/satyem/archive/2012/08/13/thread-s-stack-memory-management.aspx + * https://learn.microsoft.com/en-us/windows/win32/procthread/thread-stack-size + * + * ^ Higher addresses ^ + * : : + * : : + * high_limit --> |--------------------| + * ^ | | + * | | Committed region | + * | | | + * | |------------------- | <-- guard_region.BaseAddress + * reserved | | | + guard_region.RegionSize + * size | | Guard region | + * | | | + * | |--------------------| <-- guard_region.BaseAddress, + * | | | uncommitted_region.BaseAddress + * | | Uncommitted region | + uncommitted_region.RegionSize + * v | | + * low_limit --> |------------------- | <-- uncommitted_region.BaseAddress + * : : + * : : + * v Lower addresses v + */ + + GetCurrentThreadStackLimits(&low_limit, &high_limit); + + result_size = VirtualQuery((void*)low_limit, + &uncommitted_region, sizeof(uncommitted_region)); + ZEND_ASSERT(result_size >= sizeof(uncommitted_region)); + + result_size = VirtualQuery((int8_t*)uncommitted_region.BaseAddress + uncommitted_region.RegionSize, + &guard_region, sizeof(guard_region)); + ZEND_ASSERT(result_size >= sizeof(uncommitted_region)); + + stack->base = (void*)high_limit; + stack->max_size = (uintptr_t)high_limit - (uintptr_t)low_limit; + + ZEND_ASSERT(stack->max_size > guard_region.RegionSize); + stack->max_size -= guard_region.RegionSize; + + /* The uncommitted region does not shrink below 1 page */ + page_size = zend_get_page_size(); + ZEND_ASSERT(stack->max_size > page_size); + stack->max_size -= page_size; + + return true; +} +#else /* ZEND_WIN32 */ +static bool zend_call_stack_get_win32(zend_call_stack *stack) +{ + return false; +} +#endif /* ZEND_WIN32 */ + +#if defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) +static bool zend_call_stack_get_macos(zend_call_stack *stack) +{ + void *base = pthread_get_stackaddr_np(pthread_self()); + size_t max_size; + + if (pthread_main_np()) { + /* pthread_get_stacksize_np() returns a too low value for the main + * thread in OSX 10.9, 10.10: + * https://mail.openjdk.org/pipermail/hotspot-dev/2013-October/011353.html + * https://github.com/rust-lang/rust/issues/43347 + */ + + /* Stack size is 8MiB by default for main threads + * https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html */ + max_size = 8 * 1024 * 1024; + } else { + max_size = pthread_get_stacksize_np(pthread_self()); + } + + stack->base = base; + stack->max_size = max_size; + + return true; +} +#else /* defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) */ +static bool zend_call_stack_get_macos(zend_call_stack *stack) +{ + return false; +} +#endif /* defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) */ + +/** Get the stack information for the calling thread */ +ZEND_API bool zend_call_stack_get(zend_call_stack *stack) +{ + if (zend_call_stack_get_linux(stack)) { + return true; + } + + if (zend_call_stack_get_freebsd(stack)) { + return true; + } + + if (zend_call_stack_get_win32(stack)) { + return true; + } + + if (zend_call_stack_get_macos(stack)) { + return true; + } + + return false; +} + +#endif /* ZEND_CHECK_STACK_LIMIT */ diff --git a/Zend/zend_call_stack.h b/Zend/zend_call_stack.h new file mode 100644 index 0000000000000..c71395bd6d42c --- /dev/null +++ b/Zend/zend_call_stack.h @@ -0,0 +1,91 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Arnaud Le Blanc | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_CALL_STACK_H +#define ZEND_CALL_STACK_H + +#include "zend.h" +#include "zend_portability.h" +#ifdef __APPLE__ +# include +#endif + +#ifdef ZEND_CHECK_STACK_LIMIT + +typedef struct _zend_call_stack { + void *base; + size_t max_size; +} zend_call_stack; + +ZEND_API void zend_call_stack_init(void); + +ZEND_API bool zend_call_stack_get(zend_call_stack *stack); + +/** Returns an approximation of the current stack position */ +static zend_always_inline void *zend_call_stack_position(void) { +#ifdef ZEND_WIN32 + return _AddressOfReturnAddress(); +#elif PHP_HAVE_BUILTIN_FRAME_ADDRESS + return __builtin_frame_address(0); +#else + void *a; + void *pos = (void*)&a; + return pos; +#endif +} + +static zend_always_inline bool zend_call_stack_overflowed(void *stack_limit) { + return (uintptr_t) zend_call_stack_position() <= (uintptr_t) stack_limit; +} + +static inline void* zend_call_stack_limit(void *base, size_t size, size_t reserved_size) +{ + if (UNEXPECTED(size > (uintptr_t)base)) { + return (void*)0; + } + + base = (int8_t*)base - size; + + if (UNEXPECTED(UINTPTR_MAX - (uintptr_t)base < reserved_size)) { + return (void*)UINTPTR_MAX; + } + + return (int8_t*)base + reserved_size; +} + +static inline size_t zend_call_stack_default_size(void) +{ +#ifdef __linux__ + return 8 * 1024 * 1024; +#endif +#ifdef __FreeBSD__ + return 8 * 1024 * 1024; +#endif +#ifdef __APPLE__ + // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html + if (pthread_main_np()) { + return 8 * 1024 * 1024; + } + return 512 * 1024; +#endif + + return 2 * 1024 * 1024; +} + +#endif /* ZEND_CHECK_STACK_LIMIT */ +#endif /* ZEND_CALL_STACK_H */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index fc5216b797082..084c47f45bc47 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -34,6 +34,7 @@ #include "zend_vm.h" #include "zend_enum.h" #include "zend_observer.h" +#include "zend_call_stack.h" #define SET_NODE(target, src) do { \ target ## _type = (src)->op_type; \ @@ -56,8 +57,8 @@ #define FC(member) (CG(file_context).member) typedef struct _zend_loop_var { - zend_uchar opcode; - zend_uchar var_type; + uint8_t opcode; + uint8_t var_type; uint32_t var_num; uint32_t try_catch_offset; } zend_loop_var; @@ -88,7 +89,7 @@ ZEND_API zend_compiler_globals compiler_globals; ZEND_API zend_executor_globals executor_globals; #endif -static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2); +static zend_op *zend_emit_op(znode *result, uint8_t opcode, znode *op1, znode *op2); static bool zend_try_ct_eval_array(zval *result, zend_ast *ast); static void zend_eval_const_expr(zend_ast **ast_ptr); @@ -212,7 +213,7 @@ void zend_assert_valid_class_name(const zend_string *name) /* {{{ */ typedef struct _builtin_type_info { const char* name; const size_t name_len; - const zend_uchar type; + const uint8_t type; } builtin_type_info; static const builtin_type_info builtin_types[] = { @@ -245,7 +246,7 @@ static const confusable_type_info confusable_types[] = { {NULL, 0, NULL}, }; -static zend_always_inline zend_uchar zend_lookup_builtin_type_by_name(const zend_string *name) /* {{{ */ +static zend_always_inline uint8_t zend_lookup_builtin_type_by_name(const zend_string *name) /* {{{ */ { const builtin_type_info *info = &builtin_types[0]; @@ -378,7 +379,7 @@ void zend_init_compiler_data_structures(void) /* {{{ */ CG(encoding_declared) = 0; CG(memoized_exprs) = NULL; - CG(memoize_mode) = 0; + CG(memoize_mode) = ZEND_MEMOIZE_NONE; } /* }}} */ @@ -658,7 +659,7 @@ void zend_stop_lexing(void) } static inline void zend_begin_loop( - zend_uchar free_opcode, const znode *loop_var, bool is_switch) /* {{{ */ + uint8_t free_opcode, const znode *loop_var, bool is_switch) /* {{{ */ { zend_brk_cont_element *brk_cont_element; int parent = CG(context).current_brk_cont; @@ -902,6 +903,25 @@ uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */ } /* }}} */ +uint32_t zend_add_anonymous_class_modifier(uint32_t flags, uint32_t new_flag) +{ + uint32_t new_flags = flags | new_flag; + if (new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) { + zend_throw_exception(zend_ce_compile_error, + "Cannot use the abstract modifier on an anonymous class", 0); + return 0; + } + if (new_flag & ZEND_ACC_FINAL) { + zend_throw_exception(zend_ce_compile_error, "Cannot use the final modifier on an anonymous class", 0); + return 0; + } + if ((flags & ZEND_ACC_READONLY_CLASS) && (new_flag & ZEND_ACC_READONLY_CLASS)) { + zend_throw_exception(zend_ce_compile_error, "Multiple readonly modifiers are not allowed", 0); + return 0; + } + return new_flags; +} + uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag, zend_modifier_target target) /* {{{ */ { uint32_t new_flags = flags | new_flag; @@ -1591,7 +1611,7 @@ static inline bool class_name_refers_to_active_ce(zend_string *class_name, uint3 } /* }}} */ -uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ */ +uint32_t zend_get_class_fetch_type(const zend_string *name) /* {{{ */ { if (zend_string_equals_literal_ci(name, "self")) { return ZEND_FETCH_CLASS_SELF; @@ -1996,7 +2016,7 @@ zend_ast *zend_negate_num_string(zend_ast *ast) /* {{{ */ zval *zv = zend_ast_get_zval(ast); if (Z_TYPE_P(zv) == IS_LONG) { if (Z_LVAL_P(zv) == 0) { - ZVAL_NEW_STR(zv, zend_string_init("-0", sizeof("-0")-1, 0)); + ZVAL_NEW_STR(zv, ZSTR_INIT_LITERAL("-0", 0)); } else { ZEND_ASSERT(Z_LVAL_P(zv) > 0); Z_LVAL_P(zv) *= -1; @@ -2090,7 +2110,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len) static void zend_adjust_for_fetch_type(zend_op *opline, znode *result, uint32_t type) /* {{{ */ { - zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3; + uint_fast8_t factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3; switch (type) { case BP_VAR_R: @@ -2135,7 +2155,7 @@ static inline void zend_make_tmp_result(znode *result, zend_op *opline) /* {{{ * } /* }}} */ -static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2) /* {{{ */ +static zend_op *zend_emit_op(znode *result, uint8_t opcode, znode *op1, znode *op2) /* {{{ */ { zend_op *opline = get_next_op(); opline->opcode = opcode; @@ -2155,7 +2175,7 @@ static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode } /* }}} */ -static zend_op *zend_emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, znode *op2) /* {{{ */ +static zend_op *zend_emit_op_tmp(znode *result, uint8_t opcode, znode *op1, znode *op2) /* {{{ */ { zend_op *opline = get_next_op(); opline->opcode = opcode; @@ -2235,7 +2255,7 @@ ZEND_API bool zend_is_smart_branch(const zend_op *opline) /* {{{ */ } /* }}} */ -static inline uint32_t zend_emit_cond_jump(zend_uchar opcode, znode *cond, uint32_t opnum_target) /* {{{ */ +static inline uint32_t zend_emit_cond_jump(uint8_t opcode, znode *cond, uint32_t opnum_target) /* {{{ */ { uint32_t opnum = get_next_op_number(); zend_op *opline; @@ -2286,7 +2306,7 @@ static inline void zend_update_jump_target_to_next(uint32_t opnum_jump) /* {{{ * } /* }}} */ -static inline zend_op *zend_delayed_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2) /* {{{ */ +static inline zend_op *zend_delayed_emit_op(znode *result, uint8_t opcode, znode *op1, znode *op2) /* {{{ */ { zend_op tmp_opline; @@ -2425,13 +2445,9 @@ static void zend_emit_jmp_null(znode *obj_node, uint32_t bp_type) zend_stack_push(&CG(short_circuiting_opnums), &jmp_null_opnum); } -#define ZEND_MEMOIZE_NONE 0 -#define ZEND_MEMOIZE_COMPILE 1 -#define ZEND_MEMOIZE_FETCH 2 - static void zend_compile_memoized_expr(znode *result, zend_ast *expr) /* {{{ */ { - int memoize_mode = CG(memoize_mode); + const zend_memoize_mode memoize_mode = CG(memoize_mode); if (memoize_mode == ZEND_MEMOIZE_COMPILE) { znode memoized_result; @@ -3022,6 +3038,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t opline = zend_delayed_emit_op(result, ZEND_FETCH_OBJ_R, &obj_node, &prop_node); if (opline->op2_type == IS_CONST) { convert_to_string(CT_CONSTANT(opline->op2)); + zend_string_hash_val(Z_STR_P(CT_CONSTANT(opline->op2))); opline->extended_value = zend_alloc_cache_slots(3); } @@ -3574,7 +3591,7 @@ static uint32_t zend_compile_args( znode arg_node; zend_op *opline; - zend_uchar opcode; + uint8_t opcode; if (arg->kind == ZEND_AST_UNPACK) { if (uses_named_args) { @@ -3753,7 +3770,7 @@ static uint32_t zend_compile_args( } /* }}} */ -ZEND_API zend_uchar zend_get_call_op(const zend_op *init_op, zend_function *fbc) /* {{{ */ +ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc) /* {{{ */ { if (fbc) { ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)); @@ -4204,7 +4221,7 @@ static void zend_compile_assert(znode *result, zend_ast_list *args, zend_string /* If the original argument was named, add the new argument as named as well, * as mixing named and positional is not allowed. */ zend_ast *name = zend_ast_create_zval_from_str( - zend_string_init("description", sizeof("description") - 1, 0)); + ZSTR_INIT_LITERAL("description", 0)); arg = zend_ast_create(ZEND_AST_NAMED_ARG, name, arg); } zend_ast_list_add((zend_ast *) args, arg); @@ -5526,9 +5543,9 @@ static void zend_compile_if(zend_ast *ast) /* {{{ */ } /* }}} */ -static zend_uchar determine_switch_jumptable_type(zend_ast_list *cases) { +static uint8_t determine_switch_jumptable_type(zend_ast_list *cases) { uint32_t i; - zend_uchar common_type = IS_UNDEF; + uint8_t common_type = IS_UNDEF; for (i = 0; i < cases->children; i++) { zend_ast *case_ast = cases->child[i]; zend_ast **cond_ast = &case_ast->child[0]; @@ -5567,7 +5584,7 @@ static zend_uchar determine_switch_jumptable_type(zend_ast_list *cases) { return common_type; } -static bool should_use_jumptable(zend_ast_list *cases, zend_uchar jumptable_type) { +static bool should_use_jumptable(zend_ast_list *cases, uint8_t jumptable_type) { if (CG(compiler_options) & ZEND_COMPILE_NO_JUMPTABLES) { return 0; } @@ -5593,7 +5610,7 @@ static void zend_compile_switch(zend_ast *ast) /* {{{ */ znode expr_node, case_node; zend_op *opline; uint32_t *jmpnz_opnums, opnum_default_jmp, opnum_switch = (uint32_t)-1; - zend_uchar jumptable_type; + uint8_t jumptable_type; HashTable *jumptable = NULL; zend_compile_expr(&expr_node, expr_ast); @@ -5775,7 +5792,7 @@ static void zend_compile_match(znode *result, zend_ast *ast) case_node.u.op.var = get_temporary_variable(); uint32_t num_conds = count_match_conds(arms); - zend_uchar can_use_jumptable = can_match_use_jumptable(arms); + uint8_t can_use_jumptable = can_match_use_jumptable(arms); bool uses_jumptable = can_use_jumptable && num_conds >= 2; HashTable *jumptable = NULL; uint32_t *jmpnz_opnums = NULL; @@ -6305,7 +6322,7 @@ static zend_type zend_compile_single_typename(zend_ast *ast) return (zend_type) ZEND_TYPE_INIT_CODE(ast->attr, 0, 0); } else { zend_string *class_name = zend_ast_get_str(ast); - zend_uchar type_code = zend_lookup_builtin_type_by_name(class_name); + uint8_t type_code = zend_lookup_builtin_type_by_name(class_name); if (type_code != 0) { if ((ast->attr & ZEND_NAME_NOT_FQ) != ZEND_NAME_NOT_FQ) { @@ -6853,7 +6870,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 uint32_t property_flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_READONLY); znode var_node, default_node; - zend_uchar opcode; + uint8_t opcode; zend_op *opline; zend_arg_info *arg_info; @@ -7278,9 +7295,9 @@ static void add_stringable_interface(zend_class_entry *ce) { erealloc(ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces); // TODO: Add known interned strings instead? ce->interface_names[ce->num_interfaces - 1].name = - zend_string_init("Stringable", sizeof("Stringable") - 1, 0); + ZSTR_INIT_LITERAL("Stringable", 0); ce->interface_names[ce->num_interfaces - 1].lc_name = - zend_string_init("stringable", sizeof("stringable") - 1, 0); + ZSTR_INIT_LITERAL("stringable", 0); } static zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name, bool has_body) /* {{{ */ @@ -7392,11 +7409,7 @@ static zend_string *zend_begin_func_decl(znode *result, zend_op_array *op_array, } zend_register_seen_symbol(lcname, ZEND_SYMBOL_FUNCTION); - if (toplevel) { - if (UNEXPECTED(zend_hash_add_ptr(CG(function_table), lcname, op_array) == NULL)) { - do_bind_function_error(lcname, op_array, 1); - } - } else { + if (!toplevel) { uint32_t func_ref = zend_add_dynamic_func_def(op_array); if (op_array->fn_flags & ZEND_ACC_CLOSURE) { opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL); @@ -7421,7 +7434,7 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel) zend_ast *stmt_ast = decl->child[2]; zend_ast *return_type_ast = decl->child[3]; bool is_method = decl->kind == ZEND_AST_METHOD; - zend_string *lcname = NULL; + zend_string *lcname; zend_class_entry *orig_class_entry = CG(active_class_entry); zend_op_array *orig_op_array = CG(active_op_array); @@ -7525,6 +7538,11 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel) CG(zend_lineno) = decl->start_lineno; zend_check_magic_method_implementation( CG(active_class_entry), (zend_function *) op_array, lcname, E_COMPILE_ERROR); + } else if (toplevel) { + /* Only register the function after a successful compile */ + if (UNEXPECTED(zend_hash_add_ptr(CG(function_table), lcname, op_array) == NULL)) { + do_bind_function_error(lcname, op_array, true); + } } /* put the implicit return on the really last line */ @@ -7613,7 +7631,7 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f } else { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as default value for property %s::$%s of type %s", - zend_zval_type_name(&value_zv), + zend_zval_value_name(&value_zv), ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(str)); } } @@ -7675,7 +7693,7 @@ static void zend_check_trait_alias_modifiers(uint32_t attr) /* {{{ */ } /* }}} */ -static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr_ast) /* {{{ */ +static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr_ast) { zend_ast_list *list = zend_ast_get_list(ast); zend_class_entry *ce = CG(active_class_entry); @@ -7687,9 +7705,24 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as zend_ast *name_ast = const_ast->child[0]; zend_ast **value_ast_ptr = &const_ast->child[1]; zend_ast *doc_comment_ast = const_ast->child[2]; + zend_ast *type_ast = const_ast->child[3]; zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast)); zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL; zval value_zv; + zend_type type = ZEND_TYPE_INIT_NONE(0); + + if (type_ast) { + type = zend_compile_typename(type_ast, /* force_allow_null */ 0); + + uint32_t type_mask = ZEND_TYPE_PURE_MASK(type); + + if (type_mask != MAY_BE_ANY && (type_mask & (MAY_BE_CALLABLE|MAY_BE_VOID|MAY_BE_NEVER))) { + zend_string *type_str = zend_type_to_string(type); + + zend_error_noreturn(E_COMPILE_ERROR, "Class constant %s::%s cannot have type %s", + ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(type_str)); + } + } if (UNEXPECTED((flags & ZEND_ACC_PRIVATE) && (flags & ZEND_ACC_FINAL))) { zend_error_noreturn( @@ -7699,14 +7732,21 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as } zend_const_expr_to_zval(&value_zv, value_ast_ptr, /* allow_dynamic */ false); - c = zend_declare_class_constant_ex(ce, name, &value_zv, flags, doc_comment); + + if (!Z_CONSTANT(value_zv) && ZEND_TYPE_IS_SET(type) && !zend_is_valid_default_value(type, &value_zv)) { + zend_string *type_str = zend_type_to_string(type); + + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as value for class constant %s::%s of type %s", + zend_zval_type_name(&value_zv), ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(type_str)); + } + + c = zend_declare_typed_class_constant(ce, name, &value_zv, flags, doc_comment, type); if (attr_ast) { zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, 0); } } } -/* }}} */ static void zend_compile_class_const_group(zend_ast *ast) /* {{{ */ { @@ -8197,12 +8237,6 @@ static void zend_compile_use(zend_ast *ast) /* {{{ */ zend_string *old_name = zend_ast_get_str(old_name_ast); zend_string *new_name, *lookup_name; - /* Check that we are not attempting to alias a built-in type */ - if (type == ZEND_SYMBOL_CLASS && zend_is_reserved_class_name(old_name)) { - zend_error_noreturn(E_COMPILE_ERROR, - "Cannot alias '%s' as it is a built-in type", ZSTR_VAL(old_name)); - } - if (new_name_ast) { new_name = zend_string_copy(zend_ast_get_str(new_name_ast)); } else { @@ -8499,7 +8533,7 @@ static bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast) /* {{{ */ } /* }}} */ -ZEND_API bool zend_is_op_long_compatible(zval *op) +ZEND_API bool zend_is_op_long_compatible(const zval *op) { if (Z_TYPE_P(op) == IS_ARRAY) { return false; @@ -8512,7 +8546,7 @@ ZEND_API bool zend_is_op_long_compatible(zval *op) if (Z_TYPE_P(op) == IS_STRING) { double dval = 0; - zend_uchar is_num = is_numeric_str_function(Z_STR_P(op), NULL, &dval); + uint8_t is_num = is_numeric_str_function(Z_STR_P(op), NULL, &dval); if (is_num == 0 || (is_num == IS_DOUBLE && !zend_is_long_compatible(dval, zend_dval_to_lval(dval)))) { return false; } @@ -8521,7 +8555,7 @@ ZEND_API bool zend_is_op_long_compatible(zval *op) return true; } -ZEND_API bool zend_binary_op_produces_error(uint32_t opcode, zval *op1, zval *op2) /* {{{ */ +ZEND_API bool zend_binary_op_produces_error(uint32_t opcode, const zval *op1, const zval *op2) /* {{{ */ { if ((opcode == ZEND_CONCAT || opcode == ZEND_FAST_CONCAT)) { /* Array to string warning. */ @@ -8594,7 +8628,7 @@ static inline bool zend_try_ct_eval_binary_op(zval *result, uint32_t opcode, zva } /* }}} */ -ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, zval *op) +ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, const zval *op) { if (opcode == ZEND_BW_NOT) { /* BW_NOT on string does not convert the string into an integer. */ @@ -9183,7 +9217,7 @@ static void zend_compile_assign_coalesce(znode *result, zend_ast *ast) /* {{{ */ /* Remember expressions compiled during the initial BP_VAR_IS lookup, * to avoid double-evaluation when we compile again with BP_VAR_W. */ HashTable *orig_memoized_exprs = CG(memoized_exprs); - int orig_memoize_mode = CG(memoize_mode); + const zend_memoize_mode orig_memoize_mode = CG(memoize_mode); zend_ensure_writable_variable(var_ast); if (is_this_fetch(var_ast)) { @@ -9668,16 +9702,18 @@ static void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */ class_ast = ast->child[0]; const_ast = ast->child[1]; - if (class_ast->kind == ZEND_AST_ZVAL) { - zend_string *resolved_name; - - resolved_name = zend_resolve_class_name_ast(class_ast); - if (const_ast->kind == ZEND_AST_ZVAL && zend_try_ct_eval_class_const(&result->u.constant, resolved_name, zend_ast_get_str(const_ast))) { - result->op_type = IS_CONST; + if (class_ast->kind == ZEND_AST_ZVAL && const_ast->kind == ZEND_AST_ZVAL) { + zval *const_zv = zend_ast_get_zval(const_ast); + if (Z_TYPE_P(const_zv) == IS_STRING) { + zend_string *const_str = Z_STR_P(const_zv); + zend_string *resolved_name = zend_resolve_class_name_ast(class_ast); + if (zend_try_ct_eval_class_const(&result->u.constant, resolved_name, const_str)) { + result->op_type = IS_CONST; + zend_string_release_ex(resolved_name, 0); + return; + } zend_string_release_ex(resolved_name, 0); - return; } - zend_string_release_ex(resolved_name, 0); } zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION); @@ -9688,7 +9724,9 @@ static void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */ zend_set_class_name_op1(opline, &class_node); - opline->extended_value = zend_alloc_cache_slots(2); + if (opline->op1_type == IS_CONST || opline->op2_type == IS_CONST) { + opline->extended_value = zend_alloc_cache_slots(2); + } } /* }}} */ @@ -9710,8 +9748,8 @@ static void zend_compile_class_name(znode *result, zend_ast *ast) /* {{{ */ if (expr_node.op_type == IS_CONST) { /* Unlikely case that happen if class_ast is constant folded. * Handle it here, to avoid needing a CONST specialization in the VM. */ - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"::class\" on value of type %s", - zend_zval_type_name(&expr_node.u.constant)); + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"::class\" on %s", + zend_zval_value_name(&expr_node.u.constant)); } zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, &expr_node, NULL); @@ -9990,6 +10028,8 @@ static void zend_compile_const_expr_const(zend_ast **ast_ptr) /* {{{ */ zval result; zend_string *resolved_name; + CG(zend_lineno) = zend_ast_get_lineno(ast); + resolved_name = zend_resolve_const_name( orig_name, name_ast->attr, &is_fully_qualified); @@ -10425,6 +10465,14 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */ static void zend_compile_expr(znode *result, zend_ast *ast) { +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_error_noreturn(E_COMPILE_ERROR, + "Maximum call stack size of %zu bytes reached during compilation. Try splitting expression", + (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit))); + } +#endif /* ZEND_CHECK_STACK_LIMIT */ + uint32_t checkpoint = zend_short_circuiting_checkpoint(); zend_compile_expr_inner(result, ast); zend_short_circuiting_commit(checkpoint, result, ast); @@ -10680,7 +10728,7 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ } } else if (Z_TYPE_P(container) == IS_STRING) { zend_long offset; - zend_uchar c; + uint8_t c; if (Z_TYPE_P(dim) == IS_LONG) { offset = Z_LVAL_P(dim); } else if (Z_TYPE_P(dim) != IS_STRING || is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, 1) != IS_LONG) { @@ -10689,7 +10737,7 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ if (offset < 0 || (size_t)offset >= Z_STRLEN_P(container)) { return; } - c = (zend_uchar) Z_STRVAL_P(container)[offset]; + c = (uint8_t) Z_STRVAL_P(container)[offset]; ZVAL_CHAR(&result, c); } else if (Z_TYPE_P(container) <= IS_FALSE) { return; /* warning... handle at runtime */ @@ -10732,6 +10780,11 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ zend_eval_const_expr(&ast->child[0]); zend_eval_const_expr(&ast->child[1]); + if (UNEXPECTED(ast->child[1]->kind != ZEND_AST_ZVAL + || Z_TYPE_P(zend_ast_get_zval(ast->child[1])) != IS_STRING)) { + return; + } + class_ast = ast->child[0]; name_ast = ast->child[1]; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index fa9e582869fbd..d474d13e86d42 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -24,6 +24,7 @@ #include "zend_ast.h" #include +#include #include "zend_llist.h" @@ -33,9 +34,6 @@ } while (0) #define MAKE_NOP(opline) do { \ - (opline)->op1.num = 0; \ - (opline)->op2.num = 0; \ - (opline)->result.num = 0; \ (opline)->opcode = ZEND_NOP; \ SET_UNUSED((opline)->op1); \ SET_UNUSED((opline)->op2); \ @@ -79,8 +77,8 @@ typedef union _znode_op { } znode_op; typedef struct _znode { /* used only during compilation */ - zend_uchar op_type; - zend_uchar flag; + uint8_t op_type; + uint8_t flag; union { znode_op op; zval constant; /* replaced by literal/zv */ @@ -140,10 +138,10 @@ struct _zend_op { znode_op result; uint32_t extended_value; uint32_t lineno; - zend_uchar opcode; - zend_uchar op1_type; - zend_uchar op2_type; - zend_uchar result_type; + uint8_t opcode; /* Opcodes defined in Zend/zend_vm_opcodes.h */ + uint8_t op1_type; /* IS_UNUSED, IS_CONST, IS_TMP_VAR, IS_VAR, IS_CV */ + uint8_t op2_type; /* IS_UNUSED, IS_CONST, IS_TMP_VAR, IS_VAR, IS_CV */ + uint8_t result_type; /* IS_UNUSED, IS_CONST, IS_TMP_VAR, IS_VAR, IS_CV */ }; @@ -240,7 +238,7 @@ typedef struct _zend_oparray_context { /* or IS_CONSTANT_VISITED_MARK | | | */ #define ZEND_CLASS_CONST_IS_CASE (1 << 6) /* | | | X */ /* | | | */ -/* Class Flags (unused: 21,30,31) | | | */ +/* Class Flags (unused: 30,31) | | | */ /* =========== | | | */ /* | | | */ /* Special class types | | | */ @@ -287,6 +285,8 @@ typedef struct _zend_oparray_context { /* | | | */ /* Class is linked apart from variance obligations. | | | */ #define ZEND_ACC_NEARLY_LINKED (1 << 20) /* X | | | */ +/* Class has readonly props | | | */ +#define ZEND_ACC_HAS_READONLY_PROPS (1 << 21) /* X | | | */ /* | | | */ /* stored in opcache (may be partially) | | | */ #define ZEND_ACC_CACHED (1 << 22) /* X | | | */ @@ -407,6 +407,7 @@ typedef struct _zend_class_constant { zend_string *doc_comment; HashTable *attributes; zend_class_entry *ce; + zend_type type; } zend_class_constant; #define ZEND_CLASS_CONST_FLAGS(c) Z_CONSTANT_FLAGS((c)->value) @@ -431,15 +432,15 @@ typedef struct _zend_arg_info { * It's also used for the return type. */ typedef struct _zend_internal_function_info { - zend_uintptr_t required_num_args; + uintptr_t required_num_args; zend_type type; const char *default_value; } zend_internal_function_info; struct _zend_op_array { /* Common elements */ - zend_uchar type; - zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ + uint8_t type; + uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; zend_class_entry *scope; @@ -448,8 +449,8 @@ struct _zend_op_array { uint32_t required_num_args; zend_arg_info *arg_info; HashTable *attributes; - uint32_t T; /* number of temporary variables */ ZEND_MAP_PTR_DEF(void **, run_time_cache); + uint32_t T; /* number of temporary variables */ /* END of common elements */ int cache_size; /* number of run_time_cache_slots * sizeof(void*) */ @@ -493,8 +494,8 @@ typedef void (ZEND_FASTCALL *zif_handler)(INTERNAL_FUNCTION_PARAMETERS); typedef struct _zend_internal_function { /* Common elements */ - zend_uchar type; - zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ + uint8_t type; + uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string* function_name; zend_class_entry *scope; @@ -503,8 +504,8 @@ typedef struct _zend_internal_function { uint32_t required_num_args; zend_internal_arg_info *arg_info; HashTable *attributes; - uint32_t T; /* number of temporary variables */ ZEND_MAP_PTR_DEF(void **, run_time_cache); + uint32_t T; /* number of temporary variables */ /* END of common elements */ zif_handler handler; @@ -515,12 +516,12 @@ typedef struct _zend_internal_function { #define ZEND_FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? ZSTR_VAL((function)->common.scope->name) : "") union _zend_function { - zend_uchar type; /* MUST be the first element of this struct! */ + uint8_t type; /* MUST be the first element of this struct! */ uint32_t quick_arg_flags; struct { - zend_uchar type; /* never used */ - zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ + uint8_t type; /* never used */ + uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; zend_class_entry *scope; @@ -529,8 +530,8 @@ union _zend_function { uint32_t required_num_args; zend_arg_info *arg_info; /* index -1 represents the return value info, if any */ HashTable *attributes; - uint32_t T; /* number of temporary variables */ ZEND_MAP_PTR_DEF(void **, run_time_cache); + uint32_t T; /* number of temporary variables */ } common; zend_op_array op_array; @@ -606,8 +607,12 @@ struct _zend_execute_data { #define ZEND_CALL_NUM_ARGS(call) \ (call)->This.u2.num_args +/* Ensure the correct alignment before slots calculation */ +ZEND_STATIC_ASSERT(ZEND_MM_ALIGNED_SIZE(sizeof(zval)) == sizeof(zval), + "zval must be aligned by ZEND_MM_ALIGNMENT"); +/* A number of call frame slots (zvals) reserved for zend_execute_data. */ #define ZEND_CALL_FRAME_SLOT \ - ((int)((ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval)))) + ((int)((sizeof(zend_execute_data) + sizeof(zval) - 1) / sizeof(zval))) #define ZEND_CALL_VAR(call, n) \ ((zval*)(((char*)(call)) + ((int)(n)))) @@ -817,6 +822,7 @@ typedef enum { zend_ast *zend_ast_append_str(zend_ast *left, zend_ast *right); zend_ast *zend_negate_num_string(zend_ast *ast); uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag); +uint32_t zend_add_anonymous_class_modifier(uint32_t flags, uint32_t new_flag); uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag, zend_modifier_target target); uint32_t zend_modifier_token_to_flag(zend_modifier_target target, uint32_t flags); @@ -845,9 +851,9 @@ ZEND_API zend_op_array *compile_string(zend_string *source_string, const char *f ZEND_API zend_op_array *compile_filename(int type, zend_string *filename); ZEND_API zend_ast *zend_compile_string_to_ast( zend_string *code, struct _zend_arena **ast_arena, zend_string *filename); -ZEND_API int zend_execute_scripts(int type, zval *retval, int file_count, ...); -ZEND_API int open_file_for_scanning(zend_file_handle *file_handle); -ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size); +ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count, ...); +ZEND_API zend_result open_file_for_scanning(zend_file_handle *file_handle); +ZEND_API void init_op_array(zend_op_array *op_array, uint8_t type, int initial_ops_size); ZEND_API void destroy_op_array(zend_op_array *op_array); ZEND_API void zend_destroy_static_vars(zend_op_array *op_array); ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle); @@ -895,8 +901,8 @@ ZEND_API void pass_two(zend_op_array *op_array); ZEND_API bool zend_is_compiling(void); ZEND_API char *zend_make_compiled_string_description(const char *name); ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_handlers); -uint32_t zend_get_class_fetch_type(zend_string *name); -ZEND_API zend_uchar zend_get_call_op(const zend_op *init_op, zend_function *fbc); +uint32_t zend_get_class_fetch_type(const zend_string *name); +ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, zend_function *fbc); ZEND_API bool zend_is_smart_branch(const zend_op *opline); typedef bool (*zend_auto_global_callback)(zend_string *name); @@ -1204,8 +1210,8 @@ END_EXTERN_C() /* The default value for CG(compiler_options) during eval() */ #define ZEND_COMPILE_DEFAULT_FOR_EVAL 0 -ZEND_API bool zend_is_op_long_compatible(zval *op); -ZEND_API bool zend_binary_op_produces_error(uint32_t opcode, zval *op1, zval *op2); -ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, zval *op); +ZEND_API bool zend_is_op_long_compatible(const zval *op); +ZEND_API bool zend_binary_op_produces_error(uint32_t opcode, const zval *op1, const zval *op2); +ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, const zval *op); #endif /* ZEND_COMPILE_H */ diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index f002e321d8b2b..854f9c2116ee2 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -43,15 +43,9 @@ void free_zend_constant(zval *zv) if (!(ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)) { zval_ptr_dtor_nogc(&c->value); - if (c->name) { - zend_string_release_ex(c->name, 0); - } efree(c); } else { zval_internal_ptr_dtor(&c->value); - if (c->name) { - zend_string_release_ex(c->name, 1); - } free(c); } } @@ -67,7 +61,6 @@ static void copy_zend_constant(zval *zv) memcpy(Z_PTR_P(zv), c, sizeof(zend_constant)); c = Z_PTR_P(zv); - c->name = zend_string_copy(c->name); if (Z_TYPE(c->value) == IS_STRING) { Z_STR(c->value) = zend_string_dup(Z_STR(c->value), 1); } @@ -129,8 +122,7 @@ ZEND_API void zend_register_null_constant(const char *name, size_t name_len, int ZVAL_NULL(&c.value); ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number); - c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT); - zend_register_constant(&c); + zend_register_internal_constant(name, name_len, &c); } ZEND_API void zend_register_bool_constant(const char *name, size_t name_len, bool bval, int flags, int module_number) @@ -139,8 +131,7 @@ ZEND_API void zend_register_bool_constant(const char *name, size_t name_len, boo ZVAL_BOOL(&c.value, bval); ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number); - c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT); - zend_register_constant(&c); + zend_register_internal_constant(name, name_len, &c); } ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zend_long lval, int flags, int module_number) @@ -149,8 +140,7 @@ ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zen ZVAL_LONG(&c.value, lval); ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number); - c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT); - zend_register_constant(&c); + zend_register_internal_constant(name, name_len, &c); } @@ -160,8 +150,7 @@ ZEND_API void zend_register_double_constant(const char *name, size_t name_len, d ZVAL_DOUBLE(&c.value, dval); ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number); - c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT); - zend_register_constant(&c); + zend_register_internal_constant(name, name_len, &c); } @@ -171,8 +160,7 @@ ZEND_API void zend_register_stringl_constant(const char *name, size_t name_len, ZVAL_STR(&c.value, zend_string_init_interned(strval, strlen, flags & CONST_PERSISTENT)); ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number); - c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT); - zend_register_constant(&c); + zend_register_internal_constant(name, name_len, &c); } @@ -373,7 +361,7 @@ ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string * } MARK_CONSTANT_VISITED(ret_constant); - ret = zval_update_constant_ex(ret_constant, c->ce); + ret = zend_update_class_constant(c, constant_name, c->ce); RESET_CONSTANT_VISITED(ret_constant); if (UNEXPECTED(ret != SUCCESS)) { @@ -545,10 +533,9 @@ static void* zend_hash_add_constant(HashTable *ht, zend_string *key, zend_consta return ret; } -ZEND_API zend_result zend_register_constant(zend_constant *c) +ZEND_API zend_result zend_register_constant(zend_string *name, zend_constant *c) { zend_string *lowercase_name = NULL; - zend_string *name; zend_result ret = SUCCESS; bool persistent = (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) != 0; @@ -556,14 +543,12 @@ ZEND_API zend_result zend_register_constant(zend_constant *c) printf("Registering constant for module %d\n", c->module_number); #endif - const char *slash = strrchr(ZSTR_VAL(c->name), '\\'); + const char *slash = strrchr(ZSTR_VAL(name), '\\'); if (slash) { - lowercase_name = zend_string_init(ZSTR_VAL(c->name), ZSTR_LEN(c->name), persistent); - zend_str_tolower(ZSTR_VAL(lowercase_name), slash - ZSTR_VAL(c->name)); + lowercase_name = zend_string_init(ZSTR_VAL(name), ZSTR_LEN(name), persistent); + zend_str_tolower(ZSTR_VAL(lowercase_name), slash - ZSTR_VAL(name)); lowercase_name = zend_new_interned_string(lowercase_name); name = lowercase_name; - } else { - name = c->name; } /* Check if the user is trying to define any special constant */ @@ -572,7 +557,6 @@ ZEND_API zend_result zend_register_constant(zend_constant *c) || zend_hash_add_constant(EG(zend_constants), name, c) == NULL ) { zend_error(E_WARNING, "Constant %s already defined", ZSTR_VAL(name)); - zend_string_release(c->name); if (!persistent) { zval_ptr_dtor_nogc(&c->value); } @@ -583,3 +567,13 @@ ZEND_API zend_result zend_register_constant(zend_constant *c) } return ret; } + +ZEND_API zend_result zend_register_internal_constant(const char *name, size_t name_len, zend_constant *c) { + zend_string *name_str = zend_string_init_interned(name, name_len, ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT); + + zend_result result = zend_register_constant(name_str, c); + + zend_string_release(name_str); + + return result; +} diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index 736dbb0091085..d0ad242143fb4 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -32,7 +32,6 @@ typedef struct _zend_constant { zval value; - zend_string *name; } zend_constant; #define ZEND_CONSTANT_FLAGS(c) \ @@ -84,7 +83,8 @@ ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zen ZEND_API void zend_register_double_constant(const char *name, size_t name_len, double dval, int flags, int module_number); ZEND_API void zend_register_string_constant(const char *name, size_t name_len, const char *strval, int flags, int module_number); ZEND_API void zend_register_stringl_constant(const char *name, size_t name_len, const char *strval, size_t strlen, int flags, int module_number); -ZEND_API zend_result zend_register_constant(zend_constant *c); +ZEND_API zend_result zend_register_internal_constant(const char *name, size_t name_len, zend_constant *c); +ZEND_API zend_result zend_register_constant(zend_string *name, zend_constant *c); #ifdef ZTS void zend_copy_constants(HashTable *target, HashTable *source); #endif diff --git a/Zend/zend_cpuinfo.h b/Zend/zend_cpuinfo.h index ebfbab799795d..31e7c54e0b6f0 100644 --- a/Zend/zend_cpuinfo.h +++ b/Zend/zend_cpuinfo.h @@ -61,6 +61,11 @@ typedef enum _zend_cpu_feature { /* EBX */ ZEND_CPU_FEATURE_AVX2 = (1<<5 | ZEND_CPU_EBX_MASK), + ZEND_CPU_FEATURE_AVX512F = (1<<16 | ZEND_CPU_EBX_MASK), + ZEND_CPU_FEATURE_AVX512DQ = (1<<17 | ZEND_CPU_EBX_MASK), + ZEND_CPU_FEATURE_AVX512CD = (1<<28 | ZEND_CPU_EBX_MASK), + /* intentionally don't support = (1<<30 | ZEND_CPU_EBX_MASK) */ + /* intentionally don't support = (1<<31 | ZEND_CPU_EBX_MASK) */ /* EDX */ ZEND_CPU_FEATURE_FPU = (1<<0 | ZEND_CPU_EDX_MASK), @@ -174,6 +179,29 @@ static inline int zend_cpu_supports_avx2(void) { #endif return __builtin_cpu_supports("avx2"); } + +#if PHP_HAVE_AVX512_SUPPORTS +ZEND_NO_SANITIZE_ADDRESS +static inline int zend_cpu_supports_avx512(void) { +#if PHP_HAVE_BUILTIN_CPU_INIT + __builtin_cpu_init(); +#endif + return __builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512dq") + && __builtin_cpu_supports("avx512cd") && __builtin_cpu_supports("avx512bw") + && __builtin_cpu_supports("avx512vl"); +} +#endif + +#if PHP_HAVE_AVX512_VBMI_SUPPORTS +ZEND_NO_SANITIZE_ADDRESS +static inline int zend_cpu_supports_avx512_vbmi(void) { +#if PHP_HAVE_BUILTIN_CPU_INIT + __builtin_cpu_init(); +#endif + return zend_cpu_supports_avx512() && __builtin_cpu_supports("avx512vbmi"); +} +#endif + #else static inline int zend_cpu_supports_sse2(void) { @@ -203,6 +231,16 @@ static inline int zend_cpu_supports_avx(void) { static inline int zend_cpu_supports_avx2(void) { return zend_cpu_supports(ZEND_CPU_FEATURE_AVX2); } + +static inline int zend_cpu_supports_avx512(void) { + /* TODO: avx512_bw/avx512_vl use bit 30/31 which are reserved for mask */ + return 0; +} + +static zend_always_inline int zend_cpu_supports_avx512_vbmi(void) { + /* TODO: avx512_vbmi use ECX of cpuid 7 */ + return 0; +} #endif /* __builtin_cpu_supports has pclmul from gcc9 */ diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c index 3e455b702cbf2..21628f74956bb 100644 --- a/Zend/zend_enum.c +++ b/Zend/zend_enum.c @@ -41,9 +41,17 @@ zend_object *zend_enum_new(zval *result, zend_class_entry *ce, zend_string *case zend_object *zobj = zend_objects_new(ce); ZVAL_OBJ(result, zobj); - ZVAL_STR_COPY(OBJ_PROP_NUM(zobj, 0), case_name); + zval *zname = OBJ_PROP_NUM(zobj, 0); + ZVAL_STR_COPY(zname, case_name); + /* ZVAL_COPY does not set Z_PROP_FLAG, this needs to be cleared to avoid leaving IS_PROP_REINITABLE set */ + Z_PROP_FLAG_P(zname) = 0; + if (backing_value_zv != NULL) { - ZVAL_COPY(OBJ_PROP_NUM(zobj, 1), backing_value_zv); + zval *prop = OBJ_PROP_NUM(zobj, 1); + + ZVAL_COPY(prop, backing_value_zv); + /* ZVAL_COPY does not set Z_PROP_FLAG, this needs to be cleared to avoid leaving IS_PROP_REINITABLE set */ + Z_PROP_FLAG_P(prop) = 0; } return zobj; @@ -85,7 +93,7 @@ static void zend_verify_enum_magic_methods(zend_class_entry *ce) ZEND_ENUM_DISALLOW_MAGIC_METHOD(__serialize, "__serialize"); ZEND_ENUM_DISALLOW_MAGIC_METHOD(__unserialize, "__unserialize"); - const char *forbidden_methods[] = { + static const char *const forbidden_methods[] = { "__sleep", "__wakeup", "__set_state", @@ -175,11 +183,11 @@ void zend_enum_add_interfaces(zend_class_entry *ce) ce->interface_names = erealloc(ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces); ce->interface_names[num_interfaces_before].name = zend_string_copy(zend_ce_unit_enum->name); - ce->interface_names[num_interfaces_before].lc_name = zend_string_init("unitenum", sizeof("unitenum") - 1, 0); + ce->interface_names[num_interfaces_before].lc_name = ZSTR_INIT_LITERAL("unitenum", 0); if (ce->enum_backing_type != IS_UNDEF) { ce->interface_names[num_interfaces_before + 1].name = zend_string_copy(zend_ce_backed_enum->name); - ce->interface_names[num_interfaces_before + 1].lc_name = zend_string_init("backedenum", sizeof("backedenum") - 1, 0); + ce->interface_names[num_interfaces_before + 1].lc_name = ZSTR_INIT_LITERAL("backedenum", 0); } ce->default_object_handlers = &zend_enum_object_handlers; @@ -408,8 +416,11 @@ static void zend_enum_register_func(zend_class_entry *ce, zend_known_string_id n zif->module = EG(current_module); zif->scope = ce; zif->T = ZEND_OBSERVER_ENABLED; - ZEND_MAP_PTR_NEW(zif->run_time_cache); - ZEND_MAP_PTR_SET(zif->run_time_cache, zend_arena_alloc(&CG(arena), zend_internal_run_time_cache_reserved_size())); + if (EG(active)) { // at run-time + ZEND_MAP_PTR_INIT(zif->run_time_cache, zend_arena_calloc(&CG(arena), 1, zend_internal_run_time_cache_reserved_size())); + } else { + ZEND_MAP_PTR_NEW(zif->run_time_cache); + } if (!zend_hash_add_ptr(&ce->function_table, name, zif)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(name)); @@ -478,7 +489,7 @@ static const zend_function_entry backed_enum_methods[] = { }; ZEND_API zend_class_entry *zend_register_internal_enum( - const char *name, zend_uchar type, const zend_function_entry *functions) + const char *name, uint8_t type, const zend_function_entry *functions) { ZEND_ASSERT(type == IS_UNDEF || type == IS_LONG || type == IS_STRING); diff --git a/Zend/zend_enum.h b/Zend/zend_enum.h index dbb230c4175c3..7b58592d42bd5 100644 --- a/Zend/zend_enum.h +++ b/Zend/zend_enum.h @@ -22,6 +22,8 @@ #include "zend.h" #include "zend_types.h" +#include + BEGIN_EXTERN_C() extern ZEND_API zend_class_entry *zend_ce_unit_enum; @@ -37,7 +39,7 @@ void zend_enum_register_funcs(zend_class_entry *ce); void zend_enum_register_props(zend_class_entry *ce); ZEND_API zend_class_entry *zend_register_internal_enum( - const char *name, zend_uchar type, const zend_function_entry *functions); + const char *name, uint8_t type, const zend_function_entry *functions); ZEND_API void zend_enum_add_case(zend_class_entry *ce, zend_string *case_name, zval *value); ZEND_API void zend_enum_add_case_cstr(zend_class_entry *ce, const char *name, zval *value); ZEND_API zend_object *zend_enum_get_case(zend_class_entry *ce, zend_string *name); diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 174234e2f438e..8dea48042336c 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -647,7 +647,7 @@ ZEND_METHOD(Exception, __toString) str = ZSTR_EMPTY_ALLOC(); exception = ZEND_THIS; - fname = zend_string_init("gettraceasstring", sizeof("gettraceasstring")-1, 0); + fname = ZSTR_INIT_LITERAL("gettraceasstring", 0); while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) { zend_string *prev_str = str; @@ -671,24 +671,36 @@ ZEND_METHOD(Exception, __toString) } if ((Z_OBJCE_P(exception) == zend_ce_type_error || Z_OBJCE_P(exception) == zend_ce_argument_count_error) && strstr(ZSTR_VAL(message), ", called in ")) { - zend_string *real_message = zend_strpprintf(0, "%s and defined", ZSTR_VAL(message)); + zval message_zv; + ZVAL_STR(&message_zv, message); + zend_string *real_message = zend_strpprintf_unchecked(0, "%Z and defined", &message_zv); zend_string_release_ex(message, 0); message = real_message; } + zend_string *tmp_trace = (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) + ? zend_string_copy(Z_STR(trace)) + : ZSTR_INIT_LITERAL("#0 {main}\n", false); + + zval name_zv, trace_zv, file_zv, prev_str_zv; + ZVAL_STR(&name_zv, Z_OBJCE_P(exception)->name); + ZVAL_STR(&trace_zv, tmp_trace); + ZVAL_STR(&file_zv, file); + ZVAL_STR(&prev_str_zv, prev_str); + if (ZSTR_LEN(message) > 0) { - str = zend_strpprintf(0, "%s: %s in %s:" ZEND_LONG_FMT - "\nStack trace:\n%s%s%s", - ZSTR_VAL(Z_OBJCE_P(exception)->name), ZSTR_VAL(message), ZSTR_VAL(file), line, - (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n", - ZSTR_LEN(prev_str) ? "\n\nNext " : "", ZSTR_VAL(prev_str)); + zval message_zv; + ZVAL_STR(&message_zv, message); + + str = zend_strpprintf_unchecked(0, "%Z: %Z in %Z:" ZEND_LONG_FMT "\nStack trace:\n%Z%s%Z", + &name_zv, &message_zv, &file_zv, line, + &trace_zv, ZSTR_LEN(prev_str) ? "\n\nNext " : "", &prev_str_zv); } else { - str = zend_strpprintf(0, "%s in %s:" ZEND_LONG_FMT - "\nStack trace:\n%s%s%s", - ZSTR_VAL(Z_OBJCE_P(exception)->name), ZSTR_VAL(file), line, - (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n", - ZSTR_LEN(prev_str) ? "\n\nNext " : "", ZSTR_VAL(prev_str)); + str = zend_strpprintf_unchecked(0, "%Z in %Z:" ZEND_LONG_FMT "\nStack trace:\n%Z%s%Z", + &name_zv, &file_zv, line, + &trace_zv, ZSTR_LEN(prev_str) ? "\n\nNext " : "", &prev_str_zv); } + zend_string_release_ex(tmp_trace, false); zend_string_release_ex(prev_str, 0); zend_string_release_ex(message, 0); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index fc54a8e0262e1..42c9fcdc0fc1c 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -42,6 +42,7 @@ #include "zend_smart_str.h" #include "zend_observer.h" #include "zend_system_id.h" +#include "zend_call_stack.h" #include "Optimizer/zend_func_info.h" /* Virtual current working directory support */ @@ -144,8 +145,8 @@ ZEND_API const zend_internal_function zend_pass_function = { 0, /* required_num_args */ (zend_internal_arg_info *) zend_pass_function_arg_info + 1, /* arg_info */ NULL, /* attributes */ - 0, /* T */ NULL, /* run_time_cache */ + 0, /* T */ ZEND_FN(pass), /* handler */ NULL, /* module */ {NULL,NULL,NULL,NULL} /* reserved */ @@ -386,6 +387,21 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(uint32_t var EXECUTE_D return ret; } +static zend_always_inline zval *_get_zval_ptr_tmpvarcv(int op_type, znode_op node, int type EXECUTE_DATA_DC) +{ + if (op_type & (IS_TMP_VAR|IS_VAR)) { + if (op_type == IS_TMP_VAR) { + return _get_zval_ptr_tmp(node.var EXECUTE_DATA_CC); + } else { + ZEND_ASSERT(op_type == IS_VAR); + return _get_zval_ptr_var_deref(node.var EXECUTE_DATA_CC); + } + } else { + ZEND_ASSERT(op_type == IS_CV); + return _get_zval_ptr_cv_deref(node.var, type EXECUTE_DATA_CC); + } +} + static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, int type EXECUTE_DATA_DC OPLINE_DC) { if (op_type & (IS_TMP_VAR|IS_VAR)) { @@ -530,7 +546,7 @@ static inline ZEND_ATTRIBUTE_UNUSED zval *_get_obj_zval_ptr_ptr(int op_type, zno return get_zval_ptr_ptr(op_type, node, type); } -static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr) +static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr, zend_refcounted **garbage_ptr) { zend_reference *ref; @@ -543,20 +559,12 @@ static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *v ref = Z_REF_P(value_ptr); GC_ADDREF(ref); if (Z_REFCOUNTED_P(variable_ptr)) { - zend_refcounted *garbage = Z_COUNTED_P(variable_ptr); - - if (GC_DELREF(garbage) == 0) { - ZVAL_REF(variable_ptr, ref); - rc_dtor_func(garbage); - return; - } else { - gc_check_possible_root(garbage); - } + *garbage_ptr = Z_COUNTED_P(variable_ptr); } ZVAL_REF(variable_ptr, ref); } -static zend_never_inline zval* zend_assign_to_typed_property_reference(zend_property_info *prop_info, zval *prop, zval *value_ptr EXECUTE_DATA_DC) +static zend_never_inline zval* zend_assign_to_typed_property_reference(zend_property_info *prop_info, zval *prop, zval *value_ptr, zend_refcounted **garbage_ptr EXECUTE_DATA_DC) { if (!zend_verify_prop_assignable_by_ref(prop_info, value_ptr, EX_USES_STRICT_TYPES())) { return &EG(uninitialized_zval); @@ -564,12 +572,12 @@ static zend_never_inline zval* zend_assign_to_typed_property_reference(zend_prop if (Z_ISREF_P(prop)) { ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(prop), prop_info); } - zend_assign_to_variable_reference(prop, value_ptr); + zend_assign_to_variable_reference(prop, value_ptr, garbage_ptr); ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(prop), prop_info); return prop; } -static zend_never_inline ZEND_COLD zval *zend_wrong_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline ZEND_COLD zval *zend_wrong_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr, zend_refcounted **garbage_ptr OPLINE_DC EXECUTE_DATA_DC) { zend_error(E_NOTICE, "Only variables should be assigned by reference"); if (UNEXPECTED(EG(exception) != NULL)) { @@ -578,7 +586,7 @@ static zend_never_inline ZEND_COLD zval *zend_wrong_assign_to_variable_reference /* Use IS_TMP_VAR instead of IS_VAR to avoid ISREF check */ Z_TRY_ADDREF_P(value_ptr); - return zend_assign_to_variable(variable_ptr, value_ptr, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + return zend_assign_to_variable_ex(variable_ptr, value_ptr, IS_TMP_VAR, EX_USES_STRICT_TYPES(), garbage_ptr); } ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num) @@ -634,7 +642,7 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_erro || opline->opcode == ZEND_POST_DEC_OBJ) { zend_throw_error(NULL, "Attempt to increment/decrement property \"%s\" on %s", - ZSTR_VAL(property_name), zend_zval_type_name(object) + ZSTR_VAL(property_name), zend_zval_value_name(object) ); } else if (opline->opcode == ZEND_FETCH_OBJ_W || opline->opcode == ZEND_FETCH_OBJ_RW @@ -642,12 +650,12 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_erro || opline->opcode == ZEND_ASSIGN_OBJ_REF) { zend_throw_error(NULL, "Attempt to modify property \"%s\" on %s", - ZSTR_VAL(property_name), zend_zval_type_name(object) + ZSTR_VAL(property_name), zend_zval_value_name(object) ); } else { zend_throw_error(NULL, "Attempt to assign property \"%s\" on %s", - ZSTR_VAL(property_name), zend_zval_type_name(object) + ZSTR_VAL(property_name), zend_zval_value_name(object) ); } zend_tmp_string_release(tmp_property_name); @@ -674,7 +682,7 @@ static ZEND_COLD void zend_verify_type_error_common( *need_msg = zend_type_to_string_resolved(arg_info->type, zf->common.scope); if (value) { - *given_kind = zend_zval_type_name(value); + *given_kind = zend_zval_value_name(value); } else { *given_kind = "none"; } @@ -718,7 +726,7 @@ static bool zend_verify_weak_scalar_type_hint(uint32_t type_mask, zval *arg) /* For an int|float union type and string value, * determine chosen type by is_numeric_string() semantics. */ if ((type_mask & MAY_BE_DOUBLE) && Z_TYPE_P(arg) == IS_STRING) { - zend_uchar type = is_numeric_str_function(Z_STR_P(arg), &lval, &dval); + uint8_t type = is_numeric_str_function(Z_STR_P(arg), &lval, &dval); if (type == IS_LONG) { zend_string_release(Z_STR_P(arg)); ZVAL_LONG(arg, lval); @@ -755,7 +763,7 @@ static bool zend_verify_weak_scalar_type_hint(uint32_t type_mask, zval *arg) } #if ZEND_DEBUG -static bool can_convert_to_string(zval *zv) { +static bool can_convert_to_string(const zval *zv) { /* We don't call cast_object here, because this check must be side-effect free. As this * is only used for a sanity check of arginfo/zpp consistency, it's okay if we accept * more than actually allowed here. */ @@ -767,7 +775,7 @@ static bool can_convert_to_string(zval *zv) { } /* Used to sanity-check internal arginfo types without performing any actual type conversions. */ -static bool zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_mask, zval *arg) +static bool zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_mask, const zval *arg) { zend_long lval; double dval; @@ -812,7 +820,17 @@ ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool s return zend_verify_weak_scalar_type_hint(type_mask, arg); } -ZEND_COLD zend_never_inline void zend_verify_property_type_error(zend_property_info *info, zval *property) +ZEND_COLD zend_never_inline void zend_verify_class_constant_type_error(const zend_class_constant *c, const zend_string *name, const zval *constant) +{ + zend_string *type_str = zend_type_to_string(c->type); + + zend_type_error("Cannot assign %s to class constant %s::%s of type %s", + zend_zval_type_name(constant), ZSTR_VAL(c->ce->name), ZSTR_VAL(name), ZSTR_VAL(type_str)); + + zend_string_release(type_str); +} + +ZEND_COLD zend_never_inline void zend_verify_property_type_error(const zend_property_info *info, const zval *property) { zend_string *type_str; @@ -823,14 +841,14 @@ ZEND_COLD zend_never_inline void zend_verify_property_type_error(zend_property_i type_str = zend_type_to_string(info->type); zend_type_error("Cannot assign %s to property %s::$%s of type %s", - zend_zval_type_name(property), + zend_zval_value_name(property), ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name), ZSTR_VAL(type_str)); zend_string_release(type_str); } -ZEND_COLD zend_never_inline void zend_magic_get_property_type_inconsistency_error(zend_property_info *info, zval *property) +ZEND_COLD zend_never_inline void zend_magic_get_property_type_inconsistency_error(const zend_property_info *info, const zval *property) { /* we _may_ land here in case reading already errored and runtime cache thus has not been updated (i.e. it contains a valid but unrelated info) */ if (EG(exception)) { @@ -847,7 +865,7 @@ ZEND_COLD zend_never_inline void zend_magic_get_property_type_inconsistency_erro zend_string_release(type_str); } -ZEND_COLD void zend_match_unhandled_error(zval *value) +ZEND_COLD void zend_match_unhandled_error(const zval *value) { smart_str msg = {0}; @@ -867,18 +885,29 @@ ZEND_COLD void zend_match_unhandled_error(zval *value) } ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error( - zend_property_info *info) { + const zend_property_info *info) { zend_throw_error(NULL, "Cannot modify readonly property %s::$%s", ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name)); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(zend_property_info *info) +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(const zend_property_info *info) { zend_throw_error(NULL, "Cannot indirectly modify readonly property %s::$%s", ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name)); } -static zend_class_entry *resolve_single_class_type(zend_string *name, zend_class_entry *self_ce) { +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_invalid_class_constant_type_error(uint8_t type) +{ + zend_type_error("Cannot use value of type %s as class constant name", zend_get_type_by_const(type)); +} + +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_object_released_while_assigning_to_property_error(const zend_property_info *info) +{ + zend_throw_error(NULL, "Object was released while assigning to property %s::$%s", + ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name)); +} + +static const zend_class_entry *resolve_single_class_type(zend_string *name, const zend_class_entry *self_ce) { if (zend_string_equals_literal_ci(name, "self")) { return self_ce; } else if (zend_string_equals_literal_ci(name, "parent")) { @@ -888,8 +917,8 @@ static zend_class_entry *resolve_single_class_type(zend_string *name, zend_class } } -static zend_always_inline zend_class_entry *zend_ce_from_type( - zend_property_info *info, zend_type *type) { +static zend_always_inline const zend_class_entry *zend_ce_from_type( + const zend_class_entry *scope, const zend_type *type) { ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*type)); zend_string *name = ZEND_TYPE_NAME(*type); if (ZSTR_HAS_CE_CACHE(name)) { @@ -899,55 +928,64 @@ static zend_always_inline zend_class_entry *zend_ce_from_type( } return ce; } - return resolve_single_class_type(name, info->ce); + return resolve_single_class_type(name, scope); } -static bool zend_check_intersection_for_property_class_type(zend_type_list *intersection_type_list, - zend_property_info *info, zend_class_entry *object_ce) +static bool zend_check_intersection_for_property_or_class_constant_class_type( + const zend_class_entry *scope, zend_type_list *intersection_type_list, const zend_class_entry *value_ce) { zend_type *list_type; ZEND_TYPE_LIST_FOREACH(intersection_type_list, list_type) { ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); - zend_class_entry *ce = zend_ce_from_type(info, list_type); - if (!ce || !instanceof_function(object_ce, ce)) { + const zend_class_entry *ce = zend_ce_from_type(scope, list_type); + if (!ce || !instanceof_function(value_ce, ce)) { return false; } } ZEND_TYPE_LIST_FOREACH_END(); return true; } -static bool zend_check_and_resolve_property_class_type( - zend_property_info *info, zend_class_entry *object_ce) { - if (ZEND_TYPE_HAS_LIST(info->type)) { +static bool zend_check_and_resolve_property_or_class_constant_class_type( + const zend_class_entry *scope, zend_type member_type, const zend_class_entry *value_ce) { + if (ZEND_TYPE_HAS_LIST(member_type)) { zend_type *list_type; - if (ZEND_TYPE_IS_INTERSECTION(info->type)) { - return zend_check_intersection_for_property_class_type( - ZEND_TYPE_LIST(info->type), info, object_ce); + if (ZEND_TYPE_IS_INTERSECTION(member_type)) { + return zend_check_intersection_for_property_or_class_constant_class_type( + scope, ZEND_TYPE_LIST(member_type), value_ce); } else { - ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(info->type), list_type) { + ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(member_type), list_type) { if (ZEND_TYPE_IS_INTERSECTION(*list_type)) { - if (zend_check_intersection_for_property_class_type( - ZEND_TYPE_LIST(*list_type), info, object_ce)) { + if (zend_check_intersection_for_property_or_class_constant_class_type( + scope, ZEND_TYPE_LIST(*list_type), value_ce)) { return true; - } + } continue; } ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); - zend_class_entry *ce = zend_ce_from_type(info, list_type); - if (ce && instanceof_function(object_ce, ce)) { + const zend_class_entry *ce = zend_ce_from_type(scope, list_type); + if (ce && instanceof_function(value_ce, ce)) { return true; } } ZEND_TYPE_LIST_FOREACH_END(); + + if ((ZEND_TYPE_PURE_MASK(member_type) & MAY_BE_STATIC)) { + return value_ce == scope; + } + return false; } - } else { - zend_class_entry *ce = zend_ce_from_type(info, &info->type); - return ce && instanceof_function(object_ce, ce); + } else if ((ZEND_TYPE_PURE_MASK(member_type) & MAY_BE_STATIC) && value_ce == scope) { + return true; + } else if (ZEND_TYPE_HAS_NAME(member_type)) { + const zend_class_entry *ce = zend_ce_from_type(scope, &member_type); + return ce && instanceof_function(value_ce, ce); } + + return false; } -static zend_always_inline bool i_zend_check_property_type(zend_property_info *info, zval *property, bool strict) +static zend_always_inline bool i_zend_check_property_type(const zend_property_info *info, zval *property, bool strict) { ZEND_ASSERT(!Z_ISREF_P(property)); if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(info->type, Z_TYPE_P(property)))) { @@ -955,16 +993,16 @@ static zend_always_inline bool i_zend_check_property_type(zend_property_info *in } if (ZEND_TYPE_IS_COMPLEX(info->type) && Z_TYPE_P(property) == IS_OBJECT - && zend_check_and_resolve_property_class_type(info, Z_OBJCE_P(property))) { + && zend_check_and_resolve_property_or_class_constant_class_type(info->ce, info->type, Z_OBJCE_P(property))) { return 1; } uint32_t type_mask = ZEND_TYPE_FULL_MASK(info->type); - ZEND_ASSERT(!(type_mask & (MAY_BE_CALLABLE|MAY_BE_STATIC))); + ZEND_ASSERT(!(type_mask & (MAY_BE_CALLABLE|MAY_BE_STATIC|MAY_BE_NEVER|MAY_BE_VOID))); return zend_verify_scalar_type_hint(type_mask, property, strict, 0); } -static zend_always_inline bool i_zend_verify_property_type(zend_property_info *info, zval *property, bool strict) +static zend_always_inline bool i_zend_verify_property_type(const zend_property_info *info, zval *property, bool strict) { if (i_zend_check_property_type(info, property, strict)) { return 1; @@ -974,15 +1012,15 @@ static zend_always_inline bool i_zend_verify_property_type(zend_property_info *i return 0; } -ZEND_API bool zend_never_inline zend_verify_property_type(zend_property_info *info, zval *property, bool strict) { +ZEND_API bool zend_never_inline zend_verify_property_type(const zend_property_info *info, zval *property, bool strict) { return i_zend_verify_property_type(info, property, strict); } -static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *info, zval *property_val, zval *value EXECUTE_DATA_DC) +static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *info, zval *property_val, zval *value, zend_refcounted **garbage_ptr EXECUTE_DATA_DC) { zval tmp; - if (UNEXPECTED(info->flags & ZEND_ACC_READONLY)) { + if (UNEXPECTED((info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE))) { zend_readonly_property_modification_error(info); return &EG(uninitialized_zval); } @@ -995,7 +1033,9 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf return &EG(uninitialized_zval); } - return zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE; + + return zend_assign_to_variable_ex(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES(), garbage_ptr); } static zend_always_inline bool zend_value_instanceof_static(zval *zv) { @@ -1227,7 +1267,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ * trust that arginfo matches what is enforced by zend_parse_parameters. */ ZEND_API bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call) { - if (fbc->internal_function.handler == ZEND_FN(pass) || (fbc->internal_function.fn_flags | ZEND_ACC_FAKE_CLOSURE)) { + if (fbc->internal_function.handler == ZEND_FN(pass) || (fbc->internal_function.fn_flags & ZEND_ACC_FAKE_CLOSURE)) { /* Be lenient about the special pass function and about fake closures. */ return 0; } @@ -1413,7 +1453,7 @@ ZEND_API bool zend_verify_internal_return_type(zend_function *zf, zval *ret) if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) { if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) { - zend_verify_void_return_error(zf, zend_zval_type_name(ret), ""); + zend_verify_void_return_error(zf, zend_zval_value_name(ret), ""); return 0; } return 1; @@ -1434,14 +1474,51 @@ static ZEND_COLD void zend_verify_missing_return_type(const zend_function *zf) zend_verify_return_error(zf, NULL); } +static zend_always_inline bool zend_check_class_constant_type(zend_class_constant *c, zval *constant) +{ + ZEND_ASSERT(!Z_ISREF_P(constant)); + if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(c->type, Z_TYPE_P(constant)))) { + return 1; + } + + if (((ZEND_TYPE_PURE_MASK(c->type) & MAY_BE_STATIC) || ZEND_TYPE_IS_COMPLEX(c->type)) && Z_TYPE_P(constant) == IS_OBJECT + && zend_check_and_resolve_property_or_class_constant_class_type(c->ce, c->type, Z_OBJCE_P(constant))) { + return 1; + } + + uint32_t type_mask = ZEND_TYPE_FULL_MASK(c->type); + ZEND_ASSERT(!(type_mask & (MAY_BE_CALLABLE|MAY_BE_NEVER|MAY_BE_VOID))); + return zend_verify_scalar_type_hint(type_mask, constant, true, false); +} + +ZEND_API bool zend_never_inline zend_verify_class_constant_type(zend_class_constant *c, const zend_string *name, zval *constant) +{ + if (!zend_check_class_constant_type(c, constant)) { + zend_verify_class_constant_type_error(c, name, constant); + return 0; + } + + return 1; +} + static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_object_as_array(void) { zend_throw_error(NULL, "Cannot use object as array"); } -static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_offset(void) +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_unset_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s in unset", zend_get_type_by_const(Z_TYPE_P(offset))); +} + +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_array_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s on array", zend_get_type_by_const(Z_TYPE_P(offset))); +} + +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_empty_or_isset_offset(const zval *offset) { - zend_type_error("Illegal offset type"); + zend_type_error("Cannot access offset of type %s in isset or empty", zend_get_type_by_const(Z_TYPE_P(offset))); } static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_string_offset(const zval *offset) @@ -2180,7 +2257,7 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_method(cons static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_method_call(zval *object, zval *function_name) { zend_throw_error(NULL, "Call to a member function %s() on %s", - Z_STRVAL_P(function_name), zend_zval_type_name(object)); + Z_STRVAL_P(function_name), zend_zval_value_name(object)); } static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_non_static_method_call(const zend_function *fbc) @@ -2228,6 +2305,14 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_new_element_for_s zend_throw_error(NULL, "[] operator not supported for strings"); } +#ifdef ZEND_CHECK_STACK_LIMIT +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_call_stack_size_error(void) +{ + zend_throw_error(NULL, "Maximum call stack size of %zu bytes reached. Infinite recursion?", + (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit))); +} +#endif /* ZEND_CHECK_STACK_LIMIT */ + static ZEND_COLD void zend_binary_assign_op_dim_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC) { if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { @@ -2242,7 +2327,7 @@ static ZEND_COLD void zend_binary_assign_op_dim_slow(zval *container, zval *dim } } -static zend_never_inline zend_uchar slow_index_convert(HashTable *ht, const zval *dim, zend_value *value EXECUTE_DATA_DC) +static zend_never_inline uint8_t slow_index_convert(HashTable *ht, const zval *dim, zend_value *value EXECUTE_DATA_DC) { switch (Z_TYPE_P(dim)) { case IS_UNDEF: { @@ -2305,12 +2390,12 @@ static zend_never_inline zend_uchar slow_index_convert(HashTable *ht, const zval value->lval = 1; return IS_LONG; default: - zend_illegal_offset(); + zend_illegal_array_offset(dim); return IS_NULL; } } -static zend_never_inline zend_uchar slow_index_convert_w(HashTable *ht, const zval *dim, zend_value *value EXECUTE_DATA_DC) +static zend_never_inline uint8_t slow_index_convert_w(HashTable *ht, const zval *dim, zend_value *value EXECUTE_DATA_DC) { switch (Z_TYPE_P(dim)) { case IS_UNDEF: { @@ -2379,7 +2464,7 @@ static zend_never_inline zend_uchar slow_index_convert_w(HashTable *ht, const zv value->lval = 1; return IS_LONG; default: - zend_illegal_offset(); + zend_illegal_array_offset(dim); return IS_NULL; } } @@ -2445,7 +2530,7 @@ static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht goto try_again; } else { zend_value val; - zend_uchar t; + uint8_t t; if (type != BP_VAR_W && type != BP_VAR_RW) { t = slow_index_convert(ht, dim, &val EXECUTE_DATA_CC); @@ -2585,7 +2670,7 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval * } if (type != BP_VAR_UNSET) { HashTable *ht = zend_new_array(0); - zend_uchar old_type = Z_TYPE_P(container); + uint8_t old_type = Z_TYPE_P(container); ZVAL_ARR(container, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -2777,8 +2862,8 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z ZVAL_UNDEFINED_OP2(); } if (!is_list && type != BP_VAR_IS) { - zend_error(E_WARNING, "Trying to access array offset on value of type %s", - zend_zval_type_name(container)); + zend_error(E_WARNING, "Trying to access array offset on %s", + zend_zval_value_name(container)); } ZVAL_NULL(result); } @@ -2838,7 +2923,7 @@ static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable ZVAL_UNDEFINED_OP2(); goto str_idx; } else { - zend_type_error("Illegal offset type in isset or empty"); + zend_illegal_empty_or_isset_offset(offset); return NULL; } } @@ -2961,7 +3046,7 @@ static zend_never_inline bool ZEND_FASTCALL zend_array_key_exists_fast(HashTable str = ZSTR_EMPTY_ALLOC(); goto str_key; } else { - zend_illegal_offset(); + zend_illegal_array_offset(key); return 0; } } @@ -2977,7 +3062,7 @@ static ZEND_COLD void ZEND_FASTCALL zend_array_key_exists_error( } if (!EG(exception)) { zend_type_error("array_key_exists(): Argument #2 ($array) must be of type array, %s given", - zend_zval_type_name(subject)); + zend_zval_value_name(subject)); } } @@ -3067,7 +3152,7 @@ static zend_never_inline bool zend_handle_fetch_obj_flags( return 1; } -static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type, uint32_t flags, bool init_undef OPLINE_DC EXECUTE_DATA_DC) +static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type, uint32_t flags OPLINE_DC EXECUTE_DATA_DC) { zval *ptr; zend_object *zobj; @@ -3116,6 +3201,8 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c ZEND_ASSERT(type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET); if (Z_TYPE_P(ptr) == IS_OBJECT) { ZVAL_COPY(result, ptr); + } else if (Z_PROP_FLAG_P(ptr) & IS_PROP_REINITABLE) { + Z_PROP_FLAG_P(ptr) &= ~IS_PROP_REINITABLE; } else { zend_readonly_property_modification_error(prop_info); ZVAL_ERROR(result); @@ -3185,9 +3272,6 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } } } - if (init_undef && UNEXPECTED(Z_TYPE_P(ptr) == IS_UNDEF)) { - ZVAL_NULL(ptr); - } end: if (prop_op_type != IS_CONST) { @@ -3199,9 +3283,10 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container { zval variable, *variable_ptr = &variable; void **cache_addr = (prop_op_type == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_RETURNS_FUNCTION) : NULL; + zend_refcounted *garbage = NULL; zend_fetch_property_address(variable_ptr, container, container_op_type, prop_ptr, prop_op_type, - cache_addr, BP_VAR_W, 0, 0 OPLINE_CC EXECUTE_DATA_CC); + cache_addr, BP_VAR_W, 0 OPLINE_CC EXECUTE_DATA_CC); if (EXPECTED(Z_TYPE_P(variable_ptr) == IS_INDIRECT)) { variable_ptr = Z_INDIRECT_P(variable_ptr); @@ -3210,7 +3295,7 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container UNEXPECTED(!Z_ISREF_P(value_ptr))) { variable_ptr = zend_wrong_assign_to_variable_reference( - variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); + variable_ptr, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { zend_property_info *prop_info = NULL; @@ -3222,9 +3307,9 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container } if (UNEXPECTED(prop_info)) { - variable_ptr = zend_assign_to_typed_property_reference(prop_info, variable_ptr, value_ptr EXECUTE_DATA_CC); + variable_ptr = zend_assign_to_typed_property_reference(prop_info, variable_ptr, value_ptr, &garbage EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } } } else if (Z_ISERROR_P(variable_ptr)) { @@ -3238,6 +3323,9 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } } static zend_never_inline void zend_assign_to_property_reference_this_const(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) @@ -3269,7 +3357,7 @@ static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval zend_class_entry *ce; zend_property_info *property_info; - zend_uchar op1_type = opline->op1_type, op2_type = opline->op2_type; + uint8_t op1_type = opline->op1_type, op2_type = opline->op2_type; if (EXPECTED(op2_type == IS_CONST)) { zval *class_name = RT_CONSTANT(opline, opline->op2); @@ -3320,11 +3408,9 @@ static zend_never_inline zend_result zend_fetch_static_property_address_ex(zval } *retval = zend_std_get_static_property_with_info(ce, name, fetch_type, &property_info); - if (UNEXPECTED(op1_type != IS_CONST)) { - zend_tmp_string_release(tmp_name); + zend_tmp_string_release(tmp_name); - FREE_OP(op1_type, opline->op1.var); - } + FREE_OP(op1_type, opline->op1.var); } if (UNEXPECTED(*retval == NULL)) { @@ -3378,7 +3464,7 @@ static zend_always_inline zend_result zend_fetch_static_property_address(zval ** return SUCCESS; } -ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(zend_property_info *prop1, zend_property_info *prop2, zval *zv) { +ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { zend_string *type1_str = zend_type_to_string(prop1->type); zend_string *type2_str = zend_type_to_string(prop2->type); zend_type_error("Reference with value of type %s held by property %s::$%s of type %s is not compatible with property %s::$%s of type %s", @@ -3394,10 +3480,10 @@ ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(zend_property_info *prop1 zend_string_release(type2_str); } -ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(zend_property_info *prop, zval *zv) { +ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(const zend_property_info *prop, const zval *zv) { zend_string *type_str = zend_type_to_string(prop->type); zend_type_error("Cannot assign %s to reference held by property %s::$%s of type %s", - zend_zval_type_name(zv), + zend_zval_value_name(zv), ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name), ZSTR_VAL(type_str) @@ -3405,11 +3491,11 @@ ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(zend_property_info *prop, zend_string_release(type_str); } -ZEND_API ZEND_COLD void zend_throw_conflicting_coercion_error(zend_property_info *prop1, zend_property_info *prop2, zval *zv) { +ZEND_API ZEND_COLD void zend_throw_conflicting_coercion_error(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { zend_string *type1_str = zend_type_to_string(prop1->type); zend_string *type2_str = zend_type_to_string(prop2->type); zend_type_error("Cannot assign %s to reference held by property %s::$%s of type %s and property %s::$%s of type %s, as this would result in an inconsistent type conversion", - zend_zval_type_name(zv), + zend_zval_value_name(zv), ZSTR_VAL(prop1->ce->name), zend_get_unmangled_property_name(prop1->name), ZSTR_VAL(type1_str), @@ -3423,17 +3509,17 @@ ZEND_API ZEND_COLD void zend_throw_conflicting_coercion_error(zend_property_info /* 1: valid, 0: invalid, -1: may be valid after type coercion */ static zend_always_inline int i_zend_verify_type_assignable_zval( - zend_property_info *info, zval *zv, bool strict) { + const zend_property_info *info, const zval *zv, bool strict) { zend_type type = info->type; uint32_t type_mask; - zend_uchar zv_type = Z_TYPE_P(zv); + uint8_t zv_type = Z_TYPE_P(zv); if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(type, zv_type))) { return 1; } if (ZEND_TYPE_IS_COMPLEX(type) && zv_type == IS_OBJECT - && zend_check_and_resolve_property_class_type(info, Z_OBJCE_P(zv))) { + && zend_check_and_resolve_property_or_class_constant_class_type(info->ce, info->type, Z_OBJCE_P(zv))) { return 1; } @@ -3465,11 +3551,11 @@ static zend_always_inline int i_zend_verify_type_assignable_zval( ZEND_API bool ZEND_FASTCALL zend_verify_ref_assignable_zval(zend_reference *ref, zval *zv, bool strict) { - zend_property_info *prop; + const zend_property_info *prop; /* The value must satisfy each property type, and coerce to the same value for each property * type. Remember the first coerced type and value we've seen for this purpose. */ - zend_property_info *first_prop = NULL; + const zend_property_info *first_prop = NULL; zval coerced_value; ZVAL_UNDEF(&coerced_value); @@ -3534,15 +3620,11 @@ static zend_always_inline void i_zval_ptr_dtor_noref(zval *zval_ptr) { if (Z_REFCOUNTED_P(zval_ptr)) { zend_refcounted *ref = Z_COUNTED_P(zval_ptr); ZEND_ASSERT(Z_TYPE_P(zval_ptr) != IS_REFERENCE); - if (!GC_DELREF(ref)) { - rc_dtor_func(ref); - } else if (UNEXPECTED(GC_MAY_LEAK(ref))) { - gc_possible_root(ref); - } + GC_DTOR_NO_REF(ref); } } -ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, zend_uchar value_type, bool strict) +ZEND_API zval* zend_assign_to_typed_ref_ex(zval *variable_ptr, zval *orig_value, uint8_t value_type, bool strict, zend_refcounted **garbage_ptr) { bool ret; zval value; @@ -3557,7 +3639,9 @@ ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, ze ret = zend_verify_ref_assignable_zval(Z_REF_P(variable_ptr), &value, strict); variable_ptr = Z_REFVAL_P(variable_ptr); if (EXPECTED(ret)) { - i_zval_ptr_dtor_noref(variable_ptr); + if (Z_REFCOUNTED_P(variable_ptr)) { + *garbage_ptr = Z_COUNTED_P(variable_ptr); + } ZVAL_COPY_VALUE(variable_ptr, &value); } else { zval_ptr_dtor_nogc(&value); @@ -3575,7 +3659,17 @@ ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, ze return variable_ptr; } -ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context) { +ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, uint8_t value_type, bool strict) +{ + zend_refcounted *garbage = NULL; + zval *result = zend_assign_to_typed_ref_ex(variable_ptr, orig_value, value_type, strict, &garbage); + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + return result; +} + +ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(const zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context) { zval *val = orig_val; if (Z_ISREF_P(val) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(val))) { int result; @@ -3592,7 +3686,7 @@ ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(zend_property_ zval tmp; ZVAL_COPY(&tmp, val); if (zend_verify_weak_scalar_type_hint(ZEND_TYPE_FULL_MASK(prop_info->type), &tmp)) { - zend_property_info *ref_prop = ZEND_REF_FIRST_SOURCE(Z_REF_P(orig_val)); + const zend_property_info *ref_prop = ZEND_REF_FIRST_SOURCE(Z_REF_P(orig_val)); zend_throw_ref_type_error_type(ref_prop, prop_info, val); zval_ptr_dtor(&tmp); return 0; @@ -3616,7 +3710,7 @@ ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(zend_property_ return 0; } -ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(zend_property_info *prop_info, zval *orig_val, bool strict) { +ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(const zend_property_info *prop_info, zval *orig_val, bool strict) { return zend_verify_prop_assignable_by_ref_ex(prop_info, orig_val, strict, ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_ASSIGNMENT); } @@ -3643,7 +3737,7 @@ ZEND_API void ZEND_FASTCALL zend_ref_add_type_source(zend_property_info_source_l source_list->list = ZEND_PROPERTY_INFO_SOURCE_FROM_LIST(list); } -ZEND_API void ZEND_FASTCALL zend_ref_del_type_source(zend_property_info_source_list *source_list, zend_property_info *prop) +ZEND_API void ZEND_FASTCALL zend_ref_del_type_source(zend_property_info_source_list *source_list, const zend_property_info *prop) { zend_property_info_list *list = ZEND_PROPERTY_INFO_SOURCE_TO_LIST(source_list->list); zend_property_info **ptr, **end; @@ -4441,11 +4535,100 @@ ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, cleanup_live_vars(execute_data, op_num, catch_op_num); } +ZEND_API ZEND_ATTRIBUTE_DEPRECATED HashTable *zend_unfinished_execution_gc(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer) +{ + bool suspended_by_yield = false; + + if (Z_TYPE_INFO(EX(This)) & ZEND_CALL_GENERATOR) { + ZEND_ASSERT(EX(return_value)); + + /* The generator object is stored in EX(return_value) */ + zend_generator *generator = (zend_generator*) EX(return_value); + ZEND_ASSERT(execute_data == generator->execute_data); + + suspended_by_yield = !(generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING); + } + + return zend_unfinished_execution_gc_ex(execute_data, call, gc_buffer, suspended_by_yield); +} + +ZEND_API HashTable *zend_unfinished_execution_gc_ex(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer, bool suspended_by_yield) +{ + if (!EX(func) || !ZEND_USER_CODE(EX(func)->common.type)) { + return NULL; + } + + zend_op_array *op_array = &EX(func)->op_array; + + if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) { + uint32_t i, num_cvs = EX(func)->op_array.last_var; + for (i = 0; i < num_cvs; i++) { + zend_get_gc_buffer_add_zval(gc_buffer, EX_VAR_NUM(i)); + } + } + + if (EX_CALL_INFO() & ZEND_CALL_FREE_EXTRA_ARGS) { + zval *zv = EX_VAR_NUM(op_array->last_var + op_array->T); + zval *end = zv + (EX_NUM_ARGS() - op_array->num_args); + while (zv != end) { + zend_get_gc_buffer_add_zval(gc_buffer, zv++); + } + } + + if (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) { + zend_get_gc_buffer_add_obj(gc_buffer, Z_OBJ(execute_data->This)); + } + if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) { + zend_get_gc_buffer_add_obj(gc_buffer, ZEND_CLOSURE_OBJECT(EX(func))); + } + if (EX_CALL_INFO() & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zval extra_named_params; + ZVAL_ARR(&extra_named_params, EX(extra_named_params)); + zend_get_gc_buffer_add_zval(gc_buffer, &extra_named_params); + } + + if (call) { + uint32_t op_num = execute_data->opline - op_array->opcodes; + if (suspended_by_yield) { + /* When the execution was suspended by yield, EX(opline) points to + * next opline to execute. Otherwise, it points to the opline that + * suspended execution. */ + op_num--; + ZEND_ASSERT(EX(func)->op_array.opcodes[op_num].opcode == ZEND_YIELD + || EX(func)->op_array.opcodes[op_num].opcode == ZEND_YIELD_FROM); + } + zend_unfinished_calls_gc(execute_data, call, op_num, gc_buffer); + } + + if (execute_data->opline != op_array->opcodes) { + uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1; + for (i = 0; i < op_array->last_live_range; i++) { + const zend_live_range *range = &op_array->live_range[i]; + if (range->start > op_num) { + break; + } else if (op_num < range->end) { + uint32_t kind = range->var & ZEND_LIVE_MASK; + uint32_t var_num = range->var & ~ZEND_LIVE_MASK; + zval *var = EX_VAR(var_num); + if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) { + zend_get_gc_buffer_add_zval(gc_buffer, var); + } + } + } + } + + if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { + return execute_data->symbol_table; + } else { + return NULL; + } +} + #if ZEND_VM_SPEC static void zend_swap_operands(zend_op *op) /* {{{ */ { znode_op tmp; - zend_uchar tmp_type; + uint8_t tmp_type; tmp = op->op1; tmp_type = op->op1_type; @@ -4670,7 +4853,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar } /* }}} */ -#define ZEND_FAKE_OP_ARRAY ((zend_op_array*)(zend_intptr_t)-1) +#define ZEND_FAKE_OP_ARRAY ((zend_op_array*)(intptr_t)-1) static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval *inc_filename_zv, int type) /* {{{ */ { @@ -4825,7 +5008,7 @@ static zend_always_inline zend_result _zend_quick_get_constant( if (!check_defined_only) { ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) { - zend_error(E_DEPRECATED, "Constant %s is deprecated", ZSTR_VAL(c->name)); + zend_error(E_DEPRECATED, "Constant %s is deprecated", ZSTR_VAL(Z_STR_P(key))); return SUCCESS; } } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index ed6d66461863d..dab902c383cb3 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -26,6 +26,8 @@ #include "zend_operators.h" #include "zend_variables.h" +#include + BEGIN_EXTERN_C() struct _zend_fcall_info; ZEND_API extern void (*zend_execute_ex)(zend_execute_data *execute_data); @@ -70,17 +72,21 @@ typedef enum { ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_ASSIGNMENT, ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_MAGIC_GET, } zend_verify_prop_assignable_by_ref_context; -ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context); -ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(zend_property_info *prop_info, zval *orig_val, bool strict); +ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(const zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context); +ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(const zend_property_info *prop_info, zval *orig_val, bool strict); -ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(zend_property_info *prop, zval *zv); -ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(zend_property_info *prop1, zend_property_info *prop2, zval *zv); +ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(const zend_property_info *prop, const zval *zv); +ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv); ZEND_API ZEND_COLD zval* ZEND_FASTCALL zend_undefined_offset_write(HashTable *ht, zend_long lval); ZEND_API ZEND_COLD zval* ZEND_FASTCALL zend_undefined_index_write(HashTable *ht, zend_string *offset); ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(zend_property_info *info); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(zend_property_info *info); +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(const zend_property_info *info); +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(const zend_property_info *info); + +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_invalid_class_constant_type_error(uint8_t type); + +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_object_released_while_assigning_to_property_error(const zend_property_info *info); ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool strict, bool is_internal_arg); ZEND_API ZEND_COLD void zend_verify_arg_error( @@ -112,11 +118,12 @@ ZEND_API bool zend_verify_internal_return_type(zend_function *zf, zval *ret); ZEND_API void ZEND_FASTCALL zend_ref_add_type_source(zend_property_info_source_list *source_list, zend_property_info *prop); -ZEND_API void ZEND_FASTCALL zend_ref_del_type_source(zend_property_info_source_list *source_list, zend_property_info *prop); +ZEND_API void ZEND_FASTCALL zend_ref_del_type_source(zend_property_info_source_list *source_list, const zend_property_info *prop); -ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *value, zend_uchar value_type, bool strict); +ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *value, uint8_t value_type, bool strict); +ZEND_API zval* zend_assign_to_typed_ref_ex(zval *variable_ptr, zval *value, uint8_t value_type, bool strict, zend_refcounted **garbage_ptr); -static zend_always_inline void zend_copy_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type) +static zend_always_inline void zend_copy_to_variable(zval *variable_ptr, zval *value, uint8_t value_type) { zend_refcounted *ref = NULL; @@ -143,7 +150,7 @@ static zend_always_inline void zend_copy_to_variable(zval *variable_ptr, zval *v } } -static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type, bool strict) +static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value, uint8_t value_type, bool strict) { do { if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) { @@ -161,15 +168,30 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval } garbage = Z_COUNTED_P(variable_ptr); zend_copy_to_variable(variable_ptr, value, value_type); - if (GC_DELREF(garbage) == 0) { - rc_dtor_func(garbage); - } else { /* we need to split */ - /* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */ - if (UNEXPECTED(GC_MAY_LEAK(garbage))) { - gc_possible_root(garbage); + GC_DTOR_NO_REF(garbage); + return variable_ptr; + } + } while (0); + + zend_copy_to_variable(variable_ptr, value, value_type); + return variable_ptr; +} + +static zend_always_inline zval* zend_assign_to_variable_ex(zval *variable_ptr, zval *value, zend_uchar value_type, bool strict, zend_refcounted **garbage_ptr) +{ + do { + if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) { + if (Z_ISREF_P(variable_ptr)) { + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) { + return zend_assign_to_typed_ref_ex(variable_ptr, value, value_type, strict, garbage_ptr); + } + + variable_ptr = Z_REFVAL_P(variable_ptr); + if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) { + break; } } - return variable_ptr; + *garbage_ptr = Z_COUNTED_P(variable_ptr); } } while (0); @@ -188,8 +210,12 @@ struct _zend_vm_stack { zend_vm_stack prev; }; +/* Ensure the correct alignment before slots calculation */ +ZEND_STATIC_ASSERT(ZEND_MM_ALIGNED_SIZE(sizeof(zval)) == sizeof(zval), + "zval must be aligned by ZEND_MM_ALIGNMENT"); +/* A number of call frame slots (zvals) reserved for _zend_vm_stack. */ #define ZEND_VM_STACK_HEADER_SLOTS \ - ((ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) + ((sizeof(struct _zend_vm_stack) + sizeof(zval) - 1) / sizeof(zval)) #define ZEND_VM_STACK_ELEMENTS(stack) \ (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOTS) @@ -378,8 +404,8 @@ ZEND_API bool zend_gcc_global_regs(void); #define ZEND_USER_OPCODE_DISPATCH_TO 0x100 /* call original handler of returned opcode */ -ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler); -ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode); +ZEND_API zend_result zend_set_user_opcode_handler(uint8_t opcode, user_opcode_handler_t handler); +ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(uint8_t opcode); ZEND_API zval *zend_get_zval_ptr(const zend_op *opline, int op_type, const znode_op *node, const zend_execute_data *execute_data); @@ -387,11 +413,13 @@ ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table); ZEND_API void ZEND_FASTCALL zend_free_compiled_variables(zend_execute_data *execute_data); ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_execute_data *call, uint32_t op_num, zend_get_gc_buffer *buf); ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num); +ZEND_API ZEND_ATTRIBUTE_DEPRECATED HashTable *zend_unfinished_execution_gc(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer); +ZEND_API HashTable *zend_unfinished_execution_gc_ex(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer, bool suspended_by_yield); zval * ZEND_FASTCALL zend_handle_named_arg( zend_execute_data **call_ptr, zend_string *arg_name, uint32_t *arg_num_ptr, void **cache_slot); -ZEND_API int ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call); +ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call); #define CACHE_ADDR(num) \ ((void**)((char*)EX(run_time_cache) + (num))) @@ -454,10 +482,15 @@ ZEND_API int ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call); } while (0) #define ZEND_CLASS_HAS_TYPE_HINTS(ce) ((ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) == ZEND_ACC_HAS_TYPE_HINTS) +#define ZEND_CLASS_HAS_READONLY_PROPS(ce) ((ce->ce_flags & ZEND_ACC_HAS_READONLY_PROPS) == ZEND_ACC_HAS_READONLY_PROPS) + + +ZEND_API bool zend_verify_class_constant_type(zend_class_constant *c, const zend_string *name, zval *constant); +ZEND_COLD void zend_verify_class_constant_type_error(const zend_class_constant *c, const zend_string *name, const zval *constant); -ZEND_API bool zend_verify_property_type(zend_property_info *info, zval *property, bool strict); -ZEND_COLD void zend_verify_property_type_error(zend_property_info *info, zval *property); -ZEND_COLD void zend_magic_get_property_type_inconsistency_error(zend_property_info *info, zval *property); +ZEND_API bool zend_verify_property_type(const zend_property_info *info, zval *property, bool strict); +ZEND_COLD void zend_verify_property_type_error(const zend_property_info *info, const zval *property); +ZEND_COLD void zend_magic_get_property_type_inconsistency_error(const zend_property_info *info, const zval *property); #define ZEND_REF_ADD_TYPE_SOURCE(ref, source) \ zend_ref_add_type_source(&ZEND_REF_TYPE_SOURCES(ref), source) @@ -486,7 +519,7 @@ ZEND_COLD void zend_magic_get_property_type_inconsistency_error(zend_property_in } \ } while (0) -ZEND_COLD void zend_match_unhandled_error(zval *value); +ZEND_COLD void zend_match_unhandled_error(const zval *value); END_EXTERN_C() diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 3c29ac7dc6090..c1a5e31f7e6d9 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -37,12 +37,16 @@ #include "zend_weakrefs.h" #include "zend_inheritance.h" #include "zend_observer.h" +#include "zend_call_stack.h" #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_UNISTD_H #include #endif +#ifdef ZEND_MAX_EXECUTION_TIMERS +#include +#endif ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value); @@ -195,6 +199,7 @@ void init_executor(void) /* {{{ */ EG(filename_override) = NULL; EG(lineno_override) = -1; + zend_max_execution_timer_init(); zend_fiber_init(); zend_weakrefs_init(); @@ -289,9 +294,6 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) break; } zval_ptr_dtor_nogc(&c->value); - if (c->name) { - zend_string_release_ex(c->name, 0); - } efree(c); zend_string_release_ex(key, 0); } ZEND_HASH_MAP_FOREACH_END_DEL(); @@ -412,6 +414,7 @@ void shutdown_executor(void) /* {{{ */ zend_shutdown_executor_values(fast_shutdown); zend_weakrefs_shutdown(); + zend_max_execution_timer_shutdown(); zend_fiber_shutdown(); zend_try { @@ -566,7 +569,7 @@ ZEND_API zend_string *get_function_or_method_name(const zend_function *func) /* return zend_create_member_string(func->common.scope->name, func->common.function_name); } - return func->common.function_name ? zend_string_copy(func->common.function_name) : zend_string_init("main", sizeof("main") - 1, 0); + return func->common.function_name ? zend_string_copy(func->common.function_name) : ZSTR_INIT_LITERAL("main", 0); } /* }}} */ @@ -692,7 +695,19 @@ ZEND_API zend_result ZEND_FASTCALL zval_update_constant_with_ctx(zval *p, zend_c zval tmp; bool short_circuited; - if (UNEXPECTED(zend_ast_evaluate_ex(&tmp, ast, scope, &short_circuited, ctx) != SUCCESS)) { + // Increase the refcount during zend_ast_evaluate to avoid releasing the ast too early + // on nested calls to zval_update_constant_ex which can happen when retriggering ast + // evaluation during autoloading. + zend_ast_ref *ast_ref = Z_AST_P(p); + bool ast_is_refcounted = !(GC_FLAGS(ast_ref) & GC_IMMUTABLE); + if (ast_is_refcounted) { + GC_ADDREF(ast_ref); + } + zend_result result = zend_ast_evaluate_ex(&tmp, ast, scope, &short_circuited, ctx) != SUCCESS; + if (ast_is_refcounted && !GC_DELREF(ast_ref)) { + rc_dtor_func((zend_refcounted *)ast_ref); + } + if (UNEXPECTED(result != SUCCESS)) { return FAILURE; } zval_ptr_dtor_nogc(p); @@ -1114,7 +1129,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * if (key) { lc_name = key; } else { - if (name == NULL || !ZSTR_LEN(name)) { + if (!ZSTR_LEN(name)) { return NULL; } @@ -1140,7 +1155,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * ALLOC_HASHTABLE(CG(unlinked_uses)); zend_hash_init(CG(unlinked_uses), 0, NULL, NULL, 0); } - zend_hash_index_add_empty_element(CG(unlinked_uses), (zend_long)(zend_uintptr_t)ce); + zend_hash_index_add_empty_element(CG(unlinked_uses), (zend_long)(uintptr_t)ce); return ce; } return NULL; @@ -1366,8 +1381,35 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ /* }}} */ #ifndef ZEND_WIN32 +# ifdef ZEND_MAX_EXECUTION_TIMERS +static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ +{ +#ifdef ZTS + if (!tsrm_is_managed_thread()) { + fprintf(stderr, "zend_timeout_handler() called in a thread not managed by PHP. The expected signal handler will not be called. This is probably a bug.\n"); + + return; + } +#endif + + if (si->si_value.sival_ptr != &EG(max_execution_timer_timer)) { +#ifdef MAX_EXECUTION_TIMERS_DEBUG + fprintf(stderr, "Executing previous handler (if set) for unexpected signal SIGRTMIN received on thread %d\n", (pid_t) syscall(SYS_gettid)); +#endif + + if (EG(oldact).sa_sigaction) { + EG(oldact).sa_sigaction(dummy, si, uc); + + return; + } + if (EG(oldact).sa_handler) EG(oldact).sa_handler(dummy); + + return; + } +# else static void zend_timeout_handler(int dummy) /* {{{ */ { +# endif #ifdef ZTS if (!tsrm_is_managed_thread()) { fprintf(stderr, "zend_timeout_handler() called in a thread not managed by PHP. The expected signal handler will not be called. This is probably a bug.\n"); @@ -1473,6 +1515,21 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ zend_error_noreturn(E_ERROR, "Could not queue new timer"); return; } +#elif defined(ZEND_MAX_EXECUTION_TIMERS) + zend_max_execution_timer_settime(seconds); + + if (reset_signals) { + sigset_t sigset; + struct sigaction act; + + act.sa_sigaction = zend_timeout_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_ONSTACK | SA_SIGINFO; + sigaction(SIGRTMIN, &act, NULL); + sigemptyset(&sigset); + sigaddset(&sigset, SIGRTMIN); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + } #elif defined(HAVE_SETITIMER) { struct itimerval t_r; /* timeout requested */ @@ -1538,6 +1595,8 @@ void zend_unset_timeout(void) /* {{{ */ } tq_timer = NULL; } +#elif ZEND_MAX_EXECUTION_TIMERS + zend_max_execution_timer_settime(0); #elif defined(HAVE_SETITIMER) if (EG(timeout_seconds)) { struct itimerval no_timeout; diff --git a/Zend/zend_extensions.c b/Zend/zend_extensions.c index 1f3687642ab67..c0c6dc8196298 100644 --- a/Zend/zend_extensions.c +++ b/Zend/zend_extensions.c @@ -63,11 +63,10 @@ zend_result zend_load_extension_handle(DL_HANDLE handle, const char *path) { #if ZEND_EXTENSIONS_SUPPORT zend_extension *new_extension; - zend_extension_version_info *extension_version_info; - extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info"); + const zend_extension_version_info *extension_version_info = (const zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info"); if (!extension_version_info) { - extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info"); + extension_version_info = (const zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info"); } new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry"); if (!new_extension) { @@ -265,6 +264,27 @@ ZEND_API int zend_get_resource_handle(const char *module_name) } } +/** + * The handle returned by this function can be used with + * `ZEND_OP_ARRAY_EXTENSION(op_array, handle)`. + * + * The extension slot has been available since PHP 7.4 on user functions and + * has been available since PHP 8.2 on internal functions. + * + * # Safety + * The extension slot made available by calling this function is initialized on + * the first call made to the function in that request. If you need to + * initialize it before this point, call `zend_init_func_run_time_cache`. + * + * The function cache slots are not available if the function is a trampoline, + * which can be checked with something like: + * + * if (fbc->type == ZEND_USER_FUNCTION + * && !(fbc->op_array.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) + * ) { + * // Use ZEND_OP_ARRAY_EXTENSION somehow + * } + */ ZEND_API int zend_get_op_array_extension_handle(const char *module_name) { int handle = zend_op_array_extension_handles++; @@ -272,6 +292,7 @@ ZEND_API int zend_get_op_array_extension_handle(const char *module_name) return handle; } +/** See zend_get_op_array_extension_handle for important usage information. */ ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int handles) { int handle = zend_op_array_extension_handles; @@ -280,11 +301,11 @@ ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int ha return handle; } -ZEND_API size_t zend_internal_run_time_cache_reserved_size() { +ZEND_API size_t zend_internal_run_time_cache_reserved_size(void) { return zend_op_array_extension_handles * sizeof(void *); } -ZEND_API void zend_init_internal_run_time_cache() { +ZEND_API void zend_init_internal_run_time_cache(void) { size_t rt_size = zend_internal_run_time_cache_reserved_size(); if (rt_size) { size_t functions = zend_hash_num_elements(CG(function_table)); diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index f5246e74251dd..99b044adbd550 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -25,6 +25,8 @@ #include "zend_builtin_functions.h" #include "zend_observer.h" #include "zend_mmap.h" +#include "zend_compile.h" +#include "zend_closures.h" #include "zend_fibers.h" #include "zend_fibers_arginfo.h" @@ -108,6 +110,10 @@ typedef struct _zend_fiber_vm_state { uint32_t jit_trace_num; JMP_BUF *bailout; zend_fiber *active_fiber; +#ifdef ZEND_CHECK_STACK_LIMIT + void *stack_base; + void *stack_limit; +#endif } zend_fiber_vm_state; static zend_always_inline void zend_fiber_capture_vm_state(zend_fiber_vm_state *state) @@ -121,6 +127,10 @@ static zend_always_inline void zend_fiber_capture_vm_state(zend_fiber_vm_state * state->jit_trace_num = EG(jit_trace_num); state->bailout = EG(bailout); state->active_fiber = EG(active_fiber); +#ifdef ZEND_CHECK_STACK_LIMIT + state->stack_base = EG(stack_base); + state->stack_limit = EG(stack_limit); +#endif } static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state *state) @@ -134,6 +144,10 @@ static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state * EG(jit_trace_num) = state->jit_trace_num; EG(bailout) = state->bailout; EG(active_fiber) = state->active_fiber; +#ifdef ZEND_CHECK_STACK_LIMIT + EG(stack_base) = state->stack_base; + EG(stack_limit) = state->stack_limit; +#endif } #ifdef ZEND_FIBER_UCONTEXT @@ -189,8 +203,12 @@ static zend_fiber_stack *zend_fiber_stack_allocate(size_t size) { void *pointer; const size_t page_size = zend_fiber_get_page_size(); + const size_t minimum_stack_size = page_size + ZEND_FIBER_GUARD_PAGES * page_size; - ZEND_ASSERT(size >= page_size + ZEND_FIBER_GUARD_PAGES * page_size); + if (size < minimum_stack_size) { + zend_throw_exception_ex(NULL, 0, "Fiber stack size is too small, it needs to be at least %zu bytes", minimum_stack_size); + return NULL; + } const size_t stack_size = (size + page_size - 1) / page_size * page_size; const size_t alloc_size = stack_size + ZEND_FIBER_GUARD_PAGES * page_size; @@ -294,6 +312,31 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack) efree(stack); } + +#ifdef ZEND_CHECK_STACK_LIMIT +ZEND_API void* zend_fiber_stack_limit(zend_fiber_stack *stack) +{ + zend_ulong reserve = EG(reserved_stack_size); + +#ifdef __APPLE__ + /* On Apple Clang, the stack probing function ___chkstk_darwin incorrectly + * probes a location that is twice the entered function's stack usage away + * from the stack pointer, when using an alternative stack. + * https://openradar.appspot.com/radar?id=5497722702397440 + */ + reserve = reserve * 2; +#endif + + /* stack->pointer is the end of the stack */ + return (int8_t*)stack->pointer + reserve; +} + +ZEND_API void* zend_fiber_stack_base(zend_fiber_stack *stack) +{ + return (void*)((uintptr_t)stack->pointer + stack->size); +} +#endif + #ifdef ZEND_FIBER_UCONTEXT static ZEND_NORETURN void zend_fiber_trampoline(void) #else @@ -351,12 +394,12 @@ ZEND_API bool zend_fiber_switch_blocked(void) return zend_fiber_switch_blocking; } -ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, zend_fiber_coroutine coroutine, size_t stack_size) +ZEND_API zend_result zend_fiber_init_context(zend_fiber_context *context, void *kind, zend_fiber_coroutine coroutine, size_t stack_size) { context->stack = zend_fiber_stack_allocate(stack_size); if (UNEXPECTED(!context->stack)) { - return false; + return FAILURE; } #ifdef ZEND_FIBER_UCONTEXT @@ -395,7 +438,7 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, z zend_observer_fiber_init_notify(context); - return true; + return SUCCESS; } ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context) @@ -535,6 +578,11 @@ static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer) EG(jit_trace_num) = 0; EG(error_reporting) = error_reporting; +#ifdef ZEND_CHECK_STACK_LIMIT + EG(stack_base) = zend_fiber_stack_base(fiber->context.stack); + EG(stack_limit) = zend_fiber_stack_limit(fiber->context.stack); +#endif + fiber->fci.retval = &fiber->result; zend_call_function(&fiber->fci, &fiber->fci_cache); @@ -597,6 +645,7 @@ static zend_always_inline zend_fiber_transfer zend_fiber_switch_to( /* Forward bailout into current fiber. */ if (UNEXPECTED(transfer.flags & ZEND_FIBER_TRANSFER_FLAG_BAILOUT)) { + EG(active_fiber) = NULL; zend_bailout(); } @@ -694,9 +743,32 @@ static HashTable *zend_fiber_object_gc(zend_object *object, zval **table, int *n zend_get_gc_buffer_add_zval(buf, &fiber->fci.function_name); zend_get_gc_buffer_add_zval(buf, &fiber->result); + if (fiber->context.status != ZEND_FIBER_STATUS_SUSPENDED || fiber->caller != NULL) { + zend_get_gc_buffer_use(buf, table, num); + return NULL; + } + + HashTable *lastSymTable = NULL; + zend_execute_data *ex = fiber->execute_data; + for (; ex; ex = ex->prev_execute_data) { + HashTable *symTable = zend_unfinished_execution_gc_ex(ex, ex->call, buf, false); + if (symTable) { + if (lastSymTable) { + zval *val; + ZEND_HASH_FOREACH_VAL(lastSymTable, val) { + if (EXPECTED(Z_TYPE_P(val) == IS_INDIRECT)) { + val = Z_INDIRECT_P(val); + } + zend_get_gc_buffer_add_zval(buf, val); + } ZEND_HASH_FOREACH_END(); + } + lastSymTable = symTable; + } + } + zend_get_gc_buffer_use(buf, table, num); - return NULL; + return lastSymTable; } ZEND_METHOD(Fiber, __construct) @@ -740,7 +812,7 @@ ZEND_METHOD(Fiber, start) RETURN_THROWS(); } - if (!zend_fiber_init_context(&fiber->context, zend_ce_fiber, zend_fiber_execute, EG(fiber_stack_size))) { + if (zend_fiber_init_context(&fiber->context, zend_ce_fiber, zend_fiber_execute, EG(fiber_stack_size)) == FAILURE) { RETURN_THROWS(); } diff --git a/Zend/zend_fibers.h b/Zend/zend_fibers.h index 2673e7814b093..5c81f44a642e4 100644 --- a/Zend/zend_fibers.h +++ b/Zend/zend_fibers.h @@ -133,9 +133,13 @@ struct _zend_fiber { }; /* These functions may be used to create custom fiber objects using the bundled fiber switching context. */ -ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, zend_fiber_coroutine coroutine, size_t stack_size); +ZEND_API zend_result zend_fiber_init_context(zend_fiber_context *context, void *kind, zend_fiber_coroutine coroutine, size_t stack_size); ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context); ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer); +#ifdef ZEND_CHECK_STACK_LIMIT +ZEND_API void* zend_fiber_stack_limit(zend_fiber_stack *stack); +ZEND_API void* zend_fiber_stack_base(zend_fiber_stack *stack); +#endif /* ZEND_CHECK_STACK_LIMIT */ ZEND_API void zend_fiber_switch_block(void); ZEND_API void zend_fiber_switch_unblock(void); diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 66324672b1e9c..6f00786b66928 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -591,7 +591,7 @@ static zend_never_inline void ZEND_FASTCALL gc_possible_root_when_full(zend_refc if (GC_G(gc_enabled) && !GC_G(gc_active)) { GC_ADDREF(ref); gc_adjust_threshold(gc_collect_cycles()); - if (UNEXPECTED(GC_DELREF(ref)) == 0) { + if (UNEXPECTED(GC_DELREF(ref) == 0)) { rc_dtor_func(ref); return; } else if (UNEXPECTED(GC_INFO(ref))) { @@ -1741,6 +1741,22 @@ static void zend_gc_root_tmpvars(void) { } } +#if GC_BENCH +void gc_bench_print(void) +{ + fprintf(stderr, "GC Statistics\n"); + fprintf(stderr, "-------------\n"); + fprintf(stderr, "Runs: %d\n", GC_G(gc_runs)); + fprintf(stderr, "Collected: %d\n", GC_G(collected)); + fprintf(stderr, "Root buffer length: %d\n", GC_G(root_buf_length)); + fprintf(stderr, "Root buffer peak: %d\n\n", GC_G(root_buf_peak)); + fprintf(stderr, " Possible Remove from Marked\n"); + fprintf(stderr, " Root Buffered buffer grey\n"); + fprintf(stderr, " -------- -------- ----------- ------\n"); + fprintf(stderr, "ZVAL %8d %8d %9d %8d\n", GC_G(zval_possible_root), GC_G(zval_buffered), GC_G(zval_remove_from_buffer), GC_G(zval_marked_grey)); +} +#endif + #ifdef ZTS size_t zend_gc_globals_size(void) { diff --git a/Zend/zend_gc.h b/Zend/zend_gc.h index 0589e193f4a16..f4095e43bb69e 100644 --- a/Zend/zend_gc.h +++ b/Zend/zend_gc.h @@ -46,6 +46,10 @@ ZEND_API bool gc_enabled(void); ZEND_API bool gc_protect(bool protect); ZEND_API bool gc_protected(void); +#if GC_BENCH +void gc_bench_print(void); +#endif + /* The default implementation of the gc_collect_cycles callback. */ ZEND_API int zend_gc_collect_cycles(void); @@ -85,6 +89,14 @@ static zend_always_inline void gc_check_possible_root(zend_refcounted *ref) } } +static zend_always_inline void gc_check_possible_root_no_ref(zend_refcounted *ref) +{ + ZEND_ASSERT(GC_TYPE_INFO(ref) != GC_REFERENCE); + if (UNEXPECTED(GC_MAY_LEAK(ref))) { + gc_possible_root(ref); + } +} + /* These APIs can be used to simplify object get_gc implementations * over heterogeneous structures. See zend_generator_get_gc() for * a usage example. */ diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index f30fa37475c9d..0ab0257f87700 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -223,6 +223,14 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ uint32_t op_num, try_catch_offset; int i; + /* Generator is running in a suspended fiber. + * Will be dtor during fiber dtor */ + if (zend_generator_get_current(generator)->flags & ZEND_GENERATOR_IN_FIBER) { + /* Prevent finally blocks from yielding */ + generator->flags |= ZEND_GENERATOR_FORCED_CLOSE; + return; + } + /* leave yield from mode to properly allow finally execution */ if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) { zval_ptr_dtor(&generator->values); @@ -271,14 +279,25 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ ZEND_CALL_VAR(ex, ex->func->op_array.opcodes[try_catch->finally_end].op1.var); zend_generator_cleanup_unfinished_execution(generator, ex, try_catch->finally_op); - Z_OBJ_P(fast_call) = EG(exception); + zend_object *old_exception = EG(exception); + const zend_op *old_opline_before_exception = EG(opline_before_exception); EG(exception) = NULL; + Z_OBJ_P(fast_call) = NULL; Z_OPLINE_NUM_P(fast_call) = (uint32_t)-1; ex->opline = &ex->func->op_array.opcodes[try_catch->finally_op]; generator->flags |= ZEND_GENERATOR_FORCED_CLOSE; zend_generator_resume(generator); + if (old_exception) { + EG(opline_before_exception) = old_opline_before_exception; + if (EG(exception)) { + zend_exception_set_previous(EG(exception), old_exception); + } else { + EG(exception) = old_exception; + } + } + /* TODO: If we hit another yield inside try/finally, * should we also jump to the next finally block? */ break; @@ -332,7 +351,7 @@ static HashTable *zend_generator_get_gc(zend_object *object, zval **table, int * { zend_generator *generator = (zend_generator*)object; zend_execute_data *execute_data = generator->execute_data; - zend_op_array *op_array; + zend_execute_data *call = NULL; if (!execute_data) { /* If the generator has been closed, it can only hold on to three values: The value, key @@ -352,7 +371,6 @@ static HashTable *zend_generator_get_gc(zend_object *object, zval **table, int * return NULL; } - op_array = &EX(func)->op_array; zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); zend_get_gc_buffer_add_zval(gc_buffer, &generator->value); @@ -360,59 +378,17 @@ static HashTable *zend_generator_get_gc(zend_object *object, zval **table, int * zend_get_gc_buffer_add_zval(gc_buffer, &generator->retval); zend_get_gc_buffer_add_zval(gc_buffer, &generator->values); - if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) { - uint32_t i, num_cvs = EX(func)->op_array.last_var; - for (i = 0; i < num_cvs; i++) { - zend_get_gc_buffer_add_zval(gc_buffer, EX_VAR_NUM(i)); - } - } - - if (EX_CALL_INFO() & ZEND_CALL_FREE_EXTRA_ARGS) { - zval *zv = EX_VAR_NUM(op_array->last_var + op_array->T); - zval *end = zv + (EX_NUM_ARGS() - op_array->num_args); - while (zv != end) { - zend_get_gc_buffer_add_zval(gc_buffer, zv++); - } + if (UNEXPECTED(generator->frozen_call_stack)) { + /* The frozen stack is linked in reverse order */ + call = zend_generator_revert_call_stack(generator->frozen_call_stack); } - if (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) { - zend_get_gc_buffer_add_obj(gc_buffer, Z_OBJ(execute_data->This)); - } - if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) { - zend_get_gc_buffer_add_obj(gc_buffer, ZEND_CLOSURE_OBJECT(EX(func))); - } - if (EX_CALL_INFO() & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { - zval extra_named_params; - ZVAL_ARR(&extra_named_params, EX(extra_named_params)); - zend_get_gc_buffer_add_zval(gc_buffer, &extra_named_params); - } + zend_unfinished_execution_gc_ex(execute_data, call, gc_buffer, true); if (UNEXPECTED(generator->frozen_call_stack)) { - /* The frozen stack is linked in reverse order */ - zend_execute_data *call = zend_generator_revert_call_stack(generator->frozen_call_stack); - /* -1 required because we want the last run opcode, not the next to-be-run one. */ - uint32_t op_num = execute_data->opline - op_array->opcodes - 1; - zend_unfinished_calls_gc(execute_data, call, op_num, gc_buffer); zend_generator_revert_call_stack(call); } - if (execute_data->opline != op_array->opcodes) { - uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1; - for (i = 0; i < op_array->last_live_range; i++) { - const zend_live_range *range = &op_array->live_range[i]; - if (range->start > op_num) { - break; - } else if (op_num < range->end) { - uint32_t kind = range->var & ZEND_LIVE_MASK; - uint32_t var_num = range->var & ~ZEND_LIVE_MASK; - zval *var = EX_VAR(var_num); - if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) { - zend_get_gc_buffer_add_zval(gc_buffer, var); - } - } - } - } - if (generator->node.parent) { zend_get_gc_buffer_add_obj(gc_buffer, &generator->node.parent->std); } @@ -784,7 +760,8 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ } /* Resume execution */ - generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING; + generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING + | (EG(active_fiber) ? ZEND_GENERATOR_IN_FIBER : 0); if (!ZEND_OBSERVER_ENABLED) { zend_execute_ex(generator->execute_data); } else { @@ -795,7 +772,7 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ zend_observer_fcall_end(generator->execute_data, &generator->value); } } - generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING; + generator->flags &= ~(ZEND_GENERATOR_CURRENTLY_RUNNING | ZEND_GENERATOR_IN_FIBER); generator->frozen_call_stack = NULL; if (EXPECTED(generator->execute_data) && diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index 17b25a99b87c1..b3fb44c353355 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -20,6 +20,8 @@ #ifndef ZEND_GENERATORS_H #define ZEND_GENERATORS_H +#include + BEGIN_EXTERN_C() extern ZEND_API zend_class_entry *zend_ce_generator; @@ -85,13 +87,14 @@ struct _zend_generator { zend_execute_data execute_fake; /* ZEND_GENERATOR_* flags */ - zend_uchar flags; + uint8_t flags; }; -static const zend_uchar ZEND_GENERATOR_CURRENTLY_RUNNING = 0x1; -static const zend_uchar ZEND_GENERATOR_FORCED_CLOSE = 0x2; -static const zend_uchar ZEND_GENERATOR_AT_FIRST_YIELD = 0x4; -static const zend_uchar ZEND_GENERATOR_DO_INIT = 0x8; +static const uint8_t ZEND_GENERATOR_CURRENTLY_RUNNING = 0x1; +static const uint8_t ZEND_GENERATOR_FORCED_CLOSE = 0x2; +static const uint8_t ZEND_GENERATOR_AT_FIRST_YIELD = 0x4; +static const uint8_t ZEND_GENERATOR_DO_INIT = 0x8; +static const uint8_t ZEND_GENERATOR_IN_FIBER = 0x10; void zend_register_generator_ce(void); ZEND_API void zend_generator_close(zend_generator *generator, bool finished_execution); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 17469fab0c11e..8900a5f416f53 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -22,6 +22,8 @@ #include +#include +#include #include "zend_globals_macros.h" @@ -37,6 +39,8 @@ #include "zend_multibyte.h" #include "zend_multiply.h" #include "zend_arena.h" +#include "zend_call_stack.h" +#include "zend_max_execution_timer.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -54,6 +58,10 @@ END_EXTERN_C() #define SYMTABLE_CACHE_SIZE 32 +#ifdef ZEND_CHECK_STACK_LIMIT +# define ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED -1 +# define ZEND_MAX_ALLOWED_STACK_SIZE_DETECT 0 +#endif #include "zend_compile.h" @@ -65,6 +73,12 @@ typedef struct _zend_ini_entry zend_ini_entry; typedef struct _zend_fiber_context zend_fiber_context; typedef struct _zend_fiber zend_fiber; +typedef enum { + ZEND_MEMOIZE_NONE, + ZEND_MEMOIZE_COMPILE, + ZEND_MEMOIZE_FETCH, +} zend_memoize_mode; + struct _zend_compiler_globals { zend_stack loop_var_stack; @@ -82,7 +96,7 @@ struct _zend_compiler_globals { HashTable *auto_globals; /* Refer to zend_yytnamerr() in zend_language_parser.y for meaning of values */ - zend_uchar parse_error; + uint8_t parse_error; bool in_compilation; bool short_tags; @@ -124,7 +138,7 @@ struct _zend_compiler_globals { zend_stack delayed_oplines_stack; HashTable *memoized_exprs; - int memoize_mode; + zend_memoize_mode memoize_mode; void *map_ptr_real_base; void *map_ptr_base; @@ -139,6 +153,9 @@ struct _zend_compiler_globals { uint32_t rtd_key_counter; zend_stack short_circuiting_opnums; +#ifdef ZTS + uint32_t copied_functions_count; +#endif }; @@ -176,23 +193,27 @@ struct _zend_executor_globals { uint32_t jit_trace_num; /* Used by tracing JIT to reference the currently running trace */ - zend_long precision; - int ticks_count; + zend_long precision; + uint32_t persistent_constants_count; uint32_t persistent_functions_count; uint32_t persistent_classes_count; - HashTable *in_autoload; - bool full_tables_cleanup; - /* for extended information support */ bool no_extensions; + bool full_tables_cleanup; + zend_atomic_bool vm_interrupt; zend_atomic_bool timed_out; + + HashTable *in_autoload; + zend_long hard_timeout; + void *stack_base; + void *stack_limit; #ifdef ZEND_WIN32 OSVERSIONINFOEX windows_version_info; @@ -202,20 +223,21 @@ struct _zend_executor_globals { HashTable persistent_list; int user_error_handler_error_reporting; + bool exception_ignore_args; zval user_error_handler; zval user_exception_handler; zend_stack user_error_handlers_error_reporting; zend_stack user_error_handlers; zend_stack user_exception_handlers; - zend_error_handling_t error_handling; zend_class_entry *exception_class; + zend_error_handling_t error_handling; + + int capture_warnings_during_sccp; /* timeout support */ zend_long timeout_seconds; - int capture_warnings_during_sccp; - HashTable *ini_directives; HashTable *modified_ini_directives; zend_ini_entry *error_reporting_ini_entry; @@ -228,7 +250,7 @@ struct _zend_executor_globals { struct _zend_module_entry *current_module; bool active; - zend_uchar flags; + uint8_t flags; zend_long assertions; @@ -247,7 +269,6 @@ struct _zend_executor_globals { HashTable weakrefs; - bool exception_ignore_args; zend_long exception_string_param_max_len; zend_get_gc_buffer get_gc_buffer; @@ -259,7 +280,7 @@ struct _zend_executor_globals { zend_fiber *active_fiber; /* Default fiber C stack size. */ - zend_long fiber_stack_size; + size_t fiber_stack_size; /* If record_errors is enabled, all emitted diagnostics will be recorded, * in addition to being processed as usual. */ @@ -271,6 +292,18 @@ struct _zend_executor_globals { zend_string *filename_override; zend_long lineno_override; +#ifdef ZEND_CHECK_STACK_LIMIT + zend_call_stack call_stack; + zend_long max_allowed_stack_size; + zend_ulong reserved_stack_size; +#endif + +#ifdef ZEND_MAX_EXECUTION_TIMERS + timer_t max_execution_timer_timer; + pid_t pid; + struct sigaction oldact; +#endif + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; @@ -284,11 +317,11 @@ struct _zend_ini_scanner_globals { zend_file_handle *yy_out; unsigned int yy_leng; - unsigned char *yy_start; - unsigned char *yy_text; - unsigned char *yy_cursor; - unsigned char *yy_marker; - unsigned char *yy_limit; + const unsigned char *yy_start; + const unsigned char *yy_text; + const unsigned char *yy_cursor; + const unsigned char *yy_marker; + const unsigned char *yy_limit; int yy_state; zend_stack state_stack; diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index ef7111fafb5b4..8a27bd20f9494 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -26,7 +26,10 @@ # include #endif -#ifdef __SSE2__ +/* Prefer to use AVX2 instructions for better latency and throughput */ +#if defined(__AVX2__) +# include +#elif defined( __SSE2__) # include # include #endif @@ -118,7 +121,7 @@ static zend_always_inline uint32_t zend_hash_check_size(uint32_t nSize) /* size should be between HT_MIN_SIZE and HT_MAX_SIZE */ if (nSize <= HT_MIN_SIZE) { return HT_MIN_SIZE; - } else if (UNEXPECTED(nSize >= HT_MAX_SIZE)) { + } else if (UNEXPECTED(nSize > HT_MAX_SIZE)) { zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", nSize, sizeof(Bucket), sizeof(Bucket)); } @@ -166,6 +169,8 @@ static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht) void *data; uint32_t nSize = ht->nTableSize; + ZEND_ASSERT(HT_SIZE_TO_MASK(nSize)); + if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) { data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1); } else if (EXPECTED(nSize == HT_MIN_SIZE)) { @@ -174,7 +179,14 @@ static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht) HT_SET_DATA_ADDR(ht, data); /* Don't overwrite iterator count. */ ht->u.v.flags = HASH_FLAG_STATIC_KEYS; -#ifdef __SSE2__ +#if defined(__AVX2__) + do { + __m256i ymm0 = _mm256_setzero_si256(); + ymm0 = _mm256_cmpeq_epi64(ymm0, ymm0); + _mm256_storeu_si256((__m256i*)&HT_HASH_EX(data, 0), ymm0); + _mm256_storeu_si256((__m256i*)&HT_HASH_EX(data, 8), ymm0); + } while(0); +#elif defined (__SSE2__) do { __m128i xmm0 = _mm_setzero_si128(); xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); @@ -243,7 +255,7 @@ ZEND_API const HashTable zend_empty_array = { .nNumOfElements = 0, .nTableSize = HT_MIN_SIZE, .nInternalPointer = 0, - .nNextFreeElement = 0, + .nNextFreeElement = ZEND_LONG_MIN, .pDestructor = ZVAL_PTR_DTOR }; @@ -302,8 +314,9 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht) if (ht->nTableSize >= HT_MAX_SIZE) { zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%u * %zu + %zu)", ht->nTableSize * 2, sizeof(Bucket), sizeof(Bucket)); } - ht->nTableSize += ht->nTableSize; - HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); + uint32_t newTableSize = ht->nTableSize * 2; + HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(newTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); + ht->nTableSize = newTableSize; } ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, bool packed) @@ -338,9 +351,12 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht) uint32_t i; uint32_t nSize = ht->nTableSize; + ZEND_ASSERT(HT_SIZE_TO_MASK(nSize)); + HT_ASSERT_RC1(ht); - HT_FLAGS(ht) &= ~HASH_FLAG_PACKED; + // Alloc before assign to avoid inconsistencies on OOM new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + HT_FLAGS(ht) &= ~HASH_FLAG_PACKED; ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize); HT_SET_DATA_ADDR(ht, new_data); dst = ht->arData; @@ -380,7 +396,11 @@ ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht) ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed) { HT_ASSERT_RC1(ht); + if (nSize == 0) return; + + ZEND_ASSERT(HT_SIZE_TO_MASK(nSize)); + if (UNEXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED)) { if (nSize > ht->nTableSize) { ht->nTableSize = zend_hash_check_size(nSize); @@ -390,8 +410,9 @@ ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool if (packed) { ZEND_ASSERT(HT_IS_PACKED(ht)); if (nSize > ht->nTableSize) { - ht->nTableSize = zend_hash_check_size(nSize); - HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(ht->nTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); + uint32_t newTableSize = zend_hash_check_size(nSize); + HT_SET_DATA_ADDR(ht, perealloc2(HT_GET_DATA_ADDR(ht), HT_PACKED_SIZE_EX(newTableSize, HT_MIN_MASK), HT_PACKED_USED_SIZE(ht), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)); + ht->nTableSize = newTableSize; } } else { ZEND_ASSERT(!HT_IS_PACKED(ht)); @@ -399,8 +420,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool void *new_data, *old_data = HT_GET_DATA_ADDR(ht); Bucket *old_buckets = ht->arData; nSize = zend_hash_check_size(nSize); - ht->nTableSize = nSize; new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + ht->nTableSize = nSize; ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize); HT_SET_DATA_ADDR(ht, new_data); memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed); @@ -1227,8 +1248,10 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) uint32_t nSize = ht->nTableSize + ht->nTableSize; Bucket *old_buckets = ht->arData; - ht->nTableSize = nSize; + ZEND_ASSERT(HT_SIZE_TO_MASK(nSize)); + new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + ht->nTableSize = nSize; ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize); HT_SET_DATA_ADDR(ht, new_data); memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed); diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 93b9f0d4530a4..5726c8a919f43 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -298,7 +298,7 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t ZEND_API void ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort_func, bucket_compare_func_t compare_func, bool renumber); ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag); -static zend_always_inline void ZEND_FASTCALL zend_hash_sort(HashTable *ht, bucket_compare_func_t compare_func, zend_bool renumber) { +static zend_always_inline void ZEND_FASTCALL zend_hash_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber) { zend_hash_sort_ex(ht, zend_sort, compare_func, renumber); } @@ -1517,8 +1517,8 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, #define ZEND_HASH_FILL_GROW() do { \ if (UNEXPECTED(__fill_idx >= __fill_ht->nTableSize)) { \ + __fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \ __fill_ht->nNumUsed = __fill_idx; \ - __fill_ht->nNumOfElements = __fill_idx; \ __fill_ht->nNextFreeElement = __fill_idx; \ zend_hash_packed_grow(__fill_ht); \ __fill_val = __fill_ht->arPacked + __fill_idx; \ @@ -1557,8 +1557,8 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, } while (0) #define ZEND_HASH_FILL_FINISH() do { \ + __fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \ __fill_ht->nNumUsed = __fill_idx; \ - __fill_ht->nNumOfElements = __fill_idx; \ __fill_ht->nNextFreeElement = __fill_idx; \ __fill_ht->nInternalPointer = 0; \ } while (0) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 7257efa37995d..ff3a4d7080751 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -51,6 +51,9 @@ static void add_compatibility_obligation( static void add_property_compatibility_obligation( zend_class_entry *ce, const zend_property_info *child_prop, const zend_property_info *parent_prop); +static void add_class_constant_compatibility_obligation( + zend_class_entry *ce, const zend_class_constant *child_const, + const zend_class_constant *parent_const, const zend_string *const_name); static void ZEND_COLD emit_incompatible_method_error( const zend_function *child, zend_class_entry *child_scope, @@ -1359,6 +1362,29 @@ static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_en } /* }}} */ +static void emit_incompatible_class_constant_error( + const zend_class_constant *child, const zend_class_constant *parent, const zend_string *const_name) { + zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce); + zend_error_noreturn(E_COMPILE_ERROR, + "Type of %s::%s must be compatible with %s::%s of type %s", + ZSTR_VAL(child->ce->name), + ZSTR_VAL(const_name), + ZSTR_VAL(parent->ce->name), + ZSTR_VAL(const_name), + ZSTR_VAL(type_str)); +} + +static inheritance_status class_constant_types_compatible(const zend_class_constant *parent, const zend_class_constant *child) +{ + ZEND_ASSERT(ZEND_TYPE_IS_SET(parent->type)); + + if (!ZEND_TYPE_IS_SET(child->type)) { + return INHERITANCE_ERROR; + } + + return zend_perform_covariant_type_check(child->ce, child->type, parent->ce, parent->type); +} + static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */ { zval *zv = zend_hash_find_known_hash(&ce->constants_table, name); @@ -1366,9 +1392,14 @@ static void do_inherit_class_constant(zend_string *name, zend_class_constant *pa if (zv != NULL) { c = (zend_class_constant*)Z_PTR_P(zv); + if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PPP_MASK))) { zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in class %s)%s", - ZSTR_VAL(ce->name), ZSTR_VAL(name), zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_const)), ZSTR_VAL(parent_const->ce->name), (ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PUBLIC) ? "" : " or weaker"); + ZSTR_VAL(ce->name), ZSTR_VAL(name), + zend_visibility_string(ZEND_CLASS_CONST_FLAGS(parent_const)), + ZSTR_VAL(parent_const->ce->name), + (ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PUBLIC) ? "" : " or weaker" + ); } if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_FINAL))) { @@ -1377,6 +1408,15 @@ static void do_inherit_class_constant(zend_string *name, zend_class_constant *pa ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(parent_const->ce->name), ZSTR_VAL(name) ); } + + if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) && UNEXPECTED(ZEND_TYPE_IS_SET(parent_const->type))) { + inheritance_status status = class_constant_types_compatible(parent_const, c); + if (status == INHERITANCE_ERROR) { + emit_incompatible_class_constant_error(c, parent_const, name); + } else if (status == INHERITANCE_UNRESOLVED) { + add_class_constant_compatibility_obligation(ce, c, parent_const, name); + } + } } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) { if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) { ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; @@ -1385,6 +1425,7 @@ static void do_inherit_class_constant(zend_string *name, zend_class_constant *pa c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant)); memcpy(c, parent_const, sizeof(zend_class_constant)); parent_const = c; + Z_CONSTANT_FLAGS(c->value) |= CONST_OWNED; } } if (ce->type & ZEND_INTERNAL_CLASS) { @@ -1628,7 +1669,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } } - ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_USE_GUARDS | ZEND_ACC_NOT_SERIALIZABLE | ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES); + ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_HAS_READONLY_PROPS | ZEND_ACC_USE_GUARDS | ZEND_ACC_NOT_SERIALIZABLE | ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES); } /* }}} */ @@ -1640,12 +1681,18 @@ static zend_always_inline bool check_trait_property_or_constant_value_compatibil /* if any of the values is a constant, we try to resolve it */ if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) { ZVAL_COPY_OR_DUP(&op1_tmp, op1); - zval_update_constant_ex(&op1_tmp, ce); + if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) { + zval_ptr_dtor(&op1_tmp); + return false; + } op1 = &op1_tmp; } if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) { ZVAL_COPY_OR_DUP(&op2_tmp, op2); - zval_update_constant_ex(&op2_tmp, ce); + if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) { + zval_ptr_dtor(&op2_tmp); + return false; + } op2 = &op2_tmp; } @@ -2230,8 +2277,22 @@ static zend_class_entry* find_first_constant_definition(zend_class_entry *ce, ze } /* }}} */ -static bool do_trait_constant_check(zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait) /* {{{ */ -{ +static void emit_incompatible_trait_constant_error( + zend_class_entry *ce, zend_class_constant *existing_constant, zend_class_constant *trait_constant, zend_string *name, + zend_class_entry **traits, size_t current_trait +) { + zend_error_noreturn(E_COMPILE_ERROR, + "%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed", + ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name), + ZSTR_VAL(trait_constant->ce->name), + ZSTR_VAL(name), + ZSTR_VAL(ce->name) + ); +} + +static bool do_trait_constant_check( + zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait +) { uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL; zval *zv = zend_hash_find_known_hash(&ce->constants_table, name); @@ -2242,21 +2303,32 @@ static bool do_trait_constant_check(zend_class_entry *ce, zend_class_constant *t zend_class_constant *existing_constant = Z_PTR_P(zv); - if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask) || - !check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &existing_constant->value)) { + if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) { + emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait); + return false; + } + + if (ZEND_TYPE_IS_SET(trait_constant->type) != ZEND_TYPE_IS_SET(existing_constant->type)) { + emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait); + return false; + } else if (ZEND_TYPE_IS_SET(trait_constant->type)) { + inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type); + inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type); + if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) { + emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait); + return false; + } + } + + if (!check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &existing_constant->value)) { /* There is an existing constant of the same name, and it conflicts with the new one, so let's throw a fatal error */ - zend_error_noreturn(E_COMPILE_ERROR, - "%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed", - ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name), - ZSTR_VAL(trait_constant->ce->name), - ZSTR_VAL(name), - ZSTR_VAL(ce->name)); + emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait); + return false; } /* There is an existing constant which is compatible with the new one, so no need to add it */ return false; } -/* }}} */ static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */ { @@ -2376,7 +2448,9 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent ZSTR_VAL(prop_name), ZSTR_VAL(ce->name)); } - continue; + if (!(flags & ZEND_ACC_STATIC)) { + continue; + } } } @@ -2505,7 +2579,8 @@ typedef struct { enum { OBLIGATION_DEPENDENCY, OBLIGATION_COMPATIBILITY, - OBLIGATION_PROPERTY_COMPATIBILITY + OBLIGATION_PROPERTY_COMPATIBILITY, + OBLIGATION_CLASS_CONSTANT_COMPATIBILITY } type; union { zend_class_entry *dependency_ce; @@ -2521,6 +2596,11 @@ typedef struct { const zend_property_info *parent_prop; const zend_property_info *child_prop; }; + struct { + const zend_string *const_name; + const zend_class_constant *parent_const; + const zend_class_constant *child_const; + }; }; } variance_obligation; @@ -2596,6 +2676,18 @@ static void add_property_compatibility_obligation( zend_hash_next_index_insert_ptr(obligations, obligation); } +static void add_class_constant_compatibility_obligation( + zend_class_entry *ce, const zend_class_constant *child_const, + const zend_class_constant *parent_const, const zend_string *const_name) { + HashTable *obligations = get_or_init_obligations_for_class(ce); + variance_obligation *obligation = emalloc(sizeof(variance_obligation)); + obligation->type = OBLIGATION_CLASS_CONSTANT_COMPATIBILITY; + obligation->const_name = const_name; + obligation->child_const = child_const; + obligation->parent_const = parent_const; + zend_hash_next_index_insert_ptr(obligations, obligation); +} + static void resolve_delayed_variance_obligations(zend_class_entry *ce); static void check_variance_obligation(variance_obligation *obligation) { @@ -2619,13 +2711,19 @@ static void check_variance_obligation(variance_obligation *obligation) { &obligation->parent_fn, obligation->parent_scope, status); } /* Either the compatibility check was successful or only threw a warning. */ - } else { - ZEND_ASSERT(obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY); + } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) { inheritance_status status = property_types_compatible(obligation->parent_prop, obligation->child_prop); if (status != INHERITANCE_SUCCESS) { emit_incompatible_property_error(obligation->child_prop, obligation->parent_prop); } + } else { + ZEND_ASSERT(obligation->type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY); + inheritance_status status = + class_constant_types_compatible(obligation->parent_const, obligation->child_const); + if (status != INHERITANCE_SUCCESS) { + emit_incompatible_class_constant_error(obligation->child_const, obligation->parent_const, obligation->const_name); + } } } @@ -2681,7 +2779,7 @@ static void check_unrecoverable_load_failure(zend_class_entry *ce) { * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to * a fatal error, as would happen if we did not allow exceptions in the first place. */ if (CG(unlinked_uses) - && zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t)ce) == SUCCESS) { + && zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t)ce) == SUCCESS) { zend_exception_uncaught_error( "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name)); } @@ -2956,7 +3054,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string } if (CG(unlinked_uses)) { - zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t) ce); + zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce); } orig_linking_class = CG(current_linking_class); @@ -3004,7 +3102,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string } /* Normally Stringable is added during compilation. However, if it is imported from a trait, - * we need to explicilty add the interface here. */ + * we need to explicitly add the interface here. */ if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT) && !zend_class_implements_interface(ce, zend_ce_stringable)) { ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE); @@ -3089,6 +3187,7 @@ static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_e zend_string *key; zend_function *parent_func; zend_property_info *parent_info; + zend_class_constant *parent_const; inheritance_status overall_status = INHERITANCE_SUCCESS; ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) { @@ -3127,6 +3226,25 @@ static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_e } } ZEND_HASH_FOREACH_END(); + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) { + zval *zv; + if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) { + continue; + } + + zv = zend_hash_find_known_hash(&ce->constants_table, key); + if (zv) { + zend_class_constant *child_const = Z_PTR_P(zv); + if (ZEND_TYPE_IS_SET(child_const->type)) { + inheritance_status status = class_constant_types_compatible(parent_const, child_const); + ZEND_ASSERT(status != INHERITANCE_WARNING); + if (UNEXPECTED(status != INHERITANCE_SUCCESS)) { + return status; + } + } + } + } ZEND_HASH_FOREACH_END(); + return overall_status; } /* }}} */ diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 77fab940d664d..35f30eca2a864 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -63,7 +63,7 @@ static zend_result zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stag } if (stage == ZEND_INI_STAGE_RUNTIME && result == FAILURE) { /* runtime failure is OK */ - return 1; + return FAILURE; } if (ini_entry->value != ini_entry->orig_value) { zend_string_release(ini_entry->value); @@ -74,7 +74,7 @@ static zend_result zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stag ini_entry->orig_value = NULL; ini_entry->orig_modifiable = 0; } - return 0; + return SUCCESS; } /* }}} */ @@ -517,6 +517,46 @@ ZEND_API char *zend_ini_string(const char *name, size_t name_length, int orig) / } /* }}} */ + +ZEND_API zend_string *zend_ini_str_ex(const char *name, size_t name_length, bool orig, bool *exists) /* {{{ */ +{ + zend_ini_entry *ini_entry; + + ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name, name_length); + if (ini_entry) { + if (exists) { + *exists = 1; + } + + if (orig && ini_entry->modified) { + return ini_entry->orig_value ? ini_entry->orig_value : NULL; + } else { + return ini_entry->value ? ini_entry->value : NULL; + } + } else { + if (exists) { + *exists = 0; + } + return NULL; + } +} +/* }}} */ + +ZEND_API zend_string *zend_ini_str(const char *name, size_t name_length, bool orig) /* {{{ */ +{ + bool exists = 1; + zend_string *return_value; + + return_value = zend_ini_str_ex(name, name_length, orig, &exists); + if (!exists) { + return NULL; + } else if (!return_value) { + return_value = ZSTR_EMPTY_ALLOC(); + } + return return_value; +} +/* }}} */ + ZEND_API zend_string *zend_ini_get_value(zend_string *name) /* {{{ */ { zend_ini_entry *ini_entry; diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h index 56939fa9ea8cb..6ca5658e970d3 100644 --- a/Zend/zend_ini.h +++ b/Zend/zend_ini.h @@ -87,6 +87,8 @@ ZEND_API zend_long zend_ini_long(const char *name, size_t name_length, int orig) ZEND_API double zend_ini_double(const char *name, size_t name_length, int orig); ZEND_API char *zend_ini_string(const char *name, size_t name_length, int orig); ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, int orig, bool *exists); +ZEND_API zend_string *zend_ini_str(const char *name, size_t name_length, bool orig); +ZEND_API zend_string *zend_ini_str_ex(const char *name, size_t name_length, bool orig, bool *exists); ZEND_API zend_string *zend_ini_get_value(zend_string *name); ZEND_API bool zend_ini_parse_bool(zend_string *str); @@ -232,8 +234,8 @@ END_EXTERN_C() /* INI parsing engine */ typedef void (*zend_ini_parser_cb_t)(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg); BEGIN_EXTERN_C() -ZEND_API int zend_parse_ini_file(zend_file_handle *fh, bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg); -ZEND_API int zend_parse_ini_string(char *str, bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg); +ZEND_API zend_result zend_parse_ini_file(zend_file_handle *fh, bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg); +ZEND_API zend_result zend_parse_ini_string(const char *str, bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg); END_EXTERN_C() /* INI entries */ diff --git a/Zend/zend_ini_parser.y b/Zend/zend_ini_parser.y index 2d4e949d5c475..1699fddd6e753 100644 --- a/Zend/zend_ini_parser.y +++ b/Zend/zend_ini_parser.y @@ -43,6 +43,7 @@ int ini_parse(void); #endif #define ZEND_SYSTEM_INI CG(ini_parser_unbuffered_errors) +#define INI_ZVAL_IS_NUMBER 1 static int get_int_val(zval *op) { switch (Z_TYPE_P(op)) { @@ -92,8 +93,12 @@ static void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2) break; } - str_len = sprintf(str_result, "%d", i_result); - ZVAL_NEW_STR(result, zend_string_init(str_result, str_len, ZEND_SYSTEM_INI)); + if (INI_SCNG(scanner_mode) != ZEND_INI_SCANNER_TYPED) { + str_len = sprintf(str_result, "%d", i_result); + ZVAL_NEW_STR(result, zend_string_init(str_result, str_len, ZEND_SYSTEM_INI)); + } else { + ZVAL_LONG(result, i_result); + } } /* }}} */ @@ -105,6 +110,7 @@ static void zend_ini_init_string(zval *result) } else { ZVAL_EMPTY_STRING(result); } + Z_EXTRA_P(result) = 0; } /* }}} */ @@ -187,9 +193,8 @@ static ZEND_COLD void ini_error(const char *msg) { char *error_buf; int error_buf_len; - char *currently_parsed_filename; - currently_parsed_filename = zend_ini_scanner_get_filename(); + const char *const currently_parsed_filename = zend_ini_scanner_get_filename(); if (currently_parsed_filename) { error_buf_len = 128 + (int)strlen(msg) + (int)strlen(currently_parsed_filename); /* should be more than enough */ error_buf = (char *) emalloc(error_buf_len); @@ -239,7 +244,7 @@ ZEND_API zend_result zend_parse_ini_file(zend_file_handle *fh, bool unbuffered_e /* }}} */ /* {{{ zend_parse_ini_string() */ -ZEND_API zend_result zend_parse_ini_string(char *str, bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg) +ZEND_API zend_result zend_parse_ini_string(const char *str, bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg) { int retval; zend_ini_parser_param ini_parser_param; @@ -277,6 +282,42 @@ static void zval_ini_dtor(zval *zv) } /* }}} */ +static inline zend_result convert_to_number(zval *retval, const char *str, const int str_len) +{ + uint8_t type; + int overflow; + zend_long lval; + double dval; + + if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow, NULL)) != 0) { + if (type == IS_LONG) { + ZVAL_LONG(retval, lval); + return SUCCESS; + } else if (type == IS_DOUBLE && !overflow) { + ZVAL_DOUBLE(retval, dval); + return SUCCESS; + } + } + + return FAILURE; +} + +static void normalize_value(zval *zv) +{ + if (INI_SCNG(scanner_mode) != ZEND_INI_SCANNER_TYPED) { + return; + } + + ZEND_ASSERT(Z_EXTRA_P(zv) == 0 || Z_EXTRA_P(zv) == INI_ZVAL_IS_NUMBER); + if (Z_EXTRA_P(zv) == INI_ZVAL_IS_NUMBER && Z_TYPE_P(zv) == IS_STRING) { + zval number_rv; + if (convert_to_number(&number_rv, Z_STRVAL_P(zv), Z_STRLEN_P(zv)) == SUCCESS) { + zval_ptr_dtor(zv); + ZVAL_COPY_VALUE(zv, &number_rv); + } + } +} + %} %expect 0 @@ -352,7 +393,7 @@ section_string_or_value: ; string_or_value: - expr { $$ = $1; } + expr { $$ = $1; normalize_value(&$$); } | BOOL_TRUE { $$ = $1; } | BOOL_FALSE { $$ = $1; } | NULL_NULL { $$ = $1; } @@ -413,7 +454,11 @@ constant_literal: constant_string: TC_CONSTANT { zend_ini_get_constant(&$$, &$1); } | TC_RAW { $$ = $1; /*printf("TC_RAW: '%s'\n", Z_STRVAL($1));*/ } - | TC_NUMBER { $$ = $1; /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ } + | TC_NUMBER { + $$ = $1; + Z_EXTRA($$) = INI_ZVAL_IS_NUMBER; + /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ + } | TC_STRING { $$ = $1; /*printf("TC_STRING: '%s'\n", Z_STRVAL($1));*/ } | TC_WHITESPACE { $$ = $1; /*printf("TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ } ; diff --git a/Zend/zend_ini_scanner.h b/Zend/zend_ini_scanner.h index f3d7f1a82b271..f0cfac2e7affe 100644 --- a/Zend/zend_ini_scanner.h +++ b/Zend/zend_ini_scanner.h @@ -27,9 +27,9 @@ BEGIN_EXTERN_C() ZEND_COLD int zend_ini_scanner_get_lineno(void); -ZEND_COLD char *zend_ini_scanner_get_filename(void); +ZEND_COLD const char *zend_ini_scanner_get_filename(void); zend_result zend_ini_open_file_for_scanning(zend_file_handle *fh, int scanner_mode); -zend_result zend_ini_prepare_string_for_scanning(char *str, int scanner_mode); +zend_result zend_ini_prepare_string_for_scanning(const char *str, int scanner_mode); int ini_lex(zval *ini_lval); void shutdown_ini_scanner(void); END_EXTERN_C() diff --git a/Zend/zend_ini_scanner.l b/Zend/zend_ini_scanner.l index 474580ba3af96..3c4a22ad35941 100644 --- a/Zend/zend_ini_scanner.l +++ b/Zend/zend_ini_scanner.l @@ -55,9 +55,9 @@ /* emulate flex constructs */ #define BEGIN(state) YYSETCONDITION(STATE(state)) #define YYSTATE YYGETCONDITION() -#define yytext ((char*)SCNG(yy_text)) +#define yytext ((const char*)SCNG(yy_text)) #define yyleng SCNG(yy_leng) -#define yyless(x) do { YYCURSOR = (unsigned char*)yytext + x; \ +#define yyless(x) do { YYCURSOR = (const unsigned char*)yytext + x; \ yyleng = (unsigned int)x; } while(0) /* #define yymore() goto yymore_restart */ @@ -145,32 +145,13 @@ ZEND_API zend_ini_scanner_globals ini_scanner_globals; if (SCNG(scanner_mode) == ZEND_INI_SCANNER_TYPED && \ (YYSTATE == STATE(ST_VALUE) || YYSTATE == STATE(ST_RAW))) {\ zend_ini_copy_typed_value(ini_lval, type, str, len); \ + Z_EXTRA_P(ini_lval) = 0; \ } else { \ zend_ini_copy_value(ini_lval, str, len); \ } \ return type; \ } -static inline zend_result convert_to_number(zval *retval, const char *str, const int str_len) -{ - zend_uchar type; - int overflow; - zend_long lval; - double dval; - - if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow, NULL)) != 0) { - if (type == IS_LONG) { - ZVAL_LONG(retval, lval); - return SUCCESS; - } else if (type == IS_DOUBLE && !overflow) { - ZVAL_DOUBLE(retval, dval); - return SUCCESS; - } - } - - return FAILURE; -} - static void zend_ini_copy_typed_value(zval *retval, const int type, const char *str, int len) { switch (type) { @@ -183,11 +164,6 @@ static void zend_ini_copy_typed_value(zval *retval, const int type, const char * ZVAL_NULL(retval); break; - case TC_NUMBER: - if (convert_to_number(retval, str, len) == SUCCESS) { - break; - } - ZEND_FALLTHROUGH; default: zend_ini_copy_value(retval, str, len); } @@ -208,9 +184,9 @@ static void yy_pop_state(void) zend_stack_del_top(&SCNG(state_stack)); } -static void yy_scan_buffer(char *str, unsigned int len) +static void yy_scan_buffer(const char *str, unsigned int len) { - YYCURSOR = (YYCTYPE*)str; + YYCURSOR = (const YYCTYPE*)str; SCNG(yy_start) = YYCURSOR; YYLIMIT = YYCURSOR + len; } @@ -261,7 +237,7 @@ ZEND_COLD int zend_ini_scanner_get_lineno(void) /* }}} */ /* {{{ zend_ini_scanner_get_filename() */ -ZEND_COLD char *zend_ini_scanner_get_filename(void) +ZEND_COLD const char *zend_ini_scanner_get_filename(void) { return ini_filename ? ZSTR_VAL(ini_filename) : "Unknown"; } @@ -288,7 +264,7 @@ zend_result zend_ini_open_file_for_scanning(zend_file_handle *fh, int scanner_mo /* }}} */ /* {{{ zend_ini_prepare_string_for_scanning() */ -zend_result zend_ini_prepare_string_for_scanning(char *str, int scanner_mode) +zend_result zend_ini_prepare_string_for_scanning(const char *str, int scanner_mode) { int len = (int)strlen(str); @@ -303,7 +279,7 @@ zend_result zend_ini_prepare_string_for_scanning(char *str, int scanner_mode) /* }}} */ /* {{{ zend_ini_escape_string() */ -static void zend_ini_escape_string(zval *lval, char *str, int len, char quote_type) +static void zend_ini_escape_string(zval *lval, const char *str, int len, char quote_type) { char *s, *t; char *end; @@ -493,7 +469,7 @@ SECTION_VALUE_CHARS ([^$\n\r;"'\]\\]|("\\"{ANY_CHAR})|{LITERAL_DOLLAR}) } {RAW_VALUE_CHARS} { /* Raw value, only used when SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW. */ - unsigned char *sc = NULL; + const unsigned char *sc = NULL; EAT_LEADING_WHITESPACE(); while (YYCURSOR < YYLIMIT) { switch (*YYCURSOR) { @@ -591,7 +567,7 @@ end_raw_value_chars: return 0; } - unsigned char *s = SCNG(yy_text); + const unsigned char *s = SCNG(yy_text); while (s < YYLIMIT) { switch (*s++) { @@ -623,6 +599,7 @@ end_raw_value_chars: yyleng = YYCURSOR - SCNG(yy_text); zend_ini_escape_string(ini_lval, yytext, yyleng, '"'); + Z_EXTRA_P(ini_lval) = 0; return TC_QUOTED_STRING; } diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index d05310b737b01..5d2f7d0ffc4a9 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -118,7 +118,7 @@ static void zend_user_it_dtor(zend_object_iterator *_iter) /* }}} */ /* {{{ zend_user_it_valid */ -ZEND_API int zend_user_it_valid(zend_object_iterator *_iter) +ZEND_API zend_result zend_user_it_valid(zend_object_iterator *_iter) { if (_iter) { zend_user_iterator *iter = (zend_user_iterator*)_iter; @@ -198,7 +198,8 @@ ZEND_API HashTable *zend_user_it_get_gc(zend_object_iterator *_iter, zval **tabl static const zend_object_iterator_funcs zend_interface_iterator_funcs_iterator = { zend_user_it_dtor, - zend_user_it_valid, + // FIXME: Adjust the actual function prototype in zend_object_iterator_funcs + (int (*)(zend_object_iterator *)) zend_user_it_valid, zend_user_it_get_current_data, zend_user_it_get_current_key, zend_user_it_move_forward, diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 6e7b09365b112..9b663887264f0 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -267,7 +267,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type echo_expr_list unset_variables catch_name_list catch_list optional_variable parameter_list class_statement_list %type implements_list case_list if_stmt_without_else %type non_empty_parameter_list argument_list non_empty_argument_list property_list -%type class_const_list class_const_decl class_name_list trait_adaptations method_body non_empty_for_exprs +%type class_const_list first_class_const_decl class_const_decl class_name_list trait_adaptations method_body non_empty_for_exprs %type ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars %type lexical_var_list encaps_list %type array_pair non_empty_array_pair_list array_pair_list possible_array_pair @@ -282,7 +282,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type returns_ref function fn is_reference is_variadic property_modifiers %type method_modifiers class_const_modifiers member_modifier optional_cpp_modifiers -%type class_modifiers class_modifier use_type backup_fn_flags +%type class_modifiers class_modifier anonymous_class_modifiers anonymous_class_modifiers_optional use_type backup_fn_flags %type backup_lex_pos %type backup_doc_comment @@ -601,6 +601,18 @@ class_modifiers: { $$ = zend_add_class_modifier($1, $2); if (!$$) { YYERROR; } } ; +anonymous_class_modifiers: + class_modifier + { $$ = zend_add_anonymous_class_modifier(0, $1); if (!$$) { YYERROR; } } + | anonymous_class_modifiers class_modifier + { $$ = zend_add_anonymous_class_modifier($1, $2); if (!$$) { YYERROR; } } +; + +anonymous_class_modifiers_optional: + %empty { $$ = 0; } + | anonymous_class_modifiers { $$ = $1; } +; + class_modifier: T_ABSTRACT { $$ = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } | T_FINAL { $$ = ZEND_ACC_FINAL; } @@ -800,7 +812,6 @@ parameter: NULL, $6 ? zend_ast_create_zval_from_str($6) : NULL); } ; - optional_type_without_static: %empty { $$ = NULL; } | type_expr_without_static { $$ = $1; } @@ -1065,15 +1076,21 @@ property: class_const_list: class_const_list ',' class_const_decl { $$ = zend_ast_list_add($1, $3); } - | class_const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); } + | first_class_const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); } +; + +first_class_const_decl: + T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } + | semi_reserved '=' expr backup_doc_comment { zval zv; if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; } $$ = zend_ast_create(ZEND_AST_CONST_ELEM, zend_ast_create_zval(&zv), $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } + | type_expr identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $2, $4, ($5 ? zend_ast_create_zval_from_str($5) : NULL), $1); } ; class_const_decl: - identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); } + identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } ; const_decl: - T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); } + T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } ; echo_expr_list: @@ -1095,12 +1112,12 @@ non_empty_for_exprs: ; anonymous_class: - T_CLASS { $$ = CG(zend_lineno); } ctor_arguments + anonymous_class_modifiers_optional T_CLASS { $$ = CG(zend_lineno); } ctor_arguments extends_from implements_list backup_doc_comment '{' class_statement_list '}' { zend_ast *decl = zend_ast_create_decl( - ZEND_AST_CLASS, ZEND_ACC_ANON_CLASS, $2, $6, NULL, - $4, $5, $8, NULL, NULL); - $$ = zend_ast_create(ZEND_AST_NEW, decl, $3); + ZEND_AST_CLASS, ZEND_ACC_ANON_CLASS | $1, $3, $7, NULL, + $5, $6, $9, NULL, NULL); + $$ = zend_ast_create(ZEND_AST_NEW, decl, $4); } ; @@ -1244,13 +1261,12 @@ inline_function: function returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars return_type backup_fn_flags '{' inner_statement_list '}' backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $2 | $13, $1, $3, - zend_string_init("{closure}", sizeof("{closure}") - 1, 0), + ZSTR_INIT_LITERAL("{closure}", 0), $5, $7, $11, $8, NULL); CG(extra_fn_flags) = $9; } | fn returns_ref backup_doc_comment '(' parameter_list ')' return_type T_DOUBLE_ARROW backup_fn_flags backup_lex_pos expr backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_ARROW_FUNC, $2 | $12, $1, $3, - zend_string_init("{closure}", sizeof("{closure}") - 1, 0), $5, NULL, $11, $7, NULL); - ((zend_ast_decl *) $$)->lex_pos = $10; + ZSTR_INIT_LITERAL("{closure}", 0), $5, NULL, $11, $7, NULL); CG(extra_fn_flags) = $9; } ; @@ -1306,8 +1322,8 @@ function_call: { $$ = zend_ast_create(ZEND_AST_STATIC_CALL, $1, $3, $4); } | variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list { $$ = zend_ast_create(ZEND_AST_STATIC_CALL, $1, $3, $4); } - | callable_expr { $$ = CG(zend_lineno); } argument_list { - $$ = zend_ast_create(ZEND_AST_CALL, $1, $3); + | callable_expr { $$ = CG(zend_lineno); } argument_list { + $$ = zend_ast_create(ZEND_AST_CALL, $1, $3); $$->lineno = $2; } ; @@ -1380,6 +1396,10 @@ class_constant: { $$ = zend_ast_create_class_const_or_name($1, $3); } | variable_class_name T_PAAMAYIM_NEKUDOTAYIM identifier { $$ = zend_ast_create_class_const_or_name($1, $3); } + | class_name T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' + { $$ = zend_ast_create(ZEND_AST_CLASS_CONST, $1, $4); } + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' + { $$ = zend_ast_create(ZEND_AST_CLASS_CONST, $1, $4); } ; optional_expr: diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index c73a50948d6bc..054ed7bdc1ef6 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1329,7 +1329,7 @@ static zend_result check_nesting_at_end(void) } while (0) #define RETURN_EXIT_NESTING_TOKEN(_token) do { \ - if (exit_nesting(_token) && PARSER_MODE()) { \ + if (exit_nesting(_token) != SUCCESS && PARSER_MODE()) { \ RETURN_TOKEN(T_ERROR); \ } else { \ RETURN_TOKEN(_token); \ @@ -1337,7 +1337,7 @@ static zend_result check_nesting_at_end(void) } while(0) #define RETURN_END_TOKEN do { \ - if (check_nesting_at_end() && PARSER_MODE()) { \ + if (check_nesting_at_end() != SUCCESS && PARSER_MODE()) { \ RETURN_TOKEN(T_ERROR); \ } else { \ RETURN_TOKEN(END); \ @@ -1368,6 +1368,16 @@ TABS_AND_SPACES [ \t]* TOKENS [;:,.|^&+-/*=%!~$<>?@] ANY_CHAR [^] NEWLINE ("\r"|"\n"|"\r\n") +OPTIONAL_WHITESPACE [ \n\r\t]* +/* We don't use re2c with bounds checking, we just return 0 bytes if we read past the input. + * If we use wildcard matching for comments, we can read past the input, which crashes + * once we try to report a syntax error because the 0 bytes are not actually part of + * the token. We prevent this by not allowing 0 bytes, which already aren't valid anyway. */ +MULTI_LINE_COMMENT "/*"([^*\x00]*"*"+)([^*/\x00][^*\x00]*"*"+)*"/" +SINGLE_LINE_COMMENT "//"[^\x00\n\r]*[\n\r] +HASH_COMMENT "#"(([^[\x00][^\x00\n\r]*[\n\r])|[\n\r]) +WHITESPACE_OR_COMMENTS ({WHITESPACE}|{MULTI_LINE_COMMENT}|{SINGLE_LINE_COMMENT}|{HASH_COMMENT})+ +OPTIONAL_WHITESPACE_OR_COMMENTS ({WHITESPACE}|{MULTI_LINE_COMMENT}|{SINGLE_LINE_COMMENT}|{HASH_COMMENT})* /* compute yyleng before each rule */ := yyleng = YYCURSOR - SCNG(yy_text); @@ -1401,7 +1411,7 @@ NEWLINE ("\r"|"\n"|"\r\n") RETURN_TOKEN(T_ATTRIBUTE); } -"yield"{WHITESPACE}"from"[^a-zA-Z0-9_\x80-\xff] { +"yield"{WHITESPACE_OR_COMMENTS}"from"[^a-zA-Z0-9_\x80-\xff] { yyless(yyleng - 1); HANDLE_NEWLINES(yytext, yyleng); RETURN_TOKEN_WITH_IDENT(T_YIELD_FROM); @@ -1543,11 +1553,11 @@ NEWLINE ("\r"|"\n"|"\r\n") * The enum keyword must be followed by whitespace and another identifier. * This avoids the BC break of using enum in classes, namespaces, functions and constants. */ -"enum"{WHITESPACE}("extends"|"implements") { +"enum"{WHITESPACE_OR_COMMENTS}("extends"|"implements") { yyless(4); RETURN_TOKEN_WITH_STR(T_STRING, 0); } -"enum"{WHITESPACE}[a-zA-Z_\x80-\xff] { +"enum"{WHITESPACE_OR_COMMENTS}[a-zA-Z_\x80-\xff] { yyless(4); RETURN_TOKEN_WITH_IDENT(T_ENUM); } @@ -1869,7 +1879,7 @@ NEWLINE ("\r"|"\n"|"\r\n") RETURN_TOKEN(T_SR); } -"&"[ \t\r\n]*("$"|"...") { +"&"{OPTIONAL_WHITESPACE_OR_COMMENTS}("$"|"...") { yyless(1); RETURN_TOKEN(T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG); } diff --git a/Zend/zend_list.h b/Zend/zend_list.h index 680915121e2a6..55ccf78dca106 100644 --- a/Zend/zend_list.h +++ b/Zend/zend_list.h @@ -54,7 +54,7 @@ void zend_destroy_rsrc_list_dtors(void); ZEND_API zval* ZEND_FASTCALL zend_list_insert(void *ptr, int type); ZEND_API void ZEND_FASTCALL zend_list_free(zend_resource *res); -ZEND_API int ZEND_FASTCALL zend_list_delete(zend_resource *res); +ZEND_API zend_result ZEND_FASTCALL zend_list_delete(zend_resource *res); ZEND_API void ZEND_FASTCALL zend_list_close(zend_resource *res); ZEND_API zend_resource *zend_register_resource(void *rsrc_pointer, int rsrc_type); diff --git a/Zend/zend_max_execution_timer.c b/Zend/zend_max_execution_timer.c new file mode 100644 index 0000000000000..b1c83e9cbb3a6 --- /dev/null +++ b/Zend/zend_max_execution_timer.c @@ -0,0 +1,103 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Kévin Dunglas | + +----------------------------------------------------------------------+ + */ + +#ifdef ZEND_MAX_EXECUTION_TIMERS + +#include +#include +#include +#include +#include +#include +#include + +#include "zend.h" +#include "zend_globals.h" + +// Musl Libc defines this macro, glibc does not +// According to "man 2 timer_create" this field should always be available, but it's not: https://sourceware.org/bugzilla/show_bug.cgi?id=27417 +# ifndef sigev_notify_thread_id +# define sigev_notify_thread_id _sigev_un._tid +# endif + +ZEND_API void zend_max_execution_timer_init(void) /* {{{ */ +{ + struct sigevent sev; + sev.sigev_notify = SIGEV_THREAD_ID; + sev.sigev_value.sival_ptr = &EG(max_execution_timer_timer); + 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"); + } + +# 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 + + sigaction(sev.sigev_signo, NULL, &EG(oldact)); +} +/* }}} */ + +void zend_max_execution_timer_settime(zend_long seconds) /* {{{ }*/ +{ + /* Timer not initialized or shutdown. */ + if (!EG(pid)) { + return; + } + + timer_t timer = EG(max_execution_timer_timer); + + struct itimerspec its; + its.it_value.tv_sec = seconds; + its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; + +# ifdef MAX_EXECUTION_TIMERS_DEBUG + fprintf(stderr, "Setting timer %#jx on thread %d (%ld seconds)...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); +# endif + + if (timer_settime(timer, 0, &its, NULL) != 0) { + zend_strerror_noreturn(E_ERROR, errno, "Could not set timer"); + } +} +/* }}} */ + +void zend_max_execution_timer_shutdown(void) /* {{{ */ +{ + /* Don't try to delete a timer created before a call to fork() */ + if (EG(pid) != getpid()) { + return; + } + + EG(pid) = 0; + + timer_t timer = EG(max_execution_timer_timer); + +# ifdef MAX_EXECUTION_TIMERS_DEBUG + fprintf(stderr, "Deleting timer %#jx on thread %d...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); +# endif + + int err = timer_delete(timer); + if (err != 0) { + zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); + } +} +/* }}}} */ + +#endif diff --git a/ext/opcache/jit/zend_jit_oprofile.c b/Zend/zend_max_execution_timer.h similarity index 50% rename from ext/opcache/jit/zend_jit_oprofile.c rename to Zend/zend_max_execution_timer.h index a83b8056e0336..789f50e6b7dcd 100644 --- a/ext/opcache/jit/zend_jit_oprofile.c +++ b/Zend/zend_max_execution_timer.h @@ -1,6 +1,4 @@ /* - +----------------------------------------------------------------------+ - | Zend JIT | +----------------------------------------------------------------------+ | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ @@ -12,39 +10,27 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Authors: Dmitry Stogov | + | Author: Kévin Dunglas | +----------------------------------------------------------------------+ -*/ + */ + +#ifndef ZEND_MAX_EXECUTION_TIMER_H +#define ZEND_MAX_EXECUTION_TIMER_H -#define HAVE_OPROFILE 1 +# ifdef ZEND_MAX_EXECUTION_TIMERS -#include +#include "zend_long.h" -static op_agent_t op_agent = NULL; +/* Must be called after calls to fork() */ +ZEND_API void zend_max_execution_timer_init(void); +void zend_max_execution_timer_settime(zend_long seconds); +void zend_max_execution_timer_shutdown(void); -static void zend_jit_oprofile_register(const char *name, - const void *start, - size_t size) -{ - if (op_agent) { - op_write_native_code(op_agent, name, (uint64_t)(zend_uintptr_t)start, start, size); - } -} +# else -static int zend_jit_oprofile_startup(void) -{ - op_agent = op_open_agent(); - if (!op_agent) { - fprintf(stderr, "OpAgent initialization failed [%d]!\n", errno); - return 0; - } - return 1; -} +#define zend_max_execution_timer_init() +#define zend_max_execution_timer_settime(seconds) +#define zend_max_execution_timer_shutdown() -static void zend_jit_oprofile_shutdown(void) -{ - if (op_agent) { -//??? sleep(60); - op_close_agent(op_agent); - } -} +# endif +#endif diff --git a/Zend/zend_multibyte.h b/Zend/zend_multibyte.h index 5466840cd900a..b00d57e2f0b22 100644 --- a/Zend/zend_multibyte.h +++ b/Zend/zend_multibyte.h @@ -66,12 +66,12 @@ ZEND_API const char *zend_multibyte_get_encoding_name(const zend_encoding *encod ZEND_API int zend_multibyte_check_lexer_compatibility(const zend_encoding *encoding); ZEND_API const zend_encoding *zend_multibyte_encoding_detector(const unsigned char *string, size_t length, const zend_encoding **list, size_t list_size); ZEND_API size_t zend_multibyte_encoding_converter(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length, const zend_encoding *encoding_to, const zend_encoding *encoding_from); -ZEND_API int zend_multibyte_parse_encoding_list(const char *encoding_list, size_t encoding_list_len, const zend_encoding ***return_list, size_t *return_size, bool persistent); +ZEND_API zend_result zend_multibyte_parse_encoding_list(const char *encoding_list, size_t encoding_list_len, const zend_encoding ***return_list, size_t *return_size, bool persistent); ZEND_API const zend_encoding *zend_multibyte_get_internal_encoding(void); ZEND_API const zend_encoding *zend_multibyte_get_script_encoding(void); ZEND_API int zend_multibyte_set_script_encoding(const zend_encoding **encoding_list, size_t encoding_list_size); -ZEND_API int zend_multibyte_set_internal_encoding(const zend_encoding *encoding); +ZEND_API zend_result zend_multibyte_set_internal_encoding(const zend_encoding *encoding); ZEND_API zend_result zend_multibyte_set_script_encoding_by_string(const char *new_value, size_t new_value_length); END_EXTERN_C() diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index d767e83997852..b18d0f46f80a6 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -223,7 +223,7 @@ static void zend_std_call_issetter(zend_object *zobj, zend_string *prop_name, zv /* }}} */ -static zend_always_inline bool is_derived_class(zend_class_entry *child_class, zend_class_entry *parent_class) /* {{{ */ +static zend_always_inline bool is_derived_class(const zend_class_entry *child_class, const zend_class_entry *parent_class) /* {{{ */ { child_class = child_class->parent; while (child_class) { @@ -237,14 +237,14 @@ static zend_always_inline bool is_derived_class(zend_class_entry *child_class, z } /* }}} */ -static zend_never_inline int is_protected_compatible_scope(zend_class_entry *ce, zend_class_entry *scope) /* {{{ */ +static zend_never_inline int is_protected_compatible_scope(const zend_class_entry *ce, const zend_class_entry *scope) /* {{{ */ { return scope && (is_derived_class(ce, scope) || is_derived_class(scope, ce)); } /* }}} */ -static zend_never_inline zend_property_info *zend_get_parent_private_property(zend_class_entry *scope, zend_class_entry *ce, zend_string *member) /* {{{ */ +static zend_never_inline zend_property_info *zend_get_parent_private_property(zend_class_entry *scope, const zend_class_entry *ce, zend_string *member) /* {{{ */ { zval *zv; zend_property_info *prop_info; @@ -263,7 +263,7 @@ static zend_never_inline zend_property_info *zend_get_parent_private_property(ze } /* }}} */ -static ZEND_COLD zend_never_inline void zend_bad_property_access(zend_property_info *property_info, zend_class_entry *ce, zend_string *member) /* {{{ */ +static ZEND_COLD zend_never_inline void zend_bad_property_access(const zend_property_info *property_info, const zend_class_entry *ce, const zend_string *member) /* {{{ */ { zend_throw_error(NULL, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ZSTR_VAL(ce->name), ZSTR_VAL(member)); } @@ -276,13 +276,13 @@ static ZEND_COLD zend_never_inline void zend_bad_property_name(void) /* {{{ */ /* }}} */ static ZEND_COLD zend_never_inline void zend_forbidden_dynamic_property( - zend_class_entry *ce, zend_string *member) { + const zend_class_entry *ce, const zend_string *member) { zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(member)); } static ZEND_COLD zend_never_inline bool zend_deprecated_dynamic_property( - zend_object *obj, zend_string *member) { + zend_object *obj, const zend_string *member) { GC_ADDREF(obj); zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", ZSTR_VAL(obj->ce->name), ZSTR_VAL(member)); @@ -300,7 +300,7 @@ static ZEND_COLD zend_never_inline bool zend_deprecated_dynamic_property( } static ZEND_COLD zend_never_inline void zend_readonly_property_modification_scope_error( - zend_class_entry *ce, zend_string *member, zend_class_entry *scope, const char *operation) { + const zend_class_entry *ce, const zend_string *member, const zend_class_entry *scope, const char *operation) { zend_throw_error(NULL, "Cannot %s readonly property %s::$%s from %s%s", operation, ZSTR_VAL(ce->name), ZSTR_VAL(member), scope ? "scope " : "global scope", scope ? ZSTR_VAL(scope->name) : ""); @@ -312,7 +312,7 @@ static ZEND_COLD zend_never_inline void zend_readonly_property_unset_error( ZSTR_VAL(ce->name), ZSTR_VAL(member)); } -static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *ce, zend_string *member, int silent, void **cache_slot, zend_property_info **info_ptr) /* {{{ */ +static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *ce, zend_string *member, int silent, void **cache_slot, const zend_property_info **info_ptr) /* {{{ */ { zval *zv; zend_property_info *property_info; @@ -411,14 +411,14 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c static ZEND_COLD void zend_wrong_offset(zend_class_entry *ce, zend_string *member) /* {{{ */ { - zend_property_info *dummy; + const zend_property_info *dummy; /* Trigger the correct error */ zend_get_property_offset(ce, member, 0, NULL, &dummy); } /* }}} */ -ZEND_API zend_property_info *zend_get_property_info(zend_class_entry *ce, zend_string *member, int silent) /* {{{ */ +ZEND_API zend_property_info *zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent) /* {{{ */ { zval *zv; zend_property_info *property_info; @@ -488,7 +488,7 @@ ZEND_API zend_property_info *zend_get_property_info(zend_class_entry *ce, zend_s } /* }}} */ -ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_info_name, bool is_dynamic) /* {{{ */ +ZEND_API zend_result zend_check_property_access(const zend_object *zobj, zend_string *prop_info_name, bool is_dynamic) /* {{{ */ { zend_property_info *property_info; const char *class_name = NULL; @@ -536,7 +536,7 @@ ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_inf static void zend_property_guard_dtor(zval *el) /* {{{ */ { uint32_t *ptr = (uint32_t*)Z_PTR_P(el); - if (EXPECTED(!(((zend_uintptr_t)ptr) & 1))) { + if (EXPECTED(!(((uintptr_t)ptr) & 1))) { efree_size(ptr, sizeof(uint32_t)); } } @@ -553,9 +553,8 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) { zend_string *str = Z_STR_P(zv); if (EXPECTED(str == member) || - /* "str" always has a pre-calculated hash value here */ - (EXPECTED(ZSTR_H(str) == zend_string_hash_val(member)) && - EXPECTED(zend_string_equal_content(str, member)))) { + /* str and member don't necessarily have a pre-calculated hash value here */ + EXPECTED(zend_string_equal_content(str, member))) { return &Z_PROPERTY_GUARD_P(zv); } else if (EXPECTED(Z_PROPERTY_GUARD_P(zv) == 0)) { zval_ptr_dtor_str(zv); @@ -566,7 +565,7 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0); /* mark pointer as "special" using low bit */ zend_hash_add_new_ptr(guards, str, - (void*)(((zend_uintptr_t)&Z_PROPERTY_GUARD_P(zv)) | 1)); + (void*)(((uintptr_t)&Z_PROPERTY_GUARD_P(zv)) | 1)); zval_ptr_dtor_str(zv); ZVAL_ARR(zv, guards); } @@ -575,7 +574,7 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe ZEND_ASSERT(guards != NULL); zv = zend_hash_find(guards, member); if (zv != NULL) { - return (uint32_t*)(((zend_uintptr_t)Z_PTR_P(zv)) & ~1); + return (uint32_t*)(((uintptr_t)Z_PTR_P(zv)) & ~1); } } else { ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF); @@ -594,7 +593,7 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int { zval *retval; uintptr_t property_offset; - zend_property_info *prop_info = NULL; + const zend_property_info *prop_info = NULL; uint32_t *guard = NULL; zend_string *tmp_name = NULL; @@ -616,6 +615,8 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int * to make sure no actual modification is possible. */ ZVAL_COPY(rv, retval); retval = rv; + } else if (Z_PROP_FLAG_P(retval) & IS_PROP_REINITABLE) { + Z_PROP_FLAG_P(retval) &= ~IS_PROP_REINITABLE; } else { zend_readonly_property_modification_error(prop_info); retval = &EG(uninitialized_zval); @@ -634,7 +635,7 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int } } } - if (UNEXPECTED(Z_PROP_FLAG_P(retval) == IS_PROP_UNINIT)) { + if (UNEXPECTED(Z_PROP_FLAG_P(retval) & IS_PROP_UNINIT)) { /* Skip __get() for uninitialized typed properties */ goto uninit_error; } @@ -767,7 +768,7 @@ static zend_always_inline bool property_uses_strict_types(void) { } static bool verify_readonly_initialization_access( - zend_property_info *prop_info, zend_class_entry *ce, + const zend_property_info *prop_info, const zend_class_entry *ce, zend_string *name, const char *operation) { zend_class_entry *scope; if (UNEXPECTED(EG(fake_scope))) { @@ -782,7 +783,7 @@ static bool verify_readonly_initialization_access( /* We may have redeclared a parent property. In that case the parent should still be * allowed to initialize it. */ if (scope && is_derived_class(ce, scope)) { - zend_property_info *prop_info = zend_hash_find_ptr(&scope->properties_info, name); + const zend_property_info *prop_info = zend_hash_find_ptr(&scope->properties_info, name); if (prop_info) { /* This should be ensured by inheritance. */ ZEND_ASSERT(prop_info->flags & ZEND_ACC_READONLY); @@ -800,7 +801,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva { zval *variable_ptr, tmp; uintptr_t property_offset; - zend_property_info *prop_info = NULL; + const zend_property_info *prop_info = NULL; ZEND_ASSERT(!Z_ISREF_P(value)); property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__set != NULL), cache_slot, &prop_info); @@ -811,7 +812,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva Z_TRY_ADDREF_P(value); if (UNEXPECTED(prop_info)) { - if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) { + if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(variable_ptr) & IS_PROP_REINITABLE))) { Z_TRY_DELREF_P(value); zend_readonly_property_modification_error(prop_info); variable_ptr = &EG(error_zval); @@ -819,20 +820,52 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva } ZVAL_COPY_VALUE(&tmp, value); - if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, property_uses_strict_types()))) { + // Increase refcount to prevent object from being released in __toString() + GC_ADDREF(zobj); + bool type_matched = zend_verify_property_type(prop_info, &tmp, property_uses_strict_types()); + if (UNEXPECTED(GC_DELREF(zobj) == 0)) { + zend_object_released_while_assigning_to_property_error(prop_info); + zend_objects_store_del(zobj); + zval_ptr_dtor(&tmp); + variable_ptr = &EG(error_zval); + goto exit; + } + if (UNEXPECTED(!type_matched)) { Z_TRY_DELREF_P(value); variable_ptr = &EG(error_zval); goto exit; } + Z_PROP_FLAG_P(variable_ptr) &= ~IS_PROP_REINITABLE; value = &tmp; } -found: - variable_ptr = zend_assign_to_variable( - variable_ptr, value, IS_TMP_VAR, property_uses_strict_types()); +found:; + zend_refcounted *garbage = NULL; + + variable_ptr = zend_assign_to_variable_ex( + variable_ptr, value, IS_TMP_VAR, property_uses_strict_types(), &garbage); + + if (garbage) { + if (GC_DELREF(garbage) == 0) { + zend_execute_data *execute_data = EG(current_execute_data); + // Assign to result variable before calling the destructor as it may release the object + if (execute_data + && EX(func) + && ZEND_USER_CODE(EX(func)->common.type) + && EX(opline) + && EX(opline)->opcode == ZEND_ASSIGN_OBJ + && EX(opline)->result_type) { + ZVAL_COPY_DEREF(EX_VAR(EX(opline)->result.var), variable_ptr); + variable_ptr = NULL; + } + rc_dtor_func(garbage); + } else { + gc_check_possible_root_no_ref(garbage); + } + } goto exit; } - if (Z_PROP_FLAG_P(variable_ptr) == IS_PROP_UNINIT) { + if (Z_PROP_FLAG_P(variable_ptr) & IS_PROP_UNINIT) { /* Writes to uninitialized typed properties bypass __set(). */ goto write_std_property; } @@ -890,7 +923,17 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva } ZVAL_COPY_VALUE(&tmp, value); - if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, property_uses_strict_types()))) { + // Increase refcount to prevent object from being released in __toString() + GC_ADDREF(zobj); + bool type_matched = zend_verify_property_type(prop_info, &tmp, property_uses_strict_types()); + if (UNEXPECTED(GC_DELREF(zobj) == 0)) { + zend_object_released_while_assigning_to_property_error(prop_info); + zend_objects_store_del(zobj); + zval_ptr_dtor(&tmp); + variable_ptr = &EG(error_zval); + goto exit; + } + if (UNEXPECTED(!type_matched)) { zval_ptr_dtor(value); goto exit; } @@ -1037,7 +1080,7 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam { zval *retval = NULL; uintptr_t property_offset; - zend_property_info *prop_info = NULL; + const zend_property_info *prop_info = NULL; #if DEBUG_OBJECT_HANDLERS fprintf(stderr, "Ptr object #%d property: %s\n", zobj->handle, ZSTR_VAL(name)); @@ -1050,7 +1093,7 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) { if (EXPECTED(!zobj->ce->__get) || UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET) || - UNEXPECTED(prop_info && Z_PROP_FLAG_P(retval) == IS_PROP_UNINIT)) { + UNEXPECTED(prop_info && (Z_PROP_FLAG_P(retval) & IS_PROP_UNINIT))) { if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) { if (UNEXPECTED(prop_info)) { zend_throw_error(NULL, @@ -1065,6 +1108,8 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam } else if (prop_info && UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) { /* Readonly property, delegate to read_property + write_property. */ retval = NULL; + } else if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_NULL(retval); } } else { /* we do have getter - fail and let it try again with usual get/set */ @@ -1118,7 +1163,7 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void **cache_slot) /* {{{ */ { uintptr_t property_offset; - zend_property_info *prop_info = NULL; + const zend_property_info *prop_info = NULL; property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__unset != NULL), cache_slot, &prop_info); @@ -1127,8 +1172,12 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void if (Z_TYPE_P(slot) != IS_UNDEF) { if (UNEXPECTED(prop_info && (prop_info->flags & ZEND_ACC_READONLY))) { - zend_readonly_property_unset_error(prop_info->ce, name); - return; + if (Z_PROP_FLAG_P(slot) & IS_PROP_REINITABLE) { + Z_PROP_FLAG_P(slot) &= ~IS_PROP_REINITABLE; + } else { + zend_readonly_property_unset_error(prop_info->ce, name); + return; + } } if (UNEXPECTED(Z_ISREF_P(slot)) && (ZEND_DEBUG || ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(slot)))) { @@ -1145,7 +1194,7 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void } return; } - if (UNEXPECTED(Z_PROP_FLAG_P(slot) == IS_PROP_UNINIT)) { + if (UNEXPECTED(Z_PROP_FLAG_P(slot) & IS_PROP_UNINIT)) { if (UNEXPECTED(prop_info && (prop_info->flags & ZEND_ACC_READONLY) && !verify_readonly_initialization_access(prop_info, zobj->ce, name, "unset"))) { return; @@ -1174,7 +1223,7 @@ ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void if (zobj->ce->__unset) { uint32_t *guard = zend_get_property_guard(zobj, name); if (!((*guard) & IN_UNSET)) { - /* have unseter - try with it! */ + /* have unsetter - try with it! */ (*guard) |= IN_UNSET; /* prevent circular unsetting */ zend_std_call_unsetter(zobj, name); (*guard) &= ~IN_UNSET; @@ -1229,9 +1278,9 @@ static zend_never_inline zend_function *zend_get_parent_private_method(zend_clas /* Ensures that we're allowed to call a protected method. */ -ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) /* {{{ */ +ZEND_API bool zend_check_protected(const zend_class_entry *ce, const zend_class_entry *scope) /* {{{ */ { - zend_class_entry *fbc_scope = ce; + const zend_class_entry *fbc_scope = ce; /* Is the context that's calling the function, the same as one of * the function's parents? @@ -1256,7 +1305,7 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) } /* }}} */ -ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend_string *method_name, int is_static) /* {{{ */ +ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce, zend_string *method_name, bool is_static) /* {{{ */ { size_t mname_len; zend_op_array *func; @@ -1287,6 +1336,12 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend ZEND_MAP_PTR_INIT(func->run_time_cache, (void**)dummy); func->scope = fbc->common.scope; /* reserve space for arguments, local and temporary variables */ + /* EG(trampoline) is reused from other places, like FFI (e.g. zend_ffi_cdata_get_closure()) where + * it is used as an internal function. It may set fields that don't belong to common, thus + * modifying zend_op_array specific data, most significantly last_var. We need to reset this + * value so that it doesn't contain garbage when the engine allocates space for the next stack + * frame. This didn't cause any issues until now due to "lucky" structure layout. */ + func->last_var = 0; func->T = (fbc->type == ZEND_USER_FUNCTION)? MAX(fbc->op_array.last_var + fbc->op_array.T, 2) : 2; func->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : ZSTR_EMPTY_ALLOC(); func->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0; @@ -1542,7 +1597,7 @@ ZEND_API zval *zend_std_get_static_property_with_info(zend_class_entry *ce, zend } if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) { - if (UNEXPECTED(zend_update_class_constants(ce)) != SUCCESS) { + if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { return NULL; } } @@ -1645,7 +1700,7 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */ object_lhs = false; } ZEND_ASSERT(Z_TYPE_P(value) != IS_OBJECT); - zend_uchar target_type = (Z_TYPE_P(value) == IS_FALSE || Z_TYPE_P(value) == IS_TRUE) + uint8_t target_type = (Z_TYPE_P(value) == IS_FALSE || Z_TYPE_P(value) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(value); if (Z_OBJ_HT_P(object)->cast_object(Z_OBJ_P(object), &casted, target_type) == FAILURE) { // TODO: Less crazy. @@ -1750,7 +1805,7 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has int result; zval *value = NULL; uintptr_t property_offset; - zend_property_info *prop_info = NULL; + const zend_property_info *prop_info = NULL; zend_string *tmp_name = NULL; property_offset = zend_get_property_offset(zobj->ce, name, 1, cache_slot, &prop_info); @@ -1760,7 +1815,7 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has if (Z_TYPE_P(value) != IS_UNDEF) { goto found; } - if (UNEXPECTED(Z_PROP_FLAG_P(value) == IS_PROP_UNINIT)) { + if (UNEXPECTED(Z_PROP_FLAG_P(value) & IS_PROP_UNINIT)) { /* Skip __isset() for uninitialized typed properties */ result = 0; goto exit; diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 94b7f52cba3aa..475ba6263825d 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -20,6 +20,8 @@ #ifndef ZEND_OBJECT_HANDLERS_H #define ZEND_OBJECT_HANDLERS_H +#include + struct _zend_property_info; #define ZEND_WRONG_PROPERTY_INFO \ @@ -154,7 +156,7 @@ typedef zend_result (*zend_object_get_closure_t)(zend_object *obj, zend_class_en typedef HashTable *(*zend_object_get_gc_t)(zend_object *object, zval **table, int *n); -typedef zend_result (*zend_object_do_operation_t)(zend_uchar opcode, zval *result, zval *op1, zval *op2); +typedef zend_result (*zend_object_do_operation_t)(uint8_t opcode, zval *result, zval *op1, zval *op2); struct _zend_object_handlers { /* offset of real object header (usually zero) */ @@ -205,7 +207,7 @@ ZEND_API zval *zend_std_get_static_property_with_info(zend_class_entry *ce, zend ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *property_name, int type); ZEND_API ZEND_COLD bool zend_std_unset_static_property(zend_class_entry *ce, zend_string *property_name); ZEND_API zend_function *zend_std_get_constructor(zend_object *object); -ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zend_string *member, int silent); +ZEND_API struct _zend_property_info *zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent); ZEND_API HashTable *zend_std_get_properties(zend_object *object); ZEND_API HashTable *zend_std_get_gc(zend_object *object, zval **table, int *n); ZEND_API HashTable *zend_std_get_debug_info(zend_object *object, int *is_temp); @@ -231,11 +233,11 @@ ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj); * Only objects with the same identity will be considered equal. */ ZEND_API int zend_objects_not_comparable(zval *o1, zval *o2); -ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope); +ZEND_API bool zend_check_protected(const zend_class_entry *ce, const zend_class_entry *scope); -ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_info_name, bool is_dynamic); +ZEND_API zend_result zend_check_property_access(const zend_object *zobj, zend_string *prop_info_name, bool is_dynamic); -ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend_string *method_name, int is_static); +ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce, zend_string *method_name, bool is_static); ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *member); diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index df76fa0bb8dc3..4d40b76854df0 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -192,6 +192,8 @@ ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce) ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object) { + bool has_clone_method = old_object->ce->clone != NULL; + if (old_object->ce->default_properties_count) { zval *src = old_object->properties_table; zval *dst = new_object->properties_table; @@ -201,6 +203,11 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, i_zval_ptr_dtor(dst); ZVAL_COPY_VALUE_PROP(dst, src); zval_add_ref(dst); + if (has_clone_method) { + /* Unconditionally add the IS_PROP_REINITABLE flag to avoid a potential cache miss of property_info */ + Z_PROP_FLAG_P(dst) |= IS_PROP_REINITABLE; + } + if (UNEXPECTED(Z_ISREF_P(dst)) && (ZEND_DEBUG || ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(dst)))) { zend_property_info *prop_info = zend_get_property_info_for_slot(new_object, dst); @@ -211,7 +218,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, src++; dst++; } while (src != end); - } else if (old_object->properties && !old_object->ce->clone) { + } else if (old_object->properties && !has_clone_method) { /* fast copy */ if (EXPECTED(old_object->handlers == &std_object_handlers)) { if (EXPECTED(!(GC_FLAGS(old_object->properties) & IS_ARRAY_IMMUTABLE))) { @@ -245,6 +252,10 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, ZVAL_COPY_VALUE(&new_prop, prop); zval_add_ref(&new_prop); } + if (has_clone_method) { + /* Unconditionally add the IS_PROP_REINITABLE flag to avoid a potential cache miss of property_info */ + Z_PROP_FLAG_P(&new_prop) |= IS_PROP_REINITABLE; + } if (EXPECTED(key)) { _zend_hash_append(new_object->properties, key, &new_prop); } else { @@ -253,9 +264,18 @@ ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, } ZEND_HASH_FOREACH_END(); } - if (old_object->ce->clone) { + if (has_clone_method) { GC_ADDREF(new_object); zend_call_known_instance_method_with_0_params(new_object->ce->clone, new_object, NULL); + + if (ZEND_CLASS_HAS_READONLY_PROPS(new_object->ce)) { + for (uint32_t i = 0; i < new_object->ce->default_properties_count; i++) { + zval* prop = OBJ_PROP_NUM(new_object, i); + /* Unconditionally remove the IS_PROP_REINITABLE flag to avoid a potential cache miss of property_info */ + Z_PROP_FLAG_P(prop) &= ~IS_PROP_REINITABLE; + } + } + OBJ_RELEASE(new_object); } } diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h index 7a9a3a00082c0..422bf6a53e2f3 100644 --- a/Zend/zend_objects_API.h +++ b/Zend/zend_objects_API.h @@ -25,14 +25,14 @@ #define OBJ_BUCKET_INVALID (1<<0) -#define IS_OBJ_VALID(o) (!(((zend_uintptr_t)(o)) & OBJ_BUCKET_INVALID)) +#define IS_OBJ_VALID(o) (!(((uintptr_t)(o)) & OBJ_BUCKET_INVALID)) -#define SET_OBJ_INVALID(o) ((zend_object*)((((zend_uintptr_t)(o)) | OBJ_BUCKET_INVALID))) +#define SET_OBJ_INVALID(o) ((zend_object*)((((uintptr_t)(o)) | OBJ_BUCKET_INVALID))) -#define GET_OBJ_BUCKET_NUMBER(o) (((zend_intptr_t)(o)) >> 1) +#define GET_OBJ_BUCKET_NUMBER(o) (((intptr_t)(o)) >> 1) #define SET_OBJ_BUCKET_NUMBER(o, n) do { \ - (o) = (zend_object*)((((zend_uintptr_t)(n)) << 1) | OBJ_BUCKET_INVALID); \ + (o) = (zend_object*)((((uintptr_t)(n)) << 1) | OBJ_BUCKET_INVALID); \ } while (0) #define ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(h) do { \ diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 6d42379b2022e..5db656b46c268 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -45,7 +45,7 @@ static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend } } -void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size) +void init_op_array(zend_op_array *op_array, uint8_t type, int initial_ops_size) { op_array->type = type; op_array->arg_flags[0] = 0; @@ -301,6 +301,12 @@ ZEND_API void destroy_zend_class(zval *zv) return; } + /* We don't increase the refcount for class aliases, + * skip the destruction of aliases entirely. */ + if (UNEXPECTED(Z_TYPE_INFO_P(zv) == IS_ALIAS_PTR)) { + return; + } + if (ce->ce_flags & ZEND_ACC_FILE_CACHED) { zend_class_constant *c; zval *p, *end; @@ -323,6 +329,8 @@ ZEND_API void destroy_zend_class(zval *zv) return; } + ZEND_ASSERT(ce->refcount > 0); + if (--ce->refcount > 0) { return; } @@ -516,7 +524,7 @@ void zend_class_add_ref(zval *zv) { zend_class_entry *ce = Z_PTR_P(zv); - if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) { + if (Z_TYPE_P(zv) != IS_ALIAS_PTR && !(ce->ce_flags & ZEND_ACC_IMMUTABLE)) { ce->refcount++; } } diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 9af1a6b4756ec..a9932a6b592b6 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -35,9 +35,15 @@ # include #endif +#ifdef ZEND_INTRIN_AVX2_NATIVE +#include +#endif #ifdef __SSE2__ #include #endif +#if defined(__aarch64__) || defined(_M_ARM64) +#include +#endif #if defined(ZEND_WIN32) && !defined(ZTS) && defined(_MSC_VER) /* This performance improvement of tolower() on Windows gives 10-18% on bench.php */ @@ -54,14 +60,37 @@ static _locale_t current_locale = NULL; #define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2)) -#if __SSE2__ +#ifdef ZEND_INTRIN_AVX2_NATIVE +#define HAVE_BLOCKCONV + +#define BLOCKCONV_INIT_RANGE(start, end) \ + const __m256i blconv_offset = _mm256_set1_epi8((signed char)(SCHAR_MIN - start)); \ + const __m256i blconv_threshold = _mm256_set1_epi8(SCHAR_MIN + (end - start) + 1); + +#define BLOCKCONV_STRIDE sizeof(__m256i) + +#define BLOCKCONV_INIT_DELTA(delta) \ + const __m256i blconv_delta = _mm256_set1_epi8(delta); + +#define BLOCKCONV_LOAD(input) \ + __m256i blconv_operand = _mm256_loadu_si256((__m256i*)(input)); \ + __m256i blconv_mask = _mm256_cmpgt_epi8(blconv_threshold, _mm256_add_epi8(blconv_operand, blconv_offset)); + +#define BLOCKCONV_FOUND() _mm256_movemask_epi8(blconv_mask) + +#define BLOCKCONV_STORE(dest) \ + __m256i blconv_add = _mm256_and_si256(blconv_mask, blconv_delta); \ + __m256i blconv_result = _mm256_add_epi8(blconv_operand, blconv_add); \ + _mm256_storeu_si256((__m256i*)(dest), blconv_result); + +#elif __SSE2__ #define HAVE_BLOCKCONV /* Common code for SSE2 accelerated character case conversion */ #define BLOCKCONV_INIT_RANGE(start, end) \ - const __m128i blconv_start_minus_1 = _mm_set1_epi8((start) - 1); \ - const __m128i blconv_end_plus_1 = _mm_set1_epi8((end) + 1); + const __m128i blconv_offset = _mm_set1_epi8((signed char)(SCHAR_MIN - start)); \ + const __m128i blconv_threshold = _mm_set1_epi8(SCHAR_MIN + (end - start) + 1); #define BLOCKCONV_STRIDE sizeof(__m128i) @@ -70,18 +99,39 @@ static _locale_t current_locale = NULL; #define BLOCKCONV_LOAD(input) \ __m128i blconv_operand = _mm_loadu_si128((__m128i*)(input)); \ - __m128i blconv_gt = _mm_cmpgt_epi8(blconv_operand, blconv_start_minus_1); \ - __m128i blconv_lt = _mm_cmplt_epi8(blconv_operand, blconv_end_plus_1); \ - __m128i blconv_mingle = _mm_and_si128(blconv_gt, blconv_lt); + __m128i blconv_mask = _mm_cmplt_epi8(_mm_add_epi8(blconv_operand, blconv_offset), blconv_threshold); -#define BLOCKCONV_FOUND() _mm_movemask_epi8(blconv_mingle) +#define BLOCKCONV_FOUND() _mm_movemask_epi8(blconv_mask) #define BLOCKCONV_STORE(dest) \ - __m128i blconv_add = _mm_and_si128(blconv_mingle, blconv_delta); \ + __m128i blconv_add = _mm_and_si128(blconv_mask, blconv_delta); \ __m128i blconv_result = _mm_add_epi8(blconv_operand, blconv_add); \ _mm_storeu_si128((__m128i *)(dest), blconv_result); -#endif /* __SSE2__ */ +#elif defined(__aarch64__) || defined(_M_ARM64) +#define HAVE_BLOCKCONV + +#define BLOCKCONV_INIT_RANGE(start, end) \ + const int8x16_t blconv_offset = vdupq_n_s8((signed char)(SCHAR_MIN - start)); \ + const int8x16_t blconv_threshold = vdupq_n_s8(SCHAR_MIN + (end - start) + 1); + +#define BLOCKCONV_STRIDE sizeof(int8x16_t) + +#define BLOCKCONV_INIT_DELTA(delta) \ + const int8x16_t blconv_delta = vdupq_n_s8(delta); + +#define BLOCKCONV_LOAD(input) \ + int8x16_t blconv_operand = vld1q_s8((const int8_t*)(input)); \ + uint8x16_t blconv_mask = vcltq_s8(vaddq_s8(blconv_operand, blconv_offset), blconv_threshold); + +#define BLOCKCONV_FOUND() vmaxvq_u8(blconv_mask) + +#define BLOCKCONV_STORE(dest) \ + int8x16_t blconv_add = vandq_s8(vreinterpretq_s8_u8(blconv_mask), blconv_delta); \ + int8x16_t blconv_result = vaddq_s8(blconv_operand, blconv_add); \ + vst1q_s8((int8_t *)(dest), blconv_result); + +#endif /* defined(__aarch64__) || defined(_M_ARM64) */ ZEND_API const unsigned char zend_tolower_map[256] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, @@ -347,7 +397,7 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, bo } case IS_STRING: { - zend_uchar type; + uint8_t type; zend_long lval; double dval; bool trailing_data = false; @@ -841,7 +891,7 @@ ZEND_API void ZEND_COLD zend_incompatible_string_to_long_error(const zend_string zend_error(E_DEPRECATED, "Implicit conversion from float-string \"%s\" to int loses precision", ZSTR_VAL(s)); } -ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op, bool is_strict) /* {{{ */ +ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(const zval *op, bool is_strict) /* {{{ */ { try_again: switch (Z_TYPE_P(op)) { @@ -867,7 +917,7 @@ ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op, bool is_strict) /* } case IS_STRING: { - zend_uchar type; + uint8_t type; zend_long lval; double dval; if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, true))) { @@ -911,7 +961,7 @@ ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op, bool is_strict) /* } /* }}} */ -ZEND_API double ZEND_FASTCALL zval_get_double_func(zval *op) /* {{{ */ +ZEND_API double ZEND_FASTCALL zval_get_double_func(const zval *op) /* {{{ */ { try_again: switch (Z_TYPE_P(op)) { @@ -1030,7 +1080,7 @@ static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zva static zend_always_inline zend_result add_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */ { - zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); + uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { fast_long_add_function(result, op1, op2); @@ -1096,7 +1146,7 @@ ZEND_API zend_result ZEND_FASTCALL add_function(zval *result, zval *op1, zval *o static zend_always_inline zend_result sub_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */ { - zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); + uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { fast_long_sub_function(result, op1, op2); @@ -1161,7 +1211,7 @@ ZEND_API zend_result ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *o static zend_always_inline zend_result mul_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */ { - zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); + uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { zend_long overflow; @@ -1230,7 +1280,7 @@ ZEND_API zend_result ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *o static zend_result ZEND_FASTCALL pow_function_base(zval *result, zval *op1, zval *op2) /* {{{ */ { - zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); + uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { if (Z_LVAL_P(op2) >= 0) { @@ -1323,7 +1373,7 @@ ZEND_API zend_result ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *o #define DIV_BY_ZERO 2 static int ZEND_FASTCALL div_function_base(zval *result, zval *op1, zval *op2) /* {{{ */ { - zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); + uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2)); if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) { if (Z_LVAL_P(op2) == 0) { @@ -1562,7 +1612,7 @@ ZEND_API zend_result ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) if (result != op1) { ZVAL_UNDEF(result); } - zend_type_error("Cannot perform bitwise not on %s", zend_zval_type_name(op1)); + zend_type_error("Cannot perform bitwise not on %s", zend_zval_value_name(op1)); return FAILURE; } } @@ -1889,7 +1939,7 @@ ZEND_API zend_result ZEND_FASTCALL shift_right_function(zval *result, zval *op1, ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */ { - zval *orig_op1 = op1; + zval *orig_op1 = op1; zval op1_copy, op2_copy; ZVAL_UNDEF(&op1_copy); @@ -1957,6 +2007,7 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval size_t op2_len = Z_STRLEN_P(op2); size_t result_len = op1_len + op2_len; zend_string *result_str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2)); if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) { zend_throw_error(NULL, "String size overflow"); @@ -1978,6 +2029,7 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval i_zval_ptr_dtor(result); } } + GC_ADD_FLAGS(result_str, flags); /* This has to happen first to account for the cases where result == op1 == op2 and * the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to @@ -2077,7 +2129,7 @@ ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{ d1 = zval_get_double(op1); d2 = zval_get_double(op2); - return ZEND_NORMALIZE_BOOL(d1 - d2); + return ZEND_THREEWAY_COMPARE(d1, d2); } /* }}} */ @@ -2092,15 +2144,14 @@ static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */ { zend_long str_lval; double str_dval; - zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); + uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); if (type == IS_LONG) { return lval > str_lval ? 1 : lval < str_lval ? -1 : 0; } if (type == IS_DOUBLE) { - double diff = (double) lval - str_dval; - return ZEND_NORMALIZE_BOOL(diff); + return ZEND_THREEWAY_COMPARE((double) lval, str_dval); } zend_string *lval_as_str = zend_long_to_str(lval); @@ -2115,18 +2166,14 @@ static int compare_double_to_string(double dval, zend_string *str) /* {{{ */ { zend_long str_lval; double str_dval; - zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); + uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); if (type == IS_LONG) { - double diff = dval - (double) str_lval; - return ZEND_NORMALIZE_BOOL(diff); + return ZEND_THREEWAY_COMPARE(dval, (double) str_lval); } if (type == IS_DOUBLE) { - if (dval == str_dval) { - return 0; - } - return ZEND_NORMALIZE_BOOL(dval - str_dval); + return ZEND_THREEWAY_COMPARE(dval, str_dval); } zend_string *dval_as_str = zend_double_to_str(dval); @@ -2148,17 +2195,13 @@ ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */ return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1) #include #include +#include #ifdef HAVE_IEEEFP_H #include @@ -54,7 +55,7 @@ ZEND_API zend_result ZEND_FASTCALL shift_left_function(zval *result, zval *op1, ZEND_API zend_result ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2); ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2); -ZEND_API bool ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2); +ZEND_API bool ZEND_FASTCALL zend_is_identical(const zval *op1, const zval *op2); ZEND_API zend_result ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2); ZEND_API zend_result ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2); @@ -86,7 +87,7 @@ static zend_always_inline bool instanceof_function( * could not be represented as such due to overflow. It writes 1 to oflow_info * if the integer is larger than ZEND_LONG_MAX and -1 if it's smaller than ZEND_LONG_MIN. */ -ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, +ZEND_API uint8_t ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, bool allow_errors, int *oflow_info, bool *trailing_data); ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end); @@ -142,7 +143,7 @@ static zend_always_inline zend_long zend_dval_to_lval_safe(double d) #define ZEND_IS_DIGIT(c) ((c) >= '0' && (c) <= '9') #define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) -static zend_always_inline zend_uchar is_numeric_string_ex(const char *str, size_t length, zend_long *lval, +static zend_always_inline uint8_t is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, bool allow_errors, int *oflow_info, bool *trailing_data) { if (*str > '9') { @@ -151,11 +152,11 @@ static zend_always_inline zend_uchar is_numeric_string_ex(const char *str, size_ return _is_numeric_string_ex(str, length, lval, dval, allow_errors, oflow_info, trailing_data); } -static zend_always_inline zend_uchar is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, bool allow_errors) { +static zend_always_inline uint8_t is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, bool allow_errors) { return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL, NULL); } -ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval); +ZEND_API uint8_t ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval); static zend_always_inline const char * zend_memnstr(const char *haystack, const char *needle, size_t needle_len, const char *end) @@ -273,18 +274,18 @@ ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op); ZEND_API void ZEND_FASTCALL convert_to_array(zval *op); ZEND_API void ZEND_FASTCALL convert_to_object(zval *op); -ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op, bool is_strict); -ZEND_API double ZEND_FASTCALL zval_get_double_func(zval *op); +ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(const zval *op, bool is_strict); +ZEND_API double ZEND_FASTCALL zval_get_double_func(const zval *op); ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op); ZEND_API zend_string* ZEND_FASTCALL zval_try_get_string_func(zval *op); -static zend_always_inline zend_long zval_get_long(zval *op) { +static zend_always_inline zend_long zval_get_long(const zval *op) { return EXPECTED(Z_TYPE_P(op) == IS_LONG) ? Z_LVAL_P(op) : zval_get_long_func(op, false); } -static zend_always_inline zend_long zval_get_long_ex(zval *op, bool is_strict) { +static zend_always_inline zend_long zval_get_long_ex(const zval *op, bool is_strict) { return EXPECTED(Z_TYPE_P(op) == IS_LONG) ? Z_LVAL_P(op) : zval_get_long_func(op, is_strict); } -static zend_always_inline double zval_get_double(zval *op) { +static zend_always_inline double zval_get_double(const zval *op) { return EXPECTED(Z_TYPE_P(op) == IS_DOUBLE) ? Z_DVAL_P(op) : zval_get_double_func(op); } static zend_always_inline zend_string *zval_get_string(zval *op) { @@ -349,13 +350,13 @@ static zend_always_inline bool try_convert_to_string(zval *op) { #define convert_to_string(op) if (Z_TYPE_P(op) != IS_STRING) { _convert_to_string((op)); } -ZEND_API int ZEND_FASTCALL zend_is_true(zval *op); -ZEND_API bool ZEND_FASTCALL zend_object_is_true(zval *op); +ZEND_API int ZEND_FASTCALL zend_is_true(const zval *op); +ZEND_API bool ZEND_FASTCALL zend_object_is_true(const zval *op); #define zval_is_true(op) \ zend_is_true(op) -static zend_always_inline bool i_zend_is_true(zval *op) +static zend_always_inline bool i_zend_is_true(const zval *op) { bool result = 0; @@ -704,28 +705,6 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL #endif } -static zend_always_inline zend_result fast_add_function(zval *result, zval *op1, zval *op2) -{ - if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - fast_long_add_function(result, op1, op2); - return SUCCESS; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); - return SUCCESS; - } - } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) { - if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) { - ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); - return SUCCESS; - } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { - ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); - return SUCCESS; - } - } - return add_function(result, op1, op2); -} - static zend_always_inline void fast_long_sub_function(zval *result, zval *op1, zval *op2) { #if ZEND_USE_ASM_ARITHMETIC && defined(__i386__) && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 7fdeedee19bf4..c098d29d51842 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -265,7 +265,6 @@ char *alloca(); #if defined(__GNUC__) && ZEND_GCC_VERSION >= 4003 # define ZEND_COLD __attribute__((cold)) -# define ZEND_HOT __attribute__((hot)) # ifdef __OPTIMIZE__ # define ZEND_OPT_SIZE __attribute__((optimize("Os"))) # define ZEND_OPT_SPEED __attribute__((optimize("Ofast"))) @@ -275,7 +274,6 @@ char *alloca(); # endif #else # define ZEND_COLD -# define ZEND_HOT # define ZEND_OPT_SIZE # define ZEND_OPT_SPEED #endif @@ -283,11 +281,9 @@ char *alloca(); #if defined(__GNUC__) && ZEND_GCC_VERSION >= 5000 # define ZEND_ATTRIBUTE_UNUSED_LABEL __attribute__((unused)); # define ZEND_ATTRIBUTE_COLD_LABEL __attribute__((cold)); -# define ZEND_ATTRIBUTE_HOT_LABEL __attribute__((hot)); #else # define ZEND_ATTRIBUTE_UNUSED_LABEL # define ZEND_ATTRIBUTE_COLD_LABEL -# define ZEND_ATTRIBUTE_HOT_LABEL #endif #if defined(__GNUC__) && ZEND_GCC_VERSION >= 3004 && defined(__i386__) @@ -655,6 +651,46 @@ extern "C++" { # define ZEND_INTRIN_AVX2_FUNC_DECL(func) #endif +#if PHP_HAVE_AVX512_SUPPORTS && defined(HAVE_FUNC_ATTRIBUTE_TARGET) || defined(ZEND_WIN32) +#define ZEND_INTRIN_AVX512_RESOLVER 1 +#endif + +#if defined(ZEND_INTRIN_AVX512_RESOLVER) && defined(ZEND_INTRIN_HAVE_IFUNC_TARGET) +# define ZEND_INTRIN_AVX512_FUNC_PROTO 1 +#elif defined(ZEND_INTRIN_AVX512_RESOLVER) +# define ZEND_INTRIN_AVX512_FUNC_PTR 1 +#endif + +#ifdef ZEND_INTRIN_AVX512_RESOLVER +# ifdef HAVE_FUNC_ATTRIBUTE_TARGET +# define ZEND_INTRIN_AVX512_FUNC_DECL(func) ZEND_API func __attribute__((target("avx512f,avx512cd,avx512vl,avx512dq,avx512bw"))) +# else +# define ZEND_INTRIN_AVX512_FUNC_DECL(func) func +# endif +#else +# define ZEND_INTRIN_AVX512_FUNC_DECL(func) +#endif + +#if PHP_HAVE_AVX512_VBMI_SUPPORTS && defined(HAVE_FUNC_ATTRIBUTE_TARGET) +#define ZEND_INTRIN_AVX512_VBMI_RESOLVER 1 +#endif + +#if defined(ZEND_INTRIN_AVX512_VBMI_RESOLVER) && defined(ZEND_INTRIN_HAVE_IFUNC_TARGET) +# define ZEND_INTRIN_AVX512_VBMI_FUNC_PROTO 1 +#elif defined(ZEND_INTRIN_AVX512_VBMI_RESOLVER) +# define ZEND_INTRIN_AVX512_VBMI_FUNC_PTR 1 +#endif + +#ifdef ZEND_INTRIN_AVX512_VBMI_RESOLVER +# ifdef HAVE_FUNC_ATTRIBUTE_TARGET +# define ZEND_INTRIN_AVX512_VBMI_FUNC_DECL(func) ZEND_API func __attribute__((target("avx512f,avx512cd,avx512vl,avx512dq,avx512bw,avx512vbmi"))) +# else +# define ZEND_INTRIN_AVX512_VBMI_FUNC_DECL(func) func +# endif +#else +# define ZEND_INTRIN_AVX512_VBMI_FUNC_DECL(func) +#endif + /* Intrinsics macros end. */ #ifdef ZEND_WIN32 @@ -665,7 +701,7 @@ extern "C++" { # define ZEND_SET_ALIGNED(alignment, decl) decl #endif -#define ZEND_SLIDE_TO_ALIGNED(alignment, ptr) (((zend_uintptr_t)(ptr) + ((alignment)-1)) & ~((alignment)-1)) +#define ZEND_SLIDE_TO_ALIGNED(alignment, ptr) (((uintptr_t)(ptr) + ((alignment)-1)) & ~((alignment)-1)) #define ZEND_SLIDE_TO_ALIGNED16(ptr) ZEND_SLIDE_TO_ALIGNED(Z_UL(16), ptr) #ifdef ZEND_WIN32 @@ -695,10 +731,29 @@ extern "C++" { # define ZEND_VOIDP(ptr) (ptr) #endif -#if defined(__GNUC__) && ZEND_GCC_VERSION >= 9000 +#if __has_attribute(__indirect_return__) # define ZEND_INDIRECT_RETURN __attribute__((__indirect_return__)) #else # define ZEND_INDIRECT_RETURN #endif +#if __GNUC__ && !defined(__clang__) +# define __DO_PRAGMA(x) _Pragma(#x) +# define _DO_PRAGMA(x) __DO_PRAGMA(x) +# define ZEND_CGG_DIAGNOSTIC_IGNORED_START(warning) \ + _Pragma("GCC diagnostic push") \ + _DO_PRAGMA(GCC diagnostic ignored warning) +# define ZEND_CGG_DIAGNOSTIC_IGNORED_END \ + _Pragma("GCC diagnostic pop") +#else +# define ZEND_CGG_DIAGNOSTIC_IGNORED_START(warning) +# define ZEND_CGG_DIAGNOSTIC_IGNORED_END +#endif + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ +# define ZEND_STATIC_ASSERT(c, m) _Static_assert((c), m) +#else +# define ZEND_STATIC_ASSERT(c, m) +#endif + #endif /* ZEND_PORTABILITY_H */ diff --git a/Zend/zend_signal.c b/Zend/zend_signal.c index aa74bdd147c98..f6ca3f40a3e57 100644 --- a/Zend/zend_signal.c +++ b/Zend/zend_signal.c @@ -62,7 +62,7 @@ ZEND_API zend_signal_globals_t zend_signal_globals; #endif static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context); -static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*)); +static zend_result zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*)); #if defined(__CYGWIN__) || defined(__PASE__) /* Matches zend_execute_API.c; these platforms don't support ITIMER_PROF. */ @@ -71,7 +71,7 @@ static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void #define TIMEOUT_SIG SIGPROF #endif -static int zend_sigs[] = { TIMEOUT_SIG, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2 }; +static const int zend_sigs[] = { TIMEOUT_SIG, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2 }; #define SA_FLAGS_MASK ~(SA_NODEFER | SA_RESETHAND) @@ -87,18 +87,14 @@ void zend_signal_handler_defer(int signo, siginfo_t *siginfo, void *context) zend_signal_queue_t *queue, *qtmp; #ifdef ZTS - /* A signal could hit after TSRM shutdown, in this case globals are already freed. */ - if (tsrm_is_shutdown()) { + /* A signal could hit after TSRM shutdown, in this case globals are already freed. + * Or it could be delivered to a thread that didn't execute PHP yet. + * In the latter case we act as if SIGG(active) is false. */ + if (tsrm_is_shutdown() || !tsrm_is_managed_thread()) { /* Forward to default handler handler */ zend_signal_handler(signo, siginfo, context); return; } - - if (!tsrm_is_managed_thread()) { - fprintf(stderr, "zend_signal_handler_defer() called in a thread not managed by PHP. The expected signal handler will not be called. This is probably a bug.\n"); - - return; - } #endif if (EXPECTED(SIGG(active))) { @@ -186,7 +182,7 @@ static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context) sigset_t sigset; zend_signal_entry_t p_sig; #ifdef ZTS - if (tsrm_is_shutdown()) { + if (tsrm_is_shutdown() || !tsrm_is_managed_thread()) { p_sig.flags = 0; p_sig.handler = SIG_DFL; } else diff --git a/Zend/zend_smart_str.c b/Zend/zend_smart_str.c index e6002dcf1d51a..5132043c60e25 100644 --- a/Zend/zend_smart_str.c +++ b/Zend/zend_smart_str.c @@ -181,7 +181,7 @@ ZEND_API void ZEND_FASTCALL _smart_string_alloc(smart_string *str, size_t len) } } -ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, zend_string *value, size_t length) +ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, const zend_string *value, size_t length) { smart_str_append_escaped(str, ZSTR_VAL(value), MIN(length, ZSTR_LEN(value))); @@ -190,7 +190,7 @@ ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, z } } -ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *dest, zval *value, size_t truncate) { +ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *dest, const zval *value, size_t truncate) { ZEND_ASSERT(Z_TYPE_P(value) <= IS_STRING); switch (Z_TYPE_P(value)) { diff --git a/Zend/zend_smart_str.h b/Zend/zend_smart_str.h index d8b72905d0216..e271835e41db9 100644 --- a/Zend/zend_smart_str.h +++ b/Zend/zend_smart_str.h @@ -32,8 +32,8 @@ ZEND_API void ZEND_FASTCALL smart_str_append_double( smart_str *str, double num, int precision, bool zero_fraction); ZEND_API void smart_str_append_printf(smart_str *dest, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); -ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, zend_string *value, size_t length); -ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *str, zval *value, size_t truncate); +ZEND_API void ZEND_FASTCALL smart_str_append_escaped_truncated(smart_str *str, const zend_string *value, size_t length); +ZEND_API void ZEND_FASTCALL smart_str_append_scalar(smart_str *str, const zval *value, size_t truncate); END_EXTERN_C() static zend_always_inline size_t smart_str_alloc(smart_str *str, size_t len, bool persistent) { diff --git a/Zend/zend_stack.c b/Zend/zend_stack.c index f587452bb7d59..5d9cc166367e7 100644 --- a/Zend/zend_stack.c +++ b/Zend/zend_stack.c @@ -119,7 +119,7 @@ ZEND_API void zend_stack_apply(zend_stack *stack, int type, int (*apply_function } -ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, int type, int (*apply_function)(void *element, void *arg), void *arg) +ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, zend_stack_apply_direction type, int (*apply_function)(void *element, void *arg), void *arg) { int i; diff --git a/Zend/zend_stack.h b/Zend/zend_stack.h index c0a325b778870..68c3621533f92 100644 --- a/Zend/zend_stack.h +++ b/Zend/zend_stack.h @@ -28,6 +28,11 @@ typedef struct _zend_stack { #define STACK_BLOCK_SIZE 16 +typedef enum { + ZEND_STACK_APPLY_TOPDOWN, + ZEND_STACK_APPLY_BOTTOMUP, +} zend_stack_apply_direction; + BEGIN_EXTERN_C() ZEND_API void zend_stack_init(zend_stack *stack, int size); ZEND_API int zend_stack_push(zend_stack *stack, const void *element); @@ -39,11 +44,8 @@ ZEND_API void zend_stack_destroy(zend_stack *stack); ZEND_API void *zend_stack_base(const zend_stack *stack); ZEND_API int zend_stack_count(const zend_stack *stack); ZEND_API void zend_stack_apply(zend_stack *stack, int type, int (*apply_function)(void *element)); -ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, int type, int (*apply_function)(void *element, void *arg), void *arg); +ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, zend_stack_apply_direction type, int (*apply_function)(void *element, void *arg), void *arg); ZEND_API void zend_stack_clean(zend_stack *stack, void (*func)(void *), bool free_elements); END_EXTERN_C() -#define ZEND_STACK_APPLY_TOPDOWN 1 -#define ZEND_STACK_APPLY_BOTTOMUP 2 - #endif /* ZEND_STACK_H */ diff --git a/Zend/zend_stream.h b/Zend/zend_stream.h index 047719e175a04..c1f8ddfb85ca8 100644 --- a/Zend/zend_stream.h +++ b/Zend/zend_stream.h @@ -55,7 +55,7 @@ typedef struct _zend_file_handle { } handle; zend_string *filename; zend_string *opened_path; - zend_uchar type; /* packed zend_stream_type */ + uint8_t type; /* packed zend_stream_type */ bool primary_script; bool in_list; /* added into CG(open_file) */ char *buf; diff --git a/Zend/zend_string.c b/Zend/zend_string.c index b4214bc38cd6f..549270690a8a3 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -102,11 +102,15 @@ ZEND_API void zend_interned_strings_init(void) str = zend_string_alloc(sizeof("")-1, 1); ZSTR_VAL(str)[0] = '\000'; zend_empty_string = zend_new_interned_string_permanent(str); + GC_ADD_FLAGS(zend_empty_string, IS_STR_VALID_UTF8); s[1] = 0; for (i = 0; i < 256; i++) { s[0] = i; zend_one_char_string[i] = zend_new_interned_string_permanent(zend_string_init(s, 1, 1)); + if (i < 0x80) { + GC_ADD_FLAGS(zend_one_char_string[i], IS_STR_VALID_UTF8); + } } /* known strings */ @@ -114,6 +118,7 @@ ZEND_API void zend_interned_strings_init(void) for (i = 0; i < (sizeof(known_strings) / sizeof(known_strings[0])) - 1; i++) { str = zend_string_init(known_strings[i], strlen(known_strings[i]), 1); zend_known_strings[i] = zend_new_interned_string_permanent(str); + GC_ADD_FLAGS(zend_known_strings[i], IS_STR_VALID_UTF8); } } @@ -186,6 +191,17 @@ ZEND_API zend_string* ZEND_FASTCALL zend_interned_string_find_permanent(zend_str return zend_interned_string_ht_lookup(str, &interned_strings_permanent); } +static zend_string* ZEND_FASTCALL zend_init_string_for_interning(zend_string *str, bool persistent) +{ + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(str); + zend_ulong h = ZSTR_H(str); + zend_string_delref(str); + str = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), persistent); + GC_ADD_FLAGS(str, flags); + ZSTR_H(str) = h; + return str; +} + static zend_string* ZEND_FASTCALL zend_new_interned_string_permanent(zend_string *str) { zend_string *ret; @@ -203,10 +219,7 @@ static zend_string* ZEND_FASTCALL zend_new_interned_string_permanent(zend_string ZEND_ASSERT(GC_FLAGS(str) & GC_PERSISTENT); if (GC_REFCOUNT(str) > 1) { - zend_ulong h = ZSTR_H(str); - zend_string_delref(str); - str = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), 1); - ZSTR_H(str) = h; + str = zend_init_string_for_interning(str, true); } return zend_add_interned_string(str, &interned_strings_permanent, IS_STR_PERMANENT); @@ -244,10 +257,7 @@ static zend_string* ZEND_FASTCALL zend_new_interned_string_request(zend_string * } #endif if (GC_REFCOUNT(str) > 1) { - zend_ulong h = ZSTR_H(str); - zend_string_delref(str); - str = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), 0); - ZSTR_H(str) = h; + str = zend_init_string_for_interning(str, false); } ret = zend_add_interned_string(str, &CG(interned_strings), 0); @@ -370,11 +380,28 @@ ZEND_API void zend_interned_strings_switch_storage(bool request) # define I_REPLACE_SONAME_FNNAME_ZU(soname, fnname) _vgr00000ZU_ ## soname ## _ ## fnname #endif -ZEND_API bool ZEND_FASTCALL I_REPLACE_SONAME_FNNAME_ZU(NONE,zend_string_equal_val)(const zend_string *s1, const zend_string *s2) +/* See GH-9068 */ +#if defined(__GNUC__) && (__GNUC__ >= 11 || defined(__clang__)) && __has_attribute(no_caller_saved_registers) +# define NO_CALLER_SAVED_REGISTERS __attribute__((no_caller_saved_registers)) +# ifndef __clang__ +# pragma GCC push_options +# pragma GCC target ("general-regs-only") +# define POP_OPTIONS +# endif +#else +# define NO_CALLER_SAVED_REGISTERS +#endif + +ZEND_API bool ZEND_FASTCALL NO_CALLER_SAVED_REGISTERS I_REPLACE_SONAME_FNNAME_ZU(NONE,zend_string_equal_val)(const zend_string *s1, const zend_string *s2) { return !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1)); } +#ifdef POP_OPTIONS +# pragma GCC pop_options +# undef POP_OPTIONS +#endif + #if defined(__GNUC__) && defined(__i386__) ZEND_API bool ZEND_FASTCALL zend_string_equal_val(const zend_string *s1, const zend_string *s2) { diff --git a/Zend/zend_string.h b/Zend/zend_string.h index ed59ef82a14fe..1513a19c36070 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -80,6 +80,28 @@ END_EXTERN_C() /*---*/ #define ZSTR_IS_INTERNED(s) (GC_FLAGS(s) & IS_STR_INTERNED) +#define ZSTR_IS_VALID_UTF8(s) (GC_FLAGS(s) & IS_STR_VALID_UTF8) + +/* These are properties, encoded as flags, that will hold on the resulting string + * after concatenating two strings that have these property. + * Example: concatenating two UTF-8 strings yields another UTF-8 string. */ +#define ZSTR_COPYABLE_CONCAT_PROPERTIES (IS_STR_VALID_UTF8) + +#define ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(s) (GC_FLAGS(s) & ZSTR_COPYABLE_CONCAT_PROPERTIES) +/* This macro returns the copyable concat properties which hold on both strings. */ +#define ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(s1, s2) (GC_FLAGS(s1) & GC_FLAGS(s2) & ZSTR_COPYABLE_CONCAT_PROPERTIES) + +#define ZSTR_COPY_CONCAT_PROPERTIES(out, in) do { \ + zend_string *_out = (out); \ + uint32_t properties = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES((in)); \ + GC_ADD_FLAGS(_out, properties); \ +} while (0) + +#define ZSTR_COPY_CONCAT_PROPERTIES_BOTH(out, in1, in2) do { \ + zend_string *_out = (out); \ + uint32_t properties = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH((in1), (in2)); \ + GC_ADD_FLAGS(_out, properties); \ +} while (0) #define ZSTR_EMPTY_ALLOC() zend_empty_string #define ZSTR_CHAR(c) zend_one_char_string[c] @@ -108,6 +130,8 @@ END_EXTERN_C() #define ZSTR_ALLOCA_FREE(str, use_heap) free_alloca(str, use_heap) +#define ZSTR_INIT_LITERAL(s, persistent) (zend_string_init((s), strlen(s), (persistent))) + /*---*/ static zend_always_inline zend_ulong zend_string_hash_val(zend_string *s) @@ -369,10 +393,10 @@ static zend_always_inline bool zend_string_equals(const zend_string *s1, const z (ZSTR_LEN(s1) == ZSTR_LEN(s2) && !zend_binary_strcasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2))) #define zend_string_equals_literal_ci(str, c) \ - (ZSTR_LEN(str) == sizeof(c) - 1 && !zend_binary_strcasecmp(ZSTR_VAL(str), ZSTR_LEN(str), (c), sizeof(c) - 1)) + (ZSTR_LEN(str) == sizeof("" c) - 1 && !zend_binary_strcasecmp(ZSTR_VAL(str), ZSTR_LEN(str), (c), sizeof(c) - 1)) #define zend_string_equals_literal(str, literal) \ - zend_string_equals_cstr(str, literal, strlen(literal)) + zend_string_equals_cstr(str, "" literal, sizeof(literal) - 1) static zend_always_inline bool zend_string_starts_with_cstr(const zend_string *str, const char *prefix, size_t prefix_length) { @@ -387,6 +411,19 @@ static zend_always_inline bool zend_string_starts_with(const zend_string *str, c #define zend_string_starts_with_literal(str, prefix) \ zend_string_starts_with_cstr(str, prefix, strlen(prefix)) +static zend_always_inline bool zend_string_starts_with_cstr_ci(const zend_string *str, const char *prefix, size_t prefix_length) +{ + return ZSTR_LEN(str) >= prefix_length && !strncasecmp(ZSTR_VAL(str), prefix, prefix_length); +} + +static zend_always_inline bool zend_string_starts_with_ci(const zend_string *str, const zend_string *prefix) +{ + return zend_string_starts_with_cstr_ci(str, ZSTR_VAL(prefix), ZSTR_LEN(prefix)); +} + +#define zend_string_starts_with_literal_ci(str, prefix) \ + zend_string_starts_with_cstr(str, prefix, strlen(prefix)) + /* * DJBX33A (Daniel J. Bernstein, Times 33 with Addition) * @@ -593,6 +630,7 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_AUTOGLOBAL_REQUEST, "_REQUEST") \ _(ZEND_STR_COUNT, "count") \ _(ZEND_STR_SENSITIVEPARAMETER, "SensitiveParameter") \ + _(ZEND_STR_CONST_EXPR_PLACEHOLDER, "[constant expression]") \ typedef enum _zend_known_string_id { diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c index 3e7f90378ef5e..8a59196285080 100644 --- a/Zend/zend_strtod.c +++ b/Zend/zend_strtod.c @@ -959,7 +959,7 @@ pow5mult { Bigint *b1, *p5, *p51; int i; - static int p05[3] = { 5, 25, 125 }; + static const int p05[3] = { 5, 25, 125 }; if ((i = k & 3)) b = multadd(b, p05[i-1], 0); diff --git a/Zend/zend_strtod_int.h b/Zend/zend_strtod_int.h index e1cf562d64af6..f528b4753eabb 100644 --- a/Zend/zend_strtod_int.h +++ b/Zend/zend_strtod_int.h @@ -44,22 +44,6 @@ #include -#ifndef HAVE_INT32_T -# if SIZEOF_INT == 4 -typedef int int32_t; -# elif SIZEOF_LONG == 4 -typedef long int int32_t; -# endif -#endif - -#ifndef HAVE_UINT32_T -# if SIZEOF_INT == 4 -typedef unsigned int uint32_t; -# elif SIZEOF_LONG == 4 -typedef unsigned long int uint32_t; -# endif -#endif - #ifdef USE_LOCALE #undef USE_LOCALE #endif diff --git a/Zend/zend_system_id.c b/Zend/zend_system_id.c index 8390bba8b0f25..27adf3fe1a4a2 100644 --- a/Zend/zend_system_id.c +++ b/Zend/zend_system_id.c @@ -63,7 +63,7 @@ void zend_startup_system_id(void) void zend_finalize_system_id(void) { unsigned char digest[16]; - zend_uchar hooks = 0; + uint8_t hooks = 0; if (zend_ast_process) { hooks |= ZEND_HOOK_AST_PROCESS; @@ -80,7 +80,7 @@ void zend_finalize_system_id(void) PHP_MD5Update(&context, &hooks, sizeof hooks); for (int16_t i = 0; i < 256; i++) { - if (zend_get_user_opcode_handler((zend_uchar) i) != NULL) { + if (zend_get_user_opcode_handler((uint8_t) i) != NULL) { PHP_MD5Update(&context, &i, sizeof i); } } diff --git a/Zend/zend_types.h b/Zend/zend_types.h index df64541749d4c..c341ffa0b4d8c 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -25,11 +25,18 @@ #include "zend_portability.h" #include "zend_long.h" #include +#include #ifdef __SSE2__ # include # include #endif +#if defined(__AVX2__) +# include +#endif +#if defined(__aarch64__) || defined(_M_ARM64) +# include +#endif #ifdef WORDS_BIGENDIAN # define ZEND_ENDIAN_LOHI(lo, hi) hi; lo; @@ -47,7 +54,6 @@ # define ZEND_ENDIAN_LOHI_C_4(a, b, c, d) a, b, c, d #endif -typedef bool zend_bool; typedef unsigned char zend_uchar; typedef enum { @@ -71,9 +77,6 @@ typedef ZEND_RESULT_CODE zend_result; # endif #endif -typedef intptr_t zend_intptr_t; -typedef uintptr_t zend_uintptr_t; - #ifdef ZTS #define ZEND_TLS static TSRM_TLS #define ZEND_EXT_TLS TSRM_TLS @@ -318,8 +321,8 @@ struct _zval_struct { uint32_t type_info; struct { ZEND_ENDIAN_LOHI_3( - zend_uchar type, /* active type */ - zend_uchar type_flags, + uint8_t type, /* active type */ + uint8_t type_flags, union { uint16_t extra; /* not further specified */ } u) @@ -370,10 +373,10 @@ struct _zend_array { union { struct { ZEND_ENDIAN_LOHI_4( - zend_uchar flags, - zend_uchar _unused, - zend_uchar nIteratorsCount, - zend_uchar _unused2) + uint8_t flags, + uint8_t _unused, + uint8_t nIteratorsCount, + uint8_t _unused2) } v; uint32_t flags; } u; @@ -411,8 +414,15 @@ struct _zend_array { #define HT_MIN_MASK ((uint32_t) -2) #define HT_MIN_SIZE 8 +/* HT_MAX_SIZE is chosen to satisfy the following constraints: + * - HT_SIZE_TO_MASK(HT_MAX_SIZE) != 0 + * - HT_SIZE_EX(HT_MAX_SIZE, HT_SIZE_TO_MASK(HT_MAX_SIZE)) does not overflow or + * wrapparound, and is <= the addressable space size + * - HT_MAX_SIZE must be a power of two: + * (nTableSizenTableSize, (ht)->nTableMask) #define HT_PACKED_USED_SIZE(ht) \ (HT_HASH_SIZE((ht)->nTableMask) + ((size_t)(ht)->nNumUsed * sizeof(zval))) -#ifdef __SSE2__ +#if defined(__AVX2__) +# define HT_HASH_RESET(ht) do { \ + char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ + size_t size = HT_HASH_SIZE((ht)->nTableMask); \ + __m256i ymm0 = _mm256_setzero_si256(); \ + ymm0 = _mm256_cmpeq_epi64(ymm0, ymm0); \ + ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ + do { \ + _mm256_storeu_si256((__m256i*)p, ymm0); \ + _mm256_storeu_si256((__m256i*)(p+32), ymm0); \ + p += 64; \ + size -= 64; \ + } while (size != 0); \ + } while (0) +#elif defined(__SSE2__) # define HT_HASH_RESET(ht) do { \ char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ size_t size = HT_HASH_SIZE((ht)->nTableMask); \ @@ -472,6 +496,21 @@ struct _zend_array { size -= 64; \ } while (size != 0); \ } while (0) +#elif defined(__aarch64__) || defined(_M_ARM64) +# define HT_HASH_RESET(ht) do { \ + char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \ + size_t size = HT_HASH_SIZE((ht)->nTableMask); \ + int32x4_t t = vdupq_n_s32(-1); \ + ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ + do { \ + vst1q_s32((int32_t*)p, t); \ + vst1q_s32((int32_t*)(p+16), t); \ + vst1q_s32((int32_t*)(p+32), t); \ + vst1q_s32((int32_t*)(p+48), t); \ + p += 64; \ + size -= 64; \ + } while (size != 0); \ + } while (0) #else # define HT_HASH_RESET(ht) \ memset(&HT_HASH(ht, (ht)->nTableMask), HT_INVALID_IDX, HT_HASH_SIZE((ht)->nTableMask)) @@ -571,7 +610,7 @@ struct _zend_ast_ref { #define _IS_BOOL 18 #define _IS_NUMBER 19 -static zend_always_inline zend_uchar zval_get_type(const zval* pz) { +static zend_always_inline uint8_t zval_get_type(const zval* pz) { return pz->u1.v.type; } @@ -634,13 +673,33 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) { #define GC_TRY_ADDREF(p) zend_gc_try_addref(&(p)->gc) #define GC_TRY_DELREF(p) zend_gc_try_delref(&(p)->gc) +#define GC_DTOR(p) \ + do { \ + zend_refcounted_h *_p = &(p)->gc; \ + if (zend_gc_delref(_p) == 0) { \ + rc_dtor_func((zend_refcounted *)_p); \ + } else { \ + gc_check_possible_root((zend_refcounted *)_p); \ + } \ + } while (0) + +#define GC_DTOR_NO_REF(p) \ + do { \ + zend_refcounted_h *_p = &(p)->gc; \ + if (zend_gc_delref(_p) == 0) { \ + rc_dtor_func((zend_refcounted *)_p); \ + } else { \ + gc_check_possible_root_no_ref((zend_refcounted *)_p); \ + } \ + } while (0) + #define GC_TYPE_MASK 0x0000000f #define GC_FLAGS_MASK 0x000003f0 #define GC_INFO_MASK 0xfffffc00 #define GC_FLAGS_SHIFT 0 #define GC_INFO_SHIFT 10 -static zend_always_inline zend_uchar zval_gc_type(uint32_t gc_type_info) { +static zend_always_inline uint8_t zval_gc_type(uint32_t gc_type_info) { return (gc_type_info & GC_TYPE_MASK); } @@ -1172,7 +1231,7 @@ extern ZEND_API bool zend_rc_debug; * Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */ # define ZEND_RC_MOD_CHECK(p) do { \ if (zend_rc_debug) { \ - zend_uchar type = zval_gc_type((p)->u.type_info); \ + uint8_t type = zval_gc_type((p)->u.type_info); \ if (type != IS_OBJECT && type != IS_NULL) { \ ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \ ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \ @@ -1437,7 +1496,8 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) { * (both use IS_UNDEF type) in the Z_EXTRA space. As such we also need to copy * the Z_EXTRA space when copying property default values etc. We define separate * macros for this purpose, so this workaround is easier to remove in the future. */ -#define IS_PROP_UNINIT 1 +#define IS_PROP_UNINIT (1<<0) +#define IS_PROP_REINITABLE (1<<1) /* It has impact only on readonly properties */ #define Z_PROP_FLAG_P(z) Z_EXTRA_P(z) #define ZVAL_COPY_VALUE_PROP(z, v) \ do { *(z) = *(v); } while (0) @@ -1447,4 +1507,9 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) { do { ZVAL_COPY_OR_DUP(z, v); Z_PROP_FLAG_P(z) = Z_PROP_FLAG_P(v); } while (0) +static zend_always_inline bool zend_may_modify_arg_in_place(const zval *arg) +{ + return Z_REFCOUNTED_P(arg) && !(GC_FLAGS(Z_COUNTED_P(arg)) & (GC_IMMUTABLE | GC_PERSISTENT)) && Z_REFCOUNT_P(arg) == 1; +} + #endif /* ZEND_TYPES_H */ diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c index 06483d581df37..27e09d7db22b1 100644 --- a/Zend/zend_variables.c +++ b/Zend/zend_variables.c @@ -37,18 +37,18 @@ static void ZEND_FASTCALL zend_empty_destroy(zend_reference *ref); typedef void (ZEND_FASTCALL *zend_rc_dtor_func_t)(zend_refcounted *p); static const zend_rc_dtor_func_t zend_rc_dtor_func[] = { - /* IS_UNDEF */ (zend_rc_dtor_func_t)zend_empty_destroy, - /* IS_NULL */ (zend_rc_dtor_func_t)zend_empty_destroy, - /* IS_FALSE */ (zend_rc_dtor_func_t)zend_empty_destroy, - /* IS_TRUE */ (zend_rc_dtor_func_t)zend_empty_destroy, - /* IS_LONG */ (zend_rc_dtor_func_t)zend_empty_destroy, - /* IS_DOUBLE */ (zend_rc_dtor_func_t)zend_empty_destroy, - /* IS_STRING */ (zend_rc_dtor_func_t)zend_string_destroy, - /* IS_ARRAY */ (zend_rc_dtor_func_t)zend_array_destroy, - /* IS_OBJECT */ (zend_rc_dtor_func_t)zend_objects_store_del, - /* IS_RESOURCE */ (zend_rc_dtor_func_t)zend_list_free, - /* IS_REFERENCE */ (zend_rc_dtor_func_t)zend_reference_destroy, - /* IS_CONSTANT_AST */ (zend_rc_dtor_func_t)zend_ast_ref_destroy + [IS_UNDEF] = (zend_rc_dtor_func_t)zend_empty_destroy, + [IS_NULL] = (zend_rc_dtor_func_t)zend_empty_destroy, + [IS_FALSE] = (zend_rc_dtor_func_t)zend_empty_destroy, + [IS_TRUE] = (zend_rc_dtor_func_t)zend_empty_destroy, + [IS_LONG] = (zend_rc_dtor_func_t)zend_empty_destroy, + [IS_DOUBLE] = (zend_rc_dtor_func_t)zend_empty_destroy, + [IS_STRING] = (zend_rc_dtor_func_t)zend_string_destroy, + [IS_ARRAY] = (zend_rc_dtor_func_t)zend_array_destroy, + [IS_OBJECT] = (zend_rc_dtor_func_t)zend_objects_store_del, + [IS_RESOURCE] = (zend_rc_dtor_func_t)zend_list_free, + [IS_REFERENCE] = (zend_rc_dtor_func_t)zend_reference_destroy, + [IS_CONSTANT_AST] = (zend_rc_dtor_func_t)zend_ast_ref_destroy }; ZEND_API void ZEND_FASTCALL rc_dtor_func(zend_refcounted *p) diff --git a/Zend/zend_virtual_cwd.c b/Zend/zend_virtual_cwd.c index 64fc165174051..6bff2ad984d02 100644 --- a/Zend/zend_virtual_cwd.c +++ b/Zend/zend_virtual_cwd.c @@ -1009,7 +1009,7 @@ static size_t tsrm_realpath_r(char *path, size_t start, size_t len, int *ll, tim CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath) /* {{{ */ { size_t path_length = strlen(path); - char resolved_path[MAXPATHLEN] = {0}; + char resolved_path[MAXPATHLEN]; size_t start = 1; int ll = 0; time_t t; @@ -1131,6 +1131,9 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func /* skip DRIVE name */ resolved_path[0] = toupper(resolved_path[0]); resolved_path[2] = DEFAULT_SLASH; + if (path_length == 2) { + resolved_path[3] = '\0'; + } start = 3; } #endif diff --git a/Zend/zend_virtual_cwd.h b/Zend/zend_virtual_cwd.h index 728e3ba69d888..f819389af33c7 100644 --- a/Zend/zend_virtual_cwd.h +++ b/Zend/zend_virtual_cwd.h @@ -160,7 +160,7 @@ CWD_API int virtual_cwd_activate(void); CWD_API int virtual_cwd_deactivate(void); CWD_API char *virtual_getcwd_ex(size_t *length); CWD_API char *virtual_getcwd(char *buf, size_t size); -CWD_API int virtual_chdir(const char *path); +CWD_API zend_result virtual_chdir(const char *path); CWD_API int virtual_chdir_file(const char *path, int (*p_chdir)(const char *path)); CWD_API int virtual_filepath(const char *path, char **filepath); CWD_API int virtual_filepath_ex(const char *path, char **filepath, verify_path_func verify_path); @@ -260,7 +260,7 @@ extern void virtual_cwd_main_cwd_init(uint8_t); #define VCWD_OPEN_MODE(path, flags, mode) virtual_open(path, flags, mode) #define VCWD_CREAT(path, mode) virtual_creat(path, mode) #define VCWD_CHDIR(path) virtual_chdir(path) -#define VCWD_CHDIR_FILE(path) virtual_chdir_file(path, virtual_chdir) +#define VCWD_CHDIR_FILE(path) virtual_chdir_file(path, (int (*)(const char *)) virtual_chdir) #define VCWD_GETWD(buf) #define VCWD_REALPATH(path, real_path) virtual_realpath(path, real_path) #define VCWD_RENAME(oldname, newname) virtual_rename(oldname, newname) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 202bc3ad0097e..0b6604217fa35 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -384,6 +384,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (OP1_TYPE != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (OP2_TYPE == IS_CONST || OP2_TYPE == IS_CV) { @@ -412,6 +413,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -420,6 +422,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_ str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -1213,7 +1216,7 @@ ZEND_VM_C_LABEL(assign_dim_op_new_array): } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -1516,7 +1519,7 @@ ZEND_VM_HOT_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY, SPEC(RETVAL)) if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_increment_function(var_ptr); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -1568,7 +1571,7 @@ ZEND_VM_HOT_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY, SPEC(RETVAL)) if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_decrement_function(var_ptr); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -2130,6 +2133,7 @@ ZEND_VM_C_LABEL(fetch_obj_r_fast_copy): #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -2165,7 +2169,7 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, FETCH zend_fetch_property_address( result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -2182,7 +2186,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACH container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); property = GET_OP2_ZVAL_PTR(BP_VAR_R); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -2328,7 +2332,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, C container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_UNSET); property = GET_OP2_ZVAL_PTR(BP_VAR_R); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -2377,6 +2381,7 @@ ZEND_VM_HANDLER(24, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); @@ -2406,11 +2411,11 @@ ZEND_VM_C_LABEL(assign_object): zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); ZEND_VM_C_GOTO(free_and_exit_assign_obj); } else { ZEND_VM_C_LABEL(fast_assign_obj): - value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -2489,11 +2494,14 @@ ZEND_VM_C_LABEL(fast_assign_obj): } ZEND_VM_C_LABEL(free_and_exit_assign_obj): - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } FREE_OP_DATA(); ZEND_VM_C_LABEL(exit_assign_obj): + if (garbage) { + GC_DTOR_NO_REF(garbage); + } FREE_OP2(); FREE_OP1(); /* assign_obj has two opcodes! */ @@ -2506,6 +2514,7 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_STATIC_PROP, ANY, ANY, CACHE_SLOT, SPEC(OP_DATA= USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -2518,16 +2527,20 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_STATIC_PROP, ANY, ANY, CACHE_SLOT, SPEC(OP_DATA= value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); FREE_OP_DATA(); } else { - value = zend_assign_to_variable(prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -2539,6 +2552,7 @@ ZEND_VM_HANDLER(23, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, SPEC(O zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); @@ -2594,11 +2608,14 @@ ZEND_VM_C_LABEL(try_assign_dim_array): ZEND_VM_C_GOTO(assign_dim_error); } value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); - value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -2650,7 +2667,7 @@ ZEND_VM_C_LABEL(try_assign_dim_array): UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -2691,9 +2708,18 @@ ZEND_VM_HANDLER(22, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV, SPEC(RETVAL)) value = GET_OP2_ZVAL_PTR(BP_VAR_R); variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); - value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE, EX_USES_STRICT_TYPES()); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (!ZEND_VM_SPEC || UNEXPECTED(RETURN_VALUE_USED(opline))) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, OP2_TYPE, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE, EX_USES_STRICT_TYPES()); } FREE_OP1(); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -2706,6 +2732,7 @@ ZEND_VM_HANDLER(30, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = GET_OP2_ZVAL_PTR_PTR(BP_VAR_W); @@ -2721,15 +2748,19 @@ ZEND_VM_HANDLER(30, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) UNEXPECTED(!Z_ISREF_P(value_ptr))) { variable_ptr = zend_wrong_assign_to_variable_reference( - variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); + variable_ptr, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + FREE_OP2(); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -2777,6 +2808,7 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC) USE_OPLINE zval *prop, *value_ptr; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -2789,19 +2821,23 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC) value_ptr = GET_OP_DATA_ZVAL_PTR_PTR(BP_VAR_W); if (OP_DATA_TYPE == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(prop, value_ptr OPLINE_CC EXECUTE_DATA_CC))) { + if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(prop, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC))) { prop = &EG(uninitialized_zval); } } else if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - prop = zend_assign_to_typed_property_reference(prop_info, prop, value_ptr EXECUTE_DATA_CC); + prop = zend_assign_to_typed_property_reference(prop_info, prop, value_ptr, &garbage EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(prop, value_ptr); + zend_assign_to_variable_reference(prop, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), prop); } + if (garbage) { + GC_DTOR(garbage); + } + FREE_OP_DATA(); ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -2956,7 +2992,7 @@ ZEND_VM_HOT_NOCONST_HANDLER(43, ZEND_JMPZ, CONST|TMPVAR|CV, JMP_ADDR) { USE_OPLINE zval *val; - zend_uchar op1_type; + uint8_t op1_type; val = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); @@ -2990,7 +3026,7 @@ ZEND_VM_HOT_NOCONST_HANDLER(44, ZEND_JMPNZ, CONST|TMPVAR|CV, JMP_ADDR) { USE_OPLINE zval *val; - zend_uchar op1_type; + uint8_t op1_type; val = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); @@ -3139,6 +3175,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (OP1_TYPE != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (OP2_TYPE == IS_CONST || OP2_TYPE == IS_CV) { @@ -3164,6 +3201,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -3172,6 +3210,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -3232,6 +3271,8 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (OP1_TYPE != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -3321,8 +3362,6 @@ ZEND_VM_HANDLER(56, ZEND_ROPE_END, TMP, CONST|TMPVAR|CV, NUM) zend_string **rope; zval *var, *ret; uint32_t i; - size_t len = 0; - char *target; rope = (zend_string**)EX_VAR(opline->op1.var); if (OP2_TYPE == IS_CONST) { @@ -3355,12 +3394,18 @@ ZEND_VM_HANDLER(56, ZEND_ROPE_END, TMP, CONST|TMPVAR|CV, NUM) } } } + + size_t len = 0; + uint32_t flags = ZSTR_COPYABLE_CONCAT_PROPERTIES; for (i = 0; i <= opline->extended_value; i++) { + flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(rope[i]); len += ZSTR_LEN(rope[i]); } ret = EX_VAR(opline->result.var); ZVAL_STR(ret, zend_string_alloc(len, 0)); - target = Z_STRVAL_P(ret); + GC_ADD_FLAGS(Z_STR_P(ret), flags); + + char *target = Z_STRVAL_P(ret); for (i = 0; i <= opline->extended_value; i++) { memcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i])); target += ZSTR_LEN(rope[i]); @@ -5263,7 +5308,7 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY, NUM) ZEND_VM_C_GOTO(send_array); } } - zend_type_error("call_user_func_array(): Argument #2 ($args) must be of type array, %s given", zend_zval_type_name(args)); + zend_type_error("call_user_func_array(): Argument #2 ($args) must be of type array, %s given", zend_zval_value_name(args)); FREE_OP2(); FREE_OP1(); HANDLE_EXCEPTION(); @@ -5289,7 +5334,7 @@ ZEND_VM_C_LABEL(send_array): || !zend_parse_arg_long_weak(op2, &len, /* arg_num */ 3)) { zend_type_error( "array_slice(): Argument #3 ($length) must be of type ?int, %s given", - zend_zval_type_name(op2)); + zend_zval_value_name(op2)); FREE_OP2(); FREE_OP1(); HANDLE_EXCEPTION(); @@ -5855,58 +5900,84 @@ ZEND_VM_HOT_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED|CONST_FETCH, CONST, CACHE_SL ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CONST, CACHE_SLOT) +ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CONST|TMPVARCV, CACHE_SLOT) { zend_class_entry *ce, *scope; zend_class_constant *c; - zval *value, *zv; + zval *value, *zv, *constant_zv; + zend_string *constant_name; USE_OPLINE SAVE_OPLINE(); do { - if (OP1_TYPE == IS_CONST) { + if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { if (EXPECTED(CACHED_PTR(opline->extended_value + sizeof(void*)))) { value = CACHED_PTR(opline->extended_value + sizeof(void*)); break; - } else if (EXPECTED(CACHED_PTR(opline->extended_value))) { + } + } + if (OP1_TYPE == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value))) { ce = CACHED_PTR(opline->extended_value); } else { ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(ce == NULL)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP2(); HANDLE_EXCEPTION(); } + CACHE_PTR(opline->extended_value, ce); } - } else { - if (OP1_TYPE == IS_UNUSED) { - ce = zend_fetch_class(NULL, opline->op1.num); - if (UNEXPECTED(ce == NULL)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - HANDLE_EXCEPTION(); - } - } else { - ce = Z_CE_P(EX_VAR(opline->op1.var)); - } - if (EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { - value = CACHED_PTR(opline->extended_value + sizeof(void*)); - break; + } else if (OP1_TYPE == IS_UNUSED) { + ce = zend_fetch_class(NULL, opline->op1.num); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP2(); + HANDLE_EXCEPTION(); } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); + } + if (OP1_TYPE != IS_CONST + && OP2_TYPE == IS_CONST + && EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + + constant_zv = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); + if (UNEXPECTED(Z_TYPE_P(constant_zv) != IS_STRING)) { + zend_invalid_class_constant_type_error(Z_TYPE_P(constant_zv)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP2(); + HANDLE_EXCEPTION(); } + constant_name = Z_STR_P(constant_zv); + /* Magic 'class' for constant OP2 is caught at compile-time */ + if (OP2_TYPE != IS_CONST && UNEXPECTED(zend_string_equals_literal_ci(constant_name, "class"))) { + ZVAL_STR_COPY(EX_VAR(opline->result.var), ce->name); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } + zv = OP2_TYPE == IS_CONST + ? zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), constant_name) + : zend_hash_find(CE_CONSTANTS_TABLE(ce), constant_name); - zv = zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2))); if (EXPECTED(zv != NULL)) { c = Z_PTR_P(zv); scope = EX(func)->op_array.scope; if (!zend_verify_const_access(c, scope)) { - zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP2(); HANDLE_EXCEPTION(); } if (ce->ce_flags & ZEND_ACC_TRAIT) { - zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP2(); HANDLE_EXCEPTION(); } @@ -5915,27 +5986,32 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP2(); HANDLE_EXCEPTION(); } } if (Z_TYPE_P(value) == IS_CONSTANT_AST) { - zval_update_constant_ex(value, c->ce); - if (UNEXPECTED(EG(exception) != NULL)) { + if (UNEXPECTED(zend_update_class_constant(c, constant_name, c->ce) != SUCCESS)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP2(); HANDLE_EXCEPTION(); } } - CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + if (OP2_TYPE == IS_CONST) { + CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + } } else { zend_throw_error(NULL, "Undefined constant %s::%s", - ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP2(); HANDLE_EXCEPTION(); } } while (0); ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), value); + FREE_OP2(); ZEND_VM_NEXT_OPCODE(); } @@ -6022,7 +6098,7 @@ ZEND_VM_C_LABEL(num_index): str = ZSTR_EMPTY_ALLOC(); ZEND_VM_C_GOTO(str_index); } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } FREE_OP2(); @@ -6051,7 +6127,7 @@ ZEND_VM_C_LABEL(add_unpack_again): zval *val; if (HT_IS_PACKED(ht) && (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { - zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); + zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1); ZEND_HASH_FILL_PACKED(result_ht) { ZEND_HASH_PACKED_FOREACH_VAL(ht, val) { if (UNEXPECTED(Z_ISREF_P(val)) && @@ -6378,11 +6454,7 @@ ZEND_VM_HANDLER(153, ZEND_UNSET_CV, CV, UNUSED) ZVAL_UNDEF(var); SAVE_OPLINE(); - if (!GC_DELREF(garbage)) { - rc_dtor_func(garbage); - } else { - gc_check_possible_root(garbage); - } + GC_DTOR(garbage); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { ZVAL_UNDEF(var); @@ -6538,7 +6610,7 @@ ZEND_VM_C_LABEL(num_index_dim): key = ZSTR_EMPTY_ALLOC(); ZEND_VM_C_GOTO(str_index_dim); } else { - zend_type_error("Illegal offset type in unset"); + zend_illegal_unset_offset(offset); } break; } else if (Z_ISREF_P(container)) { @@ -6678,7 +6750,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, JMP_ADDR) } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; FREE_OP1(); @@ -6768,7 +6840,7 @@ ZEND_VM_COLD_CONST_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR) } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; FREE_OP1(); @@ -7142,7 +7214,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) value_type = Z_TYPE_INFO_P(value); } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array)); if (UNEXPECTED(EG(exception))) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -7928,6 +8000,12 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) { const zend_op *throw_op = EG(opline_before_exception); + + /* Exception was thrown before executing any op */ + if (UNEXPECTED(!throw_op)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, -1, 0, 0); + } + uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; int i, current_try_catch_offset = -1; @@ -8019,7 +8097,7 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY) case ZEND_USER_OPCODE_DISPATCH: ZEND_VM_DISPATCH(opline->opcode, opline); default: - ZEND_VM_DISPATCH((zend_uchar)(ret & 0xff), opline); + ZEND_VM_DISPATCH((uint8_t)(ret & 0xff), opline); } } @@ -8045,9 +8123,8 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST) } /* non persistent, case sensitive */ ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT); - c.name = zend_string_copy(Z_STR_P(name)); - if (zend_register_constant(&c) == FAILURE) { + if (zend_register_constant(Z_STR_P(name), &c) == FAILURE) { } FREE_OP1(); @@ -8196,7 +8273,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMPVAR|CV|UNUSED /* Set the new yielded key */ if (OP2_TYPE != IS_UNUSED) { zval *key = GET_OP2_ZVAL_PTR(BP_VAR_R); - if ((OP2_TYPE & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((OP2_TYPE & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -8527,7 +8604,7 @@ ZEND_VM_COLD_CONST_HANDLER(121, ZEND_STRLEN, CONST|TMPVAR|CV, ANY) zval_ptr_dtor(&tmp); } if (!EG(exception)) { - zend_type_error("strlen(): Argument #1 ($str) must be of type string, %s given", zend_zval_type_name(value)); + zend_type_error("strlen(): Argument #1 ($string) must be of type string, %s given", zend_zval_value_name(value)); } ZVAL_UNDEF(EX_VAR(opline->result.var)); } while (0); @@ -8622,7 +8699,7 @@ ZEND_VM_HANDLER(157, ZEND_FETCH_CLASS_NAME, CV|TMPVAR|UNUSED|CLASS_FETCH, ANY) if (UNEXPECTED(Z_TYPE_P(op) != IS_OBJECT)) { ZVAL_DEREF(op); if (Z_TYPE_P(op) != IS_OBJECT) { - zend_type_error("Cannot use \"::class\" on value of type %s", zend_zval_type_name(op)); + zend_type_error("Cannot use \"::class\" on %s", zend_zval_value_name(op)); ZVAL_UNDEF(EX_VAR(opline->result.var)); FREE_OP1(); HANDLE_EXCEPTION(); @@ -8739,7 +8816,9 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER)) SAVE_OPLINE_EX(); ZEND_OBSERVER_FCALL_BEGIN(execute_data); execute_data = EX(prev_execute_data); - LOAD_OPLINE(); + if (execute_data) { + LOAD_OPLINE(); + } ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } @@ -8791,7 +8870,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER)) execute_data = EG(current_execute_data); - if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { + if (!execute_data || !EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { ZEND_VM_RETURN(); } @@ -9203,7 +9282,7 @@ ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMPVAR|CV, UNUSED) ZVAL_UNDEFINED_OP1(); } count = 0; - zend_type_error("%s(): Argument #1 ($value) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1)); + zend_type_error("%s(): Argument #1 ($value) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_value_name(op1)); break; } @@ -9241,7 +9320,7 @@ ZEND_VM_COLD_CONST_HANDLER(191, ZEND_GET_CLASS, UNUSED|CONST|TMPVAR|CV, UNUSED) if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_type_name(op1)); + zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(op1)); ZVAL_UNDEF(EX_VAR(opline->result.var)); } break; @@ -9647,7 +9726,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (res_info == MAY_BE_LONG && op1_info var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); Z_LVAL_P(var_ptr)++; - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); } ZEND_VM_NEXT_OPCODE(); @@ -9660,7 +9739,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == MAY_BE_LONG), ZEND_PRE_ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); fast_long_increment_function(var_ptr); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -9673,7 +9752,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (res_info == MAY_BE_LONG && op1_info var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); Z_LVAL_P(var_ptr)--; - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); } ZEND_VM_NEXT_OPCODE(); @@ -9686,7 +9765,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == MAY_BE_LONG), ZEND_PRE_ var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); fast_long_decrement_function(var_ptr); - if (RETURN_VALUE_USED(opline)) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 7d1545ba0fce1..21b927c02b895 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -287,7 +287,7 @@ static user_opcode_handler_t zend_user_opcode_handlers[256] = { (user_opcode_handler_t)NULL }; -static zend_uchar zend_user_opcodes[256] = {0, +static uint8_t zend_user_opcodes[256] = {0, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, @@ -326,11 +326,11 @@ static const void * const * zend_opcode_handler_funcs; static zend_op hybrid_halt_op; #endif #if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC -static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op); +static const void *zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op); #endif #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) -static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op); +static const void *zend_vm_get_opcode_handler_func(uint8_t opcode, const zend_op* op); #else # define zend_vm_get_opcode_handler_func zend_vm_get_opcode_handler #endif @@ -927,6 +927,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -939,16 +940,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT value = RT_CONSTANT((opline+1), (opline+1)->op1); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); } else { - value = zend_assign_to_variable(prop, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(prop, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -958,6 +963,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -970,16 +976,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } else { - value = zend_assign_to_variable(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -989,6 +999,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -1001,16 +1012,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } else { - value = zend_assign_to_variable(prop, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(prop, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -1020,6 +1035,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -1032,16 +1048,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value, &garbage EXECUTE_DATA_CC); } else { - value = zend_assign_to_variable(prop, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(prop, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -1051,6 +1071,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_REF_SPEC_HA USE_OPLINE zval *prop, *value_ptr; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -1063,19 +1084,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_REF_SPEC_HA value_ptr = get_zval_ptr_ptr((opline+1)->op1_type, (opline+1)->op1, BP_VAR_W); if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(prop, value_ptr OPLINE_CC EXECUTE_DATA_CC))) { + if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(prop, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC))) { prop = &EG(uninitialized_zval); } } else if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - prop = zend_assign_to_typed_property_reference(prop_info, prop, value_ptr EXECUTE_DATA_CC); + prop = zend_assign_to_typed_property_reference(prop_info, prop, value_ptr, &garbage EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(prop, value_ptr); + zend_assign_to_variable_reference(prop, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), prop); } + if (garbage) { + GC_DTOR(garbage); + } + FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -2421,7 +2446,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O goto send_array; } } - zend_type_error("call_user_func_array(): Argument #2 ($args) must be of type array, %s given", zend_zval_type_name(args)); + zend_type_error("call_user_func_array(): Argument #2 ($args) must be of type array, %s given", zend_zval_value_name(args)); FREE_OP(opline->op2_type, opline->op2.var); FREE_OP(opline->op1_type, opline->op1.var); HANDLE_EXCEPTION(); @@ -2447,7 +2472,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O || !zend_parse_arg_long_weak(op2, &len, /* arg_num */ 3)) { zend_type_error( "array_slice(): Argument #3 ($length) must be of type ?int, %s given", - zend_zval_type_name(op2)); + zend_zval_value_name(op2)); FREE_OP(opline->op2_type, opline->op2.var); FREE_OP(opline->op1_type, opline->op1.var); HANDLE_EXCEPTION(); @@ -2627,7 +2652,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_UNPACK_SPEC_HANDLER( zval *val; if (HT_IS_PACKED(ht) && (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { - zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); + zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1); ZEND_HASH_FILL_PACKED(result_ht) { ZEND_HASH_PACKED_FOREACH_VAL(ht, val) { if (UNEXPECTED(Z_ISREF_P(val)) && @@ -3181,6 +3206,12 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { const zend_op *throw_op = EG(opline_before_exception); + + /* Exception was thrown before executing any op */ + if (UNEXPECTED(!throw_op)) { + ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(-1, 0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + } + uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; int i, current_try_catch_offset = -1; @@ -3272,7 +3303,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_ case ZEND_USER_OPCODE_DISPATCH: ZEND_VM_DISPATCH(opline->opcode, opline); default: - ZEND_VM_DISPATCH((zend_uchar)(ret & 0xff), opline); + ZEND_VM_DISPATCH((uint8_t)(ret & 0xff), opline); } } @@ -3425,7 +3456,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z SAVE_OPLINE_EX(); execute_data = EX(prev_execute_data); - LOAD_OPLINE(); + if (execute_data) { + LOAD_OPLINE(); + } ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } @@ -3476,7 +3509,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z execute_data = EG(current_execute_data); - if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { + if (!execute_data || !EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { ZEND_VM_RETURN(); } @@ -3563,7 +3596,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_ SAVE_OPLINE_EX(); zend_observer_fcall_begin(execute_data); execute_data = EX(prev_execute_data); - LOAD_OPLINE(); + if (execute_data) { + LOAD_OPLINE(); + } ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); } @@ -3615,7 +3650,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_ execute_data = EG(current_execute_data); - if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { + if (!execute_data || !EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) { ZEND_VM_RETURN(); } @@ -4131,7 +4166,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPZ_SPEC_CONST_H { USE_OPLINE zval *val; - zend_uchar op1_type; + uint8_t op1_type; val = RT_CONSTANT(opline, opline->op1); @@ -4165,7 +4200,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPNZ_SPEC_CONST_ { USE_OPLINE zval *val; - zend_uchar op1_type; + uint8_t op1_type; val = RT_CONSTANT(opline, opline->op1); @@ -5152,7 +5187,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CONST_HANDLER( } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; @@ -5241,7 +5276,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_ } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; @@ -5610,7 +5645,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_STRLEN_SPEC_CONST zval_ptr_dtor(&tmp); } if (!EG(exception)) { - zend_type_error("strlen(): Argument #1 ($str) must be of type string, %s given", zend_zval_type_name(value)); + zend_type_error("strlen(): Argument #1 ($string) must be of type string, %s given", zend_zval_value_name(value)); } ZVAL_UNDEF(EX_VAR(opline->result.var)); } while (0); @@ -6436,6 +6471,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_ #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -6613,6 +6649,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CONST != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CONST == IS_CONST || IS_CONST == IS_CV) { @@ -6638,6 +6675,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -6646,6 +6684,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -6706,6 +6745,8 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_ str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -7137,54 +7178,80 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS { zend_class_entry *ce, *scope; zend_class_constant *c; - zval *value, *zv; + zval *value, *zv, *constant_zv; + zend_string *constant_name; USE_OPLINE SAVE_OPLINE(); do { - if (IS_CONST == IS_CONST) { + if (IS_CONST == IS_CONST && IS_CONST == IS_CONST) { if (EXPECTED(CACHED_PTR(opline->extended_value + sizeof(void*)))) { value = CACHED_PTR(opline->extended_value + sizeof(void*)); break; - } else if (EXPECTED(CACHED_PTR(opline->extended_value))) { + } + } + if (IS_CONST == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value))) { ce = CACHED_PTR(opline->extended_value); } else { ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(ce == NULL)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } + CACHE_PTR(opline->extended_value, ce); } - } else { - if (IS_CONST == IS_UNUSED) { - ce = zend_fetch_class(NULL, opline->op1.num); - if (UNEXPECTED(ce == NULL)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - HANDLE_EXCEPTION(); - } - } else { - ce = Z_CE_P(EX_VAR(opline->op1.var)); - } - if (EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { - value = CACHED_PTR(opline->extended_value + sizeof(void*)); - break; + } else if (IS_CONST == IS_UNUSED) { + ce = zend_fetch_class(NULL, opline->op1.num); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + + HANDLE_EXCEPTION(); } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); + } + if (IS_CONST != IS_CONST + && IS_CONST == IS_CONST + && EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + + constant_zv = RT_CONSTANT(opline, opline->op2); + if (UNEXPECTED(Z_TYPE_P(constant_zv) != IS_STRING)) { + zend_invalid_class_constant_type_error(Z_TYPE_P(constant_zv)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + + HANDLE_EXCEPTION(); + } + constant_name = Z_STR_P(constant_zv); + /* Magic 'class' for constant OP2 is caught at compile-time */ + if (IS_CONST != IS_CONST && UNEXPECTED(zend_string_equals_literal_ci(constant_name, "class"))) { + ZVAL_STR_COPY(EX_VAR(opline->result.var), ce->name); + + ZEND_VM_NEXT_OPCODE(); } + zv = IS_CONST == IS_CONST + ? zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), constant_name) + : zend_hash_find(CE_CONSTANTS_TABLE(ce), constant_name); - zv = zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2))); if (EXPECTED(zv != NULL)) { c = Z_PTR_P(zv); scope = EX(func)->op_array.scope; if (!zend_verify_const_access(c, scope)) { - zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } if (ce->ce_flags & ZEND_ACC_TRAIT) { - zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } @@ -7193,21 +7260,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } if (Z_TYPE_P(value) == IS_CONSTANT_AST) { - zval_update_constant_ex(value, c->ce); - if (UNEXPECTED(EG(exception) != NULL)) { + if (UNEXPECTED(zend_update_class_constant(c, constant_name, c->ce) != SUCCESS)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } - CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + if (IS_CONST == IS_CONST) { + CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + } } else { zend_throw_error(NULL, "Undefined constant %s::%s", - ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } while (0); @@ -7300,7 +7371,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_C str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -7538,9 +7609,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CONST_SPEC_CONST_CONST } /* non persistent, case sensitive */ ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT); - c.name = zend_string_copy(Z_STR_P(name)); - if (zend_register_constant(&c) == FAILURE) { + if (zend_register_constant(Z_STR_P(name), &c) == FAILURE) { } @@ -7634,7 +7704,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER /* Set the new yielded key */ if (IS_CONST != IS_UNUSED) { zval *key = RT_CONSTANT(opline, opline->op2); - if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -8257,6 +8327,121 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_SMALLER_OR_EQUA ZEND_VM_TAIL_CALL(zend_is_smaller_or_equal_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_class_entry *ce, *scope; + zend_class_constant *c; + zval *value, *zv, *constant_zv; + zend_string *constant_name; + USE_OPLINE + + SAVE_OPLINE(); + + do { + if (IS_CONST == IS_CONST && (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value + sizeof(void*)))) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + } + if (IS_CONST == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value))) { + ce = CACHED_PTR(opline->extended_value); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + CACHE_PTR(opline->extended_value, ce); + } + } else if (IS_CONST == IS_UNUSED) { + ce = zend_fetch_class(NULL, opline->op1.num); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); + } + if (IS_CONST != IS_CONST + && (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST + && EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + + constant_zv = _get_zval_ptr_tmpvarcv(opline->op2_type, opline->op2, BP_VAR_R EXECUTE_DATA_CC); + if (UNEXPECTED(Z_TYPE_P(constant_zv) != IS_STRING)) { + zend_invalid_class_constant_type_error(Z_TYPE_P(constant_zv)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + constant_name = Z_STR_P(constant_zv); + /* Magic 'class' for constant OP2 is caught at compile-time */ + if ((IS_TMP_VAR|IS_VAR|IS_CV) != IS_CONST && UNEXPECTED(zend_string_equals_literal_ci(constant_name, "class"))) { + ZVAL_STR_COPY(EX_VAR(opline->result.var), ce->name); + FREE_OP(opline->op2_type, opline->op2.var); + ZEND_VM_NEXT_OPCODE(); + } + zv = (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST + ? zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), constant_name) + : zend_hash_find(CE_CONSTANTS_TABLE(ce), constant_name); + + if (EXPECTED(zv != NULL)) { + c = Z_PTR_P(zv); + scope = EX(func)->op_array.scope; + if (!zend_verify_const_access(c, scope)) { + zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + + if (ce->ce_flags & ZEND_ACC_TRAIT) { + zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + + value = &c->value; + // Enums require loading of all class constants to build the backed enum table + if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { + if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } + if (Z_TYPE_P(value) == IS_CONSTANT_AST) { + if (UNEXPECTED(zend_update_class_constant(c, constant_name, c->ce) != SUCCESS)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } + if ((IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST) { + CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + } + } else { + zend_throw_error(NULL, "Undefined constant %s::%s", + ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } while (0); + + ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), value); + + FREE_OP(opline->op2_type, opline->op2.var); + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -8533,6 +8718,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CONST != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if ((IS_TMP_VAR|IS_VAR) == IS_CONST || (IS_TMP_VAR|IS_VAR) == IS_CV) { @@ -8561,6 +8747,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -8569,6 +8756,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_TMPVAR_HANDL str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -8780,6 +8968,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_ #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -8957,6 +9146,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CONST != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if ((IS_TMP_VAR|IS_VAR) == IS_CONST || (IS_TMP_VAR|IS_VAR) == IS_CV) { @@ -8982,6 +9172,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -8990,6 +9181,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -9050,6 +9242,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_ str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -9496,7 +9690,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_T str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -9780,7 +9974,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMPVAR_HANDLE /* Set the new yielded key */ if ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) { zval *key = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); - if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -10419,7 +10613,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_U str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -10623,7 +10817,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLE /* Set the new yielded key */ if (IS_UNUSED != IS_UNUSED) { zval *key = NULL; - if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -10716,7 +10910,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CONST_ ZVAL_UNDEFINED_OP1(); } count = 0; - zend_type_error("%s(): Argument #1 ($value) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1)); + zend_type_error("%s(): Argument #1 ($value) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_value_name(op1)); break; } @@ -10754,7 +10948,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GET_CLASS_SPEC_CO if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_type_name(op1)); + zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(op1)); ZVAL_UNDEF(EX_VAR(opline->result.var)); } break; @@ -10898,6 +11092,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CONST != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CV == IS_CONST || IS_CV == IS_CV) { @@ -10926,6 +11121,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -10934,6 +11130,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CONST_CV_HANDLER(Z str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -11145,6 +11342,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_ #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -11322,6 +11520,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CONST != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CV == IS_CONST || IS_CV == IS_CV) { @@ -11347,6 +11546,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -11355,6 +11555,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -11415,6 +11616,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HAND str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -11860,7 +12063,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_C str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -12143,7 +12346,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZE /* Set the new yielded key */ if (IS_CV != IS_UNUSED) { zval *key = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -14243,7 +14446,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPZ_SPEC_TMPVAR_H { USE_OPLINE zval *val; - zend_uchar op1_type; + uint8_t op1_type; val = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -14277,7 +14480,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPNZ_SPEC_TMPVAR_ { USE_OPLINE zval *val; - zend_uchar op1_type; + uint8_t op1_type; val = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -14780,7 +14983,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_STRLEN_SPEC_TMPVAR_HANDLER(ZEN zval_ptr_dtor(&tmp); } if (!EG(exception)) { - zend_type_error("strlen(): Argument #1 ($str) must be of type string, %s given", zend_zval_type_name(value)); + zend_type_error("strlen(): Argument #1 ($string) must be of type string, %s given", zend_zval_value_name(value)); } ZVAL_UNDEF(EX_VAR(opline->result.var)); } while (0); @@ -14837,7 +15040,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_NAME_SPEC_TMPVAR_H if (UNEXPECTED(Z_TYPE_P(op) != IS_OBJECT)) { ZVAL_DEREF(op); if (Z_TYPE_P(op) != IS_OBJECT) { - zend_type_error("Cannot use \"::class\" on value of type %s", zend_zval_type_name(op)); + zend_type_error("Cannot use \"::class\" on %s", zend_zval_value_name(op)); ZVAL_UNDEF(EX_VAR(opline->result.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); HANDLE_EXCEPTION(); @@ -14928,6 +15131,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CONST == IS_CONST || IS_CONST == IS_CV) { @@ -14956,6 +15160,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -14964,6 +15169,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CONST_HANDL str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -15518,6 +15724,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMPVAR_CONST_ #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -15666,6 +15873,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CONST == IS_CONST || IS_CONST == IS_CV) { @@ -15691,6 +15899,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -15699,6 +15908,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -15759,6 +15969,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_ str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -16364,6 +16576,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if ((IS_TMP_VAR|IS_VAR) == IS_CONST || (IS_TMP_VAR|IS_VAR) == IS_CV) { @@ -16392,6 +16605,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -16400,6 +16614,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_TMPVAR_HAND str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -16954,6 +17169,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMPVAR_TMPVAR #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -17102,6 +17318,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if ((IS_TMP_VAR|IS_VAR) == IS_CONST || (IS_TMP_VAR|IS_VAR) == IS_CV) { @@ -17127,6 +17344,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -17135,6 +17353,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -17195,6 +17414,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -17953,7 +18174,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_TMPVAR_UNUSED_HANDL ZVAL_UNDEFINED_OP1(); } count = 0; - zend_type_error("%s(): Argument #1 ($value) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1)); + zend_type_error("%s(): Argument #1 ($value) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_value_name(op1)); break; } @@ -17991,7 +18212,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GET_CLASS_SPEC_TMPVAR_UNUSED_H if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_type_name(op1)); + zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(op1)); ZVAL_UNDEF(EX_VAR(opline->result.var)); } break; @@ -18051,6 +18272,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CV == IS_CONST || IS_CV == IS_CV) { @@ -18079,6 +18301,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -18087,6 +18310,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_TMPVAR_CV_HANDLER( str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -18279,6 +18503,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMPVAR_CV_HAN #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -18427,6 +18652,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CV == IS_CONST || IS_CV == IS_CV) { @@ -18452,6 +18678,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -18460,6 +18687,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -18520,6 +18748,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HAN str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -19260,7 +19490,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_TMP_HANDLER(ZE } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); @@ -19349,7 +19579,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(Z } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); @@ -19659,8 +19889,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_CONST_HANDLE zend_string **rope; zval *var, *ret; uint32_t i; - size_t len = 0; - char *target; rope = (zend_string**)EX_VAR(opline->op1.var); if (IS_CONST == IS_CONST) { @@ -19693,12 +19921,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_CONST_HANDLE } } } + + size_t len = 0; + uint32_t flags = ZSTR_COPYABLE_CONCAT_PROPERTIES; for (i = 0; i <= opline->extended_value; i++) { + flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(rope[i]); len += ZSTR_LEN(rope[i]); } ret = EX_VAR(opline->result.var); ZVAL_STR(ret, zend_string_alloc(len, 0)); - target = Z_STRVAL_P(ret); + GC_ADD_FLAGS(Z_STR_P(ret), flags); + + char *target = Z_STRVAL_P(ret); for (i = 0; i <= opline->extended_value; i++) { memcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i])); target += ZSTR_LEN(rope[i]); @@ -19829,7 +20063,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CON str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -19951,7 +20185,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(Z /* Set the new yielded key */ if (IS_CONST != IS_UNUSED) { zval *key = RT_CONSTANT(opline, opline->op2); - if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -20136,8 +20370,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_TMPVAR_HANDL zend_string **rope; zval *var, *ret; uint32_t i; - size_t len = 0; - char *target; rope = (zend_string**)EX_VAR(opline->op1.var); if ((IS_TMP_VAR|IS_VAR) == IS_CONST) { @@ -20170,12 +20402,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_TMPVAR_HANDL } } } + + size_t len = 0; + uint32_t flags = ZSTR_COPYABLE_CONCAT_PROPERTIES; for (i = 0; i <= opline->extended_value; i++) { + flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(rope[i]); len += ZSTR_LEN(rope[i]); } ret = EX_VAR(opline->result.var); ZVAL_STR(ret, zend_string_alloc(len, 0)); - target = Z_STRVAL_P(ret); + GC_ADD_FLAGS(Z_STR_P(ret), flags); + + char *target = Z_STRVAL_P(ret); for (i = 0; i <= opline->extended_value; i++) { memcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i])); target += ZSTR_LEN(rope[i]); @@ -20269,7 +20507,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_TMP str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -20391,7 +20629,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMPVAR_HANDLER( /* Set the new yielded key */ if ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) { zval *key = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); - if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -20730,7 +20968,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_UNU str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -20852,7 +21090,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER( /* Set the new yielded key */ if (IS_UNUSED != IS_UNUSED) { zval *key = NULL; - if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -20997,8 +21235,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_CV_HANDLER(Z zend_string **rope; zval *var, *ret; uint32_t i; - size_t len = 0; - char *target; rope = (zend_string**)EX_VAR(opline->op1.var); if (IS_CV == IS_CONST) { @@ -21031,12 +21267,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_CV_HANDLER(Z } } } + + size_t len = 0; + uint32_t flags = ZSTR_COPYABLE_CONCAT_PROPERTIES; for (i = 0; i <= opline->extended_value; i++) { + flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(rope[i]); len += ZSTR_LEN(rope[i]); } ret = EX_VAR(opline->result.var); ZVAL_STR(ret, zend_string_alloc(len, 0)); - target = Z_STRVAL_P(ret); + GC_ADD_FLAGS(Z_STR_P(ret), flags); + + char *target = Z_STRVAL_P(ret); for (i = 0; i <= opline->extended_value; i++) { memcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i])); target += ZSTR_LEN(rope[i]); @@ -21130,7 +21372,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CV_ str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -21252,7 +21494,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND /* Set the new yielded key */ if (IS_CV != IS_UNUSED) { zval *key = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -21362,7 +21604,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_VAR_R if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_increment_function(var_ptr); - if (0) { + if (UNEXPECTED(0)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -21380,7 +21622,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_VAR_R if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_increment_function(var_ptr); - if (1) { + if (UNEXPECTED(1)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -21432,7 +21674,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_SPEC_VAR_R if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_decrement_function(var_ptr); - if (0) { + if (UNEXPECTED(0)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -21450,7 +21692,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_SPEC_VAR_R if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_decrement_function(var_ptr); - if (1) { + if (UNEXPECTED(1)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -21916,7 +22158,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_VAR_HANDLER(ZE } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); @@ -22006,7 +22248,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(Z } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); @@ -22262,7 +22504,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(Z value_type = Z_TYPE_INFO_P(value); } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array)); if (UNEXPECTED(EG(exception))) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -22692,7 +22934,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CONST_H } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -22964,7 +23206,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_CONST_HAN zend_fetch_property_address( result, container, IS_VAR, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -22981,7 +23223,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_VAR_CONST_HA container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); property = RT_CONSTANT(opline, opline->op2); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_VAR, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_VAR, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -23015,7 +23257,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CONST container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); property = RT_CONSTANT(opline, opline->op2); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_VAR, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_VAR, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -23051,6 +23293,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23080,11 +23323,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -23163,11 +23406,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -23181,6 +23427,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23210,11 +23457,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -23293,11 +23540,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -23311,6 +23561,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23340,11 +23591,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -23423,11 +23674,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -23441,6 +23695,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23470,11 +23725,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -23553,11 +23808,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -23572,6 +23830,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23627,11 +23886,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -23682,7 +23944,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -23720,6 +23982,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23775,11 +24038,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -23831,7 +24097,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -23869,6 +24135,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23924,11 +24191,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -23980,7 +24250,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -24018,6 +24288,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -24073,11 +24344,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -24128,7 +24402,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -24169,9 +24443,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CONST_RETVAL_U value = RT_CONSTANT(opline, opline->op2); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); - if (0) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -24189,9 +24472,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CONST_RETVAL_U value = RT_CONSTANT(opline, opline->op2); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); - if (1) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -24703,54 +24995,80 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_ { zend_class_entry *ce, *scope; zend_class_constant *c; - zval *value, *zv; + zval *value, *zv, *constant_zv; + zend_string *constant_name; USE_OPLINE SAVE_OPLINE(); do { - if (IS_VAR == IS_CONST) { + if (IS_VAR == IS_CONST && IS_CONST == IS_CONST) { if (EXPECTED(CACHED_PTR(opline->extended_value + sizeof(void*)))) { value = CACHED_PTR(opline->extended_value + sizeof(void*)); break; - } else if (EXPECTED(CACHED_PTR(opline->extended_value))) { + } + } + if (IS_VAR == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value))) { ce = CACHED_PTR(opline->extended_value); } else { ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(ce == NULL)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } + CACHE_PTR(opline->extended_value, ce); } - } else { - if (IS_VAR == IS_UNUSED) { - ce = zend_fetch_class(NULL, opline->op1.num); - if (UNEXPECTED(ce == NULL)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - HANDLE_EXCEPTION(); - } - } else { - ce = Z_CE_P(EX_VAR(opline->op1.var)); - } - if (EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { - value = CACHED_PTR(opline->extended_value + sizeof(void*)); - break; + } else if (IS_VAR == IS_UNUSED) { + ce = zend_fetch_class(NULL, opline->op1.num); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + + HANDLE_EXCEPTION(); } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); } + if (IS_VAR != IS_CONST + && IS_CONST == IS_CONST + && EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + + constant_zv = RT_CONSTANT(opline, opline->op2); + if (UNEXPECTED(Z_TYPE_P(constant_zv) != IS_STRING)) { + zend_invalid_class_constant_type_error(Z_TYPE_P(constant_zv)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + + HANDLE_EXCEPTION(); + } + constant_name = Z_STR_P(constant_zv); + /* Magic 'class' for constant OP2 is caught at compile-time */ + if (IS_CONST != IS_CONST && UNEXPECTED(zend_string_equals_literal_ci(constant_name, "class"))) { + ZVAL_STR_COPY(EX_VAR(opline->result.var), ce->name); + + ZEND_VM_NEXT_OPCODE(); + } + zv = IS_CONST == IS_CONST + ? zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), constant_name) + : zend_hash_find(CE_CONSTANTS_TABLE(ce), constant_name); - zv = zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2))); if (EXPECTED(zv != NULL)) { c = Z_PTR_P(zv); scope = EX(func)->op_array.scope; if (!zend_verify_const_access(c, scope)) { - zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } if (ce->ce_flags & ZEND_ACC_TRAIT) { - zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } @@ -24759,21 +25077,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_ if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } if (Z_TYPE_P(value) == IS_CONSTANT_AST) { - zval_update_constant_ex(value, c->ce); - if (UNEXPECTED(EG(exception) != NULL)) { + if (UNEXPECTED(zend_update_class_constant(c, constant_name, c->ce) != SUCCESS)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } - CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + if (IS_CONST == IS_CONST) { + CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + } } else { zend_throw_error(NULL, "Undefined constant %s::%s", - ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } while (0); @@ -24866,7 +25188,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CON str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -24958,7 +25280,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_VAR_CONST_HANDL key = ZSTR_EMPTY_ALLOC(); goto str_index_dim; } else { - zend_type_error("Illegal offset type in unset"); + zend_illegal_unset_offset(offset); } break; } else if (Z_ISREF_P(container)) { @@ -25123,7 +25445,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(Z /* Set the new yielded key */ if (IS_CONST != IS_UNUSED) { zval *key = RT_CONSTANT(opline, opline->op2); - if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -25231,6 +25553,121 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IN_ARRAY_SPEC_VAR_CONST_HANDLE ZEND_VM_SMART_BRANCH(0, 1); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_class_entry *ce, *scope; + zend_class_constant *c; + zval *value, *zv, *constant_zv; + zend_string *constant_name; + USE_OPLINE + + SAVE_OPLINE(); + + do { + if (IS_VAR == IS_CONST && (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value + sizeof(void*)))) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + } + if (IS_VAR == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value))) { + ce = CACHED_PTR(opline->extended_value); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + CACHE_PTR(opline->extended_value, ce); + } + } else if (IS_VAR == IS_UNUSED) { + ce = zend_fetch_class(NULL, opline->op1.num); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); + } + if (IS_VAR != IS_CONST + && (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST + && EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + + constant_zv = _get_zval_ptr_tmpvarcv(opline->op2_type, opline->op2, BP_VAR_R EXECUTE_DATA_CC); + if (UNEXPECTED(Z_TYPE_P(constant_zv) != IS_STRING)) { + zend_invalid_class_constant_type_error(Z_TYPE_P(constant_zv)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + constant_name = Z_STR_P(constant_zv); + /* Magic 'class' for constant OP2 is caught at compile-time */ + if ((IS_TMP_VAR|IS_VAR|IS_CV) != IS_CONST && UNEXPECTED(zend_string_equals_literal_ci(constant_name, "class"))) { + ZVAL_STR_COPY(EX_VAR(opline->result.var), ce->name); + FREE_OP(opline->op2_type, opline->op2.var); + ZEND_VM_NEXT_OPCODE(); + } + zv = (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST + ? zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), constant_name) + : zend_hash_find(CE_CONSTANTS_TABLE(ce), constant_name); + + if (EXPECTED(zv != NULL)) { + c = Z_PTR_P(zv); + scope = EX(func)->op_array.scope; + if (!zend_verify_const_access(c, scope)) { + zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + + if (ce->ce_flags & ZEND_ACC_TRAIT) { + zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + + value = &c->value; + // Enums require loading of all class constants to build the backed enum table + if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { + if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } + if (Z_TYPE_P(value) == IS_CONSTANT_AST) { + if (UNEXPECTED(zend_update_class_constant(c, constant_name, c->ce) != SUCCESS)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } + if ((IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST) { + CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + } + } else { + zend_throw_error(NULL, "Undefined constant %s::%s", + ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } while (0); + + ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), value); + + FREE_OP(opline->op2_type, opline->op2.var); + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_OP_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -25396,7 +25833,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_TMPVAR_ } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -25672,7 +26109,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_TMPVAR_HA zend_fetch_property_address( result, container, IS_VAR, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -25689,7 +26126,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_VAR_TMPVAR_H container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); property = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_VAR, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_VAR, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -25723,7 +26160,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_TMPVA container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); property = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_VAR, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_VAR, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -25760,6 +26197,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -25789,11 +26227,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -25872,11 +26310,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -25890,6 +26331,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -25919,11 +26361,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -26002,11 +26444,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -26020,6 +26465,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26049,11 +26495,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -26132,11 +26578,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -26150,6 +26599,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26179,11 +26629,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -26262,11 +26712,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -26281,6 +26734,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26336,11 +26790,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -26391,7 +26848,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -26429,6 +26886,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26484,11 +26942,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -26540,7 +27001,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -26578,6 +27039,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26633,11 +27095,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -26689,7 +27154,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -26727,6 +27192,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26782,11 +27248,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -26837,7 +27306,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -27158,7 +27627,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_TMP str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -27250,7 +27719,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_VAR_TMPVAR_HAND key = ZSTR_EMPTY_ALLOC(); goto str_index_dim; } else { - zend_type_error("Illegal offset type in unset"); + zend_illegal_unset_offset(offset); } break; } else if (Z_ISREF_P(container)) { @@ -27417,7 +27886,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMPVAR_HANDLER( /* Set the new yielded key */ if ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) { zval *key = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); - if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -27508,9 +27977,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_RETVAL_UNU value = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - if (0) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -27528,9 +28006,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_RETVAL_USE value = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - if (1) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -27592,9 +28079,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_VAR_RETVAL_UNU value = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); - if (0) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -27612,9 +28108,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_VAR_RETVAL_USE value = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); - if (1) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -27627,6 +28132,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLE USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = _get_zval_ptr_ptr_var(opline->op2.var EXECUTE_DATA_CC); @@ -27642,15 +28148,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLE UNEXPECTED(!Z_ISREF_P(value_ptr))) { variable_ptr = zend_wrong_assign_to_variable_reference( - variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); + variable_ptr, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -27724,7 +28234,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_UNUSED_ } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -27812,6 +28322,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -27867,11 +28378,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -27922,7 +28436,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -27960,6 +28474,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -28015,11 +28530,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -28071,7 +28589,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -28109,6 +28627,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -28164,11 +28683,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -28220,7 +28742,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -28258,6 +28780,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -28313,11 +28836,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -28368,7 +28894,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -29179,7 +29705,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_UNU str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -29316,7 +29842,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER( /* Set the new yielded key */ if (IS_UNUSED != IS_UNUSED) { zval *key = NULL; - if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -29604,7 +30130,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CV_HAND } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -29876,7 +30402,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_CV_HANDLE zend_fetch_property_address( result, container, IS_VAR, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -29893,7 +30419,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_VAR_CV_HANDL container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); property = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_VAR, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_VAR, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -29927,7 +30453,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CV_HA container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); property = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_VAR, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_VAR, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -29963,6 +30489,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -29992,11 +30519,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30075,11 +30602,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -30093,6 +30623,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30122,11 +30653,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30205,11 +30736,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -30223,6 +30757,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30252,11 +30787,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30335,11 +30870,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -30353,6 +30891,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30382,11 +30921,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30465,11 +31004,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -30484,6 +31026,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30539,11 +31082,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -30594,7 +31140,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -30632,6 +31178,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30687,11 +31234,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -30743,7 +31293,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -30781,6 +31331,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30836,11 +31387,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -30892,7 +31446,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -30930,6 +31484,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30985,11 +31540,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -31040,7 +31598,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -31081,9 +31639,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CV_RETVAL_UNUS value = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (0) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -31101,9 +31668,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CV_RETVAL_USED value = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (1) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -31116,6 +31692,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = _get_zval_ptr_cv_BP_VAR_W(opline->op2.var EXECUTE_DATA_CC); @@ -31131,15 +31708,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER UNEXPECTED(!Z_ISREF_P(value_ptr))) { variable_ptr = zend_wrong_assign_to_variable_reference( - variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); + variable_ptr, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -31434,7 +32015,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CV_ str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -31526,7 +32107,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_VAR_CV_HANDLER( key = ZSTR_EMPTY_ALLOC(); goto str_index_dim; } else { - zend_type_error("Illegal offset type in unset"); + zend_illegal_unset_offset(offset); } break; } else if (Z_ISREF_P(container)) { @@ -31691,7 +32272,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND /* Set the new yielded key */ if (IS_CV != IS_UNUSED) { zval *key = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -31938,7 +32519,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_NAME_SPEC_UNUSED_H if (UNEXPECTED(Z_TYPE_P(op) != IS_OBJECT)) { ZVAL_DEREF(op); if (Z_TYPE_P(op) != IS_OBJECT) { - zend_type_error("Cannot use \"::class\" on value of type %s", zend_zval_type_name(op)); + zend_type_error("Cannot use \"::class\" on %s", zend_zval_value_name(op)); ZVAL_UNDEF(EX_VAR(opline->result.var)); HANDLE_EXCEPTION(); @@ -32323,6 +32904,7 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -32363,7 +32945,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_CONST_ zend_fetch_property_address( result, container, IS_UNUSED, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -32380,7 +32962,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_UNUSED_CONST container = &EX(This); property = RT_CONSTANT(opline, opline->op2); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_UNUSED, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_UNUSED, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -32526,7 +33108,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_UNUSED_CO container = &EX(This); property = RT_CONSTANT(opline, opline->op2); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_UNUSED, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_UNUSED, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -32540,6 +33122,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -32569,11 +33152,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -32652,11 +33235,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -32670,6 +33256,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -32699,11 +33286,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -32782,11 +33369,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -32800,6 +33390,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -32829,11 +33420,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -32912,11 +33503,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -32930,6 +33524,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -32959,11 +33554,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -33042,11 +33637,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -33543,54 +34141,80 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS { zend_class_entry *ce, *scope; zend_class_constant *c; - zval *value, *zv; + zval *value, *zv, *constant_zv; + zend_string *constant_name; USE_OPLINE SAVE_OPLINE(); do { - if (IS_UNUSED == IS_CONST) { + if (IS_UNUSED == IS_CONST && IS_CONST == IS_CONST) { if (EXPECTED(CACHED_PTR(opline->extended_value + sizeof(void*)))) { value = CACHED_PTR(opline->extended_value + sizeof(void*)); break; - } else if (EXPECTED(CACHED_PTR(opline->extended_value))) { + } + } + if (IS_UNUSED == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value))) { ce = CACHED_PTR(opline->extended_value); } else { ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); if (UNEXPECTED(ce == NULL)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } + CACHE_PTR(opline->extended_value, ce); } - } else { - if (IS_UNUSED == IS_UNUSED) { - ce = zend_fetch_class(NULL, opline->op1.num); - if (UNEXPECTED(ce == NULL)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - HANDLE_EXCEPTION(); - } - } else { - ce = Z_CE_P(EX_VAR(opline->op1.var)); - } - if (EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { - value = CACHED_PTR(opline->extended_value + sizeof(void*)); - break; + } else if (IS_UNUSED == IS_UNUSED) { + ce = zend_fetch_class(NULL, opline->op1.num); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + + HANDLE_EXCEPTION(); } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); + } + if (IS_UNUSED != IS_CONST + && IS_CONST == IS_CONST + && EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + + constant_zv = RT_CONSTANT(opline, opline->op2); + if (UNEXPECTED(Z_TYPE_P(constant_zv) != IS_STRING)) { + zend_invalid_class_constant_type_error(Z_TYPE_P(constant_zv)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + + HANDLE_EXCEPTION(); } + constant_name = Z_STR_P(constant_zv); + /* Magic 'class' for constant OP2 is caught at compile-time */ + if (IS_CONST != IS_CONST && UNEXPECTED(zend_string_equals_literal_ci(constant_name, "class"))) { + ZVAL_STR_COPY(EX_VAR(opline->result.var), ce->name); + + ZEND_VM_NEXT_OPCODE(); + } + zv = IS_CONST == IS_CONST + ? zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), constant_name) + : zend_hash_find(CE_CONSTANTS_TABLE(ce), constant_name); - zv = zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2))); if (EXPECTED(zv != NULL)) { c = Z_PTR_P(zv); scope = EX(func)->op_array.scope; if (!zend_verify_const_access(c, scope)) { - zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } if (ce->ce_flags & ZEND_ACC_TRAIT) { - zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } @@ -33599,21 +34223,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } if (Z_TYPE_P(value) == IS_CONSTANT_AST) { - zval_update_constant_ex(value, c->ce); - if (UNEXPECTED(EG(exception) != NULL)) { + if (UNEXPECTED(zend_update_class_constant(c, constant_name, c->ce) != SUCCESS)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } - CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + if (IS_CONST == IS_CONST) { + CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + } } else { zend_throw_error(NULL, "Undefined constant %s::%s", - ZSTR_VAL(ce->name), Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))); + ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); } } while (0); @@ -33825,7 +34453,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLE /* Set the new yielded key */ if (IS_CONST != IS_UNUSED) { zval *key = RT_CONSTANT(opline, opline->op2); - if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -33861,6 +34489,121 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLE ZEND_VM_RETURN(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_class_entry *ce, *scope; + zend_class_constant *c; + zval *value, *zv, *constant_zv; + zend_string *constant_name; + USE_OPLINE + + SAVE_OPLINE(); + + do { + if (IS_UNUSED == IS_CONST && (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value + sizeof(void*)))) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + } + if (IS_UNUSED == IS_CONST) { + if (EXPECTED(CACHED_PTR(opline->extended_value))) { + ce = CACHED_PTR(opline->extended_value); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + CACHE_PTR(opline->extended_value, ce); + } + } else if (IS_UNUSED == IS_UNUSED) { + ce = zend_fetch_class(NULL, opline->op1.num); + if (UNEXPECTED(ce == NULL)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); + } + if (IS_UNUSED != IS_CONST + && (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST + && EXPECTED(CACHED_PTR(opline->extended_value) == ce)) { + value = CACHED_PTR(opline->extended_value + sizeof(void*)); + break; + } + + constant_zv = _get_zval_ptr_tmpvarcv(opline->op2_type, opline->op2, BP_VAR_R EXECUTE_DATA_CC); + if (UNEXPECTED(Z_TYPE_P(constant_zv) != IS_STRING)) { + zend_invalid_class_constant_type_error(Z_TYPE_P(constant_zv)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + constant_name = Z_STR_P(constant_zv); + /* Magic 'class' for constant OP2 is caught at compile-time */ + if ((IS_TMP_VAR|IS_VAR|IS_CV) != IS_CONST && UNEXPECTED(zend_string_equals_literal_ci(constant_name, "class"))) { + ZVAL_STR_COPY(EX_VAR(opline->result.var), ce->name); + FREE_OP(opline->op2_type, opline->op2.var); + ZEND_VM_NEXT_OPCODE(); + } + zv = (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST + ? zend_hash_find_known_hash(CE_CONSTANTS_TABLE(ce), constant_name) + : zend_hash_find(CE_CONSTANTS_TABLE(ce), constant_name); + + if (EXPECTED(zv != NULL)) { + c = Z_PTR_P(zv); + scope = EX(func)->op_array.scope; + if (!zend_verify_const_access(c, scope)) { + zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + + if (ce->ce_flags & ZEND_ACC_TRAIT) { + zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + + value = &c->value; + // Enums require loading of all class constants to build the backed enum table + if (ce->ce_flags & ZEND_ACC_ENUM && ce->enum_backing_type != IS_UNDEF && ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { + if (UNEXPECTED(zend_update_class_constants(ce) == FAILURE)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } + if (Z_TYPE_P(value) == IS_CONSTANT_AST) { + if (UNEXPECTED(zend_update_class_constant(c, constant_name, c->ce) != SUCCESS)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } + if ((IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST) { + CACHE_POLYMORPHIC_PTR(opline->extended_value, ce, value); + } + } else { + zend_throw_error(NULL, "Undefined constant %s::%s", + ZSTR_VAL(ce->name), ZSTR_VAL(constant_name)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + FREE_OP(opline->op2_type, opline->op2.var); + HANDLE_EXCEPTION(); + } + } while (0); + + ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), value); + + FREE_OP(opline->op2_type, opline->op2.var); + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_OP_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -34198,6 +34941,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_TMPVAR #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -34233,7 +34977,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_TMPVAR zend_fetch_property_address( result, container, IS_UNUSED, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -34250,7 +34994,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_UNUSED_TMPVA container = &EX(This); property = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_UNUSED, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_UNUSED, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -34396,7 +35140,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_UNUSED_TM container = &EX(This); property = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_UNUSED, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_UNUSED, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -34410,6 +35154,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -34439,11 +35184,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -34522,11 +35267,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -34540,6 +35288,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -34569,11 +35318,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -34652,11 +35401,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -34670,6 +35422,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -34699,11 +35452,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -34782,11 +35535,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -34800,6 +35556,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -34829,11 +35586,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -34912,11 +35669,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -35565,7 +36325,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMPVAR_HANDL /* Set the new yielded key */ if ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) { zval *key = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); - if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -36107,7 +36867,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDL /* Set the new yielded key */ if (IS_UNUSED != IS_UNUSED) { zval *key = NULL; - if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -36207,7 +36967,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GET_CLASS_SPEC_UNUSED_UNUSED_H if (IS_UNUSED == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_type_name(op1)); + zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(op1)); ZVAL_UNDEF(EX_VAR(opline->result.var)); } break; @@ -36671,6 +37431,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_CV_HAN #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -36706,7 +37467,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_CV_HAN zend_fetch_property_address( result, container, IS_UNUSED, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -36723,7 +37484,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_UNUSED_CV_HA container = &EX(This); property = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_UNUSED, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_UNUSED, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -36869,7 +37630,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_UNUSED_CV container = &EX(This); property = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_UNUSED, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_UNUSED, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -36883,6 +37644,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -36912,11 +37674,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -36995,11 +37757,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -37013,6 +37778,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -37042,11 +37808,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -37125,11 +37891,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -37143,6 +37912,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -37172,11 +37942,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -37255,11 +38025,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -37273,6 +38046,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -37302,11 +38076,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -37385,11 +38159,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -38036,7 +38813,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(Z /* Set the new yielded key */ if (IS_CV != IS_UNUSED) { zval *key = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -38139,7 +38916,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_CV_RE if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_increment_function(var_ptr); - if (0) { + if (UNEXPECTED(0)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -38157,7 +38934,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_CV_RE if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_increment_function(var_ptr); - if (1) { + if (UNEXPECTED(1)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -38208,7 +38985,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_SPEC_CV_RE if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_decrement_function(var_ptr); - if (0) { + if (UNEXPECTED(0)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -38226,7 +39003,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_SPEC_CV_RE if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) { fast_long_decrement_function(var_ptr); - if (1) { + if (UNEXPECTED(1)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -38361,7 +39138,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPZ_SPEC_CV_HANDL { USE_OPLINE zval *val; - zend_uchar op1_type; + uint8_t op1_type; val = EX_VAR(opline->op1.var); @@ -38395,7 +39172,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPNZ_SPEC_CV_HAND { USE_OPLINE zval *val; - zend_uchar op1_type; + uint8_t op1_type; val = EX_VAR(opline->op1.var); @@ -39059,7 +39836,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CV_HANDLER(ZEN } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; @@ -39148,7 +39925,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZE } } } else { - zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_value_name(array_ptr)); ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; @@ -39482,7 +40259,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_STRLEN_SPEC_CV_HANDLER(ZEND_OP zval_ptr_dtor(&tmp); } if (!EG(exception)) { - zend_type_error("strlen(): Argument #1 ($str) must be of type string, %s given", zend_zval_type_name(value)); + zend_type_error("strlen(): Argument #1 ($string) must be of type string, %s given", zend_zval_value_name(value)); } ZVAL_UNDEF(EX_VAR(opline->result.var)); } while (0); @@ -39539,7 +40316,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_NAME_SPEC_CV_HANDL if (UNEXPECTED(Z_TYPE_P(op) != IS_OBJECT)) { ZVAL_DEREF(op); if (Z_TYPE_P(op) != IS_OBJECT) { - zend_type_error("Cannot use \"::class\" on value of type %s", zend_zval_type_name(op)); + zend_type_error("Cannot use \"::class\" on %s", zend_zval_value_name(op)); ZVAL_UNDEF(EX_VAR(opline->result.var)); HANDLE_EXCEPTION(); @@ -39596,7 +40373,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_LONG_NO_OV var_ptr = EX_VAR(opline->op1.var); Z_LVAL_P(var_ptr)++; - if (0) { + if (UNEXPECTED(0)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); } ZEND_VM_NEXT_OPCODE(); @@ -39609,7 +40386,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_LONG_NO_OV var_ptr = EX_VAR(opline->op1.var); Z_LVAL_P(var_ptr)++; - if (1) { + if (UNEXPECTED(1)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); } ZEND_VM_NEXT_OPCODE(); @@ -39622,7 +40399,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_LONG_SPEC_ var_ptr = EX_VAR(opline->op1.var); fast_long_increment_function(var_ptr); - if (0) { + if (UNEXPECTED(0)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -39635,7 +40412,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_LONG_SPEC_ var_ptr = EX_VAR(opline->op1.var); fast_long_increment_function(var_ptr); - if (1) { + if (UNEXPECTED(1)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -39648,7 +40425,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_LONG_NO_OV var_ptr = EX_VAR(opline->op1.var); Z_LVAL_P(var_ptr)--; - if (0) { + if (UNEXPECTED(0)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); } ZEND_VM_NEXT_OPCODE(); @@ -39661,7 +40438,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_LONG_NO_OV var_ptr = EX_VAR(opline->op1.var); Z_LVAL_P(var_ptr)--; - if (1) { + if (UNEXPECTED(1)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr)); } ZEND_VM_NEXT_OPCODE(); @@ -39674,7 +40451,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_LONG_SPEC_ var_ptr = EX_VAR(opline->op1.var); fast_long_decrement_function(var_ptr); - if (0) { + if (UNEXPECTED(0)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -39687,7 +40464,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_DEC_LONG_SPEC_ var_ptr = EX_VAR(opline->op1.var); fast_long_decrement_function(var_ptr); - if (1) { + if (UNEXPECTED(1)) { ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr); } ZEND_VM_NEXT_OPCODE(); @@ -39795,6 +40572,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CV != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CONST == IS_CONST || IS_CONST == IS_CV) { @@ -39823,6 +40601,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -39831,6 +40610,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CONST_HANDLER(Z str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -40427,7 +41207,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CONST_HA } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -40839,6 +41619,7 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -40879,7 +41660,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_CONST_HAND zend_fetch_property_address( result, container, IS_CV, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -40896,7 +41677,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_CV_CONST_HAN container = EX_VAR(opline->op1.var); property = RT_CONSTANT(opline, opline->op2); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_CV, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_CV, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -41042,7 +41823,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_CONST_ container = EX_VAR(opline->op1.var); property = RT_CONSTANT(opline, opline->op2); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_CV, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_CV, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -41056,6 +41837,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -41085,11 +41867,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -41168,11 +41950,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -41186,6 +41971,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -41215,11 +42001,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -41298,11 +42084,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -41316,6 +42105,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -41345,11 +42135,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -41428,11 +42218,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -41446,6 +42239,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -41475,11 +42269,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -41558,11 +42352,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -41577,6 +42374,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -41632,11 +42430,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -41687,7 +42488,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -41725,6 +42526,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -41780,11 +42582,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -41836,7 +42641,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -41874,6 +42679,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -41929,11 +42735,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -41985,7 +42794,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -42023,6 +42832,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -42078,11 +42888,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -42133,7 +42946,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -42174,9 +42987,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UN value = RT_CONSTANT(opline, opline->op2); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); - if (0) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -42194,9 +43016,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_US value = RT_CONSTANT(opline, opline->op2); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); - if (1) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -42290,6 +43121,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CV != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CONST == IS_CONST || IS_CONST == IS_CV) { @@ -42315,6 +43147,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CONST & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -42323,6 +43156,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -42383,6 +43217,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HAND str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -42775,7 +43611,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CONS str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -42867,7 +43703,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLE key = ZSTR_EMPTY_ALLOC(); goto str_index_dim; } else { - zend_type_error("Illegal offset type in unset"); + zend_illegal_unset_offset(offset); } break; } else if (Z_ISREF_P(container)) { @@ -43238,7 +44074,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZE /* Set the new yielded key */ if (IS_CONST != IS_UNUSED) { zval *key = RT_CONSTANT(opline, opline->op2); - if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CONST & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -43606,6 +44442,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CV != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if ((IS_TMP_VAR|IS_VAR) == IS_CONST || (IS_TMP_VAR|IS_VAR) == IS_CV) { @@ -43634,6 +44471,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -43642,6 +44480,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_TMPVAR_HANDLER( str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -44208,7 +45047,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_TMPVAR_H } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -44624,6 +45463,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_TMPVAR_HAN #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -44659,7 +45499,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_TMPVAR_HAN zend_fetch_property_address( result, container, IS_CV, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -44676,7 +45516,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_CV_TMPVAR_HA container = EX_VAR(opline->op1.var); property = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_CV, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_CV, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -44822,7 +45662,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_TMPVAR container = EX_VAR(opline->op1.var); property = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_CV, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_CV, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -44836,6 +45676,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -44865,11 +45706,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -44948,11 +45789,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -44966,6 +45810,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -44995,11 +45840,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -45078,11 +45923,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -45096,6 +45944,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -45125,11 +45974,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -45208,11 +46057,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -45226,6 +46078,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -45255,11 +46108,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -45338,11 +46191,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -45357,6 +46213,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -45412,11 +46269,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -45467,7 +46327,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -45505,6 +46365,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -45560,11 +46421,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -45616,7 +46480,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -45654,6 +46518,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -45709,11 +46574,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -45765,7 +46633,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -45803,6 +46671,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -45858,11 +46727,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -45913,7 +46785,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -46030,6 +46902,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CV != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if ((IS_TMP_VAR|IS_VAR) == IS_CONST || (IS_TMP_VAR|IS_VAR) == IS_CV) { @@ -46055,6 +46928,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -46063,6 +46937,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -46123,6 +46998,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HAN str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -46374,7 +47251,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_TMPV str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -46466,7 +47343,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_CV_TMPVAR_HANDL key = ZSTR_EMPTY_ALLOC(); goto str_index_dim; } else { - zend_type_error("Illegal offset type in unset"); + zend_illegal_unset_offset(offset); } break; } else if (Z_ISREF_P(container)) { @@ -46795,7 +47672,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMPVAR_HANDLER(Z /* Set the new yielded key */ if ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) { zval *key = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); - if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if (((IS_TMP_VAR|IS_VAR) & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -46872,9 +47749,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_RETVAL_UNUS value = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - if (0) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -46892,9 +47778,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_RETVAL_USED value = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - if (1) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -46942,9 +47837,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_RETVAL_UNUS value = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); - if (0) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -46962,9 +47866,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_RETVAL_USED value = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); - if (1) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -46977,6 +47890,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = _get_zval_ptr_ptr_var(opline->op2.var EXECUTE_DATA_CC); @@ -46992,15 +47906,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER UNEXPECTED(!Z_ISREF_P(value_ptr))) { variable_ptr = zend_wrong_assign_to_variable_reference( - variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); + variable_ptr, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -47119,7 +48037,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_UNUSED_H } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -47335,6 +48253,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -47390,11 +48309,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -47445,7 +48367,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -47483,6 +48405,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -47538,11 +48461,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -47594,7 +48520,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -47632,6 +48558,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -47687,11 +48614,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -47743,7 +48673,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -47781,6 +48711,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -47836,11 +48767,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -47891,7 +48825,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -48279,7 +49213,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_UNUS str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -48323,11 +49257,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_CV_SPEC_CV_UNUSED_HANDLE ZVAL_UNDEF(var); SAVE_OPLINE(); - if (!GC_DELREF(garbage)) { - rc_dtor_func(garbage); - } else { - gc_check_possible_root(garbage); - } + GC_DTOR(garbage); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { ZVAL_UNDEF(var); @@ -48594,7 +49524,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(Z /* Set the new yielded key */ if (IS_UNUSED != IS_UNUSED) { zval *key = NULL; - if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_UNUSED & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -48770,7 +49700,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CV_UNUSED_HANDLER(Z ZVAL_UNDEFINED_OP1(); } count = 0; - zend_type_error("%s(): Argument #1 ($value) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1)); + zend_type_error("%s(): Argument #1 ($value) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_value_name(op1)); break; } @@ -48808,7 +49738,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GET_CLASS_SPEC_CV_UNUSED_HANDL if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_type_name(op1)); + zend_type_error("get_class(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(op1)); ZVAL_UNDEF(EX_VAR(opline->result.var)); } break; @@ -48899,6 +49829,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CV != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CV == IS_CONST || IS_CV == IS_CV) { @@ -48927,6 +49858,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND } str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -48935,6 +49867,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONCAT_SPEC_CV_CV_HANDLER(ZEND str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -49531,7 +50464,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CV_HANDL } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - zend_uchar old_type; + uint8_t old_type; if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -49943,6 +50876,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER #if ZEND_DEBUG if (!EG(exception) && prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO && ZEND_TYPE_IS_SET(prop_info->type)) { + ZVAL_OPT_DEREF(retval); zend_verify_property_type(prop_info, retval, /* strict */ true); } #endif @@ -49978,7 +50912,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_CV_HANDLER zend_fetch_property_address( result, container, IS_CV, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value OPLINE_CC EXECUTE_DATA_CC); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -49995,7 +50929,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_CV_CV_HANDLE container = EX_VAR(opline->op1.var); property = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_CV, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_CV, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_RW, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -50141,7 +51075,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV_HAN container = EX_VAR(opline->op1.var); property = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); result = EX_VAR(opline->result.var); - zend_fetch_property_address(result, container, IS_CV, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0, 1 OPLINE_CC EXECUTE_DATA_CC); + zend_fetch_property_address(result, container, IS_CV, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value) : NULL), BP_VAR_UNSET, 0 OPLINE_CC EXECUTE_DATA_CC); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -50155,6 +51089,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -50184,11 +51119,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -50267,11 +51202,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -50285,6 +51223,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -50314,11 +51253,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -50397,11 +51336,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -50415,6 +51357,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -50444,11 +51387,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -50527,11 +51470,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -50545,6 +51491,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -50574,11 +51521,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -50657,11 +51604,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -50676,6 +51626,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -50731,11 +51682,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -50786,7 +51740,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -50824,6 +51778,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -50879,11 +51834,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -50935,7 +51893,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -50973,6 +51931,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -51028,11 +51987,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -51084,7 +52046,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -51122,6 +52084,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -51177,11 +52140,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -51232,7 +52198,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ UNDEF_RESULT(); } else { HashTable *ht = zend_new_array(8); - zend_uchar old_type = Z_TYPE_P(object_ptr); + uint8_t old_type = Z_TYPE_P(object_ptr); ZVAL_ARR(object_ptr, ht); if (UNEXPECTED(old_type == IS_FALSE)) { @@ -51273,9 +52239,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_RETVAL_UNUSE value = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (0) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -51293,9 +52268,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_RETVAL_USED_ value = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (1) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -51308,6 +52292,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER( USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = _get_zval_ptr_cv_BP_VAR_W(opline->op2.var EXECUTE_DATA_CC); @@ -51323,15 +52308,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER( UNEXPECTED(!Z_ISREF_P(value_ptr))) { variable_ptr = zend_wrong_assign_to_variable_reference( - variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); + variable_ptr, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -51422,6 +52411,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER zend_string *op1_str = Z_STR_P(op1); zend_string *op2_str = Z_STR_P(op2); zend_string *str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_str, op2_str); if (IS_CV != IS_CONST && UNEXPECTED(ZSTR_LEN(op1_str) == 0)) { if (IS_CV == IS_CONST || IS_CV == IS_CV) { @@ -51447,6 +52437,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER str = zend_string_extend(op1_str, len + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str) + len, ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op2_str, 0); @@ -51455,6 +52446,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + GC_ADD_FLAGS(str, flags); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV & (IS_TMP_VAR|IS_VAR)) { zend_string_release_ex(op1_str, 0); @@ -51515,6 +52507,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER str = zend_string_alloc(ZSTR_LEN(op1_str) + ZSTR_LEN(op2_str), 0); memcpy(ZSTR_VAL(str), ZSTR_VAL(op1_str), ZSTR_LEN(op1_str)); memcpy(ZSTR_VAL(str) + ZSTR_LEN(op1_str), ZSTR_VAL(op2_str), ZSTR_LEN(op2_str)+1); + + ZSTR_COPY_CONCAT_PROPERTIES_BOTH(str, op1_str, op2_str); ZVAL_NEW_STR(EX_VAR(opline->result.var), str); if (IS_CV != IS_CONST) { zend_string_release_ex(op1_str, 0); @@ -51766,7 +52760,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CV_H str = ZSTR_EMPTY_ALLOC(); goto str_index; } else { - zend_illegal_offset(); + zend_illegal_array_offset(offset); zval_ptr_dtor_nogc(expr_ptr); } @@ -51858,7 +52852,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER(Z key = ZSTR_EMPTY_ALLOC(); goto str_index_dim; } else { - zend_type_error("Illegal offset type in unset"); + zend_illegal_unset_offset(offset); } break; } else if (Z_ISREF_P(container)) { @@ -52184,7 +53178,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_ /* Set the new yielded key */ if (IS_CV != IS_UNUSED) { zval *key = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key)) == IS_REFERENCE) { + if ((IS_CV & (IS_CV|IS_VAR)) && UNEXPECTED(Z_TYPE_P(key) == IS_REFERENCE)) { key = Z_REFVAL_P(key); } ZVAL_COPY(&generator->key, key); @@ -54739,9 +55733,29 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_UNSET_STATIC_PROP_SPEC_LABEL, (void*)&&ZEND_ISSET_ISEMPTY_STATIC_PROP_SPEC_LABEL, (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_CONST_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_CONST_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV_LABEL, (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_CONST_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_BIND_LEXICAL_SPEC_TMP_CV_LABEL, (void*)&&ZEND_BIND_STATIC_SPEC_CV_UNUSED_LABEL, @@ -55774,6 +56788,16 @@ ZEND_API void execute_ex(zend_execute_data *ex) LOAD_OPLINE(); ZEND_VM_LOOP_INTERRUPT_CHECK(); +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + /* No opline was executed before exception */ + EG(opline_before_exception) = NULL; + LOAD_OPLINE(); + /* Fall through to handle exception below. */ + } +#endif /* ZEND_CHECK_STACK_LIMIT */ + while (1) { #if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG) int ret; @@ -56701,6 +57725,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST_TMPVARCV_JMPNZ) ZEND_IS_SMALLER_OR_EQUAL_SPEC_CONST_TMPVARCV_JMPNZ_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV): + VM_TRACE(ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV) + ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV): VM_TRACE(ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -58421,6 +59449,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_IN_ARRAY_SPEC_VAR_CONST) ZEND_IN_ARRAY_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV): + VM_TRACE(ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV) + ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_OBJ_OP_SPEC_VAR_TMPVAR): VM_TRACE(ZEND_ASSIGN_OBJ_OP_SPEC_VAR_TMPVAR) ZEND_ASSIGN_OBJ_OP_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -58945,6 +59977,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_YIELD_SPEC_UNUSED_CONST) ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV): + VM_TRACE(ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV) + ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_OBJ_OP_SPEC_UNUSED_TMPVAR): VM_TRACE(ZEND_ASSIGN_OBJ_OP_SPEC_UNUSED_TMPVAR) ZEND_ASSIGN_OBJ_OP_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -62801,9 +63837,29 @@ void zend_vm_init(void) ZEND_UNSET_STATIC_PROP_SPEC_HANDLER, ZEND_ISSET_ISEMPTY_STATIC_PROP_SPEC_HANDLER, ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_CONST_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV_HANDLER, ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_CONST_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_BIND_LEXICAL_SPEC_TMP_CV_HANDLER, ZEND_BIND_STATIC_SPEC_CV_UNUSED_HANDLER, @@ -63865,7 +64921,7 @@ void zend_vm_init(void) 1255, 1256 | SPEC_RULE_OP1, 1261 | SPEC_RULE_OP1, - 3450, + 3470, 1266 | SPEC_RULE_OP1, 1271 | SPEC_RULE_OP1, 1276 | SPEC_RULE_OP2, @@ -64001,81 +65057,81 @@ void zend_vm_init(void) 2430, 2431, 2432, - 2433 | SPEC_RULE_OP1, - 2438, - 2439, - 2440, - 2441 | SPEC_RULE_OP2, - 2446, - 2447 | SPEC_RULE_OP1, - 2452 | SPEC_RULE_OP1, - 2457 | SPEC_RULE_OP1, - 2462 | SPEC_RULE_OP1, + 2433 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2458, + 2459, + 2460, + 2461 | SPEC_RULE_OP2, + 2466, 2467 | SPEC_RULE_OP1, - 2472, - 2473 | SPEC_RULE_OP1, - 2478 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2503 | SPEC_RULE_OP1, - 2508 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2533 | SPEC_RULE_OP1, - 2538 | SPEC_RULE_OP1, - 2543, - 2544, - 2545, - 2546, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, - 3450, + 2472 | SPEC_RULE_OP1, + 2477 | SPEC_RULE_OP1, + 2482 | SPEC_RULE_OP1, + 2487 | SPEC_RULE_OP1, + 2492, + 2493 | SPEC_RULE_OP1, + 2498 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2523 | SPEC_RULE_OP1, + 2528 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2553 | SPEC_RULE_OP1, + 2558 | SPEC_RULE_OP1, + 2563, + 2564, + 2565, + 2566, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, + 3470, }; #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; @@ -64112,7 +65168,7 @@ static void init_opcode_serialiser(void) Z_TYPE_INFO(tmp) = IS_LONG; for (i = 0; i < zend_handlers_count; i++) { Z_LVAL(tmp) = i; - zend_hash_index_add(zend_handlers_table, (zend_long)(zend_uintptr_t)zend_opcode_handlers[i], &tmp); + zend_hash_index_add(zend_handlers_table, (zend_long)(uintptr_t)zend_opcode_handlers[i], &tmp); } } @@ -64123,14 +65179,14 @@ ZEND_API void ZEND_FASTCALL zend_serialize_opcode_handler(zend_op *op) if (!zend_handlers_table) { init_opcode_serialiser(); } - zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)op->handler); + zv = zend_hash_index_find(zend_handlers_table, (zend_long)(uintptr_t)op->handler); ZEND_ASSERT(zv != NULL); - op->handler = (const void *)(zend_uintptr_t)Z_LVAL_P(zv); + op->handler = (const void *)(uintptr_t)Z_LVAL_P(zv); } ZEND_API void ZEND_FASTCALL zend_deserialize_opcode_handler(zend_op *op) { - op->handler = zend_opcode_handlers[(zend_uintptr_t)op->handler]; + op->handler = zend_opcode_handlers[(uintptr_t)op->handler]; } ZEND_API const void* ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *op) @@ -64143,7 +65199,7 @@ ZEND_API const void* ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *o if (!zend_handlers_table) { init_opcode_serialiser(); } - zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)op->handler); + zv = zend_hash_index_find(zend_handlers_table, (zend_long)(uintptr_t)op->handler); ZEND_ASSERT(zv != NULL); return zend_opcode_handler_funcs[Z_LVAL_P(zv)]; #else @@ -64211,14 +65267,14 @@ static uint32_t ZEND_FASTCALL zend_vm_get_opcode_handler_idx(uint32_t spec, cons } #if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC -static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op) +static const void *zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op) { return zend_opcode_handlers[zend_vm_get_opcode_handler_idx(zend_spec_handlers[opcode], op)]; } #endif #if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID -static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op) +static const void *zend_vm_get_opcode_handler_func(uint8_t opcode, const zend_op* op) { uint32_t spec = zend_spec_handlers[opcode]; return zend_opcode_handler_funcs[zend_vm_get_opcode_handler_idx(spec, op)]; @@ -64228,7 +65284,7 @@ static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler(zend_op* op) { - zend_uchar opcode = zend_user_opcodes[op->opcode]; + uint8_t opcode = zend_user_opcodes[op->opcode]; if (zend_spec_handlers[op->opcode] & SPEC_RULE_COMMUTATIVE) { if (op->op1_type < op->op2_type) { @@ -64240,7 +65296,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler(zend_op* op) ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint32_t op2_info, uint32_t res_info) { - zend_uchar opcode = zend_user_opcodes[op->opcode]; + uint8_t opcode = zend_user_opcodes[op->opcode]; uint32_t spec = zend_spec_handlers[opcode]; switch (opcode) { case ZEND_ADD: @@ -64248,7 +65304,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2549 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2569 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -64256,7 +65312,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2574 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2594 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -64264,7 +65320,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2599 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2619 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -64275,17 +65331,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2624 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2644 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2649 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2669 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2674 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2694 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_MUL: @@ -64296,17 +65352,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2699 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2719 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2724 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2744 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2749 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2769 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_IDENTICAL: @@ -64317,14 +65373,14 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2774 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2794 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2849 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2869 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) { - spec = 3074 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 3094 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_NOT_IDENTICAL: @@ -64335,14 +65391,14 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2924 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2944 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2999 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 3019 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) { - spec = 3079 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 3099 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_EQUAL: @@ -64353,12 +65409,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2774 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2794 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2849 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2869 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_NOT_EQUAL: @@ -64369,12 +65425,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2924 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2944 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2999 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 3019 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_SMALLER: @@ -64382,12 +65438,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3084 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3104 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3159 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3179 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_IS_SMALLER_OR_EQUAL: @@ -64395,74 +65451,74 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3234 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3254 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3309 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3329 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_QM_ASSIGN: if (op1_info == MAY_BE_LONG) { - spec = 3396 | SPEC_RULE_OP1; + spec = 3416 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_DOUBLE) { - spec = 3401 | SPEC_RULE_OP1; + spec = 3421 | SPEC_RULE_OP1; } else if ((op->op1_type == IS_CONST) ? !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1)) : (!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))))) { - spec = 3406 | SPEC_RULE_OP1; + spec = 3426 | SPEC_RULE_OP1; } break; case ZEND_PRE_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3384 | SPEC_RULE_RETVAL; + spec = 3404 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 3386 | SPEC_RULE_RETVAL; + spec = 3406 | SPEC_RULE_RETVAL; } break; case ZEND_PRE_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3388 | SPEC_RULE_RETVAL; + spec = 3408 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 3390 | SPEC_RULE_RETVAL; + spec = 3410 | SPEC_RULE_RETVAL; } break; case ZEND_POST_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3392; + spec = 3412; } else if (op1_info == MAY_BE_LONG) { - spec = 3393; + spec = 3413; } break; case ZEND_POST_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3394; + spec = 3414; } else if (op1_info == MAY_BE_LONG) { - spec = 3395; + spec = 3415; } break; case ZEND_JMP: if (OP_JMP_ADDR(op, op->op1) > op) { - spec = 2548; + spec = 2568; } break; case ZEND_RECV: if (op->op2.num == MAY_BE_ANY) { - spec = 2547; + spec = 2567; } break; case ZEND_SEND_VAL: if (op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3446; + spec = 3466; } break; case ZEND_SEND_VAR_EX: if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3441 | SPEC_RULE_OP1; + spec = 3461 | SPEC_RULE_OP1; } break; case ZEND_FE_FETCH_R: if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) { - spec = 3448 | SPEC_RULE_RETVAL; + spec = 3468 | SPEC_RULE_RETVAL; } break; case ZEND_FETCH_DIM_R: @@ -64470,17 +65526,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3411 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3431 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_SEND_VAL_EX: if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && op->op1_type == IS_CONST && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3447; + spec = 3467; } break; case ZEND_SEND_VAR: if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3436 | SPEC_RULE_OP1; + spec = 3456 | SPEC_RULE_OP1; } break; case ZEND_BW_OR: diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 582ec490e2d77..717d4ffd3e8af 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -16,6 +16,16 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *ex) LOAD_OPLINE(); ZEND_VM_LOOP_INTERRUPT_CHECK(); +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + /* No opline was executed before exception */ + EG(opline_before_exception) = NULL; + LOAD_OPLINE(); + /* Fall through to handle exception below. */ + } +#endif /* ZEND_CHECK_STACK_LIMIT */ + while (1) { {%ZEND_VM_CONTINUE_LABEL%} {%ZEND_VM_DISPATCH%} { @@ -92,7 +102,7 @@ static void init_opcode_serialiser(void) Z_TYPE_INFO(tmp) = IS_LONG; for (i = 0; i < zend_handlers_count; i++) { Z_LVAL(tmp) = i; - zend_hash_index_add(zend_handlers_table, (zend_long)(zend_uintptr_t)zend_opcode_handlers[i], &tmp); + zend_hash_index_add(zend_handlers_table, (zend_long)(uintptr_t)zend_opcode_handlers[i], &tmp); } } @@ -103,14 +113,14 @@ ZEND_API void ZEND_FASTCALL zend_serialize_opcode_handler(zend_op *op) if (!zend_handlers_table) { init_opcode_serialiser(); } - zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)op->handler); + zv = zend_hash_index_find(zend_handlers_table, (zend_long)(uintptr_t)op->handler); ZEND_ASSERT(zv != NULL); - op->handler = (const void *)(zend_uintptr_t)Z_LVAL_P(zv); + op->handler = (const void *)(uintptr_t)Z_LVAL_P(zv); } ZEND_API void ZEND_FASTCALL zend_deserialize_opcode_handler(zend_op *op) { - op->handler = zend_opcode_handlers[(zend_uintptr_t)op->handler]; + op->handler = zend_opcode_handlers[(uintptr_t)op->handler]; } ZEND_API const void* ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *op) @@ -123,7 +133,7 @@ ZEND_API const void* ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *o if (!zend_handlers_table) { init_opcode_serialiser(); } - zv = zend_hash_index_find(zend_handlers_table, (zend_long)(zend_uintptr_t)op->handler); + zv = zend_hash_index_find(zend_handlers_table, (zend_long)(uintptr_t)op->handler); ZEND_ASSERT(zv != NULL); return zend_opcode_handler_funcs[Z_LVAL_P(zv)]; #else diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index c8617ae794adf..0f6154c64db9f 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -260,7 +260,7 @@ "UNUSED" => "NULL", "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op1.var EXECUTE_DATA_CC)", "TMPVAR" => "???", - "TMPVARCV" => "???", + "TMPVARCV" => "_get_zval_ptr_tmpvarcv(opline->op1_type, opline->op1, \\1 EXECUTE_DATA_CC)", ); $op2_get_zval_ptr_deref = array( @@ -271,7 +271,7 @@ "UNUSED" => "NULL", "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op2.var EXECUTE_DATA_CC)", "TMPVAR" => "???", - "TMPVARCV" => "???", + "TMPVARCV" => "_get_zval_ptr_tmpvarcv(opline->op2_type, opline->op2, \\1 EXECUTE_DATA_CC)", ); $op1_get_zval_ptr_undef = array( @@ -436,7 +436,7 @@ "UNUSED" => "", "CV" => "", "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", - "TMPVARCV" => "???", + "TMPVARCV" => "FREE_OP(opline->op1_type, opline->op1.var)", ); $op2_free_op = array( @@ -447,7 +447,7 @@ "UNUSED" => "", "CV" => "", "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", - "TMPVARCV" => "???", + "TMPVARCV" => "FREE_OP(opline->op2_type, opline->op2.var)", ); $op1_free_op_if_var = array( @@ -1819,11 +1819,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#endif\n"); } out($f,"#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC\n"); - out($f,"static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n"); + out($f,"static const void *zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op);\n"); out($f,"#endif\n\n"); if ($kind == ZEND_VM_KIND_HYBRID) { out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f,"static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op);\n"); + out($f,"static const void *zend_vm_get_opcode_handler_func(uint8_t opcode, const zend_op* op);\n"); out($f,"#else\n"); out($f,"# define zend_vm_get_opcode_handler_func zend_vm_get_opcode_handler\n"); out($f,"#endif\n\n"); @@ -2350,9 +2350,9 @@ function gen_vm_opcodes_header( $str .= "#define ZEND_VM_OP2_FLAGS(flags) ((flags >> 8) & 0xff)\n"; $str .= "\n"; $str .= "BEGIN_EXTERN_C()\n\n"; - $str .= "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode);\n"; - $str .= "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode);\n"; - $str .= "ZEND_API zend_uchar zend_get_opcode_id(const char *name, size_t length);\n\n"; + $str .= "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode);\n"; + $str .= "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode);\n"; + $str .= "ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length);\n\n"; $str .= "END_EXTERN_C()\n\n"; $code_len = strlen((string) $max_opcode); @@ -2636,22 +2636,22 @@ function gen_vm($def, $skel) { } fputs($f, "};\n\n"); - fputs($f, "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode) {\n"); + fputs($f, "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode) {\n"); fputs($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); fputs($f, "\t\treturn NULL;\n"); fputs($f, "\t}\n"); fputs($f, "\treturn zend_vm_opcodes_names[opcode];\n"); fputs($f, "}\n"); - fputs($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode) {\n"); + fputs($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n"); fputs($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); fputs($f, "\t\topcode = ZEND_NOP;\n"); fputs($f, "\t}\n"); fputs($f, "\treturn zend_vm_opcodes_flags[opcode];\n"); fputs($f, "}\n"); - fputs($f, "ZEND_API zend_uchar zend_get_opcode_id(const char *name, size_t length) {\n"); - fputs($f, "\tzend_uchar opcode;\n"); + fputs($f, "ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length) {\n"); + fputs($f, "\tuint8_t opcode;\n"); fputs($f, "\tfor (opcode = 0; opcode < (sizeof(zend_vm_opcodes_names) / sizeof(zend_vm_opcodes_names[0])) - 1; opcode++) {\n"); fputs($f, "\t\tconst char *opcode_name = zend_vm_opcodes_names[opcode];\n"); fputs($f, "\t\tif (opcode_name && strncmp(opcode_name, name, length) == 0) {\n"); @@ -2699,7 +2699,7 @@ function gen_vm($def, $skel) { } out($f, "\t(user_opcode_handler_t)NULL\n};\n\n"); - out($f, "static zend_uchar zend_user_opcodes[256] = {"); + out($f, "static uint8_t zend_user_opcodes[256] = {"); for ($i = 0; $i < 255; ++$i) { if ($i % 16 == 1) out($f, "\n\t"); out($f, "$i,"); @@ -2791,7 +2791,7 @@ function gen_vm($def, $skel) { } out($f, "}\n\n"); out($f, "#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC\n"); - out($f, "static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op)\n"); + out($f, "static const void *zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op)\n"); out($f, "{\n"); if (!ZEND_VM_SPEC) { out($f, "\treturn zend_opcode_handlers[zend_vm_get_opcode_handler_idx(opcode, op)];\n"); @@ -2804,7 +2804,7 @@ function gen_vm($def, $skel) { if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { // Generate zend_vm_get_opcode_handler_func() function out($f, "#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID\n"); - out($f,"static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op)\n"); + out($f,"static const void *zend_vm_get_opcode_handler_func(uint8_t opcode, const zend_op* op)\n"); out($f, "{\n"); out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n"); if (!ZEND_VM_SPEC) { @@ -2819,7 +2819,7 @@ function gen_vm($def, $skel) { // Generate zend_vm_get_opcode_handler() function out($f, "ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler(zend_op* op)\n"); out($f, "{\n"); - out($f, "\tzend_uchar opcode = zend_user_opcodes[op->opcode];\n"); + out($f, "\tuint8_t opcode = zend_user_opcodes[op->opcode];\n"); if (!ZEND_VM_SPEC) { out($f, "\top->handler = zend_opcode_handlers[zend_vm_get_opcode_handler_idx(opcode, op)];\n"); } else { @@ -2836,7 +2836,7 @@ function gen_vm($def, $skel) { // Generate zend_vm_set_opcode_handler_ex() function out($f, "ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint32_t op2_info, uint32_t res_info)\n"); out($f, "{\n"); - out($f, "\tzend_uchar opcode = zend_user_opcodes[op->opcode];\n"); + out($f, "\tuint8_t opcode = zend_user_opcodes[op->opcode];\n"); if (!ZEND_VM_SPEC) { out($f, "\top->handler = zend_opcode_handlers[zend_vm_get_opcode_handler_idx(opcode, op)];\n"); } else { diff --git a/Zend/zend_vm_handlers.h b/Zend/zend_vm_handlers.h index d07c63d89f4f7..fae2138ef912e 100644 --- a/Zend/zend_vm_handlers.h +++ b/Zend/zend_vm_handlers.h @@ -1279,572 +1279,581 @@ _(2431, ZEND_UNSET_STATIC_PROP_SPEC) \ _(2432, ZEND_ISSET_ISEMPTY_STATIC_PROP_SPEC) \ _(2433, ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_CONST) \ - _(2435, ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_CONST) \ - _(2436, ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_CONST) \ - _(2438, ZEND_BIND_LEXICAL_SPEC_TMP_CV) \ - _(2439, ZEND_BIND_STATIC_SPEC_CV_UNUSED) \ - _(2440, ZEND_FETCH_THIS_SPEC_UNUSED_UNUSED) \ - _(2441, ZEND_SEND_FUNC_ARG_SPEC_VAR_CONST) \ - _(2444, ZEND_SEND_FUNC_ARG_SPEC_VAR_UNUSED) \ - _(2446, ZEND_ISSET_ISEMPTY_THIS_SPEC_UNUSED_UNUSED) \ - _(2447, ZEND_SWITCH_LONG_SPEC_CONST_CONST) \ - _(2448, ZEND_SWITCH_LONG_SPEC_TMPVARCV_CONST) \ - _(2449, ZEND_SWITCH_LONG_SPEC_TMPVARCV_CONST) \ - _(2451, ZEND_SWITCH_LONG_SPEC_TMPVARCV_CONST) \ - _(2452, ZEND_SWITCH_STRING_SPEC_CONST_CONST) \ - _(2453, ZEND_SWITCH_STRING_SPEC_TMPVARCV_CONST) \ - _(2454, ZEND_SWITCH_STRING_SPEC_TMPVARCV_CONST) \ - _(2456, ZEND_SWITCH_STRING_SPEC_TMPVARCV_CONST) \ - _(2457, ZEND_IN_ARRAY_SPEC_CONST_CONST) \ - _(2458, ZEND_IN_ARRAY_SPEC_TMP_CONST) \ - _(2459, ZEND_IN_ARRAY_SPEC_VAR_CONST) \ - _(2461, ZEND_IN_ARRAY_SPEC_CV_CONST) \ - _(2462, ZEND_COUNT_SPEC_CONST_UNUSED) \ - _(2463, ZEND_COUNT_SPEC_TMPVAR_UNUSED) \ - _(2464, ZEND_COUNT_SPEC_TMPVAR_UNUSED) \ - _(2466, ZEND_COUNT_SPEC_CV_UNUSED) \ - _(2467, ZEND_GET_CLASS_SPEC_CONST_UNUSED) \ - _(2468, ZEND_GET_CLASS_SPEC_TMPVAR_UNUSED) \ - _(2469, ZEND_GET_CLASS_SPEC_TMPVAR_UNUSED) \ - _(2470, ZEND_GET_CLASS_SPEC_UNUSED_UNUSED) \ - _(2471, ZEND_GET_CLASS_SPEC_CV_UNUSED) \ - _(2472, ZEND_GET_CALLED_CLASS_SPEC_UNUSED_UNUSED) \ - _(2473, ZEND_GET_TYPE_SPEC_CONST_UNUSED) \ - _(2474, ZEND_GET_TYPE_SPEC_TMP_UNUSED) \ - _(2475, ZEND_GET_TYPE_SPEC_VAR_UNUSED) \ - _(2477, ZEND_GET_TYPE_SPEC_CV_UNUSED) \ - _(2478, ZEND_ARRAY_KEY_EXISTS_SPEC_CONST_CONST) \ - _(2479, ZEND_ARRAY_KEY_EXISTS_SPEC_CONST_TMPVAR) \ - _(2480, ZEND_ARRAY_KEY_EXISTS_SPEC_CONST_TMPVAR) \ - _(2482, ZEND_ARRAY_KEY_EXISTS_SPEC_CONST_CV) \ - _(2483, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_CONST) \ - _(2484, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_TMPVAR) \ - _(2485, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_TMPVAR) \ - _(2487, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_CV) \ - _(2488, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_CONST) \ - _(2489, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_TMPVAR) \ - _(2490, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_TMPVAR) \ - _(2492, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_CV) \ - _(2498, ZEND_ARRAY_KEY_EXISTS_SPEC_CV_CONST) \ - _(2499, ZEND_ARRAY_KEY_EXISTS_SPEC_CV_TMPVAR) \ - _(2500, ZEND_ARRAY_KEY_EXISTS_SPEC_CV_TMPVAR) \ - _(2502, ZEND_ARRAY_KEY_EXISTS_SPEC_CV_CV) \ - _(2503, ZEND_MATCH_SPEC_CONST_CONST) \ - _(2504, ZEND_MATCH_SPEC_TMPVARCV_CONST) \ - _(2505, ZEND_MATCH_SPEC_TMPVARCV_CONST) \ - _(2507, ZEND_MATCH_SPEC_TMPVARCV_CONST) \ - _(2513, ZEND_CASE_STRICT_SPEC_TMP_CONST) \ - _(2514, ZEND_CASE_STRICT_SPEC_TMP_TMP) \ - _(2515, ZEND_CASE_STRICT_SPEC_TMP_VAR) \ - _(2517, ZEND_CASE_STRICT_SPEC_TMP_CV) \ - _(2518, ZEND_CASE_STRICT_SPEC_VAR_CONST) \ - _(2519, ZEND_CASE_STRICT_SPEC_VAR_TMP) \ - _(2520, ZEND_CASE_STRICT_SPEC_VAR_VAR) \ - _(2522, ZEND_CASE_STRICT_SPEC_VAR_CV) \ - _(2533, ZEND_MATCH_ERROR_SPEC_CONST_UNUSED) \ - _(2534, ZEND_MATCH_ERROR_SPEC_TMPVARCV_UNUSED) \ - _(2535, ZEND_MATCH_ERROR_SPEC_TMPVARCV_UNUSED) \ - _(2537, ZEND_MATCH_ERROR_SPEC_TMPVARCV_UNUSED) \ - _(2538, ZEND_JMP_NULL_SPEC_CONST) \ - _(2539, ZEND_JMP_NULL_SPEC_TMP) \ - _(2540, ZEND_JMP_NULL_SPEC_VAR) \ - _(2542, ZEND_JMP_NULL_SPEC_CV) \ - _(2543, ZEND_CHECK_UNDEF_ARGS_SPEC_UNUSED_UNUSED) \ - _(2544, ZEND_FETCH_GLOBALS_SPEC_UNUSED_UNUSED) \ - _(2545, ZEND_VERIFY_NEVER_TYPE_SPEC_UNUSED_UNUSED) \ - _(2546, ZEND_CALLABLE_CONVERT_SPEC_UNUSED_UNUSED) \ - _(2547, ZEND_RECV_NOTYPE_SPEC) \ - _(2548, ZEND_JMP_FORWARD_SPEC) \ - _(2554, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2555, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2556, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2558, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2559, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2560, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2561, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2563, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2569, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2570, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2571, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2573, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2579, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2580, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2581, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2583, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2584, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2585, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2586, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2588, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2594, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2595, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2596, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2598, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2604, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2605, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2606, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2608, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2609, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2610, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2611, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2613, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2619, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2620, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2621, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2623, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2625, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ - _(2626, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ - _(2628, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ - _(2629, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2630, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2631, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2633, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2634, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2635, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2636, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2638, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2644, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2645, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2646, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2648, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2650, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ - _(2651, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ - _(2653, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ - _(2654, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2655, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2656, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2658, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2659, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2660, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2661, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2663, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2669, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2670, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2671, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2673, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2675, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(2676, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(2678, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(2679, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2680, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2681, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2683, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2684, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2685, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2686, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2688, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2694, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2695, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2696, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2698, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2704, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2705, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2706, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2708, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2709, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2710, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2711, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2713, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2719, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2720, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2721, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2723, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2729, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2730, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2731, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2733, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2734, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2735, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2736, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2738, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2744, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2745, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2746, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2748, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2754, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2755, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2756, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2758, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2759, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2760, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2761, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2763, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2769, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2770, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2771, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2773, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2789, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2790, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2791, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2792, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2793, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2794, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2795, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2796, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2797, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2801, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2802, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2803, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2804, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2805, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2806, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2807, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2808, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2809, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2810, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2811, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2812, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2816, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2817, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2818, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2834, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2835, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2836, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2837, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2838, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2839, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2840, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2841, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2842, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2846, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2847, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2848, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2864, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2865, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2866, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2867, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2868, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2869, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2870, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2871, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2872, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2876, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2877, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2878, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2879, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2880, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2881, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2882, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2883, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2884, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2885, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2886, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2887, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2891, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2892, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2893, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2909, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2910, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2911, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2912, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2913, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2914, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2915, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2916, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2917, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2921, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2922, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2923, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2939, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2940, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2941, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2942, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2943, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2944, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2945, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2946, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2947, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2951, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2952, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2953, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2954, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2955, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2956, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2957, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2958, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2959, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2960, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2961, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2962, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2966, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2967, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2968, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2984, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2985, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2986, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2987, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2988, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2989, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2990, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2991, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2992, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2996, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2997, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2998, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3014, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3015, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3016, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3017, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3018, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3019, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3020, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3021, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3022, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3026, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3027, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3028, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3029, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3030, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3031, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3032, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3033, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3034, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3035, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3036, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3037, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3041, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3042, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3043, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3059, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3060, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3061, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3062, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3063, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3064, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3065, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3066, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3067, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3071, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3072, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3073, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3074, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ - _(3078, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CV) \ - _(3079, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ - _(3083, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CV) \ - _(3087, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ - _(3088, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3089, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3090, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ - _(3091, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3092, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3096, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ - _(3097, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3098, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3099, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3100, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3101, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3102, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3103, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3104, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3105, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3106, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3107, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3111, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3112, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3113, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3114, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3115, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3116, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3117, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3118, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3119, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3120, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3121, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3122, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3126, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3127, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3128, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3144, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3145, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3146, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3147, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3148, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3149, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3150, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3151, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3152, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3156, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3157, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3158, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3162, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3163, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3164, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3165, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3166, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3167, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3171, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3172, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3173, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3174, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3175, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3176, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3177, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3178, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3179, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3180, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3181, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3182, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3186, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3187, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3188, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3189, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3190, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3191, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3192, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3193, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3194, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3195, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3196, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3197, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3201, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3202, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3203, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3219, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3220, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3221, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3222, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3223, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3224, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3225, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3226, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3227, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3231, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3232, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3233, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3237, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ - _(3238, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3239, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3240, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ - _(3241, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3242, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3246, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ - _(3247, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3248, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3249, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3250, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3251, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3252, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3253, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3254, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3255, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3256, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3257, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3261, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3262, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3263, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3264, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3265, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3266, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3267, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3268, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3269, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3270, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3271, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3272, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3276, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3277, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3278, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3294, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3295, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3296, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3297, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3298, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3299, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3300, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3301, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3302, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3306, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3307, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3308, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3312, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3313, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3314, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3315, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3316, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3317, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3321, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3322, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3323, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3324, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3325, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3326, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3327, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3328, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3329, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3330, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3331, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3332, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3336, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3337, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3338, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3339, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3340, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3341, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3342, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3343, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3344, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3345, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3346, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3347, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3351, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3352, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3353, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3369, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3370, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3371, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3372, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3373, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3374, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3375, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3376, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3377, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3381, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3382, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3383, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3384, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ - _(3385, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ - _(3386, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_UNUSED) \ - _(3387, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_USED) \ - _(3388, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ - _(3389, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ - _(3390, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_UNUSED) \ - _(3391, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_USED) \ - _(3392, ZEND_POST_INC_LONG_NO_OVERFLOW_SPEC_CV) \ - _(3393, ZEND_POST_INC_LONG_SPEC_CV) \ - _(3394, ZEND_POST_DEC_LONG_NO_OVERFLOW_SPEC_CV) \ - _(3395, ZEND_POST_DEC_LONG_SPEC_CV) \ - _(3396, ZEND_QM_ASSIGN_LONG_SPEC_CONST) \ - _(3397, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ - _(3398, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ - _(3400, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ - _(3401, ZEND_QM_ASSIGN_DOUBLE_SPEC_CONST) \ - _(3402, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ - _(3403, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ - _(3405, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ - _(3406, ZEND_QM_ASSIGN_NOREF_SPEC_CONST) \ - _(3407, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3408, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3410, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3412, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3413, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3415, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3416, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ - _(3417, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3418, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3420, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3421, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ - _(3422, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3423, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3425, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3431, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) \ - _(3432, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3433, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3435, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3438, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ - _(3440, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ - _(3443, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ - _(3445, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ - _(3446, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ - _(3447, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ - _(3448, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ - _(3449, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ - _(3449+1, ZEND_NULL) + _(2434, ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV) \ + _(2435, ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV) \ + _(2437, ZEND_FETCH_CLASS_CONSTANT_SPEC_CONST_TMPVARCV) \ + _(2443, ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_CONST) \ + _(2444, ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV) \ + _(2445, ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV) \ + _(2447, ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_TMPVARCV) \ + _(2448, ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_CONST) \ + _(2449, ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV) \ + _(2450, ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV) \ + _(2452, ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_TMPVARCV) \ + _(2458, ZEND_BIND_LEXICAL_SPEC_TMP_CV) \ + _(2459, ZEND_BIND_STATIC_SPEC_CV_UNUSED) \ + _(2460, ZEND_FETCH_THIS_SPEC_UNUSED_UNUSED) \ + _(2461, ZEND_SEND_FUNC_ARG_SPEC_VAR_CONST) \ + _(2464, ZEND_SEND_FUNC_ARG_SPEC_VAR_UNUSED) \ + _(2466, ZEND_ISSET_ISEMPTY_THIS_SPEC_UNUSED_UNUSED) \ + _(2467, ZEND_SWITCH_LONG_SPEC_CONST_CONST) \ + _(2468, ZEND_SWITCH_LONG_SPEC_TMPVARCV_CONST) \ + _(2469, ZEND_SWITCH_LONG_SPEC_TMPVARCV_CONST) \ + _(2471, ZEND_SWITCH_LONG_SPEC_TMPVARCV_CONST) \ + _(2472, ZEND_SWITCH_STRING_SPEC_CONST_CONST) \ + _(2473, ZEND_SWITCH_STRING_SPEC_TMPVARCV_CONST) \ + _(2474, ZEND_SWITCH_STRING_SPEC_TMPVARCV_CONST) \ + _(2476, ZEND_SWITCH_STRING_SPEC_TMPVARCV_CONST) \ + _(2477, ZEND_IN_ARRAY_SPEC_CONST_CONST) \ + _(2478, ZEND_IN_ARRAY_SPEC_TMP_CONST) \ + _(2479, ZEND_IN_ARRAY_SPEC_VAR_CONST) \ + _(2481, ZEND_IN_ARRAY_SPEC_CV_CONST) \ + _(2482, ZEND_COUNT_SPEC_CONST_UNUSED) \ + _(2483, ZEND_COUNT_SPEC_TMPVAR_UNUSED) \ + _(2484, ZEND_COUNT_SPEC_TMPVAR_UNUSED) \ + _(2486, ZEND_COUNT_SPEC_CV_UNUSED) \ + _(2487, ZEND_GET_CLASS_SPEC_CONST_UNUSED) \ + _(2488, ZEND_GET_CLASS_SPEC_TMPVAR_UNUSED) \ + _(2489, ZEND_GET_CLASS_SPEC_TMPVAR_UNUSED) \ + _(2490, ZEND_GET_CLASS_SPEC_UNUSED_UNUSED) \ + _(2491, ZEND_GET_CLASS_SPEC_CV_UNUSED) \ + _(2492, ZEND_GET_CALLED_CLASS_SPEC_UNUSED_UNUSED) \ + _(2493, ZEND_GET_TYPE_SPEC_CONST_UNUSED) \ + _(2494, ZEND_GET_TYPE_SPEC_TMP_UNUSED) \ + _(2495, ZEND_GET_TYPE_SPEC_VAR_UNUSED) \ + _(2497, ZEND_GET_TYPE_SPEC_CV_UNUSED) \ + _(2498, ZEND_ARRAY_KEY_EXISTS_SPEC_CONST_CONST) \ + _(2499, ZEND_ARRAY_KEY_EXISTS_SPEC_CONST_TMPVAR) \ + _(2500, ZEND_ARRAY_KEY_EXISTS_SPEC_CONST_TMPVAR) \ + _(2502, ZEND_ARRAY_KEY_EXISTS_SPEC_CONST_CV) \ + _(2503, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_CONST) \ + _(2504, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_TMPVAR) \ + _(2505, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_TMPVAR) \ + _(2507, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_CV) \ + _(2508, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_CONST) \ + _(2509, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_TMPVAR) \ + _(2510, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_TMPVAR) \ + _(2512, ZEND_ARRAY_KEY_EXISTS_SPEC_TMPVAR_CV) \ + _(2518, ZEND_ARRAY_KEY_EXISTS_SPEC_CV_CONST) \ + _(2519, ZEND_ARRAY_KEY_EXISTS_SPEC_CV_TMPVAR) \ + _(2520, ZEND_ARRAY_KEY_EXISTS_SPEC_CV_TMPVAR) \ + _(2522, ZEND_ARRAY_KEY_EXISTS_SPEC_CV_CV) \ + _(2523, ZEND_MATCH_SPEC_CONST_CONST) \ + _(2524, ZEND_MATCH_SPEC_TMPVARCV_CONST) \ + _(2525, ZEND_MATCH_SPEC_TMPVARCV_CONST) \ + _(2527, ZEND_MATCH_SPEC_TMPVARCV_CONST) \ + _(2533, ZEND_CASE_STRICT_SPEC_TMP_CONST) \ + _(2534, ZEND_CASE_STRICT_SPEC_TMP_TMP) \ + _(2535, ZEND_CASE_STRICT_SPEC_TMP_VAR) \ + _(2537, ZEND_CASE_STRICT_SPEC_TMP_CV) \ + _(2538, ZEND_CASE_STRICT_SPEC_VAR_CONST) \ + _(2539, ZEND_CASE_STRICT_SPEC_VAR_TMP) \ + _(2540, ZEND_CASE_STRICT_SPEC_VAR_VAR) \ + _(2542, ZEND_CASE_STRICT_SPEC_VAR_CV) \ + _(2553, ZEND_MATCH_ERROR_SPEC_CONST_UNUSED) \ + _(2554, ZEND_MATCH_ERROR_SPEC_TMPVARCV_UNUSED) \ + _(2555, ZEND_MATCH_ERROR_SPEC_TMPVARCV_UNUSED) \ + _(2557, ZEND_MATCH_ERROR_SPEC_TMPVARCV_UNUSED) \ + _(2558, ZEND_JMP_NULL_SPEC_CONST) \ + _(2559, ZEND_JMP_NULL_SPEC_TMP) \ + _(2560, ZEND_JMP_NULL_SPEC_VAR) \ + _(2562, ZEND_JMP_NULL_SPEC_CV) \ + _(2563, ZEND_CHECK_UNDEF_ARGS_SPEC_UNUSED_UNUSED) \ + _(2564, ZEND_FETCH_GLOBALS_SPEC_UNUSED_UNUSED) \ + _(2565, ZEND_VERIFY_NEVER_TYPE_SPEC_UNUSED_UNUSED) \ + _(2566, ZEND_CALLABLE_CONVERT_SPEC_UNUSED_UNUSED) \ + _(2567, ZEND_RECV_NOTYPE_SPEC) \ + _(2568, ZEND_JMP_FORWARD_SPEC) \ + _(2574, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2575, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2576, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2578, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2579, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2580, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2581, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2583, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2589, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2590, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2591, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2593, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2599, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ + _(2600, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2601, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2603, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2604, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ + _(2605, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2606, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2608, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2614, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ + _(2615, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2616, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2618, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2624, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2625, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2626, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2628, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2629, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2630, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2631, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2633, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2639, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2640, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2641, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2643, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2645, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2646, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2648, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2649, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2650, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2651, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2653, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2654, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2655, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2656, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2658, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2664, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2665, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2666, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2668, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2670, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2671, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2673, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2674, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ + _(2675, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2676, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2678, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2679, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ + _(2680, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2681, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2683, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2689, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ + _(2690, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2691, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2693, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2695, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2696, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2698, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2699, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2700, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2701, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2703, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2704, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2705, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2706, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2708, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2714, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2715, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2716, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2718, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2724, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2725, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2726, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2728, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2729, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2730, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2731, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2733, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2739, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2740, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2741, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2743, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2749, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ + _(2750, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2751, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2753, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2754, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ + _(2755, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2756, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2758, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2764, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ + _(2765, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2766, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2768, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2774, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2775, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2776, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2778, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2779, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2780, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2781, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2783, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2789, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2790, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2791, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2793, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2809, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2810, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2811, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2812, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2813, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2814, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2815, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2816, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2817, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2821, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2822, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2823, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2824, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2825, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2826, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2827, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2828, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2829, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2830, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2831, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2832, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2836, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2837, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2838, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2854, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2855, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2856, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2857, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2858, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2859, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2860, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2861, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2862, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2866, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2867, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2868, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2884, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2885, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2886, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2887, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2888, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2889, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2890, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2891, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2892, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2896, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2897, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2898, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2899, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2900, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2901, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2902, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2903, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2904, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2905, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2906, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2907, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2911, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2912, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2913, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2929, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2930, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2931, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2932, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2933, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2934, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2935, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2936, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2937, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2941, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2942, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2943, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2959, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2960, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2961, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2962, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2963, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2964, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2965, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2966, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2967, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2971, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2972, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2973, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2974, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2975, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2976, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2977, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2978, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2979, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2980, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2981, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2982, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2986, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2987, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2988, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3004, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3005, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3006, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3007, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3008, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3009, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3010, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3011, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3012, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3016, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3017, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3018, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3034, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3035, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3036, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3037, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3038, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3039, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3040, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3041, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3042, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3046, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3047, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3048, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3049, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3050, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3051, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3052, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3053, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3054, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3055, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3056, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3057, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3061, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3062, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3063, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3079, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3080, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3081, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3082, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3083, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3084, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3085, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3086, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3087, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3091, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3092, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3093, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3094, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ + _(3098, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CV) \ + _(3099, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ + _(3103, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CV) \ + _(3107, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ + _(3108, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3109, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3110, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ + _(3111, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3112, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3116, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ + _(3117, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3118, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3119, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3120, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3121, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3122, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3123, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3124, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3125, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3126, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3127, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3131, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3132, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3133, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3134, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3135, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3136, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3137, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3138, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3139, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3140, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3141, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3142, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3146, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3147, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3148, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3164, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3165, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3166, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3167, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3168, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3169, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3170, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3171, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3172, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3176, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3177, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3178, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3182, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3183, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3184, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3185, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3186, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3187, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3191, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3192, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3193, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3194, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3195, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3196, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3197, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3198, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3199, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3200, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3201, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3202, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3206, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3207, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3208, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3209, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3210, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3211, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3212, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3213, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3214, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3215, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3216, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3217, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3221, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3222, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3223, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3239, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3240, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3241, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3242, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3243, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3244, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3245, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3246, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3247, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3251, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3252, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3253, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3257, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ + _(3258, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3259, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3260, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ + _(3261, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3262, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3266, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ + _(3267, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3268, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3269, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3270, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3271, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3272, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3273, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3274, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3275, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3276, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3277, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3281, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3282, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3283, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3284, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3285, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3286, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3287, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3288, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3289, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3290, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3291, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3292, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3296, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3297, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3298, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3314, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3315, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3316, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3317, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3318, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3319, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3320, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3321, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3322, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3326, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3327, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3328, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3332, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3333, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3334, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3335, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3336, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3337, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3341, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3342, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3343, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3344, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3345, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3346, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3347, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3348, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3349, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3350, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3351, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3352, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3356, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3357, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3358, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3359, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3360, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3361, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3362, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3363, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3364, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3365, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3366, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3367, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3371, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3372, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3373, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3389, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3390, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3391, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3392, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3393, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3394, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3395, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3396, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3397, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3401, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3402, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3403, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3404, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ + _(3405, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ + _(3406, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_UNUSED) \ + _(3407, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_USED) \ + _(3408, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ + _(3409, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ + _(3410, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_UNUSED) \ + _(3411, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_USED) \ + _(3412, ZEND_POST_INC_LONG_NO_OVERFLOW_SPEC_CV) \ + _(3413, ZEND_POST_INC_LONG_SPEC_CV) \ + _(3414, ZEND_POST_DEC_LONG_NO_OVERFLOW_SPEC_CV) \ + _(3415, ZEND_POST_DEC_LONG_SPEC_CV) \ + _(3416, ZEND_QM_ASSIGN_LONG_SPEC_CONST) \ + _(3417, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3418, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3420, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3421, ZEND_QM_ASSIGN_DOUBLE_SPEC_CONST) \ + _(3422, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3423, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3425, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3426, ZEND_QM_ASSIGN_NOREF_SPEC_CONST) \ + _(3427, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ + _(3428, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ + _(3430, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ + _(3432, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3433, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3435, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3436, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ + _(3437, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3438, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3440, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3441, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ + _(3442, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3443, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3445, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3451, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) \ + _(3452, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3453, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3455, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3458, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ + _(3460, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ + _(3463, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ + _(3465, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ + _(3466, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ + _(3467, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ + _(3468, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ + _(3469, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ + _(3469+1, ZEND_NULL) diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index c3f5e9d427aa4..a9e4317e04e2d 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -410,7 +410,7 @@ static uint32_t zend_vm_opcodes_flags[203] = { 0x00047000, 0x00040000, 0x00067000, - 0x00040373, + 0x00040b73, 0x00100101, 0x00100101, 0x00000101, @@ -434,20 +434,20 @@ static uint32_t zend_vm_opcodes_flags[203] = { 0x00000101, }; -ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode) { +ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode) { if (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) { return NULL; } return zend_vm_opcodes_names[opcode]; } -ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode) { +ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) { if (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) { opcode = ZEND_NOP; } return zend_vm_opcodes_flags[opcode]; } -ZEND_API zend_uchar zend_get_opcode_id(const char *name, size_t length) { - zend_uchar opcode; +ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length) { + uint8_t opcode; for (opcode = 0; opcode < (sizeof(zend_vm_opcodes_names) / sizeof(zend_vm_opcodes_names[0])) - 1; opcode++) { const char *opcode_name = zend_vm_opcodes_names[opcode]; if (opcode_name && strncmp(opcode_name, name, length) == 0) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 165e914e1cd53..43bd8bc252802 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -77,9 +77,9 @@ BEGIN_EXTERN_C() -ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode); -ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode); -ZEND_API zend_uchar zend_get_opcode_id(const char *name, size_t length); +ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode); +ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode); +ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length); END_EXTERN_C() diff --git a/benchmark/.gitignore b/benchmark/.gitignore new file mode 100644 index 0000000000000..cc2bbd2422f01 --- /dev/null +++ b/benchmark/.gitignore @@ -0,0 +1 @@ +/repos diff --git a/benchmark/benchmark.php b/benchmark/benchmark.php new file mode 100644 index 0000000000000..9ca015f0a223b --- /dev/null +++ b/benchmark/benchmark.php @@ -0,0 +1,122 @@ +stdout; +} + +function runBench(bool $jit): array { + return runValgrindPhpCgiCommand([dirname(__DIR__) . '/Zend/bench.php'], jit: $jit); +} + +function runSymfonyDemo(bool $jit): array { + $dir = __DIR__ . '/repos/symfony-demo-2.2.3'; + cloneRepo($dir, 'https://github.com/php/benchmarking-symfony-demo-2.2.3.git'); + runPhpCommand([$dir . '/bin/console', 'cache:clear']); + runPhpCommand([$dir . '/bin/console', 'cache:warmup']); + return runValgrindPhpCgiCommand([$dir . '/public/index.php'], cwd: $dir, jit: $jit, warmup: 50, repeat: 50); +} + +function runWordpress(bool $jit): array { + $dir = __DIR__ . '/repos/wordpress-6.2'; + cloneRepo($dir, 'https://github.com/php/benchmarking-wordpress-6.2.git'); + + /* FIXME: It might be better to use a stable version of PHP for this command because we can't + * easily alter the phar file */ + runPhpCommand([ + '-d error_reporting=0', + 'wp-cli.phar', + 'core', + 'install', + '--url=wordpress.local', + '--title="Wordpress"', + '--admin_user=wordpress', + '--admin_password=wordpress', + '--admin_email=benchmark@php.net', + ], $dir); + + // Warmup + runPhpCommand([$dir . '/index.php'], $dir); + return runValgrindPhpCgiCommand([$dir . '/index.php'], cwd: $dir, jit: $jit, warmup: 50, repeat: 50); +} + +function runPhpCommand(array $args, ?string $cwd = null): ProcessResult { + return runCommand([PHP_BINARY, ...$args], $cwd); +} + +function runValgrindPhpCgiCommand( + array $args, + ?string $cwd = null, + bool $jit = false, + int $warmup = 0, + int $repeat = 1, +): array { + global $phpCgi; + $process = runCommand([ + 'valgrind', + '--tool=callgrind', + '--dump-instr=yes', + '--callgrind-out-file=/dev/null', + '--', + $phpCgi, + '-T' . ($warmup ? $warmup . ',' : '') . $repeat, + '-d max_execution_time=0', + '-d opcache.enable=1', + '-d opcache.jit_buffer_size=' . ($jit ? '128M' : '0'), + '-d opcache.validate_timestamps=0', + ...$args, + ]); + $instructions = extractInstructionsFromValgrindOutput($process->stderr); + if ($repeat > 1) { + $instructions = gmp_strval(gmp_div_q($instructions, $repeat)); + } + return ['instructions' => $instructions]; +} + +function extractInstructionsFromValgrindOutput(string $output): string { + preg_match("(==[0-9]+== Events : Ir\n==[0-9]+== Collected : (?[0-9]+))", $output, $matches); + return $matches['instructions'] ?? throw new \Exception('Unexpected valgrind output'); +} + +main(); diff --git a/benchmark/docker-compose.yml b/benchmark/docker-compose.yml new file mode 100644 index 0000000000000..6d62806d355b3 --- /dev/null +++ b/benchmark/docker-compose.yml @@ -0,0 +1,11 @@ +version: "3.8" +services: + wordpress_db: + image: mysql:8.0 + ports: + - "3306:3306" + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: wordpress + MYSQL_USER: wordpress + MYSQL_PASSWORD: wordpress diff --git a/benchmark/generate_diff.php b/benchmark/generate_diff.php new file mode 100644 index 0000000000000..8ad8fcc40ef84 --- /dev/null +++ b/benchmark/generate_diff.php @@ -0,0 +1,63 @@ + $headBenchmark) { + $baseInstructions = $baseSummary[$name]['instructions'] ?? null; + $headInstructions = $headSummary[$name]['instructions']; + $output .= "| $name | " + . formatInstructions($baseInstructions) . " | " + . formatInstructions($headInstructions) . " | " + . formatDiff($baseInstructions, $headInstructions) . " |\n"; + } + return $output; +} + +function formatInstructions(?int $instructions): string { + if ($instructions === null) { + return '-'; + } + if ($instructions > 1e6) { + return sprintf('%.0fM', $instructions / 1e6); + } elseif ($instructions > 1e3) { + return sprintf('%.0fK', $instructions / 1e3); + } else { + return (string) $instructions; + } +} + +function formatDiff(?int $baseInstructions, int $headInstructions): string { + if ($baseInstructions === null) { + return '-'; + } + $instructionDiff = $headInstructions - $baseInstructions; + return sprintf('%.2f%%', $instructionDiff / $baseInstructions * 100); +} + +$headCommitHash = $argv[1] ?? null; +$baseCommitHash = $argv[2] ?? null; +$output = main($headCommitHash, $baseCommitHash); +fwrite(STDOUT, $output); diff --git a/benchmark/shared.php b/benchmark/shared.php new file mode 100644 index 0000000000000..450101770b28b --- /dev/null +++ b/benchmark/shared.php @@ -0,0 +1,72 @@ + ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; + fwrite(STDOUT, "> $cmd\n"); + $processHandle = proc_open($cmd, $descriptorSpec, $pipes, $cwd ?? getcwd(), null); + + $stdin = $pipes[0]; + $stdout = $pipes[1]; + $stderr = $pipes[2]; + + fclose($stdin); + + stream_set_blocking($stdout, false); + stream_set_blocking($stderr, false); + + $stdoutEof = false; + $stderrEof = false; + + do { + $read = [$stdout, $stderr]; + $write = null; + $except = null; + + stream_select($read, $write, $except, 1, 0); + + foreach ($read as $stream) { + $chunk = fgets($stream); + if ($stream === $stdout) { + $result->stdout .= $chunk; + } elseif ($stream === $stderr) { + $result->stderr .= $chunk; + } + } + + $stdoutEof = $stdoutEof || feof($stdout); + $stderrEof = $stderrEof || feof($stderr); + } while(!$stdoutEof || !$stderrEof); + + fclose($stdout); + fclose($stderr); + + $statusCode = proc_close($processHandle); + if ($statusCode !== 0) { + fwrite(STDOUT, $result->stdout); + fwrite(STDERR, $result->stderr); + fwrite(STDERR, 'Exited with status code ' . $statusCode . "\n"); + exit($statusCode); + } + + return $result; +} + +function cloneRepo(string $path, string $url) { + if (is_dir($path)) { + return; + } + $dir = dirname($path); + $repo = basename($path); + if (!is_dir($dir)) { + mkdir($dir, 0755, true); + } + runCommand(['git', 'clone', '-q', '--end-of-options', $url, $repo], dirname($path)); +} diff --git a/build/gen_stub.php b/build/gen_stub.php index 31a5adc39a7af..c0b02b03738f2 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -218,11 +218,6 @@ public static function fromNode(Node $node): SimpleType { return new SimpleType($node->toLowerString(), true); } - if ($node->toLowerString() === 'true') { - // TODO PHP-Parser doesn't yet recognize true as a stand-alone built-in type - return new SimpleType($node->toLowerString(), true); - } - if ($node->toLowerString() === 'self') { throw new Exception('The exact class name must be used instead of "self"'); } @@ -650,11 +645,13 @@ public function isNullable(): bool { public function getWithoutNull(): Type { return new Type( - array_filter( - $this->types, - function(SimpleType $type) { - return !$type->isNull(); - } + array_values( + array_filter( + $this->types, + function(SimpleType $type) { + return !$type->isNull(); + } + ) ), false ); @@ -931,8 +928,11 @@ public function isUnknown(): bool class ConstName extends AbstractConstName { public string $const; - public function __construct(string $const) + public function __construct(?Name $namespace, string $const) { + if ($namespace && ($namespace = $namespace->slice(0, -1))) { + $const = $namespace->toString() . '\\' . $const; + } $this->const = $const; } @@ -941,6 +941,15 @@ public function isClassConst(): bool return false; } + public function isUnknown(): bool + { + $name = $this->__toString(); + if (($pos = strrpos($name, '\\')) !== false) { + $name = substr($name, $pos + 1); + } + return strtolower($name) === "unknown"; + } + public function __toString(): string { return $this->const; @@ -1566,49 +1575,95 @@ class EvaluatedValue /** @var mixed */ public $value; public SimpleType $type; - public ?string $cConstValue; + public Expr $expr; public bool $isUnknownConstValue; - public ?ConstInfo $originatingConst; + /** @var ConstInfo[] */ + public array $originatingConsts; /** * @param iterable $allConstInfos */ public static function createFromExpression(Expr $expr, ?SimpleType $constType, ?string $cConstName, iterable $allConstInfos): EvaluatedValue { - $originatingConst = null; - $isUnknownConstValue = null; + // This visitor replaces the PHP constants by C constants. It allows direct expansion of the compiled constants, e.g. later in the pretty printer. + $visitor = new class($allConstInfos) extends PhpParser\NodeVisitorAbstract + { + public array $visitedConstants = []; + /** @var iterable */ + public iterable $allConstInfos; + + /** + * @param iterable $allConstInfos + */ + public function __construct(iterable $allConstInfos) + { + $this->allConstInfos = $allConstInfos; + } - $evaluator = new ConstExprEvaluator( - function (Expr $expr) use ($allConstInfos, &$constType, &$originatingConst, &$isUnknownConstValue) { + public function enterNode(Node $expr) + { if (!$expr instanceof Expr\ConstFetch && !$expr instanceof Expr\ClassConstFetch) { - throw new Exception($this->getVariableTypeName() . " " . $this->getVariableLikeName() . " has an unsupported value"); + return; } if ($expr instanceof Expr\ClassConstFetch) { $originatingConstName = new ClassConstName($expr->class, $expr->name->toString()); } else { - $originatingConstName = new ConstName($expr->name->toString()); + $originatingConstName = new ConstName($expr->name->getAttribute('namespacedName'), $expr->name->toString()); } if ($originatingConstName->isUnknown()) { - $originatingConst = null; - $isUnknownConstValue = true; + return; + } + + foreach ($this->allConstInfos as $const) { + if ($originatingConstName->equals($const->name)) { + $this->visitedConstants[] = $const; + return $const->getValue($this->allConstInfos)->expr; + } + } + } + }; + + $nodeTraverser = new PhpParser\NodeTraverser; + $nodeTraverser->addVisitor($visitor); + $expr = $nodeTraverser->traverse([$expr])[0]; + + $isUnknownConstValue = false; + + $evaluator = new ConstExprEvaluator( + function (Expr $expr) use ($allConstInfos, &$isUnknownConstValue) { + // $expr is a ConstFetch with a name of a C macro here + if (!$expr instanceof Expr\ConstFetch) { + throw new Exception($this->getVariableTypeName() . " " . $this->getVariableLikeName() . " has an unsupported value"); + } + $constName = $expr->name->__toString(); + if (strtolower($constName) === "unknown") { + $isUnknownConstValue = true; return null; } foreach ($allConstInfos as $const) { - if (!$originatingConstName->equals($const->name)) { + if ($constName != $const->cValue) { continue; } - if ($constType === null && $const->phpDocType) { + if ($const->phpDocType) { $constType = $const->phpDocType->tryToSimpleType(); + if ($constType->isBool()) { + return true; + } elseif ($constType->isInt()) { + return 1; + } elseif ($constType->isFloat()) { + return M_PI; + } elseif ($constType->isString()) { + return $const->name; + } elseif ($constType->isArray()) { + return []; + } } - $originatingConst = $const; - $isUnknownConstValue = false; - return null; } @@ -1619,83 +1674,78 @@ function (Expr $expr) use ($allConstInfos, &$constType, &$originatingConst, &$is $result = $evaluator->evaluateDirectly($expr); return new EvaluatedValue( - $result, - $constType ?: SimpleType::fromValue($result), - $cConstName, - $originatingConst, - (bool) $isUnknownConstValue + $result, // note: we are generally not interested in the actual value of $result, unless it's a bare value, without constants + $constType ?? SimpleType::fromValue($result), + $cConstName === null ? $expr : new Expr\ConstFetch(new Node\Name($cConstName)), + $visitor->visitedConstants, + $isUnknownConstValue ); } public static function null(): EvaluatedValue { - return new self(null, SimpleType::null(), null, null, false); + return new self(null, SimpleType::null(), new Expr\ConstFetch(new Node\Name('null')), [], false); } /** * @param mixed $value + * @param ConstInfo[] $originatingConsts */ - private function __construct($value, SimpleType $type, ?string $cConstName, ?ConstInfo $originatingConst, bool $isUnknownConstValue) + private function __construct($value, SimpleType $type, Expr $expr, array $originatingConsts, bool $isUnknownConstValue) { $this->value = $value; $this->type = $type; - $this->cConstValue = $cConstName; - $this->originatingConst = $originatingConst; + $this->expr = $expr; + $this->originatingConsts = $originatingConsts; $this->isUnknownConstValue = $isUnknownConstValue; } - /** - * @param iterable $allConstInfos - */ - public function initializeZval(string $zvalName, iterable $allConstInfos): string + public function initializeZval(string $zvalName): string { - $cConstValue = $this->getCConstValue($allConstInfos); + $cExpr = $this->getCExpr(); $code = "\tzval $zvalName;\n"; if ($this->type->isNull()) { $code .= "\tZVAL_NULL(&$zvalName);\n"; } elseif ($this->type->isBool()) { - $code .= "\t" . ($this->value ? 'ZVAL_TRUE' : 'ZVAL_FALSE') . "(&$zvalName);\n"; + if ($cExpr == 'true') { + $code .= "\tZVAL_TRUE(&$zvalName);\n"; + } elseif ($cExpr == 'false') { + $code .= "\tZVAL_FALSE(&$zvalName);\n"; + } else { + $code .= "\tZVAL_BOOL(&$zvalName, $cExpr);\n"; + } } elseif ($this->type->isInt()) { - $code .= "\tZVAL_LONG(&$zvalName, " . ($cConstValue ?: $this->value) . ");\n"; + $code .= "\tZVAL_LONG(&$zvalName, $cExpr);\n"; } elseif ($this->type->isFloat()) { - $code .= "\tZVAL_DOUBLE(&$zvalName, " . ($cConstValue ?: $this->value) . ");\n"; + $code .= "\tZVAL_DOUBLE(&$zvalName, $cExpr);\n"; } elseif ($this->type->isString()) { - if (!$cConstValue && $this->value === "") { + if ($cExpr === '""') { $code .= "\tZVAL_EMPTY_STRING(&$zvalName);\n"; } else { - $constValue = $cConstValue ?: '"' . addslashes($this->value) . '"'; - $code .= "\tzend_string *{$zvalName}_str = zend_string_init($constValue, strlen($constValue), 1);\n"; + $code .= "\tzend_string *{$zvalName}_str = zend_string_init($cExpr, strlen($cExpr), 1);\n"; $code .= "\tZVAL_STR(&$zvalName, {$zvalName}_str);\n"; } } elseif ($this->type->isArray()) { - if (!$cConstValue && empty($this->value)) { + if ($cExpr == '[]') { $code .= "\tZVAL_EMPTY_ARRAY(&$zvalName);\n"; } else { throw new Exception("Unimplemented default value"); } } else { - throw new Exception("Invalid default value"); + throw new Exception("Invalid default value: " . print_r($this->type, true)); } return $code; } - /** - * @param iterable $allConstInfos - */ - public function getCConstValue(iterable $allConstInfos): ?string + public function getCExpr(): ?string { - if ($this->cConstValue) { - return $this->cConstValue; - } - - if ($this->originatingConst) { - return $this->originatingConst->getValue($allConstInfos)->getCConstValue($allConstInfos); - } - - return null; + // $this->expr has all its PHP constants replaced by C constants + $prettyPrinter = new Standard; + $expr = $prettyPrinter->prettyPrintExpr($this->expr); + return $expr[0] == '"' ? $expr : preg_replace('(\bnull\b)', 'NULL', str_replace('\\', '', $expr)); } } @@ -1911,8 +1961,10 @@ protected function getFieldSynopsisValueString(iterable $allConstInfos): ?string return null; } - if ($value->originatingConst) { - return $value->originatingConst->getFieldSynopsisValueString($allConstInfos); + if ($value->originatingConsts) { + return implode("\n", array_map(function (ConstInfo $const) use ($allConstInfos) { + return $const->getFieldSynopsisValueString($allConstInfos); + }, $value->originatingConsts)); } return $this->valueString; @@ -1934,7 +1986,8 @@ public function getDeclaration(iterable $allConstInfos): string } $value = EvaluatedValue::createFromExpression($this->value, $type, $this->cValue, $allConstInfos); - if ($value->isUnknownConstValue && !$value->cConstValue) { + // i.e. const NAME = UNKNOWN;, without the annotation + if ($value->isUnknownConstValue && $this->cValue === null && $value->expr instanceof Expr\ConstFetch && $value->expr->name->__toString() == $this->name->__toString()) { throw new Exception("Constant " . $this->name->__toString() . " must have a @cvalue annotation"); } @@ -1965,7 +2018,7 @@ private function getGlobalConstDeclaration(EvaluatedValue $value, iterable $allC { $constName = str_replace('\\', '\\\\', $this->name->__toString()); $constValue = $value->value; - $cConstValue = $value->getCConstValue($allConstInfos); + $cExpr = $value->getCExpr(); $flags = "CONST_PERSISTENT"; if ($this->phpVersionIdMinimumCompatibility !== null && $this->phpVersionIdMinimumCompatibility < 80000) { @@ -1980,19 +2033,19 @@ private function getGlobalConstDeclaration(EvaluatedValue $value, iterable $allC } if ($value->type->isBool()) { - return "\tREGISTER_BOOL_CONSTANT(\"$constName\", " . ($cConstValue ?: ($constValue ? "true" : "false")) . ", $flags);\n"; + return "\tREGISTER_BOOL_CONSTANT(\"$constName\", " . ($cExpr ?: ($constValue ? "true" : "false")) . ", $flags);\n"; } if ($value->type->isInt()) { - return "\tREGISTER_LONG_CONSTANT(\"$constName\", " . ($cConstValue ?: (int) $constValue) . ", $flags);\n"; + return "\tREGISTER_LONG_CONSTANT(\"$constName\", " . ($cExpr ?: (int) $constValue) . ", $flags);\n"; } if ($value->type->isFloat()) { - return "\tREGISTER_DOUBLE_CONSTANT(\"$constName\", " . ($cConstValue ?: (float) $constValue) . ", $flags);\n"; + return "\tREGISTER_DOUBLE_CONSTANT(\"$constName\", " . ($cExpr ?: (float) $constValue) . ", $flags);\n"; } if ($value->type->isString()) { - return "\tREGISTER_STRING_CONSTANT(\"$constName\", " . ($cConstValue ?: '"' . addslashes($constValue) . '"') . ", $flags);\n"; + return "\tREGISTER_STRING_CONSTANT(\"$constName\", " . ($cExpr ?: '"' . addslashes($constValue) . '"') . ", $flags);\n"; } throw new Exception("Unimplemented constant type");} @@ -2025,35 +2078,35 @@ private function getClassConstDeclaration(EvaluatedValue $value, iterable $allCo private function getValueAssertion(EvaluatedValue $value): string { - if ($value->isUnknownConstValue || $value->originatingConst || $value->cConstValue === null) { + if ($value->isUnknownConstValue || $value->originatingConsts || $this->cValue === null) { return ""; } - $cConstValue = $value->cConstValue; + $cExpr = $value->getCExpr(); $constValue = $value->value; if ($value->type->isNull()) { - return "\tZEND_ASSERT($cConstValue == NULL);\n"; + return "\tZEND_ASSERT($cExpr == NULL);\n"; } if ($value->type->isBool()) { $cValue = $constValue ? "true" : "false"; - return "\tZEND_ASSERT($cConstValue == $cValue);\n"; + return "\tZEND_ASSERT($cExpr == $cValue);\n"; } if ($value->type->isInt()) { $cValue = (int) $constValue; - return "\tZEND_ASSERT($cConstValue == $cValue);\n"; + return "\tZEND_ASSERT($cExpr == $cValue);\n"; } if ($value->type->isFloat()) { $cValue = (float) $constValue; - return "\tZEND_ASSERT($cConstValue == $cValue);\n"; + return "\tZEND_ASSERT($cExpr == $cValue);\n"; } if ($value->type->isString()) { $cValue = '"' . addslashes($constValue) . '"'; - return "\tZEND_ASSERT(strcmp($cConstValue, $cValue) == 0);\n"; + return "\tZEND_ASSERT(strcmp($cExpr, $cValue) == 0);\n"; } throw new Exception("Unimplemented constant type"); @@ -2170,7 +2223,7 @@ public function getDeclaration(iterable $allConstInfos): string { $defaultValue = EvaluatedValue::null(); } else { $defaultValue = EvaluatedValue::createFromExpression($this->defaultValue, null, null, $allConstInfos); - if ($defaultValue->isUnknownConstValue || ($defaultValue->originatingConst && $defaultValue->getCConstValue($allConstInfos) === null)) { + if ($defaultValue->isUnknownConstValue || ($defaultValue->originatingConsts && $defaultValue->getCExpr() === null)) { echo "Skipping code generation for property $this->name, because it has an unknown constant default value\n"; return ""; } @@ -2220,7 +2273,7 @@ public function getDeclaration(iterable $allConstInfos): string { if ($this->defaultValue === null && $this->type !== null) { $code .= "\tzval $zvalName;\n\tZVAL_UNDEF(&$zvalName);\n"; } else { - $code .= $defaultValue->initializeZval($zvalName, $allConstInfos); + $code .= $defaultValue->initializeZval($zvalName); } $code .= "\tzend_string *property_{$propertyName}_name = zend_string_init(\"$propertyName\", sizeof(\"$propertyName\") - 1, 1);\n"; @@ -2314,7 +2367,7 @@ public function getDeclaration(iterable $allConstInfos): string { $value = EvaluatedValue::createFromExpression($this->value, null, null, $allConstInfos); $zvalName = "enum_case_{$escapedName}_value"; - $code = "\n" . $value->initializeZval($zvalName, $allConstInfos); + $code = "\n" . $value->initializeZval($zvalName); $code .= "\tzend_enum_add_case_cstr(class_entry, \"$escapedName\", &$zvalName);\n"; } @@ -2334,11 +2387,14 @@ public function __construct(string $class, array $args) { } /** @param iterable $allConstInfos */ - public function generateCode(string $invocation, string $nameSuffix, iterable $allConstInfos): string { + public function generateCode(string $invocation, string $nameSuffix, iterable $allConstInfos, ?int $phpVersionIdMinimumCompatibility): string { + $php82MinimumCompatibility = $phpVersionIdMinimumCompatibility === null || $phpVersionIdMinimumCompatibility >= PHP_82_VERSION_ID; /* see ZEND_KNOWN_STRINGS in Zend/strings.h */ - static $knowns = [ - "SensitiveParameter" => "ZEND_STR_SENSITIVEPARAMETER", - ]; + $knowns = []; + if ($php82MinimumCompatibility) { + $knowns["SensitiveParameter"] = "ZEND_STR_SENSITIVEPARAMETER"; + } + $code = "\n"; $escapedAttributeName = strtr($this->class, '\\', '_'); if (isset($knowns[$escapedAttributeName])) { @@ -2351,7 +2407,7 @@ public function generateCode(string $invocation, string $nameSuffix, iterable $a foreach ($this->args as $i => $arg) { $value = EvaluatedValue::createFromExpression($arg->value, null, null, $allConstInfos); $zvalName = "attribute_{$escapedAttributeName}_{$nameSuffix}_arg$i"; - $code .= $value->initializeZval($zvalName, $allConstInfos); + $code .= $value->initializeZval($zvalName); $code .= "\tZVAL_COPY_VALUE(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, &$zvalName);\n"; if ($arg->name) { $code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n"; @@ -2454,8 +2510,8 @@ public function getRegistration(iterable $allConstInfos): string $code = ''; + $php80MinimumCompatibility = $this->phpVersionIdMinimumCompatibility === null || $this->phpVersionIdMinimumCompatibility >= PHP_80_VERSION_ID; $php81MinimumCompatibility = $this->phpVersionIdMinimumCompatibility === null || $this->phpVersionIdMinimumCompatibility >= PHP_81_VERSION_ID; - $php82MinimumCompatibility = $this->phpVersionIdMinimumCompatibility === null || $this->phpVersionIdMinimumCompatibility >= PHP_82_VERSION_ID; if ($this->type === "enum" && !$php81MinimumCompatibility) { $code .= "#if (PHP_VERSION_ID >= " . PHP_81_VERSION_ID . ")\n"; @@ -2522,27 +2578,27 @@ function (Name $item) { } if (!empty($this->attributes)) { - if (!$php82MinimumCompatibility) { - $code .= "\n#if (PHP_VERSION_ID >= " . PHP_82_VERSION_ID . ")"; + if (!$php80MinimumCompatibility) { + $code .= "\n#if (PHP_VERSION_ID >= " . PHP_80_VERSION_ID . ")"; } foreach ($this->attributes as $attribute) { - $code .= $attribute->generateCode("zend_add_class_attribute(class_entry", "class_$escapedName", $allConstInfos); + $code .= $attribute->generateCode("zend_add_class_attribute(class_entry", "class_$escapedName", $allConstInfos, $this->phpVersionIdMinimumCompatibility); } - if (!$php82MinimumCompatibility) { + if (!$php80MinimumCompatibility) { $code .= "#endif\n"; } } - if ($attributeInitializationCode = generateAttributeInitialization($this->funcInfos, $allConstInfos, $this->cond)) { - if (!$php82MinimumCompatibility) { - $code .= "#if (PHP_VERSION_ID >= " . PHP_82_VERSION_ID . ")\n"; + if ($attributeInitializationCode = generateAttributeInitialization($this->funcInfos, $allConstInfos, $this->phpVersionIdMinimumCompatibility, $this->cond)) { + if (!$php80MinimumCompatibility) { + $code .= "#if (PHP_VERSION_ID >= " . PHP_80_VERSION_ID . ")\n"; } $code .= "\n" . $attributeInitializationCode; - if (!$php82MinimumCompatibility) { + if (!$php80MinimumCompatibility) { $code .= "#endif\n"; } } @@ -2700,17 +2756,18 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, itera } $classSynopsisInfo->appendChild(new DOMText("\n ")); - /** @var Name[] $parentsWithInheritedConstants */ + /** @var array $parentsWithInheritedConstants */ $parentsWithInheritedConstants = []; - /** @var Name[] $parentsWithInheritedProperties */ + /** @var array $parentsWithInheritedProperties */ $parentsWithInheritedProperties = []; - /** @var Name[] $parentsWithInheritedMethods */ + /** @var array $parentsWithInheritedMethods */ $parentsWithInheritedMethods = []; $this->collectInheritedMembers( $parentsWithInheritedConstants, $parentsWithInheritedProperties, $parentsWithInheritedMethods, + $this->hasConstructor(), $classMap ); @@ -2800,14 +2857,21 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, itera $classSynopsis->appendChild($classSynopsisInfo); foreach ($parentsWithInheritedMethods as $parent) { - $classSynopsis->appendChild(new DOMText("\n ")); - $parentReference = self::getClassSynopsisReference($parent); - $escapedParentName = addslashes($parent->__toString()); - $includeElement = $this->createIncludeElement( - $doc, - "xmlns(db=http://docbook.org/ns/docbook) xpointer(id('$parentReference')/db:refentry/db:refsect1[@role='description']/descendant::db:methodsynopsis[@role='$escapedParentName')])" - ); - $classSynopsis->appendChild($includeElement); + $parentName = $parent["name"]; + $parentMethodsynopsisTypes = $parent["types"]; + + $parentReference = self::getClassSynopsisReference($parentName); + $escapedParentName = addslashes($parentName->__toString()); + + foreach ($parentMethodsynopsisTypes as $parentMethodsynopsisType) { + $classSynopsis->appendChild(new DOMText("\n ")); + $includeElement = $this->createIncludeElement( + $doc, + "xmlns(db=http://docbook.org/ns/docbook) xpointer(id('$parentReference')/db:refentry/db:refsect1[@role='description']/descendant::db:{$parentMethodsynopsisType}[@role='$escapedParentName'])" + ); + + $classSynopsis->appendChild($includeElement); + } } } @@ -2865,39 +2929,54 @@ public static function getClassSynopsisReference(Name $name): string { } /** - * @param Name[] $parentsWithInheritedConstants - * @param Name[] $parentsWithInheritedProperties - * @param Name[] $parentsWithInheritedMethods + * @param array $parentsWithInheritedConstants + * @param array $parentsWithInheritedProperties + * @param array $parentsWithInheritedMethods * @param array $classMap */ private function collectInheritedMembers( array &$parentsWithInheritedConstants, array &$parentsWithInheritedProperties, array &$parentsWithInheritedMethods, + bool $hasConstructor, array $classMap ): void { foreach ($this->extends as $parent) { $parentInfo = $classMap[$parent->toString()] ?? null; + $parentName = $parent->toString(); + if (!$parentInfo) { - throw new Exception("Missing parent class " . $parent->toString()); + throw new Exception("Missing parent class $parentName"); } - if (!empty($parentInfo->constInfos) && !isset($parentsWithInheritedConstants[$parent->toString()])) { - $parentsWithInheritedConstants[$parent->toString()] = $parent; + if (!empty($parentInfo->constInfos) && !isset($parentsWithInheritedConstants[$parentName])) { + $parentsWithInheritedConstants[] = $parent; + } + + if (!empty($parentInfo->propertyInfos) && !isset($parentsWithInheritedProperties[$parentName])) { + $parentsWithInheritedProperties[$parentName] = $parent; } - if (!empty($parentInfo->propertyInfos) && !isset($parentsWithInheritedProperties[$parent->toString()])) { - $parentsWithInheritedProperties[$parent->toString()] = $parent; + if (!$hasConstructor && $parentInfo->hasNonPrivateConstructor()) { + $parentsWithInheritedMethods[$parentName]["name"] = $parent; + $parentsWithInheritedMethods[$parentName]["types"][] = "constructorsynopsis"; } - if (!isset($parentsWithInheritedMethods[$parent->toString()]) && $parentInfo->hasMethods()) { - $parentsWithInheritedMethods[$parent->toString()] = $parent; + if ($parentInfo->hasMethods()) { + $parentsWithInheritedMethods[$parentName]["name"] = $parent; + $parentsWithInheritedMethods[$parentName]["types"][] = "methodsynopsis"; + } + + if ($parentInfo->hasDestructor()) { + $parentsWithInheritedMethods[$parentName]["name"] = $parent; + $parentsWithInheritedMethods[$parentName]["types"][] = "destructorsynopsis"; } $parentInfo->collectInheritedMembers( $parentsWithInheritedConstants, $parentsWithInheritedProperties, $parentsWithInheritedMethods, + $hasConstructor, $classMap ); } @@ -2919,6 +2998,7 @@ private function collectInheritedMembers( $parentsWithInheritedConstants, $unusedParentsWithInheritedProperties, $unusedParentsWithInheritedMethods, + $hasConstructor, $classMap ); } @@ -2935,6 +3015,17 @@ private function hasConstructor(): bool return false; } + private function hasNonPrivateConstructor(): bool + { + foreach ($this->funcInfos as $funcInfo) { + if ($funcInfo->name->isConstructor() && !($funcInfo->flags & Class_::MODIFIER_PRIVATE)) { + return true; + } + } + + return false; + } + private function hasDestructor(): bool { foreach ($this->funcInfos as $funcInfo) { @@ -3091,7 +3182,7 @@ public function getType(): string { $matches = []; if ($this->name === "param") { - preg_match('/^\s*([\w\|\\\\\[\]<>, ]+)\s*\$\w+.*$/', $value, $matches); + preg_match('/^\s*([\w\|\\\\\[\]<>, ]+)\s*(?:[{(]|\$\w+).*$/', $value, $matches); } elseif ($this->name === "return" || $this->name === "var") { preg_match('/^\s*([\w\|\\\\\[\]<>, ]+)/', $value, $matches); } @@ -3112,16 +3203,17 @@ public function getVariableName(): string { $matches = []; if ($this->name === "param") { - preg_match('/^\s*[\w\|\\\\\[\]]+\s*\$(\w+).*$/', $value, $matches); + // Allow for parsing extended types like callable(string):mixed in docblocks + preg_match('/^\s*(?[\w\|\\\\]+(?\((?(?:(?&parens)|[^(){}[\]]*+))++\)|\{(?&inparens)\}|\[(?&inparens)\])*+(?::(?&type))?)\s*\$(?\w+).*$/', $value, $matches); } elseif ($this->name === "prefer-ref") { - preg_match('/^\s*\$(\w+).*$/', $value, $matches); + preg_match('/^\s*\$(?\w+).*$/', $value, $matches); } - if (!isset($matches[1])) { + if (!isset($matches["name"])) { throw new Exception("@$this->name doesn't contain a variable name or has an invalid format \"$value\""); } - return $matches[1]; + return $matches["name"]; } } @@ -3595,7 +3687,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac foreach ($stmt->consts as $const) { $fileInfo->constInfos[] = parseConstLike( $prettyPrinter, - new ConstName($const->name->toString()), + new ConstName($const->namespacedName, $const->name->toString()), $const, 0, $stmt->getDocComment(), @@ -3838,10 +3930,10 @@ function funcInfoToCode(FileInfo $fileInfo, FuncInfo $funcInfo): string { $arginfoType = $argType->toArginfoType(); if ($arginfoType->hasClassType()) { $code .= sprintf( - "\tZEND_%s_OBJ_TYPE_MASK(%s, %s, %s, %s, %s)\n", + "\tZEND_%s_OBJ_TYPE_MASK(%s, %s, %s, %s%s)\n", $argKind, $argInfo->getSendByString(), $argInfo->name, $arginfoType->toClassTypeString(), $arginfoType->toTypeMask(), - $argInfo->getDefaultValueAsArginfoString() + !$argInfo->isVariadic ? ", " . $argInfo->getDefaultValueAsArginfoString() : "" ); } else { $code .= sprintf( @@ -3960,12 +4052,12 @@ static function (FuncInfo $funcInfo) use ($fileInfo, &$generatedFunctionDeclarat } } - $php82MinimumCompatibility = $fileInfo->generateLegacyArginfoForPhpVersionId === null || $fileInfo->generateLegacyArginfoForPhpVersionId >= PHP_82_VERSION_ID; + $php80MinimumCompatibility = $fileInfo->generateLegacyArginfoForPhpVersionId === null || $fileInfo->generateLegacyArginfoForPhpVersionId >= PHP_80_VERSION_ID; if ($fileInfo->generateClassEntries) { - if ($attributeInitializationCode = generateAttributeInitialization($fileInfo->funcInfos, $allConstInfos, null)) { - if (!$php82MinimumCompatibility) { - $attributeInitializationCode = "\n#if (PHP_VERSION_ID >= " . PHP_82_VERSION_ID . ")" . $attributeInitializationCode . "#endif\n"; + if ($attributeInitializationCode = generateAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->generateLegacyArginfoForPhpVersionId, null)) { + if (!$php80MinimumCompatibility) { + $attributeInitializationCode = "\n#if (PHP_VERSION_ID >= " . PHP_80_VERSION_ID . ")" . $attributeInitializationCode . "#endif\n"; } } @@ -4034,11 +4126,11 @@ function generateFunctionEntries(?Name $className, array $funcInfos, ?string $co /** * @param iterable $funcInfos */ -function generateAttributeInitialization(iterable $funcInfos, iterable $allConstInfos, ?string $parentCond = null): string { +function generateAttributeInitialization(iterable $funcInfos, iterable $allConstInfos, ?int $phpVersionIdMinimumCompatibility, ?string $parentCond = null): string { return generateCodeWithConditions( $funcInfos, "", - static function (FuncInfo $funcInfo) use ($allConstInfos) { + static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility) { $code = null; foreach ($funcInfo->args as $index => $arg) { @@ -4049,7 +4141,7 @@ static function (FuncInfo $funcInfo) use ($allConstInfos) { } foreach ($arg->attributes as $attribute) { - $code .= $attribute->generateCode("zend_add_parameter_attribute(zend_hash_str_find_ptr($functionTable, \"" . $funcInfo->name->getNameForAttributes() . "\", sizeof(\"" . $funcInfo->name->getNameForAttributes() . "\") - 1), $index", "{$funcInfo->name->getMethodSynopsisFilename()}_arg{$index}", $allConstInfos); + $code .= $attribute->generateCode("zend_add_parameter_attribute(zend_hash_str_find_ptr($functionTable, \"" . $funcInfo->name->getNameForAttributes() . "\", sizeof(\"" . $funcInfo->name->getNameForAttributes() . "\") - 1), $index", "{$funcInfo->name->getMethodSynopsisFilename()}_arg{$index}", $allConstInfos, $phpVersionIdMinimumCompatibility); } } @@ -4059,14 +4151,14 @@ static function (FuncInfo $funcInfo) use ($allConstInfos) { ); } -/** @param FuncInfo $funcInfos */ -function generateOptimizerInfo(array $funcInfos): string { +/** @param array $funcMap */ +function generateOptimizerInfo(array $funcMap): string { $code = "/* This is a generated file, edit the .stub.php files instead. */\n\n"; $code .= "static const func_info_t func_infos[] = {\n"; - $code .= generateCodeWithConditions($funcInfos, "", static function (FuncInfo $funcInfo) { + $code .= generateCodeWithConditions($funcMap, "", static function (FuncInfo $funcInfo) { return $funcInfo->getOptimizerInfo(); }); @@ -4262,16 +4354,18 @@ function replaceClassSynopses(string $targetDirectory, array $classMap, iterable $replacedXml = preg_replace( [ "/REPLACED-ENTITY-([A-Za-z0-9._{}%-]+?;)/", - "//i", - "//i", - "//i", - "//i", + '//i', + '//i', + '//i', + '//i', + '//i', ], [ "&$1", "", "", "", + "", "", ], $replacedXml @@ -4495,8 +4589,8 @@ function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $a $replacedXml = preg_replace( [ "/REPLACED-ENTITY-([A-Za-z0-9._{}%-]+?;)/", - "//i", - "//i", + '//i', + '//i', ], [ "&$1", @@ -4687,7 +4781,6 @@ function initPhpParser() { foreach ($fileInfos as $fileInfo) { foreach ($fileInfo->getAllFuncInfos() as $funcInfo) { - /** @var FuncInfo $funcInfo */ $funcMap[$funcInfo->name->__toString()] = $funcInfo; // TODO: Don't use aliasMap for methodsynopsis? diff --git a/build/php.m4 b/build/php.m4 index e4bef9d9f2d14..e11a00c3bcb16 100644 --- a/build/php.m4 +++ b/build/php.m4 @@ -1034,7 +1034,7 @@ AC_DEFUN([_PHP_CHECK_SIZEOF], [ #endif $3 -int main() +int main(void) { FILE *fp = fopen("conftestval", "w"); if (!fp) return(1); @@ -1102,7 +1102,7 @@ AC_CACHE_CHECK(for type of reentrant time-related functions, ac_cv_time_r_type,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include -int main() { +int main(void) { char buf[27]; struct tm t; time_t old = 0; @@ -1118,7 +1118,7 @@ return (1); ],[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include -int main() { +int main(void) { struct tm t, *s; time_t old = 0; char buf[27], *p; @@ -1159,7 +1159,7 @@ AC_DEFUN([PHP_DOES_PWRITE_WORK],[ #include #include $1 - int main() { + int main(void) { int fd = open("conftest_in", O_WRONLY|O_CREAT, 0600); if (fd < 0) return 1; @@ -1193,7 +1193,7 @@ AC_DEFUN([PHP_DOES_PREAD_WORK],[ #include #include $1 - int main() { + int main(void) { char buf[3]; int fd = open("conftest_in", O_RDONLY); if (fd < 0) return 1; @@ -1405,7 +1405,7 @@ struct s int i; char c[1]; }; -int main() +int main(void) { struct s *s = malloc(sizeof(struct s) + 3); s->i = 3; @@ -1463,7 +1463,7 @@ int seeker(void *cookie, off64_t *position, int whence) cookie_io_functions_t funcs = {reader, writer, seeker, closer}; -int main() { +int main(void) { struct cookiedata g = { 0 }; FILE *fp = fopencookie(&g, "r", funcs); @@ -1590,7 +1590,7 @@ AC_DEFUN([PHP_CHECK_FUNC_LIB],[ if test "$found" = "yes"; then ac_libs=$LIBS LIBS="$LIBS -l$2" - AC_RUN_IFELSE([AC_LANG_SOURCE([[int main() { return (0); }]])],[found=yes],[found=no],[ + AC_RUN_IFELSE([AC_LANG_SOURCE([[int main(void) { return (0); }]])],[found=yes],[found=no],[ dnl Cross compilation. found=yes ]) @@ -1644,7 +1644,7 @@ AC_DEFUN([PHP_TEST_BUILD], [ AC_LINK_IFELSE([AC_LANG_SOURCE([[ $5 char $1(); - int main() { + int main(void) { $1(); return 0; } @@ -1870,7 +1870,7 @@ AC_DEFUN([PHP_PROG_RE2C],[ if test "$php_re2c_check" != "invalid"; then AC_MSG_RESULT([$php_re2c_version (ok)]) else - AC_MSG_RESULT([$php_re2c_version]) + AC_MSG_RESULT([$php_re2c_version (too old)]) fi fi @@ -2296,7 +2296,7 @@ AC_DEFUN([PHP_TEST_WRITE_STDOUT],[ #define TEXT "This is the test message -- " -int main() +int main(void) { int n; @@ -2443,14 +2443,6 @@ AC_DEFUN([PHP_CHECK_STDINT_TYPES], [ AC_CHECK_SIZEOF([long long]) AC_CHECK_SIZEOF([size_t]) AC_CHECK_SIZEOF([off_t]) - AC_CHECK_TYPES([int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t], [], [ - AC_MSG_ERROR([One of the intN_t or uintN_t types is not available]) - ], [ -#include -#if HAVE_SYS_TYPES_H -# include -#endif - ]) ]) dnl @@ -2651,6 +2643,27 @@ AC_DEFUN([PHP_CHECK_BUILTIN_SADDLL_OVERFLOW], [ [$have_builtin_saddll_overflow], [Whether the compiler supports __builtin_saddll_overflow]) ]) +dnl +dnl PHP_CHECK_BUILTIN_USUB_OVERFLOW +dnl +AC_DEFUN([PHP_CHECK_BUILTIN_USUB_OVERFLOW], [ + AC_MSG_CHECKING([for __builtin_usub_overflow]) + + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[ + unsigned int tmpvar; + return __builtin_usub_overflow(3, 7, &tmpvar); + ]])], [ + have_builtin_usub_overflow=1 + AC_MSG_RESULT([yes]) + ], [ + have_builtin_usub_overflow=0 + AC_MSG_RESULT([no]) + ]) + + AC_DEFINE_UNQUOTED([PHP_HAVE_BUILTIN_USUB_OVERFLOW], + [$have_builtin_usub_overflow], [Whether the compiler supports __builtin_usub_overflow]) +]) + dnl dnl PHP_CHECK_BUILTIN_SSUBL_OVERFLOW dnl @@ -2733,6 +2746,26 @@ AC_DEFUN([PHP_CHECK_BUILTIN_CPU_SUPPORTS], [ [$have_builtin_cpu_supports], [Whether the compiler supports __builtin_cpu_supports]) ]) +dnl +dnl PHP_CHECK_BUILTIN_FRAME_ADDRESS +dnl +AC_DEFUN([PHP_CHECK_BUILTIN_FRAME_ADDRESS], [ + AC_MSG_CHECKING([for __builtin_frame_address]) + + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[ + return __builtin_frame_address(0) != (void*)0; + ]])], [ + have_builtin_frame_address=1 + AC_MSG_RESULT([yes]) + ], [ + have_builtin_frame_address=0 + AC_MSG_RESULT([no]) + ]) + + AC_DEFINE_UNQUOTED([PHP_HAVE_BUILTIN_FRAME_ADDRESS], + [$have_builtin_frame_address], [Whether the compiler supports __builtin_frame_address]) +]) + dnl dnl PHP_PATCH_CONFIG_HEADERS([FILE]) dnl @@ -2774,3 +2807,58 @@ AC_DEFUN([PHP_CHECK_PROCCTL], AC_MSG_RESULT([no]) ]) ]) + +dnl +dnl PHP_CHECK_AVX512_SUPPORTS +dnl +AC_DEFUN([PHP_CHECK_AVX512_SUPPORTS], [ + AC_MSG_CHECKING([for avx512 supports in compiler]) + save_CFLAGS="$CFLAGS" + CFLAGS="-mavx512f -mavx512cd -mavx512vl -mavx512dq -mavx512bw $CFLAGS" + + AC_LINK_IFELSE([AC_LANG_SOURCE([[ + #include + int main(void) { + __m512i mask = _mm512_set1_epi32(0x1); + char out[32]; + _mm512_storeu_si512(out, _mm512_shuffle_epi8(mask, mask)); + return 0; + }]])], [ + have_avx512_supports=1 + AC_MSG_RESULT([yes]) + ], [ + have_avx512_supports=0 + AC_MSG_RESULT([no]) + ]) + + CFLAGS="$save_CFLAGS" + + AC_DEFINE_UNQUOTED([PHP_HAVE_AVX512_SUPPORTS], + [$have_avx512_supports], [Whether the compiler supports AVX512]) +]) + +dnl +dnl PHP_CHECK_AVX512_VBMI_SUPPORTS +dnl +AC_DEFUN([PHP_CHECK_AVX512_VBMI_SUPPORTS], [ + AC_MSG_CHECKING([for avx512 vbmi supports in compiler]) + save_CFLAGS="$CFLAGS" + CFLAGS="-mavx512f -mavx512cd -mavx512vl -mavx512dq -mavx512bw -mavx512vbmi $CFLAGS" + AC_LINK_IFELSE([AC_LANG_SOURCE([[ + #include + int main(void) { + __m512i mask = _mm512_set1_epi32(0x1); + char out[32]; + _mm512_storeu_si512(out, _mm512_permutexvar_epi8(mask, mask)); + return 0; + }]])], [ + have_avx512_vbmi_supports=1 + AC_MSG_RESULT([yes]) + ], [ + have_avx512_vbmi_supports=0 + AC_MSG_RESULT([no]) + ]) + CFLAGS="$save_CFLAGS" + AC_DEFINE_UNQUOTED([PHP_HAVE_AVX512_VBMI_SUPPORTS], + [$have_avx512_vbmi_supports], [Whether the compiler supports AVX512 VBMI]) +]) diff --git a/configure.ac b/configure.ac index a64ca2d042f72..fcb629723817b 100644 --- a/configure.ac +++ b/configure.ac @@ -128,7 +128,9 @@ PKG_PROG_PKG_CONFIG AC_PROG_CC([cc gcc]) PHP_DETECT_ICC PHP_DETECT_SUNCC -AC_PROG_CC_C99 + +dnl AC_PROG_CC_C99 is obsolete with autoconf >= 2.70 yet necessary for <= 2.69. +m4_version_prereq([2.70],,[AC_PROG_CC_C99]) AC_PROG_CPP AC_USE_SYSTEM_EXTENSIONS AC_PROG_LN_S @@ -162,7 +164,7 @@ PHP_RUNPATH_SWITCH dnl Checks for some support/generator progs. PHP_PROG_AWK PHP_PROG_BISON([3.0.0]) -PHP_PROG_RE2C([0.13.4]) +PHP_PROG_RE2C([1.0.3]) PHP_PROG_PHP() PHP_ARG_ENABLE([re2c-cgoto], @@ -502,6 +504,8 @@ dnl Check __builtin_saddl_overflow PHP_CHECK_BUILTIN_SADDL_OVERFLOW dnl Check __builtin_saddll_overflow PHP_CHECK_BUILTIN_SADDLL_OVERFLOW +dnl Check __builtin_usub_overflow +PHP_CHECK_BUILTIN_USUB_OVERFLOW dnl Check __builtin_ssubl_overflow PHP_CHECK_BUILTIN_SSUBL_OVERFLOW dnl Check __builtin_ssubll_overflow @@ -510,10 +514,16 @@ dnl Check __builtin_cpu_init PHP_CHECK_BUILTIN_CPU_INIT dnl Check __builtin_cpu_supports PHP_CHECK_BUILTIN_CPU_SUPPORTS +dnl Check __builtin_frame_address +PHP_CHECK_BUILTIN_FRAME_ADDRESS dnl Check prctl PHP_CHECK_PRCTL dnl Check procctl PHP_CHECK_PROCCTL +dnl Check AVX512 +PHP_CHECK_AVX512_SUPPORTS +dnl Check AVX512 VBMI +PHP_CHECK_AVX512_VBMI_SUPPORTS dnl Check for __alignof__ support in the compiler AC_CACHE_CHECK(whether the compiler supports __alignof__, ac_cv_alignof_exists,[ @@ -626,6 +636,7 @@ asprintf \ nanosleep \ memmem \ memrchr \ +strerror_r \ ) AX_FUNC_WHICH_GETHOSTBYNAME_R @@ -770,7 +781,7 @@ PHP_ARG_WITH([valgrind], [whether to enable valgrind support], [AS_HELP_STRING([--with-valgrind], [Enable valgrind support])], - [yes], + [no], [no]) if test "$PHP_VALGRIND" != "no"; then @@ -1701,7 +1712,7 @@ PHP_ADD_SOURCES_X(/main, internal_functions_cli.c, -DZEND_ENABLE_STATIC_TSRMLS_C PHP_ADD_SOURCES(Zend, \ zend_language_parser.c zend_language_scanner.c \ zend_ini_parser.c zend_ini_scanner.c \ - zend_alloc.c zend_compile.c zend_constants.c zend_dtrace.c \ + zend_alloc.c zend_call_stack.c zend_compile.c zend_constants.c zend_dtrace.c \ zend_execute_API.c zend_highlight.c zend_llist.c \ zend_vm_opcodes.c zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ @@ -1712,6 +1723,7 @@ PHP_ADD_SOURCES(Zend, \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \ zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_atomic.c \ + zend_max_execution_timer.c \ Optimizer/zend_optimizer.c \ Optimizer/pass1.c \ Optimizer/pass3.c \ diff --git a/docs/parameter-parsing-api.md b/docs/parameter-parsing-api.md index 76c571068d796..a5a405e6a241a 100644 --- a/docs/parameter-parsing-api.md +++ b/docs/parameter-parsing-api.md @@ -67,7 +67,7 @@ on input and is used to verify the PHP parameter is an instance of that class. ```txt a - array (zval*) A - array or object (zval*) -b - boolean (zend_bool) +b - boolean (bool) C - class (zend_class_entry*) d - double (double) f - function or array containing php method call info (returned as @@ -97,9 +97,9 @@ The following characters also have a meaning in the specifier string: * `!` - the parameter it follows can be of specified type or NULL. If NULL is passed, and the output for such type is a pointer, then the output pointer is set to a native NULL pointer. For 'b', 'l' and 'd', an extra argument of type - zend_bool* must be passed after the corresponding bool*, zend_long* or + bool* must be passed after the corresponding bool*, zend_long* or double* arguments, respectively. A non-zero value will be written to the - zend_bool if a PHP NULL is passed. + bool if a PHP NULL is passed. For `f` use the ``ZEND_FCI_INITIALIZED(fci)`` macro to check if a callable has been provided and ``!ZEND_FCI_INITIALIZED(fci)`` to check if a PHP NULL is passed. diff --git a/docs/release-process.md b/docs/release-process.md index 4e7a5c228808b..a082aabc65bef 100644 --- a/docs/release-process.md +++ b/docs/release-process.md @@ -961,7 +961,7 @@ volunteers to begin the selection process for the next release managers. public key to a keyserver: ```shell - gpg --keyserver pgp.mit.edu --send-keys YOURKEYID + gpg --keyserver keys.openpgp.org --send-keys YOURKEYID gpg --keyserver keyserver.ubuntu.com --send-keys YOURKEYID ``` diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index d6147269b0ebb..af36e399b016d 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -633,7 +633,7 @@ PHP_FUNCTION(bcscale) RETURN_THROWS(); } - zend_string *ini_name = zend_string_init("bcmath.scale", sizeof("bcmath.scale") - 1, 0); + zend_string *ini_name = ZSTR_INIT_LITERAL("bcmath.scale", 0); zend_string *new_scale_str = zend_long_to_str(new_scale); zend_alter_ini_entry(ini_name, new_scale_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release(new_scale_str); diff --git a/ext/bcmath/libbcmath/src/add.c b/ext/bcmath/libbcmath/src/add.c index e92fb0502f014..fc76d5652e39e 100644 --- a/ext/bcmath/libbcmath/src/add.c +++ b/ext/bcmath/libbcmath/src/add.c @@ -42,10 +42,7 @@ N1 is added to N2 and the result placed into RESULT. SCALE_MIN is the minimum scale for the result. */ -void -bc_add (n1, n2, result, scale_min) - bc_num n1, n2, *result; - int scale_min; +void bc_add (bc_num n1, bc_num n2, bc_num *result, int scale_min) { bc_num sum = NULL; int cmp_res; diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index e6273c18a1101..4e32a3cbacacb 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -55,7 +55,8 @@ typedef struct bc_struct #include "config.h" #endif -#include "php.h" +#include +#include "php.h" /* Needed for safe_pemalloc() in init.c */ #include "../../php_bcmath.h" /* The base used in storing the numbers in n_value above. @@ -112,9 +113,9 @@ char bc_is_zero(bc_num num); char bc_is_zero_for_scale(bc_num num, int scale); -char bc_is_near_zero(bc_num num, int scale); +bool bc_is_near_zero(bc_num num, int scale); -char bc_is_neg(bc_num num); +bool bc_is_neg(bc_num num); void bc_add(bc_num n1, bc_num n2, bc_num *result, int scale_min); @@ -132,7 +133,7 @@ int bc_raisemod(bc_num base, bc_num expo, bc_num mo, bc_num *result, int scale); void bc_raise(bc_num num1, bc_num num2, bc_num *resul, int scale); -int bc_sqrt(bc_num *num, int scale); +bool bc_sqrt(bc_num *num, int scale); void bc_out_num(bc_num num, int o_base, void (* out_char)(char), int leading_zero); diff --git a/ext/bcmath/libbcmath/src/compare.c b/ext/bcmath/libbcmath/src/compare.c index f7c4a403993e7..b23590b5ed643 100644 --- a/ext/bcmath/libbcmath/src/compare.c +++ b/ext/bcmath/libbcmath/src/compare.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "bcmath.h" #include "private.h" @@ -42,11 +43,7 @@ than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just compare the magnitudes. */ - int -_bc_do_compare (n1, n2, use_sign, ignore_last) - bc_num n1, n2; - int use_sign; - int ignore_last; +int _bc_do_compare(bc_num n1, bc_num n2, bool use_sign, bool ignore_last) { char *n1ptr, *n2ptr; int count; @@ -151,9 +148,7 @@ _bc_do_compare (n1, n2, use_sign, ignore_last) /* This is the "user callable" routine to compare numbers N1 and N2. */ -int -bc_compare (n1, n2) - bc_num n1, n2; +int bc_compare(bc_num n1, bc_num n2) { - return _bc_do_compare (n1, n2, TRUE, FALSE); + return _bc_do_compare (n1, n2, true, false); } diff --git a/ext/bcmath/libbcmath/src/div.c b/ext/bcmath/libbcmath/src/div.c index 0f0281daa2fb3..7e26c15aeb6d6 100644 --- a/ext/bcmath/libbcmath/src/div.c +++ b/ext/bcmath/libbcmath/src/div.c @@ -79,8 +79,7 @@ static void _one_mult (unsigned char *num, int size, int digit, unsigned char *r digits after the decimal point is SCALE. It returns -1 if division by zero is tried. The algorithm is found in Knuth Vol 2. p237. */ -int -bc_divide (bc_num n1, bc_num n2, bc_num *quot, int scale) +int bc_divide (bc_num n1, bc_num n2, bc_num *quot, int scale) { bc_num qval; unsigned char *num1, *num2; diff --git a/ext/bcmath/libbcmath/src/divmod.c b/ext/bcmath/libbcmath/src/divmod.c index 8b188d2b630b1..d6f0566777a63 100644 --- a/ext/bcmath/libbcmath/src/divmod.c +++ b/ext/bcmath/libbcmath/src/divmod.c @@ -43,8 +43,7 @@ is NULL then that store will be omitted. */ -int -bc_divmod (bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale) +int bc_divmod (bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale) { bc_num quotient = NULL; bc_num temp; @@ -78,8 +77,7 @@ bc_divmod (bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale) /* Modulo for numbers. This computes NUM1 % NUM2 and puts the result in RESULT. */ -int -bc_modulo (bc_num num1, bc_num num2, bc_num *result, int scale) +int bc_modulo (bc_num num1, bc_num num2, bc_num *result, int scale) { return bc_divmod (num1, num2, NULL, result, scale); } diff --git a/ext/bcmath/libbcmath/src/doaddsub.c b/ext/bcmath/libbcmath/src/doaddsub.c index fcd768f2929f8..d3db98167d4d2 100644 --- a/ext/bcmath/libbcmath/src/doaddsub.c +++ b/ext/bcmath/libbcmath/src/doaddsub.c @@ -42,10 +42,7 @@ returned. The signs of N1 and N2 are ignored. SCALE_MIN is to set the minimum scale of the result. */ - bc_num -_bc_do_add (n1, n2, scale_min) - bc_num n1, n2; - int scale_min; +bc_num _bc_do_add(bc_num n1, bc_num n2, int scale_min) { bc_num sum; int sum_scale, sum_digits; @@ -134,10 +131,7 @@ _bc_do_add (n1, n2, scale_min) assumed to be larger than N2. SCALE_MIN is the minimum scale of the result. */ - bc_num -_bc_do_sub (n1, n2, scale_min) - bc_num n1, n2; - int scale_min; +bc_num _bc_do_sub(bc_num n1, bc_num n2, int scale_min) { bc_num diff; int diff_scale, diff_len; diff --git a/ext/bcmath/libbcmath/src/init.c b/ext/bcmath/libbcmath/src/init.c index 96e934b34da76..50d6b0653c3bf 100644 --- a/ext/bcmath/libbcmath/src/init.c +++ b/ext/bcmath/libbcmath/src/init.c @@ -39,9 +39,7 @@ /* new_num allocates a number and sets fields to known values. */ -bc_num -_bc_new_num_ex (length, scale, persistent) - int length, scale, persistent; +bc_num _bc_new_num_ex (int length, int scale, int persistent) { bc_num temp; /* PHP Change: malloc() -> pemalloc(), removed free_list code */ @@ -61,10 +59,7 @@ _bc_new_num_ex (length, scale, persistent) /* "Frees" a bc_num NUM. Actually decreases reference count and only frees the storage if reference count is zero. */ -void -_bc_free_num_ex (num, persistent) - bc_num *num; - int persistent; +void _bc_free_num_ex(bc_num *num, int persistent) { if (*num == NULL) return; (*num)->n_refs--; @@ -80,8 +75,7 @@ _bc_free_num_ex (num, persistent) /* Initialize the number package! */ -void -bc_init_numbers (void) +void bc_init_numbers(void) { BCG(_zero_) = _bc_new_num_ex (1,0,1); BCG(_one_) = _bc_new_num_ex (1,0,1); @@ -93,8 +87,7 @@ bc_init_numbers (void) /* Make a copy of a number! Just increments the reference count! */ -bc_num -bc_copy_num (bc_num num) +bc_num bc_copy_num(bc_num num) { num->n_refs++; return num; @@ -103,8 +96,7 @@ bc_copy_num (bc_num num) /* Initialize a number NUM by making it a copy of zero. */ -void -bc_init_num (bc_num *num) +void bc_init_num(bc_num *num) { *num = bc_copy_num (BCG(_zero_)); } diff --git a/ext/bcmath/libbcmath/src/int2num.c b/ext/bcmath/libbcmath/src/int2num.c index 3e675b627a8c4..7564fa76ac531 100644 --- a/ext/bcmath/libbcmath/src/int2num.c +++ b/ext/bcmath/libbcmath/src/int2num.c @@ -30,20 +30,12 @@ *************************************************************************/ #include -#include -#include -#include -#include #include "bcmath.h" -#include "private.h" /* Convert an integer VAL to a bc number NUM. */ -void -bc_int2num (num, val) - bc_num *num; - int val; +void bc_int2num(bc_num *num, int val) { char buffer[30]; char *bptr, *vptr; diff --git a/ext/bcmath/libbcmath/src/nearzero.c b/ext/bcmath/libbcmath/src/nearzero.c index 0986b02b7a9ce..c3a826041456a 100644 --- a/ext/bcmath/libbcmath/src/nearzero.c +++ b/ext/bcmath/libbcmath/src/nearzero.c @@ -29,22 +29,14 @@ *************************************************************************/ -#include -#include -#include -#include -#include +#include #include "bcmath.h" -#include "private.h" /* In some places we need to check if the number NUM is almost zero. Specifically, all but the last digit is 0 and the last digit is 1. Last digit is defined by scale. */ -char -bc_is_near_zero (num, scale) - bc_num num; - int scale; +bool bc_is_near_zero(bc_num num, int scale) { int count; char *nptr; @@ -61,7 +53,7 @@ bc_is_near_zero (num, scale) while ((count > 0) && (*nptr++ == 0)) count--; if (count != 0 && (count != 1 || *--nptr != 1)) - return FALSE; + return false; else - return TRUE; + return true; } diff --git a/ext/bcmath/libbcmath/src/neg.c b/ext/bcmath/libbcmath/src/neg.c index fe6f95aa34c85..d8f2cfaed7b67 100644 --- a/ext/bcmath/libbcmath/src/neg.c +++ b/ext/bcmath/libbcmath/src/neg.c @@ -29,19 +29,11 @@ *************************************************************************/ -#include -#include -#include -#include -#include +#include #include "bcmath.h" -#include "private.h" /* In some places we need to check if the number is negative. */ - -char -bc_is_neg (num) - bc_num num; +bool bc_is_neg(bc_num num) { return num->n_sign == MINUS; } diff --git a/ext/bcmath/libbcmath/src/num2long.c b/ext/bcmath/libbcmath/src/num2long.c index e40a126c72cb6..322fb3d9c0720 100644 --- a/ext/bcmath/libbcmath/src/num2long.c +++ b/ext/bcmath/libbcmath/src/num2long.c @@ -30,21 +30,14 @@ *************************************************************************/ #include -#include -#include -#include -#include #include "bcmath.h" -#include "private.h" /* Convert a number NUM to a long. The function returns only the integer part of the number. For numbers that are too large to represent as a long, this function returns a zero. This can be detected by checking the NUM for zero after having a zero returned. */ -long -bc_num2long (num) - bc_num num; +long bc_num2long(bc_num num) { long val; char *nptr; diff --git a/ext/bcmath/libbcmath/src/num2str.c b/ext/bcmath/libbcmath/src/num2str.c index 39f7adb1f0c39..44b05593c944f 100644 --- a/ext/bcmath/libbcmath/src/num2str.c +++ b/ext/bcmath/libbcmath/src/num2str.c @@ -39,10 +39,7 @@ /* Convert a numbers to a string. Base 10 only.*/ -zend_string -*bc_num2str_ex (num, scale) - bc_num num; - int scale; +zend_string *bc_num2str_ex(bc_num num, int scale) { zend_string *str; char *sptr; diff --git a/ext/bcmath/libbcmath/src/output.c b/ext/bcmath/libbcmath/src/output.c index 79a386eda79ad..fb7976cc67f11 100644 --- a/ext/bcmath/libbcmath/src/output.c +++ b/ext/bcmath/libbcmath/src/output.c @@ -48,7 +48,7 @@ typedef struct stk_rec { } stk_rec; /* The reference string for digits. */ -static char ref_str[] = "0123456789ABCDEF"; +static const char ref_str[] = "0123456789ABCDEF"; /* A special output routine for "multi-character digits." Exactly diff --git a/ext/bcmath/libbcmath/src/private.h b/ext/bcmath/libbcmath/src/private.h index 0e8ba33d79c59..aa2459563822c 100644 --- a/ext/bcmath/libbcmath/src/private.h +++ b/ext/bcmath/libbcmath/src/private.h @@ -31,8 +31,10 @@ /* "Private" routines to bcmath. */ +#include + /* routines */ -int _bc_do_compare (bc_num n1, bc_num n2, int use_sign, int ignore_last); +int _bc_do_compare (bc_num n1, bc_num n2, bool use_sign, bool ignore_last); bc_num _bc_do_add (bc_num n1, bc_num n2, int scale_min); bc_num _bc_do_sub (bc_num n1, bc_num n2, int scale_min); void _bc_rm_leading_zeros (bc_num num); diff --git a/ext/bcmath/libbcmath/src/recmul.c b/ext/bcmath/libbcmath/src/recmul.c index 39daaf3fb88f8..5217bf4b7c083 100644 --- a/ext/bcmath/libbcmath/src/recmul.c +++ b/ext/bcmath/libbcmath/src/recmul.c @@ -30,11 +30,7 @@ *************************************************************************/ #include -#include #include -#include -#include -#include #include "bcmath.h" #include "private.h" diff --git a/ext/bcmath/libbcmath/src/rmzero.c b/ext/bcmath/libbcmath/src/rmzero.c index 5e295c90af4d2..6aad96a978ea3 100644 --- a/ext/bcmath/libbcmath/src/rmzero.c +++ b/ext/bcmath/libbcmath/src/rmzero.c @@ -30,10 +30,6 @@ *************************************************************************/ #include -#include -#include -#include -#include #include "bcmath.h" #include "private.h" @@ -41,9 +37,7 @@ _bc_rm_leading_zeros just moves the data "value" pointer to the correct place and adjusts the length. */ - void -_bc_rm_leading_zeros (num) - bc_num num; +void _bc_rm_leading_zeros(bc_num num) { /* We can move n_value to point to the first non zero digit! */ while (*num->n_value == 0 && num->n_len > 1) { diff --git a/ext/bcmath/libbcmath/src/sqrt.c b/ext/bcmath/libbcmath/src/sqrt.c index 96cff294754a7..59ef960466c3d 100644 --- a/ext/bcmath/libbcmath/src/sqrt.c +++ b/ext/bcmath/libbcmath/src/sqrt.c @@ -30,42 +30,36 @@ *************************************************************************/ #include -#include -#include -#include -#include +#include #include "bcmath.h" #include "private.h" /* Take the square root NUM and return it in NUM with SCALE digits after the decimal place. */ -int -bc_sqrt (bc_num *num, int scale) +bool bc_sqrt(bc_num *num, int scale) { - int rscale, cmp_res, done; + int rscale, cmp_res; int cscale; bc_num guess, guess1, point5, diff; /* Initial checks. */ cmp_res = bc_compare (*num, BCG(_zero_)); - if (cmp_res < 0) - return 0; /* error */ - else - { - if (cmp_res == 0) - { + if (cmp_res < 0) { + return false; /* error */ + } else { + if (cmp_res == 0) { bc_free_num (num); *num = bc_copy_num (BCG(_zero_)); - return 1; + return true; } - } + } cmp_res = bc_compare (*num, BCG(_one_)); if (cmp_res == 0) { bc_free_num (num); *num = bc_copy_num (BCG(_one_)); - return 1; + return true; } /* Initialize the variables. */ @@ -77,14 +71,11 @@ bc_sqrt (bc_num *num, int scale) /* Calculate the initial guess. */ - if (cmp_res < 0) - { + if (cmp_res < 0) { /* The number is between 0 and 1. Guess should start at 1. */ guess = bc_copy_num (BCG(_one_)); cscale = (*num)->n_scale; - } - else - { + } else { /* The number is greater than 1. Guess should start at 10^(exp/2). */ bc_init_num(&guess); bc_int2num (&guess,10); @@ -95,26 +86,25 @@ bc_sqrt (bc_num *num, int scale) bc_raise (guess, guess1, &guess, 0); bc_free_num (&guess1); cscale = 3; - } + } /* Find the square root using Newton's algorithm. */ - done = FALSE; - while (!done) - { + bool done = false; + while (!done) { bc_free_num (&guess1); guess1 = bc_copy_num (guess); bc_divide (*num, guess, &guess, cscale); bc_add (guess, guess1, &guess, 0); bc_multiply (guess, point5, &guess, cscale); bc_sub (guess, guess1, &diff, cscale+1); - if (bc_is_near_zero (diff, cscale)) - { - if (cscale < rscale+1) - cscale = MIN (cscale*3, rscale+1); - else - done = TRUE; - } - } + if (bc_is_near_zero (diff, cscale)) { + if (cscale < rscale+1) { + cscale = MIN (cscale*3, rscale+1); + } else { + done = true; + } + } + } /* Assign the number and clean up. */ bc_free_num (num); @@ -123,5 +113,5 @@ bc_sqrt (bc_num *num, int scale) bc_free_num (&guess1); bc_free_num (&point5); bc_free_num (&diff); - return 1; + return true; } diff --git a/ext/bcmath/libbcmath/src/sub.c b/ext/bcmath/libbcmath/src/sub.c index 2949c71fbb664..3d277e51ee7e7 100644 --- a/ext/bcmath/libbcmath/src/sub.c +++ b/ext/bcmath/libbcmath/src/sub.c @@ -30,22 +30,14 @@ *************************************************************************/ #include -#include -#include -#include -#include #include "bcmath.h" #include "private.h" - /* Here is the full subtract routine that takes care of negative numbers. N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN is the minimum scale for the result. */ -void -bc_sub (n1, n2, result, scale_min) - bc_num n1, n2, *result; - int scale_min; +void bc_sub(bc_num n1, bc_num n2, bc_num *result, int scale_min) { bc_num diff = NULL; int cmp_res; diff --git a/ext/bz2/bz2.c b/ext/bz2/bz2.c index 8e55bf92bed76..7f546f95cd0eb 100644 --- a/ext/bz2/bz2.c +++ b/ext/bz2/bz2.c @@ -404,7 +404,7 @@ PHP_FUNCTION(bzopen) stream = php_stream_bz2open_from_BZFILE(bz, mode, stream); } else { - zend_argument_type_error(1, "must be of type string or file-resource, %s given", zend_zval_type_name(file)); + zend_argument_type_error(1, "must be of type string or file-resource, %s given", zend_zval_value_name(file)); RETURN_THROWS(); } diff --git a/ext/bz2/tests/002.phpt b/ext/bz2/tests/002.phpt index 00254776f7951..f87048f92314e 100644 --- a/ext/bz2/tests/002.phpt +++ b/ext/bz2/tests/002.phpt @@ -91,10 +91,10 @@ resource(%d) of type (stream) resource(%d) of type (stream) Warning: fopen(bz_open_002.txt): Failed to open stream: `br' is not a valid mode for fopen in %s on line %d -bzopen(): Argument #1 ($file) must be of type string or file-resource, bool given +bzopen(): Argument #1 ($file) must be of type string or file-resource, false given Warning: fopen(bz_open_002.txt): Failed to open stream: `br' is not a valid mode for fopen in %s on line %d -bzopen(): Argument #1 ($file) must be of type string or file-resource, bool given +bzopen(): Argument #1 ($file) must be of type string or file-resource, false given Warning: bzopen(): cannot write to a stream opened in read only mode in %s on line %d bool(false) diff --git a/ext/calendar/calendar.c b/ext/calendar/calendar.c index aab1501fd38e4..756ce0e90dc98 100644 --- a/ext/calendar/calendar.c +++ b/ext/calendar/calendar.c @@ -354,7 +354,7 @@ PHP_FUNCTION(juliantojd) /* {{{ heb_number_to_chars*/ /* -caution: the Hebrew format produces non unique result. +caution: the Hebrew format produces non-unique result. for example both: year '5' and year '5000' produce 'ה'. use the numeric one for calculations. */ diff --git a/ext/com_dotnet/com_typeinfo.c b/ext/com_dotnet/com_typeinfo.c index ccdcc3ff7e8c8..bebbe2e2ad024 100644 --- a/ext/com_dotnet/com_typeinfo.c +++ b/ext/com_dotnet/com_typeinfo.c @@ -197,7 +197,7 @@ PHP_COM_DOTNET_API zend_result php_com_import_typelib(ITypeLib *TL, int mode, in if (pTKind == TKIND_ENUM) { ITypeLib_GetTypeInfo(TL, i, &TypeInfo); for (j = 0; ; j++) { - zend_string *const_name; + zend_string *const_name, *name; if (FAILED(ITypeInfo_GetVarDesc(TypeInfo, j, &pVarDesc))) { break; @@ -228,12 +228,13 @@ PHP_COM_DOTNET_API zend_result php_com_import_typelib(ITypeLib *TL, int mode, in ZVAL_LONG(&c.value, Z_LVAL(value)); if (mode & CONST_PERSISTENT) { /* duplicate string in a persistent manner */ - c.name = zend_string_dup(const_name, /* persistent */ true); + name = zend_string_dup(const_name, /* persistent */ true); zend_string_release_ex(const_name, /* persistent */ false); } else { - c.name = const_name; + name = const_name; } - zend_register_constant(&c); + zend_register_constant(name, &c); + zend_string_release(name); } ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc); } diff --git a/ext/com_dotnet/com_variant.c b/ext/com_dotnet/com_variant.c index b40ac6a5c31f9..14580ef6a8a7c 100644 --- a/ext/com_dotnet/com_variant.c +++ b/ext/com_dotnet/com_variant.c @@ -95,7 +95,7 @@ static void safe_array_from_zval(VARIANT *v, zval *z, int codepage) static void php_com_variant_from_zval_ex(VARIANT *v, zval *z, int codepage, VARTYPE vt) { php_com_dotnet_object *obj; - zend_uchar ztype = IS_NULL; + uint8_t ztype = IS_NULL; if (z) { ZVAL_DEREF(z); diff --git a/ext/com_dotnet/tests/bug77578.phpt b/ext/com_dotnet/tests/bug77578.phpt index 653a16123218d..a820935d5d775 100644 --- a/ext/com_dotnet/tests/bug77578.phpt +++ b/ext/com_dotnet/tests/bug77578.phpt @@ -6,8 +6,8 @@ com_dotnet 0x073800 && defined(PHP_WIN32) - if (len > sizeof("file://") - 1 && '/' != url[sizeof("file://") - 1] && !strncmp("file://", url, sizeof("file://") - 1) && len < MAXPATHLEN - 2) { + if ( + zend_string_starts_with_literal_ci(url, "file://") + && '/' != ZSTR_VAL(url)[sizeof("file://") - 1] + && ZSTR_LEN(url) < MAXPATHLEN - 2 + ) { char _tmp[MAXPATHLEN] = {0}; memmove(_tmp, "file:///", sizeof("file:///") - 1); - memmove(_tmp + sizeof("file:///") - 1, url + sizeof("file://") - 1, len - sizeof("file://") + 1); + memmove(_tmp + sizeof("file:///") - 1, ZSTR_VAL(url) + sizeof("file://") - 1, ZSTR_LEN(url) - sizeof("file://") + 1); - return php_curl_option_str(ch, CURLOPT_URL, _tmp, len + 1); + return php_curl_option_str(ch, CURLOPT_URL, _tmp, ZSTR_LEN(url) + 1); } #endif - return php_curl_option_str(ch, CURLOPT_URL, url, len); + return php_curl_option_str(ch, CURLOPT_URL, ZSTR_VAL(url), ZSTR_LEN(url)); } /* }}} */ @@ -805,6 +816,8 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) if (Z_TYPE(retval) == IS_STRING) { length = MIN((int) (size * nmemb), Z_STRLEN(retval)); memcpy(data, Z_STRVAL(retval), length); + } else if (Z_TYPE(retval) == IS_LONG) { + length = Z_LVAL_P(&retval); } zval_ptr_dtor(&retval); } @@ -1134,7 +1147,7 @@ PHP_FUNCTION(curl_init) _php_curl_set_default_options(ch); if (url) { - if (php_curl_option_url(ch, ZSTR_VAL(url), ZSTR_LEN(url)) == FAILURE) { + if (php_curl_option_url(ch, url) == FAILURE) { zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -1372,7 +1385,7 @@ static inline zend_result build_mime_structure_from_hash(php_curl *ch, zval *zpo postval = Z_STR_P(prop); if (php_check_open_basedir(ZSTR_VAL(postval))) { - return 1; + return FAILURE; } prop = zend_read_property(curl_CURLFile_class, Z_OBJ_P(current), "mime", sizeof("mime")-1, 0, &rv); @@ -1943,7 +1956,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue { zend_string *tmp_str; zend_string *str = zval_get_tmp_string(zvalue, &tmp_str); - zend_result ret = php_curl_option_url(ch, ZSTR_VAL(str), ZSTR_LEN(str)); + zend_result ret = php_curl_option_url(ch, str); zend_tmp_string_release(tmp_str); return ret; } @@ -2067,7 +2080,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue struct curl_slist *slist = NULL; if (Z_TYPE_P(zvalue) != IS_ARRAY) { - char *name = NULL; + const char *name = NULL; switch (option) { case CURLOPT_HTTPHEADER: name = "CURLOPT_HTTPHEADER"; diff --git a/ext/curl/multi.c b/ext/curl/multi.c index 628fc197849f2..fcf21ebad76b7 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -523,7 +523,7 @@ static zend_function *curl_multi_get_constructor(zend_object *object) { return NULL; } -void curl_multi_free_obj(zend_object *object) +static void curl_multi_free_obj(zend_object *object) { php_curlm *mh = curl_multi_from_obj(object); diff --git a/ext/curl/tests/CONFLICTS b/ext/curl/tests/CONFLICTS new file mode 100644 index 0000000000000..0702cb5bfbb01 --- /dev/null +++ b/ext/curl/tests/CONFLICTS @@ -0,0 +1 @@ +all diff --git a/ext/curl/tests/bug45161.phpt b/ext/curl/tests/bug45161.phpt index 9ba8f5f90249c..7e67b6d741ed5 100644 --- a/ext/curl/tests/bug45161.phpt +++ b/ext/curl/tests/bug45161.phpt @@ -2,6 +2,10 @@ Bug #45161 (Reusing a curl handle leaks memory) --EXTENSIONS-- curl +--SKIPIF-- + --FILE-- res++]; + } +} + +$inputHandle = fopen(__FILE__, 'r'); + +$ch = curl_init(); +curl_setopt($ch, CURLOPT_URL, "{$host}/get.inc?test=input"); +curl_setopt($ch, CURLOPT_UPLOAD, 1); +curl_setopt($ch, CURLOPT_READFUNCTION, new Input); +curl_setopt($ch, CURLOPT_INFILE, $inputHandle); +curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + +$mh = curl_multi_init(); +curl_multi_add_handle($mh, $ch); +do { + $status = curl_multi_exec($mh, $active); + curl_pause($ch, CURLPAUSE_CONT); + if ($active) { + usleep(100); + curl_multi_select($mh); + } +} while ($active && $status == CURLM_OK); + +echo curl_multi_getcontent($ch); +?> +--EXPECT-- +string(15) "Foo bar baz qux" diff --git a/ext/curl/tests/curl_version_basic_001.phpt b/ext/curl/tests/curl_version_basic_001.phpt index 6bc361badef9c..52652822a308f 100644 --- a/ext/curl/tests/curl_version_basic_001.phpt +++ b/ext/curl/tests/curl_version_basic_001.phpt @@ -22,6 +22,6 @@ int(%i) int(%i) string(%i) "%s" string(%i) "%s" -string(%i) "%s" -string(%i) "%s" +string(%i) "%S" +string(%i) "%S" bool(true) diff --git a/ext/curl/tests/responder/get.inc b/ext/curl/tests/responder/get.inc index 4ed9ae0282346..c139c8c7d43a8 100644 --- a/ext/curl/tests/responder/get.inc +++ b/ext/curl/tests/responder/get.inc @@ -4,6 +4,9 @@ case 'post': var_dump($_POST); break; + case 'input': + var_dump(file_get_contents('php://input')); + break; case 'getpost': var_dump($_GET); var_dump($_POST); diff --git a/ext/date/lib/interval.c b/ext/date/lib/interval.c index e3bf5101b1ddd..da9262da999b6 100644 --- a/ext/date/lib/interval.c +++ b/ext/date/lib/interval.c @@ -36,25 +36,6 @@ static void swap_times(timelib_time **one, timelib_time **two, timelib_rel_time rt->invert = 1; } -static void swap_if_negative(timelib_rel_time *rt) -{ - if (rt->y == 0 && rt->m == 0 && rt->d == 0 && rt->h == 0 && rt->i == 0 && rt->s == 0 && rt->us == 0) { - return; - } - if (rt->y >= 0 && rt->m >= 0 && rt->d >= 0 && rt->h >= 0 && rt->i >= 0 && rt->s >= 0 && rt->us >= 0) { - return; - } - - rt->invert = 1 - rt->invert; - rt->y = 0 - rt->y; - rt->m = 0 - rt->m; - rt->d = 0 - rt->d; - rt->h = 0 - rt->h; - rt->i = 0 - rt->i; - rt->s = 0 - rt->s; - rt->us = 0 - rt->us; -} - static void sort_old_to_new(timelib_time **one, timelib_time **two, timelib_rel_time *rt) { /* Check whether date/times need to be inverted. If both times are @@ -115,80 +96,48 @@ static timelib_rel_time *timelib_diff_with_tzid(timelib_time *one, timelib_time rt->days = timelib_diff_days(one, two); /* Fall Back: Cater for transition period, where rt->invert is 0, but there are negative numbers */ - if (one->dst == 1 && two->dst == 0) { - /* First for two "Type 3" times */ - if (one->zone_type == TIMELIB_ZONETYPE_ID && two->zone_type == TIMELIB_ZONETYPE_ID) { - int success = timelib_get_time_zone_offset_info(two->sse, two->tz_info, &trans_offset, &trans_transition_time, NULL); - if ( - success && - one->sse < trans_transition_time && - one->sse >= trans_transition_time + dst_corr - ) { - timelib_sll flipped = SECS_PER_HOUR + (rt->i * 60) + (rt->s); - rt->h = flipped / SECS_PER_HOUR; - rt->i = (flipped - rt->h * SECS_PER_HOUR) / 60; - rt->s = flipped % 60; - } - } else if (rt->h == 0 && (rt->i < 0 || rt->s < 0)) { - /* Then for all the others */ - timelib_sll flipped = SECS_PER_HOUR + (rt->i * 60) + (rt->s); - rt->h = flipped / SECS_PER_HOUR; - rt->i = (flipped - rt->h * SECS_PER_HOUR) / 60; - rt->s = flipped % 60; - dst_corr += SECS_PER_HOUR; - dst_h_corr++; - } + if (two->sse < one->sse) { + timelib_sll flipped = llabs((rt->i * 60) + (rt->s) - dst_corr); + rt->h = flipped / SECS_PER_HOUR; + rt->i = (flipped - rt->h * SECS_PER_HOUR) / 60; + rt->s = flipped % 60; + + rt->invert = 1 - rt->invert; } timelib_do_rel_normalize(rt->invert ? one : two, rt); - /* Do corrections for "Type 3" times with the same TZID */ - if (one->zone_type == TIMELIB_ZONETYPE_ID && two->zone_type == TIMELIB_ZONETYPE_ID && strcmp(one->tz_info->name, two->tz_info->name) == 0) { - if (one->dst == 1 && two->dst == 0) { /* Fall Back */ - if (two->tz_info) { - int success = timelib_get_time_zone_offset_info(two->sse, two->tz_info, &trans_offset, &trans_transition_time, NULL); - - if ( - success && - two->sse >= trans_transition_time && - ((two->sse - one->sse + dst_corr) % SECS_PER_DAY) > (two->sse - trans_transition_time) - ) { - rt->h -= dst_h_corr; - rt->i -= dst_m_corr; - } + if (one->dst == 1 && two->dst == 0) { /* Fall Back */ + if (two->tz_info) { + if ((two->sse - one->sse + dst_corr) < SECS_PER_DAY) { + rt->h -= dst_h_corr; + rt->i -= dst_m_corr; } - } else if (one->dst == 0 && two->dst == 1) { /* Spring Forward */ - if (two->tz_info) { - int success = timelib_get_time_zone_offset_info(two->sse, two->tz_info, &trans_offset, &trans_transition_time, NULL); - - if ( - success && - !((one->sse + SECS_PER_DAY > trans_transition_time) && (one->sse + SECS_PER_DAY <= (trans_transition_time + dst_corr))) && - two->sse >= trans_transition_time && - ((two->sse - one->sse + dst_corr) % SECS_PER_DAY) > (two->sse - trans_transition_time) - ) { - rt->h -= dst_h_corr; - rt->i -= dst_m_corr; - } + } + } else if (one->dst == 0 && two->dst == 1) { /* Spring Forward */ + if (two->tz_info) { + int success = timelib_get_time_zone_offset_info(two->sse, two->tz_info, &trans_offset, &trans_transition_time, NULL); + + if ( + success && + !((one->sse + SECS_PER_DAY > trans_transition_time) && (one->sse + SECS_PER_DAY <= (trans_transition_time + dst_corr))) && + two->sse >= trans_transition_time && + ((two->sse - one->sse + dst_corr) % SECS_PER_DAY) > (two->sse - trans_transition_time) + ) { + rt->h -= dst_h_corr; + rt->i -= dst_m_corr; } - } else if (two->sse - one->sse >= SECS_PER_DAY) { - /* Check whether we're in the period to the next transition time */ - if (timelib_get_time_zone_offset_info(two->sse - two->z, two->tz_info, &trans_offset, &trans_transition_time, NULL)) { - dst_corr = one->z - trans_offset; - - if (two->sse >= trans_transition_time - dst_corr && two->sse < trans_transition_time) { - rt->d--; - rt->h = 24; - } + } + } else if (two->sse - one->sse >= SECS_PER_DAY) { + /* Check whether we're in the period to the next transition time */ + if (timelib_get_time_zone_offset_info(two->sse - two->z, two->tz_info, &trans_offset, &trans_transition_time, NULL)) { + dst_corr = one->z - trans_offset; + + if (two->sse >= trans_transition_time - dst_corr && two->sse < trans_transition_time) { + rt->d--; + rt->h = 24; } } - } else { - rt->h -= dst_h_corr; - rt->i -= dst_m_corr; - - swap_if_negative(rt); - - timelib_do_rel_normalize(rt->invert ? one : two, rt); } return rt; diff --git a/ext/date/lib/parse_date.c b/ext/date/lib/parse_date.c index fde143646992f..5a44e1c4497dc 100644 --- a/ext/date/lib/parse_date.c +++ b/ext/date/lib/parse_date.c @@ -1,9 +1,9 @@ -/* Generated by re2c 0.15.3 on Thu Dec 1 10:59:46 2022 */ +/* Generated by re2c 0.15.3 on Wed Jan 25 10:49:23 2023 */ #line 1 "ext/date/lib/parse_date.re" /* * The MIT License (MIT) * - * Copyright (c) 2015-2019 Derick Rethans + * Copyright (c) 2015-2023 Derick Rethans * Copyright (c) 2018 MongoDB, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -29,6 +29,7 @@ #include "timelib_private.h" #include +#include #include #include #include @@ -582,7 +583,13 @@ static timelib_ull timelib_get_signed_nr(Scanner *s, const char **ptr, int max_l ++len; } + errno = 0; tmp_nr = strtoll(str, NULL, 10); + if (errno == ERANGE) { + timelib_free(str); + add_error(s, TIMELIB_ERR_NUMBER_OUT_OF_RANGE, "Number out of range"); + return 0; + } timelib_free(str); @@ -787,7 +794,7 @@ static timelib_long timelib_lookup_abbr(const char **ptr, int *dst, char **tz_ab (**ptr >= 'A' && **ptr <= 'Z') || (**ptr >= 'a' && **ptr <= 'z') || (**ptr >= '0' && **ptr <= '9') || - **ptr == '/' || **ptr == '_' || **ptr == '-' + **ptr == '/' || **ptr == '_' || **ptr == '-' || **ptr == '+' ) { ++*ptr; } @@ -984,11 +991,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) std: s->tok = cursor; s->len = 0; -#line 1115 "ext/date/lib/parse_date.re" +#line 1122 "ext/date/lib/parse_date.re" -#line 992 "" +#line 999 "" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -1126,7 +1133,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy3: YYDEBUG(3, *YYCURSOR); -#line 1849 "ext/date/lib/parse_date.re" +#line 1856 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("tzcorrection | tz"); @@ -1139,7 +1146,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIMEZONE; } -#line 1143 "" +#line 1150 "" yy4: YYDEBUG(4, *YYCURSOR); yych = *++YYCURSOR; @@ -1446,12 +1453,12 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1483; yy12: YYDEBUG(12, *YYCURSOR); -#line 1944 "ext/date/lib/parse_date.re" +#line 1951 "ext/date/lib/parse_date.re" { add_error(s, TIMELIB_ERR_UNEXPECTED_CHARACTER, "Unexpected character"); goto std; } -#line 1455 "" +#line 1462 "" yy13: YYDEBUG(13, *YYCURSOR); yych = *++YYCURSOR; @@ -2695,11 +2702,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy54; yy49: YYDEBUG(49, *YYCURSOR); -#line 1933 "ext/date/lib/parse_date.re" +#line 1940 "ext/date/lib/parse_date.re" { goto std; } -#line 2703 "" +#line 2710 "" yy50: YYDEBUG(50, *YYCURSOR); yych = *++YYCURSOR; @@ -2708,12 +2715,12 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(51, *YYCURSOR); ++YYCURSOR; YYDEBUG(52, *YYCURSOR); -#line 1938 "ext/date/lib/parse_date.re" +#line 1945 "ext/date/lib/parse_date.re" { s->pos = cursor; s->line++; goto std; } -#line 2717 "" +#line 2724 "" yy53: YYDEBUG(53, *YYCURSOR); yych = *++YYCURSOR; @@ -3135,7 +3142,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 's') goto yy85; yy84: YYDEBUG(84, *YYCURSOR); -#line 1917 "ext/date/lib/parse_date.re" +#line 1924 "ext/date/lib/parse_date.re" { timelib_ull i; DEBUG_OUTPUT("relative"); @@ -3150,7 +3157,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 3154 "" +#line 3161 "" yy85: YYDEBUG(85, *YYCURSOR); yych = *++YYCURSOR; @@ -4159,7 +4166,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy219: YYDEBUG(219, *YYCURSOR); -#line 1780 "ext/date/lib/parse_date.re" +#line 1787 "ext/date/lib/parse_date.re" { const timelib_relunit* relunit; DEBUG_OUTPUT("daytext"); @@ -4176,7 +4183,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEKDAY; } -#line 4180 "" +#line 4187 "" yy220: YYDEBUG(220, *YYCURSOR); yych = *++YYCURSOR; @@ -4722,7 +4729,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy248: YYDEBUG(248, *YYCURSOR); -#line 1839 "ext/date/lib/parse_date.re" +#line 1846 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("monthtext"); TIMELIB_INIT; @@ -4731,7 +4738,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 4735 "" +#line 4742 "" yy249: YYDEBUG(249, *YYCURSOR); ++YYCURSOR; @@ -4980,7 +4987,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) goto yy267; yy262: YYDEBUG(262, *YYCURSOR); -#line 1585 "ext/date/lib/parse_date.re" +#line 1592 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datetextual | datenoyear"); @@ -4993,7 +5000,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 4997 "" +#line 5004 "" yy263: YYDEBUG(263, *YYCURSOR); yyaccept = 6; @@ -5120,7 +5127,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy276: YYDEBUG(276, *YYCURSOR); -#line 1887 "ext/date/lib/parse_date.re" +#line 1894 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz"); @@ -5149,7 +5156,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 5153 "" +#line 5160 "" yy277: YYDEBUG(277, *YYCURSOR); yyaccept = 7; @@ -5447,7 +5454,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(300, *YYCURSOR); ++YYCURSOR; YYDEBUG(301, *YYCURSOR); -#line 1863 "ext/date/lib/parse_date.re" +#line 1870 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12"); TIMELIB_INIT; @@ -5470,7 +5477,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 5474 "" +#line 5481 "" yy302: YYDEBUG(302, *YYCURSOR); yych = *++YYCURSOR; @@ -6148,7 +6155,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(362, *YYCURSOR); ++YYCURSOR; YYDEBUG(363, *YYCURSOR); -#line 1557 "ext/date/lib/parse_date.re" +#line 1564 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenoday"); @@ -6161,7 +6168,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 6165 "" +#line 6172 "" yy364: YYDEBUG(364, *YYCURSOR); yych = *++YYCURSOR; @@ -6392,7 +6399,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy372; yy371: YYDEBUG(371, *YYCURSOR); -#line 1701 "ext/date/lib/parse_date.re" +#line 1708 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextshort"); @@ -6405,7 +6412,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 6409 "" +#line 6416 "" yy372: YYDEBUG(372, *YYCURSOR); yych = *++YYCURSOR; @@ -6987,7 +6994,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy398: YYDEBUG(398, *YYCURSOR); -#line 1759 "ext/date/lib/parse_date.re" +#line 1766 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("ago"); TIMELIB_INIT; @@ -7007,7 +7014,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AGO; } -#line 7011 "" +#line 7018 "" yy399: YYDEBUG(399, *YYCURSOR); yyaccept = 5; @@ -8796,7 +8803,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy461: YYDEBUG(461, *YYCURSOR); -#line 1450 "ext/date/lib/parse_date.re" +#line 1457 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash"); TIMELIB_INIT; @@ -8807,7 +8814,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 8811 "" +#line 8818 "" yy462: YYDEBUG(462, *YYCURSOR); yych = *++YYCURSOR; @@ -8929,7 +8936,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(484, *YYCURSOR); ++YYCURSOR; YYDEBUG(485, *YYCURSOR); -#line 1476 "ext/date/lib/parse_date.re" +#line 1483 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601datex"); TIMELIB_INIT; @@ -8940,7 +8947,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 8944 "" +#line 8951 "" yy486: YYDEBUG(486, *YYCURSOR); yyaccept = 1; @@ -9694,7 +9701,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy509: YYDEBUG(509, *YYCURSOR); -#line 1599 "ext/date/lib/parse_date.re" +#line 1606 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenoyearrev"); TIMELIB_INIT; @@ -9705,7 +9712,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 9709 "" +#line 9716 "" yy510: YYDEBUG(510, *YYCURSOR); yyaccept = 9; @@ -9846,7 +9853,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(521, *YYCURSOR); ++YYCURSOR; YYDEBUG(522, *YYCURSOR); -#line 1303 "ext/date/lib/parse_date.re" +#line 1310 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12"); TIMELIB_INIT; @@ -9862,7 +9869,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME12; } -#line 9866 "" +#line 9873 "" yy523: YYDEBUG(523, *YYCURSOR); yyaccept = 10; @@ -9875,7 +9882,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy524: YYDEBUG(524, *YYCURSOR); -#line 1340 "ext/date/lib/parse_date.re" +#line 1347 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("timetiny24 | timeshort24 | timelong24 | iso8601long"); @@ -9902,7 +9909,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 9906 "" +#line 9913 "" yy525: YYDEBUG(525, *YYCURSOR); yyaccept = 10; @@ -10215,7 +10222,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(556, *YYCURSOR); ++YYCURSOR; YYDEBUG(557, *YYCURSOR); -#line 1320 "ext/date/lib/parse_date.re" +#line 1327 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("mssqltime"); TIMELIB_INIT; @@ -10234,7 +10241,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 10238 "" +#line 10245 "" yy558: YYDEBUG(558, *YYCURSOR); yyaccept = 10; @@ -10340,7 +10347,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy574; yy568: YYDEBUG(568, *YYCURSOR); -#line 1516 "ext/date/lib/parse_date.re" +#line 1523 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datefull"); @@ -10354,7 +10361,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL; } -#line 10358 "" +#line 10365 "" yy569: YYDEBUG(569, *YYCURSOR); yych = *++YYCURSOR; @@ -11090,7 +11097,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(639, *YYCURSOR); ++YYCURSOR; YYDEBUG(640, *YYCURSOR); -#line 1531 "ext/date/lib/parse_date.re" +#line 1538 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pointed date YYYY"); TIMELIB_INIT; @@ -11101,7 +11108,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 11105 "" +#line 11112 "" yy641: YYDEBUG(641, *YYCURSOR); yyaccept = 10; @@ -11137,7 +11144,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy638; yy645: YYDEBUG(645, *YYCURSOR); -#line 1543 "ext/date/lib/parse_date.re" +#line 1550 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pointed date YY"); @@ -11150,7 +11157,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 11154 "" +#line 11161 "" yy646: YYDEBUG(646, *YYCURSOR); yyaccept = 10; @@ -11791,7 +11798,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy690: YYDEBUG(690, *YYCURSOR); -#line 1502 "ext/date/lib/parse_date.re" +#line 1509 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshort"); @@ -11804,7 +11811,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 11808 "" +#line 11815 "" yy691: YYDEBUG(691, *YYCURSOR); yyaccept = 12; @@ -11910,7 +11917,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy700: YYDEBUG(700, *YYCURSOR); -#line 1434 "ext/date/lib/parse_date.re" +#line 1441 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("americanshort | american"); @@ -11925,7 +11932,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AMERICAN; } -#line 11929 "" +#line 11936 "" yy701: YYDEBUG(701, *YYCURSOR); yyaccept = 13; @@ -12159,7 +12166,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= ':') goto yy737; yy734: YYDEBUG(734, *YYCURSOR); -#line 1729 "ext/date/lib/parse_date.re" +#line 1736 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("clf"); @@ -12179,7 +12186,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 12183 "" +#line 12190 "" yy735: YYDEBUG(735, *YYCURSOR); yyaccept = 14; @@ -12799,7 +12806,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy808: YYDEBUG(808, *YYCURSOR); -#line 1462 "ext/date/lib/parse_date.re" +#line 1469 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("iso8601date2"); @@ -12812,7 +12819,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 12816 "" +#line 12823 "" yy809: YYDEBUG(809, *YYCURSOR); yych = *++YYCURSOR; @@ -12851,7 +12858,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(815, *YYCURSOR); ++YYCURSOR; YYDEBUG(816, *YYCURSOR); -#line 1715 "ext/date/lib/parse_date.re" +#line 1722 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextreverse"); @@ -12864,7 +12871,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 12868 "" +#line 12875 "" yy817: YYDEBUG(817, *YYCURSOR); yych = *++YYCURSOR; @@ -13029,7 +13036,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy828: YYDEBUG(828, *YYCURSOR); -#line 1750 "ext/date/lib/parse_date.re" +#line 1757 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("year4"); TIMELIB_INIT; @@ -13037,7 +13044,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 13041 "" +#line 13048 "" yy829: YYDEBUG(829, *YYCURSOR); yych = *++YYCURSOR; @@ -13242,7 +13249,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy838: YYDEBUG(838, *YYCURSOR); -#line 1571 "ext/date/lib/parse_date.re" +#line 1578 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenodayrev"); @@ -13255,7 +13262,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 13259 "" +#line 13266 "" yy839: YYDEBUG(839, *YYCURSOR); yych = *++YYCURSOR; @@ -13476,7 +13483,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '7') goto yy861; yy859: YYDEBUG(859, *YYCURSOR); -#line 1682 "ext/date/lib/parse_date.re" +#line 1689 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweek"); @@ -13494,7 +13501,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 13498 "" +#line 13505 "" yy860: YYDEBUG(860, *YYCURSOR); yych = *++YYCURSOR; @@ -13504,7 +13511,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(861, *YYCURSOR); ++YYCURSOR; YYDEBUG(862, *YYCURSOR); -#line 1663 "ext/date/lib/parse_date.re" +#line 1670 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweekday"); @@ -13522,7 +13529,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 13526 "" +#line 13533 "" yy863: YYDEBUG(863, *YYCURSOR); yych = *++YYCURSOR; @@ -13594,7 +13601,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy866: YYDEBUG(866, *YYCURSOR); -#line 1649 "ext/date/lib/parse_date.re" +#line 1656 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgydotd"); @@ -13607,7 +13614,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_YEARDAY; } -#line 13611 "" +#line 13618 "" yy867: YYDEBUG(867, *YYCURSOR); yych = *++YYCURSOR; @@ -13710,7 +13717,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy887: YYDEBUG(887, *YYCURSOR); -#line 1623 "ext/date/lib/parse_date.re" +#line 1630 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif"); @@ -13735,7 +13742,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_XMLRPC_SOAP; } -#line 13739 "" +#line 13746 "" yy888: YYDEBUG(888, *YYCURSOR); yych = *++YYCURSOR; @@ -14031,7 +14038,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy893: YYDEBUG(893, *YYCURSOR); -#line 1611 "ext/date/lib/parse_date.re" +#line 1618 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenocolon"); TIMELIB_INIT; @@ -14042,7 +14049,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NOCOLON; } -#line 14046 "" +#line 14053 "" yy894: YYDEBUG(894, *YYCURSOR); yych = *++YYCURSOR; @@ -14964,7 +14971,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1018: YYDEBUG(1018, *YYCURSOR); -#line 1488 "ext/date/lib/parse_date.re" +#line 1495 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshorter"); @@ -14977,7 +14984,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 14981 "" +#line 14988 "" yy1019: YYDEBUG(1019, *YYCURSOR); yyaccept = 22; @@ -16185,7 +16192,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1127: YYDEBUG(1127, *YYCURSOR); -#line 1368 "ext/date/lib/parse_date.re" +#line 1375 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnunocolon"); TIMELIB_INIT; @@ -16207,7 +16214,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_GNU_NOCOLON; } -#line 16211 "" +#line 16218 "" yy1128: YYDEBUG(1128, *YYCURSOR); yych = *++YYCURSOR; @@ -16307,7 +16314,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1135: YYDEBUG(1135, *YYCURSOR); -#line 1414 "ext/date/lib/parse_date.re" +#line 1421 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("iso8601nocolon"); @@ -16326,7 +16333,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_NOCOLON; } -#line 16330 "" +#line 16337 "" yy1136: YYDEBUG(1136, *YYCURSOR); yyaccept = 25; @@ -17302,7 +17309,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1179: YYDEBUG(1179, *YYCURSOR); -#line 1822 "ext/date/lib/parse_date.re" +#line 1829 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -17318,7 +17325,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 17322 "" +#line 17329 "" yy1180: YYDEBUG(1180, *YYCURSOR); ++YYCURSOR; @@ -17384,7 +17391,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1188, *YYCURSOR); ++YYCURSOR; YYDEBUG(1189, *YYCURSOR); -#line 1281 "ext/date/lib/parse_date.re" +#line 1288 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -17405,7 +17412,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEK_DAY_OF_MONTH; } -#line 17409 "" +#line 17416 "" yy1190: YYDEBUG(1190, *YYCURSOR); yyaccept = 26; @@ -17545,7 +17552,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1206: YYDEBUG(1206, *YYCURSOR); -#line 1798 "ext/date/lib/parse_date.re" +#line 1805 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -17568,7 +17575,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 17572 "" +#line 17579 "" yy1207: YYDEBUG(1207, *YYCURSOR); yych = *++YYCURSOR; @@ -20517,7 +20524,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1388: YYDEBUG(1388, *YYCURSOR); -#line 1258 "ext/date/lib/parse_date.re" +#line 1265 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("backof | frontof"); TIMELIB_INIT; @@ -20539,7 +20546,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 20543 "" +#line 20550 "" yy1389: YYDEBUG(1389, *YYCURSOR); yyaccept = 28; @@ -20838,7 +20845,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1410, *YYCURSOR); ++YYCURSOR; YYDEBUG(1411, *YYCURSOR); -#line 1241 "ext/date/lib/parse_date.re" +#line 1248 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("firstdayof | lastdayof"); TIMELIB_INIT; @@ -20854,7 +20861,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 20858 "" +#line 20865 "" yy1412: YYDEBUG(1412, *YYCURSOR); yyaccept = 1; @@ -22376,7 +22383,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1483; yy1485: YYDEBUG(1485, *YYCURSOR); -#line 1175 "ext/date/lib/parse_date.re" +#line 1182 "ext/date/lib/parse_date.re" { timelib_ull i; @@ -22401,7 +22408,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22405 "" +#line 22412 "" yy1486: YYDEBUG(1486, *YYCURSOR); ++YYCURSOR; @@ -22409,7 +22416,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1488; yy1487: YYDEBUG(1487, *YYCURSOR); -#line 1201 "ext/date/lib/parse_date.re" +#line 1208 "ext/date/lib/parse_date.re" { timelib_sll i; timelib_ull us; @@ -22448,7 +22455,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22452 "" +#line 22459 "" yy1488: YYDEBUG(1488, *YYCURSOR); yych = *++YYCURSOR; @@ -22917,7 +22924,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1524: YYDEBUG(1524, *YYCURSOR); -#line 1163 "ext/date/lib/parse_date.re" +#line 1170 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("tomorrow"); TIMELIB_INIT; @@ -22928,7 +22935,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22932 "" +#line 22939 "" yy1525: YYDEBUG(1525, *YYCURSOR); yych = *++YYCURSOR; @@ -22963,7 +22970,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1527: YYDEBUG(1527, *YYCURSOR); -#line 1153 "ext/date/lib/parse_date.re" +#line 1160 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("midnight | today"); TIMELIB_INIT; @@ -22972,7 +22979,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22976 "" +#line 22983 "" yy1528: YYDEBUG(1528, *YYCURSOR); yych = *++YYCURSOR; @@ -25067,7 +25074,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1612: YYDEBUG(1612, *YYCURSOR); -#line 1132 "ext/date/lib/parse_date.re" +#line 1139 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("now"); TIMELIB_INIT; @@ -25075,7 +25082,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 25079 "" +#line 25086 "" yy1613: YYDEBUG(1613, *YYCURSOR); yych = *++YYCURSOR; @@ -25214,7 +25221,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1620: YYDEBUG(1620, *YYCURSOR); -#line 1141 "ext/date/lib/parse_date.re" +#line 1148 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("noon"); TIMELIB_INIT; @@ -25225,7 +25232,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 25229 "" +#line 25236 "" yy1621: YYDEBUG(1621, *YYCURSOR); yyaccept = 1; @@ -25758,7 +25765,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1643: YYDEBUG(1643, *YYCURSOR); -#line 1120 "ext/date/lib/parse_date.re" +#line 1127 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("yesterday"); TIMELIB_INIT; @@ -25769,7 +25776,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 25773 "" +#line 25780 "" yy1644: YYDEBUG(1644, *YYCURSOR); yyaccept = 1; @@ -25942,7 +25949,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) goto yy1643; } } -#line 1948 "ext/date/lib/parse_date.re" +#line 1955 "ext/date/lib/parse_date.re" } diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index 800cd830fbd68..1dcfdd8c91f05 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2019 Derick Rethans + * Copyright (c) 2015-2023 Derick Rethans * Copyright (c) 2018 MongoDB, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -27,6 +27,7 @@ #include "timelib_private.h" #include +#include #include #include #include @@ -580,7 +581,13 @@ static timelib_ull timelib_get_signed_nr(Scanner *s, const char **ptr, int max_l ++len; } + errno = 0; tmp_nr = strtoll(str, NULL, 10); + if (errno == ERANGE) { + timelib_free(str); + add_error(s, TIMELIB_ERR_NUMBER_OUT_OF_RANGE, "Number out of range"); + return 0; + } timelib_free(str); @@ -785,7 +792,7 @@ static timelib_long timelib_lookup_abbr(const char **ptr, int *dst, char **tz_ab (**ptr >= 'A' && **ptr <= 'Z') || (**ptr >= 'a' && **ptr <= 'z') || (**ptr >= '0' && **ptr <= '9') || - **ptr == '/' || **ptr == '_' || **ptr == '-' + **ptr == '/' || **ptr == '_' || **ptr == '-' || **ptr == '+' ) { ++*ptr; } diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index c9e8c6d82980e..e385b2e3468c2 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2022 Derick Rethans + * Copyright (c) 2015-2023 Derick Rethans * Copyright (c) 2018,2021 MongoDB, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -30,9 +30,9 @@ # include "timelib_config.h" #endif -#define TIMELIB_VERSION 202203 -#define TIMELIB_EXTENDED_VERSION 20220301 -#define TIMELIB_ASCII_VERSION "2022.03" +#define TIMELIB_VERSION 202207 +#define TIMELIB_EXTENDED_VERSION 20220701 +#define TIMELIB_ASCII_VERSION "2022.07" #include #include @@ -321,6 +321,7 @@ typedef struct _timelib_abbr_info { #define TIMELIB_ERR_INVALID_TZ_OFFSET 0x223 #define TIMELIB_ERR_FORMAT_LITERAL_MISMATCH 0x224 #define TIMELIB_ERR_MIX_ISO_WITH_NATURAL 0x225 +#define TIMELIB_ERR_NUMBER_OUT_OF_RANGE 0x226 #define TIMELIB_ZONETYPE_NONE 0 #define TIMELIB_ZONETYPE_OFFSET 1 diff --git a/ext/date/lib/timezonedb.h b/ext/date/lib/timezonedb.h index 2b4f626f23ec4..94397084d7bb2 100644 --- a/ext/date/lib/timezonedb.h +++ b/ext/date/lib/timezonedb.h @@ -19,593 +19,593 @@ const timelib_tzdb_index_entry timezonedb_idx_builtin[597] = { { (char*) "Africa/Brazzaville" , 0x000A9B }, { (char*) "Africa/Bujumbura" , 0x000B2A }, { (char*) "Africa/Cairo" , 0x000BB9 }, - { (char*) "Africa/Casablanca" , 0x0010C1 }, - { (char*) "Africa/Ceuta" , 0x00184C }, - { (char*) "Africa/Conakry" , 0x001A98 }, - { (char*) "Africa/Dakar" , 0x001B42 }, - { (char*) "Africa/Dar_es_Salaam" , 0x001BE3 }, - { (char*) "Africa/Djibouti" , 0x001C90 }, - { (char*) "Africa/Douala" , 0x001D1F }, - { (char*) "Africa/El_Aaiun" , 0x001DAE }, - { (char*) "Africa/Freetown" , 0x0024E0 }, - { (char*) "Africa/Gaborone" , 0x002630 }, - { (char*) "Africa/Harare" , 0x0026F0 }, - { (char*) "Africa/Johannesburg" , 0x00277F }, - { (char*) "Africa/Juba" , 0x002849 }, - { (char*) "Africa/Kampala" , 0x002A1F }, - { (char*) "Africa/Khartoum" , 0x002AE1 }, - { (char*) "Africa/Kigali" , 0x002CB7 }, - { (char*) "Africa/Kinshasa" , 0x002D46 }, - { (char*) "Africa/Lagos" , 0x002DEE }, - { (char*) "Africa/Libreville" , 0x002EAE }, - { (char*) "Africa/Lome" , 0x002F3D }, - { (char*) "Africa/Luanda" , 0x002FCB }, - { (char*) "Africa/Lubumbashi" , 0x003069 }, - { (char*) "Africa/Lusaka" , 0x003124 }, - { (char*) "Africa/Malabo" , 0x0031B3 }, - { (char*) "Africa/Maputo" , 0x003255 }, - { (char*) "Africa/Maseru" , 0x0032E4 }, - { (char*) "Africa/Mbabane" , 0x00338D }, - { (char*) "Africa/Mogadishu" , 0x00341E }, - { (char*) "Africa/Monrovia" , 0x0034CB }, - { (char*) "Africa/Nairobi" , 0x00357B }, - { (char*) "Africa/Ndjamena" , 0x003646 }, - { (char*) "Africa/Niamey" , 0x0036F2 }, - { (char*) "Africa/Nouakchott" , 0x0037A7 }, - { (char*) "Africa/Ouagadougou" , 0x003851 }, - { (char*) "Africa/Porto-Novo" , 0x0038DF }, - { (char*) "Africa/Sao_Tome" , 0x003981 }, - { (char*) "Africa/Timbuktu" , 0x003A3A }, - { (char*) "Africa/Tripoli" , 0x003AC8 }, - { (char*) "Africa/Tunis" , 0x003C83 }, - { (char*) "Africa/Windhoek" , 0x003E50 }, - { (char*) "America/Adak" , 0x0040DA }, - { (char*) "America/Anchorage" , 0x0044BF }, - { (char*) "America/Anguilla" , 0x0048AF }, - { (char*) "America/Antigua" , 0x00493D }, - { (char*) "America/Araguaina" , 0x0049DE }, - { (char*) "America/Argentina/Buenos_Aires" , 0x004C43 }, - { (char*) "America/Argentina/Catamarca" , 0x004F28 }, - { (char*) "America/Argentina/ComodRivadavia" , 0x005213 }, - { (char*) "America/Argentina/Cordoba" , 0x0054E3 }, - { (char*) "America/Argentina/Jujuy" , 0x0057E9 }, - { (char*) "America/Argentina/La_Rioja" , 0x005AB1 }, - { (char*) "America/Argentina/Mendoza" , 0x005D97 }, - { (char*) "America/Argentina/Rio_Gallegos" , 0x006073 }, - { (char*) "America/Argentina/Salta" , 0x006352 }, - { (char*) "America/Argentina/San_Juan" , 0x006626 }, - { (char*) "America/Argentina/San_Luis" , 0x00690C }, - { (char*) "America/Argentina/Tucuman" , 0x006BF2 }, - { (char*) "America/Argentina/Ushuaia" , 0x006EE0 }, - { (char*) "America/Aruba" , 0x0071C5 }, - { (char*) "America/Asuncion" , 0x007268 }, - { (char*) "America/Atikokan" , 0x0075E8 }, - { (char*) "America/Atka" , 0x0076F5 }, - { (char*) "America/Bahia" , 0x007ACA }, - { (char*) "America/Bahia_Banderas" , 0x007D85 }, - { (char*) "America/Barbados" , 0x00807A }, - { (char*) "America/Belem" , 0x00819C }, - { (char*) "America/Belize" , 0x008344 }, - { (char*) "America/Blanc-Sablon" , 0x008765 }, - { (char*) "America/Boa_Vista" , 0x00885A }, - { (char*) "America/Bogota" , 0x008A1B }, - { (char*) "America/Boise" , 0x008ADA }, - { (char*) "America/Buenos_Aires" , 0x008EED }, - { (char*) "America/Cambridge_Bay" , 0x0091BD }, - { (char*) "America/Campo_Grande" , 0x009550 }, - { (char*) "America/Cancun" , 0x009926 }, - { (char*) "America/Caracas" , 0x009B4F }, - { (char*) "America/Catamarca" , 0x009C19 }, - { (char*) "America/Cayenne" , 0x009EE9 }, - { (char*) "America/Cayman" , 0x009F8C }, - { (char*) "America/Chicago" , 0x00A02D }, - { (char*) "America/Chihuahua" , 0x00A727 }, - { (char*) "America/Ciudad_Juarez" , 0x00A9FC }, - { (char*) "America/Coral_Harbour" , 0x00ACF2 }, - { (char*) "America/Cordoba" , 0x00AD93 }, - { (char*) "America/Costa_Rica" , 0x00B063 }, - { (char*) "America/Creston" , 0x00B157 }, - { (char*) "America/Cuiaba" , 0x00B213 }, - { (char*) "America/Curacao" , 0x00B5D0 }, - { (char*) "America/Danmarkshavn" , 0x00B673 }, - { (char*) "America/Dawson" , 0x00B858 }, - { (char*) "America/Dawson_Creek" , 0x00BC7B }, - { (char*) "America/Denver" , 0x00BF52 }, - { (char*) "America/Detroit" , 0x00C385 }, - { (char*) "America/Dominica" , 0x00C72D }, - { (char*) "America/Edmonton" , 0x00C7BB }, - { (char*) "America/Eirunepe" , 0x00CBAE }, - { (char*) "America/El_Salvador" , 0x00CD7D }, - { (char*) "America/Ensenada" , 0x00CE39 }, - { (char*) "America/Fort_Nelson" , 0x00D246 }, - { (char*) "America/Fort_Wayne" , 0x00D80E }, - { (char*) "America/Fortaleza" , 0x00DA2D }, - { (char*) "America/Glace_Bay" , 0x00DC43 }, - { (char*) "America/Godthab" , 0x00DFDA }, - { (char*) "America/Goose_Bay" , 0x00E389 }, - { (char*) "America/Grand_Turk" , 0x00E9E1 }, - { (char*) "America/Grenada" , 0x00ED42 }, - { (char*) "America/Guadeloupe" , 0x00EDD0 }, - { (char*) "America/Guatemala" , 0x00EE5E }, - { (char*) "America/Guayaquil" , 0x00EF3E }, - { (char*) "America/Guyana" , 0x00F00F }, - { (char*) "America/Halifax" , 0x00F0D0 }, - { (char*) "America/Havana" , 0x00F782 }, - { (char*) "America/Hermosillo" , 0x00FBEB }, - { (char*) "America/Indiana/Indianapolis" , 0x00FD1B }, - { (char*) "America/Indiana/Knox" , 0x00FF53 }, - { (char*) "America/Indiana/Marengo" , 0x01036C }, - { (char*) "America/Indiana/Petersburg" , 0x0105C6 }, - { (char*) "America/Indiana/Tell_City" , 0x010890 }, - { (char*) "America/Indiana/Vevay" , 0x010ABA }, - { (char*) "America/Indiana/Vincennes" , 0x010C51 }, - { (char*) "America/Indiana/Winamac" , 0x010EA7 }, - { (char*) "America/Indianapolis" , 0x01112D }, - { (char*) "America/Inuvik" , 0x01134C }, - { (char*) "America/Iqaluit" , 0x01169D }, - { (char*) "America/Jamaica" , 0x011A19 }, - { (char*) "America/Jujuy" , 0x011B78 }, - { (char*) "America/Juneau" , 0x011E36 }, - { (char*) "America/Kentucky/Louisville" , 0x01221C }, - { (char*) "America/Kentucky/Monticello" , 0x012720 }, - { (char*) "America/Knox_IN" , 0x012B0C }, - { (char*) "America/Kralendijk" , 0x012F10 }, - { (char*) "America/La_Paz" , 0x012FCD }, - { (char*) "America/Lima" , 0x013083 }, - { (char*) "America/Los_Angeles" , 0x0131AA }, - { (char*) "America/Louisville" , 0x0136CB }, - { (char*) "America/Lower_Princes" , 0x013BB1 }, - { (char*) "America/Maceio" , 0x013C6E }, - { (char*) "America/Managua" , 0x013E80 }, - { (char*) "America/Manaus" , 0x013FB3 }, - { (char*) "America/Marigot" , 0x01416A }, - { (char*) "America/Martinique" , 0x014227 }, - { (char*) "America/Matamoros" , 0x0142E5 }, - { (char*) "America/Mazatlan" , 0x0144D2 }, - { (char*) "America/Mendoza" , 0x0147DE }, - { (char*) "America/Menominee" , 0x014AAE }, - { (char*) "America/Merida" , 0x014E6E }, - { (char*) "America/Metlakatla" , 0x015119 }, - { (char*) "America/Mexico_City" , 0x01538F }, - { (char*) "America/Miquelon" , 0x0156AE }, - { (char*) "America/Moncton" , 0x0158E0 }, - { (char*) "America/Monterrey" , 0x015ED9 }, - { (char*) "America/Montevideo" , 0x01619F }, - { (char*) "America/Montreal" , 0x016574 }, - { (char*) "America/Montserrat" , 0x016C35 }, - { (char*) "America/Nassau" , 0x016CC3 }, - { (char*) "America/New_York" , 0x0170BD }, - { (char*) "America/Nipigon" , 0x0177AD }, - { (char*) "America/Nome" , 0x017E6E }, - { (char*) "America/Noronha" , 0x018256 }, - { (char*) "America/North_Dakota/Beulah" , 0x018456 }, - { (char*) "America/North_Dakota/Center" , 0x01888A }, - { (char*) "America/North_Dakota/New_Salem" , 0x018C89 }, - { (char*) "America/Nuuk" , 0x01908E }, - { (char*) "America/Ojinaga" , 0x019453 }, - { (char*) "America/Panama" , 0x019740 }, - { (char*) "America/Pangnirtung" , 0x0197E1 }, - { (char*) "America/Paramaribo" , 0x019B44 }, - { (char*) "America/Phoenix" , 0x019C0B }, - { (char*) "America/Port-au-Prince" , 0x019D24 }, - { (char*) "America/Port_of_Spain" , 0x019F65 }, - { (char*) "America/Porto_Acre" , 0x019FF3 }, - { (char*) "America/Porto_Velho" , 0x01A1A1 }, - { (char*) "America/Puerto_Rico" , 0x01A33F }, - { (char*) "America/Punta_Arenas" , 0x01A3FC }, - { (char*) "America/Rainy_River" , 0x01A8DE }, - { (char*) "America/Rankin_Inlet" , 0x01ADF8 }, - { (char*) "America/Recife" , 0x01B141 }, - { (char*) "America/Regina" , 0x01B33B }, - { (char*) "America/Resolute" , 0x01B5DA }, - { (char*) "America/Rio_Branco" , 0x01B924 }, - { (char*) "America/Rosario" , 0x01BAD6 }, - { (char*) "America/Santa_Isabel" , 0x01BDA6 }, - { (char*) "America/Santarem" , 0x01C1B3 }, - { (char*) "America/Santiago" , 0x01C363 }, - { (char*) "America/Santo_Domingo" , 0x01C8CB }, - { (char*) "America/Sao_Paulo" , 0x01CA14 }, - { (char*) "America/Scoresbysund" , 0x01CE0E }, - { (char*) "America/Shiprock" , 0x01D016 }, - { (char*) "America/Sitka" , 0x01D434 }, - { (char*) "America/St_Barthelemy" , 0x01D80F }, - { (char*) "America/St_Johns" , 0x01D8CC }, - { (char*) "America/St_Kitts" , 0x01E050 }, - { (char*) "America/St_Lucia" , 0x01E0DE }, - { (char*) "America/St_Thomas" , 0x01E17F }, - { (char*) "America/St_Vincent" , 0x01E20D }, - { (char*) "America/Swift_Current" , 0x01E2AE }, - { (char*) "America/Tegucigalpa" , 0x01E43C }, - { (char*) "America/Thule" , 0x01E50A }, - { (char*) "America/Thunder_Bay" , 0x01E6EB }, - { (char*) "America/Tijuana" , 0x01EDAC }, - { (char*) "America/Toronto" , 0x01F1C8 }, - { (char*) "America/Tortola" , 0x01F8A6 }, - { (char*) "America/Vancouver" , 0x01F934 }, - { (char*) "America/Virgin" , 0x01FE8B }, - { (char*) "America/Whitehorse" , 0x01FF48 }, - { (char*) "America/Winnipeg" , 0x02036B }, - { (char*) "America/Yakutat" , 0x0208A2 }, - { (char*) "America/Yellowknife" , 0x020C70 }, - { (char*) "Antarctica/Casey" , 0x020FDF }, - { (char*) "Antarctica/Davis" , 0x0210E3 }, - { (char*) "Antarctica/DumontDUrville" , 0x0211B9 }, - { (char*) "Antarctica/Macquarie" , 0x02126D }, - { (char*) "Antarctica/Mawson" , 0x021659 }, - { (char*) "Antarctica/McMurdo" , 0x021703 }, - { (char*) "Antarctica/Palmer" , 0x021A35 }, - { (char*) "Antarctica/Rothera" , 0x021DBE }, - { (char*) "Antarctica/South_Pole" , 0x021E55 }, - { (char*) "Antarctica/Syowa" , 0x022274 }, - { (char*) "Antarctica/Troll" , 0x02230A }, - { (char*) "Antarctica/Vostok" , 0x0223CC }, - { (char*) "Arctic/Longyearbyen" , 0x022463 }, - { (char*) "Asia/Aden" , 0x022730 }, - { (char*) "Asia/Almaty" , 0x0227C1 }, - { (char*) "Asia/Amman" , 0x022A45 }, - { (char*) "Asia/Anadyr" , 0x022DF1 }, - { (char*) "Asia/Aqtau" , 0x0230F7 }, - { (char*) "Asia/Aqtobe" , 0x023376 }, - { (char*) "Asia/Ashgabat" , 0x0235F6 }, - { (char*) "Asia/Ashkhabad" , 0x023779 }, - { (char*) "Asia/Atyrau" , 0x0238FC }, - { (char*) "Asia/Baghdad" , 0x023B85 }, - { (char*) "Asia/Bahrain" , 0x023E07 }, - { (char*) "Asia/Baku" , 0x023EC0 }, - { (char*) "Asia/Bangkok" , 0x0241B4 }, - { (char*) "Asia/Barnaul" , 0x024258 }, - { (char*) "Asia/Beirut" , 0x024563 }, - { (char*) "Asia/Bishkek" , 0x02484B }, - { (char*) "Asia/Brunei" , 0x024AC1 }, - { (char*) "Asia/Calcutta" , 0x024B67 }, - { (char*) "Asia/Chita" , 0x024C4F }, - { (char*) "Asia/Choibalsan" , 0x024F5D }, - { (char*) "Asia/Chongqing" , 0x0251E6 }, - { (char*) "Asia/Chungking" , 0x02537B }, - { (char*) "Asia/Colombo" , 0x025510 }, - { (char*) "Asia/Dacca" , 0x025613 }, - { (char*) "Asia/Damascus" , 0x025706 }, - { (char*) "Asia/Dhaka" , 0x025BE4 }, - { (char*) "Asia/Dili" , 0x025CD7 }, - { (char*) "Asia/Dubai" , 0x025D8D }, - { (char*) "Asia/Dushanbe" , 0x025E1E }, - { (char*) "Asia/Famagusta" , 0x025F98 }, - { (char*) "Asia/Gaza" , 0x02635F }, - { (char*) "Asia/Harbin" , 0x02685F }, - { (char*) "Asia/Hebron" , 0x0269F4 }, - { (char*) "Asia/Ho_Chi_Minh" , 0x026F05 }, - { (char*) "Asia/Hong_Kong" , 0x026FFD }, - { (char*) "Asia/Hovd" , 0x027310 }, - { (char*) "Asia/Irkutsk" , 0x027599 }, - { (char*) "Asia/Istanbul" , 0x0278B7 }, - { (char*) "Asia/Jakarta" , 0x027D73 }, - { (char*) "Asia/Jayapura" , 0x027E84 }, - { (char*) "Asia/Jerusalem" , 0x027F71 }, - { (char*) "Asia/Kabul" , 0x0283AF }, - { (char*) "Asia/Kamchatka" , 0x02845A }, - { (char*) "Asia/Karachi" , 0x02874F }, - { (char*) "Asia/Kashgar" , 0x028865 }, - { (char*) "Asia/Kathmandu" , 0x0288F6 }, - { (char*) "Asia/Katmandu" , 0x0289A3 }, - { (char*) "Asia/Khandyga" , 0x028A50 }, - { (char*) "Asia/Kolkata" , 0x028D81 }, - { (char*) "Asia/Krasnoyarsk" , 0x028E69 }, - { (char*) "Asia/Kuala_Lumpur" , 0x029173 }, - { (char*) "Asia/Kuching" , 0x029293 }, - { (char*) "Asia/Kuwait" , 0x0293ED }, - { (char*) "Asia/Macao" , 0x02947E }, - { (char*) "Asia/Macau" , 0x0297A1 }, - { (char*) "Asia/Magadan" , 0x029AC4 }, - { (char*) "Asia/Makassar" , 0x029DCF }, - { (char*) "Asia/Manila" , 0x029EE2 }, - { (char*) "Asia/Muscat" , 0x029FDC }, - { (char*) "Asia/Nicosia" , 0x02A06D }, - { (char*) "Asia/Novokuznetsk" , 0x02A2E1 }, - { (char*) "Asia/Novosibirsk" , 0x02A5D4 }, - { (char*) "Asia/Omsk" , 0x02A8E5 }, - { (char*) "Asia/Oral" , 0x02ABE3 }, - { (char*) "Asia/Phnom_Penh" , 0x02AE6F }, - { (char*) "Asia/Pontianak" , 0x02AF43 }, - { (char*) "Asia/Pyongyang" , 0x02B05C }, - { (char*) "Asia/Qatar" , 0x02B11F }, - { (char*) "Asia/Qostanay" , 0x02B1C3 }, - { (char*) "Asia/Qyzylorda" , 0x02B450 }, - { (char*) "Asia/Rangoon" , 0x02B6E9 }, - { (char*) "Asia/Riyadh" , 0x02B7B0 }, - { (char*) "Asia/Saigon" , 0x02B841 }, - { (char*) "Asia/Sakhalin" , 0x02B939 }, - { (char*) "Asia/Samarkand" , 0x02BC50 }, - { (char*) "Asia/Seoul" , 0x02BDDB }, - { (char*) "Asia/Shanghai" , 0x02BF86 }, - { (char*) "Asia/Singapore" , 0x02C127 }, - { (char*) "Asia/Srednekolymsk" , 0x02C233 }, - { (char*) "Asia/Taipei" , 0x02C547 }, - { (char*) "Asia/Tashkent" , 0x02C752 }, - { (char*) "Asia/Tbilisi" , 0x02C8DD }, - { (char*) "Asia/Tehran" , 0x02CB5E }, - { (char*) "Asia/Tel_Aviv" , 0x02CE96 }, - { (char*) "Asia/Thimbu" , 0x02D2D4 }, - { (char*) "Asia/Thimphu" , 0x02D37A }, - { (char*) "Asia/Tokyo" , 0x02D420 }, - { (char*) "Asia/Tomsk" , 0x02D501 }, - { (char*) "Asia/Ujung_Pandang" , 0x02D80C }, - { (char*) "Asia/Ulaanbaatar" , 0x02D8D6 }, - { (char*) "Asia/Ulan_Bator" , 0x02DB49 }, - { (char*) "Asia/Urumqi" , 0x02DDA7 }, - { (char*) "Asia/Ust-Nera" , 0x02DE45 }, - { (char*) "Asia/Vientiane" , 0x02E168 }, - { (char*) "Asia/Vladivostok" , 0x02E24E }, - { (char*) "Asia/Yakutsk" , 0x02E553 }, - { (char*) "Asia/Yangon" , 0x02E857 }, - { (char*) "Asia/Yekaterinburg" , 0x02E91E }, - { (char*) "Asia/Yerevan" , 0x02EC30 }, - { (char*) "Atlantic/Azores" , 0x02EF00 }, - { (char*) "Atlantic/Bermuda" , 0x02F4BF }, - { (char*) "Atlantic/Canary" , 0x02F8CB }, - { (char*) "Atlantic/Cape_Verde" , 0x02FAC3 }, - { (char*) "Atlantic/Faeroe" , 0x02FB7E }, - { (char*) "Atlantic/Faroe" , 0x02FD43 }, - { (char*) "Atlantic/Jan_Mayen" , 0x02FF08 }, - { (char*) "Atlantic/Madeira" , 0x0301D5 }, - { (char*) "Atlantic/Reykjavik" , 0x03079D }, - { (char*) "Atlantic/South_Georgia" , 0x030A9A }, - { (char*) "Atlantic/St_Helena" , 0x030B2A }, - { (char*) "Atlantic/Stanley" , 0x030BCB }, - { (char*) "Australia/ACT" , 0x030EEC }, - { (char*) "Australia/Adelaide" , 0x031280 }, - { (char*) "Australia/Brisbane" , 0x031634 }, - { (char*) "Australia/Broken_Hill" , 0x031778 }, - { (char*) "Australia/Canberra" , 0x031B4D }, - { (char*) "Australia/Currie" , 0x031EE1 }, - { (char*) "Australia/Darwin" , 0x0322D8 }, - { (char*) "Australia/Eucla" , 0x0323E0 }, - { (char*) "Australia/Hobart" , 0x03253F }, - { (char*) "Australia/LHI" , 0x03293E }, - { (char*) "Australia/Lindeman" , 0x032BFE }, - { (char*) "Australia/Lord_Howe" , 0x032D6E }, - { (char*) "Australia/Melbourne" , 0x03303E }, - { (char*) "Australia/North" , 0x0333DA }, - { (char*) "Australia/NSW" , 0x0334D0 }, - { (char*) "Australia/Perth" , 0x033864 }, - { (char*) "Australia/Queensland" , 0x0339C0 }, - { (char*) "Australia/South" , 0x033AED }, - { (char*) "Australia/Sydney" , 0x033E92 }, - { (char*) "Australia/Tasmania" , 0x034242 }, - { (char*) "Australia/Victoria" , 0x034639 }, - { (char*) "Australia/West" , 0x0349CD }, - { (char*) "Australia/Yancowinna" , 0x034B0B }, - { (char*) "Brazil/Acre" , 0x034EC4 }, - { (char*) "Brazil/DeNoronha" , 0x035072 }, - { (char*) "Brazil/East" , 0x035262 }, - { (char*) "Brazil/West" , 0x035626 }, - { (char*) "Canada/Atlantic" , 0x0357CE }, - { (char*) "Canada/Central" , 0x035E62 }, - { (char*) "Canada/Eastern" , 0x03637C }, - { (char*) "Canada/Mountain" , 0x036A3D }, - { (char*) "Canada/Newfoundland" , 0x036E13 }, - { (char*) "Canada/Pacific" , 0x037575 }, - { (char*) "Canada/Saskatchewan" , 0x037AB3 }, - { (char*) "Canada/Yukon" , 0x037D3D }, - { (char*) "CET" , 0x03814E }, - { (char*) "Chile/Continental" , 0x0383C7 }, - { (char*) "Chile/EasterIsland" , 0x03891D }, - { (char*) "CST6CDT" , 0x038DBF }, - { (char*) "Cuba" , 0x039182 }, - { (char*) "EET" , 0x0395EB }, - { (char*) "Egypt" , 0x0397E8 }, - { (char*) "Eire" , 0x039CF0 }, - { (char*) "EST" , 0x03A2D4 }, - { (char*) "EST5EDT" , 0x03A34F }, - { (char*) "Etc/GMT" , 0x03A712 }, - { (char*) "Etc/GMT+0" , 0x03A78D }, - { (char*) "Etc/GMT+1" , 0x03A808 }, - { (char*) "Etc/GMT+10" , 0x03A885 }, - { (char*) "Etc/GMT+11" , 0x03A903 }, - { (char*) "Etc/GMT+12" , 0x03A981 }, - { (char*) "Etc/GMT+2" , 0x03A9FF }, - { (char*) "Etc/GMT+3" , 0x03AA7C }, - { (char*) "Etc/GMT+4" , 0x03AAF9 }, - { (char*) "Etc/GMT+5" , 0x03AB76 }, - { (char*) "Etc/GMT+6" , 0x03ABF3 }, - { (char*) "Etc/GMT+7" , 0x03AC70 }, - { (char*) "Etc/GMT+8" , 0x03ACED }, - { (char*) "Etc/GMT+9" , 0x03AD6A }, - { (char*) "Etc/GMT-0" , 0x03ADE7 }, - { (char*) "Etc/GMT-1" , 0x03AE62 }, - { (char*) "Etc/GMT-10" , 0x03AEE0 }, - { (char*) "Etc/GMT-11" , 0x03AF5F }, - { (char*) "Etc/GMT-12" , 0x03AFDE }, - { (char*) "Etc/GMT-13" , 0x03B05D }, - { (char*) "Etc/GMT-14" , 0x03B0DC }, - { (char*) "Etc/GMT-2" , 0x03B15B }, - { (char*) "Etc/GMT-3" , 0x03B1D9 }, - { (char*) "Etc/GMT-4" , 0x03B257 }, - { (char*) "Etc/GMT-5" , 0x03B2D5 }, - { (char*) "Etc/GMT-6" , 0x03B353 }, - { (char*) "Etc/GMT-7" , 0x03B3D1 }, - { (char*) "Etc/GMT-8" , 0x03B44F }, - { (char*) "Etc/GMT-9" , 0x03B4CD }, - { (char*) "Etc/GMT0" , 0x03B54B }, - { (char*) "Etc/Greenwich" , 0x03B5C6 }, - { (char*) "Etc/UCT" , 0x03B641 }, - { (char*) "Etc/Universal" , 0x03B6BC }, - { (char*) "Etc/UTC" , 0x03B737 }, - { (char*) "Etc/Zulu" , 0x03B7B2 }, - { (char*) "Europe/Amsterdam" , 0x03B82D }, - { (char*) "Europe/Andorra" , 0x03BC68 }, - { (char*) "Europe/Astrakhan" , 0x03BDF9 }, - { (char*) "Europe/Athens" , 0x03C0ED }, - { (char*) "Europe/Belfast" , 0x03C3A3 }, - { (char*) "Europe/Belgrade" , 0x03C9EE }, - { (char*) "Europe/Berlin" , 0x03CBD8 }, - { (char*) "Europe/Bratislava" , 0x03CEB9 }, - { (char*) "Europe/Brussels" , 0x03D198 }, - { (char*) "Europe/Bucharest" , 0x03D5F3 }, - { (char*) "Europe/Budapest" , 0x03D894 }, - { (char*) "Europe/Busingen" , 0x03DB9E }, - { (char*) "Europe/Chisinau" , 0x03DDA3 }, - { (char*) "Europe/Copenhagen" , 0x03E0A2 }, - { (char*) "Europe/Dublin" , 0x03E31D }, - { (char*) "Europe/Gibraltar" , 0x03E901 }, - { (char*) "Europe/Guernsey" , 0x03EDD1 }, - { (char*) "Europe/Helsinki" , 0x03F428 }, - { (char*) "Europe/Isle_of_Man" , 0x03F615 }, - { (char*) "Europe/Istanbul" , 0x03FC60 }, - { (char*) "Europe/Jersey" , 0x04011C }, - { (char*) "Europe/Kaliningrad" , 0x040773 }, - { (char*) "Europe/Kiev" , 0x040B1B }, - { (char*) "Europe/Kirov" , 0x040D55 }, - { (char*) "Europe/Kyiv" , 0x04103C }, - { (char*) "Europe/Lisbon" , 0x04128A }, - { (char*) "Europe/Ljubljana" , 0x041857 }, - { (char*) "Europe/London" , 0x041A41 }, - { (char*) "Europe/Luxembourg" , 0x04208C }, - { (char*) "Europe/Madrid" , 0x0424D7 }, - { (char*) "Europe/Malta" , 0x042874 }, - { (char*) "Europe/Mariehamn" , 0x042C20 }, - { (char*) "Europe/Minsk" , 0x042E0D }, - { (char*) "Europe/Monaco" , 0x043141 }, - { (char*) "Europe/Moscow" , 0x0435A7 }, - { (char*) "Europe/Nicosia" , 0x043953 }, - { (char*) "Europe/Oslo" , 0x043BB4 }, - { (char*) "Europe/Paris" , 0x043E64 }, - { (char*) "Europe/Podgorica" , 0x0442C1 }, - { (char*) "Europe/Prague" , 0x0444AB }, - { (char*) "Europe/Riga" , 0x04478A }, - { (char*) "Europe/Rome" , 0x044A4C }, - { (char*) "Europe/Samara" , 0x044E0B }, - { (char*) "Europe/San_Marino" , 0x04510C }, - { (char*) "Europe/Sarajevo" , 0x0454CB }, - { (char*) "Europe/Saratov" , 0x0456B5 }, - { (char*) "Europe/Simferopol" , 0x0459A7 }, - { (char*) "Europe/Skopje" , 0x045D1A }, - { (char*) "Europe/Sofia" , 0x045F04 }, - { (char*) "Europe/Stockholm" , 0x046160 }, - { (char*) "Europe/Tallinn" , 0x04635D }, - { (char*) "Europe/Tirane" , 0x04660C }, - { (char*) "Europe/Tiraspol" , 0x046874 }, - { (char*) "Europe/Ulyanovsk" , 0x046B73 }, - { (char*) "Europe/Uzhgorod" , 0x046E89 }, - { (char*) "Europe/Vaduz" , 0x0470C3 }, - { (char*) "Europe/Vatican" , 0x0472AD }, - { (char*) "Europe/Vienna" , 0x04766C }, - { (char*) "Europe/Vilnius" , 0x04790A }, - { (char*) "Europe/Volgograd" , 0x047BBA }, - { (char*) "Europe/Warsaw" , 0x047EB7 }, - { (char*) "Europe/Zagreb" , 0x04825E }, - { (char*) "Europe/Zaporozhye" , 0x048448 }, - { (char*) "Europe/Zurich" , 0x048682 }, - { (char*) "Factory" , 0x04887F }, - { (char*) "GB" , 0x0488FC }, - { (char*) "GB-Eire" , 0x048F47 }, - { (char*) "GMT" , 0x049592 }, - { (char*) "GMT+0" , 0x04960D }, - { (char*) "GMT-0" , 0x049688 }, - { (char*) "GMT0" , 0x049703 }, - { (char*) "Greenwich" , 0x04977E }, - { (char*) "Hongkong" , 0x0497F9 }, - { (char*) "HST" , 0x049B0C }, - { (char*) "Iceland" , 0x049B88 }, - { (char*) "Indian/Antananarivo" , 0x049C16 }, - { (char*) "Indian/Chagos" , 0x049CC2 }, - { (char*) "Indian/Christmas" , 0x049D66 }, - { (char*) "Indian/Cocos" , 0x049DF7 }, - { (char*) "Indian/Comoro" , 0x049E8F }, - { (char*) "Indian/Kerguelen" , 0x049F1E }, - { (char*) "Indian/Mahe" , 0x049FAF }, - { (char*) "Indian/Maldives" , 0x04A040 }, - { (char*) "Indian/Mauritius" , 0x04A0E4 }, - { (char*) "Indian/Mayotte" , 0x04A1A3 }, - { (char*) "Indian/Reunion" , 0x04A232 }, - { (char*) "Iran" , 0x04A2C3 }, - { (char*) "Israel" , 0x04A5FB }, - { (char*) "Jamaica" , 0x04AA39 }, - { (char*) "Japan" , 0x04AB98 }, - { (char*) "Kwajalein" , 0x04AC79 }, - { (char*) "Libya" , 0x04AD60 }, - { (char*) "MET" , 0x04AF1B }, - { (char*) "Mexico/BajaNorte" , 0x04B194 }, - { (char*) "Mexico/BajaSur" , 0x04B5A1 }, - { (char*) "Mexico/General" , 0x04B87B }, - { (char*) "MST" , 0x04BB8C }, - { (char*) "MST7MDT" , 0x04BC07 }, - { (char*) "Navajo" , 0x04BFCA }, - { (char*) "NZ" , 0x04C3E8 }, - { (char*) "NZ-CHAT" , 0x04C807 }, - { (char*) "Pacific/Apia" , 0x04CB3B }, - { (char*) "Pacific/Auckland" , 0x04CCDE }, - { (char*) "Pacific/Bougainville" , 0x04D115 }, - { (char*) "Pacific/Chatham" , 0x04D1F6 }, - { (char*) "Pacific/Chuuk" , 0x04D539 }, - { (char*) "Pacific/Easter" , 0x04D617 }, - { (char*) "Pacific/Efate" , 0x04DAC6 }, - { (char*) "Pacific/Enderbury" , 0x04DC28 }, - { (char*) "Pacific/Fakaofo" , 0x04DCE0 }, - { (char*) "Pacific/Fiji" , 0x04DD85 }, - { (char*) "Pacific/Funafuti" , 0x04DF1D }, - { (char*) "Pacific/Galapagos" , 0x04DFAF }, - { (char*) "Pacific/Gambier" , 0x04E07B }, - { (char*) "Pacific/Guadalcanal" , 0x04E11A }, - { (char*) "Pacific/Guam" , 0x04E1AC }, - { (char*) "Pacific/Honolulu" , 0x04E316 }, - { (char*) "Pacific/Johnston" , 0x04E405 }, - { (char*) "Pacific/Kanton" , 0x04E4EE }, - { (char*) "Pacific/Kiritimati" , 0x04E5B5 }, - { (char*) "Pacific/Kosrae" , 0x04E67B }, - { (char*) "Pacific/Kwajalein" , 0x04E77F }, - { (char*) "Pacific/Majuro" , 0x04E86F }, - { (char*) "Pacific/Marquesas" , 0x04E972 }, - { (char*) "Pacific/Midway" , 0x04EA1A }, - { (char*) "Pacific/Nauru" , 0x04EADD }, - { (char*) "Pacific/Niue" , 0x04EBA0 }, - { (char*) "Pacific/Norfolk" , 0x04EC46 }, - { (char*) "Pacific/Noumea" , 0x04ED49 }, - { (char*) "Pacific/Pago_Pago" , 0x04EE1B }, - { (char*) "Pacific/Palau" , 0x04EEB9 }, - { (char*) "Pacific/Pitcairn" , 0x04EF59 }, - { (char*) "Pacific/Pohnpei" , 0x04EFFE }, - { (char*) "Pacific/Ponape" , 0x04F0EE }, - { (char*) "Pacific/Port_Moresby" , 0x04F180 }, - { (char*) "Pacific/Rarotonga" , 0x04F243 }, - { (char*) "Pacific/Saipan" , 0x04F3E5 }, - { (char*) "Pacific/Samoa" , 0x04F546 }, - { (char*) "Pacific/Tahiti" , 0x04F5E4 }, - { (char*) "Pacific/Tarawa" , 0x04F684 }, - { (char*) "Pacific/Tongatapu" , 0x04F725 }, - { (char*) "Pacific/Truk" , 0x04F81E }, - { (char*) "Pacific/Wake" , 0x04F8C4 }, - { (char*) "Pacific/Wallis" , 0x04F961 }, - { (char*) "Pacific/Yap" , 0x04F9F3 }, - { (char*) "Poland" , 0x04FA99 }, - { (char*) "Portugal" , 0x04FE40 }, - { (char*) "PRC" , 0x0503FA }, - { (char*) "PST8PDT" , 0x05058F }, - { (char*) "ROC" , 0x050952 }, - { (char*) "ROK" , 0x050B5D }, - { (char*) "Singapore" , 0x050D08 }, - { (char*) "Turkey" , 0x050E14 }, - { (char*) "UCT" , 0x0512D0 }, - { (char*) "Universal" , 0x05134B }, - { (char*) "US/Alaska" , 0x0513C6 }, - { (char*) "US/Aleutian" , 0x0517A3 }, - { (char*) "US/Arizona" , 0x051B78 }, - { (char*) "US/Central" , 0x051C74 }, - { (char*) "US/East-Indiana" , 0x05235A }, - { (char*) "US/Eastern" , 0x052579 }, - { (char*) "US/Hawaii" , 0x052C55 }, - { (char*) "US/Indiana-Starke" , 0x052D3E }, - { (char*) "US/Michigan" , 0x053142 }, - { (char*) "US/Mountain" , 0x0534D1 }, - { (char*) "US/Pacific" , 0x0538EF }, - { (char*) "US/Samoa" , 0x053E09 }, - { (char*) "UTC" , 0x053EA7 }, - { (char*) "W-SU" , 0x053F22 }, - { (char*) "WET" , 0x0542BA }, - { (char*) "Zulu" , 0x0544B4 }, + { (char*) "Africa/Casablanca" , 0x0010E2 }, + { (char*) "Africa/Ceuta" , 0x00186D }, + { (char*) "Africa/Conakry" , 0x001AB9 }, + { (char*) "Africa/Dakar" , 0x001B63 }, + { (char*) "Africa/Dar_es_Salaam" , 0x001C04 }, + { (char*) "Africa/Djibouti" , 0x001CB1 }, + { (char*) "Africa/Douala" , 0x001D40 }, + { (char*) "Africa/El_Aaiun" , 0x001DCF }, + { (char*) "Africa/Freetown" , 0x002501 }, + { (char*) "Africa/Gaborone" , 0x002651 }, + { (char*) "Africa/Harare" , 0x002711 }, + { (char*) "Africa/Johannesburg" , 0x0027A0 }, + { (char*) "Africa/Juba" , 0x00286A }, + { (char*) "Africa/Kampala" , 0x002A40 }, + { (char*) "Africa/Khartoum" , 0x002B02 }, + { (char*) "Africa/Kigali" , 0x002CD8 }, + { (char*) "Africa/Kinshasa" , 0x002D67 }, + { (char*) "Africa/Lagos" , 0x002E0F }, + { (char*) "Africa/Libreville" , 0x002ECF }, + { (char*) "Africa/Lome" , 0x002F5E }, + { (char*) "Africa/Luanda" , 0x002FEC }, + { (char*) "Africa/Lubumbashi" , 0x00308A }, + { (char*) "Africa/Lusaka" , 0x003145 }, + { (char*) "Africa/Malabo" , 0x0031D4 }, + { (char*) "Africa/Maputo" , 0x003276 }, + { (char*) "Africa/Maseru" , 0x003305 }, + { (char*) "Africa/Mbabane" , 0x0033AE }, + { (char*) "Africa/Mogadishu" , 0x00343F }, + { (char*) "Africa/Monrovia" , 0x0034EC }, + { (char*) "Africa/Nairobi" , 0x00359C }, + { (char*) "Africa/Ndjamena" , 0x003667 }, + { (char*) "Africa/Niamey" , 0x003713 }, + { (char*) "Africa/Nouakchott" , 0x0037C8 }, + { (char*) "Africa/Ouagadougou" , 0x003872 }, + { (char*) "Africa/Porto-Novo" , 0x003900 }, + { (char*) "Africa/Sao_Tome" , 0x0039A2 }, + { (char*) "Africa/Timbuktu" , 0x003A5B }, + { (char*) "Africa/Tripoli" , 0x003AE9 }, + { (char*) "Africa/Tunis" , 0x003CA4 }, + { (char*) "Africa/Windhoek" , 0x003E71 }, + { (char*) "America/Adak" , 0x0040FB }, + { (char*) "America/Anchorage" , 0x0044EA }, + { (char*) "America/Anguilla" , 0x0048DA }, + { (char*) "America/Antigua" , 0x004968 }, + { (char*) "America/Araguaina" , 0x004A09 }, + { (char*) "America/Argentina/Buenos_Aires" , 0x004C6E }, + { (char*) "America/Argentina/Catamarca" , 0x004F53 }, + { (char*) "America/Argentina/ComodRivadavia" , 0x00523E }, + { (char*) "America/Argentina/Cordoba" , 0x00550E }, + { (char*) "America/Argentina/Jujuy" , 0x005814 }, + { (char*) "America/Argentina/La_Rioja" , 0x005ADC }, + { (char*) "America/Argentina/Mendoza" , 0x005DC2 }, + { (char*) "America/Argentina/Rio_Gallegos" , 0x00609E }, + { (char*) "America/Argentina/Salta" , 0x00637D }, + { (char*) "America/Argentina/San_Juan" , 0x006651 }, + { (char*) "America/Argentina/San_Luis" , 0x006937 }, + { (char*) "America/Argentina/Tucuman" , 0x006C1D }, + { (char*) "America/Argentina/Ushuaia" , 0x006F0B }, + { (char*) "America/Aruba" , 0x0071F0 }, + { (char*) "America/Asuncion" , 0x007293 }, + { (char*) "America/Atikokan" , 0x007613 }, + { (char*) "America/Atka" , 0x007720 }, + { (char*) "America/Bahia" , 0x007AF5 }, + { (char*) "America/Bahia_Banderas" , 0x007DB0 }, + { (char*) "America/Barbados" , 0x0080A5 }, + { (char*) "America/Belem" , 0x0081C7 }, + { (char*) "America/Belize" , 0x00836F }, + { (char*) "America/Blanc-Sablon" , 0x008790 }, + { (char*) "America/Boa_Vista" , 0x008885 }, + { (char*) "America/Bogota" , 0x008A46 }, + { (char*) "America/Boise" , 0x008B05 }, + { (char*) "America/Buenos_Aires" , 0x008F18 }, + { (char*) "America/Cambridge_Bay" , 0x0091E8 }, + { (char*) "America/Campo_Grande" , 0x00957B }, + { (char*) "America/Cancun" , 0x009951 }, + { (char*) "America/Caracas" , 0x009B7A }, + { (char*) "America/Catamarca" , 0x009C44 }, + { (char*) "America/Cayenne" , 0x009F14 }, + { (char*) "America/Cayman" , 0x009FB7 }, + { (char*) "America/Chicago" , 0x00A058 }, + { (char*) "America/Chihuahua" , 0x00A752 }, + { (char*) "America/Ciudad_Juarez" , 0x00AA27 }, + { (char*) "America/Coral_Harbour" , 0x00AD1D }, + { (char*) "America/Cordoba" , 0x00ADBE }, + { (char*) "America/Costa_Rica" , 0x00B08E }, + { (char*) "America/Creston" , 0x00B182 }, + { (char*) "America/Cuiaba" , 0x00B23E }, + { (char*) "America/Curacao" , 0x00B5FB }, + { (char*) "America/Danmarkshavn" , 0x00B69E }, + { (char*) "America/Dawson" , 0x00B883 }, + { (char*) "America/Dawson_Creek" , 0x00BCA6 }, + { (char*) "America/Denver" , 0x00BF7D }, + { (char*) "America/Detroit" , 0x00C3B0 }, + { (char*) "America/Dominica" , 0x00C758 }, + { (char*) "America/Edmonton" , 0x00C7E6 }, + { (char*) "America/Eirunepe" , 0x00CBE1 }, + { (char*) "America/El_Salvador" , 0x00CDB0 }, + { (char*) "America/Ensenada" , 0x00CE6C }, + { (char*) "America/Fort_Nelson" , 0x00D279 }, + { (char*) "America/Fort_Wayne" , 0x00D841 }, + { (char*) "America/Fortaleza" , 0x00DA60 }, + { (char*) "America/Glace_Bay" , 0x00DC76 }, + { (char*) "America/Godthab" , 0x00E00D }, + { (char*) "America/Goose_Bay" , 0x00E3DE }, + { (char*) "America/Grand_Turk" , 0x00EA36 }, + { (char*) "America/Grenada" , 0x00ED97 }, + { (char*) "America/Guadeloupe" , 0x00EE25 }, + { (char*) "America/Guatemala" , 0x00EEB3 }, + { (char*) "America/Guayaquil" , 0x00EF93 }, + { (char*) "America/Guyana" , 0x00F064 }, + { (char*) "America/Halifax" , 0x00F125 }, + { (char*) "America/Havana" , 0x00F7D7 }, + { (char*) "America/Hermosillo" , 0x00FC40 }, + { (char*) "America/Indiana/Indianapolis" , 0x00FD70 }, + { (char*) "America/Indiana/Knox" , 0x00FFA8 }, + { (char*) "America/Indiana/Marengo" , 0x0103C1 }, + { (char*) "America/Indiana/Petersburg" , 0x01061B }, + { (char*) "America/Indiana/Tell_City" , 0x0108E5 }, + { (char*) "America/Indiana/Vevay" , 0x010B0F }, + { (char*) "America/Indiana/Vincennes" , 0x010CA6 }, + { (char*) "America/Indiana/Winamac" , 0x010EFC }, + { (char*) "America/Indianapolis" , 0x011182 }, + { (char*) "America/Inuvik" , 0x0113A1 }, + { (char*) "America/Iqaluit" , 0x0116F2 }, + { (char*) "America/Jamaica" , 0x011A6E }, + { (char*) "America/Jujuy" , 0x011BCD }, + { (char*) "America/Juneau" , 0x011E8B }, + { (char*) "America/Kentucky/Louisville" , 0x012271 }, + { (char*) "America/Kentucky/Monticello" , 0x012775 }, + { (char*) "America/Knox_IN" , 0x012B61 }, + { (char*) "America/Kralendijk" , 0x012F65 }, + { (char*) "America/La_Paz" , 0x013022 }, + { (char*) "America/Lima" , 0x0130D8 }, + { (char*) "America/Los_Angeles" , 0x0131FF }, + { (char*) "America/Louisville" , 0x013720 }, + { (char*) "America/Lower_Princes" , 0x013C06 }, + { (char*) "America/Maceio" , 0x013CC3 }, + { (char*) "America/Managua" , 0x013ED5 }, + { (char*) "America/Manaus" , 0x014008 }, + { (char*) "America/Marigot" , 0x0141BF }, + { (char*) "America/Martinique" , 0x01427C }, + { (char*) "America/Matamoros" , 0x01433A }, + { (char*) "America/Mazatlan" , 0x014527 }, + { (char*) "America/Mendoza" , 0x014833 }, + { (char*) "America/Menominee" , 0x014B03 }, + { (char*) "America/Merida" , 0x014EC3 }, + { (char*) "America/Metlakatla" , 0x01516E }, + { (char*) "America/Mexico_City" , 0x0153E4 }, + { (char*) "America/Miquelon" , 0x015703 }, + { (char*) "America/Moncton" , 0x015935 }, + { (char*) "America/Monterrey" , 0x015F2E }, + { (char*) "America/Montevideo" , 0x0161F4 }, + { (char*) "America/Montreal" , 0x0165C9 }, + { (char*) "America/Montserrat" , 0x016C8A }, + { (char*) "America/Nassau" , 0x016D18 }, + { (char*) "America/New_York" , 0x017112 }, + { (char*) "America/Nipigon" , 0x017802 }, + { (char*) "America/Nome" , 0x017EC3 }, + { (char*) "America/Noronha" , 0x0182AB }, + { (char*) "America/North_Dakota/Beulah" , 0x0184AB }, + { (char*) "America/North_Dakota/Center" , 0x0188DF }, + { (char*) "America/North_Dakota/New_Salem" , 0x018CDE }, + { (char*) "America/Nuuk" , 0x0190E3 }, + { (char*) "America/Ojinaga" , 0x0194C5 }, + { (char*) "America/Panama" , 0x0197B2 }, + { (char*) "America/Pangnirtung" , 0x019853 }, + { (char*) "America/Paramaribo" , 0x019BB6 }, + { (char*) "America/Phoenix" , 0x019C7D }, + { (char*) "America/Port-au-Prince" , 0x019D91 }, + { (char*) "America/Port_of_Spain" , 0x019FD2 }, + { (char*) "America/Porto_Acre" , 0x01A060 }, + { (char*) "America/Porto_Velho" , 0x01A20E }, + { (char*) "America/Puerto_Rico" , 0x01A3AC }, + { (char*) "America/Punta_Arenas" , 0x01A469 }, + { (char*) "America/Rainy_River" , 0x01A94B }, + { (char*) "America/Rankin_Inlet" , 0x01AE65 }, + { (char*) "America/Recife" , 0x01B1AE }, + { (char*) "America/Regina" , 0x01B3A8 }, + { (char*) "America/Resolute" , 0x01B647 }, + { (char*) "America/Rio_Branco" , 0x01B991 }, + { (char*) "America/Rosario" , 0x01BB43 }, + { (char*) "America/Santa_Isabel" , 0x01BE13 }, + { (char*) "America/Santarem" , 0x01C220 }, + { (char*) "America/Santiago" , 0x01C3D0 }, + { (char*) "America/Santo_Domingo" , 0x01C933 }, + { (char*) "America/Sao_Paulo" , 0x01CA7C }, + { (char*) "America/Scoresbysund" , 0x01CE76 }, + { (char*) "America/Shiprock" , 0x01D07E }, + { (char*) "America/Sitka" , 0x01D49C }, + { (char*) "America/St_Barthelemy" , 0x01D877 }, + { (char*) "America/St_Johns" , 0x01D934 }, + { (char*) "America/St_Kitts" , 0x01E0B8 }, + { (char*) "America/St_Lucia" , 0x01E146 }, + { (char*) "America/St_Thomas" , 0x01E1E7 }, + { (char*) "America/St_Vincent" , 0x01E275 }, + { (char*) "America/Swift_Current" , 0x01E316 }, + { (char*) "America/Tegucigalpa" , 0x01E4A4 }, + { (char*) "America/Thule" , 0x01E572 }, + { (char*) "America/Thunder_Bay" , 0x01E753 }, + { (char*) "America/Tijuana" , 0x01EE14 }, + { (char*) "America/Toronto" , 0x01F230 }, + { (char*) "America/Tortola" , 0x01F90E }, + { (char*) "America/Vancouver" , 0x01F99C }, + { (char*) "America/Virgin" , 0x01FEF3 }, + { (char*) "America/Whitehorse" , 0x01FFB0 }, + { (char*) "America/Winnipeg" , 0x0203D3 }, + { (char*) "America/Yakutat" , 0x02090A }, + { (char*) "America/Yellowknife" , 0x020CD8 }, + { (char*) "Antarctica/Casey" , 0x0210AE }, + { (char*) "Antarctica/Davis" , 0x0211B2 }, + { (char*) "Antarctica/DumontDUrville" , 0x021288 }, + { (char*) "Antarctica/Macquarie" , 0x02133C }, + { (char*) "Antarctica/Mawson" , 0x021728 }, + { (char*) "Antarctica/McMurdo" , 0x0217D2 }, + { (char*) "Antarctica/Palmer" , 0x021B04 }, + { (char*) "Antarctica/Rothera" , 0x021E8D }, + { (char*) "Antarctica/South_Pole" , 0x021F24 }, + { (char*) "Antarctica/Syowa" , 0x022343 }, + { (char*) "Antarctica/Troll" , 0x0223D9 }, + { (char*) "Antarctica/Vostok" , 0x02249B }, + { (char*) "Arctic/Longyearbyen" , 0x022532 }, + { (char*) "Asia/Aden" , 0x0227FF }, + { (char*) "Asia/Almaty" , 0x022890 }, + { (char*) "Asia/Amman" , 0x022B0F }, + { (char*) "Asia/Anadyr" , 0x022EBB }, + { (char*) "Asia/Aqtau" , 0x0231C1 }, + { (char*) "Asia/Aqtobe" , 0x023440 }, + { (char*) "Asia/Ashgabat" , 0x0236C0 }, + { (char*) "Asia/Ashkhabad" , 0x023843 }, + { (char*) "Asia/Atyrau" , 0x0239C6 }, + { (char*) "Asia/Baghdad" , 0x023C4F }, + { (char*) "Asia/Bahrain" , 0x023ED1 }, + { (char*) "Asia/Baku" , 0x023F8A }, + { (char*) "Asia/Bangkok" , 0x02427E }, + { (char*) "Asia/Barnaul" , 0x024322 }, + { (char*) "Asia/Beirut" , 0x02462D }, + { (char*) "Asia/Bishkek" , 0x024915 }, + { (char*) "Asia/Brunei" , 0x024B8B }, + { (char*) "Asia/Calcutta" , 0x024C31 }, + { (char*) "Asia/Chita" , 0x024D19 }, + { (char*) "Asia/Choibalsan" , 0x025027 }, + { (char*) "Asia/Chongqing" , 0x0252B0 }, + { (char*) "Asia/Chungking" , 0x025445 }, + { (char*) "Asia/Colombo" , 0x0255DA }, + { (char*) "Asia/Dacca" , 0x0256DD }, + { (char*) "Asia/Damascus" , 0x0257D0 }, + { (char*) "Asia/Dhaka" , 0x025CAE }, + { (char*) "Asia/Dili" , 0x025DA1 }, + { (char*) "Asia/Dubai" , 0x025E57 }, + { (char*) "Asia/Dushanbe" , 0x025EE8 }, + { (char*) "Asia/Famagusta" , 0x026062 }, + { (char*) "Asia/Gaza" , 0x026429 }, + { (char*) "Asia/Harbin" , 0x026E15 }, + { (char*) "Asia/Hebron" , 0x026FAA }, + { (char*) "Asia/Ho_Chi_Minh" , 0x0279A7 }, + { (char*) "Asia/Hong_Kong" , 0x027A9F }, + { (char*) "Asia/Hovd" , 0x027DB2 }, + { (char*) "Asia/Irkutsk" , 0x02803B }, + { (char*) "Asia/Istanbul" , 0x028359 }, + { (char*) "Asia/Jakarta" , 0x028815 }, + { (char*) "Asia/Jayapura" , 0x028926 }, + { (char*) "Asia/Jerusalem" , 0x028A13 }, + { (char*) "Asia/Kabul" , 0x028E51 }, + { (char*) "Asia/Kamchatka" , 0x028EFC }, + { (char*) "Asia/Karachi" , 0x0291F1 }, + { (char*) "Asia/Kashgar" , 0x029307 }, + { (char*) "Asia/Kathmandu" , 0x029398 }, + { (char*) "Asia/Katmandu" , 0x029445 }, + { (char*) "Asia/Khandyga" , 0x0294F2 }, + { (char*) "Asia/Kolkata" , 0x029823 }, + { (char*) "Asia/Krasnoyarsk" , 0x02990B }, + { (char*) "Asia/Kuala_Lumpur" , 0x029C15 }, + { (char*) "Asia/Kuching" , 0x029D35 }, + { (char*) "Asia/Kuwait" , 0x029E8F }, + { (char*) "Asia/Macao" , 0x029F20 }, + { (char*) "Asia/Macau" , 0x02A243 }, + { (char*) "Asia/Magadan" , 0x02A566 }, + { (char*) "Asia/Makassar" , 0x02A871 }, + { (char*) "Asia/Manila" , 0x02A984 }, + { (char*) "Asia/Muscat" , 0x02AA7E }, + { (char*) "Asia/Nicosia" , 0x02AB0F }, + { (char*) "Asia/Novokuznetsk" , 0x02AD7E }, + { (char*) "Asia/Novosibirsk" , 0x02B071 }, + { (char*) "Asia/Omsk" , 0x02B382 }, + { (char*) "Asia/Oral" , 0x02B680 }, + { (char*) "Asia/Phnom_Penh" , 0x02B90C }, + { (char*) "Asia/Pontianak" , 0x02B9E0 }, + { (char*) "Asia/Pyongyang" , 0x02BAF9 }, + { (char*) "Asia/Qatar" , 0x02BBBC }, + { (char*) "Asia/Qostanay" , 0x02BC60 }, + { (char*) "Asia/Qyzylorda" , 0x02BEED }, + { (char*) "Asia/Rangoon" , 0x02C186 }, + { (char*) "Asia/Riyadh" , 0x02C24D }, + { (char*) "Asia/Saigon" , 0x02C2DE }, + { (char*) "Asia/Sakhalin" , 0x02C3D6 }, + { (char*) "Asia/Samarkand" , 0x02C6ED }, + { (char*) "Asia/Seoul" , 0x02C878 }, + { (char*) "Asia/Shanghai" , 0x02CA23 }, + { (char*) "Asia/Singapore" , 0x02CBC4 }, + { (char*) "Asia/Srednekolymsk" , 0x02CCD0 }, + { (char*) "Asia/Taipei" , 0x02CFE0 }, + { (char*) "Asia/Tashkent" , 0x02D1EB }, + { (char*) "Asia/Tbilisi" , 0x02D376 }, + { (char*) "Asia/Tehran" , 0x02D5F7 }, + { (char*) "Asia/Tel_Aviv" , 0x02D92F }, + { (char*) "Asia/Thimbu" , 0x02DD6D }, + { (char*) "Asia/Thimphu" , 0x02DE13 }, + { (char*) "Asia/Tokyo" , 0x02DEB9 }, + { (char*) "Asia/Tomsk" , 0x02DF9A }, + { (char*) "Asia/Ujung_Pandang" , 0x02E2A5 }, + { (char*) "Asia/Ulaanbaatar" , 0x02E36F }, + { (char*) "Asia/Ulan_Bator" , 0x02E5DD }, + { (char*) "Asia/Urumqi" , 0x02E83B }, + { (char*) "Asia/Ust-Nera" , 0x02E8D9 }, + { (char*) "Asia/Vientiane" , 0x02EBFC }, + { (char*) "Asia/Vladivostok" , 0x02ECE2 }, + { (char*) "Asia/Yakutsk" , 0x02EFE7 }, + { (char*) "Asia/Yangon" , 0x02F2EB }, + { (char*) "Asia/Yekaterinburg" , 0x02F3B2 }, + { (char*) "Asia/Yerevan" , 0x02F6C4 }, + { (char*) "Atlantic/Azores" , 0x02F994 }, + { (char*) "Atlantic/Bermuda" , 0x02FF53 }, + { (char*) "Atlantic/Canary" , 0x03035F }, + { (char*) "Atlantic/Cape_Verde" , 0x030557 }, + { (char*) "Atlantic/Faeroe" , 0x030612 }, + { (char*) "Atlantic/Faroe" , 0x0307D7 }, + { (char*) "Atlantic/Jan_Mayen" , 0x03099C }, + { (char*) "Atlantic/Madeira" , 0x030C69 }, + { (char*) "Atlantic/Reykjavik" , 0x031231 }, + { (char*) "Atlantic/South_Georgia" , 0x03152E }, + { (char*) "Atlantic/St_Helena" , 0x0315BE }, + { (char*) "Atlantic/Stanley" , 0x03165F }, + { (char*) "Australia/ACT" , 0x031980 }, + { (char*) "Australia/Adelaide" , 0x031D14 }, + { (char*) "Australia/Brisbane" , 0x0320C8 }, + { (char*) "Australia/Broken_Hill" , 0x03220C }, + { (char*) "Australia/Canberra" , 0x0325E1 }, + { (char*) "Australia/Currie" , 0x032975 }, + { (char*) "Australia/Darwin" , 0x032D6C }, + { (char*) "Australia/Eucla" , 0x032E74 }, + { (char*) "Australia/Hobart" , 0x032FD3 }, + { (char*) "Australia/LHI" , 0x0333D2 }, + { (char*) "Australia/Lindeman" , 0x033692 }, + { (char*) "Australia/Lord_Howe" , 0x033802 }, + { (char*) "Australia/Melbourne" , 0x033AD2 }, + { (char*) "Australia/North" , 0x033E6E }, + { (char*) "Australia/NSW" , 0x033F64 }, + { (char*) "Australia/Perth" , 0x0342F8 }, + { (char*) "Australia/Queensland" , 0x034454 }, + { (char*) "Australia/South" , 0x034581 }, + { (char*) "Australia/Sydney" , 0x034926 }, + { (char*) "Australia/Tasmania" , 0x034CD6 }, + { (char*) "Australia/Victoria" , 0x0350CD }, + { (char*) "Australia/West" , 0x035461 }, + { (char*) "Australia/Yancowinna" , 0x03559F }, + { (char*) "Brazil/Acre" , 0x035958 }, + { (char*) "Brazil/DeNoronha" , 0x035B06 }, + { (char*) "Brazil/East" , 0x035CF6 }, + { (char*) "Brazil/West" , 0x0360BA }, + { (char*) "Canada/Atlantic" , 0x036262 }, + { (char*) "Canada/Central" , 0x0368F6 }, + { (char*) "Canada/Eastern" , 0x036E10 }, + { (char*) "Canada/Mountain" , 0x0374D1 }, + { (char*) "Canada/Newfoundland" , 0x0378A7 }, + { (char*) "Canada/Pacific" , 0x038009 }, + { (char*) "Canada/Saskatchewan" , 0x038547 }, + { (char*) "Canada/Yukon" , 0x0387D1 }, + { (char*) "CET" , 0x038BE2 }, + { (char*) "Chile/Continental" , 0x038E5B }, + { (char*) "Chile/EasterIsland" , 0x0393B1 }, + { (char*) "CST6CDT" , 0x039853 }, + { (char*) "Cuba" , 0x039C16 }, + { (char*) "EET" , 0x03A07F }, + { (char*) "Egypt" , 0x03A27C }, + { (char*) "Eire" , 0x03A7A5 }, + { (char*) "EST" , 0x03AD89 }, + { (char*) "EST5EDT" , 0x03AE04 }, + { (char*) "Etc/GMT" , 0x03B1C7 }, + { (char*) "Etc/GMT+0" , 0x03B242 }, + { (char*) "Etc/GMT+1" , 0x03B2BD }, + { (char*) "Etc/GMT+10" , 0x03B33A }, + { (char*) "Etc/GMT+11" , 0x03B3B8 }, + { (char*) "Etc/GMT+12" , 0x03B436 }, + { (char*) "Etc/GMT+2" , 0x03B4B4 }, + { (char*) "Etc/GMT+3" , 0x03B531 }, + { (char*) "Etc/GMT+4" , 0x03B5AE }, + { (char*) "Etc/GMT+5" , 0x03B62B }, + { (char*) "Etc/GMT+6" , 0x03B6A8 }, + { (char*) "Etc/GMT+7" , 0x03B725 }, + { (char*) "Etc/GMT+8" , 0x03B7A2 }, + { (char*) "Etc/GMT+9" , 0x03B81F }, + { (char*) "Etc/GMT-0" , 0x03B89C }, + { (char*) "Etc/GMT-1" , 0x03B917 }, + { (char*) "Etc/GMT-10" , 0x03B995 }, + { (char*) "Etc/GMT-11" , 0x03BA14 }, + { (char*) "Etc/GMT-12" , 0x03BA93 }, + { (char*) "Etc/GMT-13" , 0x03BB12 }, + { (char*) "Etc/GMT-14" , 0x03BB91 }, + { (char*) "Etc/GMT-2" , 0x03BC10 }, + { (char*) "Etc/GMT-3" , 0x03BC8E }, + { (char*) "Etc/GMT-4" , 0x03BD0C }, + { (char*) "Etc/GMT-5" , 0x03BD8A }, + { (char*) "Etc/GMT-6" , 0x03BE08 }, + { (char*) "Etc/GMT-7" , 0x03BE86 }, + { (char*) "Etc/GMT-8" , 0x03BF04 }, + { (char*) "Etc/GMT-9" , 0x03BF82 }, + { (char*) "Etc/GMT0" , 0x03C000 }, + { (char*) "Etc/Greenwich" , 0x03C07B }, + { (char*) "Etc/UCT" , 0x03C0F6 }, + { (char*) "Etc/Universal" , 0x03C171 }, + { (char*) "Etc/UTC" , 0x03C1EC }, + { (char*) "Etc/Zulu" , 0x03C267 }, + { (char*) "Europe/Amsterdam" , 0x03C2E2 }, + { (char*) "Europe/Andorra" , 0x03C71D }, + { (char*) "Europe/Astrakhan" , 0x03C8AE }, + { (char*) "Europe/Athens" , 0x03CBA2 }, + { (char*) "Europe/Belfast" , 0x03CE58 }, + { (char*) "Europe/Belgrade" , 0x03D4A3 }, + { (char*) "Europe/Berlin" , 0x03D68D }, + { (char*) "Europe/Bratislava" , 0x03D969 }, + { (char*) "Europe/Brussels" , 0x03DC48 }, + { (char*) "Europe/Bucharest" , 0x03E0A3 }, + { (char*) "Europe/Budapest" , 0x03E344 }, + { (char*) "Europe/Busingen" , 0x03E64E }, + { (char*) "Europe/Chisinau" , 0x03E853 }, + { (char*) "Europe/Copenhagen" , 0x03EB52 }, + { (char*) "Europe/Dublin" , 0x03EDCD }, + { (char*) "Europe/Gibraltar" , 0x03F3B1 }, + { (char*) "Europe/Guernsey" , 0x03F881 }, + { (char*) "Europe/Helsinki" , 0x03FED8 }, + { (char*) "Europe/Isle_of_Man" , 0x0400C5 }, + { (char*) "Europe/Istanbul" , 0x040710 }, + { (char*) "Europe/Jersey" , 0x040BCC }, + { (char*) "Europe/Kaliningrad" , 0x041223 }, + { (char*) "Europe/Kiev" , 0x0415CB }, + { (char*) "Europe/Kirov" , 0x041805 }, + { (char*) "Europe/Kyiv" , 0x041AFE }, + { (char*) "Europe/Lisbon" , 0x041D47 }, + { (char*) "Europe/Ljubljana" , 0x042314 }, + { (char*) "Europe/London" , 0x0424FE }, + { (char*) "Europe/Luxembourg" , 0x042B49 }, + { (char*) "Europe/Madrid" , 0x042F94 }, + { (char*) "Europe/Malta" , 0x043331 }, + { (char*) "Europe/Mariehamn" , 0x0436DD }, + { (char*) "Europe/Minsk" , 0x0438CA }, + { (char*) "Europe/Monaco" , 0x043BFE }, + { (char*) "Europe/Moscow" , 0x044064 }, + { (char*) "Europe/Nicosia" , 0x044410 }, + { (char*) "Europe/Oslo" , 0x044671 }, + { (char*) "Europe/Paris" , 0x044921 }, + { (char*) "Europe/Podgorica" , 0x044D7E }, + { (char*) "Europe/Prague" , 0x044F68 }, + { (char*) "Europe/Riga" , 0x045247 }, + { (char*) "Europe/Rome" , 0x045509 }, + { (char*) "Europe/Samara" , 0x0458C8 }, + { (char*) "Europe/San_Marino" , 0x045BC9 }, + { (char*) "Europe/Sarajevo" , 0x045F88 }, + { (char*) "Europe/Saratov" , 0x046172 }, + { (char*) "Europe/Simferopol" , 0x046464 }, + { (char*) "Europe/Skopje" , 0x0467D7 }, + { (char*) "Europe/Sofia" , 0x0469C1 }, + { (char*) "Europe/Stockholm" , 0x046C1D }, + { (char*) "Europe/Tallinn" , 0x046E1A }, + { (char*) "Europe/Tirane" , 0x0470C9 }, + { (char*) "Europe/Tiraspol" , 0x047331 }, + { (char*) "Europe/Ulyanovsk" , 0x047630 }, + { (char*) "Europe/Uzhgorod" , 0x047946 }, + { (char*) "Europe/Vaduz" , 0x047B80 }, + { (char*) "Europe/Vatican" , 0x047D6A }, + { (char*) "Europe/Vienna" , 0x048129 }, + { (char*) "Europe/Vilnius" , 0x0483C7 }, + { (char*) "Europe/Volgograd" , 0x048677 }, + { (char*) "Europe/Warsaw" , 0x048986 }, + { (char*) "Europe/Zagreb" , 0x048D2D }, + { (char*) "Europe/Zaporozhye" , 0x048F17 }, + { (char*) "Europe/Zurich" , 0x049151 }, + { (char*) "Factory" , 0x04934E }, + { (char*) "GB" , 0x0493CB }, + { (char*) "GB-Eire" , 0x049A16 }, + { (char*) "GMT" , 0x04A061 }, + { (char*) "GMT+0" , 0x04A0DC }, + { (char*) "GMT-0" , 0x04A157 }, + { (char*) "GMT0" , 0x04A1D2 }, + { (char*) "Greenwich" , 0x04A24D }, + { (char*) "Hongkong" , 0x04A2C8 }, + { (char*) "HST" , 0x04A5DB }, + { (char*) "Iceland" , 0x04A657 }, + { (char*) "Indian/Antananarivo" , 0x04A6E5 }, + { (char*) "Indian/Chagos" , 0x04A791 }, + { (char*) "Indian/Christmas" , 0x04A835 }, + { (char*) "Indian/Cocos" , 0x04A8C6 }, + { (char*) "Indian/Comoro" , 0x04A95E }, + { (char*) "Indian/Kerguelen" , 0x04A9ED }, + { (char*) "Indian/Mahe" , 0x04AA7E }, + { (char*) "Indian/Maldives" , 0x04AB0F }, + { (char*) "Indian/Mauritius" , 0x04ABB3 }, + { (char*) "Indian/Mayotte" , 0x04AC72 }, + { (char*) "Indian/Reunion" , 0x04AD01 }, + { (char*) "Iran" , 0x04AD92 }, + { (char*) "Israel" , 0x04B0CA }, + { (char*) "Jamaica" , 0x04B508 }, + { (char*) "Japan" , 0x04B667 }, + { (char*) "Kwajalein" , 0x04B748 }, + { (char*) "Libya" , 0x04B82F }, + { (char*) "MET" , 0x04B9EA }, + { (char*) "Mexico/BajaNorte" , 0x04BC63 }, + { (char*) "Mexico/BajaSur" , 0x04C070 }, + { (char*) "Mexico/General" , 0x04C34A }, + { (char*) "MST" , 0x04C65B }, + { (char*) "MST7MDT" , 0x04C6D6 }, + { (char*) "Navajo" , 0x04CA99 }, + { (char*) "NZ" , 0x04CEB7 }, + { (char*) "NZ-CHAT" , 0x04D2D6 }, + { (char*) "Pacific/Apia" , 0x04D60A }, + { (char*) "Pacific/Auckland" , 0x04D7AD }, + { (char*) "Pacific/Bougainville" , 0x04DBDF }, + { (char*) "Pacific/Chatham" , 0x04DCC0 }, + { (char*) "Pacific/Chuuk" , 0x04E003 }, + { (char*) "Pacific/Easter" , 0x04E0E1 }, + { (char*) "Pacific/Efate" , 0x04E590 }, + { (char*) "Pacific/Enderbury" , 0x04E6F2 }, + { (char*) "Pacific/Fakaofo" , 0x04E7AA }, + { (char*) "Pacific/Fiji" , 0x04E84F }, + { (char*) "Pacific/Funafuti" , 0x04E9E7 }, + { (char*) "Pacific/Galapagos" , 0x04EA79 }, + { (char*) "Pacific/Gambier" , 0x04EB45 }, + { (char*) "Pacific/Guadalcanal" , 0x04EBE4 }, + { (char*) "Pacific/Guam" , 0x04EC76 }, + { (char*) "Pacific/Honolulu" , 0x04EDE0 }, + { (char*) "Pacific/Johnston" , 0x04EECF }, + { (char*) "Pacific/Kanton" , 0x04EFB8 }, + { (char*) "Pacific/Kiritimati" , 0x04F07F }, + { (char*) "Pacific/Kosrae" , 0x04F145 }, + { (char*) "Pacific/Kwajalein" , 0x04F249 }, + { (char*) "Pacific/Majuro" , 0x04F339 }, + { (char*) "Pacific/Marquesas" , 0x04F437 }, + { (char*) "Pacific/Midway" , 0x04F4DF }, + { (char*) "Pacific/Nauru" , 0x04F5A2 }, + { (char*) "Pacific/Niue" , 0x04F665 }, + { (char*) "Pacific/Norfolk" , 0x04F70B }, + { (char*) "Pacific/Noumea" , 0x04F80E }, + { (char*) "Pacific/Pago_Pago" , 0x04F8E0 }, + { (char*) "Pacific/Palau" , 0x04F97E }, + { (char*) "Pacific/Pitcairn" , 0x04FA1E }, + { (char*) "Pacific/Pohnpei" , 0x04FAC3 }, + { (char*) "Pacific/Ponape" , 0x04FBB3 }, + { (char*) "Pacific/Port_Moresby" , 0x04FC45 }, + { (char*) "Pacific/Rarotonga" , 0x04FD03 }, + { (char*) "Pacific/Saipan" , 0x04FEA5 }, + { (char*) "Pacific/Samoa" , 0x050006 }, + { (char*) "Pacific/Tahiti" , 0x0500A4 }, + { (char*) "Pacific/Tarawa" , 0x050144 }, + { (char*) "Pacific/Tongatapu" , 0x0501E5 }, + { (char*) "Pacific/Truk" , 0x0502DE }, + { (char*) "Pacific/Wake" , 0x050384 }, + { (char*) "Pacific/Wallis" , 0x050421 }, + { (char*) "Pacific/Yap" , 0x0504B3 }, + { (char*) "Poland" , 0x050559 }, + { (char*) "Portugal" , 0x050900 }, + { (char*) "PRC" , 0x050EBA }, + { (char*) "PST8PDT" , 0x05104F }, + { (char*) "ROC" , 0x051412 }, + { (char*) "ROK" , 0x05161D }, + { (char*) "Singapore" , 0x0517C8 }, + { (char*) "Turkey" , 0x0518D4 }, + { (char*) "UCT" , 0x051D90 }, + { (char*) "Universal" , 0x051E0B }, + { (char*) "US/Alaska" , 0x051E86 }, + { (char*) "US/Aleutian" , 0x052263 }, + { (char*) "US/Arizona" , 0x052638 }, + { (char*) "US/Central" , 0x052734 }, + { (char*) "US/East-Indiana" , 0x052E1A }, + { (char*) "US/Eastern" , 0x053039 }, + { (char*) "US/Hawaii" , 0x053715 }, + { (char*) "US/Indiana-Starke" , 0x0537FE }, + { (char*) "US/Michigan" , 0x053C02 }, + { (char*) "US/Mountain" , 0x053F91 }, + { (char*) "US/Pacific" , 0x0543AF }, + { (char*) "US/Samoa" , 0x0548C9 }, + { (char*) "UTC" , 0x054967 }, + { (char*) "W-SU" , 0x0549E2 }, + { (char*) "WET" , 0x054D7A }, + { (char*) "Zulu" , 0x054F74 }, }; -const unsigned char timelib_timezone_db_data_builtin[345391] = { +const unsigned char timelib_timezone_db_data_builtin[348143] = { /* Africa/Abidjan */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -833,7 +833,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0xBD, 0x4D, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x93, 0xB4, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0xFA, 0x7B, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0xFC, 0xEF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA, 0xC7, 0xE8, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0xCB, 0xAE, 0x60, 0xFF, @@ -897,7 +897,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x4C, 0x61, 0xBD, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x89, 0x58, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xA4, 0xFA, 0x50, 0x00, 0x00, 0x00, 0x00, 0x53, 0x75, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xAC, 0x89, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xDA, 0xBC, 0x60, 0x00, -0x00, 0x00, 0x00, 0x54, 0x24, 0x82, 0x50, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x00, 0x00, 0x00, 0x54, 0x24, 0x82, 0x50, 0x00, 0x00, 0x00, 0x00, 0x64, 0x4A, 0xF0, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, @@ -905,10 +905,12 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, -0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x1D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, -0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, -0x00, 0x45, 0x45, 0x54, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x0A, 0x00, 0xB7, 0x2E, 0x88, -0x01, 0x42, 0x57, 0x88, 0x00, 0x00, 0x00, 0x00, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x00, +0x00, 0x1D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, +0x09, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x0A, 0x45, +0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x34, 0x2E, 0x35, 0x2E, 0x35, 0x2F, +0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x34, 0x2F, 0x32, 0x34, 0x0A, 0x00, 0xB7, 0x2E, +0x88, 0x01, 0x42, 0x57, 0x88, 0x00, 0x00, 0x00, 0x00, /* Africa/Casablanca */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x4D, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -949,7 +951,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x5E, 0xD3, 0x0F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x60, 0x72, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0xA0, 0x7C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xC5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x62, 0x77, 0x24, 0x20, 0x00, 0x00, 0x00, 0x00, 0x64, 0x16, 0x6C, 0xA0, 0x00, -0x00, 0x00, 0x00, 0x64, 0x4D, 0xCB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x65, 0xED, 0x14, 0x20, 0x00, +0x00, 0x00, 0x00, 0x64, 0x44, 0x91, 0x20, 0x00, 0x00, 0x00, 0x00, 0x65, 0xED, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, 0x66, 0x1B, 0x38, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x67, 0xBA, 0x81, 0x20, 0x00, 0x00, 0x00, 0x00, 0x67, 0xF1, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x69, 0x91, 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x69, 0xBF, 0x4D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x67, 0xD0, 0x20, 0x00, @@ -957,7 +959,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x6D, 0x6C, 0x9C, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x0B, 0xE4, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x3A, 0x09, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD9, 0x51, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x71, 0x10, 0xB0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x72, 0xAF, 0xF9, 0x20, 0x00, -0x00, 0x00, 0x00, 0x72, 0xE7, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x74, 0x86, 0xA0, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x72, 0xDE, 0x1D, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x86, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x74, 0xB4, 0xC5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x76, 0x54, 0x0D, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x8B, 0x6C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x2A, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x78, 0x58, 0xD9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x79, 0xF8, 0x22, 0x20, 0x00, @@ -965,7 +967,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x7C, 0x06, 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xA5, 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xD3, 0x95, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x72, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xAA, 0x3D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x81, 0x49, 0x85, 0xA0, 0x00, -0x00, 0x00, 0x00, 0x81, 0x80, 0xE4, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x83, 0x20, 0x2D, 0x20, 0x00, +0x00, 0x00, 0x00, 0x81, 0x77, 0xAA, 0x20, 0x00, 0x00, 0x00, 0x00, 0x83, 0x20, 0x2D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x83, 0x4E, 0x51, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x84, 0xED, 0x9A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x85, 0x24, 0xF9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x86, 0xC4, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x86, 0xF2, 0x66, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x91, 0xAE, 0xA0, 0x00, @@ -973,7 +975,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x8A, 0x9F, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x3E, 0xFD, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x6D, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x0C, 0x6A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x43, 0xC9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8F, 0xE3, 0x12, 0x20, 0x00, -0x00, 0x00, 0x00, 0x90, 0x1A, 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB9, 0xB9, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x90, 0x11, 0x36, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB9, 0xB9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xE7, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x93, 0x87, 0x26, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x93, 0xBE, 0x85, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5D, 0xCE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x95, 0x8B, 0xF2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x97, 0x2B, 0x3B, 0x20, 0x00, @@ -981,7 +983,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x99, 0x39, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD8, 0x8A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x06, 0xAE, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xA5, 0xF7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xDD, 0x56, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x7C, 0x9E, 0xA0, 0x00, -0x00, 0x00, 0x00, 0x9E, 0xB3, 0xFD, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x53, 0x46, 0x20, 0x00, +0x00, 0x00, 0x00, 0x9E, 0xAA, 0xC3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x53, 0x46, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x81, 0x6A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x20, 0xB3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x58, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA3, 0xF7, 0x5A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x25, 0x7F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA5, 0xC4, 0xC7, 0xA0, 0x00, @@ -989,7 +991,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0xA7, 0xD2, 0xCE, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x72, 0x16, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA9, 0xA0, 0x3B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x3F, 0x83, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x76, 0xE2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x16, 0x2B, 0x20, 0x00, -0x00, 0x00, 0x00, 0xAD, 0x4D, 0x8A, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAE, 0xEC, 0xD2, 0xA0, 0x00, +0x00, 0x00, 0x00, 0xAD, 0x44, 0x4F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAE, 0xEC, 0xD2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x1A, 0xF7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xBA, 0x3F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xF1, 0x9E, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x90, 0xE7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB2, 0xBF, 0x0B, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x5E, 0x54, 0x20, 0x00, @@ -997,7 +999,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0xB6, 0x6C, 0x5A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x0B, 0xA3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x39, 0xC7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xD9, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x10, 0x6F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xAF, 0xB7, 0xA0, 0x00, -0x00, 0x00, 0x00, 0xBB, 0xE7, 0x16, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x86, 0x5F, 0x20, 0x00, +0x00, 0x00, 0x00, 0xBB, 0xDD, 0xDC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x86, 0x5F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBD, 0xB4, 0x83, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x53, 0xCC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x8B, 0x2B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x2A, 0x73, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x58, 0x98, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xF7, 0xE0, 0xA0, 0x00, @@ -1005,15 +1007,15 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0xC5, 0x05, 0xE7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xA5, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xD3, 0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x72, 0x9C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xA9, 0xFB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x49, 0x44, 0x20, 0x00, -0x00, 0x00, 0x00, 0xCA, 0x80, 0xA3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1F, 0xEB, 0xA0, 0x00, +0x00, 0x00, 0x00, 0xCA, 0x77, 0x68, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1F, 0xEB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x4E, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xED, 0x58, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x24, 0xB7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xC4, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xF2, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x91, 0x6D, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xC8, 0xCC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x68, 0x14, 0xA0, 0x00, -0x00, 0x00, 0x00, 0xD3, 0x9F, 0x73, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x3E, 0xBC, 0x20, 0x00, +0x00, 0x00, 0x00, 0xD3, 0x96, 0x39, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x3E, 0xBC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x6C, 0xE0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x0C, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x43, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xE2, 0xD0, 0xA0, 0x00, -0x00, 0x00, 0x00, 0xD9, 0x1A, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB9, 0x78, 0x20, 0x00, +0x00, 0x00, 0x00, 0xD9, 0x10, 0xF5, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB9, 0x78, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xE7, 0x9C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x86, 0xE5, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xBE, 0x44, 0x20, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, @@ -1166,7 +1168,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x5E, 0x9B, 0xB0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x5E, 0xD3, 0x0F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x60, 0x72, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0xA0, 0x7C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xC5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x62, 0x77, 0x24, 0x20, 0x00, -0x00, 0x00, 0x00, 0x64, 0x16, 0x6C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x64, 0x4D, 0xCB, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x64, 0x16, 0x6C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x64, 0x44, 0x91, 0x20, 0x00, 0x00, 0x00, 0x00, 0x65, 0xED, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, 0x66, 0x1B, 0x38, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x67, 0xBA, 0x81, 0x20, 0x00, 0x00, 0x00, 0x00, 0x67, 0xF1, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x69, 0x91, 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x69, 0xBF, 0x4D, 0x20, 0x00, @@ -1174,7 +1176,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x6D, 0x35, 0x3D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x6C, 0x9C, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x0B, 0xE4, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x3A, 0x09, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD9, 0x51, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x71, 0x10, 0xB0, 0xA0, 0x00, -0x00, 0x00, 0x00, 0x72, 0xAF, 0xF9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0xE7, 0x58, 0x20, 0x00, +0x00, 0x00, 0x00, 0x72, 0xAF, 0xF9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0xDE, 0x1D, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x86, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x74, 0xB4, 0xC5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x76, 0x54, 0x0D, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x8B, 0x6C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x2A, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x78, 0x58, 0xD9, 0xA0, 0x00, @@ -1182,7 +1184,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x7B, 0xCE, 0xC9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x06, 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xA5, 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xD3, 0x95, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x72, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xAA, 0x3D, 0x20, 0x00, -0x00, 0x00, 0x00, 0x81, 0x49, 0x85, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x81, 0x80, 0xE4, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x81, 0x49, 0x85, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x81, 0x77, 0xAA, 0x20, 0x00, 0x00, 0x00, 0x00, 0x83, 0x20, 0x2D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x83, 0x4E, 0x51, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x84, 0xED, 0x9A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x85, 0x24, 0xF9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x86, 0xC4, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x86, 0xF2, 0x66, 0x20, 0x00, @@ -1190,7 +1192,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x8A, 0x68, 0x56, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x9F, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x3E, 0xFD, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x6D, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x0C, 0x6A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x43, 0xC9, 0xA0, 0x00, -0x00, 0x00, 0x00, 0x8F, 0xE3, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1A, 0x71, 0x20, 0x00, +0x00, 0x00, 0x00, 0x8F, 0xE3, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x90, 0x11, 0x36, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB9, 0xB9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xE7, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x93, 0x87, 0x26, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x93, 0xBE, 0x85, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5D, 0xCE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x95, 0x8B, 0xF2, 0xA0, 0x00, @@ -1198,7 +1200,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x99, 0x01, 0xE2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x99, 0x39, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD8, 0x8A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x06, 0xAE, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xA5, 0xF7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xDD, 0x56, 0x20, 0x00, -0x00, 0x00, 0x00, 0x9E, 0x7C, 0x9E, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xB3, 0xFD, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x9E, 0x7C, 0x9E, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xAA, 0xC3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x53, 0x46, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x81, 0x6A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x20, 0xB3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x58, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA3, 0xF7, 0x5A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x25, 0x7F, 0x20, 0x00, @@ -1206,7 +1208,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0xA7, 0x9B, 0x6F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xD2, 0xCE, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x72, 0x16, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA9, 0xA0, 0x3B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x3F, 0x83, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x76, 0xE2, 0xA0, 0x00, -0x00, 0x00, 0x00, 0xAD, 0x16, 0x2B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x4D, 0x8A, 0x20, 0x00, +0x00, 0x00, 0x00, 0xAD, 0x16, 0x2B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x44, 0x4F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAE, 0xEC, 0xD2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x1A, 0xF7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xBA, 0x3F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xF1, 0x9E, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x90, 0xE7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB2, 0xBF, 0x0B, 0xA0, 0x00, @@ -1214,7 +1216,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0xB6, 0x34, 0xFB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6C, 0x5A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x0B, 0xA3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x39, 0xC7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xD9, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x10, 0x6F, 0x20, 0x00, -0x00, 0x00, 0x00, 0xBB, 0xAF, 0xB7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xE7, 0x16, 0xA0, 0x00, +0x00, 0x00, 0x00, 0xBB, 0xAF, 0xB7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xDD, 0xDC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x86, 0x5F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBD, 0xB4, 0x83, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x53, 0xCC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x8B, 0x2B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x2A, 0x73, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x58, 0x98, 0x20, 0x00, @@ -1222,15 +1224,15 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0xC4, 0xCE, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x05, 0xE7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xA5, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xD3, 0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x72, 0x9C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xA9, 0xFB, 0xA0, 0x00, -0x00, 0x00, 0x00, 0xCA, 0x49, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x80, 0xA3, 0x20, 0x00, +0x00, 0x00, 0x00, 0xCA, 0x49, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x77, 0x68, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1F, 0xEB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x4E, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xED, 0x58, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x24, 0xB7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xC4, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xF2, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x91, 0x6D, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xC8, 0xCC, 0x20, 0x00, -0x00, 0x00, 0x00, 0xD3, 0x68, 0x14, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x9F, 0x73, 0xA0, 0x00, +0x00, 0x00, 0x00, 0xD3, 0x68, 0x14, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x96, 0x39, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x3E, 0xBC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x6C, 0xE0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x0C, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x43, 0x88, 0x20, 0x00, -0x00, 0x00, 0x00, 0xD8, 0xE2, 0xD0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x1A, 0x2F, 0xA0, 0x00, +0x00, 0x00, 0x00, 0xD8, 0xE2, 0xD0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x10, 0xF5, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB9, 0x78, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xE7, 0x9C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x86, 0xE5, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xBE, 0x44, 0x20, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, @@ -1839,8 +1841,8 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x53, 0x54, 0x00, 0x42, 0x44, 0x54, 0x00, 0x41, 0x48, 0x53, 0x54, 0x00, 0x48, 0x44, 0x54, 0x00, 0x0A, 0x48, 0x53, 0x54, 0x31, 0x30, 0x48, 0x44, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x32, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x31, 0x2E, 0x31, 0x2E, 0x30, 0x0A, 0x00, 0xD8, 0x7D, 0xE0, 0x00, 0x05, 0x19, -0x72, 0x00, 0x00, 0x00, 0x10, 0x41, 0x6C, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6E, 0x20, 0x49, 0x73, -0x6C, 0x61, 0x6E, 0x64, 0x73, +0x72, 0x00, 0x00, 0x00, 0x1A, 0x41, 0x6C, 0x61, 0x73, 0x6B, 0x61, 0x20, 0x2D, 0x20, 0x77, 0x65, +0x73, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x41, 0x6C, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6E, 0x73, /* America/Anchorage */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x55, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -4139,9 +4141,9 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x54, 0x00, 0x4D, 0x44, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x4D, 0x50, 0x54, 0x00, 0x0A, 0x4D, 0x53, 0x54, 0x37, 0x4D, 0x44, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x32, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x31, 0x2E, 0x31, 0x2E, 0x30, 0x0A, 0x00, 0xDB, 0x0A, 0x38, 0x00, 0x65, -0x85, 0x95, 0x00, 0x00, 0x00, 0x1D, 0x4D, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x2D, -0x20, 0x41, 0x42, 0x3B, 0x20, 0x42, 0x43, 0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x53, 0x4B, 0x20, -0x28, 0x57, 0x29, +0x85, 0x95, 0x00, 0x00, 0x00, 0x25, 0x4D, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x2D, +0x20, 0x41, 0x42, 0x3B, 0x20, 0x42, 0x43, 0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x4E, 0x54, 0x20, +0x28, 0x45, 0x29, 0x3B, 0x20, 0x53, 0x4B, 0x20, 0x28, 0x57, 0x29, /* America/Eirunepe */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x42, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -4486,9 +4488,9 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4D, 0x7C, 0x50, 0x00, 0x00, 0x00, 0x00, 0x14, 0x33, 0xFA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x15, 0x23, 0xEB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x16, 0x13, 0xDC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0xCD, 0x90, 0x00, @@ -4532,16 +4534,19 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x5D, 0xB4, 0xEC, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xF3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x94, 0xCE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xD5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x7D, 0xEA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xB7, 0x10, 0x00, -0x00, 0x00, 0x00, 0x63, 0x5D, 0xCC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x00, 0x00, 0x00, 0x63, 0x5D, 0xCC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x00, +0x00, 0x00, 0x00, 0x65, 0x3D, 0xAE, 0x90, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x03, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, -0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0x4C, -0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x2D, 0x30, 0x32, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x32, -0x3E, 0x32, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, +0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, +0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, +0x2D, 0x30, 0x32, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x32, 0x3E, 0x32, 0x3C, 0x2D, 0x30, 0x31, 0x3E, +0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x2D, 0x31, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, +0x2E, 0x30, 0x2F, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, /* America/Goose_Bay */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -7466,9 +7471,9 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x50, 0x48, 0x50, 0x32, 0x01, 0x47, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4D, 0x7C, 0x50, 0x00, 0x00, 0x00, 0x00, 0x14, 0x33, 0xFA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x15, 0x23, 0xEB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x16, 0x13, 0xDC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0xCD, 0x90, 0x00, @@ -7512,18 +7517,20 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x5D, 0xB4, 0xEC, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xF3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x94, 0xCE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xD5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x7D, 0xEA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xB7, 0x10, 0x00, -0x00, 0x00, 0x00, 0x63, 0x5D, 0xCC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x00, 0x00, 0x00, 0x63, 0x5D, 0xCC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x00, +0x00, 0x00, 0x00, 0x65, 0x3D, 0xAE, 0x90, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x03, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, -0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0x4C, -0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x2D, 0x30, 0x32, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x32, -0x3E, 0x32, 0x0A, 0x00, 0xEB, 0x43, 0xDD, 0x00, 0xC3, 0xB8, 0x2A, 0x00, 0x00, 0x00, 0x16, 0x47, -0x72, 0x65, 0x65, 0x6E, 0x6C, 0x61, 0x6E, 0x64, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, -0x72, 0x65, 0x61, 0x73, 0x29, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, +0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, +0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, +0x2D, 0x30, 0x32, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x32, 0x3E, 0x32, 0x3C, 0x2D, 0x30, 0x31, 0x3E, +0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x2D, 0x31, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, +0x2E, 0x30, 0x2F, 0x30, 0x0A, 0x00, 0xEB, 0x43, 0xDD, 0x00, 0xC3, 0xB8, 0x2A, 0x00, 0x00, 0x00, +0x11, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x47, 0x72, 0x65, 0x65, 0x6E, 0x6C, 0x61, +0x6E, 0x64, /* America/Ojinaga */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -7675,9 +7682,9 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x01, 0x02, 0xFF, 0xFF, 0x96, 0xEE, 0x00, 0x00, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x08, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x0C, 0x4C, 0x4D, 0x54, 0x00, 0x4D, 0x44, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x0A, 0x4D, 0x53, 0x54, 0x37, 0x0A, -0x00, 0xBC, 0x5E, 0x01, 0x00, 0x67, 0xA5, 0xDA, 0x00, 0x00, 0x00, 0x1D, 0x4D, 0x53, 0x54, 0x20, -0x2D, 0x20, 0x41, 0x72, 0x69, 0x7A, 0x6F, 0x6E, 0x61, 0x20, 0x28, 0x65, 0x78, 0x63, 0x65, 0x70, -0x74, 0x20, 0x4E, 0x61, 0x76, 0x61, 0x6A, 0x6F, 0x29, +0x00, 0xBC, 0x5E, 0x01, 0x00, 0x67, 0xA5, 0xDA, 0x00, 0x00, 0x00, 0x18, 0x4D, 0x53, 0x54, 0x20, +0x2D, 0x20, 0x41, 0x5A, 0x20, 0x28, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x20, 0x4E, 0x61, 0x76, +0x61, 0x6A, 0x6F, 0x29, /* America/Port-au-Prince */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x48, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -8414,8 +8421,8 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x2D, 0x30, 0x34, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x0A, 0x3C, 0x2D, 0x30, 0x34, 0x3E, 0x34, 0x3C, 0x2D, 0x30, 0x33, 0x3E, 0x2C, 0x4D, 0x39, 0x2E, 0x31, 0x2E, 0x36, 0x2F, 0x32, 0x34, 0x2C, 0x4D, 0x34, 0x2E, 0x31, 0x2E, 0x36, 0x2F, 0x32, 0x34, 0x0A, 0x00, 0x56, 0x49, 0xD8, 0x00, 0xA6, -0xD4, 0x55, 0x00, 0x00, 0x00, 0x12, 0x43, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x28, 0x6D, 0x6F, 0x73, -0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0xD4, 0x55, 0x00, 0x00, 0x00, 0x0D, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x43, 0x68, +0x69, 0x6C, 0x65, /* America/Santo_Domingo */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x44, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -9556,14 +9563,21 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x61, 0x73, 0x6B, 0x61, 0x20, 0x2D, 0x20, 0x59, 0x61, 0x6B, 0x75, 0x74, 0x61, 0x74, /* America/Yellowknife */ -0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xFF, -0xFF, 0xFF, 0xFF, 0xBE, 0x2A, 0x18, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0x89, 0x0C, 0x90, 0xFF, -0xFF, 0xFF, 0xFF, 0xD2, 0x23, 0xF4, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0x61, 0x18, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xFF, +0xFF, 0xFF, 0xFF, 0x88, 0xDE, 0xCE, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x9E, 0xB8, 0xAF, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0x9F, 0xBB, 0x07, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xA0, 0x98, 0x91, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xA0, 0xD2, 0x85, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xA2, 0x8A, 0xE8, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xA3, 0x84, 0x06, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xA4, 0x6A, 0xCA, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xA5, 0x35, 0xC3, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xA6, 0x53, 0xE7, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xA7, 0x15, 0xA5, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x33, 0xC9, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xA8, 0xFE, 0xC2, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0x89, 0x0C, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xD2, 0x23, 0xF4, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0x61, 0x18, 0x00, 0xFF, +0xFF, 0xFF, 0xFF, 0xD5, 0x55, 0xE3, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xD6, 0x20, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, 0x19, 0x90, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0xFC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xFB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, 0xDE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0xDD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xC0, 0x80, 0x00, @@ -9599,18 +9613,18 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x40, 0x6F, 0xCE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x9B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4F, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x7D, 0x80, 0x00, 0x00, 0x00, 0x00, 0x44, 0x2F, 0x92, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, 0x5F, 0x80, 0x00, -0x00, 0x00, 0x00, 0x45, 0xF3, 0xC5, 0x10, 0x03, 0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x04, 0xFF, 0xFF, -0xAB, 0xA0, 0x01, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x0C, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x10, -0x2D, 0x30, 0x30, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x4D, 0x50, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, -0x4D, 0x44, 0x54, 0x00, 0x0A, 0x4D, 0x53, 0x54, 0x37, 0x4D, 0x44, 0x54, 0x2C, 0x4D, 0x33, 0x2E, -0x32, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x31, 0x2E, 0x31, 0x2E, 0x30, 0x0A, 0x00, 0xE8, 0x9E, 0xC7, -0x00, 0x64, 0x2C, 0x88, 0x00, 0x00, 0x00, 0x17, 0x4D, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, -0x20, 0x2D, 0x20, 0x4E, 0x54, 0x20, 0x28, 0x63, 0x65, 0x6E, 0x74, 0x72, 0x61, 0x6C, 0x29, +0x00, 0x00, 0x00, 0x45, 0xF3, 0xC5, 0x10, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0xFF, 0xFF, 0x95, 0xA0, 0x00, 0x00, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x04, 0xFF, 0xFF, 0x9D, 0x90, +0x00, 0x08, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x0C, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x10, 0x4C, 0x4D, +0x54, 0x00, 0x4D, 0x44, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x4D, 0x50, +0x54, 0x00, 0x0A, 0x4D, 0x53, 0x54, 0x37, 0x4D, 0x44, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x32, 0x2E, +0x30, 0x2C, 0x4D, 0x31, 0x31, 0x2E, 0x31, 0x2E, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Antarctica/Casey */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x41, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -10069,9 +10083,8 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x46, 0x50, 0x00, 0x04, 0x00, 0x00, 0x62, 0x70, 0x01, 0x08, 0x00, 0x00, 0x54, 0x60, 0x00, 0x0C, 0x00, 0x00, 0x54, 0x60, 0x01, 0x0C, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, 0x37, 0x00, 0x2B, 0x30, 0x36, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x36, 0x3E, 0x2D, 0x36, -0x0A, 0x00, 0xCB, 0x52, 0xC8, 0x01, 0x88, 0x13, 0x18, 0x00, 0x00, 0x00, 0x17, 0x4B, 0x61, 0x7A, -0x61, 0x6B, 0x68, 0x73, 0x74, 0x61, 0x6E, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, -0x65, 0x61, 0x73, 0x29, +0x0A, 0x00, 0xCB, 0x52, 0xC8, 0x01, 0x88, 0x13, 0x18, 0x00, 0x00, 0x00, 0x12, 0x6D, 0x6F, 0x73, +0x74, 0x20, 0x6F, 0x66, 0x20, 0x4B, 0x61, 0x7A, 0x61, 0x6B, 0x68, 0x73, 0x74, 0x61, 0x6E, /* Asia/Amman */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x4A, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -11065,7 +11078,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x15, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0xBD, 0x4A, 0xB0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x59, 0xCF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0xFA, 0xA6, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x38, 0x9C, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xE5, 0xEB, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xCD, 0xAC, 0xFE, 0x00, 0xFF, @@ -11125,7 +11138,77 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x5C, 0x9D, 0x43, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xB3, 0x62, 0x50, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7E, 0x77, 0x60, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x93, 0x52, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5E, 0x59, 0x60, 0x00, 0x00, 0x00, 0x00, 0x61, 0x7B, 0x1D, 0x60, 0x00, -0x00, 0x00, 0x00, 0x62, 0x3F, 0x8C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x63, 0x5C, 0x5E, 0xF0, 0x02, +0x00, 0x00, 0x00, 0x62, 0x3F, 0x8C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x63, 0x5C, 0x5E, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x64, 0x4C, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3C, 0x40, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x66, 0x19, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x1C, 0x22, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x67, 0xF0, 0x72, 0x80, 0x00, 0x00, 0x00, 0x00, 0x68, 0xFC, 0x04, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x69, 0xC7, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xDB, 0xE6, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x6B, 0xA6, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xC5, 0x03, 0x70, 0x00, +0x00, 0x00, 0x00, 0x6D, 0x86, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA4, 0xE5, 0x70, 0x00, +0x00, 0x00, 0x00, 0x6F, 0x66, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x84, 0xC7, 0x70, 0x00, +0x00, 0x00, 0x00, 0x71, 0x4F, 0xDC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x72, 0x64, 0xA9, 0x70, 0x00, +0x00, 0x00, 0x00, 0x73, 0x2F, 0xBE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x74, 0x44, 0x8B, 0x70, 0x00, +0x00, 0x00, 0x00, 0x75, 0x0F, 0xA0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x76, 0x2D, 0xA7, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x76, 0xEF, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0D, 0x89, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x78, 0xCF, 0x64, 0x80, 0x00, 0x00, 0x00, 0x00, 0x79, 0xED, 0x6B, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x7A, 0xAF, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCD, 0x4D, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x7C, 0x98, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xA3, 0xF5, 0x70, 0x00, +0x00, 0x00, 0x00, 0x7E, 0x78, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7A, 0x9C, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x80, 0x58, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x48, 0x09, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x82, 0x38, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x1E, 0xB1, 0x70, 0x00, +0x00, 0x00, 0x00, 0x83, 0x4C, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x56, 0x10, 0x70, 0x00, +0x00, 0x00, 0x00, 0x84, 0x17, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xEC, 0x1E, 0x70, 0x00, +0x00, 0x00, 0x00, 0x85, 0x23, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x85, 0x35, 0xF2, 0x70, 0x00, +0x00, 0x00, 0x00, 0x86, 0x01, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x86, 0xC2, 0xC5, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x86, 0xF0, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x87, 0x15, 0xD4, 0x70, 0x00, +0x00, 0x00, 0x00, 0x87, 0xE0, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x88, 0x99, 0x6D, 0x70, 0x00, +0x00, 0x00, 0x00, 0x88, 0xC7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xF5, 0xB6, 0x70, 0x00, +0x00, 0x00, 0x00, 0x89, 0xC0, 0xCB, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x66, 0xDA, 0x70, 0x00, +0x00, 0x00, 0x00, 0x8A, 0x9E, 0x47, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xD5, 0x98, 0x70, 0x00, +0x00, 0x00, 0x00, 0x8B, 0xA0, 0xAD, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x3D, 0x81, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x8C, 0x6B, 0xB4, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xBE, 0xB4, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x8D, 0x80, 0x8F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x14, 0x29, 0x70, 0x00, +0x00, 0x00, 0x00, 0x8E, 0x42, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x9E, 0x96, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x8F, 0x60, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8F, 0xE1, 0x96, 0x70, 0x00, +0x00, 0x00, 0x00, 0x90, 0x19, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x90, 0x7E, 0x78, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x91, 0x49, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB8, 0x3D, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x91, 0xE6, 0x70, 0x80, 0x00, 0x00, 0x00, 0x00, 0x92, 0x5E, 0x5A, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x93, 0x29, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x85, 0xAA, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x93, 0xBD, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x3E, 0x3C, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x95, 0x09, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5C, 0x52, 0x70, 0x00, +0x00, 0x00, 0x00, 0x95, 0x8A, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x27, 0x59, 0x70, 0x00, +0x00, 0x00, 0x00, 0x96, 0xE9, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x32, 0xF9, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x97, 0x61, 0x2C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x98, 0x07, 0x3B, 0x70, 0x00, +0x00, 0x00, 0x00, 0x98, 0xC9, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x66, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x99, 0x37, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xE7, 0x1D, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9A, 0xB2, 0x32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD7, 0x0E, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9B, 0x05, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xC6, 0xFF, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9C, 0x92, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xA4, 0x7B, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9C, 0xDB, 0xE8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xA6, 0xE1, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9E, 0x71, 0xF6, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x7B, 0x22, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x9E, 0xB2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x86, 0xC3, 0x70, 0x00, +0x00, 0x00, 0x00, 0xA0, 0x7F, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x6F, 0xDF, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA2, 0x56, 0xA4, 0x80, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x4F, 0xC1, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA4, 0x24, 0x11, 0x80, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x2F, 0xA3, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA5, 0xFA, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7, 0x0F, 0x85, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA7, 0xDA, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xEF, 0x67, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA9, 0xBA, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xD8, 0x84, 0x70, 0x00, +0x00, 0x00, 0x00, 0xAB, 0x9A, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xB8, 0x66, 0x70, 0x00, +0x00, 0x00, 0x00, 0xAD, 0x7A, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAE, 0x98, 0x48, 0x70, 0x00, +0x00, 0x00, 0x00, 0xAF, 0x5A, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x78, 0x2A, 0x70, 0x00, +0x00, 0x00, 0x00, 0xB1, 0x43, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x58, 0x0C, 0x70, 0x00, +0x00, 0x00, 0x00, 0xB3, 0x23, 0x21, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x37, 0xEE, 0x70, 0x00, +0x00, 0x00, 0x00, 0xB5, 0x03, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x21, 0x0A, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xB6, 0xE2, 0xE5, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0xEC, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xB8, 0xC2, 0xC7, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xD7, 0x94, 0x70, 0x00, +0x00, 0x00, 0x00, 0xBA, 0xAB, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xAE, 0x3B, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xBC, 0x8B, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x84, 0xE3, 0x70, 0x00, +0x00, 0x00, 0x00, 0xBE, 0x6B, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x52, 0x50, 0x70, 0x00, +0x00, 0x00, 0x00, 0xC0, 0x4B, 0x8A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x28, 0xF7, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xC1, 0x57, 0x2A, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xFF, 0x9F, 0x70, 0x00, +0x00, 0x00, 0x00, 0xC3, 0x2D, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xCD, 0x0C, 0x70, 0x00, +0x00, 0x00, 0x00, 0xC5, 0x04, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xA3, 0xB3, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xC6, 0xD1, 0xE6, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x09, 0x37, 0x70, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, @@ -11133,14 +11216,22 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x20, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2A, -0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, -0x00, 0x1C, 0x20, 0x00, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, -0x54, 0x00, 0x49, 0x44, 0x54, 0x00, 0x49, 0x53, 0x54, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, -0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x2C, 0x4D, -0x31, 0x30, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x0A, 0x00, 0xB9, 0x64, 0xF0, 0x01, 0x47, -0x40, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x47, 0x61, 0x7A, 0x61, 0x20, 0x53, 0x74, 0x72, 0x69, 0x70, - +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x00, 0x00, 0x20, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, +0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, 0x00, 0x1C, 0x20, 0x00, +0x11, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x49, 0x44, +0x54, 0x00, 0x49, 0x53, 0x54, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, +0x2C, 0x4D, 0x33, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x34, +0x2E, 0x34, 0x2F, 0x35, 0x30, 0x0A, 0x00, 0xB9, 0x64, 0xF0, 0x01, 0x47, 0x40, 0x0A, 0x00, 0x00, +0x00, 0x0A, 0x47, 0x61, 0x7A, 0x61, 0x20, 0x53, 0x74, 0x72, 0x69, 0x70, /* Asia/Harbin */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -11176,7 +11267,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x15, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0xBD, 0x4A, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x59, 0xCF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0xFA, 0xA6, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x38, 0x9C, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xE5, 0xEB, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xCD, 0xAC, 0xFE, 0x00, 0xFF, @@ -11237,7 +11328,77 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x5C, 0x9D, 0x43, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xB3, 0x62, 0x50, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7E, 0x77, 0x60, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x93, 0x52, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5E, 0x59, 0x60, 0x00, 0x00, 0x00, 0x00, 0x61, 0x7B, 0x1D, 0x60, 0x00, -0x00, 0x00, 0x00, 0x62, 0x3F, 0x8C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x63, 0x5C, 0x5E, 0xF0, 0x02, +0x00, 0x00, 0x00, 0x62, 0x3F, 0x8C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x63, 0x5C, 0x5E, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x64, 0x4C, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3C, 0x40, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x66, 0x19, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x1C, 0x22, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x67, 0xF0, 0x72, 0x80, 0x00, 0x00, 0x00, 0x00, 0x68, 0xFC, 0x04, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x69, 0xC7, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xDB, 0xE6, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x6B, 0xA6, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xC5, 0x03, 0x70, 0x00, +0x00, 0x00, 0x00, 0x6D, 0x86, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA4, 0xE5, 0x70, 0x00, +0x00, 0x00, 0x00, 0x6F, 0x66, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x84, 0xC7, 0x70, 0x00, +0x00, 0x00, 0x00, 0x71, 0x4F, 0xDC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x72, 0x64, 0xA9, 0x70, 0x00, +0x00, 0x00, 0x00, 0x73, 0x2F, 0xBE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x74, 0x44, 0x8B, 0x70, 0x00, +0x00, 0x00, 0x00, 0x75, 0x0F, 0xA0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x76, 0x2D, 0xA7, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x76, 0xEF, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0D, 0x89, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x78, 0xCF, 0x64, 0x80, 0x00, 0x00, 0x00, 0x00, 0x79, 0xED, 0x6B, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x7A, 0xAF, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCD, 0x4D, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x7C, 0x98, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xA3, 0xF5, 0x70, 0x00, +0x00, 0x00, 0x00, 0x7E, 0x78, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7A, 0x9C, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x80, 0x58, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x48, 0x09, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x82, 0x38, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x1E, 0xB1, 0x70, 0x00, +0x00, 0x00, 0x00, 0x83, 0x4C, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x56, 0x10, 0x70, 0x00, +0x00, 0x00, 0x00, 0x84, 0x17, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xEC, 0x1E, 0x70, 0x00, +0x00, 0x00, 0x00, 0x85, 0x23, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x85, 0x35, 0xF2, 0x70, 0x00, +0x00, 0x00, 0x00, 0x86, 0x01, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x86, 0xC2, 0xC5, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x86, 0xF0, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x87, 0x15, 0xD4, 0x70, 0x00, +0x00, 0x00, 0x00, 0x87, 0xE0, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x88, 0x99, 0x6D, 0x70, 0x00, +0x00, 0x00, 0x00, 0x88, 0xC7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xF5, 0xB6, 0x70, 0x00, +0x00, 0x00, 0x00, 0x89, 0xC0, 0xCB, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x66, 0xDA, 0x70, 0x00, +0x00, 0x00, 0x00, 0x8A, 0x9E, 0x47, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xD5, 0x98, 0x70, 0x00, +0x00, 0x00, 0x00, 0x8B, 0xA0, 0xAD, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x3D, 0x81, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x8C, 0x6B, 0xB4, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xBE, 0xB4, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x8D, 0x80, 0x8F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x14, 0x29, 0x70, 0x00, +0x00, 0x00, 0x00, 0x8E, 0x42, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x9E, 0x96, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x8F, 0x60, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8F, 0xE1, 0x96, 0x70, 0x00, +0x00, 0x00, 0x00, 0x90, 0x19, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x90, 0x7E, 0x78, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x91, 0x49, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB8, 0x3D, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x91, 0xE6, 0x70, 0x80, 0x00, 0x00, 0x00, 0x00, 0x92, 0x5E, 0x5A, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x93, 0x29, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x85, 0xAA, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x93, 0xBD, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x3E, 0x3C, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x95, 0x09, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5C, 0x52, 0x70, 0x00, +0x00, 0x00, 0x00, 0x95, 0x8A, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x27, 0x59, 0x70, 0x00, +0x00, 0x00, 0x00, 0x96, 0xE9, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x32, 0xF9, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x97, 0x61, 0x2C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x98, 0x07, 0x3B, 0x70, 0x00, +0x00, 0x00, 0x00, 0x98, 0xC9, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x66, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x99, 0x37, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xE7, 0x1D, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9A, 0xB2, 0x32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD7, 0x0E, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9B, 0x05, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xC6, 0xFF, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9C, 0x92, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xA4, 0x7B, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9C, 0xDB, 0xE8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xA6, 0xE1, 0x70, 0x00, +0x00, 0x00, 0x00, 0x9E, 0x71, 0xF6, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x7B, 0x22, 0xF0, 0x00, +0x00, 0x00, 0x00, 0x9E, 0xB2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x86, 0xC3, 0x70, 0x00, +0x00, 0x00, 0x00, 0xA0, 0x7F, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x6F, 0xDF, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA2, 0x56, 0xA4, 0x80, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x4F, 0xC1, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA4, 0x24, 0x11, 0x80, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x2F, 0xA3, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA5, 0xFA, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7, 0x0F, 0x85, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA7, 0xDA, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xEF, 0x67, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xA9, 0xBA, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xD8, 0x84, 0x70, 0x00, +0x00, 0x00, 0x00, 0xAB, 0x9A, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xB8, 0x66, 0x70, 0x00, +0x00, 0x00, 0x00, 0xAD, 0x7A, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAE, 0x98, 0x48, 0x70, 0x00, +0x00, 0x00, 0x00, 0xAF, 0x5A, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x78, 0x2A, 0x70, 0x00, +0x00, 0x00, 0x00, 0xB1, 0x43, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x58, 0x0C, 0x70, 0x00, +0x00, 0x00, 0x00, 0xB3, 0x23, 0x21, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x37, 0xEE, 0x70, 0x00, +0x00, 0x00, 0x00, 0xB5, 0x03, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x21, 0x0A, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xB6, 0xE2, 0xE5, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0xEC, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xB8, 0xC2, 0xC7, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xD7, 0x94, 0x70, 0x00, +0x00, 0x00, 0x00, 0xBA, 0xAB, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xAE, 0x3B, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xBC, 0x8B, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x84, 0xE3, 0x70, 0x00, +0x00, 0x00, 0x00, 0xBE, 0x6B, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x52, 0x50, 0x70, 0x00, +0x00, 0x00, 0x00, 0xC0, 0x4B, 0x8A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x28, 0xF7, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xC1, 0x57, 0x2A, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xFF, 0x9F, 0x70, 0x00, +0x00, 0x00, 0x00, 0xC3, 0x2D, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xCD, 0x0C, 0x70, 0x00, +0x00, 0x00, 0x00, 0xC5, 0x04, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xA3, 0xB3, 0xF0, 0x00, +0x00, 0x00, 0x00, 0xC6, 0xD1, 0xE6, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x09, 0x37, 0x70, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, @@ -11245,14 +11406,22 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, -0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, -0x0D, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, -0x45, 0x45, 0x54, 0x00, 0x49, 0x44, 0x54, 0x00, 0x49, 0x53, 0x54, 0x00, 0x0A, 0x45, 0x45, 0x54, -0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, -0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x0A, 0x00, 0xB9, 0x71, 0xF5, -0x01, 0x48, 0x35, 0x7C, 0x00, 0x00, 0x00, 0x09, 0x57, 0x65, 0x73, 0x74, 0x20, 0x42, 0x61, 0x6E, -0x6B, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, +0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, 0x00, 0x1C, +0x20, 0x00, 0x11, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, +0x49, 0x44, 0x54, 0x00, 0x49, 0x53, 0x54, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, +0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x2C, 0x4D, 0x31, 0x30, +0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x0A, 0x00, 0xB9, 0x71, 0xF5, 0x01, 0x48, 0x35, 0x7C, +0x00, 0x00, 0x00, 0x09, 0x57, 0x65, 0x73, 0x74, 0x20, 0x42, 0x61, 0x6E, 0x6B, /* Asia/Ho_Chi_Minh */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x56, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -12150,8 +12319,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x34, 0x0A, 0x00, 0xBE, 0xFD, 0x3A, 0x01, 0x45, 0x92, 0x5A, 0x00, 0x00, 0x00, -0x13, 0x43, 0x79, 0x70, 0x72, 0x75, 0x73, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, -0x65, 0x61, 0x73, 0x29, +0x0E, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x43, 0x79, 0x70, 0x72, 0x75, 0x73, /* Asia/Novokuznetsk */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -12748,9 +12916,9 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x9A, 0xB0, 0x01, 0x0C, 0x00, 0x00, 0xA8, 0xC0, 0x00, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x31, 0x30, 0x00, 0x2B, 0x31, 0x32, 0x00, 0x2B, 0x31, 0x31, 0x00, 0x0A, 0x3C, 0x2B, 0x31, 0x31, 0x3E, 0x2D, 0x31, 0x31, 0x0A, 0x00, 0xF0, 0x46, 0x6A, 0x01, 0xFD, 0x36, 0x12, 0x00, 0x00, -0x00, 0x22, 0x4D, 0x53, 0x4B, 0x2B, 0x30, 0x38, 0x20, 0x2D, 0x20, 0x53, 0x61, 0x6B, 0x68, 0x61, -0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x4E, 0x6F, 0x72, 0x74, 0x68, 0x20, 0x4B, 0x75, 0x72, 0x69, -0x6C, 0x20, 0x49, 0x73, +0x00, 0x1E, 0x4D, 0x53, 0x4B, 0x2B, 0x30, 0x38, 0x20, 0x2D, 0x20, 0x53, 0x61, 0x6B, 0x68, 0x61, +0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x4E, 0x20, 0x4B, 0x75, 0x72, 0x69, 0x6C, 0x20, 0x49, 0x73, + /* Asia/Taipei */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x54, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -13128,9 +13296,8 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x03, 0x00, 0x00, 0x64, 0x34, 0x00, 0x00, 0x00, 0x00, 0x62, 0x70, 0x00, 0x04, 0x00, 0x00, 0x7E, 0x90, 0x01, 0x08, 0x00, 0x00, 0x70, 0x80, 0x00, 0x0C, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x37, 0x00, 0x2B, 0x30, 0x39, 0x00, 0x2B, 0x30, 0x38, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x38, 0x3E, 0x2D, -0x38, 0x0A, 0x00, 0xD2, 0x71, 0xB2, 0x01, 0xB5, 0xBF, 0xCD, 0x00, 0x00, 0x00, 0x15, 0x4D, 0x6F, -0x6E, 0x67, 0x6F, 0x6C, 0x69, 0x61, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, -0x61, 0x73, 0x29, +0x38, 0x0A, 0x00, 0xD2, 0x71, 0xB2, 0x01, 0xB5, 0xBF, 0xCD, 0x00, 0x00, 0x00, 0x10, 0x6D, 0x6F, +0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x6F, 0x6E, 0x67, 0x6F, 0x6C, 0x69, 0x61, /* Asia/Ulan_Bator */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -16316,7 +16483,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0xBD, 0x4D, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x93, 0xB4, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0xFA, 0x7B, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0xFC, 0xEF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA, 0xC7, 0xE8, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0xCB, 0xAE, 0x60, 0xFF, @@ -16380,7 +16547,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x4C, 0x61, 0xBD, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x89, 0x58, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xA4, 0xFA, 0x50, 0x00, 0x00, 0x00, 0x00, 0x53, 0x75, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xAC, 0x89, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xDA, 0xBC, 0x60, 0x00, -0x00, 0x00, 0x00, 0x54, 0x24, 0x82, 0x50, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x00, 0x00, 0x00, 0x54, 0x24, 0x82, 0x50, 0x00, 0x00, 0x00, 0x00, 0x64, 0x4A, 0xF0, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, @@ -16388,10 +16555,12 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, -0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x1D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, -0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, -0x00, 0x45, 0x45, 0x54, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x0A, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x00, +0x00, 0x1D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, +0x09, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x0A, 0x45, +0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x34, 0x2E, 0x35, 0x2E, 0x35, 0x2F, +0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x34, 0x2F, 0x32, 0x34, 0x0A, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Eire */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -17288,9 +17457,8 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x30, 0x01, 0x0D, 0x4C, 0x4D, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00, 0x43, 0x45, 0x54, 0x00, 0x43, 0x45, 0x4D, 0x54, 0x00, 0x0A, 0x43, 0x45, 0x54, 0x2D, 0x31, 0x43, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, -0x0A, 0x00, 0xD9, 0x70, 0x10, 0x01, 0x27, 0x0D, 0xDA, 0x00, 0x00, 0x00, 0x14, 0x47, 0x65, 0x72, -0x6D, 0x61, 0x6E, 0x79, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, -0x29, +0x0A, 0x00, 0xD9, 0x70, 0x10, 0x01, 0x27, 0x0D, 0xDA, 0x00, 0x00, 0x00, 0x0F, 0x6D, 0x6F, 0x73, +0x74, 0x20, 0x6F, 0x66, 0x20, 0x47, 0x65, 0x72, 0x6D, 0x61, 0x6E, 0x79, /* Europe/Bratislava */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x53, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -18339,7 +18507,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA1, 0x00, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB5, 0xA4, 0x0B, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x27, 0x99, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0xCE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x17, 0x08, 0xCD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x17, 0xFA, 0x01, 0xB0, 0x00, @@ -18372,15 +18540,16 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x4A, 0xE3, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0x8D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xCC, 0xA3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x4C, 0x1D, 0x60, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, -0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x04, 0x01, 0x04, 0x01, 0x03, 0x04, 0x01, -0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, -0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, -0x04, 0x01, 0x04, 0x01, 0x03, 0x01, 0x00, 0x00, 0x2E, 0x98, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x04, 0x05, 0x04, 0x05, 0x03, 0x04, 0x05, +0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, +0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, +0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x00, 0x00, 0x2E, 0x98, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x00, 0x00, 0x46, 0x50, 0x01, 0x08, 0x00, 0x00, 0x38, 0x40, 0x00, 0x0C, 0x00, 0x00, -0x38, 0x40, 0x01, 0x0C, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, -0x2B, 0x30, 0x34, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x33, 0x3E, 0x2D, 0x33, 0x0A, 0x00, 0xE2, 0xBE, -0xE0, 0x01, 0x5E, 0x6B, 0x08, 0x00, 0x00, 0x00, 0x0E, 0x4D, 0x53, 0x4B, 0x2B, 0x30, 0x30, 0x20, -0x2D, 0x20, 0x4B, 0x69, 0x72, 0x6F, 0x76, +0x38, 0x40, 0x01, 0x10, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x14, 0x00, 0x00, 0x38, 0x40, 0x00, 0x14, +0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, 0x34, 0x00, +0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x0A, 0x4D, 0x53, 0x4B, 0x2D, 0x33, 0x0A, 0x00, +0xE2, 0xBE, 0xE0, 0x01, 0x5E, 0x6B, 0x08, 0x00, 0x00, 0x00, 0x0E, 0x4D, 0x53, 0x4B, 0x2B, 0x30, +0x30, 0x20, 0x2D, 0x20, 0x4B, 0x69, 0x72, 0x6F, 0x76, /* Europe/Kyiv */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x55, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -18418,8 +18587,8 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00, 0x4D, 0x53, 0x44, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x34, 0x0A, 0x00, 0xD6, -0x48, 0xC5, 0x01, 0x41, 0x39, 0x12, 0x00, 0x00, 0x00, 0x14, 0x55, 0x6B, 0x72, 0x61, 0x69, 0x6E, -0x65, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0x48, 0xC5, 0x01, 0x41, 0x39, 0x12, 0x00, 0x00, 0x00, 0x0F, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, +0x66, 0x20, 0x55, 0x6B, 0x72, 0x61, 0x69, 0x6E, 0x65, /* Europe/Lisbon */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -20192,7 +20361,7 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA1, 0xF5, 0x46, 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xB5, 0xA4, 0x0B, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x27, 0x99, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0xCE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x17, 0x08, 0xCD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x17, 0xFA, 0x01, 0xB0, 0x00, @@ -20226,15 +20395,16 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x00, 0x4C, 0xCC, 0xA3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x4C, 0x1D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x5B, 0xD4, 0xED, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x5F, 0xE7, 0xB2, 0x60, 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x02, 0x04, 0x01, -0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, -0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, -0x04, 0x01, 0x04, 0x01, 0x02, 0x01, 0x02, 0x01, 0x00, 0x00, 0x29, 0xA4, 0x00, 0x00, 0x00, 0x00, +0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x02, 0x04, 0x05, +0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, +0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, +0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x02, 0x05, 0x00, 0x00, 0x29, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x00, 0x00, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0C, -0x00, 0x00, 0x38, 0x40, 0x01, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, -0x34, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x33, 0x3E, 0x2D, 0x33, 0x0A, 0x00, -0xD3, 0xB0, 0xB5, 0x01, 0x56, 0x6E, 0xC2, 0x00, 0x00, 0x00, 0x12, 0x4D, 0x53, 0x4B, 0x2B, 0x30, -0x30, 0x20, 0x2D, 0x20, 0x56, 0x6F, 0x6C, 0x67, 0x6F, 0x67, 0x72, 0x61, 0x64, +0x00, 0x00, 0x38, 0x40, 0x01, 0x10, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x14, 0x00, 0x00, 0x38, 0x40, +0x00, 0x14, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x2B, 0x30, +0x35, 0x00, 0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x0A, 0x4D, 0x53, 0x4B, 0x2D, 0x33, +0x0A, 0x00, 0xD3, 0xB0, 0xB5, 0x01, 0x56, 0x6E, 0xC2, 0x00, 0x00, 0x00, 0x12, 0x4D, 0x53, 0x4B, +0x2B, 0x30, 0x30, 0x20, 0x2D, 0x20, 0x56, 0x6F, 0x6C, 0x67, 0x6F, 0x67, 0x72, 0x61, 0x64, /* Europe/Warsaw */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x50, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -21655,9 +21825,9 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0xC0, 0x00, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x4E, 0x5A, 0x53, 0x54, 0x00, 0x4E, 0x5A, 0x4D, 0x54, 0x00, 0x4E, 0x5A, 0x44, 0x54, 0x00, 0x0A, 0x4E, 0x5A, 0x53, 0x54, 0x2D, 0x31, 0x32, 0x4E, 0x5A, 0x44, 0x54, 0x2C, 0x4D, 0x39, 0x2E, 0x35, 0x2E, 0x30, 0x2C, 0x4D, 0x34, 0x2E, 0x31, 0x2E, 0x30, -0x2F, 0x33, 0x0A, 0x00, 0x51, 0x13, 0x35, 0x02, 0x1D, 0x54, 0xBA, 0x00, 0x00, 0x00, 0x18, 0x4E, -0x65, 0x77, 0x20, 0x5A, 0x65, 0x61, 0x6C, 0x61, 0x6E, 0x64, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, -0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0x2F, 0x33, 0x0A, 0x00, 0x51, 0x13, 0x35, 0x02, 0x1D, 0x54, 0xBA, 0x00, 0x00, 0x00, 0x13, 0x6D, +0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x4E, 0x65, 0x77, 0x20, 0x5A, 0x65, 0x61, 0x6C, 0x61, +0x6E, 0x64, /* Pacific/Bougainville */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x50, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -22096,9 +22266,8 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x00, 0x00, 0x8C, 0xA0, 0x00, 0x0C, 0x00, 0x00, 0xA8, 0xC0, 0x00, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x31, 0x31, 0x00, 0x2B, 0x30, 0x39, 0x00, 0x2B, 0x31, 0x30, 0x00, 0x2B, 0x31, 0x32, 0x00, 0x0A, 0x3C, 0x2B, 0x31, 0x32, 0x3E, 0x2D, 0x31, 0x32, 0x0A, 0x00, 0x94, 0x3D, 0x38, 0x02, 0x17, -0xE3, 0x80, 0x00, 0x00, 0x00, 0x1D, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x49, -0x73, 0x6C, 0x61, 0x6E, 0x64, 0x73, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, -0x61, 0x73, 0x29, +0xE3, 0x80, 0x00, 0x00, 0x00, 0x18, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x61, +0x72, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x49, 0x73, 0x6C, 0x61, 0x6E, 0x64, 0x73, /* Pacific/Marquesas */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x50, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -22270,9 +22439,8 @@ const unsigned char timelib_timezone_db_data_builtin[345391] = { 0x02, 0x00, 0x00, 0x89, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x89, 0xF0, 0x00, 0x04, 0x00, 0x00, 0x8C, 0xA0, 0x00, 0x09, 0x4C, 0x4D, 0x54, 0x00, 0x50, 0x4D, 0x4D, 0x54, 0x00, 0x2B, 0x31, 0x30, 0x00, 0x0A, 0x3C, 0x2B, 0x31, 0x30, 0x3E, 0x2D, 0x31, 0x30, 0x0A, 0x00, 0x7A, 0xD5, 0x50, 0x01, 0xF3, -0x37, 0x7A, 0x00, 0x00, 0x00, 0x1D, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4E, 0x65, 0x77, 0x20, -0x47, 0x75, 0x69, 0x6E, 0x65, 0x61, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, -0x61, 0x73, 0x29, +0x37, 0x7A, 0x00, 0x00, 0x00, 0x18, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x50, 0x61, +0x70, 0x75, 0x61, 0x20, 0x4E, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6E, 0x65, 0x61, /* Pacific/Rarotonga */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -23705,593 +23873,593 @@ const timelib_tzdb_index_entry timezonedb_idx_builtin[597] = { { (char*) "Africa/Brazzaville" , 0x000E79 }, { (char*) "Africa/Bujumbura" , 0x000F1A }, { (char*) "Africa/Cairo" , 0x000FBB }, - { (char*) "Africa/Casablanca" , 0x00176A }, - { (char*) "Africa/Ceuta" , 0x0020F3 }, - { (char*) "Africa/Conakry" , 0x002911 }, - { (char*) "Africa/Dakar" , 0x0029ED }, - { (char*) "Africa/Dar_es_Salaam" , 0x002AAF }, - { (char*) "Africa/Djibouti" , 0x002B90 }, - { (char*) "Africa/Douala" , 0x002C31 }, - { (char*) "Africa/El_Aaiun" , 0x002CD2 }, - { (char*) "Africa/Freetown" , 0x0035D5 }, - { (char*) "Africa/Gaborone" , 0x0037B1 }, - { (char*) "Africa/Harare" , 0x0038A8 }, - { (char*) "Africa/Johannesburg" , 0x003949 }, - { (char*) "Africa/Juba" , 0x003A4B }, - { (char*) "Africa/Kampala" , 0x003CFE }, - { (char*) "Africa/Khartoum" , 0x003E05 }, - { (char*) "Africa/Kigali" , 0x0040B8 }, - { (char*) "Africa/Kinshasa" , 0x004159 }, - { (char*) "Africa/Lagos" , 0x004213 }, - { (char*) "Africa/Libreville" , 0x00430A }, - { (char*) "Africa/Lome" , 0x0043AB }, - { (char*) "Africa/Luanda" , 0x00444B }, - { (char*) "Africa/Lubumbashi" , 0x004512 }, - { (char*) "Africa/Lusaka" , 0x0045EE }, - { (char*) "Africa/Malabo" , 0x00468F }, - { (char*) "Africa/Maputo" , 0x004752 }, - { (char*) "Africa/Maseru" , 0x0047F3 }, - { (char*) "Africa/Mbabane" , 0x0048BF }, - { (char*) "Africa/Mogadishu" , 0x004963 }, - { (char*) "Africa/Monrovia" , 0x004A44 }, - { (char*) "Africa/Nairobi" , 0x004B20 }, - { (char*) "Africa/Ndjamena" , 0x004C35 }, - { (char*) "Africa/Niamey" , 0x004D08 }, - { (char*) "Africa/Nouakchott" , 0x004DED }, - { (char*) "Africa/Ouagadougou" , 0x004EC9 }, - { (char*) "Africa/Porto-Novo" , 0x004F69 }, - { (char*) "Africa/Sao_Tome" , 0x00502C }, - { (char*) "Africa/Timbuktu" , 0x005136 }, - { (char*) "Africa/Tripoli" , 0x0051D6 }, - { (char*) "Africa/Tunis" , 0x005453 }, - { (char*) "Africa/Windhoek" , 0x005710 }, - { (char*) "America/Adak" , 0x005AD7 }, - { (char*) "America/Anchorage" , 0x006427 }, - { (char*) "America/Anguilla" , 0x006D89 }, - { (char*) "America/Antigua" , 0x006E29 }, - { (char*) "America/Araguaina" , 0x006EEB }, - { (char*) "America/Argentina/Buenos_Aires" , 0x007266 }, - { (char*) "America/Argentina/Catamarca" , 0x0076AD }, - { (char*) "America/Argentina/ComodRivadavia" , 0x007AFA }, - { (char*) "America/Argentina/Cordoba" , 0x007F2C }, - { (char*) "America/Argentina/Jujuy" , 0x008394 }, - { (char*) "America/Argentina/La_Rioja" , 0x0087B4 }, - { (char*) "America/Argentina/Mendoza" , 0x008C01 }, - { (char*) "America/Argentina/Rio_Gallegos" , 0x00903F }, - { (char*) "America/Argentina/Salta" , 0x009480 }, - { (char*) "America/Argentina/San_Juan" , 0x0098AC }, - { (char*) "America/Argentina/San_Luis" , 0x009CF9 }, - { (char*) "America/Argentina/Tucuman" , 0x00A152 }, - { (char*) "America/Argentina/Ushuaia" , 0x00A5AC }, - { (char*) "America/Aruba" , 0x00A9F3 }, - { (char*) "America/Asuncion" , 0x00AAB9 }, - { (char*) "America/Atikokan" , 0x00B2B3 }, - { (char*) "America/Atka" , 0x00B430 }, - { (char*) "America/Bahia" , 0x00BD70 }, - { (char*) "America/Bahia_Banderas" , 0x00C173 }, - { (char*) "America/Barbados" , 0x00C610 }, - { (char*) "America/Belem" , 0x00C7D0 }, - { (char*) "America/Belize" , 0x00CA20 }, - { (char*) "America/Blanc-Sablon" , 0x00D07A }, - { (char*) "America/Boa_Vista" , 0x00D1CC }, - { (char*) "America/Bogota" , 0x00D449 }, - { (char*) "America/Boise" , 0x00D53D }, - { (char*) "America/Buenos_Aires" , 0x00DED3 }, - { (char*) "America/Cambridge_Bay" , 0x00E305 }, - { (char*) "America/Campo_Grande" , 0x00EBF3 }, - { (char*) "America/Cancun" , 0x00F1A7 }, - { (char*) "America/Caracas" , 0x00F501 }, - { (char*) "America/Catamarca" , 0x00F607 }, - { (char*) "America/Cayenne" , 0x00FA39 }, - { (char*) "America/Cayman" , 0x00FAFD }, - { (char*) "America/Chicago" , 0x00FBBF }, - { (char*) "America/Chihuahua" , 0x0109E7 }, - { (char*) "America/Ciudad_Juarez" , 0x010E57 }, - { (char*) "America/Coral_Harbour" , 0x011481 }, - { (char*) "America/Cordoba" , 0x011543 }, - { (char*) "America/Costa_Rica" , 0x011975 }, - { (char*) "America/Creston" , 0x011ABD }, - { (char*) "America/Cuiaba" , 0x011BAB }, - { (char*) "America/Curacao" , 0x01213C }, - { (char*) "America/Danmarkshavn" , 0x012202 }, - { (char*) "America/Dawson" , 0x0124E2 }, - { (char*) "America/Dawson_Creek" , 0x012B4E }, - { (char*) "America/Denver" , 0x012F94 }, - { (char*) "America/Detroit" , 0x013951 }, - { (char*) "America/Dominica" , 0x01422C }, - { (char*) "America/Edmonton" , 0x0142CC }, - { (char*) "America/Eirunepe" , 0x014C11 }, - { (char*) "America/El_Salvador" , 0x014EAE }, - { (char*) "America/Ensenada" , 0x014F9A }, - { (char*) "America/Fort_Nelson" , 0x0158EC }, - { (char*) "America/Fort_Wayne" , 0x0161CC }, - { (char*) "America/Fortaleza" , 0x01686A }, - { (char*) "America/Glace_Bay" , 0x016B5A }, - { (char*) "America/Godthab" , 0x017411 }, - { (char*) "America/Goose_Bay" , 0x0179C5 }, - { (char*) "America/Grand_Turk" , 0x01867B }, - { (char*) "America/Grenada" , 0x018DB1 }, - { (char*) "America/Guadeloupe" , 0x018E51 }, - { (char*) "America/Guatemala" , 0x018EF1 }, - { (char*) "America/Guayaquil" , 0x019015 }, - { (char*) "America/Guyana" , 0x01911B }, - { (char*) "America/Halifax" , 0x01921F }, - { (char*) "America/Havana" , 0x019FA9 }, - { (char*) "America/Hermosillo" , 0x01A925 }, - { (char*) "America/Indiana/Indianapolis" , 0x01AAFF }, - { (char*) "America/Indiana/Knox" , 0x01B1B6 }, - { (char*) "America/Indiana/Marengo" , 0x01BB63 }, - { (char*) "America/Indiana/Petersburg" , 0x01C250 }, - { (char*) "America/Indiana/Tell_City" , 0x01C9EF }, - { (char*) "America/Indiana/Vevay" , 0x01D0B3 }, - { (char*) "America/Indiana/Vincennes" , 0x01D66F }, - { (char*) "America/Indiana/Winamac" , 0x01DD45 }, - { (char*) "America/Indianapolis" , 0x01E469 }, - { (char*) "America/Inuvik" , 0x01EB07 }, - { (char*) "America/Iqaluit" , 0x01F341 }, - { (char*) "America/Jamaica" , 0x01FC00 }, - { (char*) "America/Jujuy" , 0x01FDEE }, - { (char*) "America/Juneau" , 0x020204 }, - { (char*) "America/Kentucky/Louisville" , 0x020B55 }, - { (char*) "America/Kentucky/Monticello" , 0x021663 }, - { (char*) "America/Knox_IN" , 0x021FC3 }, - { (char*) "America/Kralendijk" , 0x02295B }, - { (char*) "America/La_Paz" , 0x022A5D }, - { (char*) "America/Lima" , 0x022B43 }, - { (char*) "America/Los_Angeles" , 0x022CD7 }, - { (char*) "America/Louisville" , 0x02380E }, - { (char*) "America/Lower_Princes" , 0x0242FE }, - { (char*) "America/Maceio" , 0x024400 }, - { (char*) "America/Managua" , 0x0246F6 }, - { (char*) "America/Manaus" , 0x0248B0 }, - { (char*) "America/Marigot" , 0x024B19 }, - { (char*) "America/Martinique" , 0x024C1B }, - { (char*) "America/Matamoros" , 0x024D0F }, - { (char*) "America/Mazatlan" , 0x0252D1 }, - { (char*) "America/Mendoza" , 0x025777 }, - { (char*) "America/Menominee" , 0x025BA9 }, - { (char*) "America/Merida" , 0x0264B6 }, - { (char*) "America/Metlakatla" , 0x0268BF }, - { (char*) "America/Mexico_City" , 0x026E71 }, - { (char*) "America/Miquelon" , 0x027351 }, - { (char*) "America/Moncton" , 0x0279D1 }, - { (char*) "America/Monterrey" , 0x028647 }, - { (char*) "America/Montevideo" , 0x028A5D }, - { (char*) "America/Montreal" , 0x029041 }, - { (char*) "America/Montserrat" , 0x029DF3 }, - { (char*) "America/Nassau" , 0x029E93 }, - { (char*) "America/New_York" , 0x02A7F3 }, - { (char*) "America/Nipigon" , 0x02B5F3 }, - { (char*) "America/Nome" , 0x02C3A5 }, - { (char*) "America/Noronha" , 0x02CCFD }, - { (char*) "America/North_Dakota/Beulah" , 0x02CFD7 }, - { (char*) "America/North_Dakota/Center" , 0x02D954 }, - { (char*) "America/North_Dakota/New_Salem" , 0x02E2D1 }, - { (char*) "America/Nuuk" , 0x02EC54 }, - { (char*) "America/Ojinaga" , 0x02F21E }, - { (char*) "America/Panama" , 0x02F83A }, - { (char*) "America/Pangnirtung" , 0x02F8FC }, - { (char*) "America/Paramaribo" , 0x0301A2 }, - { (char*) "America/Phoenix" , 0x0302A6 }, - { (char*) "America/Port-au-Prince" , 0x030437 }, - { (char*) "America/Port_of_Spain" , 0x0309DD }, - { (char*) "America/Porto_Acre" , 0x030A7D }, - { (char*) "America/Porto_Velho" , 0x030CEF }, - { (char*) "America/Puerto_Rico" , 0x030F35 }, - { (char*) "America/Punta_Arenas" , 0x031037 }, - { (char*) "America/Rainy_River" , 0x0317C5 }, - { (char*) "America/Rankin_Inlet" , 0x032305 }, - { (char*) "America/Recife" , 0x032B39 }, - { (char*) "America/Regina" , 0x032E0D }, - { (char*) "America/Resolute" , 0x033202 }, - { (char*) "America/Rio_Branco" , 0x033A37 }, - { (char*) "America/Rosario" , 0x033CAD }, - { (char*) "America/Santa_Isabel" , 0x0340DF }, - { (char*) "America/Santarem" , 0x034A31 }, - { (char*) "America/Santiago" , 0x034C94 }, - { (char*) "America/Santo_Domingo" , 0x035685 }, - { (char*) "America/Sao_Paulo" , 0x03585B }, - { (char*) "America/Scoresbysund" , 0x035E33 }, - { (char*) "America/Shiprock" , 0x0365CA }, - { (char*) "America/Sitka" , 0x036F72 }, - { (char*) "America/St_Barthelemy" , 0x0378AA }, - { (char*) "America/St_Johns" , 0x0379AC }, - { (char*) "America/St_Kitts" , 0x038821 }, - { (char*) "America/St_Lucia" , 0x0388C1 }, - { (char*) "America/St_Thomas" , 0x038983 }, - { (char*) "America/St_Vincent" , 0x038A23 }, - { (char*) "America/Swift_Current" , 0x038AE5 }, - { (char*) "America/Tegucigalpa" , 0x038D33 }, - { (char*) "America/Thule" , 0x038E3B }, - { (char*) "America/Thunder_Bay" , 0x039433 }, - { (char*) "America/Tijuana" , 0x03A1E5 }, - { (char*) "America/Toronto" , 0x03AB46 }, - { (char*) "America/Tortola" , 0x03B915 }, - { (char*) "America/Vancouver" , 0x03B9B5 }, - { (char*) "America/Virgin" , 0x03C526 }, - { (char*) "America/Whitehorse" , 0x03C628 }, - { (char*) "America/Winnipeg" , 0x03CC94 }, - { (char*) "America/Yakutat" , 0x03D7F1 }, - { (char*) "America/Yellowknife" , 0x03E10E }, - { (char*) "Antarctica/Casey" , 0x03E989 }, - { (char*) "Antarctica/Davis" , 0x03EB0C }, - { (char*) "Antarctica/DumontDUrville" , 0x03EC38 }, - { (char*) "Antarctica/Macquarie" , 0x03ED08 }, - { (char*) "Antarctica/Mawson" , 0x03F5F8 }, - { (char*) "Antarctica/McMurdo" , 0x03F6C3 }, - { (char*) "Antarctica/Palmer" , 0x03FEBE }, - { (char*) "Antarctica/Rothera" , 0x04044C }, - { (char*) "Antarctica/South_Pole" , 0x0404F5 }, - { (char*) "Antarctica/Syowa" , 0x040E86 }, - { (char*) "Antarctica/Troll" , 0x040F2E }, - { (char*) "Antarctica/Vostok" , 0x0413BB }, - { (char*) "Arctic/Longyearbyen" , 0x041464 }, - { (char*) "Asia/Aden" , 0x041D6A }, - { (char*) "Asia/Almaty" , 0x041E0D }, - { (char*) "Asia/Amman" , 0x042207 }, - { (char*) "Asia/Anadyr" , 0x0427AC }, - { (char*) "Asia/Aqtau" , 0x042C61 }, - { (char*) "Asia/Aqtobe" , 0x04304B }, - { (char*) "Asia/Ashgabat" , 0x043449 }, - { (char*) "Asia/Ashkhabad" , 0x0436B2 }, - { (char*) "Asia/Atyrau" , 0x04391B }, - { (char*) "Asia/Baghdad" , 0x043D0D }, - { (char*) "Asia/Bahrain" , 0x0440E2 }, - { (char*) "Asia/Baku" , 0x0441CD }, - { (char*) "Asia/Bangkok" , 0x044696 }, - { (char*) "Asia/Barnaul" , 0x04475B }, - { (char*) "Asia/Beirut" , 0x044C2C }, - { (char*) "Asia/Bishkek" , 0x0454A2 }, - { (char*) "Asia/Brunei" , 0x045877 }, - { (char*) "Asia/Calcutta" , 0x045940 }, - { (char*) "Asia/Chita" , 0x045A69 }, - { (char*) "Asia/Choibalsan" , 0x045F40 }, - { (char*) "Asia/Chongqing" , 0x046305 }, - { (char*) "Asia/Chungking" , 0x046542 }, - { (char*) "Asia/Colombo" , 0x04677F }, - { (char*) "Asia/Dacca" , 0x0468F1 }, - { (char*) "Asia/Damascus" , 0x046A40 }, - { (char*) "Asia/Dhaka" , 0x04719D }, - { (char*) "Asia/Dili" , 0x0472EC }, - { (char*) "Asia/Dubai" , 0x0473CD }, - { (char*) "Asia/Dushanbe" , 0x047470 }, - { (char*) "Asia/Famagusta" , 0x0476BD }, - { (char*) "Asia/Gaza" , 0x047EC4 }, - { (char*) "Asia/Harbin" , 0x048850 }, - { (char*) "Asia/Hebron" , 0x048A8D }, - { (char*) "Asia/Ho_Chi_Minh" , 0x049434 }, - { (char*) "Asia/Hong_Kong" , 0x049591 }, - { (char*) "Asia/Hovd" , 0x049A6E }, - { (char*) "Asia/Irkutsk" , 0x049E12 }, - { (char*) "Asia/Istanbul" , 0x04A305 }, - { (char*) "Asia/Jakarta" , 0x04AA9E }, - { (char*) "Asia/Jayapura" , 0x04AC36 }, - { (char*) "Asia/Jerusalem" , 0x04AD55 }, - { (char*) "Asia/Kabul" , 0x04B6B5 }, - { (char*) "Asia/Kamchatka" , 0x04B783 }, - { (char*) "Asia/Karachi" , 0x04BC21 }, - { (char*) "Asia/Kashgar" , 0x04BDA8 }, - { (char*) "Asia/Kathmandu" , 0x04BE4B }, - { (char*) "Asia/Katmandu" , 0x04BF1D }, - { (char*) "Asia/Khandyga" , 0x04BFEF }, - { (char*) "Asia/Kolkata" , 0x04C502 }, - { (char*) "Asia/Krasnoyarsk" , 0x04C62B }, - { (char*) "Asia/Kuala_Lumpur" , 0x04CAF9 }, - { (char*) "Asia/Kuching" , 0x04CCAA }, - { (char*) "Asia/Kuwait" , 0x04CE99 }, - { (char*) "Asia/Macao" , 0x04CF3C }, - { (char*) "Asia/Macau" , 0x04D413 }, - { (char*) "Asia/Magadan" , 0x04D8EA }, - { (char*) "Asia/Makassar" , 0x04DDBE }, - { (char*) "Asia/Manila" , 0x04DF11 }, - { (char*) "Asia/Muscat" , 0x04E065 }, - { (char*) "Asia/Nicosia" , 0x04E108 }, - { (char*) "Asia/Novokuznetsk" , 0x04E8F9 }, - { (char*) "Asia/Novosibirsk" , 0x04ED95 }, - { (char*) "Asia/Omsk" , 0x04F26C }, - { (char*) "Asia/Oral" , 0x04F72E }, - { (char*) "Asia/Phnom_Penh" , 0x04FB28 }, - { (char*) "Asia/Pontianak" , 0x04FC4D }, - { (char*) "Asia/Pyongyang" , 0x04FDD0 }, - { (char*) "Asia/Qatar" , 0x04FEC9 }, - { (char*) "Asia/Qostanay" , 0x04FF8E }, - { (char*) "Asia/Qyzylorda" , 0x050399 }, - { (char*) "Asia/Rangoon" , 0x0507B5 }, - { (char*) "Asia/Riyadh" , 0x0508BF }, - { (char*) "Asia/Saigon" , 0x050962 }, - { (char*) "Asia/Sakhalin" , 0x050ABF }, - { (char*) "Asia/Samarkand" , 0x050F87 }, - { (char*) "Asia/Seoul" , 0x0511D7 }, - { (char*) "Asia/Shanghai" , 0x05144C }, - { (char*) "Asia/Singapore" , 0x051695 }, - { (char*) "Asia/Srednekolymsk" , 0x051832 }, - { (char*) "Asia/Taipei" , 0x051D0A }, - { (char*) "Asia/Tashkent" , 0x05200F }, - { (char*) "Asia/Tbilisi" , 0x05226D }, - { (char*) "Asia/Tehran" , 0x052676 }, - { (char*) "Asia/Tel_Aviv" , 0x052B62 }, - { (char*) "Asia/Thimbu" , 0x0534C2 }, - { (char*) "Asia/Thimphu" , 0x05358B }, - { (char*) "Asia/Tokyo" , 0x053654 }, - { (char*) "Asia/Tomsk" , 0x053795 }, - { (char*) "Asia/Ujung_Pandang" , 0x053C66 }, - { (char*) "Asia/Ulaanbaatar" , 0x053D70 }, - { (char*) "Asia/Ulan_Bator" , 0x0540FE }, - { (char*) "Asia/Urumqi" , 0x054477 }, - { (char*) "Asia/Ust-Nera" , 0x054527 }, - { (char*) "Asia/Vientiane" , 0x054A1D }, - { (char*) "Asia/Vladivostok" , 0x054B5E }, - { (char*) "Asia/Yakutsk" , 0x055027 }, - { (char*) "Asia/Yangon" , 0x0554EF }, - { (char*) "Asia/Yekaterinburg" , 0x0555F9 }, - { (char*) "Asia/Yerevan" , 0x055AE0 }, - { (char*) "Atlantic/Azores" , 0x055F5D }, - { (char*) "Atlantic/Bermuda" , 0x056D19 }, - { (char*) "Atlantic/Canary" , 0x057681 }, - { (char*) "Atlantic/Cape_Verde" , 0x057E04 }, - { (char*) "Atlantic/Faeroe" , 0x057F10 }, - { (char*) "Atlantic/Faroe" , 0x058633 }, - { (char*) "Atlantic/Jan_Mayen" , 0x058D56 }, - { (char*) "Atlantic/Madeira" , 0x05965C }, - { (char*) "Atlantic/Reykjavik" , 0x05A426 }, - { (char*) "Atlantic/South_Georgia" , 0x05A8BC }, - { (char*) "Atlantic/St_Helena" , 0x05A95E }, - { (char*) "Atlantic/Stanley" , 0x05AA20 }, - { (char*) "Australia/ACT" , 0x05AEDC }, - { (char*) "Australia/Adelaide" , 0x05B776 }, - { (char*) "Australia/Brisbane" , 0x05C031 }, - { (char*) "Australia/Broken_Hill" , 0x05C1F7 }, - { (char*) "Australia/Canberra" , 0x05CAD4 }, - { (char*) "Australia/Currie" , 0x05D36E }, - { (char*) "Australia/Darwin" , 0x05DCB0 }, - { (char*) "Australia/Eucla" , 0x05DE13 }, - { (char*) "Australia/Hobart" , 0x05E000 }, - { (char*) "Australia/LHI" , 0x05E94A }, - { (char*) "Australia/Lindeman" , 0x05F08C }, - { (char*) "Australia/Lord_Howe" , 0x05F292 }, - { (char*) "Australia/Melbourne" , 0x05F9E4 }, - { (char*) "Australia/North" , 0x060286 }, - { (char*) "Australia/NSW" , 0x0603D7 }, - { (char*) "Australia/Perth" , 0x060C71 }, - { (char*) "Australia/Queensland" , 0x060E59 }, - { (char*) "Australia/South" , 0x061008 }, - { (char*) "Australia/Sydney" , 0x0618B4 }, - { (char*) "Australia/Tasmania" , 0x06216A }, - { (char*) "Australia/Victoria" , 0x062AAC }, - { (char*) "Australia/West" , 0x063346 }, - { (char*) "Australia/Yancowinna" , 0x063510 }, - { (char*) "Brazil/Acre" , 0x063DD1 }, - { (char*) "Brazil/DeNoronha" , 0x064043 }, - { (char*) "Brazil/East" , 0x06430D }, - { (char*) "Brazil/West" , 0x0648AF }, - { (char*) "Canada/Atlantic" , 0x064B09 }, - { (char*) "Canada/Central" , 0x065875 }, - { (char*) "Canada/Eastern" , 0x0663B5 }, - { (char*) "Canada/Mountain" , 0x067167 }, - { (char*) "Canada/Newfoundland" , 0x067A8F }, - { (char*) "Canada/Pacific" , 0x0688E2 }, - { (char*) "Canada/Saskatchewan" , 0x06943A }, - { (char*) "Canada/Yukon" , 0x06981A }, - { (char*) "CET" , 0x069E74 }, - { (char*) "Chile/Continental" , 0x06A6AE }, - { (char*) "Chile/EasterIsland" , 0x06B08D }, - { (char*) "CST6CDT" , 0x06B944 }, - { (char*) "Cuba" , 0x06C256 }, - { (char*) "EET" , 0x06CBD2 }, - { (char*) "Egypt" , 0x06D352 }, - { (char*) "Eire" , 0x06DB01 }, - { (char*) "EST" , 0x06E8B1 }, - { (char*) "EST5EDT" , 0x06E92F }, - { (char*) "Etc/GMT" , 0x06F241 }, - { (char*) "Etc/GMT+0" , 0x06F2BF }, - { (char*) "Etc/GMT+1" , 0x06F33D }, - { (char*) "Etc/GMT+10" , 0x06F3BD }, - { (char*) "Etc/GMT+11" , 0x06F43E }, - { (char*) "Etc/GMT+12" , 0x06F4BF }, - { (char*) "Etc/GMT+2" , 0x06F540 }, - { (char*) "Etc/GMT+3" , 0x06F5C0 }, - { (char*) "Etc/GMT+4" , 0x06F640 }, - { (char*) "Etc/GMT+5" , 0x06F6C0 }, - { (char*) "Etc/GMT+6" , 0x06F740 }, - { (char*) "Etc/GMT+7" , 0x06F7C0 }, - { (char*) "Etc/GMT+8" , 0x06F840 }, - { (char*) "Etc/GMT+9" , 0x06F8C0 }, - { (char*) "Etc/GMT-0" , 0x06F940 }, - { (char*) "Etc/GMT-1" , 0x06F9BE }, - { (char*) "Etc/GMT-10" , 0x06FA3F }, - { (char*) "Etc/GMT-11" , 0x06FAC1 }, - { (char*) "Etc/GMT-12" , 0x06FB43 }, - { (char*) "Etc/GMT-13" , 0x06FBC5 }, - { (char*) "Etc/GMT-14" , 0x06FC47 }, - { (char*) "Etc/GMT-2" , 0x06FCC9 }, - { (char*) "Etc/GMT-3" , 0x06FD4A }, - { (char*) "Etc/GMT-4" , 0x06FDCB }, - { (char*) "Etc/GMT-5" , 0x06FE4C }, - { (char*) "Etc/GMT-6" , 0x06FECD }, - { (char*) "Etc/GMT-7" , 0x06FF4E }, - { (char*) "Etc/GMT-8" , 0x06FFCF }, - { (char*) "Etc/GMT-9" , 0x070050 }, - { (char*) "Etc/GMT0" , 0x0700D1 }, - { (char*) "Etc/Greenwich" , 0x07014F }, - { (char*) "Etc/UCT" , 0x0701CD }, - { (char*) "Etc/Universal" , 0x07024B }, - { (char*) "Etc/UTC" , 0x0702C9 }, - { (char*) "Etc/Zulu" , 0x070347 }, - { (char*) "Europe/Amsterdam" , 0x0703C5 }, - { (char*) "Europe/Andorra" , 0x070F2F }, - { (char*) "Europe/Astrakhan" , 0x071609 }, - { (char*) "Europe/Athens" , 0x071AA6 }, - { (char*) "Europe/Belfast" , 0x072388 }, - { (char*) "Europe/Belgrade" , 0x0731E4 }, - { (char*) "Europe/Berlin" , 0x073970 }, - { (char*) "Europe/Bratislava" , 0x07428A }, - { (char*) "Europe/Brussels" , 0x074B93 }, - { (char*) "Europe/Bucharest" , 0x075714 }, - { (char*) "Europe/Budapest" , 0x075FA8 }, - { (char*) "Europe/Busingen" , 0x0768F4 }, - { (char*) "Europe/Chisinau" , 0x07707D }, - { (char*) "Europe/Copenhagen" , 0x0779DF }, - { (char*) "Europe/Dublin" , 0x078244 }, - { (char*) "Europe/Gibraltar" , 0x078FF4 }, - { (char*) "Europe/Guernsey" , 0x079BFC }, - { (char*) "Europe/Helsinki" , 0x07AA9C }, - { (char*) "Europe/Isle_of_Man" , 0x07B214 }, - { (char*) "Europe/Istanbul" , 0x07C060 }, - { (char*) "Europe/Jersey" , 0x07C7F9 }, - { (char*) "Europe/Kaliningrad" , 0x07D699 }, - { (char*) "Europe/Kiev" , 0x07DC8E }, - { (char*) "Europe/Kirov" , 0x07E4E2 }, - { (char*) "Europe/Kyiv" , 0x07E96F }, - { (char*) "Europe/Lisbon" , 0x07F1D7 }, - { (char*) "Europe/Ljubljana" , 0x07FF9F }, - { (char*) "Europe/London" , 0x08072B }, - { (char*) "Europe/Luxembourg" , 0x081587 }, - { (char*) "Europe/Madrid" , 0x082115 }, - { (char*) "Europe/Malta" , 0x082B67 }, - { (char*) "Europe/Mariehamn" , 0x0835AF }, - { (char*) "Europe/Minsk" , 0x083D27 }, - { (char*) "Europe/Monaco" , 0x08424E }, - { (char*) "Europe/Moscow" , 0x084DDA }, - { (char*) "Europe/Nicosia" , 0x0853F9 }, - { (char*) "Europe/Oslo" , 0x085BD7 }, - { (char*) "Europe/Paris" , 0x086497 }, - { (char*) "Europe/Podgorica" , 0x087035 }, - { (char*) "Europe/Prague" , 0x0877C1 }, - { (char*) "Europe/Riga" , 0x0880CA }, - { (char*) "Europe/Rome" , 0x08896C }, - { (char*) "Europe/Samara" , 0x0893C9 }, - { (char*) "Europe/San_Marino" , 0x08989F }, - { (char*) "Europe/Sarajevo" , 0x08A2FC }, - { (char*) "Europe/Saratov" , 0x08AA88 }, - { (char*) "Europe/Simferopol" , 0x08AF35 }, - { (char*) "Europe/Skopje" , 0x08B504 }, - { (char*) "Europe/Sofia" , 0x08BC90 }, - { (char*) "Europe/Stockholm" , 0x08C4B9 }, - { (char*) "Europe/Tallinn" , 0x08CC3A }, - { (char*) "Europe/Tirane" , 0x08D4AA }, - { (char*) "Europe/Tiraspol" , 0x08DCDA }, - { (char*) "Europe/Ulyanovsk" , 0x08E63C }, - { (char*) "Europe/Uzhgorod" , 0x08EB3F }, - { (char*) "Europe/Vaduz" , 0x08F393 }, - { (char*) "Europe/Vatican" , 0x08FAFF }, - { (char*) "Europe/Vienna" , 0x09055C }, - { (char*) "Europe/Vilnius" , 0x090E00 }, - { (char*) "Europe/Volgograd" , 0x09167E }, - { (char*) "Europe/Warsaw" , 0x091B1B }, - { (char*) "Europe/Zagreb" , 0x092585 }, - { (char*) "Europe/Zaporozhye" , 0x092D11 }, - { (char*) "Europe/Zurich" , 0x093565 }, - { (char*) "Factory" , 0x093CE6 }, - { (char*) "GB" , 0x093D66 }, - { (char*) "GB-Eire" , 0x094BC2 }, - { (char*) "GMT" , 0x095A1E }, - { (char*) "GMT+0" , 0x095A9C }, - { (char*) "GMT-0" , 0x095B1A }, - { (char*) "GMT0" , 0x095B98 }, - { (char*) "Greenwich" , 0x095C16 }, - { (char*) "Hongkong" , 0x095C94 }, - { (char*) "HST" , 0x096171 }, - { (char*) "Iceland" , 0x0961F0 }, - { (char*) "Indian/Antananarivo" , 0x096290 }, - { (char*) "Indian/Chagos" , 0x096377 }, - { (char*) "Indian/Christmas" , 0x09643C }, - { (char*) "Indian/Cocos" , 0x0964DF }, - { (char*) "Indian/Comoro" , 0x09658B }, - { (char*) "Indian/Kerguelen" , 0x09662C }, - { (char*) "Indian/Mahe" , 0x0966CF }, - { (char*) "Indian/Maldives" , 0x096772 }, - { (char*) "Indian/Mauritius" , 0x096837 }, - { (char*) "Indian/Mayotte" , 0x096926 }, - { (char*) "Indian/Reunion" , 0x0969C7 }, - { (char*) "Iran" , 0x096A6A }, - { (char*) "Israel" , 0x096F56 }, - { (char*) "Jamaica" , 0x0978B6 }, - { (char*) "Japan" , 0x097AA4 }, - { (char*) "Kwajalein" , 0x097BE5 }, - { (char*) "Libya" , 0x097D1F }, - { (char*) "MET" , 0x097F9C }, - { (char*) "Mexico/BajaNorte" , 0x0987D6 }, - { (char*) "Mexico/BajaSur" , 0x099128 }, - { (char*) "Mexico/General" , 0x09959C }, - { (char*) "MST" , 0x099A6E }, - { (char*) "MST7MDT" , 0x099AEC }, - { (char*) "Navajo" , 0x09A3FE }, - { (char*) "NZ" , 0x09ADA6 }, - { (char*) "NZ-CHAT" , 0x09B737 }, - { (char*) "Pacific/Apia" , 0x09BF49 }, - { (char*) "Pacific/Auckland" , 0x09C1AB }, - { (char*) "Pacific/Bougainville" , 0x09CB54 }, - { (char*) "Pacific/Chatham" , 0x09CC6A }, - { (char*) "Pacific/Chuuk" , 0x09D48B }, - { (char*) "Pacific/Easter" , 0x09D5A5 }, - { (char*) "Pacific/Efate" , 0x09DE69 }, - { (char*) "Pacific/Enderbury" , 0x09E081 }, - { (char*) "Pacific/Fakaofo" , 0x09E169 }, - { (char*) "Pacific/Fiji" , 0x09E22F }, - { (char*) "Pacific/Funafuti" , 0x09E46F }, - { (char*) "Pacific/Galapagos" , 0x09E513 }, - { (char*) "Pacific/Gambier" , 0x09E610 }, - { (char*) "Pacific/Guadalcanal" , 0x09E6C1 }, - { (char*) "Pacific/Guam" , 0x09E765 }, - { (char*) "Pacific/Honolulu" , 0x09E95F }, - { (char*) "Pacific/Johnston" , 0x09EABA }, - { (char*) "Pacific/Kanton" , 0x09EC0F }, - { (char*) "Pacific/Kiritimati" , 0x09ED06 }, - { (char*) "Pacific/Kosrae" , 0x09EDFE }, - { (char*) "Pacific/Kwajalein" , 0x09EF61 }, - { (char*) "Pacific/Majuro" , 0x09F0A4 }, - { (char*) "Pacific/Marquesas" , 0x09F1F5 }, - { (char*) "Pacific/Midway" , 0x09F2B1 }, - { (char*) "Pacific/Nauru" , 0x09F3A4 }, - { (char*) "Pacific/Niue" , 0x09F49E }, - { (char*) "Pacific/Norfolk" , 0x09F567 }, - { (char*) "Pacific/Noumea" , 0x09F8D5 }, - { (char*) "Pacific/Pago_Pago" , 0x09FA03 }, - { (char*) "Pacific/Palau" , 0x09FABE }, - { (char*) "Pacific/Pitcairn" , 0x09FB70 }, - { (char*) "Pacific/Pohnpei" , 0x09FC38 }, - { (char*) "Pacific/Ponape" , 0x09FD73 }, - { (char*) "Pacific/Port_Moresby" , 0x09FE17 }, - { (char*) "Pacific/Rarotonga" , 0x09FEEC }, - { (char*) "Pacific/Saipan" , 0x0A0145 }, - { (char*) "Pacific/Samoa" , 0x0A0331 }, - { (char*) "Pacific/Tahiti" , 0x0A03EC }, - { (char*) "Pacific/Tarawa" , 0x0A049E }, - { (char*) "Pacific/Tongatapu" , 0x0A0551 }, - { (char*) "Pacific/Truk" , 0x0A06C3 }, - { (char*) "Pacific/Wake" , 0x0A077B }, - { (char*) "Pacific/Wallis" , 0x0A082A }, - { (char*) "Pacific/Yap" , 0x0A08CE }, - { (char*) "Poland" , 0x0A0986 }, - { (char*) "Portugal" , 0x0A13F0 }, - { (char*) "PRC" , 0x0A21A5 }, - { (char*) "PST8PDT" , 0x0A23E2 }, - { (char*) "ROC" , 0x0A2CF4 }, - { (char*) "ROK" , 0x0A2FF9 }, - { (char*) "Singapore" , 0x0A326E }, - { (char*) "Turkey" , 0x0A340B }, - { (char*) "UCT" , 0x0A3BA4 }, - { (char*) "Universal" , 0x0A3C22 }, - { (char*) "US/Alaska" , 0x0A3CA0 }, - { (char*) "US/Aleutian" , 0x0A45EF }, - { (char*) "US/Arizona" , 0x0A4F2F }, - { (char*) "US/Central" , 0x0A50A3 }, - { (char*) "US/East-Indiana" , 0x0A5EB7 }, - { (char*) "US/Eastern" , 0x0A6555 }, - { (char*) "US/Hawaii" , 0x0A7341 }, - { (char*) "US/Indiana-Starke" , 0x0A7496 }, - { (char*) "US/Michigan" , 0x0A7E2E }, - { (char*) "US/Mountain" , 0x0A86F0 }, - { (char*) "US/Pacific" , 0x0A9098 }, - { (char*) "US/Samoa" , 0x0A9BC8 }, - { (char*) "UTC" , 0x0A9C83 }, - { (char*) "W-SU" , 0x0A9D01 }, - { (char*) "WET" , 0x0AA30C }, - { (char*) "Zulu" , 0x0AAA89 }, + { (char*) "Africa/Casablanca" , 0x001926 }, + { (char*) "Africa/Ceuta" , 0x0022AF }, + { (char*) "Africa/Conakry" , 0x002ACD }, + { (char*) "Africa/Dakar" , 0x002BA9 }, + { (char*) "Africa/Dar_es_Salaam" , 0x002C6B }, + { (char*) "Africa/Djibouti" , 0x002D4C }, + { (char*) "Africa/Douala" , 0x002DED }, + { (char*) "Africa/El_Aaiun" , 0x002E8E }, + { (char*) "Africa/Freetown" , 0x003791 }, + { (char*) "Africa/Gaborone" , 0x00396D }, + { (char*) "Africa/Harare" , 0x003A64 }, + { (char*) "Africa/Johannesburg" , 0x003B05 }, + { (char*) "Africa/Juba" , 0x003C07 }, + { (char*) "Africa/Kampala" , 0x003EBA }, + { (char*) "Africa/Khartoum" , 0x003FC1 }, + { (char*) "Africa/Kigali" , 0x004274 }, + { (char*) "Africa/Kinshasa" , 0x004315 }, + { (char*) "Africa/Lagos" , 0x0043CF }, + { (char*) "Africa/Libreville" , 0x0044C6 }, + { (char*) "Africa/Lome" , 0x004567 }, + { (char*) "Africa/Luanda" , 0x004607 }, + { (char*) "Africa/Lubumbashi" , 0x0046CE }, + { (char*) "Africa/Lusaka" , 0x0047AA }, + { (char*) "Africa/Malabo" , 0x00484B }, + { (char*) "Africa/Maputo" , 0x00490E }, + { (char*) "Africa/Maseru" , 0x0049AF }, + { (char*) "Africa/Mbabane" , 0x004A7B }, + { (char*) "Africa/Mogadishu" , 0x004B1F }, + { (char*) "Africa/Monrovia" , 0x004C00 }, + { (char*) "Africa/Nairobi" , 0x004CDC }, + { (char*) "Africa/Ndjamena" , 0x004DF1 }, + { (char*) "Africa/Niamey" , 0x004EC4 }, + { (char*) "Africa/Nouakchott" , 0x004FA9 }, + { (char*) "Africa/Ouagadougou" , 0x005085 }, + { (char*) "Africa/Porto-Novo" , 0x005125 }, + { (char*) "Africa/Sao_Tome" , 0x0051E8 }, + { (char*) "Africa/Timbuktu" , 0x0052F2 }, + { (char*) "Africa/Tripoli" , 0x005392 }, + { (char*) "Africa/Tunis" , 0x00560F }, + { (char*) "Africa/Windhoek" , 0x0058CC }, + { (char*) "America/Adak" , 0x005C93 }, + { (char*) "America/Anchorage" , 0x0065ED }, + { (char*) "America/Anguilla" , 0x006F4F }, + { (char*) "America/Antigua" , 0x006FEF }, + { (char*) "America/Araguaina" , 0x0070B1 }, + { (char*) "America/Argentina/Buenos_Aires" , 0x00742C }, + { (char*) "America/Argentina/Catamarca" , 0x007873 }, + { (char*) "America/Argentina/ComodRivadavia" , 0x007CC0 }, + { (char*) "America/Argentina/Cordoba" , 0x0080F2 }, + { (char*) "America/Argentina/Jujuy" , 0x00855A }, + { (char*) "America/Argentina/La_Rioja" , 0x00897A }, + { (char*) "America/Argentina/Mendoza" , 0x008DC7 }, + { (char*) "America/Argentina/Rio_Gallegos" , 0x009205 }, + { (char*) "America/Argentina/Salta" , 0x009646 }, + { (char*) "America/Argentina/San_Juan" , 0x009A72 }, + { (char*) "America/Argentina/San_Luis" , 0x009EBF }, + { (char*) "America/Argentina/Tucuman" , 0x00A318 }, + { (char*) "America/Argentina/Ushuaia" , 0x00A772 }, + { (char*) "America/Aruba" , 0x00ABB9 }, + { (char*) "America/Asuncion" , 0x00AC7F }, + { (char*) "America/Atikokan" , 0x00B479 }, + { (char*) "America/Atka" , 0x00B5F6 }, + { (char*) "America/Bahia" , 0x00BF36 }, + { (char*) "America/Bahia_Banderas" , 0x00C339 }, + { (char*) "America/Barbados" , 0x00C7D6 }, + { (char*) "America/Belem" , 0x00C996 }, + { (char*) "America/Belize" , 0x00CBE6 }, + { (char*) "America/Blanc-Sablon" , 0x00D240 }, + { (char*) "America/Boa_Vista" , 0x00D392 }, + { (char*) "America/Bogota" , 0x00D60F }, + { (char*) "America/Boise" , 0x00D703 }, + { (char*) "America/Buenos_Aires" , 0x00E099 }, + { (char*) "America/Cambridge_Bay" , 0x00E4CB }, + { (char*) "America/Campo_Grande" , 0x00EDB9 }, + { (char*) "America/Cancun" , 0x00F36D }, + { (char*) "America/Caracas" , 0x00F6C7 }, + { (char*) "America/Catamarca" , 0x00F7CD }, + { (char*) "America/Cayenne" , 0x00FBFF }, + { (char*) "America/Cayman" , 0x00FCC3 }, + { (char*) "America/Chicago" , 0x00FD85 }, + { (char*) "America/Chihuahua" , 0x010BAD }, + { (char*) "America/Ciudad_Juarez" , 0x01101D }, + { (char*) "America/Coral_Harbour" , 0x011647 }, + { (char*) "America/Cordoba" , 0x011709 }, + { (char*) "America/Costa_Rica" , 0x011B3B }, + { (char*) "America/Creston" , 0x011C83 }, + { (char*) "America/Cuiaba" , 0x011D71 }, + { (char*) "America/Curacao" , 0x012302 }, + { (char*) "America/Danmarkshavn" , 0x0123C8 }, + { (char*) "America/Dawson" , 0x0126A8 }, + { (char*) "America/Dawson_Creek" , 0x012D14 }, + { (char*) "America/Denver" , 0x01315A }, + { (char*) "America/Detroit" , 0x013B17 }, + { (char*) "America/Dominica" , 0x0143F2 }, + { (char*) "America/Edmonton" , 0x014492 }, + { (char*) "America/Eirunepe" , 0x014DDF }, + { (char*) "America/El_Salvador" , 0x01507C }, + { (char*) "America/Ensenada" , 0x015168 }, + { (char*) "America/Fort_Nelson" , 0x015ABA }, + { (char*) "America/Fort_Wayne" , 0x01639A }, + { (char*) "America/Fortaleza" , 0x016A38 }, + { (char*) "America/Glace_Bay" , 0x016D28 }, + { (char*) "America/Godthab" , 0x0175DF }, + { (char*) "America/Goose_Bay" , 0x017D5A }, + { (char*) "America/Grand_Turk" , 0x018A10 }, + { (char*) "America/Grenada" , 0x019146 }, + { (char*) "America/Guadeloupe" , 0x0191E6 }, + { (char*) "America/Guatemala" , 0x019286 }, + { (char*) "America/Guayaquil" , 0x0193AA }, + { (char*) "America/Guyana" , 0x0194B0 }, + { (char*) "America/Halifax" , 0x0195B4 }, + { (char*) "America/Havana" , 0x01A33E }, + { (char*) "America/Hermosillo" , 0x01ACBA }, + { (char*) "America/Indiana/Indianapolis" , 0x01AE94 }, + { (char*) "America/Indiana/Knox" , 0x01B54B }, + { (char*) "America/Indiana/Marengo" , 0x01BEF8 }, + { (char*) "America/Indiana/Petersburg" , 0x01C5E5 }, + { (char*) "America/Indiana/Tell_City" , 0x01CD84 }, + { (char*) "America/Indiana/Vevay" , 0x01D448 }, + { (char*) "America/Indiana/Vincennes" , 0x01DA04 }, + { (char*) "America/Indiana/Winamac" , 0x01E0DA }, + { (char*) "America/Indianapolis" , 0x01E7FE }, + { (char*) "America/Inuvik" , 0x01EE9C }, + { (char*) "America/Iqaluit" , 0x01F6D6 }, + { (char*) "America/Jamaica" , 0x01FF95 }, + { (char*) "America/Jujuy" , 0x020183 }, + { (char*) "America/Juneau" , 0x020599 }, + { (char*) "America/Kentucky/Louisville" , 0x020EEA }, + { (char*) "America/Kentucky/Monticello" , 0x0219F8 }, + { (char*) "America/Knox_IN" , 0x022358 }, + { (char*) "America/Kralendijk" , 0x022CF0 }, + { (char*) "America/La_Paz" , 0x022DF2 }, + { (char*) "America/Lima" , 0x022ED8 }, + { (char*) "America/Los_Angeles" , 0x02306C }, + { (char*) "America/Louisville" , 0x023BA3 }, + { (char*) "America/Lower_Princes" , 0x024693 }, + { (char*) "America/Maceio" , 0x024795 }, + { (char*) "America/Managua" , 0x024A8B }, + { (char*) "America/Manaus" , 0x024C45 }, + { (char*) "America/Marigot" , 0x024EAE }, + { (char*) "America/Martinique" , 0x024FB0 }, + { (char*) "America/Matamoros" , 0x0250A4 }, + { (char*) "America/Mazatlan" , 0x025666 }, + { (char*) "America/Mendoza" , 0x025B0C }, + { (char*) "America/Menominee" , 0x025F3E }, + { (char*) "America/Merida" , 0x02684B }, + { (char*) "America/Metlakatla" , 0x026C54 }, + { (char*) "America/Mexico_City" , 0x027206 }, + { (char*) "America/Miquelon" , 0x0276E6 }, + { (char*) "America/Moncton" , 0x027D66 }, + { (char*) "America/Monterrey" , 0x0289DC }, + { (char*) "America/Montevideo" , 0x028DF2 }, + { (char*) "America/Montreal" , 0x0293D6 }, + { (char*) "America/Montserrat" , 0x02A188 }, + { (char*) "America/Nassau" , 0x02A228 }, + { (char*) "America/New_York" , 0x02AB88 }, + { (char*) "America/Nipigon" , 0x02B988 }, + { (char*) "America/Nome" , 0x02C73A }, + { (char*) "America/Noronha" , 0x02D092 }, + { (char*) "America/North_Dakota/Beulah" , 0x02D36C }, + { (char*) "America/North_Dakota/Center" , 0x02DCE9 }, + { (char*) "America/North_Dakota/New_Salem" , 0x02E666 }, + { (char*) "America/Nuuk" , 0x02EFE9 }, + { (char*) "America/Ojinaga" , 0x02F775 }, + { (char*) "America/Panama" , 0x02FD91 }, + { (char*) "America/Pangnirtung" , 0x02FE53 }, + { (char*) "America/Paramaribo" , 0x0306F9 }, + { (char*) "America/Phoenix" , 0x0307FD }, + { (char*) "America/Port-au-Prince" , 0x030989 }, + { (char*) "America/Port_of_Spain" , 0x030F2F }, + { (char*) "America/Porto_Acre" , 0x030FCF }, + { (char*) "America/Porto_Velho" , 0x031241 }, + { (char*) "America/Puerto_Rico" , 0x031487 }, + { (char*) "America/Punta_Arenas" , 0x031589 }, + { (char*) "America/Rainy_River" , 0x031D17 }, + { (char*) "America/Rankin_Inlet" , 0x032857 }, + { (char*) "America/Recife" , 0x03308B }, + { (char*) "America/Regina" , 0x03335F }, + { (char*) "America/Resolute" , 0x033754 }, + { (char*) "America/Rio_Branco" , 0x033F89 }, + { (char*) "America/Rosario" , 0x0341FF }, + { (char*) "America/Santa_Isabel" , 0x034631 }, + { (char*) "America/Santarem" , 0x034F83 }, + { (char*) "America/Santiago" , 0x0351E6 }, + { (char*) "America/Santo_Domingo" , 0x035BD2 }, + { (char*) "America/Sao_Paulo" , 0x035DA8 }, + { (char*) "America/Scoresbysund" , 0x036380 }, + { (char*) "America/Shiprock" , 0x036B17 }, + { (char*) "America/Sitka" , 0x0374BF }, + { (char*) "America/St_Barthelemy" , 0x037DF7 }, + { (char*) "America/St_Johns" , 0x037EF9 }, + { (char*) "America/St_Kitts" , 0x038D6E }, + { (char*) "America/St_Lucia" , 0x038E0E }, + { (char*) "America/St_Thomas" , 0x038ED0 }, + { (char*) "America/St_Vincent" , 0x038F70 }, + { (char*) "America/Swift_Current" , 0x039032 }, + { (char*) "America/Tegucigalpa" , 0x039280 }, + { (char*) "America/Thule" , 0x039388 }, + { (char*) "America/Thunder_Bay" , 0x039980 }, + { (char*) "America/Tijuana" , 0x03A732 }, + { (char*) "America/Toronto" , 0x03B093 }, + { (char*) "America/Tortola" , 0x03BE62 }, + { (char*) "America/Vancouver" , 0x03BF02 }, + { (char*) "America/Virgin" , 0x03CA73 }, + { (char*) "America/Whitehorse" , 0x03CB75 }, + { (char*) "America/Winnipeg" , 0x03D1E1 }, + { (char*) "America/Yakutat" , 0x03DD3E }, + { (char*) "America/Yellowknife" , 0x03E65B }, + { (char*) "Antarctica/Casey" , 0x03EF83 }, + { (char*) "Antarctica/Davis" , 0x03F106 }, + { (char*) "Antarctica/DumontDUrville" , 0x03F232 }, + { (char*) "Antarctica/Macquarie" , 0x03F302 }, + { (char*) "Antarctica/Mawson" , 0x03FBF2 }, + { (char*) "Antarctica/McMurdo" , 0x03FCBD }, + { (char*) "Antarctica/Palmer" , 0x0404B8 }, + { (char*) "Antarctica/Rothera" , 0x040A46 }, + { (char*) "Antarctica/South_Pole" , 0x040AEF }, + { (char*) "Antarctica/Syowa" , 0x041480 }, + { (char*) "Antarctica/Troll" , 0x041528 }, + { (char*) "Antarctica/Vostok" , 0x0419B5 }, + { (char*) "Arctic/Longyearbyen" , 0x041A5E }, + { (char*) "Asia/Aden" , 0x042364 }, + { (char*) "Asia/Almaty" , 0x042407 }, + { (char*) "Asia/Amman" , 0x0427FC }, + { (char*) "Asia/Anadyr" , 0x042DA1 }, + { (char*) "Asia/Aqtau" , 0x043256 }, + { (char*) "Asia/Aqtobe" , 0x043640 }, + { (char*) "Asia/Ashgabat" , 0x043A3E }, + { (char*) "Asia/Ashkhabad" , 0x043CA7 }, + { (char*) "Asia/Atyrau" , 0x043F10 }, + { (char*) "Asia/Baghdad" , 0x044302 }, + { (char*) "Asia/Bahrain" , 0x0446D7 }, + { (char*) "Asia/Baku" , 0x0447C2 }, + { (char*) "Asia/Bangkok" , 0x044C8B }, + { (char*) "Asia/Barnaul" , 0x044D50 }, + { (char*) "Asia/Beirut" , 0x045221 }, + { (char*) "Asia/Bishkek" , 0x045A97 }, + { (char*) "Asia/Brunei" , 0x045E6C }, + { (char*) "Asia/Calcutta" , 0x045F35 }, + { (char*) "Asia/Chita" , 0x04605E }, + { (char*) "Asia/Choibalsan" , 0x046535 }, + { (char*) "Asia/Chongqing" , 0x0468FA }, + { (char*) "Asia/Chungking" , 0x046B37 }, + { (char*) "Asia/Colombo" , 0x046D74 }, + { (char*) "Asia/Dacca" , 0x046EE6 }, + { (char*) "Asia/Damascus" , 0x047035 }, + { (char*) "Asia/Dhaka" , 0x047792 }, + { (char*) "Asia/Dili" , 0x0478E1 }, + { (char*) "Asia/Dubai" , 0x0479C2 }, + { (char*) "Asia/Dushanbe" , 0x047A65 }, + { (char*) "Asia/Famagusta" , 0x047CB2 }, + { (char*) "Asia/Gaza" , 0x0484B9 }, + { (char*) "Asia/Harbin" , 0x0493AF }, + { (char*) "Asia/Hebron" , 0x0495EC }, + { (char*) "Asia/Ho_Chi_Minh" , 0x04A4FD }, + { (char*) "Asia/Hong_Kong" , 0x04A65A }, + { (char*) "Asia/Hovd" , 0x04AB37 }, + { (char*) "Asia/Irkutsk" , 0x04AEDB }, + { (char*) "Asia/Istanbul" , 0x04B3CE }, + { (char*) "Asia/Jakarta" , 0x04BB67 }, + { (char*) "Asia/Jayapura" , 0x04BCFF }, + { (char*) "Asia/Jerusalem" , 0x04BE1E }, + { (char*) "Asia/Kabul" , 0x04C77E }, + { (char*) "Asia/Kamchatka" , 0x04C84C }, + { (char*) "Asia/Karachi" , 0x04CCEA }, + { (char*) "Asia/Kashgar" , 0x04CE71 }, + { (char*) "Asia/Kathmandu" , 0x04CF14 }, + { (char*) "Asia/Katmandu" , 0x04CFE6 }, + { (char*) "Asia/Khandyga" , 0x04D0B8 }, + { (char*) "Asia/Kolkata" , 0x04D5CB }, + { (char*) "Asia/Krasnoyarsk" , 0x04D6F4 }, + { (char*) "Asia/Kuala_Lumpur" , 0x04DBC2 }, + { (char*) "Asia/Kuching" , 0x04DD73 }, + { (char*) "Asia/Kuwait" , 0x04DF62 }, + { (char*) "Asia/Macao" , 0x04E005 }, + { (char*) "Asia/Macau" , 0x04E4DC }, + { (char*) "Asia/Magadan" , 0x04E9B3 }, + { (char*) "Asia/Makassar" , 0x04EE87 }, + { (char*) "Asia/Manila" , 0x04EFDA }, + { (char*) "Asia/Muscat" , 0x04F12E }, + { (char*) "Asia/Nicosia" , 0x04F1D1 }, + { (char*) "Asia/Novokuznetsk" , 0x04F9BD }, + { (char*) "Asia/Novosibirsk" , 0x04FE59 }, + { (char*) "Asia/Omsk" , 0x050330 }, + { (char*) "Asia/Oral" , 0x0507F2 }, + { (char*) "Asia/Phnom_Penh" , 0x050BEC }, + { (char*) "Asia/Pontianak" , 0x050D11 }, + { (char*) "Asia/Pyongyang" , 0x050E94 }, + { (char*) "Asia/Qatar" , 0x050F8D }, + { (char*) "Asia/Qostanay" , 0x051052 }, + { (char*) "Asia/Qyzylorda" , 0x05145D }, + { (char*) "Asia/Rangoon" , 0x051879 }, + { (char*) "Asia/Riyadh" , 0x051983 }, + { (char*) "Asia/Saigon" , 0x051A26 }, + { (char*) "Asia/Sakhalin" , 0x051B83 }, + { (char*) "Asia/Samarkand" , 0x05204B }, + { (char*) "Asia/Seoul" , 0x05229B }, + { (char*) "Asia/Shanghai" , 0x052510 }, + { (char*) "Asia/Singapore" , 0x052759 }, + { (char*) "Asia/Srednekolymsk" , 0x0528F6 }, + { (char*) "Asia/Taipei" , 0x052DCA }, + { (char*) "Asia/Tashkent" , 0x0530CF }, + { (char*) "Asia/Tbilisi" , 0x05332D }, + { (char*) "Asia/Tehran" , 0x053736 }, + { (char*) "Asia/Tel_Aviv" , 0x053C22 }, + { (char*) "Asia/Thimbu" , 0x054582 }, + { (char*) "Asia/Thimphu" , 0x05464B }, + { (char*) "Asia/Tokyo" , 0x054714 }, + { (char*) "Asia/Tomsk" , 0x054855 }, + { (char*) "Asia/Ujung_Pandang" , 0x054D26 }, + { (char*) "Asia/Ulaanbaatar" , 0x054E30 }, + { (char*) "Asia/Ulan_Bator" , 0x0551B9 }, + { (char*) "Asia/Urumqi" , 0x055532 }, + { (char*) "Asia/Ust-Nera" , 0x0555E2 }, + { (char*) "Asia/Vientiane" , 0x055AD8 }, + { (char*) "Asia/Vladivostok" , 0x055C19 }, + { (char*) "Asia/Yakutsk" , 0x0560E2 }, + { (char*) "Asia/Yangon" , 0x0565AA }, + { (char*) "Asia/Yekaterinburg" , 0x0566B4 }, + { (char*) "Asia/Yerevan" , 0x056B9B }, + { (char*) "Atlantic/Azores" , 0x057018 }, + { (char*) "Atlantic/Bermuda" , 0x057DD4 }, + { (char*) "Atlantic/Canary" , 0x05873C }, + { (char*) "Atlantic/Cape_Verde" , 0x058EBF }, + { (char*) "Atlantic/Faeroe" , 0x058FCB }, + { (char*) "Atlantic/Faroe" , 0x0596EE }, + { (char*) "Atlantic/Jan_Mayen" , 0x059E11 }, + { (char*) "Atlantic/Madeira" , 0x05A717 }, + { (char*) "Atlantic/Reykjavik" , 0x05B4E1 }, + { (char*) "Atlantic/South_Georgia" , 0x05B977 }, + { (char*) "Atlantic/St_Helena" , 0x05BA19 }, + { (char*) "Atlantic/Stanley" , 0x05BADB }, + { (char*) "Australia/ACT" , 0x05BF97 }, + { (char*) "Australia/Adelaide" , 0x05C831 }, + { (char*) "Australia/Brisbane" , 0x05D0EC }, + { (char*) "Australia/Broken_Hill" , 0x05D2B2 }, + { (char*) "Australia/Canberra" , 0x05DB8F }, + { (char*) "Australia/Currie" , 0x05E429 }, + { (char*) "Australia/Darwin" , 0x05ED6B }, + { (char*) "Australia/Eucla" , 0x05EECE }, + { (char*) "Australia/Hobart" , 0x05F0BB }, + { (char*) "Australia/LHI" , 0x05FA05 }, + { (char*) "Australia/Lindeman" , 0x060147 }, + { (char*) "Australia/Lord_Howe" , 0x06034D }, + { (char*) "Australia/Melbourne" , 0x060A9F }, + { (char*) "Australia/North" , 0x061341 }, + { (char*) "Australia/NSW" , 0x061492 }, + { (char*) "Australia/Perth" , 0x061D2C }, + { (char*) "Australia/Queensland" , 0x061F14 }, + { (char*) "Australia/South" , 0x0620C3 }, + { (char*) "Australia/Sydney" , 0x06296F }, + { (char*) "Australia/Tasmania" , 0x063225 }, + { (char*) "Australia/Victoria" , 0x063B67 }, + { (char*) "Australia/West" , 0x064401 }, + { (char*) "Australia/Yancowinna" , 0x0645CB }, + { (char*) "Brazil/Acre" , 0x064E8C }, + { (char*) "Brazil/DeNoronha" , 0x0650FE }, + { (char*) "Brazil/East" , 0x0653C8 }, + { (char*) "Brazil/West" , 0x06596A }, + { (char*) "Canada/Atlantic" , 0x065BC4 }, + { (char*) "Canada/Central" , 0x066930 }, + { (char*) "Canada/Eastern" , 0x067470 }, + { (char*) "Canada/Mountain" , 0x068222 }, + { (char*) "Canada/Newfoundland" , 0x068B4A }, + { (char*) "Canada/Pacific" , 0x06999D }, + { (char*) "Canada/Saskatchewan" , 0x06A4F5 }, + { (char*) "Canada/Yukon" , 0x06A8D5 }, + { (char*) "CET" , 0x06AF2F }, + { (char*) "Chile/Continental" , 0x06B769 }, + { (char*) "Chile/EasterIsland" , 0x06C148 }, + { (char*) "CST6CDT" , 0x06C9FF }, + { (char*) "Cuba" , 0x06D311 }, + { (char*) "EET" , 0x06DC8D }, + { (char*) "Egypt" , 0x06E40D }, + { (char*) "Eire" , 0x06ED78 }, + { (char*) "EST" , 0x06FB28 }, + { (char*) "EST5EDT" , 0x06FBA6 }, + { (char*) "Etc/GMT" , 0x0704B8 }, + { (char*) "Etc/GMT+0" , 0x070536 }, + { (char*) "Etc/GMT+1" , 0x0705B4 }, + { (char*) "Etc/GMT+10" , 0x070634 }, + { (char*) "Etc/GMT+11" , 0x0706B5 }, + { (char*) "Etc/GMT+12" , 0x070736 }, + { (char*) "Etc/GMT+2" , 0x0707B7 }, + { (char*) "Etc/GMT+3" , 0x070837 }, + { (char*) "Etc/GMT+4" , 0x0708B7 }, + { (char*) "Etc/GMT+5" , 0x070937 }, + { (char*) "Etc/GMT+6" , 0x0709B7 }, + { (char*) "Etc/GMT+7" , 0x070A37 }, + { (char*) "Etc/GMT+8" , 0x070AB7 }, + { (char*) "Etc/GMT+9" , 0x070B37 }, + { (char*) "Etc/GMT-0" , 0x070BB7 }, + { (char*) "Etc/GMT-1" , 0x070C35 }, + { (char*) "Etc/GMT-10" , 0x070CB6 }, + { (char*) "Etc/GMT-11" , 0x070D38 }, + { (char*) "Etc/GMT-12" , 0x070DBA }, + { (char*) "Etc/GMT-13" , 0x070E3C }, + { (char*) "Etc/GMT-14" , 0x070EBE }, + { (char*) "Etc/GMT-2" , 0x070F40 }, + { (char*) "Etc/GMT-3" , 0x070FC1 }, + { (char*) "Etc/GMT-4" , 0x071042 }, + { (char*) "Etc/GMT-5" , 0x0710C3 }, + { (char*) "Etc/GMT-6" , 0x071144 }, + { (char*) "Etc/GMT-7" , 0x0711C5 }, + { (char*) "Etc/GMT-8" , 0x071246 }, + { (char*) "Etc/GMT-9" , 0x0712C7 }, + { (char*) "Etc/GMT0" , 0x071348 }, + { (char*) "Etc/Greenwich" , 0x0713C6 }, + { (char*) "Etc/UCT" , 0x071444 }, + { (char*) "Etc/Universal" , 0x0714C2 }, + { (char*) "Etc/UTC" , 0x071540 }, + { (char*) "Etc/Zulu" , 0x0715BE }, + { (char*) "Europe/Amsterdam" , 0x07163C }, + { (char*) "Europe/Andorra" , 0x0721A6 }, + { (char*) "Europe/Astrakhan" , 0x072880 }, + { (char*) "Europe/Athens" , 0x072D1D }, + { (char*) "Europe/Belfast" , 0x0735FF }, + { (char*) "Europe/Belgrade" , 0x07445B }, + { (char*) "Europe/Berlin" , 0x074BE7 }, + { (char*) "Europe/Bratislava" , 0x0754FC }, + { (char*) "Europe/Brussels" , 0x075E05 }, + { (char*) "Europe/Bucharest" , 0x076986 }, + { (char*) "Europe/Budapest" , 0x07721A }, + { (char*) "Europe/Busingen" , 0x077B66 }, + { (char*) "Europe/Chisinau" , 0x0782EF }, + { (char*) "Europe/Copenhagen" , 0x078C51 }, + { (char*) "Europe/Dublin" , 0x0794B6 }, + { (char*) "Europe/Gibraltar" , 0x07A266 }, + { (char*) "Europe/Guernsey" , 0x07AE6E }, + { (char*) "Europe/Helsinki" , 0x07BD0E }, + { (char*) "Europe/Isle_of_Man" , 0x07C486 }, + { (char*) "Europe/Istanbul" , 0x07D2D2 }, + { (char*) "Europe/Jersey" , 0x07DA6B }, + { (char*) "Europe/Kaliningrad" , 0x07E90B }, + { (char*) "Europe/Kiev" , 0x07EF00 }, + { (char*) "Europe/Kirov" , 0x07F754 }, + { (char*) "Europe/Kyiv" , 0x07FC0F }, + { (char*) "Europe/Lisbon" , 0x080472 }, + { (char*) "Europe/Ljubljana" , 0x08123A }, + { (char*) "Europe/London" , 0x0819C6 }, + { (char*) "Europe/Luxembourg" , 0x082822 }, + { (char*) "Europe/Madrid" , 0x0833B0 }, + { (char*) "Europe/Malta" , 0x083E02 }, + { (char*) "Europe/Mariehamn" , 0x08484A }, + { (char*) "Europe/Minsk" , 0x084FC2 }, + { (char*) "Europe/Monaco" , 0x0854E9 }, + { (char*) "Europe/Moscow" , 0x086075 }, + { (char*) "Europe/Nicosia" , 0x086694 }, + { (char*) "Europe/Oslo" , 0x086E72 }, + { (char*) "Europe/Paris" , 0x087732 }, + { (char*) "Europe/Podgorica" , 0x0882D0 }, + { (char*) "Europe/Prague" , 0x088A5C }, + { (char*) "Europe/Riga" , 0x089365 }, + { (char*) "Europe/Rome" , 0x089C07 }, + { (char*) "Europe/Samara" , 0x08A664 }, + { (char*) "Europe/San_Marino" , 0x08AB3A }, + { (char*) "Europe/Sarajevo" , 0x08B597 }, + { (char*) "Europe/Saratov" , 0x08BD23 }, + { (char*) "Europe/Simferopol" , 0x08C1D0 }, + { (char*) "Europe/Skopje" , 0x08C79F }, + { (char*) "Europe/Sofia" , 0x08CF2B }, + { (char*) "Europe/Stockholm" , 0x08D754 }, + { (char*) "Europe/Tallinn" , 0x08DED5 }, + { (char*) "Europe/Tirane" , 0x08E745 }, + { (char*) "Europe/Tiraspol" , 0x08EF75 }, + { (char*) "Europe/Ulyanovsk" , 0x08F8D7 }, + { (char*) "Europe/Uzhgorod" , 0x08FDDA }, + { (char*) "Europe/Vaduz" , 0x09062E }, + { (char*) "Europe/Vatican" , 0x090D9A }, + { (char*) "Europe/Vienna" , 0x0917F7 }, + { (char*) "Europe/Vilnius" , 0x09209B }, + { (char*) "Europe/Volgograd" , 0x092919 }, + { (char*) "Europe/Warsaw" , 0x092DE0 }, + { (char*) "Europe/Zagreb" , 0x09384A }, + { (char*) "Europe/Zaporozhye" , 0x093FD6 }, + { (char*) "Europe/Zurich" , 0x09482A }, + { (char*) "Factory" , 0x094FAB }, + { (char*) "GB" , 0x09502B }, + { (char*) "GB-Eire" , 0x095E87 }, + { (char*) "GMT" , 0x096CE3 }, + { (char*) "GMT+0" , 0x096D61 }, + { (char*) "GMT-0" , 0x096DDF }, + { (char*) "GMT0" , 0x096E5D }, + { (char*) "Greenwich" , 0x096EDB }, + { (char*) "Hongkong" , 0x096F59 }, + { (char*) "HST" , 0x097436 }, + { (char*) "Iceland" , 0x0974B5 }, + { (char*) "Indian/Antananarivo" , 0x097555 }, + { (char*) "Indian/Chagos" , 0x09763C }, + { (char*) "Indian/Christmas" , 0x097701 }, + { (char*) "Indian/Cocos" , 0x0977A4 }, + { (char*) "Indian/Comoro" , 0x097850 }, + { (char*) "Indian/Kerguelen" , 0x0978F1 }, + { (char*) "Indian/Mahe" , 0x097994 }, + { (char*) "Indian/Maldives" , 0x097A37 }, + { (char*) "Indian/Mauritius" , 0x097AFC }, + { (char*) "Indian/Mayotte" , 0x097BEB }, + { (char*) "Indian/Reunion" , 0x097C8C }, + { (char*) "Iran" , 0x097D2F }, + { (char*) "Israel" , 0x09821B }, + { (char*) "Jamaica" , 0x098B7B }, + { (char*) "Japan" , 0x098D69 }, + { (char*) "Kwajalein" , 0x098EAA }, + { (char*) "Libya" , 0x098FE4 }, + { (char*) "MET" , 0x099261 }, + { (char*) "Mexico/BajaNorte" , 0x099A9B }, + { (char*) "Mexico/BajaSur" , 0x09A3ED }, + { (char*) "Mexico/General" , 0x09A861 }, + { (char*) "MST" , 0x09AD33 }, + { (char*) "MST7MDT" , 0x09ADB1 }, + { (char*) "Navajo" , 0x09B6C3 }, + { (char*) "NZ" , 0x09C06B }, + { (char*) "NZ-CHAT" , 0x09C9FC }, + { (char*) "Pacific/Apia" , 0x09D20E }, + { (char*) "Pacific/Auckland" , 0x09D470 }, + { (char*) "Pacific/Bougainville" , 0x09DE14 }, + { (char*) "Pacific/Chatham" , 0x09DF2A }, + { (char*) "Pacific/Chuuk" , 0x09E74B }, + { (char*) "Pacific/Easter" , 0x09E865 }, + { (char*) "Pacific/Efate" , 0x09F129 }, + { (char*) "Pacific/Enderbury" , 0x09F341 }, + { (char*) "Pacific/Fakaofo" , 0x09F429 }, + { (char*) "Pacific/Fiji" , 0x09F4EF }, + { (char*) "Pacific/Funafuti" , 0x09F72F }, + { (char*) "Pacific/Galapagos" , 0x09F7D3 }, + { (char*) "Pacific/Gambier" , 0x09F8D0 }, + { (char*) "Pacific/Guadalcanal" , 0x09F981 }, + { (char*) "Pacific/Guam" , 0x09FA25 }, + { (char*) "Pacific/Honolulu" , 0x09FC1F }, + { (char*) "Pacific/Johnston" , 0x09FD7A }, + { (char*) "Pacific/Kanton" , 0x09FECF }, + { (char*) "Pacific/Kiritimati" , 0x09FFC6 }, + { (char*) "Pacific/Kosrae" , 0x0A00BE }, + { (char*) "Pacific/Kwajalein" , 0x0A0221 }, + { (char*) "Pacific/Majuro" , 0x0A0364 }, + { (char*) "Pacific/Marquesas" , 0x0A04B0 }, + { (char*) "Pacific/Midway" , 0x0A056C }, + { (char*) "Pacific/Nauru" , 0x0A065F }, + { (char*) "Pacific/Niue" , 0x0A0759 }, + { (char*) "Pacific/Norfolk" , 0x0A0822 }, + { (char*) "Pacific/Noumea" , 0x0A0B90 }, + { (char*) "Pacific/Pago_Pago" , 0x0A0CBE }, + { (char*) "Pacific/Palau" , 0x0A0D79 }, + { (char*) "Pacific/Pitcairn" , 0x0A0E2B }, + { (char*) "Pacific/Pohnpei" , 0x0A0EF3 }, + { (char*) "Pacific/Ponape" , 0x0A102E }, + { (char*) "Pacific/Port_Moresby" , 0x0A10D2 }, + { (char*) "Pacific/Rarotonga" , 0x0A11A2 }, + { (char*) "Pacific/Saipan" , 0x0A13FB }, + { (char*) "Pacific/Samoa" , 0x0A15E7 }, + { (char*) "Pacific/Tahiti" , 0x0A16A2 }, + { (char*) "Pacific/Tarawa" , 0x0A1754 }, + { (char*) "Pacific/Tongatapu" , 0x0A1807 }, + { (char*) "Pacific/Truk" , 0x0A1979 }, + { (char*) "Pacific/Wake" , 0x0A1A31 }, + { (char*) "Pacific/Wallis" , 0x0A1AE0 }, + { (char*) "Pacific/Yap" , 0x0A1B84 }, + { (char*) "Poland" , 0x0A1C3C }, + { (char*) "Portugal" , 0x0A26A6 }, + { (char*) "PRC" , 0x0A345B }, + { (char*) "PST8PDT" , 0x0A3698 }, + { (char*) "ROC" , 0x0A3FAA }, + { (char*) "ROK" , 0x0A42AF }, + { (char*) "Singapore" , 0x0A4524 }, + { (char*) "Turkey" , 0x0A46C1 }, + { (char*) "UCT" , 0x0A4E5A }, + { (char*) "Universal" , 0x0A4ED8 }, + { (char*) "US/Alaska" , 0x0A4F56 }, + { (char*) "US/Aleutian" , 0x0A58A5 }, + { (char*) "US/Arizona" , 0x0A61E5 }, + { (char*) "US/Central" , 0x0A6359 }, + { (char*) "US/East-Indiana" , 0x0A716D }, + { (char*) "US/Eastern" , 0x0A780B }, + { (char*) "US/Hawaii" , 0x0A85F7 }, + { (char*) "US/Indiana-Starke" , 0x0A874C }, + { (char*) "US/Michigan" , 0x0A90E4 }, + { (char*) "US/Mountain" , 0x0A99A6 }, + { (char*) "US/Pacific" , 0x0AA34E }, + { (char*) "US/Samoa" , 0x0AAE7E }, + { (char*) "UTC" , 0x0AAF39 }, + { (char*) "W-SU" , 0x0AAFB7 }, + { (char*) "WET" , 0x0AB5C2 }, + { (char*) "Zulu" , 0x0ABD3F }, }; -const unsigned char timelib_timezone_db_data_builtin[699143] = { +const unsigned char timelib_timezone_db_data_builtin[703933] = { /* Africa/Abidjan */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -24582,7 +24750,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { /* Africa/Cairo */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x45, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x80, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x80, 0x00, 0x00, 0x00, 0xC8, 0x93, 0xB4, 0xE0, 0xC8, 0xFA, 0x7B, 0xD0, 0xC9, 0xFC, 0xEF, 0xE0, 0xCA, 0xC7, 0xE8, 0xD0, 0xCB, 0xCB, 0xAE, 0x60, 0xCC, 0xDF, 0x29, 0xD0, 0xCD, 0xAC, 0xE1, 0xE0, 0xCE, 0xC6, 0xF4, 0xD0, 0xCF, 0x8F, 0x66, 0xE0, 0xD0, 0xA9, 0x79, 0xD0, 0xD1, 0x84, 0x60, 0xE0, 0xD2, 0x8A, 0xAD, 0x50, @@ -24614,95 +24782,123 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x46, 0x31, 0x20, 0xE0, 0x46, 0xE0, 0x6A, 0x50, 0x48, 0x11, 0x02, 0xE0, 0x48, 0xB7, 0x11, 0xD0, 0x49, 0xF0, 0xE4, 0xE0, 0x4A, 0x8D, 0xB9, 0x50, 0x4B, 0xDA, 0x01, 0x60, 0x4C, 0x61, 0xBD, 0xD0, 0x4C, 0x89, 0x58, 0xE0, 0x4C, 0xA4, 0xFA, 0x50, 0x53, 0x75, 0x38, 0xE0, 0x53, 0xAC, 0x89, 0xD0, -0x53, 0xDA, 0xBC, 0x60, 0x54, 0x24, 0x82, 0x50, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x53, 0xDA, 0xBC, 0x60, 0x54, 0x24, 0x82, 0x50, 0x64, 0x4A, 0xF0, 0x60, 0x65, 0x3A, 0xD3, 0x50, +0x66, 0x2A, 0xD2, 0x60, 0x67, 0x23, 0xEF, 0xD0, 0x68, 0x0A, 0xB4, 0x60, 0x69, 0x03, 0xD1, 0xD0, +0x69, 0xEA, 0x96, 0x60, 0x6A, 0xE3, 0xB3, 0xD0, 0x6B, 0xD3, 0xB2, 0xE0, 0x6C, 0xC3, 0x95, 0xD0, +0x6D, 0xB3, 0x94, 0xE0, 0x6E, 0xA3, 0x77, 0xD0, 0x6F, 0x93, 0x76, 0xE0, 0x70, 0x83, 0x59, 0xD0, +0x71, 0x73, 0x58, 0xE0, 0x72, 0x6C, 0x76, 0x50, 0x73, 0x53, 0x3A, 0xE0, 0x74, 0x4C, 0x58, 0x50, +0x75, 0x3C, 0x57, 0x60, 0x76, 0x2C, 0x3A, 0x50, 0x77, 0x1C, 0x39, 0x60, 0x78, 0x0C, 0x1C, 0x50, +0x78, 0xFC, 0x1B, 0x60, 0x79, 0xEB, 0xFE, 0x50, 0x7A, 0xDB, 0xFD, 0x60, 0x7B, 0xCB, 0xE0, 0x50, +0x7C, 0xBB, 0xDF, 0x60, 0x7D, 0xB4, 0xFC, 0xD0, 0x7E, 0x9B, 0xC1, 0x60, 0x7F, 0x94, 0xDE, 0xD0, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, +0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x1D, +0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, +0x00, 0x2A, 0x30, 0x01, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, +0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, +0x00, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0xBD, 0x4D, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x93, +0xB4, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0xFA, 0x7B, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0xFC, +0xEF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA, 0xC7, 0xE8, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0xCB, +0xAE, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xDF, 0x29, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCD, 0xAC, +0xE1, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCE, 0xC6, 0xF4, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0x8F, +0x66, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xA9, 0x79, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD1, 0x84, +0x60, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0x8A, 0xAD, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x36, +0x63, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF4, 0x2D, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x0B, +0xB9, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0x60, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xEC, +0xFA, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB5, 0x6D, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xCF, +0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x97, 0xF2, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xB0, +0xB3, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x79, 0x25, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x91, +0xE6, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x5A, 0x59, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x73, +0x1A, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x3B, 0x8C, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x55, +0x9F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0x1E, 0x11, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x36, +0xD2, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x45, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x18, +0x06, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xE1, 0xCA, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xF9, +0x39, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xC2, 0xFD, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xDB, +0xBE, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xA5, 0x82, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBC, +0xF2, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x86, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, +0x25, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x67, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x7F, +0x59, 0x70, 0x00, 0x00, 0x00, 0x00, 0x03, 0x49, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, +0xDE, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x2B, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, +0x11, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0C, 0xD5, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x24, +0x45, 0x70, 0x00, 0x00, 0x00, 0x00, 0x08, 0xEE, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, +0x78, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xCF, 0x3C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE7, +0xFD, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xB1, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC9, +0x31, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x92, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xAA, +0x64, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x74, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, 0x11, 0x8B, +0x98, 0x70, 0x00, 0x00, 0x00, 0x00, 0x12, 0x55, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x6E, +0x1D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x14, 0x37, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x4F, +0x50, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x19, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, +0x93, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x17, 0xFA, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x70, +0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x19, 0xDB, 0x7B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, +0x3C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xBE, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xD5, +0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x9F, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xB6, +0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x67, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x97, +0xD7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x21, 0x61, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x7A, +0x5C, 0x70, 0x00, 0x00, 0x00, 0x00, 0x23, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x62, +0x27, 0x70, 0x00, 0x00, 0x00, 0x00, 0x25, 0x25, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x26, 0x3C, +0xC3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x27, 0x06, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x1D, +0xF6, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x28, 0xE7, 0xBA, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, +0x7B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xCA, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xE1, +0xAF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xAB, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0xC2, +0xE2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x8C, 0xA6, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xA0, +0x13, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x6B, 0x0C, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x31, 0x7F, +0xF5, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4A, 0xEE, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x33, 0x5F, +0xD7, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x2A, 0xD0, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x35, 0x3F, +0xB9, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x36, 0x0A, 0xB2, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x37, 0x28, +0xD6, 0x60, 0x00, 0x00, 0x00, 0x00, 0x37, 0xF3, 0xCF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x39, 0x08, +0xB8, 0x60, 0x00, 0x00, 0x00, 0x00, 0x39, 0xD3, 0xB1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xE8, +0x9A, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xB3, 0x93, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xC8, +0x7C, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x93, 0x75, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xA8, +0x5E, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x73, 0x57, 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x91, +0x7A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x41, 0x5C, 0x73, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x71, +0x5C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x43, 0x3C, 0x55, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x51, +0x3E, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x45, 0x12, 0xFD, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x31, +0x20, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x46, 0xE0, 0x6A, 0x50, 0x00, 0x00, 0x00, 0x00, 0x48, 0x11, +0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x48, 0xB7, 0x11, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x49, 0xF0, +0xE4, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x8D, 0xB9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xDA, +0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xBD, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x89, +0x58, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xA4, 0xFA, 0x50, 0x00, 0x00, 0x00, 0x00, 0x53, 0x75, +0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xAC, 0x89, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xDA, +0xBC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x54, 0x24, 0x82, 0x50, 0x00, 0x00, 0x00, 0x00, 0x64, 0x4A, +0xF0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3A, 0xD3, 0x50, 0x00, 0x00, 0x00, 0x00, 0x66, 0x2A, +0xD2, 0x60, 0x00, 0x00, 0x00, 0x00, 0x67, 0x23, 0xEF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x0A, +0xB4, 0x60, 0x00, 0x00, 0x00, 0x00, 0x69, 0x03, 0xD1, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x69, 0xEA, +0x96, 0x60, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xE3, 0xB3, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xD3, +0xB2, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xC3, 0x95, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x6D, 0xB3, +0x94, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA3, 0x77, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x93, +0x76, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x83, 0x59, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x71, 0x73, +0x58, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6C, 0x76, 0x50, 0x00, 0x00, 0x00, 0x00, 0x73, 0x53, +0x3A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x4C, 0x58, 0x50, 0x00, 0x00, 0x00, 0x00, 0x75, 0x3C, +0x57, 0x60, 0x00, 0x00, 0x00, 0x00, 0x76, 0x2C, 0x3A, 0x50, 0x00, 0x00, 0x00, 0x00, 0x77, 0x1C, +0x39, 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x1C, 0x50, 0x00, 0x00, 0x00, 0x00, 0x78, 0xFC, +0x1B, 0x60, 0x00, 0x00, 0x00, 0x00, 0x79, 0xEB, 0xFE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xDB, +0xFD, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCB, 0xE0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xBB, +0xDF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xB4, 0xFC, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x9B, +0xC1, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x94, 0xDE, 0xD0, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, +0x02, 0x03, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x1D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, -0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, -0x7D, 0xBD, 0x4D, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x93, 0xB4, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xC8, 0xFA, 0x7B, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0xFC, 0xEF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xCA, 0xC7, 0xE8, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0xCB, 0xAE, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, -0xCC, 0xDF, 0x29, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCD, 0xAC, 0xE1, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xCE, 0xC6, 0xF4, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0x8F, 0x66, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xD0, 0xA9, 0x79, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD1, 0x84, 0x60, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xD2, 0x8A, 0xAD, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x36, 0x63, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, -0xE8, 0xF4, 0x2D, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x0B, 0xB9, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, -0xEA, 0xD5, 0x60, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xEC, 0xFA, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xEC, 0xB5, 0x6D, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xCF, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xEE, 0x97, 0xF2, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xB0, 0xB3, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xF0, 0x79, 0x25, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x91, 0xE6, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xF2, 0x5A, 0x59, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x73, 0x1A, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xF4, 0x3B, 0x8C, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x55, 0x9F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xF6, 0x1E, 0x11, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x36, 0xD2, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xF7, 0xFF, 0x45, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x18, 0x06, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xF9, 0xE1, 0xCA, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xF9, 0x39, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xFB, 0xC2, 0xFD, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xDB, 0xBE, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xFD, 0xA5, 0x82, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBC, 0xF2, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0x86, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x25, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x01, 0x67, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x59, 0x70, 0x00, 0x00, 0x00, 0x00, -0x03, 0x49, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, 0xDE, 0x70, 0x00, 0x00, 0x00, 0x00, -0x05, 0x2B, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0x11, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x07, 0x0C, 0xD5, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x24, 0x45, 0x70, 0x00, 0x00, 0x00, 0x00, -0x08, 0xEE, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x78, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x0A, 0xCF, 0x3C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE7, 0xFD, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x0C, 0xB1, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC9, 0x31, 0x70, 0x00, 0x00, 0x00, 0x00, -0x0E, 0x92, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xAA, 0x64, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x10, 0x74, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, 0x11, 0x8B, 0x98, 0x70, 0x00, 0x00, 0x00, 0x00, -0x12, 0x55, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x6E, 0x1D, 0x70, 0x00, 0x00, 0x00, 0x00, -0x14, 0x37, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x4F, 0x50, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x16, 0x19, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x93, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x17, 0xFA, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x70, 0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x19, 0xDB, 0x7B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x3C, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x1B, 0xBE, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xD5, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, -0x1D, 0x9F, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xB6, 0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x1F, 0x80, 0x67, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x97, 0xD7, 0x70, 0x00, 0x00, 0x00, 0x00, -0x21, 0x61, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x7A, 0x5C, 0x70, 0x00, 0x00, 0x00, 0x00, -0x23, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x62, 0x27, 0x70, 0x00, 0x00, 0x00, 0x00, -0x25, 0x25, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x26, 0x3C, 0xC3, 0x70, 0x00, 0x00, 0x00, 0x00, -0x27, 0x06, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x1D, 0xF6, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x28, 0xE7, 0xBA, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x7B, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x2A, 0xCA, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xE1, 0xAF, 0x70, 0x00, 0x00, 0x00, 0x00, -0x2C, 0xAB, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0xC2, 0xE2, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x2E, 0x8C, 0xA6, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xA0, 0x13, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x30, 0x6B, 0x0C, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x31, 0x7F, 0xF5, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x32, 0x4A, 0xEE, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x33, 0x5F, 0xD7, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x34, 0x2A, 0xD0, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x35, 0x3F, 0xB9, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x36, 0x0A, 0xB2, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x37, 0x28, 0xD6, 0x60, 0x00, 0x00, 0x00, 0x00, -0x37, 0xF3, 0xCF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x39, 0x08, 0xB8, 0x60, 0x00, 0x00, 0x00, 0x00, -0x39, 0xD3, 0xB1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xE8, 0x9A, 0x60, 0x00, 0x00, 0x00, 0x00, -0x3B, 0xB3, 0x93, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xC8, 0x7C, 0x60, 0x00, 0x00, 0x00, 0x00, -0x3D, 0x93, 0x75, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xA8, 0x5E, 0x60, 0x00, 0x00, 0x00, 0x00, -0x3F, 0x73, 0x57, 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x91, 0x7A, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x41, 0x5C, 0x73, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x71, 0x5C, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x43, 0x3C, 0x55, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x51, 0x3E, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x45, 0x12, 0xFD, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x31, 0x20, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x46, 0xE0, 0x6A, 0x50, 0x00, 0x00, 0x00, 0x00, 0x48, 0x11, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x48, 0xB7, 0x11, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x49, 0xF0, 0xE4, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x4A, 0x8D, 0xB9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xDA, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, -0x4C, 0x61, 0xBD, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x89, 0x58, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x4C, 0xA4, 0xFA, 0x50, 0x00, 0x00, 0x00, 0x00, 0x53, 0x75, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x53, 0xAC, 0x89, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xDA, 0xBC, 0x60, 0x00, 0x00, 0x00, 0x00, -0x54, 0x24, 0x82, 0x50, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x00, 0x00, 0x1D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, -0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x45, -0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x45, 0x45, 0x54, -0x2D, 0x32, 0x0A, 0x00, 0xB7, 0x2E, 0x88, 0x01, 0x42, 0x57, 0x88, 0x00, 0x00, 0x00, 0x00, +0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x34, 0x2E, 0x35, 0x2E, +0x35, 0x2F, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x34, 0x2F, 0x32, 0x34, 0x0A, 0x00, +0xB7, 0x2E, 0x88, 0x01, 0x42, 0x57, 0x88, 0x00, 0x00, 0x00, 0x00, /* Africa/Casablanca */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x4D, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -24723,11 +24919,11 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x59, 0x58, 0x53, 0xA0, 0x59, 0xF5, 0x36, 0x20, 0x5A, 0xB7, 0x02, 0xA0, 0x5A, 0xF7, 0x9C, 0x20, 0x5B, 0x25, 0xC0, 0xA0, 0x5B, 0xD5, 0x18, 0x20, 0x5C, 0xCE, 0x43, 0xA0, 0x5C, 0xFC, 0x68, 0x20, 0x5E, 0x9B, 0xB0, 0xA0, 0x5E, 0xD3, 0x0F, 0xA0, 0x60, 0x72, 0x58, 0x20, 0x60, 0xA0, 0x7C, 0xA0, -0x62, 0x3F, 0xC5, 0x20, 0x62, 0x77, 0x24, 0x20, 0x64, 0x16, 0x6C, 0xA0, 0x64, 0x4D, 0xCB, 0xA0, +0x62, 0x3F, 0xC5, 0x20, 0x62, 0x77, 0x24, 0x20, 0x64, 0x16, 0x6C, 0xA0, 0x64, 0x44, 0x91, 0x20, 0x65, 0xED, 0x14, 0x20, 0x66, 0x1B, 0x38, 0xA0, 0x67, 0xBA, 0x81, 0x20, 0x67, 0xF1, 0xE0, 0x20, 0x69, 0x91, 0x28, 0xA0, 0x69, 0xBF, 0x4D, 0x20, 0x6B, 0x67, 0xD0, 0x20, 0x6B, 0x95, 0xF4, 0xA0, 0x6D, 0x35, 0x3D, 0x20, 0x6D, 0x6C, 0x9C, 0x20, 0x6F, 0x0B, 0xE4, 0xA0, 0x6F, 0x3A, 0x09, 0x20, -0x70, 0xD9, 0x51, 0xA0, 0x71, 0x10, 0xB0, 0xA0, 0x72, 0xAF, 0xF9, 0x20, 0x72, 0xE7, 0x58, 0x20, +0x70, 0xD9, 0x51, 0xA0, 0x71, 0x10, 0xB0, 0xA0, 0x72, 0xAF, 0xF9, 0x20, 0x72, 0xDE, 0x1D, 0xA0, 0x74, 0x86, 0xA0, 0xA0, 0x74, 0xB4, 0xC5, 0x20, 0x76, 0x54, 0x0D, 0xA0, 0x76, 0x8B, 0x6C, 0xA0, 0x78, 0x2A, 0xB5, 0x20, 0x78, 0x58, 0xD9, 0xA0, 0x79, 0xF8, 0x22, 0x20, 0x7A, 0x2F, 0x81, 0x20, 0x7B, 0xCE, 0xC9, 0xA0, 0x7C, 0x06, 0x28, 0xA0, 0x7D, 0xA5, 0x71, 0x20, 0x7D, 0xD3, 0x95, 0xA0, @@ -24775,7 +24971,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x5E, 0xD3, 0x0F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x60, 0x72, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0xA0, 0x7C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xC5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x62, 0x77, 0x24, 0x20, 0x00, 0x00, 0x00, 0x00, 0x64, 0x16, 0x6C, 0xA0, 0x00, 0x00, 0x00, -0x00, 0x64, 0x4D, 0xCB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x65, 0xED, 0x14, 0x20, 0x00, 0x00, 0x00, +0x00, 0x64, 0x44, 0x91, 0x20, 0x00, 0x00, 0x00, 0x00, 0x65, 0xED, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, 0x66, 0x1B, 0x38, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x67, 0xBA, 0x81, 0x20, 0x00, 0x00, 0x00, 0x00, 0x67, 0xF1, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x69, 0x91, 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x69, 0xBF, 0x4D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x67, 0xD0, 0x20, 0x00, 0x00, 0x00, @@ -24783,7 +24979,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x6D, 0x6C, 0x9C, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x0B, 0xE4, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x3A, 0x09, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD9, 0x51, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x71, 0x10, 0xB0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x72, 0xAF, 0xF9, 0x20, 0x00, 0x00, 0x00, -0x00, 0x72, 0xE7, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x74, 0x86, 0xA0, 0xA0, 0x00, 0x00, 0x00, +0x00, 0x72, 0xDE, 0x1D, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x86, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x74, 0xB4, 0xC5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x76, 0x54, 0x0D, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x8B, 0x6C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x2A, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x78, 0x58, 0xD9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x79, 0xF8, 0x22, 0x20, 0x00, 0x00, 0x00, @@ -24791,7 +24987,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x7C, 0x06, 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xA5, 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xD3, 0x95, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x72, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xAA, 0x3D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x81, 0x49, 0x85, 0xA0, 0x00, 0x00, 0x00, -0x00, 0x81, 0x80, 0xE4, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x83, 0x20, 0x2D, 0x20, 0x00, 0x00, 0x00, +0x00, 0x81, 0x77, 0xAA, 0x20, 0x00, 0x00, 0x00, 0x00, 0x83, 0x20, 0x2D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x83, 0x4E, 0x51, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x84, 0xED, 0x9A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x85, 0x24, 0xF9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x86, 0xC4, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x86, 0xF2, 0x66, 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x91, 0xAE, 0xA0, 0x00, 0x00, 0x00, @@ -24799,7 +24995,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x8A, 0x9F, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x3E, 0xFD, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x6D, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x0C, 0x6A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x43, 0xC9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8F, 0xE3, 0x12, 0x20, 0x00, 0x00, 0x00, -0x00, 0x90, 0x1A, 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB9, 0xB9, 0xA0, 0x00, 0x00, 0x00, +0x00, 0x90, 0x11, 0x36, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB9, 0xB9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xE7, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x93, 0x87, 0x26, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x93, 0xBE, 0x85, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5D, 0xCE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x95, 0x8B, 0xF2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x97, 0x2B, 0x3B, 0x20, 0x00, 0x00, 0x00, @@ -24807,7 +25003,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x99, 0x39, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD8, 0x8A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x06, 0xAE, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xA5, 0xF7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xDD, 0x56, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x7C, 0x9E, 0xA0, 0x00, 0x00, 0x00, -0x00, 0x9E, 0xB3, 0xFD, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x53, 0x46, 0x20, 0x00, 0x00, 0x00, +0x00, 0x9E, 0xAA, 0xC3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x53, 0x46, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x81, 0x6A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x20, 0xB3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x58, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA3, 0xF7, 0x5A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x25, 0x7F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA5, 0xC4, 0xC7, 0xA0, 0x00, 0x00, 0x00, @@ -24815,7 +25011,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0xA7, 0xD2, 0xCE, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x72, 0x16, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA9, 0xA0, 0x3B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x3F, 0x83, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x76, 0xE2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x16, 0x2B, 0x20, 0x00, 0x00, 0x00, -0x00, 0xAD, 0x4D, 0x8A, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAE, 0xEC, 0xD2, 0xA0, 0x00, 0x00, 0x00, +0x00, 0xAD, 0x44, 0x4F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAE, 0xEC, 0xD2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x1A, 0xF7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xBA, 0x3F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xF1, 0x9E, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x90, 0xE7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB2, 0xBF, 0x0B, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x5E, 0x54, 0x20, 0x00, 0x00, 0x00, @@ -24823,7 +25019,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0xB6, 0x6C, 0x5A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x0B, 0xA3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x39, 0xC7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xD9, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x10, 0x6F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xAF, 0xB7, 0xA0, 0x00, 0x00, 0x00, -0x00, 0xBB, 0xE7, 0x16, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x86, 0x5F, 0x20, 0x00, 0x00, 0x00, +0x00, 0xBB, 0xDD, 0xDC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x86, 0x5F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBD, 0xB4, 0x83, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x53, 0xCC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x8B, 0x2B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x2A, 0x73, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x58, 0x98, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xF7, 0xE0, 0xA0, 0x00, 0x00, 0x00, @@ -24831,15 +25027,15 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0xC5, 0x05, 0xE7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xA5, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xD3, 0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x72, 0x9C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xA9, 0xFB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x49, 0x44, 0x20, 0x00, 0x00, 0x00, -0x00, 0xCA, 0x80, 0xA3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1F, 0xEB, 0xA0, 0x00, 0x00, 0x00, +0x00, 0xCA, 0x77, 0x68, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1F, 0xEB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x4E, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xED, 0x58, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x24, 0xB7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xC4, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xF2, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x91, 0x6D, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xC8, 0xCC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x68, 0x14, 0xA0, 0x00, 0x00, 0x00, -0x00, 0xD3, 0x9F, 0x73, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x3E, 0xBC, 0x20, 0x00, 0x00, 0x00, +0x00, 0xD3, 0x96, 0x39, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x3E, 0xBC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x6C, 0xE0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x0C, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x43, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xE2, 0xD0, 0xA0, 0x00, 0x00, 0x00, -0x00, 0xD9, 0x1A, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB9, 0x78, 0x20, 0x00, 0x00, 0x00, +0x00, 0xD9, 0x10, 0xF5, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB9, 0x78, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xE7, 0x9C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x86, 0xE5, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xBE, 0x44, 0x20, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, @@ -25082,11 +25278,11 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x5A, 0xF7, 0x9C, 0x20, 0x5B, 0x25, 0xC0, 0xA0, 0x5B, 0xD5, 0x18, 0x20, 0x5C, 0xCE, 0x43, 0xA0, 0x5C, 0xFC, 0x68, 0x20, 0x5E, 0x9B, 0xB0, 0xA0, 0x5E, 0xD3, 0x0F, 0xA0, 0x60, 0x72, 0x58, 0x20, 0x60, 0xA0, 0x7C, 0xA0, 0x62, 0x3F, 0xC5, 0x20, 0x62, 0x77, 0x24, 0x20, 0x64, 0x16, 0x6C, 0xA0, -0x64, 0x4D, 0xCB, 0xA0, 0x65, 0xED, 0x14, 0x20, 0x66, 0x1B, 0x38, 0xA0, 0x67, 0xBA, 0x81, 0x20, +0x64, 0x44, 0x91, 0x20, 0x65, 0xED, 0x14, 0x20, 0x66, 0x1B, 0x38, 0xA0, 0x67, 0xBA, 0x81, 0x20, 0x67, 0xF1, 0xE0, 0x20, 0x69, 0x91, 0x28, 0xA0, 0x69, 0xBF, 0x4D, 0x20, 0x6B, 0x67, 0xD0, 0x20, 0x6B, 0x95, 0xF4, 0xA0, 0x6D, 0x35, 0x3D, 0x20, 0x6D, 0x6C, 0x9C, 0x20, 0x6F, 0x0B, 0xE4, 0xA0, 0x6F, 0x3A, 0x09, 0x20, 0x70, 0xD9, 0x51, 0xA0, 0x71, 0x10, 0xB0, 0xA0, 0x72, 0xAF, 0xF9, 0x20, -0x72, 0xE7, 0x58, 0x20, 0x74, 0x86, 0xA0, 0xA0, 0x74, 0xB4, 0xC5, 0x20, 0x76, 0x54, 0x0D, 0xA0, +0x72, 0xDE, 0x1D, 0xA0, 0x74, 0x86, 0xA0, 0xA0, 0x74, 0xB4, 0xC5, 0x20, 0x76, 0x54, 0x0D, 0xA0, 0x76, 0x8B, 0x6C, 0xA0, 0x78, 0x2A, 0xB5, 0x20, 0x78, 0x58, 0xD9, 0xA0, 0x79, 0xF8, 0x22, 0x20, 0x7A, 0x2F, 0x81, 0x20, 0x7B, 0xCE, 0xC9, 0xA0, 0x7C, 0x06, 0x28, 0xA0, 0x7D, 0xA5, 0x71, 0x20, 0x7D, 0xD3, 0x95, 0xA0, 0x7F, 0x72, 0xDE, 0x20, 0x7F, 0xAA, 0x3D, 0x20, 0x01, 0x03, 0x02, 0x03, @@ -25127,7 +25323,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0x5E, 0x9B, 0xB0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x5E, 0xD3, 0x0F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x60, 0x72, 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x60, 0xA0, 0x7C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xC5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x62, 0x77, 0x24, 0x20, -0x00, 0x00, 0x00, 0x00, 0x64, 0x16, 0x6C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x64, 0x4D, 0xCB, 0xA0, +0x00, 0x00, 0x00, 0x00, 0x64, 0x16, 0x6C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x64, 0x44, 0x91, 0x20, 0x00, 0x00, 0x00, 0x00, 0x65, 0xED, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, 0x66, 0x1B, 0x38, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x67, 0xBA, 0x81, 0x20, 0x00, 0x00, 0x00, 0x00, 0x67, 0xF1, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x69, 0x91, 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x69, 0xBF, 0x4D, 0x20, @@ -25135,7 +25331,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0x6D, 0x35, 0x3D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x6C, 0x9C, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x0B, 0xE4, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x3A, 0x09, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD9, 0x51, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x71, 0x10, 0xB0, 0xA0, -0x00, 0x00, 0x00, 0x00, 0x72, 0xAF, 0xF9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0xE7, 0x58, 0x20, +0x00, 0x00, 0x00, 0x00, 0x72, 0xAF, 0xF9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0xDE, 0x1D, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x86, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x74, 0xB4, 0xC5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x76, 0x54, 0x0D, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x8B, 0x6C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x2A, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x78, 0x58, 0xD9, 0xA0, @@ -25143,7 +25339,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCE, 0xC9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x06, 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xA5, 0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xD3, 0x95, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x72, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xAA, 0x3D, 0x20, -0x00, 0x00, 0x00, 0x00, 0x81, 0x49, 0x85, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x81, 0x80, 0xE4, 0xA0, +0x00, 0x00, 0x00, 0x00, 0x81, 0x49, 0x85, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x81, 0x77, 0xAA, 0x20, 0x00, 0x00, 0x00, 0x00, 0x83, 0x20, 0x2D, 0x20, 0x00, 0x00, 0x00, 0x00, 0x83, 0x4E, 0x51, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x84, 0xED, 0x9A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x85, 0x24, 0xF9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x86, 0xC4, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x86, 0xF2, 0x66, 0x20, @@ -25151,7 +25347,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0x8A, 0x68, 0x56, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x9F, 0xB5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x3E, 0xFD, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x6D, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x0C, 0x6A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x43, 0xC9, 0xA0, -0x00, 0x00, 0x00, 0x00, 0x8F, 0xE3, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1A, 0x71, 0x20, +0x00, 0x00, 0x00, 0x00, 0x8F, 0xE3, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x90, 0x11, 0x36, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB9, 0xB9, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xE7, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x93, 0x87, 0x26, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x93, 0xBE, 0x85, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5D, 0xCE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x95, 0x8B, 0xF2, 0xA0, @@ -25159,7 +25355,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0xE2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x99, 0x39, 0x41, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD8, 0x8A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x06, 0xAE, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xA5, 0xF7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xDD, 0x56, 0x20, -0x00, 0x00, 0x00, 0x00, 0x9E, 0x7C, 0x9E, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xB3, 0xFD, 0xA0, +0x00, 0x00, 0x00, 0x00, 0x9E, 0x7C, 0x9E, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xAA, 0xC3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x53, 0x46, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x81, 0x6A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x20, 0xB3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x58, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA3, 0xF7, 0x5A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x25, 0x7F, 0x20, @@ -25167,7 +25363,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0xA7, 0x9B, 0x6F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xD2, 0xCE, 0x20, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x72, 0x16, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xA9, 0xA0, 0x3B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x3F, 0x83, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x76, 0xE2, 0xA0, -0x00, 0x00, 0x00, 0x00, 0xAD, 0x16, 0x2B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x4D, 0x8A, 0x20, +0x00, 0x00, 0x00, 0x00, 0xAD, 0x16, 0x2B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x44, 0x4F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAE, 0xEC, 0xD2, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x1A, 0xF7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xBA, 0x3F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xF1, 0x9E, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x90, 0xE7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB2, 0xBF, 0x0B, 0xA0, @@ -25175,7 +25371,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0xB6, 0x34, 0xFB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x6C, 0x5A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x0B, 0xA3, 0x20, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x39, 0xC7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xD9, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x10, 0x6F, 0x20, -0x00, 0x00, 0x00, 0x00, 0xBB, 0xAF, 0xB7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xE7, 0x16, 0xA0, +0x00, 0x00, 0x00, 0x00, 0xBB, 0xAF, 0xB7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xDD, 0xDC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x86, 0x5F, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBD, 0xB4, 0x83, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x53, 0xCC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x8B, 0x2B, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x2A, 0x73, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x58, 0x98, 0x20, @@ -25183,15 +25379,15 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0xC4, 0xCE, 0x88, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x05, 0xE7, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xA5, 0x2F, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xD3, 0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x72, 0x9C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xA9, 0xFB, 0xA0, -0x00, 0x00, 0x00, 0x00, 0xCA, 0x49, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x80, 0xA3, 0x20, +0x00, 0x00, 0x00, 0x00, 0xCA, 0x49, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x77, 0x68, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1F, 0xEB, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x4E, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xED, 0x58, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x24, 0xB7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xC4, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xF2, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x91, 0x6D, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xC8, 0xCC, 0x20, -0x00, 0x00, 0x00, 0x00, 0xD3, 0x68, 0x14, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x9F, 0x73, 0xA0, +0x00, 0x00, 0x00, 0x00, 0xD3, 0x68, 0x14, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x96, 0x39, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x3E, 0xBC, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x6C, 0xE0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x0C, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x43, 0x88, 0x20, -0x00, 0x00, 0x00, 0x00, 0xD8, 0xE2, 0xD0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x1A, 0x2F, 0xA0, +0x00, 0x00, 0x00, 0x00, 0xD8, 0xE2, 0xD0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x10, 0xF5, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB9, 0x78, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xE7, 0x9C, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x86, 0xE5, 0x20, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xBE, 0x44, 0x20, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, @@ -26037,9 +26233,9 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x53, 0x54, 0x00, 0x48, 0x44, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x48, 0x53, 0x54, 0x31, 0x30, 0x48, 0x44, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x32, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x31, 0x2E, -0x31, 0x2E, 0x30, 0x0A, 0x00, 0xD8, 0x7D, 0xE0, 0x00, 0x05, 0x19, 0x72, 0x00, 0x00, 0x00, 0x10, -0x41, 0x6C, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6E, 0x20, 0x49, 0x73, 0x6C, 0x61, 0x6E, 0x64, 0x73, - +0x31, 0x2E, 0x30, 0x0A, 0x00, 0xD8, 0x7D, 0xE0, 0x00, 0x05, 0x19, 0x72, 0x00, 0x00, 0x00, 0x1A, +0x41, 0x6C, 0x61, 0x73, 0x6B, 0x61, 0x20, 0x2D, 0x20, 0x77, 0x65, 0x73, 0x74, 0x65, 0x72, 0x6E, +0x20, 0x41, 0x6C, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6E, 0x73, /* America/Anchorage */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x55, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -29888,9 +30084,9 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x54, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x4D, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x4D, 0x53, 0x54, 0x37, 0x4D, 0x44, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x32, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x31, 0x2E, 0x31, 0x2E, 0x30, 0x0A, 0x00, 0xDB, 0x0A, 0x38, -0x00, 0x65, 0x85, 0x95, 0x00, 0x00, 0x00, 0x1D, 0x4D, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, -0x20, 0x2D, 0x20, 0x41, 0x42, 0x3B, 0x20, 0x42, 0x43, 0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x53, -0x4B, 0x20, 0x28, 0x57, 0x29, +0x00, 0x65, 0x85, 0x95, 0x00, 0x00, 0x00, 0x25, 0x4D, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, +0x20, 0x2D, 0x20, 0x41, 0x42, 0x3B, 0x20, 0x42, 0x43, 0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x4E, +0x54, 0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x53, 0x4B, 0x20, 0x28, 0x57, 0x29, /* America/Eirunepe */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x42, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -30552,8 +30748,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { /* America/Godthab */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x9B, 0x80, 0x68, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x9B, 0x80, 0x68, 0x00, 0x13, 0x4D, 0x7C, 0x50, 0x14, 0x33, 0xFA, 0x90, 0x15, 0x23, 0xEB, 0x90, 0x16, 0x13, 0xDC, 0x90, 0x17, 0x03, 0xCD, 0x90, 0x17, 0xF3, 0xBE, 0x90, 0x18, 0xE3, 0xAF, 0x90, 0x19, 0xD3, 0xA0, 0x90, 0x1A, 0xC3, 0x91, 0x90, 0x1B, 0xBC, 0xBD, 0x10, 0x1C, 0xAC, 0xAE, 0x10, 0x1D, 0x9C, 0x9F, 0x10, @@ -30575,74 +30771,102 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x56, 0xF7, 0x30, 0x90, 0x58, 0x15, 0x46, 0x10, 0x58, 0xD7, 0x12, 0x90, 0x59, 0xF5, 0x28, 0x10, 0x5A, 0xB6, 0xF4, 0x90, 0x5B, 0xD5, 0x0A, 0x10, 0x5C, 0xA0, 0x11, 0x10, 0x5D, 0xB4, 0xEC, 0x10, 0x5E, 0x7F, 0xF3, 0x10, 0x5F, 0x94, 0xCE, 0x10, 0x60, 0x5F, 0xD5, 0x10, 0x61, 0x7D, 0xEA, 0x90, -0x62, 0x3F, 0xB7, 0x10, 0x63, 0x5D, 0xCC, 0x90, 0x64, 0x1F, 0x99, 0x10, 0x01, 0x04, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x05, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, -0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, -0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, -0x2D, 0x30, 0x32, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, -0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, -0x9B, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4D, 0x7C, 0x50, 0x00, 0x00, 0x00, 0x00, -0x14, 0x33, 0xFA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x15, 0x23, 0xEB, 0x90, 0x00, 0x00, 0x00, 0x00, -0x16, 0x13, 0xDC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0xCD, 0x90, 0x00, 0x00, 0x00, 0x00, -0x17, 0xF3, 0xBE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x18, 0xE3, 0xAF, 0x90, 0x00, 0x00, 0x00, 0x00, -0x19, 0xD3, 0xA0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xC3, 0x91, 0x90, 0x00, 0x00, 0x00, 0x00, -0x1B, 0xBC, 0xBD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xAC, 0xAE, 0x10, 0x00, 0x00, 0x00, 0x00, -0x1D, 0x9C, 0x9F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x8C, 0x90, 0x10, 0x00, 0x00, 0x00, 0x00, -0x1F, 0x7C, 0x81, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6C, 0x72, 0x10, 0x00, 0x00, 0x00, 0x00, -0x21, 0x5C, 0x63, 0x10, 0x00, 0x00, 0x00, 0x00, 0x22, 0x4C, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, -0x23, 0x3C, 0x45, 0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2C, 0x36, 0x10, 0x00, 0x00, 0x00, 0x00, -0x25, 0x1C, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0C, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, -0x27, 0x05, 0x43, 0x90, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF5, 0x34, 0x90, 0x00, 0x00, 0x00, 0x00, -0x28, 0xE5, 0x25, 0x90, 0x00, 0x00, 0x00, 0x00, 0x29, 0xD5, 0x16, 0x90, 0x00, 0x00, 0x00, 0x00, -0x2A, 0xC5, 0x07, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xB4, 0xF8, 0x90, 0x00, 0x00, 0x00, 0x00, -0x2C, 0xA4, 0xE9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xDA, 0x90, 0x00, 0x00, 0x00, 0x00, -0x2E, 0x84, 0xCB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0xBC, 0x90, 0x00, 0x00, 0x00, 0x00, -0x30, 0x64, 0xAD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0xD9, 0x10, 0x00, 0x00, 0x00, 0x00, -0x32, 0x72, 0xB4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0xBB, 0x10, 0x00, 0x00, 0x00, 0x00, -0x34, 0x52, 0x96, 0x10, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x9D, 0x10, 0x00, 0x00, 0x00, 0x00, -0x36, 0x32, 0x78, 0x10, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x7F, 0x10, 0x00, 0x00, 0x00, 0x00, -0x38, 0x1B, 0x94, 0x90, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x61, 0x10, 0x00, 0x00, 0x00, 0x00, -0x39, 0xFB, 0x76, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBD, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, -0x3B, 0xDB, 0x58, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x5F, 0x90, 0x00, 0x00, 0x00, 0x00, -0x3D, 0xBB, 0x3A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x86, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, -0x3F, 0x9B, 0x1C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x23, 0x90, 0x00, 0x00, 0x00, 0x00, -0x41, 0x84, 0x39, 0x10, 0x00, 0x00, 0x00, 0x00, 0x42, 0x46, 0x05, 0x90, 0x00, 0x00, 0x00, 0x00, -0x43, 0x64, 0x1B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0xE7, 0x90, 0x00, 0x00, 0x00, 0x00, -0x45, 0x43, 0xFD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xC9, 0x90, 0x00, 0x00, 0x00, 0x00, -0x47, 0x23, 0xDF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEE, 0xE6, 0x10, 0x00, 0x00, 0x00, 0x00, -0x49, 0x03, 0xC1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0xCE, 0xC8, 0x10, 0x00, 0x00, 0x00, 0x00, -0x4A, 0xE3, 0xA3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0xAA, 0x10, 0x00, 0x00, 0x00, 0x00, -0x4C, 0xCC, 0xBF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x8C, 0x10, 0x00, 0x00, 0x00, 0x00, -0x4E, 0xAC, 0xA1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6E, 0x6E, 0x10, 0x00, 0x00, 0x00, 0x00, -0x50, 0x8C, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x57, 0x8A, 0x90, 0x00, 0x00, 0x00, 0x00, -0x52, 0x6C, 0x65, 0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x37, 0x6C, 0x90, 0x00, 0x00, 0x00, 0x00, -0x54, 0x4C, 0x47, 0x90, 0x00, 0x00, 0x00, 0x00, 0x55, 0x17, 0x4E, 0x90, 0x00, 0x00, 0x00, 0x00, -0x56, 0x2C, 0x29, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xF7, 0x30, 0x90, 0x00, 0x00, 0x00, 0x00, -0x58, 0x15, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xD7, 0x12, 0x90, 0x00, 0x00, 0x00, 0x00, -0x59, 0xF5, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xB6, 0xF4, 0x90, 0x00, 0x00, 0x00, 0x00, -0x5B, 0xD5, 0x0A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA0, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, -0x5D, 0xB4, 0xEC, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xF3, 0x10, 0x00, 0x00, 0x00, 0x00, -0x5F, 0x94, 0xCE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xD5, 0x10, 0x00, 0x00, 0x00, 0x00, -0x61, 0x7D, 0xEA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xB7, 0x10, 0x00, 0x00, 0x00, 0x00, -0x63, 0x5D, 0xCC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x01, 0x04, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, +0x62, 0x3F, 0xB7, 0x10, 0x63, 0x5D, 0xCC, 0x90, 0x64, 0x1F, 0x99, 0x10, 0x65, 0x3D, 0xAE, 0x90, +0x66, 0x08, 0xB5, 0x90, 0x67, 0x1D, 0x90, 0x90, 0x67, 0xE8, 0x97, 0x90, 0x68, 0xFD, 0x72, 0x90, +0x69, 0xC8, 0x79, 0x90, 0x6A, 0xDD, 0x54, 0x90, 0x6B, 0xA8, 0x5B, 0x90, 0x6C, 0xC6, 0x71, 0x10, +0x6D, 0x88, 0x3D, 0x90, 0x6E, 0xA6, 0x53, 0x10, 0x6F, 0x68, 0x1F, 0x90, 0x70, 0x86, 0x35, 0x10, +0x71, 0x51, 0x3C, 0x10, 0x72, 0x66, 0x17, 0x10, 0x73, 0x31, 0x1E, 0x10, 0x74, 0x45, 0xF9, 0x10, +0x75, 0x11, 0x00, 0x10, 0x76, 0x2F, 0x15, 0x90, 0x76, 0xF0, 0xE2, 0x10, 0x78, 0x0E, 0xF7, 0x90, +0x78, 0xD0, 0xC4, 0x10, 0x79, 0xEE, 0xD9, 0x90, 0x7A, 0xB0, 0xA6, 0x10, 0x7B, 0xCE, 0xBB, 0x90, +0x7C, 0x99, 0xC2, 0x90, 0x7D, 0xAE, 0x9D, 0x90, 0x7E, 0x79, 0xA4, 0x90, 0x7F, 0x8E, 0x7F, 0x90, +0x01, 0x04, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x05, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, -0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, -0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, -0x2D, 0x30, 0x32, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, -0x0A, 0x3C, 0x2D, 0x30, 0x32, 0x3E, 0x32, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, +0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, +0x04, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, +0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0xFF, 0xFF, 0xF1, 0xF0, 0x01, 0x0C, 0x4C, +0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x2D, 0x30, 0x32, 0x00, 0x2D, 0x30, 0x31, 0x00, 0x00, +0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x54, 0x5A, 0x69, +0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x75, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x80, 0x68, +0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4D, 0x7C, 0x50, 0x00, 0x00, 0x00, 0x00, 0x14, 0x33, 0xFA, +0x90, 0x00, 0x00, 0x00, 0x00, 0x15, 0x23, 0xEB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x16, 0x13, 0xDC, +0x90, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0xCD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x17, 0xF3, 0xBE, +0x90, 0x00, 0x00, 0x00, 0x00, 0x18, 0xE3, 0xAF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x19, 0xD3, 0xA0, +0x90, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xC3, 0x91, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xBC, 0xBD, +0x10, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xAC, 0xAE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x9C, 0x9F, +0x10, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x8C, 0x90, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x81, +0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6C, 0x72, 0x10, 0x00, 0x00, 0x00, 0x00, 0x21, 0x5C, 0x63, +0x10, 0x00, 0x00, 0x00, 0x00, 0x22, 0x4C, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, 0x23, 0x3C, 0x45, +0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2C, 0x36, 0x10, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1C, 0x27, +0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0C, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, 0x27, 0x05, 0x43, +0x90, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF5, 0x34, 0x90, 0x00, 0x00, 0x00, 0x00, 0x28, 0xE5, 0x25, +0x90, 0x00, 0x00, 0x00, 0x00, 0x29, 0xD5, 0x16, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xC5, 0x07, +0x90, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xB4, 0xF8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xA4, 0xE9, +0x90, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xDA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x84, 0xCB, +0x90, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0xBC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x30, 0x64, 0xAD, +0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0xD9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xB4, +0x10, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0xBB, 0x10, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x96, +0x10, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x9D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0x78, +0x10, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x7F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, 0x94, +0x90, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x61, 0x10, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, 0x76, +0x90, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBD, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, 0x58, +0x90, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x5F, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBB, 0x3A, +0x90, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x86, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9B, 0x1C, +0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x23, 0x90, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x39, +0x10, 0x00, 0x00, 0x00, 0x00, 0x42, 0x46, 0x05, 0x90, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x1B, +0x10, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0xE7, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xFD, +0x10, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xC9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x47, 0x23, 0xDF, +0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEE, 0xE6, 0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0x03, 0xC1, +0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0xCE, 0xC8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4A, 0xE3, 0xA3, +0x10, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0xAA, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xCC, 0xBF, +0x90, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x8C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4E, 0xAC, 0xA1, +0x90, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6E, 0x6E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x50, 0x8C, 0x83, +0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x57, 0x8A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6C, 0x65, +0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x37, 0x6C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x54, 0x4C, 0x47, +0x90, 0x00, 0x00, 0x00, 0x00, 0x55, 0x17, 0x4E, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0x2C, 0x29, +0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xF7, 0x30, 0x90, 0x00, 0x00, 0x00, 0x00, 0x58, 0x15, 0x46, +0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xD7, 0x12, 0x90, 0x00, 0x00, 0x00, 0x00, 0x59, 0xF5, 0x28, +0x10, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xB6, 0xF4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x5B, 0xD5, 0x0A, +0x10, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA0, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xB4, 0xEC, +0x10, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xF3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x94, 0xCE, +0x10, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xD5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x7D, 0xEA, +0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xB7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x63, 0x5D, 0xCC, +0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3D, 0xAE, +0x90, 0x00, 0x00, 0x00, 0x00, 0x66, 0x08, 0xB5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0x1D, 0x90, +0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xE8, 0x97, 0x90, 0x00, 0x00, 0x00, 0x00, 0x68, 0xFD, 0x72, +0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xC8, 0x79, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xDD, 0x54, +0x90, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xA8, 0x5B, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xC6, 0x71, +0x10, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x88, 0x3D, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA6, 0x53, +0x10, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x68, 0x1F, 0x90, 0x00, 0x00, 0x00, 0x00, 0x70, 0x86, 0x35, +0x10, 0x00, 0x00, 0x00, 0x00, 0x71, 0x51, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x72, 0x66, 0x17, +0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x31, 0x1E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0x45, 0xF9, +0x10, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x76, 0x2F, 0x15, +0x90, 0x00, 0x00, 0x00, 0x00, 0x76, 0xF0, 0xE2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0E, 0xF7, +0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xD0, 0xC4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x79, 0xEE, 0xD9, +0x90, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xB0, 0xA6, 0x10, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCE, 0xBB, +0x90, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x99, 0xC2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xAE, 0x9D, +0x90, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x79, 0xA4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x8E, 0x7F, +0x90, 0x01, 0x04, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, +0x00, 0x04, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, +0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0xFF, 0xFF, 0xF1, 0xF0, 0x01, 0x0C, +0x4C, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x2D, 0x30, 0x32, 0x00, 0x2D, 0x30, 0x31, 0x00, +0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x0A, 0x3C, +0x2D, 0x30, 0x32, 0x3E, 0x32, 0x3C, 0x2D, 0x30, 0x31, 0x3E, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, +0x30, 0x2F, 0x2D, 0x31, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x30, 0x0A, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* America/Goose_Bay */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -36729,8 +36953,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { /* America/Nuuk */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x47, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x9B, 0x80, 0x68, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x9B, 0x80, 0x68, 0x00, 0x13, 0x4D, 0x7C, 0x50, 0x14, 0x33, 0xFA, 0x90, 0x15, 0x23, 0xEB, 0x90, 0x16, 0x13, 0xDC, 0x90, 0x17, 0x03, 0xCD, 0x90, 0x17, 0xF3, 0xBE, 0x90, 0x18, 0xE3, 0xAF, 0x90, 0x19, 0xD3, 0xA0, 0x90, 0x1A, 0xC3, 0x91, 0x90, 0x1B, 0xBC, 0xBD, 0x10, 0x1C, 0xAC, 0xAE, 0x10, 0x1D, 0x9C, 0x9F, 0x10, @@ -36752,75 +36976,103 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x56, 0xF7, 0x30, 0x90, 0x58, 0x15, 0x46, 0x10, 0x58, 0xD7, 0x12, 0x90, 0x59, 0xF5, 0x28, 0x10, 0x5A, 0xB6, 0xF4, 0x90, 0x5B, 0xD5, 0x0A, 0x10, 0x5C, 0xA0, 0x11, 0x10, 0x5D, 0xB4, 0xEC, 0x10, 0x5E, 0x7F, 0xF3, 0x10, 0x5F, 0x94, 0xCE, 0x10, 0x60, 0x5F, 0xD5, 0x10, 0x61, 0x7D, 0xEA, 0x90, -0x62, 0x3F, 0xB7, 0x10, 0x63, 0x5D, 0xCC, 0x90, 0x64, 0x1F, 0x99, 0x10, 0x01, 0x04, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x05, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, -0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, -0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, -0x2D, 0x30, 0x32, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, -0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, -0x9B, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4D, 0x7C, 0x50, 0x00, 0x00, 0x00, 0x00, -0x14, 0x33, 0xFA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x15, 0x23, 0xEB, 0x90, 0x00, 0x00, 0x00, 0x00, -0x16, 0x13, 0xDC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0xCD, 0x90, 0x00, 0x00, 0x00, 0x00, -0x17, 0xF3, 0xBE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x18, 0xE3, 0xAF, 0x90, 0x00, 0x00, 0x00, 0x00, -0x19, 0xD3, 0xA0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xC3, 0x91, 0x90, 0x00, 0x00, 0x00, 0x00, -0x1B, 0xBC, 0xBD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xAC, 0xAE, 0x10, 0x00, 0x00, 0x00, 0x00, -0x1D, 0x9C, 0x9F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x8C, 0x90, 0x10, 0x00, 0x00, 0x00, 0x00, -0x1F, 0x7C, 0x81, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6C, 0x72, 0x10, 0x00, 0x00, 0x00, 0x00, -0x21, 0x5C, 0x63, 0x10, 0x00, 0x00, 0x00, 0x00, 0x22, 0x4C, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, -0x23, 0x3C, 0x45, 0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2C, 0x36, 0x10, 0x00, 0x00, 0x00, 0x00, -0x25, 0x1C, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0C, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, -0x27, 0x05, 0x43, 0x90, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF5, 0x34, 0x90, 0x00, 0x00, 0x00, 0x00, -0x28, 0xE5, 0x25, 0x90, 0x00, 0x00, 0x00, 0x00, 0x29, 0xD5, 0x16, 0x90, 0x00, 0x00, 0x00, 0x00, -0x2A, 0xC5, 0x07, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xB4, 0xF8, 0x90, 0x00, 0x00, 0x00, 0x00, -0x2C, 0xA4, 0xE9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xDA, 0x90, 0x00, 0x00, 0x00, 0x00, -0x2E, 0x84, 0xCB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0xBC, 0x90, 0x00, 0x00, 0x00, 0x00, -0x30, 0x64, 0xAD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0xD9, 0x10, 0x00, 0x00, 0x00, 0x00, -0x32, 0x72, 0xB4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0xBB, 0x10, 0x00, 0x00, 0x00, 0x00, -0x34, 0x52, 0x96, 0x10, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x9D, 0x10, 0x00, 0x00, 0x00, 0x00, -0x36, 0x32, 0x78, 0x10, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x7F, 0x10, 0x00, 0x00, 0x00, 0x00, -0x38, 0x1B, 0x94, 0x90, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x61, 0x10, 0x00, 0x00, 0x00, 0x00, -0x39, 0xFB, 0x76, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBD, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, -0x3B, 0xDB, 0x58, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x5F, 0x90, 0x00, 0x00, 0x00, 0x00, -0x3D, 0xBB, 0x3A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x86, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, -0x3F, 0x9B, 0x1C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x23, 0x90, 0x00, 0x00, 0x00, 0x00, -0x41, 0x84, 0x39, 0x10, 0x00, 0x00, 0x00, 0x00, 0x42, 0x46, 0x05, 0x90, 0x00, 0x00, 0x00, 0x00, -0x43, 0x64, 0x1B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0xE7, 0x90, 0x00, 0x00, 0x00, 0x00, -0x45, 0x43, 0xFD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xC9, 0x90, 0x00, 0x00, 0x00, 0x00, -0x47, 0x23, 0xDF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEE, 0xE6, 0x10, 0x00, 0x00, 0x00, 0x00, -0x49, 0x03, 0xC1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0xCE, 0xC8, 0x10, 0x00, 0x00, 0x00, 0x00, -0x4A, 0xE3, 0xA3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0xAA, 0x10, 0x00, 0x00, 0x00, 0x00, -0x4C, 0xCC, 0xBF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x8C, 0x10, 0x00, 0x00, 0x00, 0x00, -0x4E, 0xAC, 0xA1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6E, 0x6E, 0x10, 0x00, 0x00, 0x00, 0x00, -0x50, 0x8C, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x57, 0x8A, 0x90, 0x00, 0x00, 0x00, 0x00, -0x52, 0x6C, 0x65, 0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x37, 0x6C, 0x90, 0x00, 0x00, 0x00, 0x00, -0x54, 0x4C, 0x47, 0x90, 0x00, 0x00, 0x00, 0x00, 0x55, 0x17, 0x4E, 0x90, 0x00, 0x00, 0x00, 0x00, -0x56, 0x2C, 0x29, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xF7, 0x30, 0x90, 0x00, 0x00, 0x00, 0x00, -0x58, 0x15, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xD7, 0x12, 0x90, 0x00, 0x00, 0x00, 0x00, -0x59, 0xF5, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xB6, 0xF4, 0x90, 0x00, 0x00, 0x00, 0x00, -0x5B, 0xD5, 0x0A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA0, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, -0x5D, 0xB4, 0xEC, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xF3, 0x10, 0x00, 0x00, 0x00, 0x00, -0x5F, 0x94, 0xCE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xD5, 0x10, 0x00, 0x00, 0x00, 0x00, -0x61, 0x7D, 0xEA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xB7, 0x10, 0x00, 0x00, 0x00, 0x00, -0x63, 0x5D, 0xCC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x01, 0x04, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, +0x62, 0x3F, 0xB7, 0x10, 0x63, 0x5D, 0xCC, 0x90, 0x64, 0x1F, 0x99, 0x10, 0x65, 0x3D, 0xAE, 0x90, +0x66, 0x08, 0xB5, 0x90, 0x67, 0x1D, 0x90, 0x90, 0x67, 0xE8, 0x97, 0x90, 0x68, 0xFD, 0x72, 0x90, +0x69, 0xC8, 0x79, 0x90, 0x6A, 0xDD, 0x54, 0x90, 0x6B, 0xA8, 0x5B, 0x90, 0x6C, 0xC6, 0x71, 0x10, +0x6D, 0x88, 0x3D, 0x90, 0x6E, 0xA6, 0x53, 0x10, 0x6F, 0x68, 0x1F, 0x90, 0x70, 0x86, 0x35, 0x10, +0x71, 0x51, 0x3C, 0x10, 0x72, 0x66, 0x17, 0x10, 0x73, 0x31, 0x1E, 0x10, 0x74, 0x45, 0xF9, 0x10, +0x75, 0x11, 0x00, 0x10, 0x76, 0x2F, 0x15, 0x90, 0x76, 0xF0, 0xE2, 0x10, 0x78, 0x0E, 0xF7, 0x90, +0x78, 0xD0, 0xC4, 0x10, 0x79, 0xEE, 0xD9, 0x90, 0x7A, 0xB0, 0xA6, 0x10, 0x7B, 0xCE, 0xBB, 0x90, +0x7C, 0x99, 0xC2, 0x90, 0x7D, 0xAE, 0x9D, 0x90, 0x7E, 0x79, 0xA4, 0x90, 0x7F, 0x8E, 0x7F, 0x90, +0x01, 0x04, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x05, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, -0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, -0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, -0x2D, 0x30, 0x32, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, -0x0A, 0x3C, 0x2D, 0x30, 0x32, 0x3E, 0x32, 0x0A, 0x00, 0xEB, 0x43, 0xDD, 0x00, 0xC3, 0xB8, 0x2A, -0x00, 0x00, 0x00, 0x16, 0x47, 0x72, 0x65, 0x65, 0x6E, 0x6C, 0x61, 0x6E, 0x64, 0x20, 0x28, 0x6D, -0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, +0x05, 0x06, 0x05, 0x06, 0x05, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, +0x04, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, +0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0xFF, 0xFF, 0xF1, 0xF0, 0x01, 0x0C, 0x4C, +0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x2D, 0x30, 0x32, 0x00, 0x2D, 0x30, 0x31, 0x00, 0x00, +0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x54, 0x5A, 0x69, +0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x75, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x9B, 0x80, 0x68, +0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4D, 0x7C, 0x50, 0x00, 0x00, 0x00, 0x00, 0x14, 0x33, 0xFA, +0x90, 0x00, 0x00, 0x00, 0x00, 0x15, 0x23, 0xEB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x16, 0x13, 0xDC, +0x90, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0xCD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x17, 0xF3, 0xBE, +0x90, 0x00, 0x00, 0x00, 0x00, 0x18, 0xE3, 0xAF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x19, 0xD3, 0xA0, +0x90, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xC3, 0x91, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xBC, 0xBD, +0x10, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xAC, 0xAE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x9C, 0x9F, +0x10, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x8C, 0x90, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x81, +0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6C, 0x72, 0x10, 0x00, 0x00, 0x00, 0x00, 0x21, 0x5C, 0x63, +0x10, 0x00, 0x00, 0x00, 0x00, 0x22, 0x4C, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, 0x23, 0x3C, 0x45, +0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2C, 0x36, 0x10, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1C, 0x27, +0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0C, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, 0x27, 0x05, 0x43, +0x90, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF5, 0x34, 0x90, 0x00, 0x00, 0x00, 0x00, 0x28, 0xE5, 0x25, +0x90, 0x00, 0x00, 0x00, 0x00, 0x29, 0xD5, 0x16, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xC5, 0x07, +0x90, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xB4, 0xF8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xA4, 0xE9, +0x90, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xDA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x84, 0xCB, +0x90, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0xBC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x30, 0x64, 0xAD, +0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0xD9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xB4, +0x10, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0xBB, 0x10, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x96, +0x10, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x9D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0x78, +0x10, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x7F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, 0x94, +0x90, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x61, 0x10, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, 0x76, +0x90, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBD, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, 0x58, +0x90, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x5F, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBB, 0x3A, +0x90, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x86, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9B, 0x1C, +0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x23, 0x90, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x39, +0x10, 0x00, 0x00, 0x00, 0x00, 0x42, 0x46, 0x05, 0x90, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x1B, +0x10, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0xE7, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xFD, +0x10, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xC9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x47, 0x23, 0xDF, +0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEE, 0xE6, 0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0x03, 0xC1, +0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0xCE, 0xC8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4A, 0xE3, 0xA3, +0x10, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0xAA, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xCC, 0xBF, +0x90, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x8C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4E, 0xAC, 0xA1, +0x90, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6E, 0x6E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x50, 0x8C, 0x83, +0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x57, 0x8A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6C, 0x65, +0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x37, 0x6C, 0x90, 0x00, 0x00, 0x00, 0x00, 0x54, 0x4C, 0x47, +0x90, 0x00, 0x00, 0x00, 0x00, 0x55, 0x17, 0x4E, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0x2C, 0x29, +0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xF7, 0x30, 0x90, 0x00, 0x00, 0x00, 0x00, 0x58, 0x15, 0x46, +0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xD7, 0x12, 0x90, 0x00, 0x00, 0x00, 0x00, 0x59, 0xF5, 0x28, +0x10, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xB6, 0xF4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x5B, 0xD5, 0x0A, +0x10, 0x00, 0x00, 0x00, 0x00, 0x5C, 0xA0, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xB4, 0xEC, +0x10, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7F, 0xF3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x94, 0xCE, +0x10, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5F, 0xD5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x7D, 0xEA, +0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0xB7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x63, 0x5D, 0xCC, +0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1F, 0x99, 0x10, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3D, 0xAE, +0x90, 0x00, 0x00, 0x00, 0x00, 0x66, 0x08, 0xB5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0x1D, 0x90, +0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xE8, 0x97, 0x90, 0x00, 0x00, 0x00, 0x00, 0x68, 0xFD, 0x72, +0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xC8, 0x79, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xDD, 0x54, +0x90, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xA8, 0x5B, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xC6, 0x71, +0x10, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x88, 0x3D, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA6, 0x53, +0x10, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x68, 0x1F, 0x90, 0x00, 0x00, 0x00, 0x00, 0x70, 0x86, 0x35, +0x10, 0x00, 0x00, 0x00, 0x00, 0x71, 0x51, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x72, 0x66, 0x17, +0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x31, 0x1E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0x45, 0xF9, +0x10, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x76, 0x2F, 0x15, +0x90, 0x00, 0x00, 0x00, 0x00, 0x76, 0xF0, 0xE2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0E, 0xF7, +0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xD0, 0xC4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x79, 0xEE, 0xD9, +0x90, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xB0, 0xA6, 0x10, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCE, 0xBB, +0x90, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x99, 0xC2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xAE, 0x9D, +0x90, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x79, 0xA4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x8E, 0x7F, +0x90, 0x01, 0x04, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, +0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0xFF, 0xFF, 0xCF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xD5, 0xD0, +0x00, 0x04, 0xFF, 0xFF, 0xD5, 0xD0, 0x00, 0x04, 0xFF, 0xFF, 0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, +0xE3, 0xE0, 0x01, 0x08, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x08, 0xFF, 0xFF, 0xF1, 0xF0, 0x01, 0x0C, +0x4C, 0x4D, 0x54, 0x00, 0x2D, 0x30, 0x33, 0x00, 0x2D, 0x30, 0x32, 0x00, 0x2D, 0x30, 0x31, 0x00, +0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x0A, 0x3C, +0x2D, 0x30, 0x32, 0x3E, 0x32, 0x3C, 0x2D, 0x30, 0x31, 0x3E, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, +0x30, 0x2F, 0x2D, 0x31, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x30, 0x0A, 0x00, +0xEB, 0x43, 0xDD, 0x00, 0xC3, 0xB8, 0x2A, 0x00, 0x00, 0x00, 0x11, 0x6D, 0x6F, 0x73, 0x74, 0x20, +0x6F, 0x66, 0x20, 0x47, 0x72, 0x65, 0x65, 0x6E, 0x6C, 0x61, 0x6E, 0x64, /* America/Ojinaga */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -37121,9 +37373,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x08, 0x4C, 0x4D, 0x54, 0x00, 0x4D, 0x44, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x4D, 0x53, 0x54, 0x37, 0x0A, 0x00, 0xBC, 0x5E, 0x01, 0x00, 0x67, 0xA5, 0xDA, -0x00, 0x00, 0x00, 0x1D, 0x4D, 0x53, 0x54, 0x20, 0x2D, 0x20, 0x41, 0x72, 0x69, 0x7A, 0x6F, 0x6E, -0x61, 0x20, 0x28, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x20, 0x4E, 0x61, 0x76, 0x61, 0x6A, 0x6F, -0x29, +0x00, 0x00, 0x00, 0x18, 0x4D, 0x53, 0x54, 0x20, 0x2D, 0x20, 0x41, 0x5A, 0x20, 0x28, 0x65, 0x78, +0x63, 0x65, 0x70, 0x74, 0x20, 0x4E, 0x61, 0x76, 0x61, 0x6A, 0x6F, 0x29, /* America/Port-au-Prince */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x48, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -38482,9 +38733,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x3C, 0x2D, 0x30, 0x34, 0x3E, 0x34, 0x3C, 0x2D, 0x30, 0x33, 0x3E, 0x2C, 0x4D, 0x39, 0x2E, 0x31, 0x2E, 0x36, 0x2F, 0x32, 0x34, 0x2C, 0x4D, 0x34, 0x2E, 0x31, 0x2E, 0x36, 0x2F, -0x32, 0x34, 0x0A, 0x00, 0x56, 0x49, 0xD8, 0x00, 0xA6, 0xD4, 0x55, 0x00, 0x00, 0x00, 0x12, 0x43, -0x68, 0x69, 0x6C, 0x65, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, -0x29, +0x32, 0x34, 0x0A, 0x00, 0x56, 0x49, 0xD8, 0x00, 0xA6, 0xD4, 0x55, 0x00, 0x00, 0x00, 0x0D, 0x6D, +0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x43, 0x68, 0x69, 0x6C, 0x65, /* America/Santo_Domingo */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x44, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -40764,142 +41014,153 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x73, 0x6B, 0x61, 0x20, 0x2D, 0x20, 0x59, 0x61, 0x6B, 0x75, 0x74, 0x61, 0x74, /* America/Yellowknife */ -0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xBE, 0x2A, 0x18, 0x00, -0xCB, 0x89, 0x0C, 0x90, 0xD2, 0x23, 0xF4, 0x70, 0xD2, 0x61, 0x18, 0x00, 0x04, 0x61, 0x19, 0x90, -0x05, 0x50, 0xFC, 0x80, 0x06, 0x40, 0xFB, 0x90, 0x07, 0x30, 0xDE, 0x80, 0x08, 0x20, 0xDD, 0x90, -0x09, 0x10, 0xC0, 0x80, 0x0A, 0x00, 0xBF, 0x90, 0x0A, 0xF0, 0xA2, 0x80, 0x0B, 0xE0, 0xA1, 0x90, -0x0C, 0xD9, 0xBF, 0x00, 0x0D, 0xC0, 0x83, 0x90, 0x0E, 0xB9, 0xA1, 0x00, 0x0F, 0xA9, 0xA0, 0x10, -0x10, 0x99, 0x83, 0x00, 0x11, 0x89, 0x82, 0x10, 0x12, 0x79, 0x65, 0x00, 0x13, 0x69, 0x64, 0x10, -0x14, 0x59, 0x47, 0x00, 0x15, 0x49, 0x46, 0x10, 0x16, 0x39, 0x29, 0x00, 0x17, 0x29, 0x28, 0x10, -0x18, 0x22, 0x45, 0x80, 0x19, 0x09, 0x0A, 0x10, 0x1A, 0x02, 0x27, 0x80, 0x1A, 0xF2, 0x26, 0x90, -0x1B, 0xE2, 0x09, 0x80, 0x1C, 0xD2, 0x08, 0x90, 0x1D, 0xC1, 0xEB, 0x80, 0x1E, 0xB1, 0xEA, 0x90, -0x1F, 0xA1, 0xCD, 0x80, 0x20, 0x76, 0x1D, 0x10, 0x21, 0x81, 0xAF, 0x80, 0x22, 0x55, 0xFF, 0x10, -0x23, 0x6A, 0xCC, 0x00, 0x24, 0x35, 0xE1, 0x10, 0x25, 0x4A, 0xAE, 0x00, 0x26, 0x15, 0xC3, 0x10, -0x27, 0x2A, 0x90, 0x00, 0x27, 0xFE, 0xDF, 0x90, 0x29, 0x0A, 0x72, 0x00, 0x29, 0xDE, 0xC1, 0x90, -0x2A, 0xEA, 0x54, 0x00, 0x2B, 0xBE, 0xA3, 0x90, 0x2C, 0xD3, 0x70, 0x80, 0x2D, 0x9E, 0x85, 0x90, -0x2E, 0xB3, 0x52, 0x80, 0x2F, 0x7E, 0x67, 0x90, 0x30, 0x93, 0x34, 0x80, 0x31, 0x67, 0x84, 0x10, -0x32, 0x73, 0x16, 0x80, 0x33, 0x47, 0x66, 0x10, 0x34, 0x52, 0xF8, 0x80, 0x35, 0x27, 0x48, 0x10, -0x36, 0x32, 0xDA, 0x80, 0x37, 0x07, 0x2A, 0x10, 0x38, 0x1B, 0xF7, 0x00, 0x38, 0xE7, 0x0C, 0x10, -0x39, 0xFB, 0xD9, 0x00, 0x3A, 0xC6, 0xEE, 0x10, 0x3B, 0xDB, 0xBB, 0x00, 0x3C, 0xB0, 0x0A, 0x90, -0x3D, 0xBB, 0x9D, 0x00, 0x3E, 0x8F, 0xEC, 0x90, 0x3F, 0x9B, 0x7F, 0x00, 0x40, 0x6F, 0xCE, 0x90, -0x41, 0x84, 0x9B, 0x80, 0x42, 0x4F, 0xB0, 0x90, 0x43, 0x64, 0x7D, 0x80, 0x44, 0x2F, 0x92, 0x90, -0x45, 0x44, 0x5F, 0x80, 0x45, 0xF3, 0xC5, 0x10, 0x47, 0x2D, 0x7C, 0x00, 0x47, 0xD3, 0xA7, 0x10, -0x49, 0x0D, 0x5E, 0x00, 0x49, 0xB3, 0x89, 0x10, 0x4A, 0xED, 0x40, 0x00, 0x4B, 0x9C, 0xA5, 0x90, -0x4C, 0xD6, 0x5C, 0x80, 0x4D, 0x7C, 0x87, 0x90, 0x4E, 0xB6, 0x3E, 0x80, 0x4F, 0x5C, 0x69, 0x90, -0x50, 0x96, 0x20, 0x80, 0x51, 0x3C, 0x4B, 0x90, 0x52, 0x76, 0x02, 0x80, 0x53, 0x1C, 0x2D, 0x90, -0x54, 0x55, 0xE4, 0x80, 0x54, 0xFC, 0x0F, 0x90, 0x56, 0x35, 0xC6, 0x80, 0x56, 0xE5, 0x2C, 0x10, -0x58, 0x1E, 0xE3, 0x00, 0x58, 0xC5, 0x0E, 0x10, 0x59, 0xFE, 0xC5, 0x00, 0x5A, 0xA4, 0xF0, 0x10, -0x5B, 0xDE, 0xA7, 0x00, 0x5C, 0x84, 0xD2, 0x10, 0x5D, 0xBE, 0x89, 0x00, 0x5E, 0x64, 0xB4, 0x10, -0x5F, 0x9E, 0x6B, 0x00, 0x60, 0x4D, 0xD0, 0x90, 0x61, 0x87, 0x87, 0x80, 0x62, 0x2D, 0xB2, 0x90, -0x63, 0x67, 0x69, 0x80, 0x64, 0x0D, 0x94, 0x90, 0x65, 0x47, 0x4B, 0x80, 0x65, 0xED, 0x76, 0x90, -0x67, 0x27, 0x2D, 0x80, 0x67, 0xCD, 0x58, 0x90, 0x69, 0x07, 0x0F, 0x80, 0x69, 0xAD, 0x3A, 0x90, -0x6A, 0xE6, 0xF1, 0x80, 0x6B, 0x96, 0x57, 0x10, 0x6C, 0xD0, 0x0E, 0x00, 0x6D, 0x76, 0x39, 0x10, -0x6E, 0xAF, 0xF0, 0x00, 0x6F, 0x56, 0x1B, 0x10, 0x70, 0x8F, 0xD2, 0x00, 0x71, 0x35, 0xFD, 0x10, -0x72, 0x6F, 0xB4, 0x00, 0x73, 0x15, 0xDF, 0x10, 0x74, 0x4F, 0x96, 0x00, 0x74, 0xFE, 0xFB, 0x90, -0x76, 0x38, 0xB2, 0x80, 0x76, 0xDE, 0xDD, 0x90, 0x78, 0x18, 0x94, 0x80, 0x78, 0xBE, 0xBF, 0x90, -0x79, 0xF8, 0x76, 0x80, 0x7A, 0x9E, 0xA1, 0x90, 0x7B, 0xD8, 0x58, 0x80, 0x7C, 0x7E, 0x83, 0x90, -0x7D, 0xB8, 0x3A, 0x80, 0x7E, 0x5E, 0x65, 0x90, 0x7F, 0x98, 0x1C, 0x80, 0x03, 0x01, 0x02, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x04, -0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x0C, 0xFF, 0xFF, 0xAB, 0xA0, -0x01, 0x10, 0x2D, 0x30, 0x30, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x4D, 0x50, 0x54, 0x00, 0x4D, 0x53, -0x54, 0x00, 0x4D, 0x44, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, -0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xFF, 0xFF, 0xFF, 0xFF, -0xBE, 0x2A, 0x18, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0x89, 0x0C, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, -0xD2, 0x23, 0xF4, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0x61, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, -0x04, 0x61, 0x19, 0x90, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0xFC, 0x80, 0x00, 0x00, 0x00, 0x00, -0x06, 0x40, 0xFB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, 0xDE, 0x80, 0x00, 0x00, 0x00, 0x00, -0x08, 0x20, 0xDD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, -0x0A, 0x00, 0xBF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xF0, 0xA2, 0x80, 0x00, 0x00, 0x00, 0x00, -0x0B, 0xE0, 0xA1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, -0x0D, 0xC0, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, -0x0F, 0xA9, 0xA0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, -0x11, 0x89, 0x82, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, 0x79, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, -0x13, 0x69, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x14, 0x59, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, -0x15, 0x49, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, -0x17, 0x29, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x18, 0x22, 0x45, 0x80, 0x00, 0x00, 0x00, 0x00, -0x19, 0x09, 0x0A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x02, 0x27, 0x80, 0x00, 0x00, 0x00, 0x00, -0x1A, 0xF2, 0x26, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xE2, 0x09, 0x80, 0x00, 0x00, 0x00, 0x00, -0x1C, 0xD2, 0x08, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xC1, 0xEB, 0x80, 0x00, 0x00, 0x00, 0x00, -0x1E, 0xB1, 0xEA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xA1, 0xCD, 0x80, 0x00, 0x00, 0x00, 0x00, -0x20, 0x76, 0x1D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0xAF, 0x80, 0x00, 0x00, 0x00, 0x00, -0x22, 0x55, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x23, 0x6A, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, -0x24, 0x35, 0xE1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x25, 0x4A, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, -0x26, 0x15, 0xC3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, -0x27, 0xFE, 0xDF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0A, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, -0x29, 0xDE, 0xC1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xEA, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, -0x2B, 0xBE, 0xA3, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xD3, 0x70, 0x80, 0x00, 0x00, 0x00, 0x00, -0x2D, 0x9E, 0x85, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2E, 0xB3, 0x52, 0x80, 0x00, 0x00, 0x00, 0x00, -0x2F, 0x7E, 0x67, 0x90, 0x00, 0x00, 0x00, 0x00, 0x30, 0x93, 0x34, 0x80, 0x00, 0x00, 0x00, 0x00, -0x31, 0x67, 0x84, 0x10, 0x00, 0x00, 0x00, 0x00, 0x32, 0x73, 0x16, 0x80, 0x00, 0x00, 0x00, 0x00, -0x33, 0x47, 0x66, 0x10, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, -0x35, 0x27, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0xDA, 0x80, 0x00, 0x00, 0x00, 0x00, -0x37, 0x07, 0x2A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, -0x38, 0xE7, 0x0C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, -0x3A, 0xC6, 0xEE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, -0x3C, 0xB0, 0x0A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBB, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x00, -0x3E, 0x8F, 0xEC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9B, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, -0x40, 0x6F, 0xCE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x9B, 0x80, 0x00, 0x00, 0x00, 0x00, -0x42, 0x4F, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x7D, 0x80, 0x00, 0x00, 0x00, 0x00, -0x44, 0x2F, 0x92, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, 0x5F, 0x80, 0x00, 0x00, 0x00, 0x00, -0x45, 0xF3, 0xC5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0x2D, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, -0x47, 0xD3, 0xA7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0D, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, -0x49, 0xB3, 0x89, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4A, 0xED, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, -0x4B, 0x9C, 0xA5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xD6, 0x5C, 0x80, 0x00, 0x00, 0x00, 0x00, -0x4D, 0x7C, 0x87, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4E, 0xB6, 0x3E, 0x80, 0x00, 0x00, 0x00, 0x00, -0x4F, 0x5C, 0x69, 0x90, 0x00, 0x00, 0x00, 0x00, 0x50, 0x96, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, -0x51, 0x3C, 0x4B, 0x90, 0x00, 0x00, 0x00, 0x00, 0x52, 0x76, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, -0x53, 0x1C, 0x2D, 0x90, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xE4, 0x80, 0x00, 0x00, 0x00, 0x00, -0x54, 0xFC, 0x0F, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0x35, 0xC6, 0x80, 0x00, 0x00, 0x00, 0x00, -0x56, 0xE5, 0x2C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0x1E, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, -0x58, 0xC5, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x59, 0xFE, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, -0x5A, 0xA4, 0xF0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5B, 0xDE, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, -0x5C, 0x84, 0xD2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xBE, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, -0x5E, 0x64, 0xB4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x9E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, -0x60, 0x4D, 0xD0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x61, 0x87, 0x87, 0x80, 0x00, 0x00, 0x00, 0x00, -0x62, 0x2D, 0xB2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x63, 0x67, 0x69, 0x80, 0x00, 0x00, 0x00, 0x00, -0x64, 0x0D, 0x94, 0x90, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x4B, 0x80, 0x00, 0x00, 0x00, 0x00, -0x65, 0xED, 0x76, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0x27, 0x2D, 0x80, 0x00, 0x00, 0x00, 0x00, -0x67, 0xCD, 0x58, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0x07, 0x0F, 0x80, 0x00, 0x00, 0x00, 0x00, -0x69, 0xAD, 0x3A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xE6, 0xF1, 0x80, 0x00, 0x00, 0x00, 0x00, -0x6B, 0x96, 0x57, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xD0, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, -0x6D, 0x76, 0x39, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xAF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, -0x6F, 0x56, 0x1B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8F, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, -0x71, 0x35, 0xFD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6F, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, -0x73, 0x15, 0xDF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0x4F, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, -0x74, 0xFE, 0xFB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0xB2, 0x80, 0x00, 0x00, 0x00, 0x00, -0x76, 0xDE, 0xDD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0x18, 0x94, 0x80, 0x00, 0x00, 0x00, 0x00, -0x78, 0xBE, 0xBF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x79, 0xF8, 0x76, 0x80, 0x00, 0x00, 0x00, 0x00, -0x7A, 0x9E, 0xA1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xD8, 0x58, 0x80, 0x00, 0x00, 0x00, 0x00, -0x7C, 0x7E, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xB8, 0x3A, 0x80, 0x00, 0x00, 0x00, 0x00, -0x7E, 0x5E, 0x65, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x98, 0x1C, 0x80, 0x03, 0x01, 0x02, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, -0x04, 0x03, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x04, -0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x0C, 0xFF, 0xFF, 0xAB, 0xA0, -0x01, 0x10, 0x2D, 0x30, 0x30, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x4D, 0x50, 0x54, 0x00, 0x4D, 0x53, -0x54, 0x00, 0x4D, 0x44, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, -0x0A, 0x4D, 0x53, 0x54, 0x37, 0x4D, 0x44, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x32, 0x2E, 0x30, 0x2C, -0x4D, 0x31, 0x31, 0x2E, 0x31, 0x2E, 0x30, 0x0A, 0x00, 0xE8, 0x9E, 0xC7, 0x00, 0x64, 0x2C, 0x88, -0x00, 0x00, 0x00, 0x17, 0x4D, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x2D, 0x20, 0x4E, -0x54, 0x20, 0x28, 0x63, 0x65, 0x6E, 0x74, 0x72, 0x61, 0x6C, 0x29, +0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x88, 0xDE, 0xCE, 0xE0, +0x9E, 0xB8, 0xAF, 0x90, 0x9F, 0xBB, 0x07, 0x80, 0xA0, 0x98, 0x91, 0x90, 0xA0, 0xD2, 0x85, 0x80, +0xA2, 0x8A, 0xE8, 0x90, 0xA3, 0x84, 0x06, 0x00, 0xA4, 0x6A, 0xCA, 0x90, 0xA5, 0x35, 0xC3, 0x80, +0xA6, 0x53, 0xE7, 0x10, 0xA7, 0x15, 0xA5, 0x80, 0xA8, 0x33, 0xC9, 0x10, 0xA8, 0xFE, 0xC2, 0x00, +0xCB, 0x89, 0x0C, 0x90, 0xD2, 0x23, 0xF4, 0x70, 0xD2, 0x61, 0x18, 0x00, 0xD5, 0x55, 0xE3, 0x10, +0xD6, 0x20, 0xDC, 0x00, 0x04, 0x61, 0x19, 0x90, 0x05, 0x50, 0xFC, 0x80, 0x06, 0x40, 0xFB, 0x90, +0x07, 0x30, 0xDE, 0x80, 0x08, 0x20, 0xDD, 0x90, 0x09, 0x10, 0xC0, 0x80, 0x0A, 0x00, 0xBF, 0x90, +0x0A, 0xF0, 0xA2, 0x80, 0x0B, 0xE0, 0xA1, 0x90, 0x0C, 0xD9, 0xBF, 0x00, 0x0D, 0xC0, 0x83, 0x90, +0x0E, 0xB9, 0xA1, 0x00, 0x0F, 0xA9, 0xA0, 0x10, 0x10, 0x99, 0x83, 0x00, 0x11, 0x89, 0x82, 0x10, +0x12, 0x79, 0x65, 0x00, 0x13, 0x69, 0x64, 0x10, 0x14, 0x59, 0x47, 0x00, 0x15, 0x49, 0x46, 0x10, +0x16, 0x39, 0x29, 0x00, 0x17, 0x29, 0x28, 0x10, 0x18, 0x22, 0x45, 0x80, 0x19, 0x09, 0x0A, 0x10, +0x1A, 0x02, 0x27, 0x80, 0x1A, 0xF2, 0x26, 0x90, 0x1B, 0xE2, 0x09, 0x80, 0x1C, 0xD2, 0x08, 0x90, +0x1D, 0xC1, 0xEB, 0x80, 0x1E, 0xB1, 0xEA, 0x90, 0x1F, 0xA1, 0xCD, 0x80, 0x20, 0x76, 0x1D, 0x10, +0x21, 0x81, 0xAF, 0x80, 0x22, 0x55, 0xFF, 0x10, 0x23, 0x6A, 0xCC, 0x00, 0x24, 0x35, 0xE1, 0x10, +0x25, 0x4A, 0xAE, 0x00, 0x26, 0x15, 0xC3, 0x10, 0x27, 0x2A, 0x90, 0x00, 0x27, 0xFE, 0xDF, 0x90, +0x29, 0x0A, 0x72, 0x00, 0x29, 0xDE, 0xC1, 0x90, 0x2A, 0xEA, 0x54, 0x00, 0x2B, 0xBE, 0xA3, 0x90, +0x2C, 0xD3, 0x70, 0x80, 0x2D, 0x9E, 0x85, 0x90, 0x2E, 0xB3, 0x52, 0x80, 0x2F, 0x7E, 0x67, 0x90, +0x30, 0x93, 0x34, 0x80, 0x31, 0x67, 0x84, 0x10, 0x32, 0x73, 0x16, 0x80, 0x33, 0x47, 0x66, 0x10, +0x34, 0x52, 0xF8, 0x80, 0x35, 0x27, 0x48, 0x10, 0x36, 0x32, 0xDA, 0x80, 0x37, 0x07, 0x2A, 0x10, +0x38, 0x1B, 0xF7, 0x00, 0x38, 0xE7, 0x0C, 0x10, 0x39, 0xFB, 0xD9, 0x00, 0x3A, 0xC6, 0xEE, 0x10, +0x3B, 0xDB, 0xBB, 0x00, 0x3C, 0xB0, 0x0A, 0x90, 0x3D, 0xBB, 0x9D, 0x00, 0x3E, 0x8F, 0xEC, 0x90, +0x3F, 0x9B, 0x7F, 0x00, 0x40, 0x6F, 0xCE, 0x90, 0x41, 0x84, 0x9B, 0x80, 0x42, 0x4F, 0xB0, 0x90, +0x43, 0x64, 0x7D, 0x80, 0x44, 0x2F, 0x92, 0x90, 0x45, 0x44, 0x5F, 0x80, 0x45, 0xF3, 0xC5, 0x10, +0x47, 0x2D, 0x7C, 0x00, 0x47, 0xD3, 0xA7, 0x10, 0x49, 0x0D, 0x5E, 0x00, 0x49, 0xB3, 0x89, 0x10, +0x4A, 0xED, 0x40, 0x00, 0x4B, 0x9C, 0xA5, 0x90, 0x4C, 0xD6, 0x5C, 0x80, 0x4D, 0x7C, 0x87, 0x90, +0x4E, 0xB6, 0x3E, 0x80, 0x4F, 0x5C, 0x69, 0x90, 0x50, 0x96, 0x20, 0x80, 0x51, 0x3C, 0x4B, 0x90, +0x52, 0x76, 0x02, 0x80, 0x53, 0x1C, 0x2D, 0x90, 0x54, 0x55, 0xE4, 0x80, 0x54, 0xFC, 0x0F, 0x90, +0x56, 0x35, 0xC6, 0x80, 0x56, 0xE5, 0x2C, 0x10, 0x58, 0x1E, 0xE3, 0x00, 0x58, 0xC5, 0x0E, 0x10, +0x59, 0xFE, 0xC5, 0x00, 0x5A, 0xA4, 0xF0, 0x10, 0x5B, 0xDE, 0xA7, 0x00, 0x5C, 0x84, 0xD2, 0x10, +0x5D, 0xBE, 0x89, 0x00, 0x5E, 0x64, 0xB4, 0x10, 0x5F, 0x9E, 0x6B, 0x00, 0x60, 0x4D, 0xD0, 0x90, +0x61, 0x87, 0x87, 0x80, 0x62, 0x2D, 0xB2, 0x90, 0x63, 0x67, 0x69, 0x80, 0x64, 0x0D, 0x94, 0x90, +0x65, 0x47, 0x4B, 0x80, 0x65, 0xED, 0x76, 0x90, 0x67, 0x27, 0x2D, 0x80, 0x67, 0xCD, 0x58, 0x90, +0x69, 0x07, 0x0F, 0x80, 0x69, 0xAD, 0x3A, 0x90, 0x6A, 0xE6, 0xF1, 0x80, 0x6B, 0x96, 0x57, 0x10, +0x6C, 0xD0, 0x0E, 0x00, 0x6D, 0x76, 0x39, 0x10, 0x6E, 0xAF, 0xF0, 0x00, 0x6F, 0x56, 0x1B, 0x10, +0x70, 0x8F, 0xD2, 0x00, 0x71, 0x35, 0xFD, 0x10, 0x72, 0x6F, 0xB4, 0x00, 0x73, 0x15, 0xDF, 0x10, +0x74, 0x4F, 0x96, 0x00, 0x74, 0xFE, 0xFB, 0x90, 0x76, 0x38, 0xB2, 0x80, 0x76, 0xDE, 0xDD, 0x90, +0x78, 0x18, 0x94, 0x80, 0x78, 0xBE, 0xBF, 0x90, 0x79, 0xF8, 0x76, 0x80, 0x7A, 0x9E, 0xA1, 0x90, +0x7B, 0xD8, 0x58, 0x80, 0x7C, 0x7E, 0x83, 0x90, 0x7D, 0xB8, 0x3A, 0x80, 0x7E, 0x5E, 0x65, 0x90, +0x7F, 0x98, 0x1C, 0x80, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0xFF, 0xFF, 0x95, 0xA0, 0x00, 0x00, +0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x08, 0xFF, 0xFF, 0xAB, 0xA0, +0x01, 0x0C, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x4D, 0x44, 0x54, 0x00, +0x4D, 0x53, 0x54, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x4D, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, +0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, +0x00, 0x14, 0xFF, 0xFF, 0xFF, 0xFF, 0x88, 0xDE, 0xCE, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x9E, 0xB8, +0xAF, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xBB, 0x07, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xA0, 0x98, +0x91, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xA0, 0xD2, 0x85, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xA2, 0x8A, +0xE8, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xA3, 0x84, 0x06, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xA4, 0x6A, +0xCA, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0x35, 0xC3, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xA6, 0x53, +0xE7, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xA7, 0x15, 0xA5, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x33, +0xC9, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0xFE, 0xC2, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0x89, +0x0C, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0x23, 0xF4, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0x61, +0x18, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0x55, 0xE3, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xD6, 0x20, +0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, 0x19, 0x90, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, +0xFC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xFB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, +0xDE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0xDD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, +0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0xBF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xF0, +0xA2, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xA1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, +0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, +0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xA0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, +0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x82, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, 0x79, +0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x14, 0x59, +0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x49, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, +0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x29, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x18, 0x22, +0x45, 0x80, 0x00, 0x00, 0x00, 0x00, 0x19, 0x09, 0x0A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x02, +0x27, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF2, 0x26, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xE2, +0x09, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xD2, 0x08, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xC1, +0xEB, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xB1, 0xEA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xA1, +0xCD, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x76, 0x1D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, +0xAF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x22, 0x55, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x23, 0x6A, +0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xE1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x25, 0x4A, +0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x15, 0xC3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2A, +0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xFE, 0xDF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0A, +0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0xDE, 0xC1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xEA, +0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xBE, 0xA3, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xD3, +0x70, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x9E, 0x85, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2E, 0xB3, +0x52, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x7E, 0x67, 0x90, 0x00, 0x00, 0x00, 0x00, 0x30, 0x93, +0x34, 0x80, 0x00, 0x00, 0x00, 0x00, 0x31, 0x67, 0x84, 0x10, 0x00, 0x00, 0x00, 0x00, 0x32, 0x73, +0x16, 0x80, 0x00, 0x00, 0x00, 0x00, 0x33, 0x47, 0x66, 0x10, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, +0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, +0xDA, 0x80, 0x00, 0x00, 0x00, 0x00, 0x37, 0x07, 0x2A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, +0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xE7, 0x0C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, +0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xC6, 0xEE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, +0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xB0, 0x0A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBB, +0x9D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x8F, 0xEC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9B, +0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6F, 0xCE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, +0x9B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4F, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, +0x7D, 0x80, 0x00, 0x00, 0x00, 0x00, 0x44, 0x2F, 0x92, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, +0x5F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x45, 0xF3, 0xC5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0x2D, +0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xD3, 0xA7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0D, +0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0xB3, 0x89, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4A, 0xED, +0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x9C, 0xA5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xD6, +0x5C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x7C, 0x87, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4E, 0xB6, +0x3E, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x5C, 0x69, 0x90, 0x00, 0x00, 0x00, 0x00, 0x50, 0x96, +0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3C, 0x4B, 0x90, 0x00, 0x00, 0x00, 0x00, 0x52, 0x76, +0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x53, 0x1C, 0x2D, 0x90, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, +0xE4, 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0xFC, 0x0F, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0x35, +0xC6, 0x80, 0x00, 0x00, 0x00, 0x00, 0x56, 0xE5, 0x2C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0x1E, +0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xC5, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x59, 0xFE, +0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xA4, 0xF0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5B, 0xDE, +0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x84, 0xD2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xBE, +0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x64, 0xB4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x9E, +0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x4D, 0xD0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x61, 0x87, +0x87, 0x80, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2D, 0xB2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x63, 0x67, +0x69, 0x80, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0D, 0x94, 0x90, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, +0x4B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x65, 0xED, 0x76, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0x27, +0x2D, 0x80, 0x00, 0x00, 0x00, 0x00, 0x67, 0xCD, 0x58, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0x07, +0x0F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x69, 0xAD, 0x3A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xE6, +0xF1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x96, 0x57, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xD0, +0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x76, 0x39, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xAF, +0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x56, 0x1B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8F, +0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x35, 0xFD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6F, +0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xDF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0x4F, +0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xFE, 0xFB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, +0xB2, 0x80, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDE, 0xDD, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0x18, +0x94, 0x80, 0x00, 0x00, 0x00, 0x00, 0x78, 0xBE, 0xBF, 0x90, 0x00, 0x00, 0x00, 0x00, 0x79, 0xF8, +0x76, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x9E, 0xA1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xD8, +0x58, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xB8, +0x3A, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x5E, 0x65, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x98, +0x1C, 0x80, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, +0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0xFF, 0xFF, 0x95, 0xA0, 0x00, 0x00, 0xFF, 0xFF, +0xAB, 0xA0, 0x01, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x08, 0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x0C, +0xFF, 0xFF, 0xAB, 0xA0, 0x01, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x4D, 0x44, 0x54, 0x00, 0x4D, 0x53, +0x54, 0x00, 0x4D, 0x57, 0x54, 0x00, 0x4D, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, +0x00, 0x00, 0x00, 0x01, 0x0A, 0x4D, 0x53, 0x54, 0x37, 0x4D, 0x44, 0x54, 0x2C, 0x4D, 0x33, 0x2E, +0x32, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x31, 0x2E, 0x31, 0x2E, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Antarctica/Casey */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x41, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -41840,8 +42101,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x54, 0x60, 0x00, 0x0C, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, 0x37, 0x00, 0x2B, 0x30, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0A, 0x3C, 0x2B, 0x30, 0x36, 0x3E, 0x2D, 0x36, 0x0A, 0x00, 0xCB, 0x52, 0xC8, 0x01, 0x88, 0x13, 0x18, 0x00, -0x00, 0x00, 0x17, 0x4B, 0x61, 0x7A, 0x61, 0x6B, 0x68, 0x73, 0x74, 0x61, 0x6E, 0x20, 0x28, 0x6D, -0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0x00, 0x00, 0x12, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x4B, 0x61, 0x7A, 0x61, 0x6B, +0x68, 0x73, 0x74, 0x61, 0x6E, /* Asia/Amman */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x4A, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -43430,15 +43691,15 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x56, 0x29, 0x5C, 0x60, 0x56, 0xF5, 0xC2, 0xF0, 0x58, 0x13, 0xCA, 0x60, 0x58, 0xD5, 0xA4, 0xF0, 0x59, 0xF3, 0xAC, 0x60, 0x5A, 0xB5, 0x86, 0xF0, 0x5B, 0xD3, 0x8E, 0x60, 0x5C, 0x9D, 0x43, 0xE0, 0x5D, 0xB3, 0x62, 0x50, 0x5E, 0x7E, 0x77, 0x60, 0x5F, 0x93, 0x52, 0x60, 0x60, 0x5E, 0x59, 0x60, -0x61, 0x7B, 0x1D, 0x60, 0x62, 0x3F, 0x8C, 0xE0, 0x63, 0x5C, 0x5E, 0xF0, 0x64, 0x1E, 0x39, 0x80, -0x65, 0x3C, 0x40, 0xF0, 0x66, 0x07, 0x56, 0x00, 0x67, 0x1C, 0x22, 0xF0, 0x67, 0xE7, 0x38, 0x00, +0x61, 0x7B, 0x1D, 0x60, 0x62, 0x3F, 0x8C, 0xE0, 0x63, 0x5C, 0x5E, 0xF0, 0x64, 0x4C, 0x5E, 0x00, +0x65, 0x3C, 0x40, 0xF0, 0x66, 0x19, 0xCB, 0x00, 0x67, 0x1C, 0x22, 0xF0, 0x67, 0xF0, 0x72, 0x80, 0x68, 0xFC, 0x04, 0xF0, 0x69, 0xC7, 0x1A, 0x00, 0x6A, 0xDB, 0xE6, 0xF0, 0x6B, 0xA6, 0xFC, 0x00, 0x6C, 0xC5, 0x03, 0x70, 0x6D, 0x86, 0xDE, 0x00, 0x6E, 0xA4, 0xE5, 0x70, 0x6F, 0x66, 0xC0, 0x00, 0x70, 0x84, 0xC7, 0x70, 0x71, 0x4F, 0xDC, 0x80, 0x72, 0x64, 0xA9, 0x70, 0x73, 0x2F, 0xBE, 0x80, 0x74, 0x44, 0x8B, 0x70, 0x75, 0x0F, 0xA0, 0x80, 0x76, 0x2D, 0xA7, 0xF0, 0x76, 0xEF, 0x82, 0x80, 0x78, 0x0D, 0x89, 0xF0, 0x78, 0xCF, 0x64, 0x80, 0x79, 0xED, 0x6B, 0xF0, 0x7A, 0xAF, 0x46, 0x80, -0x7B, 0xCD, 0x4D, 0xF0, 0x7C, 0x98, 0x63, 0x00, 0x7D, 0xAD, 0x2F, 0xF0, 0x7E, 0x78, 0x45, 0x00, -0x7F, 0x8D, 0x11, 0xF0, 0x03, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x7B, 0xCD, 0x4D, 0xF0, 0x7C, 0x98, 0x63, 0x00, 0x7D, 0xA3, 0xF5, 0x70, 0x7E, 0x78, 0x45, 0x00, +0x7F, 0x7A, 0x9C, 0xF0, 0x03, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06, 0x05, 0x06, 0x07, 0x08, 0x07, 0x08, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, @@ -43456,7 +43717,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, +0x00, 0x01, 0x30, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0xBD, 0x4A, 0xB0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x59, 0xCF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0xFA, 0xA6, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x38, 0x9C, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xE5, 0xEB, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xCD, 0xAC, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xCE, @@ -43517,9 +43778,9 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x7E, 0x77, 0x60, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x93, 0x52, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5E, 0x59, 0x60, 0x00, 0x00, 0x00, 0x00, 0x61, 0x7B, 0x1D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0x8C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x63, 0x5C, 0x5E, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x64, -0x1E, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3C, 0x40, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x66, -0x07, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x1C, 0x22, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x67, -0xE7, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xFC, 0x04, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x69, +0x4C, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3C, 0x40, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x66, +0x19, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x1C, 0x22, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x67, +0xF0, 0x72, 0x80, 0x00, 0x00, 0x00, 0x00, 0x68, 0xFC, 0x04, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x69, 0xC7, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xDB, 0xE6, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xA6, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xC5, 0x03, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x86, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA4, 0xE5, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6F, @@ -43530,8 +43791,85 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0xEF, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0D, 0x89, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x78, 0xCF, 0x64, 0x80, 0x00, 0x00, 0x00, 0x00, 0x79, 0xED, 0x6B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xAF, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCD, 0x4D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7C, -0x98, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xAD, 0x2F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7E, -0x78, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x8D, 0x11, 0xF0, 0x03, 0x01, 0x02, 0x01, 0x02, +0x98, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xA3, 0xF5, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7E, +0x78, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7A, 0x9C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x80, +0x58, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x48, 0x09, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x82, +0x38, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x1E, 0xB1, 0x70, 0x00, 0x00, 0x00, 0x00, 0x83, +0x4C, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x56, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, 0x84, +0x17, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xEC, 0x1E, 0x70, 0x00, 0x00, 0x00, 0x00, 0x85, +0x23, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x85, 0x35, 0xF2, 0x70, 0x00, 0x00, 0x00, 0x00, 0x86, +0x01, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x86, 0xC2, 0xC5, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x86, +0xF0, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x87, 0x15, 0xD4, 0x70, 0x00, 0x00, 0x00, 0x00, 0x87, +0xE0, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x88, 0x99, 0x6D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x88, +0xC7, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xF5, 0xB6, 0x70, 0x00, 0x00, 0x00, 0x00, 0x89, +0xC0, 0xCB, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x66, 0xDA, 0x70, 0x00, 0x00, 0x00, 0x00, 0x8A, +0x9E, 0x47, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xD5, 0x98, 0x70, 0x00, 0x00, 0x00, 0x00, 0x8B, +0xA0, 0xAD, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x3D, 0x81, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x8C, +0x6B, 0xB4, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xBE, 0xB4, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x8D, +0x80, 0x8F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x14, 0x29, 0x70, 0x00, 0x00, 0x00, 0x00, 0x8E, +0x42, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x9E, 0x96, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x8F, +0x60, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8F, 0xE1, 0x96, 0x70, 0x00, 0x00, 0x00, 0x00, 0x90, +0x19, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x90, 0x7E, 0x78, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x91, +0x49, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB8, 0x3D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x91, +0xE6, 0x70, 0x80, 0x00, 0x00, 0x00, 0x00, 0x92, 0x5E, 0x5A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x93, +0x29, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x85, 0xAA, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x93, +0xBD, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x3E, 0x3C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x95, +0x09, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5C, 0x52, 0x70, 0x00, 0x00, 0x00, 0x00, 0x95, +0x8A, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x27, 0x59, 0x70, 0x00, 0x00, 0x00, 0x00, 0x96, +0xE9, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x32, 0xF9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x97, +0x61, 0x2C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x98, 0x07, 0x3B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x98, +0xC9, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x66, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x99, +0x37, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xE7, 0x1D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9A, +0xB2, 0x32, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD7, 0x0E, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9B, +0x05, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xC6, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9C, +0x92, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xA4, 0x7B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9C, +0xDB, 0xE8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xA6, 0xE1, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9E, +0x71, 0xF6, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x7B, 0x22, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x9E, +0xB2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x86, 0xC3, 0x70, 0x00, 0x00, 0x00, 0x00, 0xA0, +0x7F, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x6F, 0xDF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA2, +0x56, 0xA4, 0x80, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x4F, 0xC1, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA4, +0x24, 0x11, 0x80, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x2F, 0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA5, +0xFA, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7, 0x0F, 0x85, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA7, +0xDA, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xEF, 0x67, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA9, +0xBA, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xD8, 0x84, 0x70, 0x00, 0x00, 0x00, 0x00, 0xAB, +0x9A, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xB8, 0x66, 0x70, 0x00, 0x00, 0x00, 0x00, 0xAD, +0x7A, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAE, 0x98, 0x48, 0x70, 0x00, 0x00, 0x00, 0x00, 0xAF, +0x5A, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x78, 0x2A, 0x70, 0x00, 0x00, 0x00, 0x00, 0xB1, +0x43, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x58, 0x0C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xB3, +0x23, 0x21, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x37, 0xEE, 0x70, 0x00, 0x00, 0x00, 0x00, 0xB5, +0x03, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x21, 0x0A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xB6, +0xE2, 0xE5, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0xEC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xB8, +0xC2, 0xC7, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xD7, 0x94, 0x70, 0x00, 0x00, 0x00, 0x00, 0xBA, +0xAB, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xAE, 0x3B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xBC, +0x8B, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x84, 0xE3, 0x70, 0x00, 0x00, 0x00, 0x00, 0xBE, +0x6B, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x52, 0x50, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, +0x4B, 0x8A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x28, 0xF7, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xC1, +0x57, 0x2A, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xFF, 0x9F, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC3, +0x2D, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xCD, 0x0C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC5, +0x04, 0x79, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xA3, 0xB3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xC6, +0xD1, 0xE6, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x09, 0x37, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC7, +0xD4, 0x4C, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x71, 0x20, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xC8, +0xA8, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xE9, 0x19, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC9, +0xB4, 0x2E, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x47, 0xC8, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCA, +0x7F, 0x35, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xD2, 0x35, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCB, +0x94, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1E, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCC, +0x4C, 0xA2, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xB2, 0x17, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCD, +0x73, 0xF2, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xEB, 0xDC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCE, +0x23, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x91, 0xF9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCF, +0x5D, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xC2, 0x84, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCF, +0xF0, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x71, 0xDB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD1, +0x3C, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x99, 0x2B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD1, +0xC7, 0x5E, 0x80, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x51, 0xBD, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD3, +0x1C, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x66, 0x98, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD3, +0x9E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x31, 0x9F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD4, +0xFC, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x3D, 0x40, 0x70, 0x00, 0x00, 0x00, 0x00, 0xD5, +0x6B, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x1A, 0xBC, 0x70, 0x00, 0x00, 0x00, 0x00, 0xD6, +0xDC, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x0A, 0xAD, 0x70, 0x00, 0x00, 0x00, 0x00, 0xD7, +0x42, 0x1A, 0x80, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xFA, 0x9E, 0x70, 0x00, 0x00, 0x00, 0x00, 0xD8, +0xBC, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xE1, 0x54, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD9, +0x18, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xDA, 0x80, 0x70, 0x00, 0x00, 0x00, 0x00, 0xDA, +0xA5, 0x95, 0x80, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB7, 0xFC, 0x70, 0x00, 0x00, 0x00, 0x00, 0xDA, +0xE6, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xBA, 0x62, 0x70, 0x03, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06, 0x05, 0x06, 0x07, 0x08, 0x07, 0x08, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, @@ -43541,16 +43879,26 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, -0x03, 0x00, 0x00, 0x20, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, -0x20, 0x00, 0x09, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, -0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x01, -0x0D, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x4C, 0x4D, 0x54, -0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x49, 0x44, 0x54, 0x00, 0x49, 0x53, -0x54, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, -0x2C, 0x4D, 0x33, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x34, -0x2E, 0x34, 0x2F, 0x35, 0x30, 0x0A, 0x00, 0xB9, 0x64, 0xF0, 0x01, 0x47, 0x40, 0x0A, 0x00, 0x00, -0x00, 0x0A, 0x47, 0x61, 0x7A, 0x61, 0x20, 0x53, 0x74, 0x72, 0x69, 0x70, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x00, 0x00, 0x20, 0x50, 0x00, +0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x1C, +0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, +0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, 0x00, 0x1C, 0x20, 0x00, +0x11, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, +0x45, 0x45, 0x54, 0x00, 0x49, 0x44, 0x54, 0x00, 0x49, 0x53, 0x54, 0x00, 0x00, 0x01, 0x01, 0x00, +0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x34, 0x2E, +0x34, 0x2F, 0x35, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x0A, +0x00, 0xB9, 0x64, 0xF0, 0x01, 0x47, 0x40, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x47, 0x61, 0x7A, 0x61, +0x20, 0x53, 0x74, 0x72, 0x69, 0x70, /* Asia/Harbin */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -43624,14 +43972,14 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x58, 0x13, 0xCA, 0x60, 0x58, 0xD5, 0xA4, 0xF0, 0x59, 0xF3, 0xAC, 0x60, 0x5A, 0xB5, 0x86, 0xF0, 0x5B, 0xD3, 0x8E, 0x60, 0x5C, 0x9D, 0x43, 0xE0, 0x5D, 0xB3, 0x62, 0x50, 0x5E, 0x7E, 0x77, 0x60, 0x5F, 0x93, 0x52, 0x60, 0x60, 0x5E, 0x59, 0x60, 0x61, 0x7B, 0x1D, 0x60, 0x62, 0x3F, 0x8C, 0xE0, -0x63, 0x5C, 0x5E, 0xF0, 0x64, 0x1E, 0x39, 0x80, 0x65, 0x3C, 0x40, 0xF0, 0x66, 0x07, 0x56, 0x00, -0x67, 0x1C, 0x22, 0xF0, 0x67, 0xE7, 0x38, 0x00, 0x68, 0xFC, 0x04, 0xF0, 0x69, 0xC7, 0x1A, 0x00, +0x63, 0x5C, 0x5E, 0xF0, 0x64, 0x4C, 0x5E, 0x00, 0x65, 0x3C, 0x40, 0xF0, 0x66, 0x19, 0xCB, 0x00, +0x67, 0x1C, 0x22, 0xF0, 0x67, 0xF0, 0x72, 0x80, 0x68, 0xFC, 0x04, 0xF0, 0x69, 0xC7, 0x1A, 0x00, 0x6A, 0xDB, 0xE6, 0xF0, 0x6B, 0xA6, 0xFC, 0x00, 0x6C, 0xC5, 0x03, 0x70, 0x6D, 0x86, 0xDE, 0x00, 0x6E, 0xA4, 0xE5, 0x70, 0x6F, 0x66, 0xC0, 0x00, 0x70, 0x84, 0xC7, 0x70, 0x71, 0x4F, 0xDC, 0x80, 0x72, 0x64, 0xA9, 0x70, 0x73, 0x2F, 0xBE, 0x80, 0x74, 0x44, 0x8B, 0x70, 0x75, 0x0F, 0xA0, 0x80, 0x76, 0x2D, 0xA7, 0xF0, 0x76, 0xEF, 0x82, 0x80, 0x78, 0x0D, 0x89, 0xF0, 0x78, 0xCF, 0x64, 0x80, 0x79, 0xED, 0x6B, 0xF0, 0x7A, 0xAF, 0x46, 0x80, 0x7B, 0xCD, 0x4D, 0xF0, 0x7C, 0x98, 0x63, 0x00, -0x7D, 0xAD, 0x2F, 0xF0, 0x7E, 0x78, 0x45, 0x00, 0x7F, 0x8D, 0x11, 0xF0, 0x03, 0x01, 0x02, 0x01, +0x7D, 0xA3, 0xF5, 0x70, 0x7E, 0x78, 0x45, 0x00, 0x7F, 0x7A, 0x9C, 0xF0, 0x03, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06, 0x05, 0x06, 0x07, 0x08, 0x07, 0x08, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, @@ -43649,7 +43997,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x49, 0x53, 0x54, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, +0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0xBD, 0x4A, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x59, 0xCF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0xFA, 0xA6, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x38, 0x9C, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xE5, 0xEB, 0x80, 0xFF, 0xFF, 0xFF, @@ -43711,9 +44059,9 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x5D, 0xB3, 0x62, 0x50, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x7E, 0x77, 0x60, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x93, 0x52, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5E, 0x59, 0x60, 0x00, 0x00, 0x00, 0x00, 0x61, 0x7B, 0x1D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3F, 0x8C, 0xE0, 0x00, 0x00, 0x00, -0x00, 0x63, 0x5C, 0x5E, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1E, 0x39, 0x80, 0x00, 0x00, 0x00, -0x00, 0x65, 0x3C, 0x40, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x66, 0x07, 0x56, 0x00, 0x00, 0x00, 0x00, -0x00, 0x67, 0x1C, 0x22, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x67, 0xE7, 0x38, 0x00, 0x00, 0x00, 0x00, +0x00, 0x63, 0x5C, 0x5E, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x64, 0x4C, 0x5E, 0x00, 0x00, 0x00, 0x00, +0x00, 0x65, 0x3C, 0x40, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x66, 0x19, 0xCB, 0x00, 0x00, 0x00, 0x00, +0x00, 0x67, 0x1C, 0x22, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x67, 0xF0, 0x72, 0x80, 0x00, 0x00, 0x00, 0x00, 0x68, 0xFC, 0x04, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x69, 0xC7, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xDB, 0xE6, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xA6, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xC5, 0x03, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x86, 0xDE, 0x00, 0x00, 0x00, 0x00, @@ -43725,8 +44073,85 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x78, 0x0D, 0x89, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x78, 0xCF, 0x64, 0x80, 0x00, 0x00, 0x00, 0x00, 0x79, 0xED, 0x6B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xAF, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCD, 0x4D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x98, 0x63, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7D, 0xAD, 0x2F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x78, 0x45, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7F, 0x8D, 0x11, 0xF0, 0x03, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, +0x00, 0x7D, 0xA3, 0xF5, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x78, 0x45, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7F, 0x7A, 0x9C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x58, 0x27, 0x00, 0x00, 0x00, 0x00, +0x00, 0x81, 0x48, 0x09, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x82, 0x38, 0x09, 0x00, 0x00, 0x00, 0x00, +0x00, 0x83, 0x1E, 0xB1, 0x70, 0x00, 0x00, 0x00, 0x00, 0x83, 0x4C, 0xE4, 0x00, 0x00, 0x00, 0x00, +0x00, 0x83, 0x56, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, 0x84, 0x17, 0xEB, 0x00, 0x00, 0x00, 0x00, +0x00, 0x84, 0xEC, 0x1E, 0x70, 0x00, 0x00, 0x00, 0x00, 0x85, 0x23, 0x8B, 0x80, 0x00, 0x00, 0x00, +0x00, 0x85, 0x35, 0xF2, 0x70, 0x00, 0x00, 0x00, 0x00, 0x86, 0x01, 0x07, 0x80, 0x00, 0x00, 0x00, +0x00, 0x86, 0xC2, 0xC5, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x86, 0xF0, 0xF8, 0x80, 0x00, 0x00, 0x00, +0x00, 0x87, 0x15, 0xD4, 0x70, 0x00, 0x00, 0x00, 0x00, 0x87, 0xE0, 0xE9, 0x80, 0x00, 0x00, 0x00, +0x00, 0x88, 0x99, 0x6D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x88, 0xC7, 0xA0, 0x00, 0x00, 0x00, 0x00, +0x00, 0x88, 0xF5, 0xB6, 0x70, 0x00, 0x00, 0x00, 0x00, 0x89, 0xC0, 0xCB, 0x80, 0x00, 0x00, 0x00, +0x00, 0x8A, 0x66, 0xDA, 0x70, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x9E, 0x47, 0x80, 0x00, 0x00, 0x00, +0x00, 0x8A, 0xD5, 0x98, 0x70, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xA0, 0xAD, 0x80, 0x00, 0x00, 0x00, +0x00, 0x8C, 0x3D, 0x81, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x6B, 0xB4, 0x80, 0x00, 0x00, 0x00, +0x00, 0x8C, 0xBE, 0xB4, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x80, 0x8F, 0x80, 0x00, 0x00, 0x00, +0x00, 0x8E, 0x14, 0x29, 0x70, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x42, 0x5C, 0x00, 0x00, 0x00, 0x00, +0x00, 0x8E, 0x9E, 0x96, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x60, 0x71, 0x80, 0x00, 0x00, 0x00, +0x00, 0x8F, 0xE1, 0x96, 0x70, 0x00, 0x00, 0x00, 0x00, 0x90, 0x19, 0x03, 0x80, 0x00, 0x00, 0x00, +0x00, 0x90, 0x7E, 0x78, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x91, 0x49, 0x8E, 0x00, 0x00, 0x00, 0x00, +0x00, 0x91, 0xB8, 0x3D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x91, 0xE6, 0x70, 0x80, 0x00, 0x00, 0x00, +0x00, 0x92, 0x5E, 0x5A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x93, 0x29, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x93, 0x85, 0xAA, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x93, 0xBD, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x94, 0x3E, 0x3C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x95, 0x09, 0x52, 0x00, 0x00, 0x00, 0x00, +0x00, 0x95, 0x5C, 0x52, 0x70, 0x00, 0x00, 0x00, 0x00, 0x95, 0x8A, 0x85, 0x00, 0x00, 0x00, 0x00, +0x00, 0x96, 0x27, 0x59, 0x70, 0x00, 0x00, 0x00, 0x00, 0x96, 0xE9, 0x34, 0x00, 0x00, 0x00, 0x00, +0x00, 0x97, 0x32, 0xF9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x97, 0x61, 0x2C, 0x80, 0x00, 0x00, 0x00, +0x00, 0x98, 0x07, 0x3B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x98, 0xC9, 0x16, 0x00, 0x00, 0x00, 0x00, +0x00, 0x99, 0x00, 0x66, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x99, 0x37, 0xD4, 0x00, 0x00, 0x00, 0x00, +0x00, 0x99, 0xE7, 0x1D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xB2, 0x32, 0x80, 0x00, 0x00, 0x00, +0x00, 0x9A, 0xD7, 0x0E, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x05, 0x41, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9B, 0xC6, 0xFF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x92, 0x14, 0x80, 0x00, 0x00, 0x00, +0x00, 0x9C, 0xA4, 0x7B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xDB, 0xE8, 0x80, 0x00, 0x00, 0x00, +0x00, 0x9D, 0xA6, 0xE1, 0x70, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x71, 0xF6, 0x80, 0x00, 0x00, 0x00, +0x00, 0x9E, 0x7B, 0x22, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xB2, 0x90, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9F, 0x86, 0xC3, 0x70, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x7F, 0xFD, 0x00, 0x00, 0x00, 0x00, +0x00, 0xA1, 0x6F, 0xDF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x56, 0xA4, 0x80, 0x00, 0x00, 0x00, +0x00, 0xA3, 0x4F, 0xC1, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x24, 0x11, 0x80, 0x00, 0x00, 0x00, +0x00, 0xA5, 0x2F, 0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA5, 0xFA, 0xB9, 0x00, 0x00, 0x00, 0x00, +0x00, 0xA7, 0x0F, 0x85, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xDA, 0x9B, 0x00, 0x00, 0x00, 0x00, +0x00, 0xA8, 0xEF, 0x67, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xA9, 0xBA, 0x7D, 0x00, 0x00, 0x00, 0x00, +0x00, 0xAA, 0xD8, 0x84, 0x70, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x9A, 0x5F, 0x00, 0x00, 0x00, 0x00, +0x00, 0xAC, 0xB8, 0x66, 0x70, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x7A, 0x41, 0x00, 0x00, 0x00, 0x00, +0x00, 0xAE, 0x98, 0x48, 0x70, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x5A, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0xB0, 0x78, 0x2A, 0x70, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x43, 0x3F, 0x80, 0x00, 0x00, 0x00, +0x00, 0xB2, 0x58, 0x0C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x23, 0x21, 0x80, 0x00, 0x00, 0x00, +0x00, 0xB4, 0x37, 0xEE, 0x70, 0x00, 0x00, 0x00, 0x00, 0xB5, 0x03, 0x03, 0x80, 0x00, 0x00, 0x00, +0x00, 0xB6, 0x21, 0x0A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xB6, 0xE2, 0xE5, 0x80, 0x00, 0x00, 0x00, +0x00, 0xB8, 0x00, 0xEC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xB8, 0xC2, 0xC7, 0x80, 0x00, 0x00, 0x00, +0x00, 0xB9, 0xD7, 0x94, 0x70, 0x00, 0x00, 0x00, 0x00, 0xBA, 0xAB, 0xE4, 0x00, 0x00, 0x00, 0x00, +0x00, 0xBB, 0xAE, 0x3B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x8B, 0xC6, 0x00, 0x00, 0x00, 0x00, +0x00, 0xBD, 0x84, 0xE3, 0x70, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x6B, 0xA8, 0x00, 0x00, 0x00, 0x00, +0x00, 0xBF, 0x52, 0x50, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x4B, 0x8A, 0x00, 0x00, 0x00, 0x00, +0x00, 0xC1, 0x28, 0xF7, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x57, 0x2A, 0x80, 0x00, 0x00, 0x00, +0x00, 0xC2, 0xFF, 0x9F, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x2D, 0xD2, 0x00, 0x00, 0x00, 0x00, +0x00, 0xC4, 0xCD, 0x0C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x04, 0x79, 0x80, 0x00, 0x00, 0x00, +0x00, 0xC6, 0xA3, 0xB3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xD1, 0xE6, 0x80, 0x00, 0x00, 0x00, +0x00, 0xC7, 0x09, 0x37, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC7, 0xD4, 0x4C, 0x80, 0x00, 0x00, 0x00, +0x00, 0xC8, 0x71, 0x20, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xA8, 0x8E, 0x00, 0x00, 0x00, 0x00, +0x00, 0xC8, 0xE9, 0x19, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC9, 0xB4, 0x2E, 0x80, 0x00, 0x00, 0x00, +0x00, 0xCA, 0x47, 0xC8, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x7F, 0x35, 0x80, 0x00, 0x00, 0x00, +0x00, 0xCA, 0xD2, 0x35, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x94, 0x10, 0x80, 0x00, 0x00, 0x00, +0x00, 0xCC, 0x1E, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x4C, 0xA2, 0x80, 0x00, 0x00, 0x00, +0x00, 0xCC, 0xB2, 0x17, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCD, 0x73, 0xF2, 0x80, 0x00, 0x00, 0x00, +0x00, 0xCD, 0xEB, 0xDC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x23, 0x4A, 0x00, 0x00, 0x00, 0x00, +0x00, 0xCE, 0x91, 0xF9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xCF, 0x5D, 0x0F, 0x00, 0x00, 0x00, 0x00, +0x00, 0xCF, 0xC2, 0x84, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xF0, 0xB7, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD0, 0x71, 0xDB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x3C, 0xF1, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD1, 0x99, 0x2B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xC7, 0x5E, 0x80, 0x00, 0x00, 0x00, +0x00, 0xD2, 0x51, 0xBD, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x1C, 0xD3, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD3, 0x66, 0x98, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x9E, 0x06, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD4, 0x31, 0x9F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xFC, 0xB5, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD5, 0x3D, 0x40, 0x70, 0x00, 0x00, 0x00, 0x00, 0xD5, 0x6B, 0x73, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD6, 0x1A, 0xBC, 0x70, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xDC, 0x97, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD7, 0x0A, 0xAD, 0x70, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x42, 0x1A, 0x80, 0x00, 0x00, 0x00, +0x00, 0xD7, 0xFA, 0x9E, 0x70, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xBC, 0x79, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD8, 0xE1, 0x54, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x18, 0xC2, 0x00, 0x00, 0x00, 0x00, +0x00, 0xD9, 0xDA, 0x80, 0x70, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xA5, 0x95, 0x80, 0x00, 0x00, 0x00, +0x00, 0xDA, 0xB7, 0xFC, 0x70, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xE6, 0x2F, 0x00, 0x00, 0x00, 0x00, +0x00, 0xDB, 0xBA, 0x62, 0x70, 0x03, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x06, 0x05, 0x06, 0x05, 0x06, 0x07, 0x08, 0x07, 0x08, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, @@ -43735,17 +44160,27 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, -0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x00, 0x00, 0x20, -0xE7, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, -0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x2A, 0x30, 0x01, -0x0D, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, 0x00, 0x1C, -0x20, 0x00, 0x11, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, -0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x49, 0x44, 0x54, 0x00, 0x49, 0x53, 0x54, 0x00, 0x00, 0x01, -0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, -0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, -0x30, 0x0A, 0x00, 0xB9, 0x71, 0xF5, 0x01, 0x48, 0x35, 0x7C, 0x00, 0x00, 0x00, 0x09, 0x57, 0x65, -0x73, 0x74, 0x20, 0x42, 0x61, 0x6E, 0x6B, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, +0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x2A, +0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, +0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, 0x00, 0x1C, 0x20, 0x00, +0x11, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x0D, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x11, 0x00, 0x00, 0x1C, +0x20, 0x00, 0x09, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, +0x49, 0x44, 0x54, 0x00, 0x49, 0x53, 0x54, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, +0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x45, 0x45, 0x54, +0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, +0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x34, 0x2E, 0x34, 0x2F, 0x35, 0x30, 0x0A, 0x00, 0xB9, 0x71, 0xF5, +0x01, 0x48, 0x35, 0x7C, 0x00, 0x00, 0x00, 0x09, 0x57, 0x65, 0x73, 0x74, 0x20, 0x42, 0x61, 0x6E, +0x6B, /* Asia/Ho_Chi_Minh */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x56, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -45169,9 +45604,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, -0x34, 0x0A, 0x00, 0xBE, 0xFD, 0x3A, 0x01, 0x45, 0x92, 0x5A, 0x00, 0x00, 0x00, 0x13, 0x43, 0x79, -0x70, 0x72, 0x75, 0x73, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, -0x29, +0x34, 0x0A, 0x00, 0xBE, 0xFD, 0x3A, 0x01, 0x45, 0x92, 0x5A, 0x00, 0x00, 0x00, 0x0E, 0x6D, 0x6F, +0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x43, 0x79, 0x70, 0x72, 0x75, 0x73, /* Asia/Novokuznetsk */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -46050,9 +46484,9 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x9A, 0xB0, 0x00, 0x0C, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x31, 0x30, 0x00, 0x2B, 0x31, 0x32, 0x00, 0x2B, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0A, 0x3C, 0x2B, 0x31, 0x31, 0x3E, 0x2D, 0x31, 0x31, 0x0A, 0x00, 0xF0, 0x46, 0x6A, 0x01, 0xFD, -0x36, 0x12, 0x00, 0x00, 0x00, 0x22, 0x4D, 0x53, 0x4B, 0x2B, 0x30, 0x38, 0x20, 0x2D, 0x20, 0x53, -0x61, 0x6B, 0x68, 0x61, 0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x4E, 0x6F, 0x72, 0x74, 0x68, 0x20, -0x4B, 0x75, 0x72, 0x69, 0x6C, 0x20, 0x49, 0x73, +0x36, 0x12, 0x00, 0x00, 0x00, 0x1E, 0x4D, 0x53, 0x4B, 0x2B, 0x30, 0x38, 0x20, 0x2D, 0x20, 0x53, +0x61, 0x6B, 0x68, 0x61, 0x20, 0x28, 0x45, 0x29, 0x3B, 0x20, 0x4E, 0x20, 0x4B, 0x75, 0x72, 0x69, +0x6C, 0x20, 0x49, 0x73, /* Asia/Taipei */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x54, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -46654,8 +47088,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0x62, 0x70, 0x00, 0x04, 0x00, 0x00, 0x7E, 0x90, 0x01, 0x08, 0x00, 0x00, 0x70, 0x80, 0x00, 0x0C, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x37, 0x00, 0x2B, 0x30, 0x39, 0x00, 0x2B, 0x30, 0x38, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x38, 0x3E, 0x2D, 0x38, 0x0A, 0x00, 0xD2, 0x71, -0xB2, 0x01, 0xB5, 0xBF, 0xCD, 0x00, 0x00, 0x00, 0x15, 0x4D, 0x6F, 0x6E, 0x67, 0x6F, 0x6C, 0x69, -0x61, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0xB2, 0x01, 0xB5, 0xBF, 0xCD, 0x00, 0x00, 0x00, 0x10, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, +0x20, 0x4D, 0x6F, 0x6E, 0x67, 0x6F, 0x6C, 0x69, 0x61, /* Asia/Ulan_Bator */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -53257,7 +53691,7 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { /* Egypt */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x80, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x80, 0x00, 0x00, 0x00, 0xC8, 0x93, 0xB4, 0xE0, 0xC8, 0xFA, 0x7B, 0xD0, 0xC9, 0xFC, 0xEF, 0xE0, 0xCA, 0xC7, 0xE8, 0xD0, 0xCB, 0xCB, 0xAE, 0x60, 0xCC, 0xDF, 0x29, 0xD0, 0xCD, 0xAC, 0xE1, 0xE0, 0xCE, 0xC6, 0xF4, 0xD0, 0xCF, 0x8F, 0x66, 0xE0, 0xD0, 0xA9, 0x79, 0xD0, 0xD1, 0x84, 0x60, 0xE0, 0xD2, 0x8A, 0xAD, 0x50, @@ -53289,95 +53723,123 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x46, 0x31, 0x20, 0xE0, 0x46, 0xE0, 0x6A, 0x50, 0x48, 0x11, 0x02, 0xE0, 0x48, 0xB7, 0x11, 0xD0, 0x49, 0xF0, 0xE4, 0xE0, 0x4A, 0x8D, 0xB9, 0x50, 0x4B, 0xDA, 0x01, 0x60, 0x4C, 0x61, 0xBD, 0xD0, 0x4C, 0x89, 0x58, 0xE0, 0x4C, 0xA4, 0xFA, 0x50, 0x53, 0x75, 0x38, 0xE0, 0x53, 0xAC, 0x89, 0xD0, -0x53, 0xDA, 0xBC, 0x60, 0x54, 0x24, 0x82, 0x50, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x53, 0xDA, 0xBC, 0x60, 0x54, 0x24, 0x82, 0x50, 0x64, 0x4A, 0xF0, 0x60, 0x65, 0x3A, 0xD3, 0x50, +0x66, 0x2A, 0xD2, 0x60, 0x67, 0x23, 0xEF, 0xD0, 0x68, 0x0A, 0xB4, 0x60, 0x69, 0x03, 0xD1, 0xD0, +0x69, 0xEA, 0x96, 0x60, 0x6A, 0xE3, 0xB3, 0xD0, 0x6B, 0xD3, 0xB2, 0xE0, 0x6C, 0xC3, 0x95, 0xD0, +0x6D, 0xB3, 0x94, 0xE0, 0x6E, 0xA3, 0x77, 0xD0, 0x6F, 0x93, 0x76, 0xE0, 0x70, 0x83, 0x59, 0xD0, +0x71, 0x73, 0x58, 0xE0, 0x72, 0x6C, 0x76, 0x50, 0x73, 0x53, 0x3A, 0xE0, 0x74, 0x4C, 0x58, 0x50, +0x75, 0x3C, 0x57, 0x60, 0x76, 0x2C, 0x3A, 0x50, 0x77, 0x1C, 0x39, 0x60, 0x78, 0x0C, 0x1C, 0x50, +0x78, 0xFC, 0x1B, 0x60, 0x79, 0xEB, 0xFE, 0x50, 0x7A, 0xDB, 0xFD, 0x60, 0x7B, 0xCB, 0xE0, 0x50, +0x7C, 0xBB, 0xDF, 0x60, 0x7D, 0xB4, 0xFC, 0xD0, 0x7E, 0x9B, 0xC1, 0x60, 0x7F, 0x94, 0xDE, 0xD0, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, +0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x1D, +0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, +0x00, 0x2A, 0x30, 0x01, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, +0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, +0x00, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, 0x7D, 0xBD, 0x4D, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x93, +0xB4, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0xFA, 0x7B, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0xFC, +0xEF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA, 0xC7, 0xE8, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0xCB, +0xAE, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xCC, 0xDF, 0x29, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCD, 0xAC, +0xE1, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCE, 0xC6, 0xF4, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0x8F, +0x66, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xA9, 0x79, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD1, 0x84, +0x60, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0x8A, 0xAD, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x36, +0x63, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF4, 0x2D, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x0B, +0xB9, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0x60, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xEC, +0xFA, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB5, 0x6D, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xCF, +0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x97, 0xF2, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xB0, +0xB3, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x79, 0x25, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x91, +0xE6, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x5A, 0x59, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x73, +0x1A, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x3B, 0x8C, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x55, +0x9F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0x1E, 0x11, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x36, +0xD2, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x45, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x18, +0x06, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xE1, 0xCA, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xF9, +0x39, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xC2, 0xFD, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xDB, +0xBE, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xA5, 0x82, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBC, +0xF2, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x86, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, +0x25, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x67, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x7F, +0x59, 0x70, 0x00, 0x00, 0x00, 0x00, 0x03, 0x49, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, +0xDE, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x2B, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, +0x11, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0C, 0xD5, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x24, +0x45, 0x70, 0x00, 0x00, 0x00, 0x00, 0x08, 0xEE, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, +0x78, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xCF, 0x3C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE7, +0xFD, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xB1, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC9, +0x31, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x92, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xAA, +0x64, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x74, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, 0x11, 0x8B, +0x98, 0x70, 0x00, 0x00, 0x00, 0x00, 0x12, 0x55, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x6E, +0x1D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x14, 0x37, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x4F, +0x50, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x19, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, +0x93, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x17, 0xFA, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x70, +0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x19, 0xDB, 0x7B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, +0x3C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xBE, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xD5, +0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x9F, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xB6, +0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x67, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x97, +0xD7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x21, 0x61, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x7A, +0x5C, 0x70, 0x00, 0x00, 0x00, 0x00, 0x23, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x62, +0x27, 0x70, 0x00, 0x00, 0x00, 0x00, 0x25, 0x25, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x26, 0x3C, +0xC3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x27, 0x06, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x1D, +0xF6, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x28, 0xE7, 0xBA, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, +0x7B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xCA, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xE1, +0xAF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xAB, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0xC2, +0xE2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x8C, 0xA6, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xA0, +0x13, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x6B, 0x0C, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x31, 0x7F, +0xF5, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4A, 0xEE, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x33, 0x5F, +0xD7, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x2A, 0xD0, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x35, 0x3F, +0xB9, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x36, 0x0A, 0xB2, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x37, 0x28, +0xD6, 0x60, 0x00, 0x00, 0x00, 0x00, 0x37, 0xF3, 0xCF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x39, 0x08, +0xB8, 0x60, 0x00, 0x00, 0x00, 0x00, 0x39, 0xD3, 0xB1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xE8, +0x9A, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xB3, 0x93, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xC8, +0x7C, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x93, 0x75, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xA8, +0x5E, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x73, 0x57, 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x91, +0x7A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x41, 0x5C, 0x73, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x71, +0x5C, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x43, 0x3C, 0x55, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x51, +0x3E, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x45, 0x12, 0xFD, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x31, +0x20, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x46, 0xE0, 0x6A, 0x50, 0x00, 0x00, 0x00, 0x00, 0x48, 0x11, +0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x48, 0xB7, 0x11, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x49, 0xF0, +0xE4, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x8D, 0xB9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xDA, +0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x61, 0xBD, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x89, +0x58, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xA4, 0xFA, 0x50, 0x00, 0x00, 0x00, 0x00, 0x53, 0x75, +0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xAC, 0x89, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xDA, +0xBC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x54, 0x24, 0x82, 0x50, 0x00, 0x00, 0x00, 0x00, 0x64, 0x4A, +0xF0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3A, 0xD3, 0x50, 0x00, 0x00, 0x00, 0x00, 0x66, 0x2A, +0xD2, 0x60, 0x00, 0x00, 0x00, 0x00, 0x67, 0x23, 0xEF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x0A, +0xB4, 0x60, 0x00, 0x00, 0x00, 0x00, 0x69, 0x03, 0xD1, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x69, 0xEA, +0x96, 0x60, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xE3, 0xB3, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x6B, 0xD3, +0xB2, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xC3, 0x95, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x6D, 0xB3, +0x94, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xA3, 0x77, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x93, +0x76, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x83, 0x59, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x71, 0x73, +0x58, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6C, 0x76, 0x50, 0x00, 0x00, 0x00, 0x00, 0x73, 0x53, +0x3A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x4C, 0x58, 0x50, 0x00, 0x00, 0x00, 0x00, 0x75, 0x3C, +0x57, 0x60, 0x00, 0x00, 0x00, 0x00, 0x76, 0x2C, 0x3A, 0x50, 0x00, 0x00, 0x00, 0x00, 0x77, 0x1C, +0x39, 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x1C, 0x50, 0x00, 0x00, 0x00, 0x00, 0x78, 0xFC, +0x1B, 0x60, 0x00, 0x00, 0x00, 0x00, 0x79, 0xEB, 0xFE, 0x50, 0x00, 0x00, 0x00, 0x00, 0x7A, 0xDB, +0xFD, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCB, 0xE0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xBB, +0xDF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xB4, 0xFC, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x9B, +0xC1, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x94, 0xDE, 0xD0, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, +0x02, 0x03, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, +0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x1D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, 0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x45, 0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, -0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0xFF, 0xFF, 0xFF, 0xFF, -0x7D, 0xBD, 0x4D, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x93, 0xB4, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xC8, 0xFA, 0x7B, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0xFC, 0xEF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xCA, 0xC7, 0xE8, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCB, 0xCB, 0xAE, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, -0xCC, 0xDF, 0x29, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCD, 0xAC, 0xE1, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xCE, 0xC6, 0xF4, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0x8F, 0x66, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xD0, 0xA9, 0x79, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD1, 0x84, 0x60, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, -0xD2, 0x8A, 0xAD, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x36, 0x63, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, -0xE8, 0xF4, 0x2D, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x0B, 0xB9, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, -0xEA, 0xD5, 0x60, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xEC, 0xFA, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xEC, 0xB5, 0x6D, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xCF, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xEE, 0x97, 0xF2, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xB0, 0xB3, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xF0, 0x79, 0x25, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x91, 0xE6, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xF2, 0x5A, 0x59, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x73, 0x1A, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xF4, 0x3B, 0x8C, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x55, 0x9F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xF6, 0x1E, 0x11, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x36, 0xD2, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xF7, 0xFF, 0x45, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x18, 0x06, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xF9, 0xE1, 0xCA, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xF9, 0x39, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xFB, 0xC2, 0xFD, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xDB, 0xBE, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -0xFD, 0xA5, 0x82, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBC, 0xF2, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0x86, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x25, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x01, 0x67, 0xE9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x7F, 0x59, 0x70, 0x00, 0x00, 0x00, 0x00, -0x03, 0x49, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, 0xDE, 0x70, 0x00, 0x00, 0x00, 0x00, -0x05, 0x2B, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0x11, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x07, 0x0C, 0xD5, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x24, 0x45, 0x70, 0x00, 0x00, 0x00, 0x00, -0x08, 0xEE, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x78, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x0A, 0xCF, 0x3C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE7, 0xFD, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x0C, 0xB1, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC9, 0x31, 0x70, 0x00, 0x00, 0x00, 0x00, -0x0E, 0x92, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xAA, 0x64, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x10, 0x74, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, 0x11, 0x8B, 0x98, 0x70, 0x00, 0x00, 0x00, 0x00, -0x12, 0x55, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x6E, 0x1D, 0x70, 0x00, 0x00, 0x00, 0x00, -0x14, 0x37, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x4F, 0x50, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x16, 0x19, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x93, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x17, 0xFA, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x70, 0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x19, 0xDB, 0x7B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xF4, 0x3C, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x1B, 0xBE, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xD5, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, -0x1D, 0x9F, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xB6, 0xA3, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x1F, 0x80, 0x67, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x97, 0xD7, 0x70, 0x00, 0x00, 0x00, 0x00, -0x21, 0x61, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x7A, 0x5C, 0x70, 0x00, 0x00, 0x00, 0x00, -0x23, 0x44, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x62, 0x27, 0x70, 0x00, 0x00, 0x00, 0x00, -0x25, 0x25, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x26, 0x3C, 0xC3, 0x70, 0x00, 0x00, 0x00, 0x00, -0x27, 0x06, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x1D, 0xF6, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x28, 0xE7, 0xBA, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x7B, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x2A, 0xCA, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xE1, 0xAF, 0x70, 0x00, 0x00, 0x00, 0x00, -0x2C, 0xAB, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0xC2, 0xE2, 0xF0, 0x00, 0x00, 0x00, 0x00, -0x2E, 0x8C, 0xA6, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xA0, 0x13, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x30, 0x6B, 0x0C, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x31, 0x7F, 0xF5, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x32, 0x4A, 0xEE, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x33, 0x5F, 0xD7, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x34, 0x2A, 0xD0, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x35, 0x3F, 0xB9, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x36, 0x0A, 0xB2, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x37, 0x28, 0xD6, 0x60, 0x00, 0x00, 0x00, 0x00, -0x37, 0xF3, 0xCF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x39, 0x08, 0xB8, 0x60, 0x00, 0x00, 0x00, 0x00, -0x39, 0xD3, 0xB1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xE8, 0x9A, 0x60, 0x00, 0x00, 0x00, 0x00, -0x3B, 0xB3, 0x93, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xC8, 0x7C, 0x60, 0x00, 0x00, 0x00, 0x00, -0x3D, 0x93, 0x75, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xA8, 0x5E, 0x60, 0x00, 0x00, 0x00, 0x00, -0x3F, 0x73, 0x57, 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x91, 0x7A, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x41, 0x5C, 0x73, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x71, 0x5C, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x43, 0x3C, 0x55, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x51, 0x3E, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x45, 0x12, 0xFD, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x31, 0x20, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x46, 0xE0, 0x6A, 0x50, 0x00, 0x00, 0x00, 0x00, 0x48, 0x11, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x48, 0xB7, 0x11, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x49, 0xF0, 0xE4, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x4A, 0x8D, 0xB9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xDA, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, -0x4C, 0x61, 0xBD, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x89, 0x58, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x4C, 0xA4, 0xFA, 0x50, 0x00, 0x00, 0x00, 0x00, 0x53, 0x75, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x53, 0xAC, 0x89, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x53, 0xDA, 0xBC, 0x60, 0x00, 0x00, 0x00, 0x00, -0x54, 0x24, 0x82, 0x50, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x01, 0x02, 0x01, -0x02, 0x01, 0x02, 0x00, 0x00, 0x1D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x00, -0x00, 0x1C, 0x20, 0x00, 0x09, 0x00, 0x00, 0x2A, 0x30, 0x01, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x45, -0x45, 0x53, 0x54, 0x00, 0x45, 0x45, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x45, 0x45, 0x54, -0x2D, 0x32, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x34, 0x2E, 0x35, 0x2E, +0x35, 0x2F, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x34, 0x2F, 0x32, 0x34, 0x0A, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Eire */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -55153,8 +55615,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x43, 0x45, 0x54, 0x2D, 0x31, 0x43, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x0A, 0x00, 0xD9, 0x70, 0x10, 0x01, 0x27, -0x0D, 0xDA, 0x00, 0x00, 0x00, 0x14, 0x47, 0x65, 0x72, 0x6D, 0x61, 0x6E, 0x79, 0x20, 0x28, 0x6D, -0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0x0D, 0xDA, 0x00, 0x00, 0x00, 0x0F, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x47, 0x65, +0x72, 0x6D, 0x61, 0x6E, 0x79, /* Europe/Bratislava */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x53, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -57798,8 +58260,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { /* Europe/Kirov */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0xA1, 0x00, 0x39, 0x80, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x18, 0xA1, 0x00, 0x39, 0x80, 0xB5, 0xA4, 0x0B, 0x50, 0x15, 0x27, 0x99, 0xC0, 0x16, 0x18, 0xCE, 0x30, 0x17, 0x08, 0xCD, 0x40, 0x17, 0xFA, 0x01, 0xB0, 0x18, 0xEA, 0x00, 0xC0, 0x19, 0xDB, 0x35, 0x30, 0x1A, 0xCC, 0x85, 0xC0, 0x1B, 0xBC, 0x92, 0xE0, 0x1C, 0xAC, 0x83, 0xE0, 0x1D, 0x9C, 0x74, 0xE0, 0x1E, 0x8C, 0x65, 0xE0, @@ -57819,57 +58281,60 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x02, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x06, 0x07, 0x06, 0x07, 0x04, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, -0x07, 0x06, 0x07, 0x06, 0x07, 0x04, 0x07, 0x00, 0x00, 0x2E, 0x98, 0x00, 0x00, 0x00, 0x00, 0x2A, +0x07, 0x06, 0x07, 0x06, 0x07, 0x08, 0x07, 0x00, 0x00, 0x2E, 0x98, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x00, 0x00, 0x46, 0x50, 0x01, 0x08, 0x00, 0x00, 0x38, 0x40, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x00, 0x0C, 0x00, 0x00, 0x46, 0x50, 0x01, 0x08, 0x00, 0x00, 0x38, 0x40, 0x01, -0x0C, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, -0x30, 0x35, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, -0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, -0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x08, 0x00, -0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xA1, 0x00, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB5, -0xA4, 0x0B, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x27, 0x99, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x16, -0x18, 0xCE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x17, 0x08, 0xCD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x17, -0xFA, 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x18, 0xEA, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x19, -0xDB, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xCC, 0x85, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1B, -0xBC, 0x92, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xAC, 0x83, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1D, -0x9C, 0x74, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x8C, 0x65, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, -0x7C, 0x56, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6C, 0x47, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x21, -0x5C, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x22, 0x4C, 0x29, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x23, -0x3C, 0x1A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2C, 0x0B, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x25, -0x1C, 0x0A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0B, 0xFB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x27, -0x05, 0x27, 0x70, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF5, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x29, -0xD4, 0xEC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xC4, 0xEB, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2B, -0xB4, 0xDC, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xA4, 0xCD, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2D, -0x94, 0xBE, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x84, 0xAF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2F, -0x74, 0xA0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, 0x64, 0x91, 0x70, 0x00, 0x00, 0x00, 0x00, 0x31, -0x5D, 0xBC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0x97, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x33, -0x3D, 0x9E, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x79, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x35, -0x1D, 0x80, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0x5B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x36, -0xFD, 0x62, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x38, -0xDD, 0x44, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, 0x5A, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3A, -0xBD, 0x26, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, 0x3C, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3C, -0xA6, 0x43, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBB, 0x1E, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3E, -0x86, 0x25, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9B, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, -0x66, 0x07, 0x70, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x1C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x42, -0x45, 0xE9, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0xFE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x44, -0x25, 0xCB, 0x70, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x46, -0x05, 0xAD, 0x70, 0x00, 0x00, 0x00, 0x00, 0x47, 0x23, 0xC2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x47, -0xEE, 0xC9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x03, 0xA4, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x49, -0xCE, 0xAB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4A, 0xE3, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4B, -0xAE, 0x8D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xCC, 0xA3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4D, -0x8E, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x4C, 0x1D, 0x60, 0x01, 0x03, 0x02, 0x03, 0x02, -0x03, 0x02, 0x03, 0x02, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x06, 0x07, 0x06, -0x07, 0x04, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, +0x10, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x14, 0x00, 0x00, 0x38, 0x40, 0x00, 0x14, 0x00, 0x00, 0x2A, +0x30, 0x00, 0x14, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, +0x30, 0x34, 0x00, 0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, +0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA1, +0x00, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB5, 0xA4, 0x0B, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, +0x27, 0x99, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0xCE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x17, +0x08, 0xCD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x17, 0xFA, 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x18, +0xEA, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x19, 0xDB, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x1A, +0xCC, 0x85, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xBC, 0x92, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1C, +0xAC, 0x83, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x9C, 0x74, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1E, +0x8C, 0x65, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x56, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x20, +0x6C, 0x47, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x5C, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x22, +0x4C, 0x29, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x23, 0x3C, 0x1A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x24, +0x2C, 0x0B, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1C, 0x0A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x26, +0x0B, 0xFB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x05, 0x27, 0x70, 0x00, 0x00, 0x00, 0x00, 0x27, +0xF5, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x29, 0xD4, 0xEC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2A, +0xC4, 0xEB, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xB4, 0xDC, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2C, +0xA4, 0xCD, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xBE, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2E, +0x84, 0xAF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0xA0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, +0x64, 0x91, 0x70, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0xBC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x32, +0x72, 0x97, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0x9E, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x34, +0x52, 0x79, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x80, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x36, +0x32, 0x5B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x62, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x38, +0x1B, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x44, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x39, +0xFB, 0x5A, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBD, 0x26, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3B, +0xDB, 0x3C, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x43, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3D, +0xBB, 0x1E, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x86, 0x25, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3F, +0x9B, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x07, 0x70, 0x00, 0x00, 0x00, 0x00, 0x41, +0x84, 0x1C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xE9, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, +0x63, 0xFE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0xCB, 0x70, 0x00, 0x00, 0x00, 0x00, 0x45, +0x43, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xAD, 0x70, 0x00, 0x00, 0x00, 0x00, 0x47, +0x23, 0xC2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEE, 0xC9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x49, +0x03, 0xA4, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x49, 0xCE, 0xAB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4A, +0xE3, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0x8D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4C, +0xCC, 0xA3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x54, +0x4C, 0x1D, 0x60, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x04, 0x05, 0x04, 0x05, +0x04, 0x05, 0x04, 0x05, 0x04, 0x06, 0x07, 0x06, 0x07, 0x04, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, -0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x04, 0x07, 0x00, 0x00, 0x2E, 0x98, 0x00, 0x00, -0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x00, 0x00, 0x46, 0x50, 0x01, 0x08, 0x00, 0x00, 0x38, 0x40, -0x00, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x00, 0x0C, 0x00, 0x00, 0x46, 0x50, 0x01, 0x08, 0x00, 0x00, -0x38, 0x40, 0x01, 0x0C, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, -0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, -0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x3C, 0x2B, 0x30, 0x33, 0x3E, -0x2D, 0x33, 0x0A, 0x00, 0xE2, 0xBE, 0xE0, 0x01, 0x5E, 0x6B, 0x08, 0x00, 0x00, 0x00, 0x0E, 0x4D, -0x53, 0x4B, 0x2B, 0x30, 0x30, 0x20, 0x2D, 0x20, 0x4B, 0x69, 0x72, 0x6F, 0x76, +0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, +0x08, 0x07, 0x00, 0x00, 0x2E, 0x98, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x00, 0x00, +0x46, 0x50, 0x01, 0x08, 0x00, 0x00, 0x38, 0x40, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x00, 0x0C, +0x00, 0x00, 0x46, 0x50, 0x01, 0x08, 0x00, 0x00, 0x38, 0x40, 0x01, 0x10, 0x00, 0x00, 0x2A, 0x30, +0x00, 0x14, 0x00, 0x00, 0x38, 0x40, 0x00, 0x14, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x14, 0x4C, 0x4D, +0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x4D, 0x53, +0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x4D, 0x53, 0x4B, 0x2D, 0x33, +0x0A, 0x00, 0xE2, 0xBE, 0xE0, 0x01, 0x5E, 0x6B, 0x08, 0x00, 0x00, 0x00, 0x0E, 0x4D, 0x53, 0x4B, +0x2B, 0x30, 0x30, 0x20, 0x2D, 0x20, 0x4B, 0x69, 0x72, 0x6F, 0x76, /* Europe/Kyiv */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x55, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -58005,8 +58470,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x45, 0x45, 0x54, 0x2D, 0x32, 0x45, 0x45, 0x53, 0x54, 0x2C, 0x4D, 0x33, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x33, 0x2C, 0x4D, 0x31, 0x30, 0x2E, 0x35, 0x2E, 0x30, 0x2F, 0x34, 0x0A, 0x00, 0xD6, 0x48, 0xC5, 0x01, 0x41, 0x39, 0x12, -0x00, 0x00, 0x00, 0x14, 0x55, 0x6B, 0x72, 0x61, 0x69, 0x6E, 0x65, 0x20, 0x28, 0x6D, 0x6F, 0x73, -0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0x00, 0x00, 0x00, 0x0F, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x55, 0x6B, 0x72, 0x61, +0x69, 0x6E, 0x65, /* Europe/Lisbon */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -62776,8 +63241,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { /* Europe/Volgograd */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x52, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0xA1, 0xF5, 0x46, 0xDC, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x18, 0xA1, 0xF5, 0x46, 0xDC, 0xB5, 0xA4, 0x0B, 0x50, 0x15, 0x27, 0x99, 0xC0, 0x16, 0x18, 0xCE, 0x30, 0x17, 0x08, 0xCD, 0x40, 0x17, 0xFA, 0x01, 0xB0, 0x18, 0xEA, 0x00, 0xC0, 0x19, 0xDB, 0x35, 0x30, 0x1A, 0xCC, 0x85, 0xC0, 0x1B, 0xBC, 0x92, 0xE0, 0x1C, 0xAC, 0x83, 0xE0, 0x1D, 0x9C, 0x74, 0xE0, 0x1E, 0x8C, 0x65, 0xE0, @@ -62797,58 +63262,61 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x04, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, -0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x04, 0x07, 0x04, +0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x08, 0x07, 0x04, 0x07, 0x00, 0x00, 0x29, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x00, 0x00, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x00, 0x08, 0x00, -0x00, 0x46, 0x50, 0x01, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x01, 0x08, 0x00, 0x00, 0x2A, 0x30, 0x00, -0x04, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x2B, 0x30, 0x35, -0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, -0x08, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xA1, 0xF5, 0x46, 0xDC, 0xFF, 0xFF, 0xFF, -0xFF, 0xB5, 0xA4, 0x0B, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x27, 0x99, 0xC0, 0x00, 0x00, 0x00, -0x00, 0x16, 0x18, 0xCE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x17, 0x08, 0xCD, 0x40, 0x00, 0x00, 0x00, -0x00, 0x17, 0xFA, 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x18, 0xEA, 0x00, 0xC0, 0x00, 0x00, 0x00, -0x00, 0x19, 0xDB, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x1A, 0xCC, 0x85, 0xC0, 0x00, 0x00, 0x00, -0x00, 0x1B, 0xBC, 0x92, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xAC, 0x83, 0xE0, 0x00, 0x00, 0x00, -0x00, 0x1D, 0x9C, 0x74, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x8C, 0x65, 0xE0, 0x00, 0x00, 0x00, -0x00, 0x1F, 0x7C, 0x56, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6C, 0x47, 0xE0, 0x00, 0x00, 0x00, -0x00, 0x21, 0x5C, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x22, 0x4C, 0x29, 0xE0, 0x00, 0x00, 0x00, -0x00, 0x23, 0x3C, 0x28, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2C, 0x19, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x25, 0x1C, 0x0A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0B, 0xFB, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x27, 0x05, 0x27, 0x70, 0x00, 0x00, 0x00, 0x00, 0x27, 0xF5, 0x18, 0x70, 0x00, 0x00, 0x00, -0x00, 0x29, 0xD4, 0xEC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xC4, 0xEB, 0x70, 0x00, 0x00, 0x00, -0x00, 0x2B, 0xB4, 0xDC, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xA4, 0xCD, 0x70, 0x00, 0x00, 0x00, -0x00, 0x2D, 0x94, 0xBE, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x84, 0xAF, 0x70, 0x00, 0x00, 0x00, -0x00, 0x2F, 0x74, 0xA0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, 0x64, 0x91, 0x70, 0x00, 0x00, 0x00, -0x00, 0x31, 0x5D, 0xBC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0x97, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x33, 0x3D, 0x9E, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x79, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x35, 0x1D, 0x80, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0x5B, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x36, 0xFD, 0x62, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1B, 0x78, 0x70, 0x00, 0x00, 0x00, -0x00, 0x38, 0xDD, 0x44, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x39, 0xFB, 0x5A, 0x70, 0x00, 0x00, 0x00, -0x00, 0x3A, 0xBD, 0x26, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xDB, 0x3C, 0x70, 0x00, 0x00, 0x00, -0x00, 0x3C, 0xA6, 0x43, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xBB, 0x1E, 0x70, 0x00, 0x00, 0x00, -0x00, 0x3E, 0x86, 0x25, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x9B, 0x00, 0x70, 0x00, 0x00, 0x00, -0x00, 0x40, 0x66, 0x07, 0x70, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x1C, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x42, 0x45, 0xE9, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0xFE, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x44, 0x25, 0xCB, 0x70, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xE0, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x46, 0x05, 0xAD, 0x70, 0x00, 0x00, 0x00, 0x00, 0x47, 0x23, 0xC2, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x47, 0xEE, 0xC9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x03, 0xA4, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x49, 0xCE, 0xAB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4A, 0xE3, 0x86, 0xF0, 0x00, 0x00, 0x00, -0x00, 0x4B, 0xAE, 0x8D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xCC, 0xA3, 0x70, 0x00, 0x00, 0x00, -0x00, 0x4D, 0x8E, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x4C, 0x1D, 0x60, 0x00, 0x00, 0x00, -0x00, 0x5B, 0xD4, 0xED, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x5F, 0xE7, 0xB2, 0x60, 0x01, 0x02, 0x03, -0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x06, 0x07, 0x06, -0x07, 0x06, 0x07, 0x04, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, +0x00, 0x46, 0x50, 0x01, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x01, 0x10, 0x00, 0x00, 0x2A, 0x30, 0x00, +0x14, 0x00, 0x00, 0x38, 0x40, 0x00, 0x14, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x14, 0x4C, 0x4D, 0x54, +0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x4D, 0x53, 0x44, +0x00, 0x4D, 0x53, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x54, +0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA1, +0xF5, 0x46, 0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xB5, 0xA4, 0x0B, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, +0x27, 0x99, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0xCE, 0x30, 0x00, 0x00, 0x00, 0x00, 0x17, +0x08, 0xCD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x17, 0xFA, 0x01, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x18, +0xEA, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x19, 0xDB, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x1A, +0xCC, 0x85, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xBC, 0x92, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1C, +0xAC, 0x83, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x9C, 0x74, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1E, +0x8C, 0x65, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x7C, 0x56, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x20, +0x6C, 0x47, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x5C, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x22, +0x4C, 0x29, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x23, 0x3C, 0x28, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x24, +0x2C, 0x19, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1C, 0x0A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x26, +0x0B, 0xFB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x05, 0x27, 0x70, 0x00, 0x00, 0x00, 0x00, 0x27, +0xF5, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x29, 0xD4, 0xEC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2A, +0xC4, 0xEB, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2B, 0xB4, 0xDC, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2C, +0xA4, 0xCD, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x94, 0xBE, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2E, +0x84, 0xAF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x74, 0xA0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, +0x64, 0x91, 0x70, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5D, 0xBC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x32, +0x72, 0x97, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x33, 0x3D, 0x9E, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x34, +0x52, 0x79, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1D, 0x80, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x36, +0x32, 0x5B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFD, 0x62, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x38, +0x1B, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x38, 0xDD, 0x44, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x39, +0xFB, 0x5A, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xBD, 0x26, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3B, +0xDB, 0x3C, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xA6, 0x43, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3D, +0xBB, 0x1E, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x86, 0x25, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3F, +0x9B, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x07, 0x70, 0x00, 0x00, 0x00, 0x00, 0x41, +0x84, 0x1C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xE9, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, +0x63, 0xFE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25, 0xCB, 0x70, 0x00, 0x00, 0x00, 0x00, 0x45, +0x43, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xAD, 0x70, 0x00, 0x00, 0x00, 0x00, 0x47, +0x23, 0xC2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x47, 0xEE, 0xC9, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x49, +0x03, 0xA4, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x49, 0xCE, 0xAB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4A, +0xE3, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4B, 0xAE, 0x8D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x4C, +0xCC, 0xA3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x8E, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x54, +0x4C, 0x1D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x5B, 0xD4, 0xED, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x5F, +0xE7, 0xB2, 0x60, 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x04, 0x05, 0x04, 0x05, +0x04, 0x05, 0x04, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x04, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, +0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, -0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x04, 0x07, 0x04, 0x07, 0x00, 0x00, -0x29, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x00, 0x00, 0x38, 0x40, 0x00, 0x08, -0x00, 0x00, 0x46, 0x50, 0x01, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x46, 0x50, -0x01, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x01, 0x08, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, 0x4C, 0x4D, -0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x2B, 0x30, 0x35, 0x00, 0x00, 0x00, -0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x0A, 0x3C, 0x2B, 0x30, 0x33, 0x3E, 0x2D, 0x33, 0x0A, 0x00, -0xD3, 0xB0, 0xB5, 0x01, 0x56, 0x6E, 0xC2, 0x00, 0x00, 0x00, 0x12, 0x4D, 0x53, 0x4B, 0x2B, 0x30, -0x30, 0x20, 0x2D, 0x20, 0x56, 0x6F, 0x6C, 0x67, 0x6F, 0x67, 0x72, 0x61, 0x64, +0x08, 0x07, 0x04, 0x07, 0x00, 0x00, 0x29, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x04, +0x00, 0x00, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0C, 0x00, 0x00, 0x38, 0x40, +0x00, 0x08, 0x00, 0x00, 0x46, 0x50, 0x01, 0x0C, 0x00, 0x00, 0x38, 0x40, 0x01, 0x10, 0x00, 0x00, +0x2A, 0x30, 0x00, 0x14, 0x00, 0x00, 0x38, 0x40, 0x00, 0x14, 0x00, 0x00, 0x2A, 0x30, 0x00, 0x14, +0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x30, 0x33, 0x00, 0x2B, 0x30, 0x34, 0x00, 0x2B, 0x30, 0x35, 0x00, +0x4D, 0x53, 0x44, 0x00, 0x4D, 0x53, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x0A, 0x4D, 0x53, 0x4B, 0x2D, 0x33, 0x0A, 0x00, 0xD3, 0xB0, 0xB5, 0x01, 0x56, 0x6E, +0xC2, 0x00, 0x00, 0x00, 0x12, 0x4D, 0x53, 0x4B, 0x2B, 0x30, 0x30, 0x20, 0x2D, 0x20, 0x56, 0x6F, +0x6C, 0x67, 0x6F, 0x67, 0x72, 0x61, 0x64, /* Europe/Warsaw */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x50, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -65776,8 +66244,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x0A, 0x4E, 0x5A, 0x53, 0x54, 0x2D, 0x31, 0x32, 0x4E, 0x5A, 0x44, 0x54, 0x2C, 0x4D, 0x39, 0x2E, 0x35, 0x2E, 0x30, 0x2C, 0x4D, 0x34, 0x2E, 0x31, 0x2E, 0x30, 0x2F, 0x33, 0x0A, 0x00, 0x51, 0x13, 0x35, 0x02, 0x1D, 0x54, 0xBA, 0x00, 0x00, 0x00, -0x18, 0x4E, 0x65, 0x77, 0x20, 0x5A, 0x65, 0x61, 0x6C, 0x61, 0x6E, 0x64, 0x20, 0x28, 0x6D, 0x6F, -0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, 0x29, +0x13, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x4E, 0x65, 0x77, 0x20, 0x5A, 0x65, 0x61, +0x6C, 0x61, 0x6E, 0x64, /* Pacific/Bougainville */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x50, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -66446,9 +66914,8 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x8C, 0xA0, 0x00, 0x0C, 0x00, 0x00, 0xA8, 0xC0, 0x00, 0x10, 0x4C, 0x4D, 0x54, 0x00, 0x2B, 0x31, 0x31, 0x00, 0x2B, 0x30, 0x39, 0x00, 0x2B, 0x31, 0x30, 0x00, 0x2B, 0x31, 0x32, 0x00, 0x0A, 0x3C, 0x2B, 0x31, 0x32, 0x3E, 0x2D, 0x31, 0x32, 0x0A, 0x00, 0x94, 0x3D, 0x38, 0x02, 0x17, 0xE3, 0x80, -0x00, 0x00, 0x00, 0x1D, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x49, 0x73, 0x6C, -0x61, 0x6E, 0x64, 0x73, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x73, -0x29, +0x00, 0x00, 0x00, 0x18, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x61, 0x72, 0x73, +0x68, 0x61, 0x6C, 0x6C, 0x20, 0x49, 0x73, 0x6C, 0x61, 0x6E, 0x64, 0x73, /* Pacific/Marquesas */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x50, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -66683,9 +67150,9 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { 0x90, 0x01, 0x02, 0x00, 0x00, 0x89, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x89, 0xF0, 0x00, 0x04, 0x00, 0x00, 0x8C, 0xA0, 0x00, 0x09, 0x4C, 0x4D, 0x54, 0x00, 0x50, 0x4D, 0x4D, 0x54, 0x00, 0x2B, 0x31, 0x30, 0x00, 0x0A, 0x3C, 0x2B, 0x31, 0x30, 0x3E, 0x2D, 0x31, 0x30, 0x0A, 0x00, 0x7A, 0xD5, 0x50, -0x01, 0xF3, 0x37, 0x7A, 0x00, 0x00, 0x00, 0x1D, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4E, 0x65, -0x77, 0x20, 0x47, 0x75, 0x69, 0x6E, 0x65, 0x61, 0x20, 0x28, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, -0x72, 0x65, 0x61, 0x73, 0x29, +0x01, 0xF3, 0x37, 0x7A, 0x00, 0x00, 0x00, 0x18, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, +0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4E, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6E, 0x65, 0x61, + /* Pacific/Rarotonga */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -69532,4 +69999,4 @@ const unsigned char timelib_timezone_db_data_builtin[699143] = { }; #endif -const timelib_tzdb timezonedb_builtin = { "2022.7", 597, timezonedb_idx_builtin, timelib_timezone_db_data_builtin }; +const timelib_tzdb timezonedb_builtin = { "2023.3", 597, timezonedb_idx_builtin, timelib_timezone_db_data_builtin }; diff --git a/ext/date/lib/tm2unixtime.c b/ext/date/lib/tm2unixtime.c index 37bfc98fa1d60..f13a9412406f3 100644 --- a/ext/date/lib/tm2unixtime.c +++ b/ext/date/lib/tm2unixtime.c @@ -32,8 +32,16 @@ static int days_in_month[13] = { 31, 31, 28, 31, 30, 31, 30, 31, 3 static void do_range_limit(timelib_sll start, timelib_sll end, timelib_sll adj, timelib_sll *a, timelib_sll *b) { if (*a < start) { - *b -= (start - *a - 1) / adj + 1; - *a += adj * ((start - *a - 1) / adj + 1); + /* We calculate 'a + 1' first as 'start - *a - 1' causes an int64_t overflows if *a is + * LONG_MIN. 'start' is 0 in this context, and '0 - LONG_MIN > LONG_MAX'. */ + timelib_sll a_plus_1 = *a + 1; + + *b -= (start - a_plus_1) / adj + 1; + + /* This code add the extra 'adj' separately, as otherwise this can overflow int64_t in + * situations where *b is near LONG_MIN. */ + *a += adj * ((start - a_plus_1) / adj); + *a += adj; } if (*a >= end) { *b += *a / adj; @@ -462,9 +470,15 @@ void timelib_update_ts(timelib_time* time, timelib_tzinfo* tzi) do_adjust_relative(time); do_adjust_special(time); - time->sse = - (timelib_epoch_days_from_time(time) * SECS_PER_DAY) + - timelib_hms_to_seconds(time->h, time->i, time->s); + /* You might be wondering, why this code does this in two steps. This is because + * timelib_epoch_days_from_time(time) * SECS_PER_DAY with the lowest limit of + * timelib_epoch_days_from_time() is less than the range of an int64_t. This then overflows. In + * order to be able to still allow for any time in that day that only halfly fits in the int64_t + * range, we add the time element first, which is always positive, and then twice half the value + * of the earliest day as expressed as unix timestamp. */ + time->sse = timelib_hms_to_seconds(time->h, time->i, time->s); + time->sse += timelib_epoch_days_from_time(time) * (SECS_PER_DAY / 2); + time->sse += timelib_epoch_days_from_time(time) * (SECS_PER_DAY / 2); // This modifies time->sse, if needed do_adjust_timezone(time, tzi); diff --git a/ext/date/php_date.c b/ext/date/php_date.c index ac0ae01b36011..02f65e2a1b937 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -235,7 +235,7 @@ PHPAPI time_t php_time(void) #include "php_date_arginfo.h" -static char* guess_timezone(const timelib_tzdb *tzdb); +static const char* guess_timezone(const timelib_tzdb *tzdb); static void date_register_classes(void); /* }}} */ @@ -269,6 +269,8 @@ PHP_INI_END() zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period; zend_class_entry *date_ce_immutable, *date_ce_interface; +zend_class_entry *date_ce_date_error, *date_ce_date_object_error, *date_ce_date_range_error; +zend_class_entry *date_ce_date_exception, *date_ce_date_invalid_timezone_exception, *date_ce_date_invalid_operation_exception, *date_ce_date_malformed_string_exception, *date_ce_date_malformed_interval_string_exception, *date_ce_date_malformed_period_string_exception; PHPAPI zend_class_entry *php_date_get_date_ce(void) @@ -307,9 +309,25 @@ static zend_object_handlers date_object_handlers_timezone; static zend_object_handlers date_object_handlers_interval; static zend_object_handlers date_object_handlers_period; -#define DATE_CHECK_INITIALIZED(member, class_name) \ +static void date_throw_uninitialized_error(zend_class_entry *ce) +{ + if (ce->type == ZEND_INTERNAL_CLASS) { + zend_throw_error(date_ce_date_object_error, "Object of type %s has not been correctly initialized by calling parent::__construct() in its constructor", ZSTR_VAL(ce->name)); + } else { + zend_class_entry *ce_ptr = ce; + while (ce_ptr && ce_ptr->parent && ce_ptr->type == ZEND_USER_CLASS) { + ce_ptr = ce_ptr->parent; + } + if (ce_ptr->type != ZEND_INTERNAL_CLASS) { + zend_throw_error(date_ce_date_object_error, "Object of type %s not been correctly initialized by calling parent::__construct() in its constructor", ZSTR_VAL(ce->name)); + } + zend_throw_error(date_ce_date_object_error, "Object of type %s (inheriting %s) has not been correctly initialized by calling parent::__construct() in its constructor", ZSTR_VAL(ce->name), ZSTR_VAL(ce_ptr->name)); + } +} + +#define DATE_CHECK_INITIALIZED(member, ce) \ if (!(member)) { \ - zend_throw_error(NULL, "The " #class_name " object has not been correctly initialized by its constructor"); \ + date_throw_uninitialized_error(ce); \ RETURN_THROWS(); \ } @@ -502,7 +520,7 @@ static timelib_tzinfo *php_date_parse_tzfile(const char *formal_tzname, const ti return tzi; } -timelib_tzinfo *php_date_parse_tzfile_wrapper(const char *formal_tzname, const timelib_tzdb *tzdb, int *dummy_error_code) +static timelib_tzinfo *php_date_parse_tzfile_wrapper(const char *formal_tzname, const timelib_tzdb *tzdb, int *dummy_error_code) { return php_date_parse_tzfile(formal_tzname, tzdb); } @@ -531,7 +549,7 @@ static PHP_INI_MH(OnUpdate_date_timezone) /* }}} */ /* {{{ Helper functions */ -static char* guess_timezone(const timelib_tzdb *tzdb) +static const char* guess_timezone(const timelib_tzdb *tzdb) { /* Checking whether timezone has been set with date_default_timezone_set() */ if (DATEG(timezone) && (strlen(DATEG(timezone))) > 0) { @@ -555,16 +573,45 @@ static char* guess_timezone(const timelib_tzdb *tzdb) PHPAPI timelib_tzinfo *get_timezone_info(void) { - char *tz; timelib_tzinfo *tzi; - tz = guess_timezone(DATE_TIMEZONEDB); + const char *tz = guess_timezone(DATE_TIMEZONEDB); tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB); if (! tzi) { - zend_throw_error(NULL, "Timezone database is corrupt. Please file a bug report as this should never happen"); + zend_throw_error(date_ce_date_error, "Timezone database is corrupt. Please file a bug report as this should never happen"); } return tzi; } + +static void update_property(zend_object *object, zend_string *key, zval *prop_val) +{ + if (ZSTR_LEN(key) > 0 && ZSTR_VAL(key)[0] == '\0') { // not public + const char *class_name, *prop_name; + size_t prop_name_len; + + if (zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len) == SUCCESS) { + if (class_name[0] != '*') { // private + zend_string *cname; + zend_class_entry *ce; + + cname = zend_string_init(class_name, strlen(class_name), 0); + ce = zend_lookup_class(cname); + + if (ce) { + zend_update_property(ce, object, prop_name, prop_name_len, prop_val); + } + + zend_string_release_ex(cname, 0); + } else { // protected + zend_update_property(object->ce, object, prop_name, prop_name_len, prop_val); + } + } + return; + } + + // public + zend_update_property(object->ce, object, ZSTR_VAL(key), ZSTR_LEN(key), prop_val); +} /* }}} */ @@ -589,7 +636,7 @@ static const char * const day_short_names[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -static char *english_suffix(timelib_sll number) +static const char *english_suffix(timelib_sll number) { if (number >= 10 && number <= 19) { return "th"; @@ -722,7 +769,7 @@ static zend_string *date_format(const char *format, size_t format_len, timelib_t /* timezone */ case 'I': length = slprintf(buffer, sizeof(buffer), "%d", localtime ? offset->is_dst : 0); break; case 'p': - if (!localtime || strcmp(offset->abbr, "UTC") == 0 || strcmp(offset->abbr, "Z") == 0) { + if (!localtime || strcmp(offset->abbr, "UTC") == 0 || strcmp(offset->abbr, "Z") == 0 || strcmp(offset->abbr, "GMT+0000") == 0) { length = slprintf(buffer, sizeof(buffer), "%s", "Z"); break; } @@ -1603,7 +1650,7 @@ static void date_period_it_move_forward(zend_object_iterator *iter) } create_date_period_datetime(object->current, object->start_ce, ¤t_zv); - zend_string *property_name = zend_string_init("current", sizeof("current") - 1, 0); + zend_string *property_name = ZSTR_INIT_LITERAL("current", 0); zend_std_write_property(&object->std, property_name, ¤t_zv, NULL); zval_ptr_dtor(¤t_zv); zend_string_release(property_name); @@ -1623,7 +1670,7 @@ static void date_period_it_rewind(zend_object_iterator *iter) timelib_time_dtor(iterator->object->current); } if (!iterator->object->start) { - zend_throw_error(NULL, "DatePeriod has not been initialized correctly"); + date_throw_uninitialized_error(date_ce_period); return; } @@ -1649,7 +1696,7 @@ static const zend_object_iterator_funcs date_period_it_funcs = { NULL, /* get_gc */ }; -zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ +static zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ { date_period_it *iterator; @@ -1779,6 +1826,17 @@ static void date_register_classes(void) /* {{{ */ date_object_handlers_period.get_property_ptr_ptr = date_period_get_property_ptr_ptr; date_object_handlers_period.read_property = date_period_read_property; date_object_handlers_period.write_property = date_period_write_property; + + date_ce_date_error = register_class_DateError(zend_ce_error); + date_ce_date_object_error = register_class_DateObjectError(date_ce_date_error); + date_ce_date_range_error = register_class_DateRangeError(date_ce_date_error); + + date_ce_date_exception = register_class_DateException(zend_ce_exception); + date_ce_date_invalid_timezone_exception = register_class_DateInvalidTimeZoneException(date_ce_date_exception); + date_ce_date_invalid_operation_exception = register_class_DateInvalidOperationException(date_ce_date_exception); + date_ce_date_malformed_string_exception = register_class_DateMalformedStringException(date_ce_date_exception); + date_ce_date_malformed_interval_string_exception = register_class_DateMalformedIntervalStringException(date_ce_date_exception); + date_ce_date_malformed_period_string_exception = register_class_DateMalformedPeriodStringException(date_ce_date_exception); } /* }}} */ static zend_object *date_object_new_date(zend_class_entry *class_type) /* {{{ */ @@ -1830,7 +1888,7 @@ static int date_object_compare_date(zval *d1, zval *d2) /* {{{ */ o2 = Z_PHPDATE_P(d2); if (!o1->time || !o2->time) { - php_error_docref(NULL, E_WARNING, "Trying to compare an incomplete DateTime or DateTimeImmutable object"); + zend_throw_error(date_ce_date_object_error, "Trying to compare an incomplete DateTime or DateTimeImmutable object"); return ZEND_UNCOMPARABLE; } if (!o1->time->sse_uptodate) { @@ -1970,12 +2028,12 @@ static int date_object_compare_timezone(zval *tz1, zval *tz2) /* {{{ */ o2 = Z_PHPTIMEZONE_P(tz2); if (!o1->initialized || !o2->initialized) { - zend_throw_error(NULL, "Trying to compare uninitialized DateTimeZone objects"); + zend_throw_error(date_ce_date_object_error, "Trying to compare uninitialized DateTimeZone objects"); return 1; } if (o1->type != o2->type) { - php_error_docref(NULL, E_WARNING, "Trying to compare different kinds of DateTimeZone objects"); + zend_throw_error(date_ce_date_exception, "Cannot compare two different kinds of DateTimeZone objects"); return ZEND_UNCOMPARABLE; } @@ -2014,7 +2072,7 @@ static void php_timezone_to_string(php_timezone_obj *tzobj, zval *zv) } } -void date_timezone_object_to_hash(php_timezone_obj *tzobj, HashTable *props) +static void date_timezone_object_to_hash(php_timezone_obj *tzobj, HashTable *props) { zval zv; @@ -2116,7 +2174,7 @@ static void date_interval_object_to_hash(php_interval_obj *intervalobj, HashTabl /* Records whether this is a special relative interval that needs to be recreated from a string */ if (intervalobj->from_string) { - ZVAL_BOOL(&zv, (zend_bool)intervalobj->from_string); + ZVAL_BOOL(&zv, (bool)intervalobj->from_string); zend_hash_str_update(props, "from_string", strlen("from_string"), &zv); ZVAL_STR_COPY(&zv, intervalobj->date_string); zend_hash_str_update(props, "date_string", strlen("date_string"), &zv); @@ -2142,7 +2200,7 @@ static void date_interval_object_to_hash(php_interval_obj *intervalobj, HashTabl ZVAL_FALSE(&zv); zend_hash_str_update(props, "days", sizeof("days")-1, &zv); } - ZVAL_BOOL(&zv, (zend_bool)intervalobj->from_string); + ZVAL_BOOL(&zv, (bool)intervalobj->from_string); zend_hash_str_update(props, "from_string", strlen("from_string"), &zv); #undef PHP_DATE_INTERVAL_ADD_PROPERTY @@ -2254,6 +2312,19 @@ static void date_object_free_storage_period(zend_object *object) /* {{{ */ zend_object_std_dtor(&intern->std); } /* }}} */ +static void add_common_properties(HashTable *myht, zend_object *zobj) +{ + HashTable *common; + zend_string *name; + zval *prop; + + common = zend_std_get_properties(zobj); + + ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_IND(common, name, prop) { + zend_hash_add(myht, name, prop); + } ZEND_HASH_FOREACH_END(); +} + /* Advanced Interface */ PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object) /* {{{ */ { @@ -2336,8 +2407,8 @@ PHPAPI bool php_date_initialize(php_date_obj *dateobj, const char *time_str, siz /* If called from a constructor throw an exception */ if ((flags & PHP_DATE_INIT_CTOR) && err && err->error_count) { /* spit out the first library error message, at least */ - zend_throw_exception_ex(NULL, 0, "Failed to parse time string (%s) at position %d (%c): %s", time_str, - err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message); + zend_throw_exception_ex(date_ce_date_malformed_string_exception, 0, "Failed to parse time string (%s) at position %d (%c): %s", time_str, + err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); } if (err && err->error_count) { timelib_time_dtor(dateobj->time); @@ -2547,7 +2618,7 @@ PHP_METHOD(DateTime, createFromImmutable) ZEND_PARSE_PARAMETERS_END(); old_obj = Z_PHPDATE_P(datetimeimmutable_object); - DATE_CHECK_INITIALIZED(old_obj->time, DateTimeImmutable); + DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeimmutable_object)); php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value); new_obj = Z_PHPDATE_P(return_value); @@ -2568,7 +2639,7 @@ PHP_METHOD(DateTime, createFromInterface) ZEND_PARSE_PARAMETERS_END(); old_obj = Z_PHPDATE_P(datetimeinterface_object); - DATE_CHECK_INITIALIZED(old_obj->time, DateTimeInterface); + DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object)); php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value); new_obj = Z_PHPDATE_P(return_value); @@ -2589,7 +2660,7 @@ PHP_METHOD(DateTimeImmutable, createFromMutable) ZEND_PARSE_PARAMETERS_END(); old_obj = Z_PHPDATE_P(datetime_object); - DATE_CHECK_INITIALIZED(old_obj->time, DateTime); + DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetime_object)); php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value); new_obj = Z_PHPDATE_P(return_value); @@ -2610,7 +2681,7 @@ PHP_METHOD(DateTimeImmutable, createFromInterface) ZEND_PARSE_PARAMETERS_END(); old_obj = Z_PHPDATE_P(datetimeinterface_object); - DATE_CHECK_INITIALIZED(old_obj->time, DateTimeInterface); + DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object)); php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value); new_obj = Z_PHPDATE_P(return_value); @@ -2693,6 +2764,7 @@ PHP_METHOD(DateTime, __set_state) dateobj = Z_PHPDATE_P(return_value); if (!php_date_initialize_from_hash(&dateobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTime object"); + RETURN_THROWS(); } } /* }}} */ @@ -2714,6 +2786,7 @@ PHP_METHOD(DateTimeImmutable, __set_state) dateobj = Z_PHPDATE_P(return_value); if (!php_date_initialize_from_hash(&dateobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTimeImmutable object"); + RETURN_THROWS(); } } /* }}} */ @@ -2728,11 +2801,13 @@ PHP_METHOD(DateTime, __serialize) ZEND_PARSE_PARAMETERS_NONE(); dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); date_object_to_hash(dateobj, myht); + + add_common_properties(myht, &dateobj->std); } /* }}} */ @@ -2746,14 +2821,41 @@ PHP_METHOD(DateTimeImmutable, __serialize) ZEND_PARSE_PARAMETERS_NONE(); dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTimeImmutable); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); date_object_to_hash(dateobj, myht); + + add_common_properties(myht, &dateobj->std); } /* }}} */ +static bool date_time_is_internal_property(zend_string *name) +{ + if ( + zend_string_equals_literal(name, "date") || + zend_string_equals_literal(name, "timezone_type") || + zend_string_equals_literal(name, "timezone") + ) { + return 1; + } + return 0; +} + +static void restore_custom_datetime_properties(zval *object, HashTable *myht) +{ + zend_string *prop_name; + zval *prop_val; + + ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(myht, prop_name, prop_val) { + if (!prop_name || (Z_TYPE_P(prop_val) == IS_REFERENCE) || date_time_is_internal_property(prop_name)) { + continue; + } + update_property(Z_OBJ_P(object), prop_name, prop_val); + } ZEND_HASH_FOREACH_END(); +} + /* {{{ */ PHP_METHOD(DateTime, __unserialize) { @@ -2771,7 +2873,10 @@ PHP_METHOD(DateTime, __unserialize) if (!php_date_initialize_from_hash(&dateobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTime object"); + RETURN_THROWS(); } + + restore_custom_datetime_properties(object, myht); } /* }}} */ @@ -2792,7 +2897,10 @@ PHP_METHOD(DateTimeImmutable, __unserialize) if (!php_date_initialize_from_hash(&dateobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTimeImmutable object"); + RETURN_THROWS(); } + + restore_custom_datetime_properties(object, myht); } /* }}} */ @@ -2869,7 +2977,7 @@ PHP_FUNCTION(date_get_last_errors) } /* }}} */ -void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *parsed_time, timelib_error_container *error) /* {{{ */ +static void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *parsed_time, timelib_error_container *error) /* {{{ */ { zval element; @@ -2988,7 +3096,7 @@ PHP_FUNCTION(date_format) RETURN_THROWS(); } dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); RETURN_STR(date_format(format, format_len, dateobj->time, dateobj->time->is_localtime)); } /* }}} */ @@ -3002,7 +3110,7 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{ dateobj = Z_PHPDATE_P(object); if (!(dateobj->time)) { - zend_throw_error(NULL, "The DateTime object has not been correctly initialized by its constructor"); + date_throw_uninitialized_error(Z_OBJCE_P(object)); return 0; } @@ -3014,7 +3122,9 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{ if (err && err->error_count) { /* spit out the first library error message, at least */ php_error_docref(NULL, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify, - err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message); + err->error_messages[0].position, + err->error_messages[0].character ? err->error_messages[0].character : ' ', + err->error_messages[0].message); timelib_time_dtor(tmp_time); return 0; } @@ -3052,6 +3162,16 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{ dateobj->time->us = tmp_time->us; } + /* Reset timezone to UTC if we detect a "@" modification */ + if ( + tmp_time->y == 1970 && tmp_time->m == 1 && tmp_time->d == 1 && + tmp_time->h == 0 && tmp_time->i == 0 && tmp_time->s == 0 && tmp_time->us == 0 && + tmp_time->have_zone && tmp_time->zone_type == TIMELIB_ZONETYPE_OFFSET && + tmp_time->z == 0 && tmp_time->dst == 0 + ) { + timelib_set_timezone_from_offset(dateobj->time, 0); + } + timelib_time_dtor(tmp_time); timelib_update_ts(dateobj->time, NULL); @@ -3081,12 +3201,38 @@ PHP_FUNCTION(date_modify) } /* }}} */ +/* {{{ */ +PHP_METHOD(DateTime, modify) +{ + zval *object; + char *modify; + size_t modify_len; + zend_error_handling zeh; + + object = ZEND_THIS; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &modify, &modify_len) == FAILURE) { + RETURN_THROWS(); + } + + zend_replace_error_handling(EH_THROW, date_ce_date_malformed_string_exception, &zeh); + if (!php_date_modify(object, modify, modify_len)) { + zend_restore_error_handling(&zeh); + RETURN_THROWS(); + } + + zend_restore_error_handling(&zeh); + + RETURN_OBJ_COPY(Z_OBJ_P(object)); +} +/* }}} */ + /* {{{ */ PHP_METHOD(DateTimeImmutable, modify) { zval *object, new_object; char *modify; size_t modify_len; + zend_error_handling zeh; object = ZEND_THIS; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &modify, &modify_len) == FAILURE) { @@ -3094,11 +3240,16 @@ PHP_METHOD(DateTimeImmutable, modify) } date_clone_immutable(object, &new_object); + + zend_replace_error_handling(EH_THROW, date_ce_date_malformed_string_exception, &zeh); if (!php_date_modify(&new_object, modify, modify_len)) { zval_ptr_dtor(&new_object); - RETURN_FALSE; + zend_restore_error_handling(&zeh); + RETURN_THROWS(); } + zend_restore_error_handling(&zeh); + RETURN_OBJ(Z_OBJ(new_object)); } /* }}} */ @@ -3110,9 +3261,9 @@ static void php_date_add(zval *object, zval *interval, zval *return_value) /* {{ timelib_time *new_time; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); intobj = Z_PHPINTERVAL_P(interval); - DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval); + DATE_CHECK_INITIALIZED(intobj->initialized, Z_OBJCE_P(interval)); if (intobj->civil_or_wall == PHP_DATE_WALL) { new_time = timelib_add_wall(dateobj->time, intobj->diff); @@ -3162,9 +3313,9 @@ static void php_date_sub(zval *object, zval *interval, zval *return_value) /* {{ timelib_time *new_time; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); intobj = Z_PHPINTERVAL_P(interval); - DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval); + DATE_CHECK_INITIALIZED(intobj->initialized, Z_OBJCE_P(interval)); if (intobj->diff->have_weekday_relative || intobj->diff->have_special_relative) { php_error_docref(NULL, E_WARNING, "Only non-special relative time specifications are supported for subtraction"); @@ -3190,6 +3341,23 @@ PHP_FUNCTION(date_sub) } php_date_sub(object, interval, return_value); + RETURN_OBJ_COPY(Z_OBJ_P(object)); +} +/* }}} */ + +/* {{{ Subtracts an interval to the current date in object. */ +PHP_METHOD(DateTime, sub) +{ + zval *object, *interval; + zend_error_handling zeh; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) { + RETURN_THROWS(); + } + + zend_replace_error_handling(EH_THROW, date_ce_date_invalid_operation_exception, &zeh); + php_date_sub(object, interval, return_value); + zend_restore_error_handling(&zeh); RETURN_OBJ_COPY(Z_OBJ_P(object)); } @@ -3199,6 +3367,7 @@ PHP_FUNCTION(date_sub) PHP_METHOD(DateTimeImmutable, sub) { zval *object, *interval, new_object; + zend_error_handling zeh; object = ZEND_THIS; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &interval, date_ce_interval) == FAILURE) { @@ -3206,7 +3375,10 @@ PHP_METHOD(DateTimeImmutable, sub) } date_clone_immutable(object, &new_object); + + zend_replace_error_handling(EH_THROW, date_ce_date_invalid_operation_exception, &zeh); php_date_sub(&new_object, interval, return_value); + zend_restore_error_handling(&zeh); RETURN_OBJ(Z_OBJ(new_object)); } @@ -3249,7 +3421,7 @@ PHP_FUNCTION(date_timezone_get) RETURN_THROWS(); } dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); if (dateobj->time->is_localtime) { php_timezone_obj *tzobj; php_date_instantiate(date_ce_timezone, return_value); @@ -3267,7 +3439,7 @@ static void php_date_timezone_set(zval *object, zval *timezone_object, zval *ret php_timezone_obj *tzobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); tzobj = Z_PHPTIMEZONE_P(timezone_object); switch (tzobj->type) { @@ -3329,7 +3501,7 @@ PHP_FUNCTION(date_offset_get) RETURN_THROWS(); } dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); if (dateobj->time->is_localtime) { switch (dateobj->time->zone_type) { case TIMELIB_ZONETYPE_ID: @@ -3356,7 +3528,7 @@ static void php_date_time_set(zval *object, zend_long h, zend_long i, zend_long php_date_obj *dateobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); dateobj->time->h = h; dateobj->time->i = i; dateobj->time->s = s; @@ -3404,7 +3576,7 @@ static void php_date_date_set(zval *object, zend_long y, zend_long m, zend_long php_date_obj *dateobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); dateobj->time->y = y; dateobj->time->m = m; dateobj->time->d = d; @@ -3450,7 +3622,7 @@ static void php_date_isodate_set(zval *object, zend_long y, zend_long w, zend_lo php_date_obj *dateobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); dateobj->time->y = y; dateobj->time->m = 1; dateobj->time->d = 1; @@ -3500,7 +3672,7 @@ static void php_date_timestamp_set(zval *object, zend_long timestamp, zval *retu php_date_obj *dateobj; dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); timelib_unixtime2local(dateobj->time, (timelib_sll)timestamp); timelib_update_ts(dateobj->time, NULL); php_date_set_time_fraction(dateobj->time, 0); @@ -3552,7 +3724,7 @@ PHP_FUNCTION(date_timestamp_get) RETURN_THROWS(); } dateobj = Z_PHPDATE_P(object); - DATE_CHECK_INITIALIZED(dateobj->time, DateTime); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(object)); if (!dateobj->time->sse_uptodate) { timelib_update_ts(dateobj->time, NULL); @@ -3561,7 +3733,7 @@ PHP_FUNCTION(date_timestamp_get) timestamp = timelib_date_to_int(dateobj->time, &epoch_does_not_fit_in_zend_long); if (epoch_does_not_fit_in_zend_long) { - zend_value_error("Epoch doesn't fit in a PHP integer"); + zend_throw_error(date_ce_date_range_error, "Epoch doesn't fit in a PHP integer"); RETURN_THROWS(); } @@ -3582,8 +3754,8 @@ PHP_FUNCTION(date_diff) } dateobj1 = Z_PHPDATE_P(object1); dateobj2 = Z_PHPDATE_P(object2); - DATE_CHECK_INITIALIZED(dateobj1->time, DateTimeInterface); - DATE_CHECK_INITIALIZED(dateobj2->time, DateTimeInterface); + DATE_CHECK_INITIALIZED(dateobj1->time, Z_OBJCE_P(object1)); + DATE_CHECK_INITIALIZED(dateobj2->time, Z_OBJCE_P(object2)); php_date_instantiate(date_ce_interval, return_value); interval = Z_PHPINTERVAL_P(return_value); @@ -3596,34 +3768,42 @@ PHP_FUNCTION(date_diff) } /* }}} */ -static bool timezone_initialize(php_timezone_obj *tzobj, const char *tz, size_t tz_len) /* {{{ */ +static bool timezone_initialize(php_timezone_obj *tzobj, const char *tz, size_t tz_len, char **warning_message) /* {{{ */ { timelib_time *dummy_t = ecalloc(1, sizeof(timelib_time)); int dst, not_found; const char *orig_tz = tz; if (strlen(tz) != tz_len) { - php_error_docref(NULL, E_WARNING, "Timezone must not contain null bytes"); + if (warning_message) { + spprintf(warning_message, 0, "Timezone must not contain null bytes"); + } efree(dummy_t); return false; } dummy_t->z = timelib_parse_zone(&tz, &dst, dummy_t, ¬_found, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); if ((dummy_t->z >= (100 * 60 * 60)) || (dummy_t->z <= (-100 * 60 * 60))) { - php_error_docref(NULL, E_WARNING, "Timezone offset is out of range (%s)", orig_tz); + if (warning_message) { + spprintf(warning_message, 0, "Timezone offset is out of range (%s)", orig_tz); + } timelib_free(dummy_t->tz_abbr); efree(dummy_t); - return FAILURE; + return false; } dummy_t->dst = dst; if (!not_found && (*tz != '\0')) { - php_error_docref(NULL, E_WARNING, "Unknown or bad timezone (%s)", orig_tz); + if (warning_message) { + spprintf(warning_message, 0, "Unknown or bad timezone (%s)", orig_tz); + } timelib_free(dummy_t->tz_abbr); efree(dummy_t); return false; } if (not_found) { - php_error_docref(NULL, E_WARNING, "Unknown or bad timezone (%s)", orig_tz); + if (warning_message) { + spprintf(warning_message, 0, "Unknown or bad timezone (%s)", orig_tz); + } efree(dummy_t); return false; } else { @@ -3639,13 +3819,16 @@ PHP_FUNCTION(timezone_open) { zend_string *tz; php_timezone_obj *tzobj; + char *warning_message; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_PATH_STR(tz) /* To prevent null bytes */ ZEND_PARSE_PARAMETERS_END(); tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value)); - if (!timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz))) { + if (!timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz), &warning_message)) { + php_error_docref(NULL, E_WARNING, "%s", warning_message); + efree(warning_message); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3657,16 +3840,17 @@ PHP_METHOD(DateTimeZone, __construct) { zend_string *tz; php_timezone_obj *tzobj; - zend_error_handling error_handling; + char *exception_message; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_PATH_STR(tz) /* To prevent null bytes */ ZEND_PARSE_PARAMETERS_END(); - zend_replace_error_handling(EH_THROW, NULL, &error_handling); tzobj = Z_PHPTIMEZONE_P(ZEND_THIS); - timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz)); - zend_restore_error_handling(&error_handling); + if (!timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz), &exception_message)) { + zend_throw_exception_ex(date_ce_date_invalid_timezone_exception, 0, "DateTimeZone::__construct(): %s", exception_message); + efree(exception_message); + } } /* }}} */ @@ -3687,10 +3871,13 @@ static bool php_date_timezone_initialize_from_hash(zval **return_value, php_time if (Z_TYPE_P(z_timezone_type) != IS_LONG) { return false; } + if (Z_LVAL_P(z_timezone_type) < TIMELIB_ZONETYPE_OFFSET || Z_LVAL_P(z_timezone_type) > TIMELIB_ZONETYPE_ID) { + return false; + } if (Z_TYPE_P(z_timezone) != IS_STRING) { return false; } - return timezone_initialize(*tzobj, Z_STRVAL_P(z_timezone), Z_STRLEN_P(z_timezone)); + return timezone_initialize(*tzobj, Z_STRVAL_P(z_timezone), Z_STRLEN_P(z_timezone), NULL); } /* }}} */ /* {{{ */ @@ -3709,8 +3896,7 @@ PHP_METHOD(DateTimeZone, __set_state) php_date_instantiate(date_ce_timezone, return_value); tzobj = Z_PHPTIMEZONE_P(return_value); if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) { - zend_throw_error(NULL, "Timezone initialization failed"); - zval_ptr_dtor(return_value); + zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); } } /* }}} */ @@ -3729,7 +3915,7 @@ PHP_METHOD(DateTimeZone, __wakeup) myht = Z_OBJPROP_P(object); if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) { - zend_throw_error(NULL, "Timezone initialization failed"); + zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); } } /* }}} */ @@ -3744,14 +3930,40 @@ PHP_METHOD(DateTimeZone, __serialize) ZEND_PARSE_PARAMETERS_NONE(); tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); date_timezone_object_to_hash(tzobj, myht); + + add_common_properties(myht, &tzobj->std); } /* }}} */ +static bool date_timezone_is_internal_property(zend_string *name) +{ + if ( + zend_string_equals_literal(name, "timezone_type") || + zend_string_equals_literal(name, "timezone") + ) { + return 1; + } + return 0; +} + +static void restore_custom_datetimezone_properties(zval *object, HashTable *myht) +{ + zend_string *prop_name; + zval *prop_val; + + ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(myht, prop_name, prop_val) { + if (!prop_name || (Z_TYPE_P(prop_val) == IS_REFERENCE) || date_timezone_is_internal_property(prop_name)) { + continue; + } + update_property(Z_OBJ_P(object), prop_name, prop_val); + } ZEND_HASH_FOREACH_END(); +} + /* {{{ */ PHP_METHOD(DateTimeZone, __unserialize) { @@ -3770,6 +3982,8 @@ PHP_METHOD(DateTimeZone, __unserialize) if (!php_date_timezone_initialize_from_hash(&object, &tzobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); } + + restore_custom_datetimezone_properties(object, myht); } /* }}} */ @@ -3783,7 +3997,7 @@ PHP_FUNCTION(timezone_name_get) RETURN_THROWS(); } tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); php_timezone_to_string(tzobj, return_value); } /* }}} */ @@ -3825,9 +4039,9 @@ PHP_FUNCTION(timezone_offset_get) RETURN_THROWS(); } tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); dateobj = Z_PHPDATE_P(dateobject); - DATE_CHECK_INITIALIZED(dateobj->time, DateTimeInterface); + DATE_CHECK_INITIALIZED(dateobj->time, Z_OBJCE_P(dateobject)); switch (tzobj->type) { case TIMELIB_ZONETYPE_ID: @@ -3858,7 +4072,7 @@ PHP_FUNCTION(timezone_transitions_get) RETURN_THROWS(); } tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); if (tzobj->type != TIMELIB_ZONETYPE_ID) { RETURN_FALSE; } @@ -3991,7 +4205,7 @@ PHP_FUNCTION(timezone_location_get) RETURN_THROWS(); } tzobj = Z_PHPTIMEZONE_P(object); - DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone); + DATE_CHECK_INITIALIZED(tzobj->initialized, Z_OBJCE_P(object)); if (tzobj->type != TIMELIB_ZONETYPE_ID) { RETURN_FALSE; } @@ -4015,23 +4229,23 @@ static bool date_interval_initialize(timelib_rel_time **rt, /*const*/ char *form timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors); if (errors->error_count > 0) { - zend_throw_exception_ex(NULL, 0, "Unknown or bad format (%s)", format); + zend_throw_exception_ex(date_ce_date_malformed_interval_string_exception, 0, "Unknown or bad format (%s)", format); retval = false; if (p) { timelib_rel_time_dtor(p); } } else { - if(p) { + if (p) { *rt = p; retval = true; } else { - if(b && e) { + if (b && e) { timelib_update_ts(b, NULL); timelib_update_ts(e, NULL); *rt = timelib_diff(b, e); retval = true; } else { - zend_throw_exception_ex(NULL, 0, "Failed to parse interval (%s)", format); + zend_throw_exception_ex(date_ce_date_malformed_interval_string_exception, 0, "Failed to parse interval (%s)", format); retval = false; } } @@ -4203,8 +4417,7 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte time = timelib_strtotime(Z_STRVAL_P(date_str), Z_STRLEN_P(date_str), &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); if (err->error_count > 0) { - php_error_docref(NULL, - E_WARNING, + zend_throw_error(NULL, "Unknown or bad format (%s) at position %d (%c) while unserializing: %s", Z_STRVAL_P(date_str), err->error_messages[0].position, @@ -4335,14 +4548,49 @@ PHP_METHOD(DateInterval, __serialize) ZEND_PARSE_PARAMETERS_NONE(); intervalobj = Z_PHPINTERVAL_P(object); - DATE_CHECK_INITIALIZED(intervalobj->initialized, DateInterval); + DATE_CHECK_INITIALIZED(intervalobj->initialized, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); date_interval_object_to_hash(intervalobj, myht); + + add_common_properties(myht, &intervalobj->std); } /* }}} */ +static bool date_interval_is_internal_property(zend_string *name) +{ + if ( + zend_string_equals_literal(name, "date_string") || + zend_string_equals_literal(name, "from_string") || + zend_string_equals_literal(name, "y") || + zend_string_equals_literal(name, "m") || + zend_string_equals_literal(name, "d") || + zend_string_equals_literal(name, "h") || + zend_string_equals_literal(name, "i") || + zend_string_equals_literal(name, "s") || + zend_string_equals_literal(name, "f") || + zend_string_equals_literal(name, "invert") || + zend_string_equals_literal(name, "days") + ) { + return 1; + } + return 0; +} + +static void restore_custom_dateinterval_properties(zval *object, HashTable *myht) +{ + zend_string *prop_name; + zval *prop_val; + + ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(myht, prop_name, prop_val) { + if (!prop_name || (Z_TYPE_P(prop_val) == IS_REFERENCE) || date_interval_is_internal_property(prop_name)) { + continue; + } + update_property(Z_OBJ_P(object), prop_name, prop_val); + } ZEND_HASH_FOREACH_END(); +} + /* {{{ */ PHP_METHOD(DateInterval, __unserialize) @@ -4360,6 +4608,7 @@ PHP_METHOD(DateInterval, __unserialize) myht = Z_ARRVAL_P(array); php_date_interval_initialize_from_hash(&object, &intervalobj, myht); + restore_custom_dateinterval_properties(object, myht); } /* }}} */ @@ -4380,13 +4629,25 @@ PHP_METHOD(DateInterval, __wakeup) } /* }}} */ +static void date_interval_instantiate_from_time(zval *return_value, timelib_time *time, zend_string *time_str) +{ + php_interval_obj *diobj; + + php_date_instantiate(date_ce_interval, return_value); + diobj = Z_PHPINTERVAL_P(return_value); + diobj->diff = timelib_rel_time_clone(&time->relative); + diobj->initialized = 1; + diobj->civil_or_wall = PHP_DATE_CIVIL; + diobj->from_string = true; + diobj->date_string = zend_string_copy(time_str); +} + /* {{{ Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string */ PHP_FUNCTION(date_interval_create_from_date_string) { zend_string *time_str = NULL; timelib_time *time; timelib_error_container *err = NULL; - php_interval_obj *diobj; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(time_str) @@ -4407,13 +4668,39 @@ PHP_FUNCTION(date_interval_create_from_date_string) goto cleanup; } - php_date_instantiate(date_ce_interval, return_value); - diobj = Z_PHPINTERVAL_P(return_value); - diobj->diff = timelib_rel_time_clone(&time->relative); - diobj->initialized = 1; - diobj->civil_or_wall = PHP_DATE_CIVIL; - diobj->from_string = true; - diobj->date_string = zend_string_copy(time_str); + date_interval_instantiate_from_time(return_value, time, time_str); + +cleanup: + timelib_time_dtor(time); + timelib_error_container_dtor(err); +} +/* }}} */ + +/* {{{ Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string */ +PHP_METHOD(DateInterval, createFromDateString) +{ + zend_string *time_str = NULL; + timelib_time *time; + timelib_error_container *err = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(time_str) + ZEND_PARSE_PARAMETERS_END(); + + time = timelib_strtotime(ZSTR_VAL(time_str), ZSTR_LEN(time_str), &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); + + if (err->error_count > 0) { + zend_throw_error(date_ce_date_malformed_interval_string_exception, "Unknown or bad format (%s) at position %d (%c): %s", ZSTR_VAL(time_str), + err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); + goto cleanup; + } + + if (time->have_date || time->have_time || time->have_zone) { + zend_throw_error(date_ce_date_malformed_interval_string_exception, "String '%s' contains non-relative elements", ZSTR_VAL(time_str)); + goto cleanup; + } + + date_interval_instantiate_from_time(return_value, time, time_str); cleanup: timelib_time_dtor(time); @@ -4503,7 +4790,7 @@ PHP_FUNCTION(date_interval_format) RETURN_THROWS(); } diobj = Z_PHPINTERVAL_P(object); - DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval); + DATE_CHECK_INITIALIZED(diobj->initialized, Z_OBJCE_P(object)); RETURN_STR(date_interval_format(format, format_len, diobj->diff)); } @@ -4521,7 +4808,7 @@ static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib if (errors->error_count > 0) { retval = false; - zend_throw_exception_ex(NULL, 0, "Unknown or bad format (%s)", format); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "Unknown or bad format (%s)", format); if (b) { timelib_time_dtor(b); } @@ -4572,19 +4859,19 @@ PHP_METHOD(DatePeriod, __construct) if (dpobj->start == NULL) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr); zend_string_release(func); RETURN_THROWS(); } if (dpobj->interval == NULL) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr); zend_string_release(func); RETURN_THROWS(); } if (dpobj->end == NULL && recurrences == 0) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr); zend_string_release(func); RETURN_THROWS(); } @@ -4626,7 +4913,7 @@ PHP_METHOD(DatePeriod, __construct) if (dpobj->end == NULL && recurrences < 1) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(NULL, 0, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func)); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func)); zend_string_release(func); RETURN_THROWS(); } @@ -4653,7 +4940,7 @@ PHP_METHOD(DatePeriod, getStartDate) ZEND_PARSE_PARAMETERS_NONE(); dpobj = Z_PHPPERIOD_P(ZEND_THIS); - DATE_CHECK_INITIALIZED(dpobj->start, DatePeriod); + DATE_CHECK_INITIALIZED(dpobj->start, Z_OBJCE_P(ZEND_THIS)); php_date_instantiate(dpobj->start_ce, return_value); dateobj = Z_PHPDATE_P(return_value); @@ -4704,7 +4991,7 @@ PHP_METHOD(DatePeriod, getDateInterval) ZEND_PARSE_PARAMETERS_NONE(); dpobj = Z_PHPPERIOD_P(ZEND_THIS); - DATE_CHECK_INITIALIZED(dpobj->interval, DatePeriod); + DATE_CHECK_INITIALIZED(dpobj->interval, Z_OBJCE_P(ZEND_THIS)); php_date_instantiate(date_ce_interval, return_value); diobj = Z_PHPINTERVAL_P(return_value); @@ -5260,14 +5547,49 @@ PHP_METHOD(DatePeriod, __serialize) ZEND_PARSE_PARAMETERS_NONE(); period_obj = Z_PHPPERIOD_P(object); - DATE_CHECK_INITIALIZED(period_obj->start, DatePeriod); + DATE_CHECK_INITIALIZED(period_obj->start, Z_OBJCE_P(object)); array_init(return_value); myht = Z_ARRVAL_P(return_value); date_period_object_to_hash(period_obj, myht); + + add_common_properties(myht, &period_obj->std); } /* }}} */ +/* {{{ date_period_is_internal_property + * Common for date_period_read_property(), date_period_write_property(), and + * restore_custom_dateperiod_properties functions + */ +static bool date_period_is_internal_property(zend_string *name) +{ + if ( + zend_string_equals_literal(name, "start") || + zend_string_equals_literal(name, "current") || + zend_string_equals_literal(name, "end") || + zend_string_equals_literal(name, "interval") || + zend_string_equals_literal(name, "recurrences") || + zend_string_equals_literal(name, "include_start_date") || + zend_string_equals_literal(name, "include_end_date") + ) { + return 1; + } + return 0; +} +/* }}} */ + +static void restore_custom_dateperiod_properties(zval *object, HashTable *myht) +{ + zend_string *prop_name; + zval *prop_val; + + ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(myht, prop_name, prop_val) { + if (!prop_name || (Z_TYPE_P(prop_val) == IS_REFERENCE) || date_period_is_internal_property(prop_name)) { + continue; + } + update_property(Z_OBJ_P(object), prop_name, prop_val); + } ZEND_HASH_FOREACH_END(); +} /* {{{ */ PHP_METHOD(DatePeriod, __unserialize) @@ -5287,6 +5609,7 @@ PHP_METHOD(DatePeriod, __unserialize) if (!php_date_period_initialize_from_hash(period_obj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DatePeriod object"); } + restore_custom_dateperiod_properties(object, myht); } /* }}} */ @@ -5309,25 +5632,6 @@ PHP_METHOD(DatePeriod, __wakeup) } /* }}} */ -/* {{{ date_period_is_internal_property - * Common for date_period_read_property() and date_period_write_property() functions - */ -static bool date_period_is_internal_property(zend_string *name) -{ - if (zend_string_equals_literal(name, "recurrences") - || zend_string_equals_literal(name, "include_start_date") - || zend_string_equals_literal(name, "include_end_date") - || zend_string_equals_literal(name, "start") - || zend_string_equals_literal(name, "current") - || zend_string_equals_literal(name, "end") - || zend_string_equals_literal(name, "interval") - ) { - return 1; - } - return 0; -} -/* }}} */ - /* {{{ date_period_read_property */ static zval *date_period_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv) { diff --git a/ext/date/php_date.stub.php b/ext/date/php_date.stub.php index 172ab6d8b1d22..0146704e42a0b 100644 --- a/ext/date/php_date.stub.php +++ b/ext/date/php_date.stub.php @@ -377,7 +377,6 @@ public function format(string $format): string {} /** * @tentative-return-type - * @alias date_modify */ public function modify(string $modifier): DateTime|false {} @@ -389,7 +388,6 @@ public function add(DateInterval $interval): DateTime {} /** * @tentative-return-type - * @alias date_sub */ public function sub(DateInterval $interval): DateTime {} @@ -668,7 +666,6 @@ public function __construct(string $duration) {} /** * @tentative-return-type - * @alias date_interval_create_from_date_string */ public static function createFromDateString(string $datetime): DateInterval|false {} @@ -749,3 +746,66 @@ public static function __set_state(array $array): DatePeriod {} public function getIterator(): Iterator {} } + +/** + * @strict-properties + */ +class DateError extends Error +{ +} + +/** + * @strict-properties + */ +class DateObjectError extends DateError +{ +} + +/** + * @strict-properties + */ +class DateRangeError extends DateRangeError +{ +} + +/** + * @strict-properties + */ +class DateException extends Exception +{ +} + +/** + * @strict-properties + */ +class DateInvalidTimeZoneException extends Exception +{ +} + +/** + * @strict-properties + */ +class DateInvalidOperationException extends DateException +{ +} + +/** + * @strict-properties + */ +class DateMalformedStringException extends DateException +{ +} + +/** + * @strict-properties + */ +class DateMalformedIntervalStringException extends DateException +{ +} + +/** + * @strict-properties + */ +class DateMalformedPeriodStringException extends DateException +{ +} diff --git a/ext/date/php_date_arginfo.h b/ext/date/php_date_arginfo.h index f7920da2ce4b5..a16b6467aeafb 100644 --- a/ext/date/php_date_arginfo.h +++ b/ext/date/php_date_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 6949e2c795288f9615222b1fd496768ab20eb7c5 */ + * Stub hash: ce0bc9fd067a6598f66a65a9159674392e6cac4d */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0) @@ -549,6 +549,8 @@ ZEND_METHOD(DateTime, __wakeup); ZEND_METHOD(DateTime, __set_state); ZEND_METHOD(DateTime, createFromImmutable); ZEND_METHOD(DateTime, createFromInterface); +ZEND_METHOD(DateTime, modify); +ZEND_METHOD(DateTime, sub); ZEND_METHOD(DateTimeImmutable, __construct); ZEND_METHOD(DateTimeImmutable, __serialize); ZEND_METHOD(DateTimeImmutable, __unserialize); @@ -570,6 +572,7 @@ ZEND_METHOD(DateTimeZone, __unserialize); ZEND_METHOD(DateTimeZone, __wakeup); ZEND_METHOD(DateTimeZone, __set_state); ZEND_METHOD(DateInterval, __construct); +ZEND_METHOD(DateInterval, createFromDateString); ZEND_METHOD(DateInterval, __serialize); ZEND_METHOD(DateInterval, __unserialize); ZEND_METHOD(DateInterval, __wakeup); @@ -663,9 +666,9 @@ static const zend_function_entry class_DateTime_methods[] = { ZEND_ME_MAPPING(createFromFormat, date_create_from_format, arginfo_class_DateTime_createFromFormat, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME_MAPPING(getLastErrors, date_get_last_errors, arginfo_class_DateTime_getLastErrors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME_MAPPING(format, date_format, arginfo_class_DateTime_format, ZEND_ACC_PUBLIC) - ZEND_ME_MAPPING(modify, date_modify, arginfo_class_DateTime_modify, ZEND_ACC_PUBLIC) + ZEND_ME(DateTime, modify, arginfo_class_DateTime_modify, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(add, date_add, arginfo_class_DateTime_add, ZEND_ACC_PUBLIC) - ZEND_ME_MAPPING(sub, date_sub, arginfo_class_DateTime_sub, ZEND_ACC_PUBLIC) + ZEND_ME(DateTime, sub, arginfo_class_DateTime_sub, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getTimezone, date_timezone_get, arginfo_class_DateTime_getTimezone, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(setTimezone, date_timezone_set, arginfo_class_DateTime_setTimezone, ZEND_ACC_PUBLIC) ZEND_ME_MAPPING(getOffset, date_offset_get, arginfo_class_DateTime_getOffset, ZEND_ACC_PUBLIC) @@ -724,7 +727,7 @@ static const zend_function_entry class_DateTimeZone_methods[] = { static const zend_function_entry class_DateInterval_methods[] = { ZEND_ME(DateInterval, __construct, arginfo_class_DateInterval___construct, ZEND_ACC_PUBLIC) - ZEND_ME_MAPPING(createFromDateString, date_interval_create_from_date_string, arginfo_class_DateInterval_createFromDateString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(DateInterval, createFromDateString, arginfo_class_DateInterval_createFromDateString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME_MAPPING(format, date_interval_format, arginfo_class_DateInterval_format, ZEND_ACC_PUBLIC) ZEND_ME(DateInterval, __serialize, arginfo_class_DateInterval___serialize, ZEND_ACC_PUBLIC) ZEND_ME(DateInterval, __unserialize, arginfo_class_DateInterval___unserialize, ZEND_ACC_PUBLIC) @@ -748,6 +751,51 @@ static const zend_function_entry class_DatePeriod_methods[] = { ZEND_FE_END }; + +static const zend_function_entry class_DateError_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateObjectError_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateRangeError_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateInvalidTimeZoneException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateInvalidOperationException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateMalformedStringException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateMalformedIntervalStringException_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_DateMalformedPeriodStringException_methods[] = { + ZEND_FE_END +}; + static void register_php_date_symbols(int module_number) { REGISTER_STRING_CONSTANT("DATE_ATOM", DATE_FORMAT_RFC3339, CONST_PERSISTENT); @@ -1083,3 +1131,102 @@ static zend_class_entry *register_class_DatePeriod(zend_class_entry *class_entry return class_entry; } + +static zend_class_entry *register_class_DateError(zend_class_entry *class_entry_Error) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateError", class_DateError_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Error); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateObjectError(zend_class_entry *class_entry_DateError) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateObjectError", class_DateObjectError_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateError); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateRangeError(zend_class_entry *class_entry_DateRangeError) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateRangeError", class_DateRangeError_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateRangeError); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateException", class_DateException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateInvalidTimeZoneException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateInvalidTimeZoneException", class_DateInvalidTimeZoneException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateInvalidOperationException(zend_class_entry *class_entry_DateException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateInvalidOperationException", class_DateInvalidOperationException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateMalformedStringException(zend_class_entry *class_entry_DateException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateMalformedStringException", class_DateMalformedStringException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateMalformedIntervalStringException(zend_class_entry *class_entry_DateException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateMalformedIntervalStringException", class_DateMalformedIntervalStringException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} + +static zend_class_entry *register_class_DateMalformedPeriodStringException(zend_class_entry *class_entry_DateException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DateMalformedPeriodStringException", class_DateMalformedPeriodStringException_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; + + return class_entry; +} diff --git a/ext/date/tests/68062.phpt b/ext/date/tests/68062.phpt index 66f7692cf4f30..15ec5fa81c1fc 100644 --- a/ext/date/tests/68062.phpt +++ b/ext/date/tests/68062.phpt @@ -10,9 +10,9 @@ echo $tz->getOffset($dt), "\n"; try { echo $tz->getOffset(1); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- 3600 -DateTimeZone::getOffset(): Argument #1 ($datetime) must be of type DateTimeInterface, int given +TypeError: DateTimeZone::getOffset(): Argument #1 ($datetime) must be of type DateTimeInterface, int given diff --git a/ext/date/tests/DateInterval_construct_exceptions.phpt b/ext/date/tests/DateInterval_construct_exceptions.phpt new file mode 100644 index 0000000000000..97df133adf088 --- /dev/null +++ b/ext/date/tests/DateInterval_construct_exceptions.phpt @@ -0,0 +1,21 @@ +--TEST-- +DateInterval constructor exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +check(fn() => new DateInterval("")); +check(fn() => new DateInterval("2007-05-11T15:30:00Z/")); +?> +--EXPECTF-- +DateMalformedIntervalStringException: Unknown or bad format () +DateMalformedIntervalStringException: Failed to parse interval (2007-05-11T15:30:00Z/) diff --git a/ext/date/tests/DateInterval_createFromDateString_broken.phpt b/ext/date/tests/DateInterval_createFromDateString_broken.phpt new file mode 100644 index 0000000000000..5b15fb154e8dc --- /dev/null +++ b/ext/date/tests/DateInterval_createFromDateString_broken.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test DateInterval::createFromDateString() function : nonsense data +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +DateMalformedIntervalStringException: Unknown or bad format (foobar) at position 0 (f): The timezone could not be found in the database diff --git a/ext/date/tests/DateInterval_serialize-003.phpt b/ext/date/tests/DateInterval_serialize-003.phpt index b338a9ae93adb..cc1d9a371bb02 100644 --- a/ext/date/tests/DateInterval_serialize-003.phpt +++ b/ext/date/tests/DateInterval_serialize-003.phpt @@ -32,7 +32,11 @@ var_dump($d); echo "\n\nUsed serialised interval:\n"; $now = new DateTimeImmutable("2022-04-22 16:25:11 BST"); var_dump($now->add($e)); -var_dump($now->sub($e)); +try { + var_dump($now->sub($e)); +} catch (DateInvalidOperationException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} ?> --EXPECTF-- Original object: @@ -84,13 +88,4 @@ object(DateTimeImmutable)#4 (3) { ["timezone"]=> string(3) "BST" } - -Warning: DateTimeImmutable::sub(): Only non-special relative time specifications are supported for subtraction in %s on line %d -object(DateTimeImmutable)#4 (3) { - ["date"]=> - string(26) "2022-04-22 16:25:11.000000" - ["timezone_type"]=> - int(2) - ["timezone"]=> - string(3) "BST" -} +DateInvalidOperationException: DateTimeImmutable::sub(): Only non-special relative time specifications are supported for subtraction diff --git a/ext/date/tests/DateInterval_set_state_exception.phpt b/ext/date/tests/DateInterval_set_state_exception.phpt new file mode 100644 index 0000000000000..3a3c6c980b5d2 --- /dev/null +++ b/ext/date/tests/DateInterval_set_state_exception.phpt @@ -0,0 +1,22 @@ +--TEST-- +DateInterval invalid serialization data with date_string +--FILE-- + $propertySet ] ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +Error: Unknown or bad format (2023-01-16-foobar$*) at position 10 (-) while unserializing: Unexpected character diff --git a/ext/date/tests/DateInterval_uninitialised_exceptions.phpt b/ext/date/tests/DateInterval_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..7a7c296b7742d --- /dev/null +++ b/ext/date/tests/DateInterval_uninitialised_exceptions.phpt @@ -0,0 +1,30 @@ +--TEST-- +DateInterval uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdi = new MyDateInterval(); + +check(fn() => serialize($mdi)); +check(fn() => $mdi->format("Y-m-d")); +?> +--EXPECTF-- +DateObjectError: Object of type MyDateInterval (inheriting DateInterval) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateInterval (inheriting DateInterval) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DatePeriod_by_ref_iterator.phpt b/ext/date/tests/DatePeriod_by_ref_iterator.phpt new file mode 100644 index 0000000000000..07e7fce39b4c8 --- /dev/null +++ b/ext/date/tests/DatePeriod_by_ref_iterator.phpt @@ -0,0 +1,22 @@ +--TEST-- +DatePeriod by-ref iterator +--FILE-- + new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, +]; + +$d = DatePeriod::__set_state( $properties ); +try { + foreach( $d as &$item ) + { + echo $item->format(DateTime::ISO8601), "\n"; + } + echo "OK\n"; +} catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Error: An iterator cannot be used with foreach by reference diff --git a/ext/date/tests/DatePeriod_modify_readonly_property.phpt b/ext/date/tests/DatePeriod_modify_readonly_property.phpt new file mode 100644 index 0000000000000..e57c72339d8fd --- /dev/null +++ b/ext/date/tests/DatePeriod_modify_readonly_property.phpt @@ -0,0 +1,25 @@ +--TEST-- +DatePeriod modify readonly property +--FILE-- +interval = "foo"; +} catch( \Error $e ) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + $foo =& $dp->interval; +} catch( \Error $e ) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +Error: Cannot modify readonly property DatePeriod::$interval +Error: Cannot modify readonly property DatePeriod::$interval diff --git a/ext/date/tests/DatePeriod_properties2.phpt b/ext/date/tests/DatePeriod_properties2.phpt index 376254698f9bb..1da4dcb9c2ff6 100644 --- a/ext/date/tests/DatePeriod_properties2.phpt +++ b/ext/date/tests/DatePeriod_properties2.phpt @@ -20,33 +20,33 @@ foreach ($properties as $property) { try { $period->$property = "new"; } catch (Error $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { $period->$property[] = "extra"; } catch (Error $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } } try { $period->start->modify("+1 hour"); } catch (Error $e) { - echo $e->getMessage() . "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Cannot modify readonly property DatePeriod::$recurrences -Cannot modify readonly property DatePeriod::$recurrences -Cannot modify readonly property DatePeriod::$include_start_date -Cannot modify readonly property DatePeriod::$include_start_date -Cannot modify readonly property DatePeriod::$start -Cannot modify readonly property DatePeriod::$start -Cannot modify readonly property DatePeriod::$current -Cannot modify readonly property DatePeriod::$current -Cannot modify readonly property DatePeriod::$end -Cannot modify readonly property DatePeriod::$end -Cannot modify readonly property DatePeriod::$interval -Cannot modify readonly property DatePeriod::$interval +Error: Cannot modify readonly property DatePeriod::$recurrences +Error: Cannot modify readonly property DatePeriod::$recurrences +Error: Cannot modify readonly property DatePeriod::$include_start_date +Error: Cannot modify readonly property DatePeriod::$include_start_date +Error: Cannot modify readonly property DatePeriod::$start +Error: Cannot modify readonly property DatePeriod::$start +Error: Cannot modify readonly property DatePeriod::$current +Error: Cannot modify readonly property DatePeriod::$current +Error: Cannot modify readonly property DatePeriod::$end +Error: Cannot modify readonly property DatePeriod::$end +Error: Cannot modify readonly property DatePeriod::$interval +Error: Cannot modify readonly property DatePeriod::$interval diff --git a/ext/date/tests/DatePeriod_set_state_exception.phpt b/ext/date/tests/DatePeriod_set_state_exception.phpt new file mode 100644 index 0000000000000..07fd322ba2d7f --- /dev/null +++ b/ext/date/tests/DatePeriod_set_state_exception.phpt @@ -0,0 +1,65 @@ +--TEST-- +DatePeriod invalid serialization data +--FILE-- + new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => null, 'end' => null, 'current' => null, + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => false, 'include_end_date' => false, + ], + /* Error situations */ + [ + 'start' => "2023-01-13 12:29:30", 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => "2023-01-16 16:49:29", 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => "2023-01-15 00:00:00", + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => "tomorrow", 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => -1, 'include_start_date' => true, 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => "true", 'include_end_date' => true, + ], + [ + 'start' => new \DateTimeImmutable("2023-01-13 12:29:30"), 'end' => new \DateTimeImmutable("2023-01-16 16:49:29"), 'current' => new \DateTimeImmutable("2023-01-15 00:00:00"), + 'interval' => DateInterval::createFromDateString("tomorrow"), 'recurrences' => 1, 'include_start_date' => true, 'include_end_date' => "true", + ], +]; + +foreach( $propertySets as $propertySet ) +{ + try { + $d = DatePeriod::__set_state( $propertySet ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +OK +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object diff --git a/ext/date/tests/DatePeriod_uninitialised_exceptions.phpt b/ext/date/tests/DatePeriod_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..753bb0fa68c4a --- /dev/null +++ b/ext/date/tests/DatePeriod_uninitialised_exceptions.phpt @@ -0,0 +1,45 @@ +--TEST-- +DateTime uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdp = new MyDatePeriod(); + +check(fn() => serialize($mdp)); +check(fn() => $mdp->getStartDate()); +check(fn() => $mdp->getDateInterval()); + +check(function() use ($mdp) { + foreach($mdp as $foo) + { + } +}); + +/* Allowed to be empty */ +check(fn() => $mdp->getEndDate()); +check(fn() => $mdp->getRecurrences()); +?> +--EXPECTF-- +DateObjectError: Object of type MyDatePeriod (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDatePeriod (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDatePeriod (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type DatePeriod has not been correctly initialized by calling parent::__construct() in its constructor +NULL +NULL diff --git a/ext/date/tests/DatePeriod_wrong_arguments.phpt b/ext/date/tests/DatePeriod_wrong_arguments.phpt new file mode 100644 index 0000000000000..0f33f5261a648 --- /dev/null +++ b/ext/date/tests/DatePeriod_wrong_arguments.phpt @@ -0,0 +1,25 @@ +--TEST-- +DatePeriod arguments/wrong arguments +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +OK +OK +OK +TypeError: DatePeriod::__construct() accepts (DateTimeInterface, DateInterval, int [, int]), or (DateTimeInterface, DateInterval, DateTime [, int]), or (string [, int]) as arguments diff --git a/ext/date/tests/DateTimeImmutable_createFromInterface_exceptions.phpt b/ext/date/tests/DateTimeImmutable_createFromInterface_exceptions.phpt new file mode 100644 index 0000000000000..e3c2c4d33b735 --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_createFromInterface_exceptions.phpt @@ -0,0 +1,37 @@ +--TEST-- +DateTimeImmutable::createFromInterface exception +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; +} + +$i = new MyDateTimeImmutable(); +try { + $m = DateTimeImmutable::createFromInterface( $i ); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTimeImmutable_createFromMutable-001.phpt b/ext/date/tests/DateTimeImmutable_createFromMutable-001.phpt index 4f542c82c8009..a6ebaa82404b6 100644 --- a/ext/date/tests/DateTimeImmutable_createFromMutable-001.phpt +++ b/ext/date/tests/DateTimeImmutable_createFromMutable-001.phpt @@ -12,7 +12,7 @@ var_dump( $i ); try { DateTimeImmutable::createFromMutable( date_create_immutable( $current ) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -24,4 +24,4 @@ object(DateTimeImmutable)#%d (3) { ["timezone"]=> string(13) "Europe/London" } -DateTimeImmutable::createFromMutable(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given +TypeError: DateTimeImmutable::createFromMutable(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given diff --git a/ext/date/tests/DateTimeImmutable_createFromMutable-002.phpt b/ext/date/tests/DateTimeImmutable_createFromMutable-002.phpt index ccbbe33f1786c..78d87f1e898ce 100644 --- a/ext/date/tests/DateTimeImmutable_createFromMutable-002.phpt +++ b/ext/date/tests/DateTimeImmutable_createFromMutable-002.phpt @@ -14,7 +14,7 @@ var_dump( $i ); try { MyDateTimeImmutable::createFromMutable( date_create_immutable( $current ) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -26,4 +26,4 @@ object(MyDateTimeImmutable)#%d (3) { ["timezone"]=> string(13) "Europe/London" } -DateTimeImmutable::createFromMutable(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given +TypeError: DateTimeImmutable::createFromMutable(): Argument #1 ($object) must be of type DateTime, DateTimeImmutable given diff --git a/ext/date/tests/DateTimeImmutable_createFromMutable_exceptions.phpt b/ext/date/tests/DateTimeImmutable_createFromMutable_exceptions.phpt new file mode 100644 index 0000000000000..2d311ad138eb6 --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_createFromMutable_exceptions.phpt @@ -0,0 +1,23 @@ +--TEST-- +DateTimeImmutable::createFromMutable exception +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTimeImmutable_inherited_serialization.phpt b/ext/date/tests/DateTimeImmutable_inherited_serialization.phpt new file mode 100644 index 0000000000000..a533b651eed67 --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_inherited_serialization.phpt @@ -0,0 +1,23 @@ +--TEST-- +Inherited DateTimeImmutable serialisation with custom properties +--FILE-- +myProperty); +?> +--EXPECTF-- +bool(true) diff --git a/ext/date/tests/DateTimeImmutable_modify_invalid_format.phpt b/ext/date/tests/DateTimeImmutable_modify_invalid_format.phpt index 3386f725acffa..8f4d5891da666 100644 --- a/ext/date/tests/DateTimeImmutable_modify_invalid_format.phpt +++ b/ext/date/tests/DateTimeImmutable_modify_invalid_format.phpt @@ -4,9 +4,12 @@ DateTimeImmutable::modify() with invalid format modify('')); +try { + var_dump($datetime->modify('')); +} catch (DateMalformedStringException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} ?> --EXPECTF-- -Warning: DateTimeImmutable::modify(): Failed to parse time string () at position 0 ( in %s on line %d -bool(false) +DateMalformedStringException: DateTimeImmutable::modify(): Failed to parse time string () at position 0 ( ): Empty string diff --git a/ext/date/tests/DateTimeImmutable_serialisation.phpt b/ext/date/tests/DateTimeImmutable_serialization.phpt similarity index 100% rename from ext/date/tests/DateTimeImmutable_serialisation.phpt rename to ext/date/tests/DateTimeImmutable_serialization.phpt diff --git a/ext/date/tests/DateTimeImmutable_set_state_exception.phpt b/ext/date/tests/DateTimeImmutable_set_state_exception.phpt new file mode 100644 index 0000000000000..6f42c6a81fa2b --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_set_state_exception.phpt @@ -0,0 +1,38 @@ +--TEST-- +DateTimeImmutable invalid serialization data +--FILE-- + "2023-01-13 12:29:30", 'timezone_type' => 1, 'timezone' => "+02:30" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + [ 'date' => 2023.113, 'timezone_type' => 1, 'timezone' => "+02:30" ], + [ 'date' => 2023.113, 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 1.4, 'timezone' => "+02:30" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3.4, 'timezone' => "Europe/Kyiv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 1, 'timezone' => 2.5 ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => 2.5 ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => "Europe/Lviv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 4, 'timezone' => "Europe/Kyiv" ], +]; + +foreach( $propertySets as $propertySet ) +{ + try { + $d = DateTimeImmutable::__set_state( $propertySet ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +OK +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object +Error: Invalid serialization data for DateTimeImmutable object diff --git a/ext/date/tests/DateTimeImmutable_uninitialised_exceptions.phpt b/ext/date/tests/DateTimeImmutable_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..38aed67b42c30 --- /dev/null +++ b/ext/date/tests/DateTimeImmutable_uninitialised_exceptions.phpt @@ -0,0 +1,79 @@ +--TEST-- +DateTime uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdti = new MyDateTimeImmutable(); +$dt = new DateTimeImmutable(); +$di = DateInterval::createFromDateString("tomorrow"); +$dtz = new DateTimeZone("Europe/Kyiv"); + +check(fn() => DateTimeImmutable::createFromInterface($mdti)); +check(fn() => DateTime::createFromImmutable($mdti)); +check(fn() => serialize($mdti)); +check(fn() => date_format($mdti, DateTime::ISO8601)); +check(fn() => $mdti->format(DateTime::ISO8601)); +check(fn() => $mdti->modify("+1 day")); +check(fn() => $mdti->add($di)); +check(fn() => $mdti->sub($di)); +check(fn() => date_timezone_get($mdti)); +check(fn() => $mdti->getTimeZone()); +check(fn() => $mdti->setTimeZone($dtz)); +check(fn() => date_offset_get($mdti)); +check(fn() => $mdti->getOffset()); +check(fn() => $mdti->setTime(17, 59, 53)); +check(fn() => $mdti->setDate(2023, 1, 16)); +check(fn() => $mdti->setISODate(2023, 3, 1)); +check(fn() => $mdti->setTimestamp(time())); +check(fn() => date_timestamp_get($mdti)); +check(fn() => $mdti->getTimestamp()); +check(fn() => date_diff($dt, $mdti)); +check(fn() => date_diff($mdti, $dt)); +check(fn() => date_diff($mdti, $mdti)); +check(fn() => $dt->diff($mdti)); +check(fn() => $mdti->diff($dt)); +check(fn() => $mdti->diff($mdti)); +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeImmutable (inheriting DateTimeImmutable) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTimeInterval_inherited_serialization.phpt b/ext/date/tests/DateTimeInterval_inherited_serialization.phpt new file mode 100644 index 0000000000000..fca8f29b901c9 --- /dev/null +++ b/ext/date/tests/DateTimeInterval_inherited_serialization.phpt @@ -0,0 +1,22 @@ +--TEST-- +Inherited DateTimeInterval serialisation with custom properties +--FILE-- +myProperty); +?> +--EXPECTF-- +bool(true) diff --git a/ext/date/tests/DateTimePeriod_inherited_serialization.phpt b/ext/date/tests/DateTimePeriod_inherited_serialization.phpt new file mode 100644 index 0000000000000..c0d94cf01ef86 --- /dev/null +++ b/ext/date/tests/DateTimePeriod_inherited_serialization.phpt @@ -0,0 +1,25 @@ +--TEST-- +Inherited DateTimePeriod serialisation with custom properties +--FILE-- +myProperty); +?> +--EXPECTF-- +bool(true) diff --git a/ext/date/tests/DateTimeZone_compare.phpt b/ext/date/tests/DateTimeZone_compare.phpt new file mode 100644 index 0000000000000..c187be332cf56 --- /dev/null +++ b/ext/date/tests/DateTimeZone_compare.phpt @@ -0,0 +1,46 @@ +--TEST-- +DateTimeZone compare handler +--FILE-- +getMessage(), "\n"; +} + +try { + var_dump($dtzID < $mdtz); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + var_dump($dtzID < $dtzAbbr); +} catch (\DateException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + var_dump($dtzAbbr < $dtzUTC); +} catch (\DateException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECT-- +DateObjectError: Trying to compare uninitialized DateTimeZone objects +DateObjectError: Trying to compare uninitialized DateTimeZone objects +DateException: Cannot compare two different kinds of DateTimeZone objects +DateException: Cannot compare two different kinds of DateTimeZone objects diff --git a/ext/date/tests/DateTimeZone_compare_basic1.phpt b/ext/date/tests/DateTimeZone_compare_basic1.phpt index 27cd7e8208702..a45485a1a7b75 100644 --- a/ext/date/tests/DateTimeZone_compare_basic1.phpt +++ b/ext/date/tests/DateTimeZone_compare_basic1.phpt @@ -14,7 +14,11 @@ foreach ($timezones as [$timezone1, $timezone2]) { compare_timezones($timezone1, $timezone2); } -var_dump(new DateTimeZone('Europe/Berlin') == new DateTimeZone('CET')); +try { + var_dump(new DateTimeZone('Europe/Berlin') == new DateTimeZone('CET')); +} catch (DateException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} function compare_timezones($timezone1, $timezone2) { @@ -41,7 +45,7 @@ $tz2 = new MyDateTimeZone(); try { var_dump($tz1 == $tz2); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -70,7 +74,5 @@ compare Europe/Amsterdam with Europe/Berlin < bool(false) = bool(false) > bool(false) - -Warning: main(): Trying to compare different kinds of DateTimeZone objects in %s on line %d -bool(false) -Trying to compare uninitialized DateTimeZone objects +DateException: Cannot compare two different kinds of DateTimeZone objects +DateObjectError: Trying to compare uninitialized DateTimeZone objects diff --git a/ext/date/tests/DateTimeZone_construct_error.phpt b/ext/date/tests/DateTimeZone_construct_error.phpt index dd0b1bb70893e..6a48231c8dc96 100644 --- a/ext/date/tests/DateTimeZone_construct_error.phpt +++ b/ext/date/tests/DateTimeZone_construct_error.phpt @@ -1,9 +1,9 @@ --TEST-- -Test new DateTimeZone() : error conditions +Test new DateTimeZone(): Too few arguments --FILE-- getMessage(), "\n"; +} catch (ArgumentCountError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -21,4 +21,4 @@ try { *** Testing DateTimeZone() : error conditions *** -- Testing new DateTimeZone() with more than expected no. of arguments -- -DateTimeZone::__construct() expects exactly 1 argument, 2 given +ArgumentCountError: DateTimeZone::__construct() expects exactly 1 argument, 2 given diff --git a/ext/date/tests/DateTimeZone_inherited_serialization.phpt b/ext/date/tests/DateTimeZone_inherited_serialization.phpt new file mode 100644 index 0000000000000..d70c983bae7f1 --- /dev/null +++ b/ext/date/tests/DateTimeZone_inherited_serialization.phpt @@ -0,0 +1,22 @@ +--TEST-- +Inherited DateTimeZone serialisation with custom properties +--FILE-- +myProperty); +?> +--EXPECTF-- +bool(true) diff --git a/ext/date/tests/DateTimeZone_serialisation.phpt b/ext/date/tests/DateTimeZone_serialization.phpt similarity index 100% rename from ext/date/tests/DateTimeZone_serialisation.phpt rename to ext/date/tests/DateTimeZone_serialization.phpt diff --git a/ext/date/tests/DateTimeZone_serialize_errors.phpt b/ext/date/tests/DateTimeZone_serialize_errors.phpt index f89e3bfafcbf4..866624e5f520d 100644 --- a/ext/date/tests/DateTimeZone_serialize_errors.phpt +++ b/ext/date/tests/DateTimeZone_serialize_errors.phpt @@ -7,9 +7,8 @@ $serialized = 'O:12:"DateTimeZone":2:{s:13:"timezone_type";i:3;s:8:"timezone";s: try { $tz = unserialize($serialized); } catch (Throwable $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> ---EXPECTF-- -Warning: DateTimeZone::__unserialize(): Timezone must not contain null bytes in %s on line %d -Invalid serialization data for DateTimeZone object +--EXPECT-- +Error: Invalid serialization data for DateTimeZone object diff --git a/ext/date/tests/DateTimeZone_set_state_exception.phpt b/ext/date/tests/DateTimeZone_set_state_exception.phpt new file mode 100644 index 0000000000000..68eb50a2fd6bd --- /dev/null +++ b/ext/date/tests/DateTimeZone_set_state_exception.phpt @@ -0,0 +1,38 @@ +--TEST-- +DateTimeZone invalid serialization data +--FILE-- + 1, 'timezone' => "+02:30" ], + [ 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + [ 'timezone_type' => 1.4, 'timezone' => "+02:30" ], + [ 'timezone_type' => 3.4, 'timezone' => "Europe/Kyiv" ], + [ 'timezone_type' => 1, 'timezone' => 2.5 ], + [ 'timezone_type' => 3, 'timezone' => 2.5 ], + [ 'timezone_type' => 3, 'timezone' => "Europe/K\0v" ], + [ 'timezone_type' => 3, 'timezone' => "99:99:99" ], + [ 'timezone_type' => 3, 'timezone' => "Europe/Lviv" ], + [ 'timezone_type' => 4, 'timezone' => "Europe/Kyiv" ], +]; + +foreach( $propertySets as $propertySet ) +{ + try { + $d = DateTimeZone::__set_state( $propertySet ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +OK +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object +Error: Invalid serialization data for DateTimeZone object diff --git a/ext/date/tests/DateTimeZone_uninitialised_exceptions.phpt b/ext/date/tests/DateTimeZone_uninitialised_exceptions.phpt new file mode 100644 index 0000000000000..ce036e306315c --- /dev/null +++ b/ext/date/tests/DateTimeZone_uninitialised_exceptions.phpt @@ -0,0 +1,58 @@ +--TEST-- +DateTime uninitialised exceptions +--INI-- +date.timezone=Europe/London +--FILE-- +getMessage(), "\n"; + } +} + +$mdt = new MyDateTime(); +$mdtz = new MyDateTimeZone(); +$dtz = new DateTimeZone("Europe/Kyiv"); +$dt = new DateTime("2023-01-16 18:18"); + +check(fn() => serialize($mdtz)); +check(fn() => timezone_name_get($mdtz)); +check(fn() => $mdtz->getName()); +check(fn() => timezone_offset_get($mdtz, $dt)); +check(fn() => $mdtz->getOffset($dt)); +check(fn() => timezone_offset_get($dtz, $mdt)); +check(fn() => $dtz->getOffset($mdt)); +check(fn() => timezone_transitions_get($mdtz, time())); +check(fn() => $mdtz->getTransitions(time())); +check(fn() => timezone_location_get($mdtz,)); +check(fn() => $mdtz->getLocation()); +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTime_add-fall-type2-type3.phpt b/ext/date/tests/DateTime_add-fall-type2-type3.phpt index 077dd565d1dba..10e4ed36e7c5e 100644 --- a/ext/date/tests/DateTime_add-fall-type2-type3.phpt +++ b/ext/date/tests/DateTime_add-fall-type2-type3.phpt @@ -2,8 +2,6 @@ DateTime::add() -- fall type2 type3 --CREDITS-- Daniel Convissor ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- getMessage(), "\n"; +} + +try { + var_dump($MDT < $DT); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + var_dump($DTI < $MDT); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + var_dump($MDT < $DTI); +} catch (\DateObjectError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECT-- +bool(false) +DateObjectError: Trying to compare an incomplete DateTime or DateTimeImmutable object +DateObjectError: Trying to compare an incomplete DateTime or DateTimeImmutable object +DateObjectError: Trying to compare an incomplete DateTime or DateTimeImmutable object +DateObjectError: Trying to compare an incomplete DateTime or DateTimeImmutable object diff --git a/ext/date/tests/DateTime_construct_error.phpt b/ext/date/tests/DateTime_construct_error.phpt index 56ab1f3003ff5..e1a99ed7b3ddb 100644 --- a/ext/date/tests/DateTime_construct_error.phpt +++ b/ext/date/tests/DateTime_construct_error.phpt @@ -1,9 +1,9 @@ --TEST-- -Test new DateTime() : error conditions +Test new DateTime(): error conditions --FILE-- getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -22,4 +22,4 @@ try { *** Testing date_create() : error conditions *** -- Testing new DateTime() with more than expected no. of arguments -- -DateTime::__construct() expects at most 2 arguments, 3 given +ArgumentCountError: DateTime::__construct() expects at most 2 arguments, 3 given diff --git a/ext/date/tests/DateTime_createFromImmutable-001.phpt b/ext/date/tests/DateTime_createFromImmutable-001.phpt index 031c8764847a4..e29a5f32341a7 100644 --- a/ext/date/tests/DateTime_createFromImmutable-001.phpt +++ b/ext/date/tests/DateTime_createFromImmutable-001.phpt @@ -17,7 +17,7 @@ var_dump( $i->format('Y-m-d H:i:s') === $current ); try { DateTime::createFromImmutable( date_create( $current ) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -30,4 +30,4 @@ object(DateTime)#%d (3) { string(13) "Europe/London" } bool(true) -DateTime::createFromImmutable(): Argument #1 ($object) must be of type DateTimeImmutable, DateTime given +TypeError: DateTime::createFromImmutable(): Argument #1 ($object) must be of type DateTimeImmutable, DateTime given diff --git a/ext/date/tests/DateTime_createFromImmutable-002.phpt b/ext/date/tests/DateTime_createFromImmutable-002.phpt index 5b8c3a5a7cfe6..778e2a98af447 100644 --- a/ext/date/tests/DateTime_createFromImmutable-002.phpt +++ b/ext/date/tests/DateTime_createFromImmutable-002.phpt @@ -19,7 +19,7 @@ var_dump( $i->format('Y-m-d H:i:s') === $current ); try { MyDateTime::createFromImmutable( date_create( $current ) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- @@ -32,4 +32,4 @@ object(MyDateTime)#%d (3) { string(13) "Europe/London" } bool(true) -DateTime::createFromImmutable(): Argument #1 ($object) must be of type DateTimeImmutable, DateTime given +TypeError: DateTime::createFromImmutable(): Argument #1 ($object) must be of type DateTimeImmutable, DateTime given diff --git a/ext/date/tests/DateTime_diff-fall-type2-type3.phpt b/ext/date/tests/DateTime_diff-fall-type2-type3.phpt index ec790f02ecb31..9024f8998d855 100644 --- a/ext/date/tests/DateTime_diff-fall-type2-type3.phpt +++ b/ext/date/tests/DateTime_diff-fall-type2-type3.phpt @@ -2,8 +2,6 @@ DateTime::diff() -- fall type2 type3 --CREDITS-- Daniel Convissor ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- myProperty); +?> +--EXPECTF-- +bool(true) diff --git a/ext/date/tests/DateTime_modify_invalid_format.phpt b/ext/date/tests/DateTime_modify_invalid_format.phpt new file mode 100644 index 0000000000000..1e1a1721c4bca --- /dev/null +++ b/ext/date/tests/DateTime_modify_invalid_format.phpt @@ -0,0 +1,18 @@ +--TEST-- +DateTime::modify() with empty string as format +--FILE-- +modify('')); +} catch (DateMalformedStringException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +Warning: date_modify(): Failed to parse time string () at position 0 ( ): Empty string in %s +bool(false) +DateMalformedStringException: DateTime::modify(): Failed to parse time string () at position 0 ( ): Empty string diff --git a/ext/date/tests/DateTime_serialisation.phpt b/ext/date/tests/DateTime_serialization.phpt similarity index 100% rename from ext/date/tests/DateTime_serialisation.phpt rename to ext/date/tests/DateTime_serialization.phpt diff --git a/ext/date/tests/DateTime_set_state_exception.phpt b/ext/date/tests/DateTime_set_state_exception.phpt new file mode 100644 index 0000000000000..8b16ec7011b62 --- /dev/null +++ b/ext/date/tests/DateTime_set_state_exception.phpt @@ -0,0 +1,40 @@ +--TEST-- +DateTime invalid serialization data +--FILE-- + "2023-01-13 12:29:30", 'timezone_type' => 1, 'timezone' => "+02:30" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + /* Error situations */ + [ 'date' => 2023.113, 'timezone_type' => 1, 'timezone' => "+02:30" ], + [ 'date' => 2023.113, 'timezone_type' => 3, 'timezone' => "Europe/Kyiv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 1.4, 'timezone' => "+02:30" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3.4, 'timezone' => "Europe/Kyiv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 1, 'timezone' => 2.5 ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => 2.5 ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 3, 'timezone' => "Europe/Lviv" ], + [ 'date' => "2023-01-13 12:29:30", 'timezone_type' => 4, 'timezone' => "Europe/Kyiv" ], +]; + +foreach( $propertySets as $propertySet ) +{ + try { + $d = DateTime::__set_state( $propertySet ); + echo "OK\n"; + } catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +OK +OK +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object diff --git a/ext/date/tests/DateTime_sub-fall-type2-type3.phpt b/ext/date/tests/DateTime_sub-fall-type2-type3.phpt index 6c2a9e03da8d4..86ff27552524a 100644 --- a/ext/date/tests/DateTime_sub-fall-type2-type3.phpt +++ b/ext/date/tests/DateTime_sub-fall-type2-type3.phpt @@ -2,8 +2,6 @@ DateTime::sub() -- fall type2 type3 --CREDITS-- Daniel Convissor ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- ---XFAIL-- -Various bugs exist --FILE-- getMessage(), "\n"; + } +} + +$mdt = new MyDateTime(); +$dt = new DateTime(); +$di = DateInterval::createFromDateString("tomorrow"); +$dtz = new DateTimeZone("Europe/Kyiv"); + +check(fn() => DateTime::createFromInterface($mdt)); +check(fn() => DateTimeImmutable::createFromMutable($mdt)); +check(fn() => serialize($mdt)); +check(fn() => date_format($mdt, DateTime::ISO8601)); +check(fn() => $mdt->format(DateTime::ISO8601)); +check(fn() => date_modify($mdt, "+1 day")); +check(fn() => $mdt->modify("+1 day")); +check(fn() => $mdt->add($di)); +check(fn() => $mdt->sub($di)); +check(fn() => date_timezone_get($mdt)); +check(fn() => $mdt->getTimeZone()); +check(fn() => date_timezone_set($mdt, $dtz)); +check(fn() => $mdt->setTimeZone($dtz)); +check(fn() => date_offset_get($mdt)); +check(fn() => $mdt->getOffset()); +check(fn() => date_time_set($mdt, 17, 59, 53)); +check(fn() => $mdt->setTime(17, 59, 53)); +check(fn() => date_date_set($mdt, 2023, 1, 16)); +check(fn() => $mdt->setDate(2023, 1, 16)); +check(fn() => date_isodate_set($mdt, 2023, 3, 1)); +check(fn() => $mdt->setISODate(2023, 3, 1)); +check(fn() => date_timestamp_set($mdt, time())); +check(fn() => $mdt->setTimestamp(time())); +check(fn() => date_timestamp_get($mdt)); +check(fn() => $mdt->getTimestamp()); +check(fn() => date_diff($dt, $mdt)); +check(fn() => date_diff($mdt, $dt)); +check(fn() => date_diff($mdt, $mdt)); +check(fn() => $dt->diff($mdt)); +check(fn() => $mdt->diff($dt)); +check(fn() => $mdt->diff($mdt)); +?> +--EXPECTF-- +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/DateTime_wakeup_exception.phpt b/ext/date/tests/DateTime_wakeup_exception.phpt new file mode 100644 index 0000000000000..dd51e52a9b1e3 --- /dev/null +++ b/ext/date/tests/DateTime_wakeup_exception.phpt @@ -0,0 +1,34 @@ +--TEST-- +DateTime invalid serialization data (wakeup) +--FILE-- +getMessage(), "\n"; + } +} +?> +--EXPECTF-- +OK? object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +Error: Invalid serialization data for DateTime object +OK? object + +Warning: unserialize(): Error at offset 109 of 122 bytes in %sDateTime_wakeup_exception.php on line 15 +OK? boolean diff --git a/ext/date/tests/bug-gh8471.phpt b/ext/date/tests/bug-gh8471.phpt index 6857551008e08..2f6656849f6c8 100644 --- a/ext/date/tests/bug-gh8471.phpt +++ b/ext/date/tests/bug-gh8471.phpt @@ -44,7 +44,7 @@ try { ?> --EXPECTF-- -The DateTime object has not been correctly initialized by its constructor -The DateTimeInterface object has not been correctly initialized by its constructor -The DateTimeImmutable object has not been correctly initialized by its constructor -The DateTimeInterface object has not been correctly initialized by its constructor +Object of type DateTime has not been correctly initialized by calling parent::__construct() in its constructor +Object of type DateTime has not been correctly initialized by calling parent::__construct() in its constructor +Object of type DateTimeImmutable has not been correctly initialized by calling parent::__construct() in its constructor +Object of type DateTimeImmutable has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/bug-gh9763.phpt b/ext/date/tests/bug-gh9763.phpt index dd7b0fb0e48e4..7166c7d27e823 100644 --- a/ext/date/tests/bug-gh9763.phpt +++ b/ext/date/tests/bug-gh9763.phpt @@ -11,18 +11,18 @@ foreach ( [ '+99:60', '+99:62', '-99:62', '-99:60', '+9960', '-9960', '+9959', ' $d = new DateTimeZone($test); echo $d->getName(), "\n"; } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } } ?> --EXPECT-- -Testing +99:60: DateTimeZone::__construct(): Timezone offset is out of range (+99:60) -Testing +99:62: DateTimeZone::__construct(): Timezone offset is out of range (+99:62) -Testing -99:62: DateTimeZone::__construct(): Timezone offset is out of range (-99:62) -Testing -99:60: DateTimeZone::__construct(): Timezone offset is out of range (-99:60) -Testing +9960: DateTimeZone::__construct(): Timezone offset is out of range (+9960) -Testing -9960: DateTimeZone::__construct(): Timezone offset is out of range (-9960) +Testing +99:60: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (+99:60) +Testing +99:62: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (+99:62) +Testing -99:62: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (-99:62) +Testing -99:60: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (-99:60) +Testing +9960: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (+9960) +Testing -9960: DateInvalidTimeZoneException: DateTimeZone::__construct(): Timezone offset is out of range (-9960) Testing +9959: +99:59 Testing -9959: -99:59 diff --git a/ext/date/tests/bug36988.phpt b/ext/date/tests/bug36988.phpt index 32359808517b1..4898ef68d0388 100644 --- a/ext/date/tests/bug36988.phpt +++ b/ext/date/tests/bug36988.phpt @@ -9,8 +9,8 @@ $start = microtime(true); try { $a = mktime(1, 1, 1, 1, 1, 11111111111); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -mktime(): Argument #6 ($year) must be of type ?int, float given +TypeError: mktime(): Argument #6 ($year) must be of type ?int, float given diff --git a/ext/date/tests/bug44562.phpt b/ext/date/tests/bug44562.phpt index 0448e95ec341a..2517207b367a4 100644 --- a/ext/date/tests/bug44562.phpt +++ b/ext/date/tests/bug44562.phpt @@ -7,7 +7,7 @@ date_default_timezone_set('Europe/Oslo'); try { $dp = new DatePeriod('2D'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $begin = new DateTime( "2008-07-20T22:44:53+0200" ); @@ -21,7 +21,7 @@ foreach ( $dp as $d ) ?> --EXPECT-- -Unknown or bad format (2D) +DateMalformedPeriodStringException: Unknown or bad format (2D) string(24) "2008-07-20T22:44:53+0200" string(24) "2008-07-21T22:44:53+0200" string(24) "2008-07-22T22:44:53+0200" diff --git a/ext/date/tests/bug45866.phpt b/ext/date/tests/bug45866.phpt index f4b09b6daf7c9..0e062ffc397c6 100644 --- a/ext/date/tests/bug45866.phpt +++ b/ext/date/tests/bug45866.phpt @@ -13,12 +13,15 @@ $date->modify( "61538461538 day" ); echo $date->format( 'r' ), "\n"; $date = new DateTime( '2009-07-29 16:44:23 Europe/London' ); -$date->modify( "£61538461538 day" ); +try { + $date->modify( "£61538461538 day" ); +} catch (DateMalformedStringException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} echo $date->format( 'r' ), "\n"; ?> --EXPECTF-- Thu, 14 Aug 168488594 16:44:23 +0100 Thu, 14 Aug 168488594 16:44:23 +0100 - -Warning: DateTime::modify(): Failed to parse time string (£61538461538 day) at position 0 (%s): Unexpected character in %sbug45866.php on line 11 +DateMalformedStringException: DateTime::modify(): Failed to parse time string (£61538461538 day) at position 0 (%s): Unexpected character Wed, 29 Jul 2009 16:44:23 +0100 diff --git a/ext/date/tests/bug48476.phpt b/ext/date/tests/bug48476.phpt index 139c2e17e2bac..4b219e541e856 100644 --- a/ext/date/tests/bug48476.phpt +++ b/ext/date/tests/bug48476.phpt @@ -13,14 +13,14 @@ $o = new MyDateTime; try { var_dump($o->format("d")); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $x = clone $o; try { var_dump($x->format("d")); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } clone $o; @@ -28,10 +28,10 @@ clone $o; try { var_dump(timezone_location_get(clone new MyDateTimezone)); } catch (Error $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -The DateTime object has not been correctly initialized by its constructor -The DateTime object has not been correctly initialized by its constructor -The DateTimeZone object has not been correctly initialized by its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTime (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type MyDateTimeZone (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor diff --git a/ext/date/tests/bug50055.phpt b/ext/date/tests/bug50055-001.phpt similarity index 88% rename from ext/date/tests/bug50055.phpt rename to ext/date/tests/bug50055-001.phpt index 907bb93e44d26..9bff3405f52be 100644 --- a/ext/date/tests/bug50055.phpt +++ b/ext/date/tests/bug50055-001.phpt @@ -23,8 +23,8 @@ date_sub($ds2, $i); 2010-03-07T13:21:38+0000 2010-04-20T13:21:38+0000 -Warning: date_sub(): Only non-special relative time specifications are supported for subtraction in %sbug50055.php on line 9 +Warning: date_sub(): Only non-special relative time specifications are supported for subtraction in %s 2010-03-07T13:21:38+0000 2010-02-16T13:21:38+0000 -Warning: date_sub(): Only non-special relative time specifications are supported for subtraction in %sbug50055.php on line 17 +Warning: date_sub(): Only non-special relative time specifications are supported for subtraction in %s diff --git a/ext/date/tests/bug50055-002.phpt b/ext/date/tests/bug50055-002.phpt new file mode 100644 index 0000000000000..5e334666f8415 --- /dev/null +++ b/ext/date/tests/bug50055-002.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #50555 (DateTime::sub() allows 'relative' time modifications) (OO). +--FILE-- +format( DateTime::ISO8601 ), "\n"; +echo date_add($da1, $i)->format( DateTime::ISO8601 ), "\n"; +try { + $ds1->sub($i); +} catch (DateInvalidOperationException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +//negative DateInterval +$da2 = date_create( $now ); +$ds2 = date_create( $now ); +$i2 = DateInterval::createFromDateString('third Tuesday of last month'); +echo $da2->format( DateTime::ISO8601 ), "\n"; +echo date_add($da2, $i2)->format( DateTime::ISO8601 ), "\n";//works +try { + $ds2->sub($i); +} catch (DateInvalidOperationException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +2010-03-07T13:21:38+0000 +2010-04-20T13:21:38+0000 +DateInvalidOperationException: DateTime::sub(): Only non-special relative time specifications are supported for subtraction +2010-03-07T13:21:38+0000 +2010-02-16T13:21:38+0000 +DateInvalidOperationException: DateTime::sub(): Only non-special relative time specifications are supported for subtraction diff --git a/ext/date/tests/bug52062.phpt b/ext/date/tests/bug52062.phpt index f967773b1cc3c..e83063fe97666 100644 --- a/ext/date/tests/bug52062.phpt +++ b/ext/date/tests/bug52062.phpt @@ -12,21 +12,21 @@ $d = new DateTime('@100000000000'); var_dump($d->format('Y-m-d H:i:s U')); try { var_dump($d->getTimestamp()); -} catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; +} catch (\DateRangeError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } var_dump($d->format('U')); try { $d->setTimestamp(100000000000); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } var_dump($d->format('Y-m-d H:i:s U')); try { var_dump($d->getTimestamp()); -} catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; +} catch (\DateRangeError $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } $i = new DateInterval('PT100000000000S'); @@ -34,9 +34,9 @@ var_dump($i->format('%s')); ?> --EXPECT-- string(32) "5138-11-16 09:46:40 100000000000" -Epoch doesn't fit in a PHP integer +DateRangeError: Epoch doesn't fit in a PHP integer string(12) "100000000000" -DateTime::setTimestamp(): Argument #1 ($timestamp) must be of type int, float given +TypeError: DateTime::setTimestamp(): Argument #1 ($timestamp) must be of type int, float given string(32) "5138-11-16 09:46:40 100000000000" -Epoch doesn't fit in a PHP integer +DateRangeError: Epoch doesn't fit in a PHP integer string(10) "1215752192" diff --git a/ext/date/tests/bug52808.phpt b/ext/date/tests/bug52808.phpt index a059624fdd7a0..45568c754458d 100644 --- a/ext/date/tests/bug52808.phpt +++ b/ext/date/tests/bug52808.phpt @@ -4,9 +4,11 @@ Bug #52808 (Segfault when specifying interval as two dates) getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } } echo "==DONE==\n"; @@ -91,7 +93,7 @@ object(DateInterval)#%d (%d) { ["from_string"]=> bool(false) } -Failed to parse interval (2007-05-11T15:30:00Z/) -Failed to parse interval (2007-05-11T15:30:00Z) -Unknown or bad format (2007-05-11T15:30:00Z/:00Z) +DateMalformedIntervalStringException: Failed to parse interval (2007-05-11T15:30:00Z/) +DateMalformedIntervalStringException: Failed to parse interval (2007-05-11T15:30:00Z) +DateMalformedIntervalStringException: Unknown or bad format (2007-05-11T15:30:00Z/:00Z) ==DONE== diff --git a/ext/date/tests/bug53437_var3.phpt b/ext/date/tests/bug53437_var3.phpt index 6fd5f11f0301b..c87c5c8b9a0cd 100644 --- a/ext/date/tests/bug53437_var3.phpt +++ b/ext/date/tests/bug53437_var3.phpt @@ -4,7 +4,7 @@ Bug #53437 DateInterval unserialize bad data, 32 bit --FILE-- --FILE-- --FILE-- --EXPECTF-- -Fatal error: Uncaught Error: The DateTime object has not been correctly initialized by its constructor in %s:%d +Fatal error: Uncaught DateObjectError: Object of type mydt (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor in %s:%d Stack trace: #0 %s(%d): DateTime->format('Y') #1 %s(%d): mydt->__construct(%s) diff --git a/ext/date/tests/bug70245.phpt b/ext/date/tests/bug70245.phpt index cdc9d4e37a7c6..90a4447cde3d3 100644 --- a/ext/date/tests/bug70245.phpt +++ b/ext/date/tests/bug70245.phpt @@ -6,8 +6,8 @@ $d = new DateTime('2011-01-15 00:00:00'); try { var_dump(strtotime('-1 month', $d)); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -strtotime(): Argument #2 ($baseTimestamp) must be of type ?int, DateTime given +TypeError: strtotime(): Argument #2 ($baseTimestamp) must be of type ?int, DateTime given diff --git a/ext/date/tests/bug70277.phpt b/ext/date/tests/bug70277.phpt index 49df2be410379..784f042a396d3 100644 --- a/ext/date/tests/bug70277.phpt +++ b/ext/date/tests/bug70277.phpt @@ -6,14 +6,14 @@ $timezone = "Europe/Zurich\0Foo"; try { var_dump(timezone_open($timezone)); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { var_dump(new DateTimeZone($timezone)); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -timezone_open(): Argument #1 ($timezone) must not contain any null bytes -DateTimeZone::__construct(): Argument #1 ($timezone) must not contain any null bytes +ValueError: timezone_open(): Argument #1 ($timezone) must not contain any null bytes +ValueError: DateTimeZone::__construct(): Argument #1 ($timezone) must not contain any null bytes diff --git a/ext/date/tests/bug73239.phpt b/ext/date/tests/bug73239.phpt index ce86e43c2c020..a05fcf817cea0 100644 --- a/ext/date/tests/bug73239.phpt +++ b/ext/date/tests/bug73239.phpt @@ -8,7 +8,7 @@ ini_set('date.timezone', 'dummy'); try { $dt = new DateTime('now'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECTF-- diff --git a/ext/date/tests/bug75002.phpt b/ext/date/tests/bug75002.phpt index 5c3085f316aee..2f4688eb35efe 100644 --- a/ext/date/tests/bug75002.phpt +++ b/ext/date/tests/bug75002.phpt @@ -16,7 +16,7 @@ foreach (new aaa($start) as $y) { ?> ==DONE== --EXPECTF-- -Fatal error: Uncaught Error: DatePeriod has not been initialized correctly in %sbug75002.php:%d +Fatal error: Uncaught DateObjectError: Object of type DatePeriod has not been correctly initialized by calling parent::__construct() in its constructor in %sbug75002.php:%d Stack trace: #0 {main} thrown in %sbug75002.php on line %d diff --git a/ext/date/tests/bug78139.phpt b/ext/date/tests/bug78139.phpt index 0ecf404274b03..47e5536cbaad6 100644 --- a/ext/date/tests/bug78139.phpt +++ b/ext/date/tests/bug78139.phpt @@ -20,8 +20,8 @@ foreach ($strings as $string) try { $tz = new \DateTimeZone($string); - } catch (Exception $e) { - echo $e->getMessage(), "\n"; + } catch (DateInvalidTimeZoneException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } echo "\n\n"; @@ -41,33 +41,33 @@ Parsing 'x UTC': Warning: timezone_open(): Unknown or bad timezone (x UTC) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (x UTC) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (x UTC) Parsing 'xx UTC': Warning: timezone_open(): Unknown or bad timezone (xx UTC) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (xx UTC) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (xx UTC) Parsing 'xUTC': Warning: timezone_open(): Unknown or bad timezone (xUTC) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (xUTC) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (xUTC) Parsing 'UTCx': Warning: timezone_open(): Unknown or bad timezone (UTCx) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (UTCx) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (UTCx) Parsing 'UTC xx': Warning: timezone_open(): Unknown or bad timezone (UTC xx) in %sbug78139.php on line %d bool(false) -DateTimeZone::__construct(): Unknown or bad timezone (UTC xx) +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (UTC xx) diff --git a/ext/date/tests/bug79015.phpt b/ext/date/tests/bug79015.phpt index 63dac799c5403..99cb03f75d5cb 100644 --- a/ext/date/tests/bug79015.phpt +++ b/ext/date/tests/bug79015.phpt @@ -2,7 +2,7 @@ Bug #79015 (undefined-behavior in php_date.c) --FILE-- --EXPECTF-- diff --git a/ext/date/tests/date_interval_bad_format_leak.phpt b/ext/date/tests/date_interval_bad_format_leak.phpt index 15e6eb9c64a91..c2e1b89fa0346 100644 --- a/ext/date/tests/date_interval_bad_format_leak.phpt +++ b/ext/date/tests/date_interval_bad_format_leak.phpt @@ -6,23 +6,23 @@ DateInterval with bad format should not leak period try { new DateInterval('P3"D'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DatePeriod('P3"D'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DatePeriod('2008-03-01T12:00:00Z1'); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Unknown or bad format (P3"D) -Unknown or bad format (P3"D) -Unknown or bad format (2008-03-01T12:00:00Z1) +DateMalformedIntervalStringException: Unknown or bad format (P3"D) +DateMalformedPeriodStringException: Unknown or bad format (P3"D) +DateMalformedPeriodStringException: Unknown or bad format (2008-03-01T12:00:00Z1) diff --git a/ext/date/tests/date_interval_create_from_date_string_broken.phpt b/ext/date/tests/date_interval_create_from_date_string_broken.phpt index c065de0f8c1ce..e3954b4895f5a 100644 --- a/ext/date/tests/date_interval_create_from_date_string_broken.phpt +++ b/ext/date/tests/date_interval_create_from_date_string_broken.phpt @@ -6,5 +6,5 @@ $i = date_interval_create_from_date_string("foobar"); var_dump($i); ?> --EXPECTF-- -Warning: date_interval_create_from_date_string(): Unknown or bad format (foobar) at position 0 (f): The timezone could not be found in the database in %sdate_interval_create_from_date_string_broken.php on line 2 +Warning: date_interval_create_from_date_string(): Unknown or bad format (foobar) at position 0 (f): The timezone could not be found in the database in %s bool(false) diff --git a/ext/date/tests/date_interval_create_from_date_string_nullparam.phpt b/ext/date/tests/date_interval_create_from_date_string_nullparam.phpt index afac12b7a33a4..1a4a17d786cfe 100644 --- a/ext/date/tests/date_interval_create_from_date_string_nullparam.phpt +++ b/ext/date/tests/date_interval_create_from_date_string_nullparam.phpt @@ -10,5 +10,5 @@ var_dump($i); --EXPECTF-- Deprecated: date_interval_create_from_date_string(): Passing null to parameter #1 ($datetime) of type string is deprecated in %s on line %d -Warning: date_interval_create_from_date_string(): Unknown or bad format () at position 0 ( ): Empty string in %sdate_interval_create_from_date_string_nullparam.php on line 2 +Warning: date_interval_create_from_date_string(): Unknown or bad format () at position 0 ( ): Empty string in %s bool(false) diff --git a/ext/date/tests/date_interval_non_relative_warning.phpt b/ext/date/tests/date_interval_non_relative_warning.phpt index fc0b246277940..9830c067e29ba 100644 --- a/ext/date/tests/date_interval_non_relative_warning.phpt +++ b/ext/date/tests/date_interval_non_relative_warning.phpt @@ -10,27 +10,31 @@ $formats = [ ]; foreach ($formats as $format) { - $d = DateInterval::createFromDateString($format); + try { + $d = DateInterval::createFromDateString($format); + } catch (DateMalformedIntervalStringException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } } +echo "====\n"; + foreach ($formats as $format) { $d = date_interval_create_from_date_string($format); } ?> --EXPECTF-- -Warning: DateInterval::createFromDateString(): String 'next weekday 15:30' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d - -Warning: DateInterval::createFromDateString(): String '+5 hours noon' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d - -Warning: DateInterval::createFromDateString(): String '-8 days March 23' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d - -Warning: DateInterval::createFromDateString(): String '+72 seconds UTC' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +DateMalformedIntervalStringException: String 'next weekday 15:30' contains non-relative elements +DateMalformedIntervalStringException: String '+5 hours noon' contains non-relative elements +DateMalformedIntervalStringException: String '-8 days March 23' contains non-relative elements +DateMalformedIntervalStringException: String '+72 seconds UTC' contains non-relative elements +==== -Warning: date_interval_create_from_date_string(): String 'next weekday 15:30' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +Warning: date_interval_create_from_date_string(): String 'next weekday 15:30' contains non-relative elements in %s on line %d -Warning: date_interval_create_from_date_string(): String '+5 hours noon' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +Warning: date_interval_create_from_date_string(): String '+5 hours noon' contains non-relative elements in %s on line %d -Warning: date_interval_create_from_date_string(): String '-8 days March 23' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +Warning: date_interval_create_from_date_string(): String '-8 days March 23' contains non-relative elements in %s on line %d -Warning: date_interval_create_from_date_string(): String '+72 seconds UTC' contains non-relative elements in %sdate_interval_non_relative_warning.php on line %d +Warning: date_interval_create_from_date_string(): String '+72 seconds UTC' contains non-relative elements in %s on line %d diff --git a/ext/date/tests/date_period_bad_iso_format.phpt b/ext/date/tests/date_period_bad_iso_format.phpt index fecc4fa23ceab..e0e8efdc2a29f 100644 --- a/ext/date/tests/date_period_bad_iso_format.phpt +++ b/ext/date/tests/date_period_bad_iso_format.phpt @@ -6,24 +6,24 @@ Test bad ISO date formats passed to DatePeriod constructor try { new DatePeriod("R4"); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DatePeriod("R4/2012-07-01T00:00:00Z"); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DatePeriod("2012-07-01T00:00:00Z/P7D"); } catch (Exception $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -DatePeriod::__construct(): ISO interval must contain a start date, "R4" given -DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given -DatePeriod::__construct(): ISO interval must contain an end date or a recurrence count, "2012-07-01T00:00:00Z/P7D" given +DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain a start date, "R4" given +DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given +DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an end date or a recurrence count, "2012-07-01T00:00:00Z/P7D" given diff --git a/ext/date/tests/date_period_set_state2.phpt b/ext/date/tests/date_period_set_state2.phpt index 7d77a632dc7e2..61d0133a66363 100644 --- a/ext/date/tests/date_period_set_state2.phpt +++ b/ext/date/tests/date_period_set_state2.phpt @@ -9,10 +9,10 @@ try { "start" => new DateTime, ] ); -} catch (\Error $exception) { - echo $exception->getMessage() . "\n"; +} catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object diff --git a/ext/date/tests/date_period_unserialize2.phpt b/ext/date/tests/date_period_unserialize2.phpt index c368155dbe83e..5ea2466da8e97 100644 --- a/ext/date/tests/date_period_unserialize2.phpt +++ b/ext/date/tests/date_period_unserialize2.phpt @@ -14,10 +14,10 @@ try { "start" => new DateTime, ] ); -} catch (\Error $exception) { - echo $exception->getMessage() . "\n"; +} catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object diff --git a/ext/date/tests/date_period_unserialize3.phpt b/ext/date/tests/date_period_unserialize3.phpt index 4213320e30ae2..d5d4a57456d9a 100644 --- a/ext/date/tests/date_period_unserialize3.phpt +++ b/ext/date/tests/date_period_unserialize3.phpt @@ -20,15 +20,15 @@ try { "include_end_date" => true, ] ); -} catch (\Error $exception) { - echo $exception->getMessage() . "\n"; +} catch (\Error $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } var_dump($period); ?> --EXPECTF-- -Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object object(DatePeriod)#%d (%d) { ["start"]=> object(DateTime)#%d (%d) { diff --git a/ext/date/tests/examine_diff.inc b/ext/date/tests/examine_diff.inc index 8c305f1d36ee5..bb8d25652c01f 100644 --- a/ext/date/tests/examine_diff.inc +++ b/ext/date/tests/examine_diff.inc @@ -68,7 +68,6 @@ function examine_diff($end_date, $start_date, $expect_spec, $expect_days, $absol $start->add($expect_interval); $result_end_date = $start->format('Y-m-d H:i:s T'); echo "ADD: $start_date + $expect_spec = **$result_end_date**\n"; - // echo "ADD: $start_date + $expect_spec = **$end_date**\n"; } if (PHPT_DATETIME_SHOW == PHPT_DATETIME_SHOW_SUB) { $end->sub($expect_interval); diff --git a/ext/date/tests/gh10152.phpt b/ext/date/tests/gh10152.phpt new file mode 100644 index 0000000000000..8b5ec9529e2e0 --- /dev/null +++ b/ext/date/tests/gh10152.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug GH-10152 (Custom properties of DateTimeImmutable child classes are not serialized) +--FILE-- +myProperty); +?> +--EXPECT-- +bool(true) diff --git a/ext/date/tests/gh10218.phpt b/ext/date/tests/gh10218.phpt new file mode 100644 index 0000000000000..ff1b493ce7f01 --- /dev/null +++ b/ext/date/tests/gh10218.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug GH-10218 (DateTimeZone fails to parse time zones that contain the "+" character) +--FILE-- + +--EXPECTF-- +object(DateTime)#%d (%d) { + ["date"]=> + string(%d) "%s" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(9) "Etc/GMT+1" +} diff --git a/ext/date/tests/gh10447.phpt b/ext/date/tests/gh10447.phpt new file mode 100644 index 0000000000000..3b7ff54c97fb5 --- /dev/null +++ b/ext/date/tests/gh10447.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug GH-10447 ('p' format specifier does not yield 'Z' for 00:00) +--FILE-- +format('Y-m-d\TH:i:sp'), "\n"; + +$date = new \DateTimeImmutable('2023-01-25T00:00:00-00:00'); +echo $date->format('Y-m-d\TH:i:sp'), "\n"; +?> +--EXPECT-- +2023-01-25T00:00:00Z +2023-01-25T00:00:00Z diff --git a/ext/date/tests/gh10583.phpt b/ext/date/tests/gh10583.phpt new file mode 100644 index 0000000000000..a63df36069d5c --- /dev/null +++ b/ext/date/tests/gh10583.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug GH-10583 (DateTime modify with tz pattern should not update linked timezone) +--FILE-- +format('c')); +var_dump($dt->modify('+1 s')->format('c')); + +$dt = new DateTimeImmutable('2015-01-01 00:00:00+00:00'); +var_dump($dt->format('c')); +var_dump($dt->modify('+1 s')->format('c')); +?> +--EXPECT-- +string(25) "2015-01-01T00:00:00+00:00" +string(25) "2015-01-01T00:00:00+00:00" +string(25) "2015-01-01T00:00:00+00:00" +string(25) "2015-01-01T00:00:00+00:00" diff --git a/ext/date/tests/gh10747-1.phpt b/ext/date/tests/gh10747-1.phpt new file mode 100644 index 0000000000000..6976422cdf206 --- /dev/null +++ b/ext/date/tests/gh10747-1.phpt @@ -0,0 +1,61 @@ +--TEST-- +Bug GH-10747 (Private fields in serialized DateTimeImmutable objects throw) +--INI-- +date.timezone=UTC +--FILE-- +var2 = 2; + $this->var4 = 4; + } +} + +$i = new I; +$s = serialize($i); +$u = unserialize($s); + +var_dump($i, str_replace(chr(0), '!', $s), $u); +?> +--EXPECTF-- +object(I)#1 (7) { + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) + ["date"]=> + string(%d) "%s" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" +} +string(%d) "O:1:"I":7:{s:4:"date";s:%d:"%s";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";s:7:"!I!var1";i:1;s:7:"!I!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}" +object(I)#2 (7) { + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) + ["date"]=> + string(%d) "%s" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" +} diff --git a/ext/date/tests/gh10747-2.phpt b/ext/date/tests/gh10747-2.phpt new file mode 100644 index 0000000000000..ba5e02731e0b6 --- /dev/null +++ b/ext/date/tests/gh10747-2.phpt @@ -0,0 +1,55 @@ +--TEST-- +Bug GH-10747 (Private fields in serialized DateTimeZone objects throw) +--FILE-- +var1 = 1; + $this->var4 = 4; + } +} + +$i = new I('Europe/Kyiv'); +$s = serialize($i); +$u = unserialize($s); + +var_dump($i, str_replace(chr(0), '!', $s), $u); +?> +--EXPECTF-- +object(I)#1 (6) { + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(11) "Europe/Kyiv" +} +string(143) "O:1:"I":6:{s:13:"timezone_type";i:3;s:8:"timezone";s:11:"Europe/Kyiv";s:7:"!I!var1";i:1;s:7:"!I!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}" +object(I)#2 (6) { + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(11) "Europe/Kyiv" +} diff --git a/ext/date/tests/gh10747-3.phpt b/ext/date/tests/gh10747-3.phpt new file mode 100644 index 0000000000000..ea37c26eb2494 --- /dev/null +++ b/ext/date/tests/gh10747-3.phpt @@ -0,0 +1,87 @@ +--TEST-- +Bug GH-10747 (Private fields in serialized DateInterval objects throw) +--FILE-- +var1 = 1; + $this->var4 = 4; + } +} + +$i = new I('P3D'); +$s = serialize($i); +$u = unserialize($s); + +var_dump($i, str_replace(chr(0), '!', $s), $u); +?> +--EXPECTF-- +object(I)#1 (14) { + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) + ["y"]=> + int(0) + ["m"]=> + int(0) + ["d"]=> + int(3) + ["h"]=> + int(0) + ["i"]=> + int(0) + ["s"]=> + int(0) + ["f"]=> + float(0) + ["invert"]=> + int(0) + ["days"]=> + bool(false) + ["from_string"]=> + bool(false) +} +string(224) "O:1:"I":14:{s:1:"y";i:0;s:1:"m";i:0;s:1:"d";i:3;s:1:"h";i:0;s:1:"i";i:0;s:1:"s";i:0;s:1:"f";d:0;s:6:"invert";i:0;s:4:"days";b:0;s:11:"from_string";b:0;s:7:"!I!var1";i:1;s:7:"!I!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}" +object(I)#2 (14) { + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) + ["y"]=> + int(0) + ["m"]=> + int(0) + ["d"]=> + int(3) + ["h"]=> + int(0) + ["i"]=> + int(0) + ["s"]=> + int(0) + ["f"]=> + float(0) + ["invert"]=> + int(0) + ["days"]=> + bool(false) + ["from_string"]=> + bool(false) +} diff --git a/ext/date/tests/gh10747-4.phpt b/ext/date/tests/gh10747-4.phpt new file mode 100644 index 0000000000000..9933902a498d8 --- /dev/null +++ b/ext/date/tests/gh10747-4.phpt @@ -0,0 +1,147 @@ +--TEST-- +Bug GH-10747 (Private fields in serialized DatePeriod objects throw) +--INI-- +date.timezone=UTC +--FILE-- +var1 = 1; + $this->var4 = 4; + } +} + +$i = new I(new DateTimeImmutable('2023-03-03 16:24'), DateInterval::createFromDateString('+1 hour'), new DateTimeImmutable('2023-03-09 16:24')); +$s = serialize($i); +$u = unserialize($s); + +var_dump($i, str_replace(chr(0), '!', $s), $u); +?> +--EXPECTF-- +object(I)#1 (11) { + ["start"]=> + object(DateTimeImmutable)#5 (3) { + ["date"]=> + string(26) "2023-03-03 16:24:00.000000" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" + } + ["current"]=> + NULL + ["end"]=> + object(DateTimeImmutable)#6 (3) { + ["date"]=> + string(26) "2023-03-09 16:24:00.000000" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" + } + ["interval"]=> + object(DateInterval)#7 (10) { + ["y"]=> + int(0) + ["m"]=> + int(0) + ["d"]=> + int(0) + ["h"]=> + int(1) + ["i"]=> + int(0) + ["s"]=> + int(0) + ["f"]=> + float(0) + ["invert"]=> + int(0) + ["days"]=> + bool(false) + ["from_string"]=> + bool(false) + } + ["recurrences"]=> + int(1) + ["include_start_date"]=> + bool(true) + ["include_end_date"]=> + bool(false) + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) +} +string(631) "O:1:"I":11:{s:5:"start";O:17:"DateTimeImmutable":3:{s:4:"date";s:26:"2023-03-03 16:24:00.000000";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}s:7:"current";N;s:3:"end";O:17:"DateTimeImmutable":3:{s:4:"date";s:26:"2023-03-09 16:24:00.000000";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}s:8:"interval";O:12:"DateInterval":10:{s:1:"y";i:0;s:1:"m";i:0;s:1:"d";i:0;s:1:"h";i:1;s:1:"i";i:0;s:1:"s";i:0;s:1:"f";d:0;s:6:"invert";i:0;s:4:"days";b:0;s:11:"from_string";b:0;}s:11:"recurrences";i:1;s:18:"include_start_date";b:1;s:16:"include_end_date";b:0;s:7:"!I!var1";i:1;s:7:"!I!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}" +object(I)#2 (11) { + ["start"]=> + object(DateTimeImmutable)#9 (3) { + ["date"]=> + string(26) "2023-03-03 16:24:00.000000" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" + } + ["current"]=> + NULL + ["end"]=> + object(DateTimeImmutable)#10 (3) { + ["date"]=> + string(26) "2023-03-09 16:24:00.000000" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" + } + ["interval"]=> + object(DateInterval)#11 (10) { + ["y"]=> + int(0) + ["m"]=> + int(0) + ["d"]=> + int(0) + ["h"]=> + int(1) + ["i"]=> + int(0) + ["s"]=> + int(0) + ["f"]=> + float(0) + ["invert"]=> + int(0) + ["days"]=> + bool(false) + ["from_string"]=> + bool(false) + } + ["recurrences"]=> + int(1) + ["include_start_date"]=> + bool(true) + ["include_end_date"]=> + bool(false) + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) +} diff --git a/ext/date/tests/gh10747-error.phpt b/ext/date/tests/gh10747-error.phpt new file mode 100644 index 0000000000000..b6c3900e23b9a --- /dev/null +++ b/ext/date/tests/gh10747-error.phpt @@ -0,0 +1,64 @@ +--TEST-- +Bug GH-10747 (Private fields in serialized DateTimeImmutable objects throw) +--FILE-- +var2 = 2; + $this->var4 = 4; + } +} + +$s = 'O:1:"I":7:{s:4:"date";s:26:"2023-03-09 17:03:11.123456";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";s:7:"!I!var1";i:1;s:7:"!I!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}'; +$u = unserialize(str_replace('!', chr(0), $s)); +var_dump($s, $u); + +// this one has the class names for the private properties changed to something non-existing +$s = 'O:1:"I":7:{s:4:"date";s:26:"2023-03-09 17:03:11.123456";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";s:7:"!J!var1";i:1;s:7:"!K!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}'; +$u = unserialize(str_replace('!', chr(0), $s)); +var_dump($s, $u); + +?> +--EXPECTF-- +string(179) "O:1:"I":7:{s:4:"date";s:26:"2023-03-09 17:03:11.123456";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";s:7:"!I!var1";i:1;s:7:"!I!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}" +object(I)#1 (7) { + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(2) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) + ["date"]=> + string(26) "2023-03-09 17:03:11.123456" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" +} +string(179) "O:1:"I":7:{s:4:"date";s:26:"2023-03-09 17:03:11.123456";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";s:7:"!J!var1";i:1;s:7:"!K!var2";i:2;s:7:"!*!var3";i:3;s:7:"!*!var4";i:4;}" +object(I)#2 (7) { + ["var1":"I":private]=> + int(1) + ["var2":"I":private]=> + int(0) + ["var3":protected]=> + int(3) + ["var4":protected]=> + int(4) + ["date"]=> + string(26) "2023-03-09 17:03:11.123456" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" +} diff --git a/ext/date/tests/gh9891.phpt b/ext/date/tests/gh9891.phpt new file mode 100644 index 0000000000000..6d8832b0d9237 --- /dev/null +++ b/ext/date/tests/gh9891.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug GH-9891 (DateTime modify with unixtimestamp (@) must work like setTimestamp) +--FILE-- +modify('@1234567890'); +var_dump($m->getTimeStamp()); + +echo "=======\n"; + +$a = new DateTime('2022-11-01 13:30:00', new DateTimezone('America/Lima')); +$b = clone $a; +echo '$a: ', $a->format(DateTime::ATOM), "\n"; +echo '$b: ', $b->format(DateTime::ATOM), "\n"; +echo '$a: @', $a->getTimestamp(), "\n"; +echo '$b: setTimestamp(', $b->getTimestamp(), ")\n"; +$a->modify('@' . $a->getTimestamp()); +$b->setTimestamp($b->getTimestamp()); +echo '$a: ', $a->format(DateTime::ATOM), "\n"; +echo '$b: ', $b->format(DateTime::ATOM), "\n"; +?> +--EXPECT-- +int(1234567890) +======= +$a: 2022-11-01T13:30:00-05:00 +$b: 2022-11-01T13:30:00-05:00 +$a: @1667327400 +$b: setTimestamp(1667327400) +$a: 2022-11-01T18:30:00+00:00 +$b: 2022-11-01T13:30:00-05:00 diff --git a/ext/date/tests/mktime_error.phpt b/ext/date/tests/mktime_error.phpt index 5bd1421369b9c..f333580b037b0 100644 --- a/ext/date/tests/mktime_error.phpt +++ b/ext/date/tests/mktime_error.phpt @@ -1,8 +1,8 @@ --TEST-- -Test mktime() function : error conditions +Test mktime() function: error conditions --FILE-- getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo "\n-- Testing mktime() function with more than expected no. of arguments --\n"; @@ -25,7 +25,7 @@ $extra_arg = 10; try { var_dump( mktime($hour, $minute, $sec, $month, $day, $year, $extra_arg) ); } catch (TypeError $e) { - echo $e->getMessage(), "\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> @@ -33,7 +33,7 @@ try { *** Testing mktime() : error conditions *** -- Testing mktime() function with Zero arguments -- -mktime() expects at least 1 argument, 0 given +ArgumentCountError: mktime() expects at least 1 argument, 0 given -- Testing mktime() function with more than expected no. of arguments -- -mktime() expects at most 6 arguments, 7 given +ArgumentCountError: mktime() expects at most 6 arguments, 7 given diff --git a/ext/date/tests/oo_001.phpt b/ext/date/tests/oo_001.phpt index 5db101f858671..4cae1f8e41a4e 100644 --- a/ext/date/tests/oo_001.phpt +++ b/ext/date/tests/oo_001.phpt @@ -23,13 +23,13 @@ try { $d = new _d; var_dump($d->format("Y-m-d H:i:s")); } catch (Error $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DateTime("1am todax"); } catch (Exception $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } $t = new DateTimeZone("UTC"); @@ -39,36 +39,36 @@ try { $t = new _t; var_dump($t->getName()); } catch (Error $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { new DateTimeZone("GottaFindThisOne"); -} catch (Exception $e) { - echo $e->getMessage(),"\n"; +} catch (DateInvalidTimeZoneException $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } $p = new _p; try { var_dump($p->getStartDate()); } catch (Error $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { var_dump($p->getDateInterval()); } catch (Error $e) { - echo $e->getMessage(),"\n"; + echo $e::class, ': ', $e->getMessage(), "\n"; } echo "DONE\n"; ?> --EXPECTF-- string(19) "%d-%d-%d %d:%d:%d" -The DateTime object has not been correctly initialized by its constructor -Failed to parse time string (1am todax) at position 4 (t): The timezone could not be found in the database +DateObjectError: Object of type _d (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor +DateMalformedStringException: Failed to parse time string (1am todax) at position 4 (t): The timezone could not be found in the database string(3) "UTC" -The DateTimeZone object has not been correctly initialized by its constructor -DateTimeZone::__construct(): Unknown or bad timezone (GottaFindThisOne) -The DatePeriod object has not been correctly initialized by its constructor -The DatePeriod object has not been correctly initialized by its constructor +DateObjectError: Object of type _t (inheriting DateTimeZone) has not been correctly initialized by calling parent::__construct() in its constructor +DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (GottaFindThisOne) +DateObjectError: Object of type _p (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor +DateObjectError: Object of type _p (inheriting DatePeriod) has not been correctly initialized by calling parent::__construct() in its constructor DONE diff --git a/ext/date/tests/ossfuzz-55589.txt b/ext/date/tests/ossfuzz-55589.txt new file mode 100644 index 0000000000000..77b4041ffa27e --- /dev/null +++ b/ext/date/tests/ossfuzz-55589.txt @@ -0,0 +1 @@ +|O:12:"DaTeInterval":2:{i:2;r:1;i:0;R:2; \ No newline at end of file diff --git a/ext/date/tests/ossfuzz-55599.txt b/ext/date/tests/ossfuzz-55599.txt new file mode 100644 index 0000000000000..624a0058c8f42 --- /dev/null +++ b/ext/date/tests/ossfuzz-55599.txt @@ -0,0 +1 @@ +|O:8:"DateTime":1:{i:1;d:2; \ No newline at end of file diff --git a/ext/date/tests/ossfuzz-55727.txt b/ext/date/tests/ossfuzz-55727.txt new file mode 100644 index 0000000000000..02389f0815c8e Binary files /dev/null and b/ext/date/tests/ossfuzz-55727.txt differ diff --git a/ext/date/tests/ossfuzz-56931.txt b/ext/date/tests/ossfuzz-56931.txt new file mode 100644 index 0000000000000..57c0ee791d424 --- /dev/null +++ b/ext/date/tests/ossfuzz-56931.txt @@ -0,0 +1 @@ +|O:12:"DateInterval":1:{s:0:"";s:2:" "; \ No newline at end of file diff --git a/ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-bd2.phpt b/ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-bd2.phpt index 74ee040390f17..6639c4218e9e8 100644 --- a/ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-bd2.phpt +++ b/ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-bd2.phpt @@ -54,7 +54,7 @@ echo 'bd8b ' . $end->format($date_format) . ' - ' . $start->format($date_format) echo "\n"; ?> --EXPECT-- -bd0 2010-11-07 01:00:00 EST America/New_York - 2010-11-07 01:59:59 EDT America/New_York = P0DT0H59M59S +bd0 2010-11-07 01:00:00 EST America/New_York - 2010-11-07 01:59:59 EDT America/New_York = P0DT0H0M1S bd5 2010-11-07 01:30:00 EST America/New_York - 2010-11-06 04:30:00 EDT America/New_York = P0DT22H bd6 2010-11-07 01:30:00 EDT America/New_York - 2010-11-06 04:30:00 EDT America/New_York = P0DT21H bd8a 2010-11-07 01:00:00 EST America/New_York - 2010-11-06 01:00:00 EDT America/New_York = P1DT0H diff --git a/ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-fa.phpt b/ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-fa.phpt index df67b5a89db75..45d0d13ce921a 100644 --- a/ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-fa.phpt +++ b/ext/date/tests/rfc-datetime_and_daylight_saving_time-type3-fa.phpt @@ -25,6 +25,12 @@ $interval = new DateInterval($interval_spec); echo 'fa2 ' . $start->format($date_format) . " + $interval_spec = " . $start->add($interval)->format($date_format) . "\n"; +$start = new DateTime('2010-03-13 04:30:00'); +$interval_spec = 'PT23H'; +$interval = new DateInterval($interval_spec); +echo 'fa2.5 ' . $start->format($date_format) . " + $interval_spec = " + . $start->add($interval)->format($date_format) . "\n"; + $start = new DateTime('2010-03-13 04:30:00'); $interval_spec = 'PT22H'; $interval = new DateInterval($interval_spec); @@ -52,6 +58,7 @@ echo 'fa6 ' . $start->format($date_format) . " + $interval_spec = " --EXPECT-- fa1 2010-03-14 01:59:59 EST America/New_York + PT1S = 2010-03-14 03:00:00 EDT America/New_York fa2 2010-03-13 04:30:00 EST America/New_York + P1D = 2010-03-14 04:30:00 EDT America/New_York +fa2.5 2010-03-13 04:30:00 EST America/New_York + PT23H = 2010-03-14 04:30:00 EDT America/New_York fa3 2010-03-13 04:30:00 EST America/New_York + PT22H = 2010-03-14 03:30:00 EDT America/New_York fa4 2010-03-13 04:30:00 EST America/New_York + PT21H = 2010-03-14 01:30:00 EST America/New_York fa5 2010-03-13 01:30:00 EST America/New_York + P1D = 2010-03-14 01:30:00 EST America/New_York diff --git a/ext/date/tests/timezone_identifiers_list_wrong_constructor.phpt b/ext/date/tests/timezone_identifiers_list_wrong_constructor.phpt index 0a697dd78fc84..2c2b603f8980f 100644 --- a/ext/date/tests/timezone_identifiers_list_wrong_constructor.phpt +++ b/ext/date/tests/timezone_identifiers_list_wrong_constructor.phpt @@ -10,15 +10,15 @@ date.timezone=UTC try { var_dump(timezone_identifiers_list(DateTimeZone::PER_COUNTRY)); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), "\n"; } try { var_dump(timezone_identifiers_list(DateTimeZone::PER_COUNTRY, 'A')); } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; + echo $e::class, ': ', $e->getMessage(), "\n"; } ?> --EXPECT-- -timezone_identifiers_list(): Argument #2 ($countryCode) must be a two-letter ISO 3166-1 compatible country code when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY -timezone_identifiers_list(): Argument #2 ($countryCode) must be a two-letter ISO 3166-1 compatible country code when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY +ValueError: timezone_identifiers_list(): Argument #2 ($countryCode) must be a two-letter ISO 3166-1 compatible country code when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY +ValueError: timezone_identifiers_list(): Argument #2 ($countryCode) must be a two-letter ISO 3166-1 compatible country code when argument #1 ($timezoneGroup) is DateTimeZone::PER_COUNTRY diff --git a/ext/date/tests/timezone_open_warning.phpt b/ext/date/tests/timezone_open_warning.phpt new file mode 100644 index 0000000000000..012192beef453 --- /dev/null +++ b/ext/date/tests/timezone_open_warning.phpt @@ -0,0 +1,23 @@ +--TEST-- +timezone_open() invalid timezones +--FILE-- +getName(), "\n"; + } +} +?> +--EXPECTF-- +In: +02:30; Out: +02:30 +In: Europe/Kyiv; Out: Europe/Kyiv + +Warning: timezone_open(): Unknown or bad timezone (2.5) in %stimezone_open_warning.php on line 6 + +Warning: timezone_open(): Unknown or bad timezone (99:60) in %stimezone_open_warning.php on line 6 + +Warning: timezone_open(): Unknown or bad timezone (Europe/Lviv) in %stimezone_open_warning.php on line 6 diff --git a/ext/date/tests/unserialize-test.phpt b/ext/date/tests/unserialize-test.phpt new file mode 100644 index 0000000000000..aaff75db6b77d --- /dev/null +++ b/ext/date/tests/unserialize-test.phpt @@ -0,0 +1,47 @@ +--TEST-- +Test DateInterval::__unserialize OSS fuzz issues +--FILE-- +getMessage(), "\n"; + } + var_dump($x); + echo "\n\n"; +} +?> +--EXPECTF-- +ossfuzz-55589.txt: +%s: unserialize(): Error at offset 39 of 39 bytes in %sunserialize-test.php on line %d +bool(false) + + +ossfuzz-55599.txt: +%s: unserialize(): Error at offset 26 of 26 bytes in %sunserialize-test.php on line %d +Error: Invalid serialization data for DateTime object +bool(false) + + +ossfuzz-55727.txt: +%s: unserialize(): Error at offset 230 of 509 bytes in %sunserialize-test.php on line %d +bool(false) + + +ossfuzz-56931.txt: +%s: unserialize(): Error at offset 39 of 39 bytes in %sunserialize-test.php on line %d + +Deprecated: Creation of dynamic property DateInterval::$ is deprecated in %s on line %d +bool(false) diff --git a/ext/dba/dba.c b/ext/dba/dba.c index 7e0f56b443e09..107541bd2efa3 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -55,8 +55,8 @@ PHP_MSHUTDOWN_FUNCTION(dba); PHP_MINFO_FUNCTION(dba); ZEND_BEGIN_MODULE_GLOBALS(dba) - char *default_handler; - dba_handler *default_hptr; + const char *default_handler; + const dba_handler *default_hptr; ZEND_END_MODULE_GLOBALS(dba) ZEND_DECLARE_MODULE_GLOBALS(dba) @@ -159,7 +159,7 @@ static zend_string* php_dba_make_key(HashTable *key) /* {{{ globals */ -static dba_handler handler[] = { +static const dba_handler handler[] = { #ifdef DBA_GDBM DBA_HND(gdbm, DBA_LOCK_EXT) /* Locking done in library if set */ #endif @@ -249,7 +249,7 @@ PHPAPI void dba_fetch_resource(dba_info **pinfo, zval **id) /* {{{ dba_get_handler PHPAPI dba_handler *dba_get_handler(const char* handler_name) { - dba_handler *hptr; + const dba_handler *hptr; for (hptr = handler; hptr->name && strcasecmp(hptr->name, handler_name); hptr++); return hptr; } @@ -262,9 +262,10 @@ static void dba_close(dba_info *info) if (info->hnd) { info->hnd->close(info); } - if (info->path) { - pefree(info->path, info->flags&DBA_PERSISTENT); - } + ZEND_ASSERT(info->path); + zend_string_release_ex(info->path, info->flags&DBA_PERSISTENT); + info->path = NULL; + if (info->fp && info->fp != info->lock.fp) { if (info->flags & DBA_PERSISTENT) { php_stream_pclose(info->fp); @@ -293,7 +294,7 @@ static void dba_close_rsrc(zend_resource *rsrc) /* }}} */ /* {{{ dba_close_pe_rsrc_deleter */ -int dba_close_pe_rsrc_deleter(zval *el, void *pDba) +static int dba_close_pe_rsrc_deleter(zval *el, void *pDba) { if (Z_RES_P(el)->ptr == pDba) { if (Z_DELREF_P(el) == 0) { @@ -318,9 +319,9 @@ static void dba_close_pe_rsrc(zend_resource *rsrc) /* }}} */ /* {{{ PHP_INI */ -ZEND_INI_MH(OnUpdateDefaultHandler) +static ZEND_INI_MH(OnUpdateDefaultHandler) { - dba_handler *hptr; + const dba_handler *hptr; if (!ZSTR_LEN(new_value)) { DBA_G(default_hptr) = NULL; @@ -377,7 +378,7 @@ PHP_MSHUTDOWN_FUNCTION(dba) /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(dba) { - dba_handler *hptr; + const dba_handler *hptr; smart_str handlers = {0}; for(hptr = handler; hptr->name; hptr++) { @@ -431,7 +432,7 @@ static void php_dba_update(INTERNAL_FUNCTION_PARAMETERS, int mode) /* }}} */ /* {{{ php_find_dbm */ -dba_info *php_dba_find(const char* path) +static dba_info *php_dba_find(const zend_string *path) { zend_resource *le; dba_info *info; @@ -444,7 +445,7 @@ dba_info *php_dba_find(const char* path) } if (le->type == le_db || le->type == le_pdb) { info = (dba_info *)(le->ptr); - if (!strcmp(info->path, path)) { + if (zend_string_equals(path, info->path)) { return (dba_info *)(le->ptr); } } @@ -454,6 +455,20 @@ dba_info *php_dba_find(const char* path) } /* }}} */ +static zend_always_inline zend_string *php_dba_zend_string_dup_safe(zend_string *s, bool persistent) +{ + if (ZSTR_IS_INTERNED(s) && !persistent) { + return s; + } else { + zend_string *duplicated_str = zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent); + if (persistent) { + GC_MAKE_PERSISTENT_LOCAL(duplicated_str); + } + return duplicated_str; + } +} + + #define FREE_PERSISTENT_RESOURCE_KEY() if (persistent_resource_key) {zend_string_release_ex(persistent_resource_key, false);} /* {{{ php_dba_open */ @@ -461,13 +476,12 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) { dba_mode_t modenr; dba_info *info, *other; - dba_handler *hptr; - char *error = NULL; + const dba_handler *hptr; + const char *error = NULL; int lock_mode, lock_flag = 0; - char *file_mode; - char *lock_file_mode = NULL; + const char *file_mode; + const char *lock_file_mode = NULL; int persistent_flag = persistent ? STREAM_OPEN_PERSISTENT : 0; - zend_string *opened_path = NULL; char *lock_name; #ifdef PHP_WIN32 bool restarted = 0; @@ -724,7 +738,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) info = pemalloc(sizeof(dba_info), persistent); memset(info, 0, sizeof(dba_info)); - info->path = pestrdup(ZSTR_VAL(path), persistent); + info->path = php_dba_zend_string_dup_safe(path, persistent); info->mode = modenr; info->file_permission = permission; info->map_size = map_size; @@ -753,8 +767,9 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (is_db_lock) { lock_name = ZSTR_VAL(path); } else { - spprintf(&lock_name, 0, "%s.lck", info->path); + spprintf(&lock_name, 0, "%s.lck", ZSTR_VAL(info->path)); if (!strcmp(file_mode, "r")) { + zend_string *opened_path = NULL; /* when in read only mode try to use existing .lck file first */ /* do not log errors for .lck file while in read only mode on .lck file */ lock_file_mode = "rb"; @@ -769,13 +784,17 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } } if (!info->lock.fp) { + zend_string *opened_path = NULL; info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path); if (info->lock.fp) { if (is_db_lock) { + ZEND_ASSERT(opened_path); /* replace the path info with the real path of the opened file */ - pefree(info->path, persistent); - info->path = pestrndup(ZSTR_VAL(opened_path), ZSTR_LEN(opened_path), persistent); + zend_string_release(info->path); + info->path = php_dba_zend_string_dup_safe(opened_path, persistent); } + } + if (opened_path) { zend_string_release_ex(opened_path, 0); } } @@ -801,7 +820,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (info->lock.fp && is_db_lock) { info->fp = info->lock.fp; /* use the same stream for locking and database access */ } else { - info->fp = php_stream_open_wrapper(info->path, file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL); + info->fp = php_stream_open_wrapper(ZSTR_VAL(info->path), file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL); } if (!info->fp) { dba_close(info); @@ -1165,7 +1184,7 @@ PHP_FUNCTION(dba_sync) /* {{{ List configured database handlers */ PHP_FUNCTION(dba_handlers) { - dba_handler *hptr; + const dba_handler *hptr; bool full_info = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &full_info) == FAILURE) { @@ -1207,7 +1226,7 @@ PHP_FUNCTION(dba_list) } if (le->type == le_db || le->type == le_pdb) { info = (dba_info *)(le->ptr); - add_index_string(return_value, i, info->path); + add_index_str(return_value, i, zend_string_copy(info->path)); } } } diff --git a/ext/dba/dba_cdb.c b/ext/dba/dba_cdb.c index 5af9121b565a6..d5af1b8cce249 100644 --- a/ext/dba/dba_cdb.c +++ b/ext/dba/dba_cdb.c @@ -73,7 +73,7 @@ DBA_OPEN_FUNC(cdb) make = 0; file = info->fp; #else - file = VCWD_OPEN(info->path, O_RDONLY); + file = VCWD_OPEN(ZSTR_VAL(info->path), O_RDONLY); if (file < 0) { *error = "Unable to open file"; return FAILURE; diff --git a/ext/dba/dba_db1.c b/ext/dba/dba_db1.c index 3a95cea460c14..57dfab38f13b7 100644 --- a/ext/dba/dba_db1.c +++ b/ext/dba/dba_db1.c @@ -61,7 +61,7 @@ DBA_OPEN_FUNC(db1) return FAILURE; /* not possible */ } - db = dbopen((char *)info->path, gmode, filemode, DB_HASH, NULL); + db = dbopen((char *)ZSTR_VAL(info->path), gmode, filemode, DB_HASH, NULL); if (db == NULL) { return FAILURE; diff --git a/ext/dba/dba_db2.c b/ext/dba/dba_db2.c index 8f6d47a9239c9..86306bd59a2b8 100644 --- a/ext/dba/dba_db2.c +++ b/ext/dba/dba_db2.c @@ -41,7 +41,7 @@ DBA_OPEN_FUNC(db2) int gmode = 0; int filemode = info->file_permission; struct stat check_stat; - int s = VCWD_STAT(info->path, &check_stat); + int s = VCWD_STAT(ZSTR_VAL(info->path), &check_stat); if (!s && !check_stat.st_size) { info->mode = DBA_TRUNC; /* force truncate */ @@ -61,7 +61,7 @@ DBA_OPEN_FUNC(db2) return FAILURE;/* not possible */ } - if (db_open(info->path, type, gmode, filemode, NULL, NULL, &dbp)) { + if (db_open(ZSTR_VAL(info->path), type, gmode, filemode, NULL, NULL, &dbp)) { return FAILURE; } diff --git a/ext/dba/dba_db3.c b/ext/dba/dba_db3.c index d9e948a623f50..5d36d86e00808 100644 --- a/ext/dba/dba_db3.c +++ b/ext/dba/dba_db3.c @@ -53,7 +53,7 @@ DBA_OPEN_FUNC(db3) int gmode = 0, err; int filemode = info->file_permission; struct stat check_stat; - int s = VCWD_STAT(info->path, &check_stat); + int s = VCWD_STAT(ZSTR_VAL(info->path), &check_stat); if (!s && !check_stat.st_size) { info->mode = DBA_TRUNC; /* force truncate */ @@ -81,9 +81,9 @@ DBA_OPEN_FUNC(db3) dbp->set_errcall(dbp, php_dba_db3_errcall_fcn); if( #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)) - (err=dbp->open(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) { + (err=dbp->open(dbp, 0, ZSTR_VAL(info->path), NULL, type, gmode, filemode)) == 0) { #else - (err=dbp->open(dbp, info->path, NULL, type, gmode, filemode)) == 0) { + (err=dbp->open(dbp, ZSTR_VAL(info->path), NULL, type, gmode, filemode)) == 0) { #endif dba_db3_data *data; diff --git a/ext/dba/dba_db4.c b/ext/dba/dba_db4.c index 3de66a4274432..a2dbd5dafa1e2 100644 --- a/ext/dba/dba_db4.c +++ b/ext/dba/dba_db4.c @@ -67,7 +67,7 @@ DBA_OPEN_FUNC(db4) int gmode = 0, err; int filemode = info->file_permission; struct stat check_stat; - int s = VCWD_STAT(info->path, &check_stat); + int s = VCWD_STAT(ZSTR_VAL(info->path), &check_stat); #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR <= 7) /* Bug 51086 */ if (!s && !check_stat.st_size) { @@ -110,9 +110,9 @@ DBA_OPEN_FUNC(db4) dbp->set_errcall(dbp, php_dba_db4_errcall_fcn); if ( #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)) - (err=dbp->open(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) { + (err=dbp->open(dbp, 0, ZSTR_VAL(info->path), NULL, type, gmode, filemode)) == 0) { #else - (err=dbp->open(dbp, info->path, NULL, type, gmode, filemode)) == 0) { + (err=dbp->open(dbp, ZSTR_VAL(info->path), NULL, type, gmode, filemode)) == 0) { #endif dba_db4_data *data; diff --git a/ext/dba/dba_dbm.c b/ext/dba/dba_dbm.c index afa645cb2fe70..88a8959082709 100644 --- a/ext/dba/dba_dbm.c +++ b/ext/dba/dba_dbm.c @@ -36,7 +36,7 @@ #include #define TRUNC_IT(extension, mode) \ - snprintf(buf, MAXPATHLEN, "%s" extension, info->path); \ + snprintf(buf, MAXPATHLEN, "%s" extension, ZSTR_VAL(info->path)); \ buf[MAXPATHLEN-1] = '\0'; \ if((fd = VCWD_OPEN_MODE(buf, O_CREAT | mode | O_WRONLY, filemode)) == -1) \ return FAILURE; \ @@ -67,7 +67,7 @@ DBA_OPEN_FUNC(dbm) TRUNC_IT(".dir", 0); } - if(dbminit((char *) info->path) == -1) { + if(dbminit((char *) ZSTR_VAL(info->path)) == -1) { return FAILURE; } diff --git a/ext/dba/dba_gdbm.c b/ext/dba/dba_gdbm.c index c3fbb5bf21e18..0781e1fb1a76f 100644 --- a/ext/dba/dba_gdbm.c +++ b/ext/dba/dba_gdbm.c @@ -46,7 +46,7 @@ DBA_OPEN_FUNC(gdbm) if(gmode == -1) return FAILURE; /* not possible */ - dbf = gdbm_open(info->path, /* int block_size */ 0, gmode, filemode, NULL); + dbf = gdbm_open(ZSTR_VAL(info->path), /* int block_size */ 0, gmode, filemode, NULL); if(dbf) { info->dbf = pemalloc(sizeof(dba_gdbm_data), info->flags&DBA_PERSISTENT); diff --git a/ext/dba/dba_lmdb.c b/ext/dba/dba_lmdb.c index 1645453324525..f147f4c810dee 100644 --- a/ext/dba/dba_lmdb.c +++ b/ext/dba/dba_lmdb.c @@ -81,7 +81,7 @@ DBA_OPEN_FUNC(lmdb) } } - rc = mdb_env_open(env, info->path, flags, mode); + rc = mdb_env_open(env, ZSTR_VAL(info->path), flags, mode); if (rc) { /* If this function [mdb_env_open()] fails, mdb_env_close() must be called to discard the MDB_env handle. * http://www.lmdb.tech/doc/group__mdb.html#ga32a193c6bf4d7d5c5d579e71f22e9340 */ diff --git a/ext/dba/dba_ndbm.c b/ext/dba/dba_ndbm.c index d872add48e6ab..758fcd1e77172 100644 --- a/ext/dba/dba_ndbm.c +++ b/ext/dba/dba_ndbm.c @@ -52,7 +52,7 @@ DBA_OPEN_FUNC(ndbm) return FAILURE; /* not possible */ } - dbf = dbm_open(info->path, gmode, filemode); + dbf = dbm_open(ZSTR_VAL(info->path), gmode, filemode); pinfo->dbf = dbf; return SUCCESS; diff --git a/ext/dba/dba_qdbm.c b/ext/dba/dba_qdbm.c index d06af20659909..d70885754bedd 100644 --- a/ext/dba/dba_qdbm.c +++ b/ext/dba/dba_qdbm.c @@ -37,16 +37,16 @@ DBA_OPEN_FUNC(qdbm) switch(info->mode) { case DBA_READER: - dbf = dpopen(info->path, DP_OREADER, 0); + dbf = dpopen(ZSTR_VAL(info->path), DP_OREADER, 0); break; case DBA_WRITER: - dbf = dpopen(info->path, DP_OWRITER, 0); + dbf = dpopen(ZSTR_VAL(info->path), DP_OWRITER, 0); break; case DBA_CREAT: - dbf = dpopen(info->path, DP_OWRITER | DP_OCREAT, 0); + dbf = dpopen(ZSTR_VAL(info->path), DP_OWRITER | DP_OCREAT, 0); break; case DBA_TRUNC: - dbf = dpopen(info->path, DP_OWRITER | DP_OCREAT | DP_OTRUNC, 0); + dbf = dpopen(ZSTR_VAL(info->path), DP_OWRITER | DP_OCREAT | DP_OTRUNC, 0); break; default: return FAILURE; diff --git a/ext/dba/dba_tcadb.c b/ext/dba/dba_tcadb.c index 23c9e2d1d363d..b085558a71133 100644 --- a/ext/dba/dba_tcadb.c +++ b/ext/dba/dba_tcadb.c @@ -39,16 +39,16 @@ DBA_OPEN_FUNC(tcadb) if (tcadb) { switch(info->mode) { case DBA_READER: - spprintf(&path_string, 0, "%s#mode=r", info->path); + spprintf(&path_string, 0, "%s#mode=r", ZSTR_VAL(info->path)); break; case DBA_WRITER: - spprintf(&path_string, 0, "%s#mode=w", info->path); + spprintf(&path_string, 0, "%s#mode=w", ZSTR_VAL(info->path)); break; case DBA_CREAT: - spprintf(&path_string, 0, "%s#mode=wc", info->path); + spprintf(&path_string, 0, "%s#mode=wc", ZSTR_VAL(info->path)); break; case DBA_TRUNC: - spprintf(&path_string, 0, "%s#mode=wct", info->path); + spprintf(&path_string, 0, "%s#mode=wct", ZSTR_VAL(info->path)); break; default: tcadbdel(tcadb); diff --git a/ext/dba/libcdb/cdb.c b/ext/dba/libcdb/cdb.c index 10cc4f9852156..e694d6a6eb12f 100644 --- a/ext/dba/libcdb/cdb.c +++ b/ext/dba/libcdb/cdb.c @@ -185,7 +185,7 @@ int cdb_find(struct cdb *c, char *key, unsigned int len) /* }}} */ /* {{{ cdb_version */ -char *cdb_version() +const char *cdb_version(void) { return "0.75, $Id$"; } diff --git a/ext/dba/libcdb/cdb.h b/ext/dba/libcdb/cdb.h index 2225b2297cfa5..4a94b81f832db 100644 --- a/ext/dba/libcdb/cdb.h +++ b/ext/dba/libcdb/cdb.h @@ -48,6 +48,6 @@ int cdb_find(struct cdb *, char *, unsigned int); #define cdb_datapos(c) ((c)->dpos) #define cdb_datalen(c) ((c)->dlen) -char *cdb_version(void); +const char *cdb_version(void); #endif diff --git a/ext/dba/libcdb/cdb_make.c b/ext/dba/libcdb/cdb_make.c index 8144ef10fb5d9..570e3625b0cea 100644 --- a/ext/dba/libcdb/cdb_make.c +++ b/ext/dba/libcdb/cdb_make.c @@ -236,7 +236,7 @@ int cdb_make_finish(struct cdb_make *c) /* }}} */ /* {{{ cdb_make_version */ -char *cdb_make_version() +const char *cdb_make_version(void) { return "0.75, $Id$"; } diff --git a/ext/dba/libcdb/cdb_make.h b/ext/dba/libcdb/cdb_make.h index 2410e3056225e..96dbd43d1e562 100644 --- a/ext/dba/libcdb/cdb_make.h +++ b/ext/dba/libcdb/cdb_make.h @@ -55,6 +55,6 @@ int cdb_make_addbegin(struct cdb_make *, unsigned int, unsigned int); int cdb_make_addend(struct cdb_make *, unsigned int, unsigned int, uint32); int cdb_make_add(struct cdb_make *, char *, unsigned int, char *, unsigned int); int cdb_make_finish(struct cdb_make *); -char *cdb_make_version(void); +const char *cdb_make_version(void); #endif diff --git a/ext/dba/libflatfile/flatfile.c b/ext/dba/libflatfile/flatfile.c index a713373046dce..7fa995b7bd21d 100644 --- a/ext/dba/libflatfile/flatfile.c +++ b/ext/dba/libflatfile/flatfile.c @@ -276,7 +276,7 @@ datum flatfile_nextkey(flatfile *dba) { /* }}} */ /* {{{ flatfile_version */ -char *flatfile_version() +const char *flatfile_version(void) { return "1.0, $Id$"; } diff --git a/ext/dba/libflatfile/flatfile.h b/ext/dba/libflatfile/flatfile.h index bb39765151a5d..801ec8054f4f1 100644 --- a/ext/dba/libflatfile/flatfile.h +++ b/ext/dba/libflatfile/flatfile.h @@ -39,6 +39,6 @@ int flatfile_delete(flatfile *dba, datum key_datum); int flatfile_findkey(flatfile *dba, datum key_datum); datum flatfile_firstkey(flatfile *dba); datum flatfile_nextkey(flatfile *dba); -char *flatfile_version(void); +const char *flatfile_version(void); #endif diff --git a/ext/dba/libinifile/inifile.c b/ext/dba/libinifile/inifile.c index cdbd83769bd7c..bb00b98fa4a14 100644 --- a/ext/dba/libinifile/inifile.c +++ b/ext/dba/libinifile/inifile.c @@ -38,7 +38,7 @@ */ /* {{{ inifile_version */ -char *inifile_version() +const char *inifile_version(void) { return "1.0, $Id$"; } diff --git a/ext/dba/libinifile/inifile.h b/ext/dba/libinifile/inifile.h index 48e06be8a555f..e931c70bcbf6b 100644 --- a/ext/dba/libinifile/inifile.h +++ b/ext/dba/libinifile/inifile.h @@ -49,7 +49,7 @@ int inifile_delete_ex(inifile *dba, const key_type *key, bool *found); int inifile_replace(inifile *dba, const key_type *key, const val_type *val); int inifile_replace_ex(inifile *dba, const key_type *key, const val_type *val, bool *found); int inifile_append(inifile *dba, const key_type *key, const val_type *val); -char *inifile_version(void); +const char *inifile_version(void); key_type inifile_key_split(const char *group_name); char * inifile_key_string(const key_type *key); diff --git a/ext/dba/php_dba.h b/ext/dba/php_dba.h index ce59e4851d9f8..30742661c3bba 100644 --- a/ext/dba/php_dba.h +++ b/ext/dba/php_dba.h @@ -38,7 +38,7 @@ typedef struct dba_lock { typedef struct dba_info { /* public */ void *dbf; /* ptr to private data or whatever */ - char *path; + zend_string *path; dba_mode_t mode; php_stream *fp; /* this is the database stream for builtin handlers */ int fd; @@ -48,7 +48,7 @@ typedef struct dba_info { zend_long driver_flags; /* private */ int flags; /* whether and how dba did locking and other flags*/ - struct dba_handler *hnd; + const struct dba_handler *hnd; dba_lock lock; } dba_info; @@ -73,9 +73,9 @@ extern zend_module_entry dba_module_entry; #define dba_module_ptr &dba_module_entry typedef struct dba_handler { - char *name; /* handler name */ + const char *name; /* handler name */ int flags; /* whether and how dba does locking and other flags*/ - zend_result (*open)(dba_info *, char **error); + zend_result (*open)(dba_info *, const char **error); void (*close)(dba_info *); zend_string* (*fetch)(dba_info *, zend_string *, int); zend_result (*update)(dba_info *, zend_string *, zend_string *, int); @@ -85,14 +85,14 @@ typedef struct dba_handler { zend_string* (*nextkey)(dba_info *); zend_result (*optimize)(dba_info *); zend_result (*sync)(dba_info *); - char* (*info)(struct dba_handler *hnd, dba_info *); + char* (*info)(const struct dba_handler *hnd, dba_info *); /* dba_info==NULL: Handler info, dba_info!=NULL: Database info */ } dba_handler; /* common prototypes which must be supplied by modules */ #define DBA_OPEN_FUNC(x) \ - zend_result dba_open_##x(dba_info *info, char **error) + zend_result dba_open_##x(dba_info *info, const char **error) #define DBA_CLOSE_FUNC(x) \ void dba_close_##x(dba_info *info) #define DBA_FETCH_FUNC(x) \ @@ -112,7 +112,7 @@ typedef struct dba_handler { #define DBA_SYNC_FUNC(x) \ zend_result dba_sync_##x(dba_info *info) #define DBA_INFO_FUNC(x) \ - char *dba_info_##x(dba_handler *hnd, dba_info *info) + char *dba_info_##x(const dba_handler *hnd, dba_info *info) #define DBA_FUNCS(x) \ DBA_OPEN_FUNC(x); \ diff --git a/ext/dom/document.c b/ext/dom/document.c index 4dee5548f1887..c60198a3be110 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1182,7 +1182,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so int validate, recover, resolve_externals, keep_blanks, substitute_ent; int resolved_path_len; int old_error_reporting = 0; - char *directory=NULL, resolved_path[MAXPATHLEN]; + char *directory=NULL, resolved_path[MAXPATHLEN + 1]; if (id != NULL) { intern = Z_DOMOBJ_P(id); diff --git a/ext/dom/node.c b/ext/dom/node.c index d55ac99efeff2..bc7108e087e75 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -1591,7 +1591,7 @@ static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ } if (Z_TYPE_P(tmp) != IS_STRING) { /* if mode == 0 then $xpath arg is 3, if mode == 1 then $xpath is 4 */ - zend_argument_type_error(3 + mode, "\"query\" option must be a string, %s given", zend_zval_type_name(tmp)); + zend_argument_type_error(3 + mode, "\"query\" option must be a string, %s given", zend_zval_value_name(tmp)); RETURN_THROWS(); } xquery = Z_STRVAL_P(tmp); diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c index 3d7e5e44a4b2c..571da9b6411d6 100644 --- a/ext/dom/parentnode.c +++ b/ext/dom/parentnode.c @@ -162,9 +162,8 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod newNode = dom_object_get_node(newNodeObj); if (newNode->doc != documentNode) { - xmlFree(fragment); php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror); - return NULL; + goto err; } if (newNode->parent != NULL) { @@ -175,25 +174,29 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod xmlSetTreeDoc(newNode, documentNode); if (newNode->type == XML_ATTRIBUTE_NODE) { - xmlFree(fragment); + goto hierarchy_request_err; + } - php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror); - return NULL; + /* + * xmlNewDocText function will always returns same address to the second parameter if the parameters are greater than or equal to three. + * If it's text, that's fine, but if it's an object, it can cause invalid pointer because many new nodes point to the same memory address. + * So we must copy the new node to avoid this situation. + */ + if (nodesc > 1) { + newNode = xmlCopyNode(newNode, 1); } if (!xmlAddChild(fragment, newNode)) { - xmlFree(fragment); - - php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror); - return NULL; + if (nodesc > 1) { + xmlFreeNode(newNode); + } + goto hierarchy_request_err; } continue; } else { - xmlFree(fragment); - - zend_argument_type_error(i + 1, "must be of type DOMNode|string, %s given", zend_zval_type_name(&nodes[i])); - return NULL; + zend_argument_type_error(i + 1, "must be of type DOMNode|string, %s given", zend_zval_value_name(&nodes[i])); + goto err; } } else if (Z_TYPE(nodes[i]) == IS_STRING) { newNode = xmlNewDocText(documentNode, (xmlChar *) Z_STRVAL(nodes[i])); @@ -201,20 +204,22 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod xmlSetTreeDoc(newNode, documentNode); if (!xmlAddChild(fragment, newNode)) { - xmlFree(fragment); - - return NULL; + xmlFreeNode(newNode); + goto hierarchy_request_err; } } else { - xmlFree(fragment); - - zend_argument_type_error(i + 1, "must be of type DOMNode|string, %s given", zend_zval_type_name(&nodes[i])); - - return NULL; + zend_argument_type_error(i + 1, "must be of type DOMNode|string, %s given", zend_zval_value_name(&nodes[i])); + goto err; } } return fragment; + +hierarchy_request_err: + php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror); +err: + xmlFreeNode(fragment); + return NULL; } static void dom_fragment_assign_parent_node(xmlNodePtr parentNode, xmlNodePtr fragment) @@ -302,7 +307,9 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc) { xmlNode *prevsib = dom_object_get_node(context); xmlNodePtr newchild, parentNode; - xmlNode *fragment; + xmlNode *fragment, *nextsib; + xmlDoc *doc; + bool afterlastchild; int stricterror = dom_get_strict_error(context->document); @@ -311,7 +318,10 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc) return; } + doc = prevsib->doc; parentNode = prevsib->parent; + nextsib = prevsib->next; + afterlastchild = (nextsib == NULL); fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc); if (fragment == NULL) { @@ -321,13 +331,42 @@ void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc) newchild = fragment->children; if (newchild) { - fragment->last->next = prevsib->next; - prevsib->next = newchild; + /* first node and last node are both both parameters to DOMElement::after() method so nextsib and prevsib are null. */ + if (!parentNode->children) { + prevsib = nextsib = NULL; + } else if (afterlastchild) { + /* + * The new node will be inserted after last node, prevsib is last node. + * The first node is the parameter to DOMElement::after() if parentNode->children == prevsib is true + * and prevsib does not change, otherwise prevsib is parentNode->last (first node). + */ + prevsib = parentNode->children == prevsib ? prevsib : parentNode->last; + } else { + /* + * The new node will be inserted after first node, prevsib is first node. + * The first node is not the parameter to DOMElement::after() if parentNode->children == prevsib is true + * and prevsib does not change otherwise prevsib is null to mean that parentNode->children is the new node. + */ + prevsib = parentNode->children == prevsib ? prevsib : NULL; + } - newchild->prev = prevsib; + if (prevsib) { + fragment->last->next = prevsib->next; + if (prevsib->next) { + prevsib->next->prev = fragment->last; + } + prevsib->next = newchild; + } else { + parentNode->children = newchild; + if (nextsib) { + fragment->last->next = nextsib; + nextsib->prev = fragment->last; + } + } + newchild->prev = prevsib; dom_fragment_assign_parent_node(parentNode, fragment); - dom_reconcile_ns(prevsib->doc, newchild); + dom_reconcile_ns(doc, newchild); } xmlFree(fragment); @@ -337,10 +376,15 @@ void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc) { xmlNode *nextsib = dom_object_get_node(context); xmlNodePtr newchild, prevsib, parentNode; - xmlNode *fragment; + xmlNode *fragment, *afternextsib; + xmlDoc *doc; + bool beforefirstchild; + doc = nextsib->doc; prevsib = nextsib->prev; + afternextsib = nextsib->next; parentNode = nextsib->parent; + beforefirstchild = !prevsib; fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc); if (fragment == NULL) { @@ -350,19 +394,40 @@ void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc) newchild = fragment->children; if (newchild) { + /* first node and last node are both both parameters to DOMElement::before() method so nextsib is null. */ + if (!parentNode->children) { + nextsib = NULL; + } else if (beforefirstchild) { + /* + * The new node will be inserted before first node, nextsib is first node and afternextsib is last node. + * The first node is not the parameter to DOMElement::before() if parentNode->children == nextsib is true + * and nextsib does not change, otherwise nextsib is the last node. + */ + nextsib = parentNode->children == nextsib ? nextsib : afternextsib; + } else { + /* + * The new node will be inserted before last node, prevsib is first node and nestsib is last node. + * The first node is not the parameter to DOMElement::before() if parentNode->children == prevsib is true + * but last node may be, so use prevsib->next to determine the value of nextsib, otherwise nextsib does not change. + */ + nextsib = parentNode->children == prevsib ? prevsib->next : nextsib; + } + if (parentNode->children == nextsib) { parentNode->children = newchild; } else { prevsib->next = newchild; } + fragment->last->next = nextsib; - nextsib->prev = fragment->last; + if (nextsib) { + nextsib->prev = fragment->last; + } newchild->prev = prevsib; dom_fragment_assign_parent_node(parentNode, fragment); - - dom_reconcile_ns(nextsib->doc, newchild); + dom_reconcile_ns(doc, newchild); } xmlFree(fragment); diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index d9463012f146b..662c6e9ef7ce1 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -403,7 +403,7 @@ static HashTable* dom_get_debug_info_helper(zend_object *object, int *is_temp) / return debug_info; } - object_str = zend_string_init("(object value omitted)", sizeof("(object value omitted)")-1, 0); + object_str = ZSTR_INIT_LITERAL("(object value omitted)", 0); ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(prop_handlers, string_key, entry) { zval value; diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 472deb3df3d7a..21886e5015084 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -485,7 +485,7 @@ class DOMCharacterData extends DOMNode implements DOMChildNode public ?DOMElement $nextElementSibling; /** @tentative-return-type */ - public function appendData(string $data): bool {} + public function appendData(string $data): true {} /** @return string|false */ public function substringData(int $offset, int $count) {} diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index 4edb4cf2bb15c..d1234f1404011 100644 --- a/ext/dom/php_dom_arginfo.h +++ b/ext/dom/php_dom_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 8365be2868e4932ea74f8eb2d4ce840117d48deb */ + * Stub hash: 9a6a0c2a5626466aa6397f0892ee5b08ec335e14 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 0) ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0) @@ -139,7 +139,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMNodeList_item, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) ZEND_END_ARG_INFO() -#define arginfo_class_DOMCharacterData_appendData arginfo_class_DOMDocumentFragment_appendXML +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DOMCharacterData_appendData, 0, 1, IS_TRUE, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMCharacterData_substringData, 0, 0, 2) ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0) diff --git a/ext/dom/tests/bug80602.phpt b/ext/dom/tests/bug80602.phpt new file mode 100644 index 0000000000000..9f041f686f516 --- /dev/null +++ b/ext/dom/tests/bug80602.phpt @@ -0,0 +1,178 @@ +--TEST-- +Bug #80602 (Segfault when using DOMChildNode::before()) +--FILE-- +loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before($target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before($target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before($doc->documentElement->lastChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before($doc->documentElement->firstChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before($target, $doc->documentElement->lastChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before($doc->documentElement->lastChild, $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before($target, $doc->documentElement->firstChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before($doc->documentElement->firstChild, $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before('bar','baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before('bar','baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before($target, 'bar','baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before('bar', $target, 'baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before('bar', 'baz', $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before($target, 'bar','baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before('bar', $target, 'baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before('bar', 'baz', $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before('bar', $target, $doc->documentElement->lastChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before($target, 'bar', $doc->documentElement->lastChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->before($target, $doc->documentElement->lastChild, 'bar'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before('bar', $doc->documentElement->firstChild, $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before($doc->documentElement->firstChild, 'bar', $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->before($doc->documentElement->firstChild, $target, 'bar'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +?> +--EXPECTF-- +foo +foo +foo +foo +foo +foo +foo +foo +barbazfoo +foobarbaz +foobarbaz +barfoobaz +barbazfoo +foobarbaz +foobarbaz +foobarbaz +barfoo +foobar +foobar +barfoo +foobar +foobar diff --git a/ext/dom/tests/bug80602_2.phpt b/ext/dom/tests/bug80602_2.phpt new file mode 100644 index 0000000000000..1151417c0f845 --- /dev/null +++ b/ext/dom/tests/bug80602_2.phpt @@ -0,0 +1,178 @@ +--TEST-- +Bug #80602 (Segfault when using DOMChildNode::after()) +--FILE-- +loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after($target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after($target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after($doc->documentElement->lastChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after($doc->documentElement->firstChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after($target, $doc->documentElement->lastChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after($doc->documentElement->lastChild, $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after($target, $doc->documentElement->firstChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after($doc->documentElement->firstChild, $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after('bar','baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after('bar','baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after($target, 'bar','baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after('bar', $target, 'baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after('bar', 'baz', $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after($target, 'bar','baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after('bar', $target, 'baz'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after('bar', 'baz', $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after('bar', $target, $doc->documentElement->lastChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after($target, 'bar', $doc->documentElement->lastChild); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->firstChild; +$target->after($target, $doc->documentElement->lastChild, 'bar'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after('bar', $doc->documentElement->firstChild, $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after($doc->documentElement->firstChild, 'bar', $target); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + + +$doc = new \DOMDocument(); +$doc->loadXML('foo'); +$target = $doc->documentElement->lastChild; +$target->after($doc->documentElement->firstChild, $target, 'bar'); +echo $doc->saveXML($doc->documentElement).PHP_EOL; + +?> +--EXPECTF-- +foo +foo +foo +foo +foo +foo +foo +foo +foobarbaz +foobarbaz +foobarbaz +barfoobaz +barbazfoo +foobarbaz +foobarbaz +foobarbaz +barfoo +foobar +foobar +barfoo +foobar +foobar diff --git a/ext/enchant/tests/dict_quick_check.phpt b/ext/enchant/tests/dict_quick_check.phpt index 3cc45079f245a..b14a009af4cf4 100644 --- a/ext/enchant/tests/dict_quick_check.phpt +++ b/ext/enchant/tests/dict_quick_check.phpt @@ -6,7 +6,7 @@ marcosptf - enchant --SKIPIF-- tag_table == REQUIRES_CUSTOM_PARSING)) { + /* Custom parsing required, which is not implemented at this point + * Return true so that other metadata can still be parsed. */ + return true; + } + dir_start = value_ptr + maker_note->offset; #ifdef EXIF_DEBUG - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process %s @x%04X + 0x%04X=%d: %s", exif_get_sectionname(section_index), (intptr_t)dir_start-(intptr_t)info->offset_base+maker_note->offset+displacement, value_len, value_len, exif_char_dump(value_ptr, value_len, (intptr_t)dir_start-(intptr_t)info->offset_base+maker_note->offset+displacement)); + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Process %s @0x%04X + 0x%04X=%d: %s", exif_get_sectionname(section_index), (intptr_t)dir_start-(intptr_t)info->offset_base+maker_note->offset+displacement, value_len, value_len, exif_char_dump(value_ptr, value_len, (intptr_t)dir_start-(intptr_t)info->offset_base+maker_note->offset+displacement)); #endif ImageInfo->sections_found |= FOUND_MAKERNOTE; @@ -3298,7 +3308,7 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr * it is faster to use a static buffer there * BUT it offers also the possibility to have * pointers read without the need to free them - * explicitley before returning. */ + * explicitly before returning. */ memset(&cbuf, 0, sizeof(cbuf)); value_ptr = cbuf; } @@ -3330,7 +3340,7 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr #ifdef EXIF_DEBUG dump_data = exif_dump_data(&dump_free, format, components, ImageInfo->motorola_intel, value_ptr); exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, - "Process tag(x%04X=%s,@x%04X + x%04X(=%d)): %s%s %s", + "Process tag(x%04X=%s,@0x%04X + x%04X(=%d)): %s%s %s", tag, exif_get_tagname_debug(tag, tag_table), offset_val+displacement, byte_count, byte_count, (components>1)&&format!=TAG_FMT_UNDEFINED&&format!=TAG_FMT_STRING?"ARRAY OF ":"", exif_get_tagformat(format), dump_data); if (dump_free) { efree(dump_data); @@ -3477,7 +3487,7 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr switch (exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel)) { case 1: ImageInfo->FocalplaneUnits = 25.4; break; /* inch */ case 2: - /* According to the information I was using, 2 measn meters. + /* According to the information I was using, 2 means meters. But looking at the Cannon powershot's files, inches is the only sensible value. */ ImageInfo->FocalplaneUnits = 25.4; @@ -3679,11 +3689,6 @@ static void exif_process_TIFF_in_JPEG(image_info_type *ImageInfo, char *CharBuf, return; } - if (length < 2) { - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Missing TIFF alignment marker"); - return; - } - /* set the thumbnail stuff to nothing so we can test to see if they get set up */ if (memcmp(CharBuf, "II", 2) == 0) { ImageInfo->motorola_intel = 0; @@ -3769,14 +3774,14 @@ static void exif_process_APP12(image_info_type *ImageInfo, char *buffer, size_t * Parse the marker stream until SOS or EOI is seen; */ static bool exif_scan_JPEG_header(image_info_type *ImageInfo) { - int section, sn; + int sn; int marker = 0, last_marker = M_PSEUDO, comment_correction=1; unsigned int ll, lh; uchar *Data; size_t fpos, size, got, itemlen; jpeg_sof_info sof_info; - for(section=0;;section++) { + while (true) { #ifdef EXIF_DEBUG fpos = php_stream_tell(ImageInfo->infile); exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Needing section %d @ 0x%08X", ImageInfo->file.count, fpos); @@ -3810,11 +3815,8 @@ static bool exif_scan_JPEG_header(image_info_type *ImageInfo) fpos = php_stream_tell(ImageInfo->infile); - if (marker == 0xff) { - /* 0xff is legal padding, but if we get that many, something's wrong. */ - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "To many padding bytes"); - return false; - } + /* safety net in case the above algorithm change dramatically, should not trigger */ + ZEND_ASSERT(marker != 0xff); /* Read the length of the section. */ if ((lh = php_stream_getc(ImageInfo->infile)) == (unsigned int)EOF) { @@ -4173,7 +4175,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir } entry_offset = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel); #ifdef EXIF_DEBUG - exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Next IFD: %s @x%04X", exif_get_sectionname(sub_section_index), entry_offset); + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Next IFD: %s @0x%04X", exif_get_sectionname(sub_section_index), entry_offset); #endif exif_process_IFD_in_TIFF(ImageInfo, entry_offset, sub_section_index); if (section_index!=SECTION_THUMBNAIL && entry_tag==TAG_SUB_IFD) { diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index c4a4d91d24348..e82b81fe3bdb1 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -650,14 +650,14 @@ static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ /* Read partial prefix byte */ if (pos != 0) { size_t num_bits = 8 - pos; - mask = ((1U << num_bits) - 1U) << pos; + mask = (1U << num_bits) - 1U; val = (*p++ >> pos) & mask; insert_pos += num_bits; } /* Read full bytes */ while (p < last_p) { - val |= *p++ << insert_pos; + val |= (uint64_t) *p++ << insert_pos; insert_pos += 8; } @@ -665,7 +665,7 @@ static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ if (p == last_p) { size_t num_bits = last_bit % 8 + 1; mask = (1U << num_bits) - 1U; - val |= (*p & mask) << insert_pos; + val |= (uint64_t) (*p & mask) << insert_pos; } return val; @@ -1107,7 +1107,7 @@ static zval *zend_ffi_cdata_get(zend_object *obj, zend_string *member, int read_ if (UNEXPECTED(!zend_string_equals_literal(member, "cdata"))) { zend_throw_error(zend_ffi_exception_ce, "Only 'cdata' property may be read"); - return &EG(uninitialized_zval);; + return &EG(uninitialized_zval); } zend_ffi_cdata_to_zval(cdata, cdata->ptr, type, BP_VAR_R, rv, 0, 0, 0); @@ -1123,13 +1123,13 @@ static zval *zend_ffi_cdata_set(zend_object *obj, zend_string *member, zval *val #if 0 if (UNEXPECTED(!cdata->ptr)) { zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference"); - return &EG(uninitialized_zval);; + return &EG(uninitialized_zval); } #endif if (UNEXPECTED(!zend_string_equals_literal(member, "cdata"))) { zend_throw_error(zend_ffi_exception_ce, "Only 'cdata' property may be set"); - return &EG(uninitialized_zval);; + return &EG(uninitialized_zval); } zend_ffi_zval_to_cdata(cdata->ptr, type, value); @@ -1687,7 +1687,7 @@ static ZEND_COLD void zend_ffi_pass_incompatible(zval *arg, zend_ffi_type *type, zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, buf2.start); } } else { - zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found PHP '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, zend_zval_type_name(arg)); + zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found PHP '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, zend_zval_value_name(arg)); } } } @@ -1714,7 +1714,7 @@ static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *typ zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from type '%s'", buf1.start, buf2.start); } } else { - zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from PHP '%s'", buf1.start, zend_zval_type_name(arg)); + zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from PHP '%s'", buf1.start, zend_zval_value_name(arg)); } } } @@ -1838,7 +1838,7 @@ static zend_object* zend_ffi_add(zend_ffi_cdata *base_cdata, zend_ffi_type *base } /* }}} */ -static zend_result zend_ffi_cdata_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2) /* {{{ */ +static zend_result zend_ffi_cdata_do_operation(uint8_t opcode, zval *result, zval *op1, zval *op2) /* {{{ */ { zend_long offset; @@ -2038,6 +2038,8 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp) } switch (type->kind) { + case ZEND_FFI_TYPE_VOID: + return NULL; case ZEND_FFI_TYPE_BOOL: case ZEND_FFI_TYPE_CHAR: case ZEND_FFI_TYPE_ENUM: @@ -2648,7 +2650,7 @@ static zend_result zend_ffi_pass_arg(zval *arg, zend_ffi_type *type, ffi_type ** zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg); if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) { - *pass_type = zend_ffi_make_fake_struct_type(type);; + *pass_type = zend_ffi_make_fake_struct_type(type); arg_values[n] = cdata->ptr; break; } @@ -2830,7 +2832,11 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */ free_alloca(arg_values, arg_values_use_heap); } - zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1, 0); + if (ZEND_FFI_TYPE(type->func.ret_type)->kind != ZEND_FFI_TYPE_VOID) { + zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1, 0); + } else { + ZVAL_NULL(return_value); + } free_alloca(ret, ret_use_heap); exit: @@ -5532,7 +5538,7 @@ static const zend_ffi_type zend_ffi_type_long_double = {.kind=ZEND_FFI_TYPE_LONG static const zend_ffi_type zend_ffi_type_ptr = {.kind=ZEND_FFI_TYPE_POINTER, .size=sizeof(void*), .align=_Alignof(void*), .pointer.type = (zend_ffi_type*)&zend_ffi_type_void}; -const struct { +static const struct { const char *name; const zend_ffi_type *type; } zend_ffi_types[] = { @@ -5770,7 +5776,7 @@ void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *d if (FFI_G(symbols)) { sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len); if (sym && sym->kind == ZEND_FFI_SYM_TYPE) { - dcl->type = ZEND_FFI_TYPE(sym->type);; + dcl->type = ZEND_FFI_TYPE(sym->type); if (sym->is_const) { dcl->attr |= ZEND_FFI_ATTR_CONST; } @@ -6592,7 +6598,7 @@ void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* { dcl->type = type; /* reset "owned" flag */ zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym); } else { - /* useless declarartion */ + /* useless declaration */ zend_ffi_type_dtor(dcl->type); } } diff --git a/ext/ffi/ffi.stub.php b/ext/ffi/ffi.stub.php index e492963616fb4..f05e938aff91d 100644 --- a/ext/ffi/ffi.stub.php +++ b/ext/ffi/ffi.stub.php @@ -10,6 +10,7 @@ final class FFI /** * @var int * @cvalue __BIGGEST_ALIGNMENT__ + * @link ffi-ffi.constants.biggest-alignment */ public const __BIGGEST_ALIGNMENT__ = UNKNOWN; diff --git a/ext/ffi/ffi_arginfo.h b/ext/ffi/ffi_arginfo.h index 23f678c47a47d..48437128ac32f 100644 --- a/ext/ffi/ffi_arginfo.h +++ b/ext/ffi/ffi_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 63f0ea1625eca4bb8309387d1b5626c10f2d101b */ + * Stub hash: dd91ae1826acbc9b89cd74477edf8784216f1a63 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_cdef, 0, 0, FFI, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, code, IS_STRING, 0, "\"\"") diff --git a/ext/ffi/tests/arrayPointer.phpt b/ext/ffi/tests/arrayPointer.phpt new file mode 100644 index 0000000000000..3a2b06563ade5 --- /dev/null +++ b/ext/ffi/tests/arrayPointer.phpt @@ -0,0 +1,20 @@ +--TEST-- +FFI: Test deprecated use of array helper functions on FFI classes doesn't crash +--EXTENSIONS-- +ffi +--INI-- +ffi.enable=1 +--FILE-- + +--EXPECTF-- +bool(false) +bool(false) +bool(false) +bool(false) diff --git a/ext/ffi/tests/bug79576.phpt b/ext/ffi/tests/bug79576.phpt index 3315b40c93fb6..af30217186407 100644 --- a/ext/ffi/tests/bug79576.phpt +++ b/ext/ffi/tests/bug79576.phpt @@ -4,7 +4,7 @@ Bug #79576 ("TYPE *" shows unhelpful message when type is not defined) ffi --SKIPIF-- --FILE-- +--FILE-- +new('struct MyStruct'); +$test_struct->x = 1023; +$test_values = [0x3fafbfcfdfefff, 0x01020304050607, 0, 0x3fffffffffffff, 0x2ffffffffffff5]; +foreach ($test_values as $test_value) { + $test_struct->y = $test_value; + var_dump($test_struct->y === $test_value); +} +var_dump($test_struct->x); +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +int(1023) diff --git a/ext/ffi/tests/gh10568.phpt b/ext/ffi/tests/gh10568.phpt new file mode 100644 index 0000000000000..9da9334920666 --- /dev/null +++ b/ext/ffi/tests/gh10568.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-10568 (Assertion failure when var_dump'ing void FFI result) +--EXTENSIONS-- +ffi +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +strlen("abc")); +?> +DONE +--EXPECT-- +NULL +DONE diff --git a/ext/ffi/tests/trampoline_reset.phpt b/ext/ffi/tests/trampoline_reset.phpt new file mode 100644 index 0000000000000..3a87ec99d2ae5 --- /dev/null +++ b/ext/ffi/tests/trampoline_reset.phpt @@ -0,0 +1,43 @@ +--TEST-- +Memory corruption when mixing __callStatic() and FFI +--EXTENSIONS-- +ffi +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +fprintf($ffi->stdout, "FFI\n"); +$ffi->fflush($ffi->stdout); +Test::baz(); +?> +--EXPECT-- +foo called +bar called +FFI +baz called diff --git a/ext/fileinfo/fileinfo.c b/ext/fileinfo/fileinfo.c index f0be4c934b16b..a6f3e64db6b45 100644 --- a/ext/fileinfo/fileinfo.c +++ b/ext/fileinfo/fileinfo.c @@ -314,7 +314,7 @@ static void _php_finfo_get_type(INTERNAL_FUNCTION_PARAMETERS, int mode, int mime break; default: - zend_argument_type_error(1, "must be of type resource|string, %s given", zend_zval_type_name(what)); + zend_argument_type_error(1, "must be of type resource|string, %s given", zend_zval_value_name(what)); RETURN_THROWS(); } diff --git a/ext/fileinfo/libmagic.patch b/ext/fileinfo/libmagic.patch index 908cc0608044c..a0c62be524f04 100644 --- a/ext/fileinfo/libmagic.patch +++ b/ext/fileinfo/libmagic.patch @@ -2949,7 +2949,7 @@ diff -u libmagic.orig/softmagic.c libmagic/softmagic.c - if (rc == 0) { - rc = file_regexec(ms, &rx, fmt, 0, 0, 0); - rv = !rc; -+ pattern = zend_string_init("~%[-0-9\\.]*s~", sizeof("~%[-0-9\\.]*s~") - 1, 0); ++ pattern = ZSTR_INIT_LITERAL("~%[-0-9\\.]*s~", 0); + if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) { + rv = -1; + } else { diff --git a/ext/fileinfo/libmagic/softmagic.c b/ext/fileinfo/libmagic/softmagic.c index afb77ba256e48..32d24a37d3df1 100644 --- a/ext/fileinfo/libmagic/softmagic.c +++ b/ext/fileinfo/libmagic/softmagic.c @@ -493,7 +493,7 @@ check_fmt(struct magic_set *ms, const char *fmt) if (strchr(fmt, '%') == NULL) return 0; - pattern = zend_string_init("~%[-0-9\\.]*s~", sizeof("~%[-0-9\\.]*s~") - 1, 0); + pattern = ZSTR_INIT_LITERAL("~%[-0-9\\.]*s~", 0); if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) { rv = -1; } else { diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 1af4f13c65af0..358f4fe7bf86c 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -867,7 +867,7 @@ ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t pat { databuf_t *data = NULL; size_t rcvd; - char arg[11]; + char arg[MAX_LENGTH_OF_LONG]; if (ftp == NULL) { return 0; @@ -964,7 +964,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *inst zend_long size; char *ptr; int ch; - char arg[11]; + char arg[MAX_LENGTH_OF_LONG]; if (ftp == NULL) { return 0; @@ -2057,7 +2057,7 @@ int ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_t path_len, ftptype_t type, zend_long resumepos) { databuf_t *data = NULL; - char arg[11]; + char arg[MAX_LENGTH_OF_LONG]; if (ftp == NULL) { return PHP_FTP_FAILED; @@ -2176,7 +2176,7 @@ int ftp_nb_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type, zend_long startpos) { databuf_t *data = NULL; - char arg[11]; + char arg[MAX_LENGTH_OF_LONG]; if (ftp == NULL) { return 0; diff --git a/ext/ftp/ftp.stub.php b/ext/ftp/ftp.stub.php index 3b8c55871e98e..beab97f2d98e4 100644 --- a/ext/ftp/ftp.stub.php +++ b/ext/ftp/ftp.stub.php @@ -2,7 +2,7 @@ /** @generate-class-entries */ -namespace FTP { +namespace { /** * @var int * @cvalue FTPTYPE_ASCII @@ -59,16 +59,6 @@ */ const FTP_MOREDATA = UNKNOWN; - /** - * @strict-properties - * @not-serializable - */ - final class Connection - { - } -} - -namespace { function ftp_connect(string $hostname, int $port = 21, int $timeout = 90): FTP\Connection|false {} #ifdef HAVE_FTP_SSL @@ -120,7 +110,7 @@ function ftp_fget(FTP\Connection $ftp, $stream, string $remote_filename, int $mo function ftp_nb_fget(FTP\Connection $ftp, $stream, string $remote_filename, int $mode = FTP_BINARY, int $offset = 0): int {} function ftp_pasv(FTP\Connection $ftp, bool $enable): bool {} function ftp_get(FTP\Connection $ftp, string $local_filename, string $remote_filename, int $mode = FTP_BINARY, int $offset = 0): bool {} - function ftp_nb_get(FTP\Connection $ftp, string $local_filename, string $remote_filename, int $mode = FTP_BINARY, int $offset = 0): int {} + function ftp_nb_get(FTP\Connection $ftp, string $local_filename, string $remote_filename, int $mode = FTP_BINARY, int $offset = 0): int|false {} function ftp_nb_continue(FTP\Connection $ftp): int {} /** @param resource $stream */ @@ -145,3 +135,13 @@ function ftp_quit(FTP\Connection $ftp): bool {} function ftp_set_option(FTP\Connection $ftp, int $option, $value): bool {} function ftp_get_option(FTP\Connection $ftp, int $option): int|bool {} } + +namespace FTP { + /** + * @strict-properties + * @not-serializable + */ + final class Connection + { + } +} diff --git a/ext/ftp/ftp_arginfo.h b/ext/ftp/ftp_arginfo.h index 6df8aecc3d73a..b5b2e37161f1d 100644 --- a/ext/ftp/ftp_arginfo.h +++ b/ext/ftp/ftp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 1f66f9b5745bebb0280464b3c1a7f8413c0c6ebc */ + * Stub hash: 072486274a3361dee3655cfd046a293cfb8a2757 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_ftp_connect, 0, 1, FTP\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, hostname, IS_STRING, 0) @@ -107,7 +107,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ftp_get, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ftp_nb_get, 0, 3, IS_LONG, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_ftp_nb_get, 0, 3, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_OBJ_INFO(0, ftp, FTP\\Connection, 0) ZEND_ARG_TYPE_INFO(0, local_filename, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, remote_filename, IS_STRING, 0) diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index 75d106bc48a69..8c6c2e900177c 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -1216,6 +1216,7 @@ PHP_FUNCTION(ftp_close) { zval *z_ftp; php_ftp_object *obj; + bool success = true; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &z_ftp, php_ftp_ce) == FAILURE) { RETURN_THROWS(); @@ -1223,12 +1224,12 @@ PHP_FUNCTION(ftp_close) obj = ftp_object_from_zend_object(Z_OBJ_P(z_ftp)); if (obj->ftp) { - ftp_quit(obj->ftp); + success = ftp_quit(obj->ftp); ftp_close(obj->ftp); obj->ftp = NULL; } - RETURN_TRUE; + RETURN_BOOL(success); } /* }}} */ @@ -1247,7 +1248,7 @@ PHP_FUNCTION(ftp_set_option) switch (option) { case PHP_FTP_OPT_TIMEOUT_SEC: if (Z_TYPE_P(z_value) != IS_LONG) { - zend_argument_type_error(3, "must be of type int for the FTP_TIMEOUT_SEC option, %s given", zend_zval_type_name(z_value)); + zend_argument_type_error(3, "must be of type int for the FTP_TIMEOUT_SEC option, %s given", zend_zval_value_name(z_value)); RETURN_THROWS(); } if (Z_LVAL_P(z_value) <= 0) { @@ -1259,7 +1260,7 @@ PHP_FUNCTION(ftp_set_option) break; case PHP_FTP_OPT_AUTOSEEK: if (Z_TYPE_P(z_value) != IS_TRUE && Z_TYPE_P(z_value) != IS_FALSE) { - zend_argument_type_error(3, "must be of type bool for the FTP_AUTOSEEK option, %s given", zend_zval_type_name(z_value)); + zend_argument_type_error(3, "must be of type bool for the FTP_AUTOSEEK option, %s given", zend_zval_value_name(z_value)); RETURN_THROWS(); } ftp->autoseek = Z_TYPE_P(z_value) == IS_TRUE ? 1 : 0; @@ -1267,7 +1268,7 @@ PHP_FUNCTION(ftp_set_option) break; case PHP_FTP_OPT_USEPASVADDRESS: if (Z_TYPE_P(z_value) != IS_TRUE && Z_TYPE_P(z_value) != IS_FALSE) { - zend_argument_type_error(3, "must be of type bool for the FTP_USEPASVADDRESS option, %s given", zend_zval_type_name(z_value)); + zend_argument_type_error(3, "must be of type bool for the FTP_USEPASVADDRESS option, %s given", zend_zval_value_name(z_value)); RETURN_THROWS(); } ftp->usepasvaddress = Z_TYPE_P(z_value) == IS_TRUE ? 1 : 0; diff --git a/ext/ftp/tests/004.phpt b/ext/ftp/tests/004.phpt index a7ef2672a7ea6..fde0b50903992 100644 --- a/ext/ftp/tests/004.phpt +++ b/ext/ftp/tests/004.phpt @@ -28,4 +28,4 @@ bool(true) Warning: ftp_login(): Not logged in. in %s on line %d bool(false) -bool(true) +bool(false) diff --git a/ext/ftp/tests/gh10521.phpt b/ext/ftp/tests/gh10521.phpt new file mode 100644 index 0000000000000..1dc40d4004271 --- /dev/null +++ b/ext/ftp/tests/gh10521.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-10521 (ftp_get/ftp_nb_get resumepos offset is maximum 10GB) +--EXTENSIONS-- +ftp +pcntl +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +bool(true) + +%s: ftp_fget(): Can't open data connection (12345678910). in %s on line %d + +%s: ftp_fget(): Can't open data connection (9223372036854775807). in %s on line %d diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc index 56c78ed3907c5..04a87f6f867db 100644 --- a/ext/ftp/tests/server.inc +++ b/ext/ftp/tests/server.inc @@ -183,6 +183,7 @@ if ($pid) { fputs($s, "200 OK\r\n"); } elseif ($buf === "QUIT\r\n") { + fputs($s, "221 Bye\r\n"); break; } elseif (preg_match("~^PORT (\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\r\n$~", $buf, $m)) { @@ -386,6 +387,10 @@ if ($pid) { case "/bug73457": fputs($s, "150 File status okay; about to open data connection.\r\n"); break; + case "gh10521": + // Just a side channel for getting the received file size. + fputs($s, "425 Can't open data connection (".$GLOBALS['rest_pos'].").\r\n"); + break; default: fputs($s, "550 {$matches[1]}: No such file or directory \r\n"); diff --git a/ext/gd/config.m4 b/ext/gd/config.m4 index 0a175d11d52e7..b342074027059 100644 --- a/ext/gd/config.m4 +++ b/ext/gd/config.m4 @@ -189,7 +189,7 @@ dnl Various checks for GD features PHP_NEW_EXTENSION(gd, gd.c $extra_sources, $ext_shared,, \\$(GD_CFLAGS)) PHP_ADD_BUILD_DIR($ext_builddir/libgd) - GD_CFLAGS="-I$ext_srcdir/libgd $GD_CFLAGS" + GD_CFLAGS="-Wno-strict-prototypes -I$ext_srcdir/libgd $GD_CFLAGS" GD_HEADER_DIRS="ext/gd/ ext/gd/libgd/" PHP_TEST_BUILD(foobar, [], [ diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 227698f92ba5c..ef53592d3467d 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -1720,38 +1720,35 @@ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char { zval *imgind; char *file = NULL; - zend_long quality = 0, type = 0; + zend_long quality = 128, type = 1; gdImagePtr im; FILE *fp; size_t file_len = 0; - int argc = ZEND_NUM_ARGS(); - int q = -1, t = 1; /* The quality parameter for gd2 stands for chunk size */ switch (image_type) { case PHP_GDIMG_TYPE_GD: - if (zend_parse_parameters(argc, "O|p!", &imgind, gd_image_ce, &file, &file_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|p!", &imgind, gd_image_ce, &file, &file_len) == FAILURE) { RETURN_THROWS(); } break; case PHP_GDIMG_TYPE_GD2: - if (zend_parse_parameters(argc, "O|p!ll", &imgind, gd_image_ce, &file, &file_len, &quality, &type) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|p!ll", &imgind, gd_image_ce, &file, &file_len, &quality, &type) == FAILURE) { RETURN_THROWS(); } break; EMPTY_SWITCH_DEFAULT_CASE() } - im = php_gd_libgdimageptr_from_zval_p(imgind); - - if (argc >= 3) { - q = quality; - if (argc == 4) { - t = type; - } + /* quality must fit in an int */ + if (quality < INT_MIN || quality > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Argument #3 ($chunk_size) must be between %d and %d", INT_MIN, INT_MAX); + RETURN_FALSE; } + im = php_gd_libgdimageptr_from_zval_p(imgind); + if (file_len) { PHP_GD_CHECK_OPEN_BASEDIR(file, "Invalid filename"); @@ -1766,10 +1763,10 @@ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char gdImageGd(im, fp); break; case PHP_GDIMG_TYPE_GD2: - if (q == -1) { - q = 128; + if (quality == -1) { + quality = 128; } - gdImageGd2(im, fp, q, t); + gdImageGd2(im, fp, quality, type); break; EMPTY_SWITCH_DEFAULT_CASE() } @@ -1792,10 +1789,10 @@ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char gdImageGd(im, tmp); break; case PHP_GDIMG_TYPE_GD2: - if (q == -1) { - q = 128; + if (quality == -1) { + quality = 128; } - gdImageGd2(im, tmp, q, t); + gdImageGd2(im, tmp, quality, type); break; EMPTY_SWITCH_DEFAULT_CASE() } @@ -3987,9 +3984,7 @@ static int _php_image_output_putbuf(struct gdIOCtx *ctx, const void* buf, int l) static void _php_image_output_ctxfree(struct gdIOCtx *ctx) /* {{{ */ { - if(ctx) { - efree(ctx); - } + efree(ctx); } /* }}} */ static void _php_image_stream_putc(struct gdIOCtx *ctx, int c) /* {{{ */ { @@ -4009,21 +4004,16 @@ static void _php_image_stream_ctxfree(struct gdIOCtx *ctx) /* {{{ */ if(ctx->data) { ctx->data = NULL; } - if(ctx) { - efree(ctx); - } + efree(ctx); } /* }}} */ static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */ { - if(ctx->data) { php_stream_close((php_stream *) ctx->data); ctx->data = NULL; } - if(ctx) { - efree(ctx); - } + efree(ctx); } /* }}} */ static gdIOCtx *create_stream_context_from_zval(zval *to_zval) { @@ -4047,7 +4037,7 @@ static gdIOCtx *create_stream_context_from_zval(zval *to_zval) { return NULL; } } else { - zend_argument_type_error(2, "must be a file name or a stream resource, %s given", zend_zval_type_name(to_zval)); + zend_argument_type_error(2, "must be a file name or a stream resource, %s given", zend_zval_value_name(to_zval)); return NULL; } diff --git a/ext/gd/gd.stub.php b/ext/gd/gd.stub.php index e3b45cb12f8e7..0c8a714068ad4 100644 --- a/ext/gd/gd.stub.php +++ b/ext/gd/gd.stub.php @@ -541,6 +541,7 @@ function imagesetbrush(GdImage $image, GdImage $brush): bool {} /** @refcount 1 */ function imagecreate(int $width, int $height): GdImage|false {} +/** @compile-time-eval */ function imagetypes(): int {} /** @refcount 1 */ @@ -628,7 +629,7 @@ function imagewbmp(GdImage $image, $file = null, ?int $foreground_color = null): function imagegd(GdImage $image, ?string $file = null): bool {} -function imagegd2(GdImage $image, ?string $file = null, int $chunk_size = UNKNOWN, int $mode = UNKNOWN): bool {} +function imagegd2(GdImage $image, ?string $file = null, int $chunk_size = 128, int $mode = IMG_GD2_RAW): bool {} #ifdef HAVE_GD_BMP /** @param resource|string|null $file */ diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h index 9e4ac86455928..cf6bcefa7b3ad 100644 --- a/ext/gd/gd_arginfo.h +++ b/ext/gd/gd_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 68be83247e5e142879ce1bc4340c1c5b8a8f670a */ + * Stub hash: 810838932a482065c48ab715857062c071db31fd */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gd_info, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -265,8 +265,8 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imagegd2, 0, 1, _IS_BOOL, 0) ZEND_ARG_OBJ_INFO(0, image, GdImage, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, file, IS_STRING, 1, "null") - ZEND_ARG_TYPE_INFO(0, chunk_size, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, chunk_size, IS_LONG, 0, "128") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "IMG_GD2_RAW") ZEND_END_ARG_INFO() #if defined(HAVE_GD_BMP) @@ -747,7 +747,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(imagesettile, arginfo_imagesettile) ZEND_FE(imagesetbrush, arginfo_imagesetbrush) ZEND_FE(imagecreate, arginfo_imagecreate) - ZEND_FE(imagetypes, arginfo_imagetypes) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(imagetypes, arginfo_imagetypes) ZEND_FE(imagecreatefromstring, arginfo_imagecreatefromstring) #if defined(HAVE_GD_AVIF) ZEND_FE(imagecreatefromavif, arginfo_imagecreatefromavif) @@ -974,25 +974,25 @@ static void register_gd_symbols(int module_number) REGISTER_STRING_CONSTANT("GD_EXTRA_VERSION", GD_EXTRA_VERSION, CONST_PERSISTENT); #endif #if defined(HAVE_GD_PNG) - REGISTER_LONG_CONSTANT("PNG_NO_FILTER", 0, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PNG_NO_FILTER", 0x0, CONST_PERSISTENT); #endif #if defined(HAVE_GD_PNG) - REGISTER_LONG_CONSTANT("PNG_FILTER_NONE", 8, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PNG_FILTER_NONE", 0x8, CONST_PERSISTENT); #endif #if defined(HAVE_GD_PNG) - REGISTER_LONG_CONSTANT("PNG_FILTER_SUB", 16, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PNG_FILTER_SUB", 0x10, CONST_PERSISTENT); #endif #if defined(HAVE_GD_PNG) - REGISTER_LONG_CONSTANT("PNG_FILTER_UP", 32, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PNG_FILTER_UP", 0x20, CONST_PERSISTENT); #endif #if defined(HAVE_GD_PNG) - REGISTER_LONG_CONSTANT("PNG_FILTER_AVG", 64, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PNG_FILTER_AVG", 0x40, CONST_PERSISTENT); #endif #if defined(HAVE_GD_PNG) - REGISTER_LONG_CONSTANT("PNG_FILTER_PAETH", 128, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PNG_FILTER_PAETH", 0x80, CONST_PERSISTENT); #endif #if defined(HAVE_GD_PNG) - REGISTER_LONG_CONSTANT("PNG_ALL_FILTERS", 248, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PNG_ALL_FILTERS", 0x8 | 0x10 | 0x20 | 0x40 | 0x80, CONST_PERSISTENT); #endif } diff --git a/ext/gd/libgd/gd_bmp.c b/ext/gd/libgd/gd_bmp.c index 00903d5ff8dcc..a80904a62914d 100644 --- a/ext/gd/libgd/gd_bmp.c +++ b/ext/gd/libgd/gd_bmp.c @@ -152,7 +152,7 @@ void gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression) gdBMPPutInt(out, im->colorsTotal); /* colours used */ gdBMPPutInt(out, 0); /* important colours */ - /* The line must be divisible by 4, else its padded with NULLs */ + /* The line must be divisible by 4, else it's padded with NULLs */ padding = ((int)(im->trueColor ? 3 : 1) * im->sx) % 4; if (padding) { padding = 4 - padding; @@ -646,7 +646,7 @@ static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info) return 1; } - /* Lets seek the next 24 pointless bytes, we don't care too much about it */ + /* Let's seek the next 24 pointless bytes, we don't care too much about it */ if (!gdGetBuf(useless_bytes, 24, infile)) { return 1; } @@ -716,7 +716,7 @@ static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, b } } - /* The line must be divisible by 4, else its padded with NULLs */ + /* The line must be divisible by 4, else it's padded with NULLs */ padding = ((int)(info->depth / 8) * info->width) % 4; if (padding) { padding = 4 - padding; @@ -883,7 +883,7 @@ static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp } } - /* The line must be divisible by 4, else its padded with NULLs */ + /* The line must be divisible by 4, else it's padded with NULLs */ padding = ((int)ceil(0.5 * info->width)) % 4; if (padding) { padding = 4 - padding; @@ -970,7 +970,7 @@ static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp } } - /* The line must be divisible by 4, else its padded with NULLs */ + /* The line must be divisible by 4, else it's padded with NULLs */ padding = (1 * info->width) % 4; if (padding) { padding = 4 - padding; diff --git a/ext/gd/tests/bug77272.phpt b/ext/gd/tests/bug77272.phpt index 4de532a5c7b3e..fc5ee464a07bb 100644 --- a/ext/gd/tests/bug77272.phpt +++ b/ext/gd/tests/bug77272.phpt @@ -8,6 +8,7 @@ gd --FILE-- GMP_MAX_BASE)) { + zend_argument_value_error(arg_num, "must be between 2 and %d", GMP_MAX_BASE); + return false; + } + + return true; +} + +static zend_result gmp_initialize_number(mpz_ptr gmp_number, const zend_string *arg_str, zend_long arg_l, zend_long base) +{ + if (arg_str) { + return convert_zstr_to_gmp(gmp_number, arg_str, base, 1); + } + + mpz_set_si(gmp_number, arg_l); + return SUCCESS; +} + /* {{{ Initializes GMP number */ ZEND_FUNCTION(gmp_init) { @@ -876,18 +896,14 @@ ZEND_FUNCTION(gmp_init) Z_PARAM_LONG(base) ZEND_PARSE_PARAMETERS_END(); - if (base && (base < 2 || base > GMP_MAX_BASE)) { - zend_argument_value_error(2, "must be between 2 and %d", GMP_MAX_BASE); + if (!gmp_verify_base(base, 2)) { RETURN_THROWS(); } INIT_GMP_RETVAL(gmp_number); - if (arg_str) { - if (convert_zstr_to_gmp(gmp_number, arg_str, base, 1) == FAILURE) { - RETURN_THROWS(); - } - } else { - mpz_set_si(gmp_number, arg_l); + + if (gmp_initialize_number(gmp_number, arg_str, arg_l, base) == FAILURE) { + RETURN_THROWS(); } } /* }}} */ @@ -1713,7 +1729,11 @@ static void gmp_init_random(void) /* Initialize */ gmp_randinit_mt(GMPG(rand_state)); /* Seed */ - gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED()); + zend_long seed = 0; + if (php_random_bytes_silent(&seed, sizeof(zend_long)) == FAILURE) { + seed = GENERATE_SEED(); + } + gmp_randseed_ui(GMPG(rand_state), seed); GMPG(rand_initialized) = 1; } @@ -2021,6 +2041,30 @@ ZEND_FUNCTION(gmp_scan1) } /* }}} */ +ZEND_METHOD(GMP, __construct) +{ + zend_string *arg_str = NULL; + zend_long arg_l = 0; + zend_long base = 0; + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_LONG(arg_str, arg_l) + Z_PARAM_LONG(base) + ZEND_PARSE_PARAMETERS_END(); + + if (!gmp_verify_base(base, 2)) { + RETURN_THROWS(); + } + + return_value = ZEND_THIS; + mpz_ptr gmp_number = GET_GMP_FROM_ZVAL(ZEND_THIS); + + if (gmp_initialize_number(gmp_number, arg_str, arg_l, base) == FAILURE) { + RETURN_THROWS(); + } +} + ZEND_METHOD(GMP, __serialize) { ZEND_PARSE_PARAMETERS_NONE(); diff --git a/ext/gmp/gmp.stub.php b/ext/gmp/gmp.stub.php index 664fc6ded264c..ff5b5afb4055b 100644 --- a/ext/gmp/gmp.stub.php +++ b/ext/gmp/gmp.stub.php @@ -59,6 +59,8 @@ class GMP { + public function __construct(int|string $num = 0, int $base = 0) {} + public function __serialize(): array {} public function __unserialize(array $data): void {} diff --git a/ext/gmp/gmp_arginfo.h b/ext/gmp/gmp_arginfo.h index c0e029f6fc396..e9a339f02a333 100644 --- a/ext/gmp/gmp_arginfo.h +++ b/ext/gmp/gmp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 64a40a366b87a96a291de6a474e60c8d98d15da1 */ + * Stub hash: d52f82c7084a8122fe07c91eb6d4ab6030daa27d */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_init, 0, 1, GMP, 0) ZEND_ARG_TYPE_MASK(0, num, MAY_BE_LONG|MAY_BE_STRING, NULL) @@ -184,6 +184,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_binomial, 0, 2, GMP, 0) ZEND_ARG_TYPE_INFO(0, k, IS_LONG, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_GMP___construct, 0, 0, 0) + ZEND_ARG_TYPE_MASK(0, num, MAY_BE_LONG|MAY_BE_STRING, "0") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, base, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_GMP___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -242,6 +247,7 @@ ZEND_FUNCTION(gmp_popcount); ZEND_FUNCTION(gmp_hamdist); ZEND_FUNCTION(gmp_nextprime); ZEND_FUNCTION(gmp_binomial); +ZEND_METHOD(GMP, __construct); ZEND_METHOD(GMP, __serialize); ZEND_METHOD(GMP, __unserialize); @@ -303,6 +309,7 @@ static const zend_function_entry ext_functions[] = { static const zend_function_entry class_GMP_methods[] = { + ZEND_ME(GMP, __construct, arginfo_class_GMP___construct, ZEND_ACC_PUBLIC) ZEND_ME(GMP, __serialize, arginfo_class_GMP___serialize, ZEND_ACC_PUBLIC) ZEND_ME(GMP, __unserialize, arginfo_class_GMP___unserialize, ZEND_ACC_PUBLIC) ZEND_FE_END diff --git a/ext/gmp/tests/bug74670.phpt b/ext/gmp/tests/bug74670.phpt index 517b09ce7f588..7180266b227d1 100644 --- a/ext/gmp/tests/bug74670.phpt +++ b/ext/gmp/tests/bug74670.phpt @@ -8,5 +8,5 @@ $str = 'C:3:"GMP":4:{s:6666666666:""}'; var_dump(unserialize($str)); ?> --EXPECTF-- -Warning: unserialize(): Error at offset 13 of 29 bytes in %s on line %d +Warning: unserialize(): Error at offset 17 of 29 bytes in %s on line %d bool(false) diff --git a/ext/gmp/tests/construct.phpt b/ext/gmp/tests/construct.phpt new file mode 100644 index 0000000000000..11c80b3d9ed82 --- /dev/null +++ b/ext/gmp/tests/construct.phpt @@ -0,0 +1,51 @@ +--TEST-- +Constructor for GMP +--EXTENSIONS-- +gmp +--FILE-- +getMessage() . "\n"; +} +try { + var_dump(new GMP("", 10)); +} catch (ValueError $e) { + echo $e->getMessage() . "\n"; +} +try { + var_dump(new GMP("hello")); +} catch (ValueError $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +object(GMP)#1 (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#1 (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#1 (1) { + ["num"]=> + string(3) "123" +} +object(GMP)#1 (1) { + ["num"]=> + string(3) "170" +} +object(GMP)#1 (1) { + ["num"]=> + string(1) "6" +} +GMP::__construct(): Argument #2 ($base) must be between 2 and 62 +GMP::__construct(): Argument #1 ($num) is not an integer string +GMP::__construct(): Argument #1 ($num) is not an integer string diff --git a/ext/gmp/tests/gmp_dynamic_property.phpt b/ext/gmp/tests/gmp_dynamic_property.phpt index 547fe51a7f6a3..ff3d4ac94e012 100644 --- a/ext/gmp/tests/gmp_dynamic_property.phpt +++ b/ext/gmp/tests/gmp_dynamic_property.phpt @@ -5,7 +5,7 @@ gmp --FILE-- {1} = 123; $serialized = serialize($g); diff --git a/ext/gmp/tests/gmp_strict_types.phpt b/ext/gmp/tests/gmp_strict_types.phpt index a63f2ef5059db..006f06465c536 100644 --- a/ext/gmp/tests/gmp_strict_types.phpt +++ b/ext/gmp/tests/gmp_strict_types.phpt @@ -51,7 +51,7 @@ object(GMP)#2 (1) { string(1) "1" } gmp_abs(): Argument #1 ($num) must be of type GMP|string|int, float given -gmp_abs(): Argument #1 ($num) must be of type GMP|string|int, bool given -gmp_abs(): Argument #1 ($num) must be of type GMP|string|int, bool given +gmp_abs(): Argument #1 ($num) must be of type GMP|string|int, false given +gmp_abs(): Argument #1 ($num) must be of type GMP|string|int, true given gmp_abs(): Argument #1 ($num) must be of type GMP|string|int, null given gmp_abs(): Argument #1 ($num) must be of type GMP|string|int, array given diff --git a/ext/hash/hash.c b/ext/hash/hash.c index 27578d27c6965..2db70351461b4 100644 --- a/ext/hash/hash.c +++ b/ext/hash/hash.c @@ -1119,12 +1119,12 @@ PHP_FUNCTION(hash_equals) /* We only allow comparing string to prevent unexpected results. */ if (Z_TYPE_P(known_zval) != IS_STRING) { - zend_argument_type_error(1, "must be of type string, %s given", zend_zval_type_name(known_zval)); + zend_argument_type_error(1, "must be of type string, %s given", zend_zval_value_name(known_zval)); RETURN_THROWS(); } if (Z_TYPE_P(user_zval) != IS_STRING) { - zend_argument_type_error(2, "must be of type string, %s given", zend_zval_type_name(user_zval)); + zend_argument_type_error(2, "must be of type string, %s given", zend_zval_value_name(user_zval)); RETURN_THROWS(); } diff --git a/ext/hash/hash_fnv.c b/ext/hash/hash_fnv.c index 37dc1f22dc7c3..92d4922bd810e 100644 --- a/ext/hash/hash_fnv.c +++ b/ext/hash/hash_fnv.c @@ -161,7 +161,7 @@ PHP_HASH_API void PHP_FNV164Final(unsigned char digest[8], PHP_FNV164_CTX * cont * alternate - if > 0 use the alternate version * * returns: - * 32 bit hash as a static hash type + * 32-bit hash as a static hash type */ static uint32_t fnv_32_buf(void *buf, size_t len, uint32_t hval, int alternate) @@ -204,7 +204,7 @@ fnv_32_buf(void *buf, size_t len, uint32_t hval, int alternate) * alternate - if > 0 use the alternate version * * returns: - * 64 bit hash as a static hash type + * 64-bit hash as a static hash type */ static uint64_t fnv_64_buf(void *buf, size_t len, uint64_t hval, int alternate) diff --git a/ext/hash/hash_md.c b/ext/hash/hash_md.c index a065f417e5395..eef2af3526608 100644 --- a/ext/hash/hash_md.c +++ b/ext/hash/hash_md.c @@ -238,7 +238,7 @@ PHP_HASH_API void PHP_MD4Update(PHP_MD4_CTX * context, const unsigned char *inpu /* }}} */ /* {{{ PHP_MD4Final - MD4 finalization. Ends an MD4 message-digest operation, writing the + MD4 finalization. Ends an MD4 message-digest operation, writing the message digest and zeroizing the context. */ PHP_HASH_API void PHP_MD4Final(unsigned char digest[16], PHP_MD4_CTX * context) diff --git a/ext/hash/hash_snefru.c b/ext/hash/hash_snefru.c index ee024652314b8..c1dbc3ae57a6c 100644 --- a/ext/hash/hash_snefru.c +++ b/ext/hash/hash_snefru.c @@ -39,7 +39,7 @@ void ph(uint32_t h[16]) static inline void Snefru(uint32_t input[16]) { - static int shifts[4] = {16, 8, 16, 24}; + static const int shifts[4] = {16, 8, 16, 24}; int b, index, rshift, lshift; const uint32_t *t0,*t1; uint32_t SBE,B00,B01,B02,B03,B04,B05,B06,B07,B08,B09,B10,B11,B12,B13,B14,B15; diff --git a/ext/hash/hash_xxhash.c b/ext/hash/hash_xxhash.c index 7ecedd81287ce..8a155c9862271 100644 --- a/ext/hash/hash_xxhash.c +++ b/ext/hash/hash_xxhash.c @@ -174,7 +174,9 @@ zend_always_inline static void _PHP_XXH3_Init(PHP_XXH3_64_CTX *ctx, HashTable *a func_init_seed(&ctx->s, (XXH64_hash_t)Z_LVAL_P(_seed)); return; } else if (_secret) { - convert_to_string(_secret); + if (!try_convert_to_string(_secret)) { + return; + } size_t len = Z_STRLEN_P(_secret); if (len < PHP_XXH3_SECRET_SIZE_MIN) { zend_throw_error(NULL, "%s: Secret length must be >= %u bytes, %zu bytes passed", algo_name, XXH3_SECRET_SIZE_MIN, len); diff --git a/ext/hash/php_hash_fnv.h b/ext/hash/php_hash_fnv.h index b05e70a8ad21e..e9d1ce8d0b442 100644 --- a/ext/hash/php_hash_fnv.h +++ b/ext/hash/php_hash_fnv.h @@ -18,12 +18,10 @@ #define PHP_HASH_FNV_H #define PHP_FNV1_32_INIT ((uint32_t)0x811c9dc5) -#define PHP_FNV1_32A_INIT PHP_FNV1_32_INIT #define PHP_FNV_32_PRIME ((uint32_t)0x01000193) #define PHP_FNV1_64_INIT ((uint64_t)0xcbf29ce484222325ULL) -#define PHP_FNV1A_64_INIT FNV1_64_INIT #define PHP_FNV_64_PRIME ((uint64_t)0x100000001b3ULL) diff --git a/ext/hash/tests/xxhash_secret.phpt b/ext/hash/tests/xxhash_secret.phpt index 91e7d929d323d..6f1efbe6c90a6 100644 --- a/ext/hash/tests/xxhash_secret.phpt +++ b/ext/hash/tests/xxhash_secret.phpt @@ -3,6 +3,13 @@ Hash: xxHash secret --FILE-- getMessage()); } + try { + $ctx = hash_init($a, options: ["secret" => new StringableThrowingClass()]); + } catch (Throwable $e) { + var_dump($e->getMessage()); + } + try { $ctx = hash_init($a, options: ["secret" => str_repeat('a', 17)]); } catch (Throwable $e) { @@ -35,8 +48,10 @@ foreach (["xxh3", "xxh128"] as $a) { ?> --EXPECT-- string(67) "xxh3: Only one of seed or secret is to be passed for initialization" +string(23) "exception in __toString" string(57) "xxh3: Secret length must be >= 136 bytes, 17 bytes passed" 8028aa834c03557a == 8028aa834c03557a == true string(69) "xxh128: Only one of seed or secret is to be passed for initialization" +string(23) "exception in __toString" string(59) "xxh128: Secret length must be >= 136 bytes, 17 bytes passed" 54279097795e7218093a05d4d781cbb9 == 54279097795e7218093a05d4d781cbb9 == true diff --git a/ext/hash/xxhash/xxhash.h b/ext/hash/xxhash/xxhash.h index 7850622aae44a..8e816c0584ebd 100644 --- a/ext/hash/xxhash/xxhash.h +++ b/ext/hash/xxhash/xxhash.h @@ -1375,6 +1375,23 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, */ # define XXH_NO_INLINE_HINTS 0 +/*! + * @def XXH3_INLINE_SECRET + * @brief Determines whether to inline the XXH3 withSecret code. + * + * When the secret size is known, the compiler can improve the performance + * of XXH3_64bits_withSecret() and XXH3_128bits_withSecret(). + * + * However, if the secret size is not known, it doesn't have any benefit. This + * happens when xxHash is compiled into a global symbol. Therefore, if + * @ref XXH_INLINE_ALL is *not* defined, this will be defined to 0. + * + * Additionally, this defaults to 0 on GCC 12+, which has an issue with function pointers + * that are *sometimes* force inline on -Og, and it is impossible to automatically + * detect this optimization level. + */ +# define XXH3_INLINE_SECRET 0 + /*! * @def XXH32_ENDJMP * @brief Whether to use a jump for `XXH32_finalize`. @@ -1439,6 +1456,15 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, # endif #endif +#ifndef XXH3_INLINE_SECRET +# if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12) \ + || !defined(XXH_INLINE_ALL) +# define XXH3_INLINE_SECRET 0 +# else +# define XXH3_INLINE_SECRET 1 +# endif +#endif + #ifndef XXH32_ENDJMP /* generally preferable for performance */ # define XXH32_ENDJMP 0 @@ -1515,6 +1541,11 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) # define XXH_NO_INLINE static #endif +#if XXH3_INLINE_SECRET +# define XXH3_WITH_SECRET_INLINE XXH_FORCE_INLINE +#else +# define XXH3_WITH_SECRET_INLINE XXH_NO_INLINE +#endif /* ************************************* @@ -1546,8 +1577,7 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) /* note: use after variable declarations */ #ifndef XXH_STATIC_ASSERT # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ -# include -# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { _Static_assert((c),m); } while(0) # elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) # else @@ -4466,7 +4496,7 @@ XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, * so that the compiler can properly optimize the vectorized loop. * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. */ -XXH_FORCE_INLINE XXH64_hash_t +XXH3_WITH_SECRET_INLINE XXH64_hash_t XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { @@ -5264,7 +5294,7 @@ XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, * It's important for performance to pass @secretLen (when it's static) * to the compiler, so that it can properly optimize the vectorized loop. */ -XXH_FORCE_INLINE XXH128_hash_t +XXH3_WITH_SECRET_INLINE XXH128_hash_t XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) diff --git a/ext/iconv/config.m4 b/ext/iconv/config.m4 index ac57c81e7d472..3cf400fe96231 100644 --- a/ext/iconv/config.m4 +++ b/ext/iconv/config.m4 @@ -30,7 +30,8 @@ if test "$PHP_ICONV" != "no"; then AC_MSG_CHECKING([if using GNU libiconv]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include -int main() { +#include +int main(void) { printf("%d", _libiconv_version); return 0; } @@ -90,7 +91,7 @@ int main() { #include #include -int main() { +int main(void) { iconv_t cd; cd = iconv_open( "*blahblah*", "*blahblahblah*" ); if (cd == (iconv_t)(-1)) { @@ -117,7 +118,7 @@ int main() { #include #include -int main() { +int main(void) { iconv_t cd = iconv_open( "UTF-8//IGNORE", "UTF-8" ); if(cd == (iconv_t)-1) { return 1; diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index c0286de7bb1ec..c2ed3f258bc88 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -906,7 +906,7 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn char *out_p; size_t out_left; zend_string *encoded = NULL; - static int qp_table[256] = { + static const int qp_table[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x00 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 */ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20 */ @@ -2236,11 +2236,11 @@ PHP_FUNCTION(iconv_set_encoding) } if(zend_string_equals_literal_ci(type, "input_encoding")) { - name = zend_string_init("iconv.input_encoding", sizeof("iconv.input_encoding") - 1, 0); + name = ZSTR_INIT_LITERAL("iconv.input_encoding", 0); } else if(zend_string_equals_literal_ci(type, "output_encoding")) { - name = zend_string_init("iconv.output_encoding", sizeof("iconv.output_encoding") - 1, 0); + name = ZSTR_INIT_LITERAL("iconv.output_encoding", 0); } else if(zend_string_equals_literal_ci(type, "internal_encoding")) { - name = zend_string_init("iconv.internal_encoding", sizeof("iconv.internal_encoding") - 1, 0); + name = ZSTR_INIT_LITERAL("iconv.internal_encoding", 0); } else { RETURN_FALSE; } diff --git a/ext/imap/config.m4 b/ext/imap/config.m4 index 5086a312d093b..3c4782cd552fb 100644 --- a/ext/imap/config.m4 +++ b/ext/imap/config.m4 @@ -17,6 +17,18 @@ AC_DEFUN([IMAP_LIB_CHK],[ ]) dnl PHP_IMAP_TEST_BUILD(function, action-if-ok, action-if-not-ok, extra-libs, extra-source) +dnl +dnl The UW-IMAP c-client library was not originally designed to be a +dnl shared library. The mm_foo functions are callbacks, and are required +dnl to be implemented by the program that is linking to c-client. This +dnl macro does the work of defining them all to no-ops for you. Note +dnl that PHP_TEST_BUILD is a link test; the undefined symbols will only +dnl cause problems if you actually try to link with c-client. For +dnl example, if your test is trivial enough to be optimized out, and if +dnl you link with --as-needed, the test/library may be omitted entirely +dnl from the final executable. In that case linking will of course +dnl succeed, but your luck won't necessarily apply at lower optimization +dnl levels or systems where --as-needed is not used. AC_DEFUN([PHP_IMAP_TEST_BUILD], [ PHP_TEST_BUILD([$1], [$2], [$3], [$4], [$5] [ @@ -229,15 +241,23 @@ if test "$PHP_IMAP" != "no"; then AC_DEFINE(HAVE_IMAP_AUTH_GSS, 1, [ ]) ], [], $TST_LIBS) - dnl Check if utf8_to_mutf7 exists. We need to do some gymnastics because - dnl utf8_to_mutf7 takes an argument and will segfault without it. We - dnl therefore test another function utf8_to_mutf7_php() which calls - dnl the utf8_to_mutf7() function with the empty string as an argument. - PHP_IMAP_TEST_BUILD(utf8_to_mutf7_php, [ - AC_DEFINE(HAVE_IMAP_MUTF7, 1, [ ]) - ], [], $TST_LIBS, [ - char utf8_to_mutf7_php(){ return utf8_to_mutf7(""); } - ]) + dnl Check if utf8_to_mutf7 exists. + old_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} -I${IMAP_INC_DIR}" + AC_LANG_PUSH(C) + AC_CACHE_CHECK(for utf8_to_mutf7, ac_cv_utf8_to_mutf7, + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ + unsigned char c = '\0'; + utf8_to_mutf7(&c); + ]])],[ + AC_DEFINE(HAVE_IMAP_MUTF7, 1, [ ]) + ac_cv_utf8_to_mutf7=yes + ],[ + ac_cv_utf8_to_mutf7=no + ]) + ) + AC_LANG_POP + AC_MSG_CHECKING(whether rfc822_output_address_list function present) PHP_TEST_BUILD(foobar, [ diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c index 38ebd7b61d93d..7723669417af3 100644 --- a/ext/imap/php_imap.c +++ b/ext/imap/php_imap.c @@ -525,11 +525,9 @@ PHP_RINIT_FUNCTION(imap) } /* }}} */ -/* {{{ PHP_RSHUTDOWN_FUNCTION */ -PHP_RSHUTDOWN_FUNCTION(imap) +static void free_errorlist(void) { ERRORLIST *ecur = NIL; - STRINGLIST *acur = NIL; if (IMAPG(imap_errorstack) != NIL) { /* output any remaining errors at their original error level */ @@ -545,6 +543,11 @@ PHP_RSHUTDOWN_FUNCTION(imap) mail_free_errorlist(&IMAPG(imap_errorstack)); IMAPG(imap_errorstack) = NIL; } +} + +static void free_stringlist(void) +{ + STRINGLIST *acur = NIL; if (IMAPG(imap_alertstack) != NIL) { /* output any remaining alerts at E_NOTICE level */ @@ -560,6 +563,13 @@ PHP_RSHUTDOWN_FUNCTION(imap) mail_free_stringlist(&IMAPG(imap_alertstack)); IMAPG(imap_alertstack) = NIL; } +} + +/* {{{ PHP_RSHUTDOWN_FUNCTION */ +PHP_RSHUTDOWN_FUNCTION(imap) +{ + free_errorlist(); + free_stringlist(); return SUCCESS; } /* }}} */ @@ -812,7 +822,7 @@ PHP_FUNCTION(imap_append) } if (internal_date) { - zend_string *regex = zend_string_init("/[0-3][0-9]-((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))-[0-9]{4} [0-2][0-9]:[0-5][0-9]:[0-5][0-9] [+-][0-9]{4}/", sizeof("/[0-3][0-9]-((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))-[0-9]{4} [0-2][0-9]:[0-5][0-9]:[0-5][0-9] [+-][0-9]{4}/") - 1, 0); + zend_string *regex = ZSTR_INIT_LITERAL("/[0-3][0-9]-((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))-[0-9]{4} [0-2][0-9]:[0-5][0-9]:[0-5][0-9] [+-][0-9]{4}/", 0); pcre_cache_entry *pce; /* Compiled regex */ zval *subpats = NULL; /* Parts (not used) */ int global = 0; @@ -3007,7 +3017,7 @@ PHP_FUNCTION(imap_mail_compose) if (Z_TYPE_P(data) != IS_ARRAY) { zend_argument_type_error(2, "individual body must be of type array, %s given", - zend_zval_type_name(data)); + zend_zval_value_name(data)); goto done; } if (zend_hash_num_elements(Z_ARRVAL_P(data)) == 0) { diff --git a/ext/imap/php_imap.h b/ext/imap/php_imap.h index ce32d3cda8d91..1dcb41cfce7f4 100644 --- a/ext/imap/php_imap.h +++ b/ext/imap/php_imap.h @@ -47,7 +47,9 @@ # endif /* these are used for quota support */ + ZEND_CGG_DIAGNOSTIC_IGNORED_START("-Wstrict-prototypes") # include "c-client.h" /* includes mail.h and rfc822.h */ + ZEND_CGG_DIAGNOSTIC_IGNORED_END # include "imap4r1.h" /* location of c-client quota functions */ #else # include "mail.h" diff --git a/ext/imap/tests/imap_getsubscribed_basic.phpt b/ext/imap/tests/imap_getsubscribed_basic.phpt index 2c1e6a941ebd8..ecae731358f62 100644 --- a/ext/imap/tests/imap_getsubscribed_basic.phpt +++ b/ext/imap/tests/imap_getsubscribed_basic.phpt @@ -7,7 +7,7 @@ imap --SKIPIF-- --CONFLICTS-- defaultmailbox diff --git a/ext/imap/tests/imap_lsub_basic.phpt b/ext/imap/tests/imap_lsub_basic.phpt index e88aa6a8de4b8..bff521624e700 100644 --- a/ext/imap/tests/imap_lsub_basic.phpt +++ b/ext/imap/tests/imap_lsub_basic.phpt @@ -7,7 +7,7 @@ imap --SKIPIF-- --CONFLICTS-- defaultmailbox diff --git a/ext/imap/tests/imap_open_error.phpt b/ext/imap/tests/imap_open_error.phpt index 02ba0006e8c44..18f0f2ef0fa2d 100644 --- a/ext/imap/tests/imap_open_error.phpt +++ b/ext/imap/tests/imap_open_error.phpt @@ -8,7 +8,7 @@ imap --SKIPIF-- --FILE-- biter->setText(ut, BREAKITER_ERROR_CODE(bio)); utext_close(ut); /* ICU shallow clones the UText */ - INTL_METHOD_CHECK_STATUS_OR_NULL(bio, "breakiter_set_text: error calling " + INTL_METHOD_CHECK_STATUS(bio, "breakiter_set_text: error calling " "BreakIterator::setText()"); /* When ICU clones the UText, it does not copy the buffer, so we have to @@ -201,7 +201,7 @@ static void _breakiter_int32_ret_int32( BREAKITER_METHOD_FETCH_OBJECT; - if (arg < INT32_MIN || arg > INT32_MAX) { + if (UNEXPECTED(arg < INT32_MIN || arg > INT32_MAX)) { zend_argument_value_error(1, "must be between %d and %d", INT32_MIN, INT32_MAX); RETURN_THROWS(); } @@ -292,7 +292,7 @@ U_CFUNC PHP_METHOD(IntlBreakIterator, isBoundary) RETURN_THROWS(); } - if (offset < INT32_MIN || offset > INT32_MAX) { + if (UNEXPECTED(offset < INT32_MIN || offset > INT32_MAX)) { zend_argument_value_error(1, "must be between %d and %d", INT32_MIN, INT32_MAX); RETURN_THROWS(); } diff --git a/ext/intl/calendar/calendar_class.cpp b/ext/intl/calendar/calendar_class.cpp index 8a2c7904a2d26..556b5df208fd4 100644 --- a/ext/intl/calendar/calendar_class.cpp +++ b/ext/intl/calendar/calendar_class.cpp @@ -94,7 +94,7 @@ static zend_object *Calendar_clone_obj(zend_object *object) Calendar *newCalendar; newCalendar = co_orig->ucal->clone(); - if (!newCalendar) { + if (UNEXPECTED(!newCalendar)) { zend_string *err_msg; intl_errors_set_code(CALENDAR_ERROR_P(co_orig), U_MEMORY_ALLOCATION_ERROR); diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp index 52d1b2cb3037d..19b12e6e22616 100644 --- a/ext/intl/calendar/calendar_methods.cpp +++ b/ext/intl/calendar/calendar_methods.cpp @@ -50,7 +50,7 @@ using icu::Locale; } #define ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE(argument, zpp_arg_position) \ - if (argument < INT32_MIN || argument > INT32_MAX) { \ + if (UNEXPECTED(argument < INT32_MIN || argument > INT32_MAX)) { \ zend_argument_value_error(getThis() ? ((zpp_arg_position)-1) : zpp_arg_position, \ "must be between %d and %d", INT32_MIN, INT32_MAX); \ RETURN_THROWS(); \ @@ -96,7 +96,7 @@ U_CFUNC PHP_FUNCTION(intlcal_create_instance) Calendar *cal = Calendar::createInstance(timeZone, Locale::createFromName(locale_str), status); - if (cal == NULL) { + if (UNEXPECTED(cal == NULL)) { delete timeZone; intl_error_set(NULL, status, "Error creating ICU Calendar object", 0); RETURN_NULL(); @@ -637,7 +637,7 @@ U_CFUNC PHP_FUNCTION(intlcal_get_time_zone) CALENDAR_METHOD_FETCH_OBJECT; TimeZone *tz = co->ucal->getTimeZone().clone(); - if (tz == NULL) { + if (UNEXPECTED(tz == NULL)) { intl_errors_set(CALENDAR_ERROR_P(co), U_MEMORY_ALLOCATION_ERROR, "intlcal_get_time_zone: could not clone TimeZone", 0); RETURN_FALSE; @@ -1000,7 +1000,7 @@ U_CFUNC PHP_FUNCTION(intlcal_from_date_time) cal = Calendar::createInstance(timeZone, Locale::createFromName(locale_str), status); - if (cal == NULL) { + if (UNEXPECTED(cal == NULL)) { delete timeZone; intl_error_set(NULL, status, "intlcal_from_date_time: " "error creating ICU Calendar object", 0); @@ -1045,7 +1045,7 @@ U_CFUNC PHP_FUNCTION(intlcal_to_date_time) INTL_METHOD_CHECK_STATUS(co, "Call to ICU method has failed"); - if (date > (double)U_INT64_MAX || date < (double)U_INT64_MIN) { + if (UNEXPECTED(date > (double)U_INT64_MAX || date < (double)U_INT64_MIN)) { intl_errors_set(CALENDAR_ERROR_P(co), U_ILLEGAL_ARGUMENT_ERROR, "intlcal_to_date_time: The calendar date is out of the " "range for a 64-bit integer", 0); diff --git a/ext/intl/calendar/gregoriancalendar_methods.cpp b/ext/intl/calendar/gregoriancalendar_methods.cpp index 757b280cd972a..014abef3f0c55 100644 --- a/ext/intl/calendar/gregoriancalendar_methods.cpp +++ b/ext/intl/calendar/gregoriancalendar_methods.cpp @@ -135,7 +135,7 @@ static void _php_intlgregcal_constructor_body( } else { // From date/time (3, 5 or 6 arguments) for (int i = 0; i < variant; i++) { - if (largs[i] < INT32_MIN || largs[i] > INT32_MAX) { + if (UNEXPECTED(largs[i] < INT32_MIN || largs[i] > INT32_MAX)) { zend_argument_value_error(getThis() ? (i-1) : i, "must be between %d and %d", INT32_MIN, INT32_MAX); RETURN_THROWS(); @@ -251,7 +251,7 @@ U_CFUNC PHP_FUNCTION(intlgregcal_is_leap_year) RETURN_THROWS(); } - if (year < INT32_MIN || year > INT32_MAX) { + if (UNEXPECTED(year < INT32_MIN || year > INT32_MAX)) { zend_argument_value_error(getThis() ? 1 : 2, "must be between %d and %d", INT32_MIN, INT32_MAX); RETURN_THROWS(); } diff --git a/ext/intl/collator/collator_convert.c b/ext/intl/collator/collator_convert.c index 55f2995895b88..acf2b2f7d41fe 100644 --- a/ext/intl/collator/collator_convert.c +++ b/ext/intl/collator/collator_convert.c @@ -308,7 +308,7 @@ zval* collator_convert_string_to_double( zval* str, zval *rv ) */ zval* collator_convert_string_to_number_if_possible( zval* str, zval *rv ) { - zend_uchar is_numeric = 0; + uint8_t is_numeric = 0; zend_long lval = 0; double dval = 0; @@ -370,7 +370,7 @@ zval* collator_normalize_sort_argument( zval* arg, zval *rv ) if( Z_TYPE_P( arg ) != IS_STRING ) { - /* If its not a string then nothing to do. + /* If it's not a string then nothing to do. * Return original arg. */ COLLATOR_CONVERT_RETURN_FAILED( arg ); diff --git a/ext/intl/collator/collator_is_numeric.c b/ext/intl/collator/collator_is_numeric.c index 823fb4088d8fd..cf18c8a672223 100644 --- a/ext/intl/collator/collator_is_numeric.c +++ b/ext/intl/collator/collator_is_numeric.c @@ -204,7 +204,7 @@ static zend_long collator_u_strtol(const UChar *nptr, UChar **endptr, int base) /* {{{ collator_is_numeric] * Taken from PHP6:is_numeric_unicode() */ -zend_uchar collator_is_numeric( UChar *str, int32_t length, zend_long *lval, double *dval, bool allow_errors ) +uint8_t collator_is_numeric( UChar *str, int32_t length, zend_long *lval, double *dval, bool allow_errors ) { zend_long local_lval; double local_dval; diff --git a/ext/intl/collator/collator_is_numeric.h b/ext/intl/collator/collator_is_numeric.h index 16afa64ae2240..d30acd0b5843a 100644 --- a/ext/intl/collator/collator_is_numeric.h +++ b/ext/intl/collator/collator_is_numeric.h @@ -18,7 +18,8 @@ #include #include +#include -zend_uchar collator_is_numeric( UChar *str, int32_t length, zend_long *lval, double *dval, bool allow_errors ); +uint8_t collator_is_numeric( UChar *str, int32_t length, zend_long *lval, double *dval, bool allow_errors ); #endif // COLLATOR_IS_NUMERIC_H diff --git a/ext/intl/common/common.stub.php b/ext/intl/common/common.stub.php index cdcca7d413d68..c76ac9f756d4a 100644 --- a/ext/intl/common/common.stub.php +++ b/ext/intl/common/common.stub.php @@ -425,9 +425,10 @@ /** * Typo: kept for backward compatibility. Use U_MULTIPLE_DECIMAL_SEPARATORS * @var int + * @deprecated * @cvalue U_MULTIPLE_DECIMAL_SEPERATORS */ -const U_MULTIPLE_DECIMAL_SEPERATORS = UNKNOWN; // TODO Deprecate +const U_MULTIPLE_DECIMAL_SEPERATORS = UNKNOWN; /** * @var int * @cvalue U_MULTIPLE_EXPONENTIAL_SYMBOLS diff --git a/ext/intl/common/common_arginfo.h b/ext/intl/common/common_arginfo.h index d549e7964c6c2..375a4303e9fec 100644 --- a/ext/intl/common/common_arginfo.h +++ b/ext/intl/common/common_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: bc47f841e1bc12324d4c5cfea798fbfb43592c07 */ + * Stub hash: 83971f2cec8c413d6207382e6ebc4ebf500e805f */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_IntlIterator_current, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() @@ -115,7 +115,7 @@ static void register_common_symbols(int module_number) REGISTER_LONG_CONSTANT("U_UNEXPECTED_TOKEN", U_UNEXPECTED_TOKEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("U_FMT_PARSE_ERROR_START", U_FMT_PARSE_ERROR_START, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("U_MULTIPLE_DECIMAL_SEPARATORS", U_MULTIPLE_DECIMAL_SEPARATORS, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("U_MULTIPLE_DECIMAL_SEPERATORS", U_MULTIPLE_DECIMAL_SEPERATORS, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("U_MULTIPLE_DECIMAL_SEPERATORS", U_MULTIPLE_DECIMAL_SEPERATORS, CONST_PERSISTENT | CONST_DEPRECATED); REGISTER_LONG_CONSTANT("U_MULTIPLE_EXPONENTIAL_SYMBOLS", U_MULTIPLE_EXPONENTIAL_SYMBOLS, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("U_MALFORMED_EXPONENTIAL_PATTERN", U_MALFORMED_EXPONENTIAL_PATTERN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("U_MULTIPLE_PERCENT_SYMBOLS", U_MULTIPLE_PERCENT_SYMBOLS, CONST_PERSISTENT); diff --git a/ext/intl/dateformat/dateformat.stub.php b/ext/intl/dateformat/dateformat.stub.php index ed49bcc0d89a9..3e5f178491bda 100644 --- a/ext/intl/dateformat/dateformat.stub.php +++ b/ext/intl/dateformat/dateformat.stub.php @@ -136,7 +136,7 @@ public function getTimeZone(): IntlTimeZone|false {} * @tentative-return-type * @alias datefmt_set_timezone */ - public function setTimeZone($timezone): ?bool {} // TODO return true on success + public function setTimeZone($timezone): bool {} /** * @tentative-return-type diff --git a/ext/intl/dateformat/dateformat_arginfo.h b/ext/intl/dateformat/dateformat_arginfo.h index 6026077c1ac23..6391c5839e09f 100644 --- a/ext/intl/dateformat/dateformat_arginfo.h +++ b/ext/intl/dateformat/dateformat_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: cefec46af242e6372a923dea0e1d2cf22da7ef3e */ + * Stub hash: c3aabab98e4864276f6cb0afb2e3fefad0386481 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDateFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1) @@ -39,7 +39,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_IntlDateFormatter_getTimeZone, 0, 0, IntlTimeZone, MAY_BE_FALSE) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_IntlDateFormatter_setTimeZone, 0, 1, _IS_BOOL, 1) +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_IntlDateFormatter_setTimeZone, 0, 1, _IS_BOOL, 0) ZEND_ARG_INFO(0, timezone) ZEND_END_ARG_INFO() diff --git a/ext/intl/dateformat/dateformat_attrcpp.cpp b/ext/intl/dateformat/dateformat_attrcpp.cpp index da74b211635cb..e34c331800622 100644 --- a/ext/intl/dateformat/dateformat_attrcpp.cpp +++ b/ext/intl/dateformat/dateformat_attrcpp.cpp @@ -69,7 +69,7 @@ U_CFUNC PHP_FUNCTION(datefmt_get_timezone) const TimeZone& tz = fetch_datefmt(dfo)->getTimeZone(); TimeZone *tz_clone = tz.clone(); - if (tz_clone == NULL) { + if (UNEXPECTED(tz_clone == NULL)) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, "datefmt_get_timezone: Out of memory when cloning time zone", 0); @@ -101,6 +101,8 @@ U_CFUNC PHP_FUNCTION(datefmt_set_timezone) } fetch_datefmt(dfo)->adoptTimeZone(timezone); + + RETURN_TRUE; } /* {{{ Get formatter calendar type. */ @@ -142,7 +144,7 @@ U_CFUNC PHP_FUNCTION(datefmt_get_calendar_object) } Calendar *cal_clone = cal->clone(); - if (cal_clone == NULL) { + if (UNEXPECTED(cal_clone == NULL)) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, "datefmt_get_calendar_object: Out of memory when cloning " "calendar", 0); @@ -193,7 +195,7 @@ U_CFUNC PHP_FUNCTION(datefmt_set_calendar) if (cal_owned) { /* a non IntlCalendar was specified, we want to keep the timezone */ TimeZone *old_timezone = fetch_datefmt(dfo)->getTimeZone().clone(); - if (old_timezone == NULL) { + if (UNEXPECTED(old_timezone == NULL)) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, "datefmt_set_calendar: Out of memory when cloning calendar", 0); @@ -203,7 +205,7 @@ U_CFUNC PHP_FUNCTION(datefmt_set_calendar) cal->adoptTimeZone(old_timezone); } else { cal = cal->clone(); - if (cal == NULL) { + if (UNEXPECTED(cal == NULL)) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_MEMORY_ALLOCATION_ERROR, "datefmt_set_calendar: Out of memory when cloning calendar", 0); diff --git a/ext/intl/dateformat/dateformat_format_object.cpp b/ext/intl/dateformat/dateformat_format_object.cpp index 9e4697902e62a..27d39866bc2e0 100644 --- a/ext/intl/dateformat/dateformat_format_object.cpp +++ b/ext/intl/dateformat/dateformat_format_object.cpp @@ -37,7 +37,7 @@ using icu::GregorianCalendar; using icu::StringPiece; using icu::SimpleDateFormat; -static const DateFormat::EStyle valid_styles[] = { +static constexpr DateFormat::EStyle valid_styles[] = { DateFormat::kNone, DateFormat::kFull, DateFormat::kLong, diff --git a/ext/intl/grapheme/grapheme_string.c b/ext/intl/grapheme/grapheme_string.c index 29bbdf7ff950c..a9cfd3d2ea6e5 100644 --- a/ext/intl/grapheme/grapheme_string.c +++ b/ext/intl/grapheme/grapheme_string.c @@ -679,7 +679,7 @@ grapheme_extract_count_iter(UBreakIterator *bi, int32_t size, unsigned char *pst /* {{{ grapheme extract iter function pointer array */ typedef int32_t (*grapheme_extract_iter)(UBreakIterator * /*bi*/, int32_t /*size*/, unsigned char * /*pstr*/, int32_t /*str_len*/); -static grapheme_extract_iter grapheme_extract_iters[] = { +static const grapheme_extract_iter grapheme_extract_iters[] = { &grapheme_extract_count_iter, &grapheme_extract_bytecount_iter, &grapheme_extract_charcount_iter, diff --git a/ext/intl/intl_convertcpp.cpp b/ext/intl/intl_convertcpp.cpp index 8ea0a0f36d1e4..43d0d2cdd385e 100644 --- a/ext/intl/intl_convertcpp.cpp +++ b/ext/intl/intl_convertcpp.cpp @@ -23,7 +23,7 @@ extern "C" { /* {{{ intl_stringFromChar */ int intl_stringFromChar(UnicodeString &ret, char *str, size_t str_len, UErrorCode *status) { - if(str_len > INT32_MAX) { + if(UNEXPECTED(str_len > INT32_MAX)) { *status = U_BUFFER_OVERFLOW_ERROR; ret.setToBogus(); return FAILURE; @@ -56,7 +56,7 @@ zend_string* intl_charFromString(const UnicodeString &from, UErrorCode *status) { zend_string *u8res; - if (from.isBogus()) { + if (UNEXPECTED(from.isBogus())) { return NULL; } diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index 430d5a741115f..fbd85b857f3bc 100644 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -328,7 +328,7 @@ static void umsg_set_timezone(MessageFormatter_object *mfo, formats = mf->getFormats(count); - if (formats == NULL) { + if (UNEXPECTED(formats == NULL)) { intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, "Out of memory retrieving subformats", 0); } @@ -403,7 +403,7 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo, /* Process key and retrieve type */ if (str_index == NULL) { /* includes case where index < 0 because it's exposed as unsigned */ - if (num_index > (zend_ulong)INT32_MAX) { + if (UNEXPECTED(num_index > (zend_ulong)INT32_MAX)) { intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found negative or too large array key", 0); continue; @@ -477,8 +477,8 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo, int32_t tInt32 = 0; if (Z_TYPE_P(elem) == IS_DOUBLE) { - if (Z_DVAL_P(elem) > (double)INT32_MAX || - Z_DVAL_P(elem) < (double)INT32_MIN) { + if (UNEXPECTED(Z_DVAL_P(elem) > (double)INT32_MAX || + Z_DVAL_P(elem) < (double)INT32_MIN)) { intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found PHP float with absolute value too large for " "32 bit integer argument", 0); @@ -486,8 +486,8 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo, tInt32 = (int32_t)Z_DVAL_P(elem); } } else if (Z_TYPE_P(elem) == IS_LONG) { - if (Z_LVAL_P(elem) > INT32_MAX || - Z_LVAL_P(elem) < INT32_MIN) { + if (UNEXPECTED(Z_LVAL_P(elem) > INT32_MAX || + Z_LVAL_P(elem) < INT32_MIN)) { intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found PHP integer with absolute value too large " "for 32 bit integer argument", 0); @@ -505,8 +505,8 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo, int64_t tInt64 = 0; if (Z_TYPE_P(elem) == IS_DOUBLE) { - if (Z_DVAL_P(elem) > (double)U_INT64_MAX || - Z_DVAL_P(elem) < (double)U_INT64_MIN) { + if (UNEXPECTED(Z_DVAL_P(elem) > (double)U_INT64_MAX || + Z_DVAL_P(elem) < (double)U_INT64_MIN)) { intl_errors_set(&err, U_ILLEGAL_ARGUMENT_ERROR, "Found PHP float with absolute value too large for " "64 bit integer argument", 0); diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c index 5bee051441f26..7827774d9b487 100644 --- a/ext/intl/php_intl.c +++ b/ext/intl/php_intl.c @@ -251,7 +251,7 @@ PHP_RSHUTDOWN_FUNCTION( intl ) /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION( intl ) { -#ifndef UCONFIG_NO_FORMATTING +#if !UCONFIG_NO_FORMATTING UErrorCode status = U_ZERO_ERROR; const char *tzdata_ver = NULL; #endif @@ -262,7 +262,7 @@ PHP_MINFO_FUNCTION( intl ) #ifdef U_ICU_DATA_VERSION php_info_print_table_row( 2, "ICU Data version", U_ICU_DATA_VERSION ); #endif -#ifndef UCONFIG_NO_FORMATTING +#if !UCONFIG_NO_FORMATTING tzdata_ver = ucal_getTZDataVersion(&status); if (U_ZERO_ERROR == status) { php_info_print_table_row( 2, "ICU TZData version", tzdata_ver); diff --git a/ext/intl/php_intl.stub.php b/ext/intl/php_intl.stub.php index c21ad58fa092e..8980a807919b9 100644 --- a/ext/intl/php_intl.stub.php +++ b/ext/intl/php_intl.stub.php @@ -351,7 +351,7 @@ function datefmt_get_calendar_object(IntlDateFormatter $formatter): IntlCalendar function datefmt_get_timezone(IntlDateFormatter $formatter): IntlTimeZone|false {} /** @param IntlTimeZone|DateTimeZone|string|null $timezone */ -function datefmt_set_timezone(IntlDateFormatter $formatter, $timezone): ?bool {} +function datefmt_set_timezone(IntlDateFormatter $formatter, $timezone): bool {} function datefmt_set_pattern(IntlDateFormatter $formatter, string $pattern): bool {} diff --git a/ext/intl/php_intl_arginfo.h b/ext/intl/php_intl_arginfo.h index b715413989145..8f2903315a386 100644 --- a/ext/intl/php_intl_arginfo.h +++ b/ext/intl/php_intl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 7008d442eba36e2bc468cc4a7a30eb859d10c07d */ + * Stub hash: 136c14d9162548cd7211985ce9a5d767a90a0b99 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_intlcal_create_instance, 0, 0, IntlCalendar, 1) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, timezone, "null") @@ -310,7 +310,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_datefmt_get_timezone, 0, 1, ZEND_ARG_OBJ_INFO(0, formatter, IntlDateFormatter, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_datefmt_set_timezone, 0, 2, _IS_BOOL, 1) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_datefmt_set_timezone, 0, 2, _IS_BOOL, 0) ZEND_ARG_OBJ_INFO(0, formatter, IntlDateFormatter, 0) ZEND_ARG_INFO(0, timezone) ZEND_END_ARG_INFO() diff --git a/ext/intl/spoofchecker/spoofchecker.stub.php b/ext/intl/spoofchecker/spoofchecker.stub.php index 71f6ad0f2e208..ed34b90da98f8 100644 --- a/ext/intl/spoofchecker/spoofchecker.stub.php +++ b/ext/intl/spoofchecker/spoofchecker.stub.php @@ -71,6 +71,18 @@ class Spoofchecker * @cvalue USPOOF_SINGLE_SCRIPT_RESTRICTIVE */ public const SINGLE_SCRIPT_RESTRICTIVE = UNKNOWN; + /** + * @var int + * @cvalue USPOOF_MIXED_NUMBERS + */ + public const MIXED_NUMBERS = UNKNOWN; +#endif +#if U_ICU_VERSION_MAJOR_NUM >= 62 + /** + * @var int + * @cvalue USPOOF_HIDDEN_OVERLAY + */ + public const HIDDEN_OVERLAY = UNKNOWN; #endif public function __construct() {} diff --git a/ext/intl/spoofchecker/spoofchecker_arginfo.h b/ext/intl/spoofchecker/spoofchecker_arginfo.h index 98df10a3350a4..4409a0aa3ec42 100644 --- a/ext/intl/spoofchecker/spoofchecker_arginfo.h +++ b/ext/intl/spoofchecker/spoofchecker_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: eb2f5a660053b4a38858045968b746bdb3be072e */ + * Stub hash: 6ebcb47ddc86a03b0543702b2529e05222a6ad93 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Spoofchecker___construct, 0, 0, 0) ZEND_END_ARG_INFO() @@ -149,6 +149,22 @@ static zend_class_entry *register_class_Spoofchecker(void) zend_declare_class_constant_ex(class_entry, const_SINGLE_SCRIPT_RESTRICTIVE_name, &const_SINGLE_SCRIPT_RESTRICTIVE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_SINGLE_SCRIPT_RESTRICTIVE_name); #endif +#if U_ICU_VERSION_MAJOR_NUM >= 58 + + zval const_MIXED_NUMBERS_value; + ZVAL_LONG(&const_MIXED_NUMBERS_value, USPOOF_MIXED_NUMBERS); + zend_string *const_MIXED_NUMBERS_name = zend_string_init_interned("MIXED_NUMBERS", sizeof("MIXED_NUMBERS") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_MIXED_NUMBERS_name, &const_MIXED_NUMBERS_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_MIXED_NUMBERS_name); +#endif +#if U_ICU_VERSION_MAJOR_NUM >= 62 + + zval const_HIDDEN_OVERLAY_value; + ZVAL_LONG(&const_HIDDEN_OVERLAY_value, USPOOF_HIDDEN_OVERLAY); + zend_string *const_HIDDEN_OVERLAY_name = zend_string_init_interned("HIDDEN_OVERLAY", sizeof("HIDDEN_OVERLAY") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_HIDDEN_OVERLAY_name, &const_HIDDEN_OVERLAY_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_HIDDEN_OVERLAY_name); +#endif return class_entry; } diff --git a/ext/intl/spoofchecker/spoofchecker_main.c b/ext/intl/spoofchecker/spoofchecker_main.c index a45d772a26f47..3831b9403ea48 100644 --- a/ext/intl/spoofchecker/spoofchecker_main.c +++ b/ext/intl/spoofchecker/spoofchecker_main.c @@ -54,7 +54,8 @@ PHP_METHOD(Spoofchecker, isSuspicious) if (error_code) { zval_ptr_dtor(error_code); - ZVAL_LONG(error_code, ret); + ZVAL_LONG(Z_REFVAL_P(error_code), ret); + Z_TRY_ADDREF_P(error_code); } RETVAL_BOOL(ret != 0); } @@ -87,7 +88,8 @@ PHP_METHOD(Spoofchecker, areConfusable) if (error_code) { zval_ptr_dtor(error_code); - ZVAL_LONG(error_code, ret); + ZVAL_LONG(Z_REFVAL_P(error_code), ret); + Z_TRY_ADDREF_P(error_code); } RETVAL_BOOL(ret != 0); } diff --git a/ext/intl/tests/dateformat_formatObject_error.phpt b/ext/intl/tests/dateformat_formatObject_error.phpt index 9f5a43c831f2b..839cb27d317c9 100644 --- a/ext/intl/tests/dateformat_formatObject_error.phpt +++ b/ext/intl/tests/dateformat_formatObject_error.phpt @@ -36,7 +36,7 @@ Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad IntlCalen bool(false) Warning: IntlDateFormatter::formatObject(): datefmt_format_object: error calling ::getTimeStamp() on the object in %s on line %d -The DateTime object has not been correctly initialized by its constructor +Object of type B (inheriting DateTime) has not been correctly initialized by calling parent::__construct() in its constructor Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the date/time format type is invalid in %s on line %d bool(false) diff --git a/ext/intl/tests/dateformat_set_timezone_id2.phpt b/ext/intl/tests/dateformat_set_timezone_id2.phpt index 6c21df6feed56..fa9e68bd86764 100644 --- a/ext/intl/tests/dateformat_set_timezone_id2.phpt +++ b/ext/intl/tests/dateformat_set_timezone_id2.phpt @@ -37,7 +37,7 @@ function ut_main() $res_str .= "-----------"; $res_str .= "\nTrying to set timezone_id= $timezone_id_entry"; - ut_datefmt_set_timezone_id( $fmt , $timezone_id_entry ); + if (ut_datefmt_set_timezone_id( $fmt , $timezone_id_entry ) !== true) die("ut_datefmt_set_timezone_id failed"); $timezone_id = ut_datefmt_get_timezone_id( $fmt ); $res_str .= "\nAfter call to set_timezone_id : timezone_id= $timezone_id"; $formatted = ut_datefmt_format( $fmt, 0); diff --git a/ext/intl/tests/dateformat_set_timezone_id3.phpt b/ext/intl/tests/dateformat_set_timezone_id3.phpt index a4952eb5a3dcb..ec14db3e60623 100644 --- a/ext/intl/tests/dateformat_set_timezone_id3.phpt +++ b/ext/intl/tests/dateformat_set_timezone_id3.phpt @@ -20,10 +20,10 @@ ini_set("intl.error_level", E_WARNING); function ut_main() { $timezone_id_arr = array ( - 'America/New_York', - 'America/Los_Angeles', - 'America/Chicago', - 'CN' + 'America/New_York' => true, + 'America/Los_Angeles' => true, + 'America/Chicago' => true, + 'CN' => false ); $timestamp_entry = 0; @@ -33,12 +33,12 @@ function ut_main() $timezone_id = ut_datefmt_get_timezone_id( $fmt ); $res_str .= "\nAfter creation of the dateformatter : timezone_id= $timezone_id\n"; - foreach( $timezone_id_arr as $timezone_id_entry ) + foreach( $timezone_id_arr as $timezone_id_entry => $result ) { $res_str .= "-----------"; $res_str .= "\nTrying to set timezone_id= $timezone_id_entry"; - ut_datefmt_set_timezone_id( $fmt , $timezone_id_entry ); + if (ut_datefmt_set_timezone_id( $fmt , $timezone_id_entry ) !== $result) die("ut_datefmt_set_timezone_id failed"); $timezone_id = ut_datefmt_get_timezone_id( $fmt ); $res_str .= "\nAfter call to set_timezone_id : timezone_id= $timezone_id"; $formatted = ut_datefmt_format( $fmt, 0); diff --git a/ext/intl/tests/dateformat_set_timezone_id_icu72-1.phpt b/ext/intl/tests/dateformat_set_timezone_id_icu72-1.phpt index aedf886da2dd0..79953ab26b465 100644 --- a/ext/intl/tests/dateformat_set_timezone_id_icu72-1.phpt +++ b/ext/intl/tests/dateformat_set_timezone_id_icu72-1.phpt @@ -19,10 +19,10 @@ ini_set("intl.error_level", E_WARNING); function ut_main() { $timezone_id_arr = array ( - 'America/New_York', - 'America/Los_Angeles', - 'America/Chicago', - 'CN' + 'America/New_York' => true, + 'America/Los_Angeles' => true, + 'America/Chicago' => true, + 'CN' => false ); $timestamp_entry = 0; @@ -32,12 +32,12 @@ function ut_main() $timezone_id = ut_datefmt_get_timezone_id( $fmt ); $res_str .= "\nAfter creation of the dateformatter : timezone_id= $timezone_id\n"; - foreach( $timezone_id_arr as $timezone_id_entry ) + foreach( $timezone_id_arr as $timezone_id_entry => $result ) { $res_str .= "-----------"; $res_str .= "\nTrying to set timezone_id= $timezone_id_entry"; - ut_datefmt_set_timezone_id( $fmt , $timezone_id_entry ); + if (ut_datefmt_set_timezone_id( $fmt , $timezone_id_entry ) !== $result) die("ut_datefmt_set_timezone_id failed"); $timezone_id = ut_datefmt_get_timezone_id( $fmt ); $res_str .= "\nAfter call to set_timezone_id : timezone_id= $timezone_id"; $formatted = ut_datefmt_format( $fmt, 0); diff --git a/ext/intl/tests/gh10647.phpt b/ext/intl/tests/gh10647.phpt new file mode 100644 index 0000000000000..61c6b87e0ddec --- /dev/null +++ b/ext/intl/tests/gh10647.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug GH-10647 (Spoofchecker::isSuspicious $errorCode always null) +--SKIPIF-- + +--FILE-- +isSuspicious("\u{041F}aypal.com", $error)); +var_dump($error); + +var_dump($x->areConfusable('google.com', 'goog1e.com', $error)); +var_dump($error); +?> +--EXPECTF-- +int(123) +bool(true) +int(%d) +bool(true) +int(%d) diff --git a/ext/intl/timezone/timezone_class.cpp b/ext/intl/timezone/timezone_class.cpp index df1da4c021daa..8afc7e2bc4a3a 100644 --- a/ext/intl/timezone/timezone_class.cpp +++ b/ext/intl/timezone/timezone_class.cpp @@ -157,7 +157,7 @@ U_CFUNC TimeZone *timezone_process_timezone_argument(zval *zv_timezone, return NULL; } timeZone = to->utimezone->clone(); - if (timeZone == NULL) { + if (UNEXPECTED(timeZone == NULL)) { spprintf(&message, 0, "%s: could not clone TimeZone", func); if (message) { intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1); @@ -193,7 +193,7 @@ U_CFUNC TimeZone *timezone_process_timezone_argument(zval *zv_timezone, return NULL; } timeZone = TimeZone::createTimeZone(id); - if (timeZone == NULL) { + if (UNEXPECTED(timeZone == NULL)) { spprintf(&message, 0, "%s: Could not create time zone", func); if (message) { intl_errors_set(outside_error, U_MEMORY_ALLOCATION_ERROR, message, 1); diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp index ef73b9416e9b8..cae64026fa5db 100644 --- a/ext/intl/timezone/timezone_methods.cpp +++ b/ext/intl/timezone/timezone_methods.cpp @@ -148,8 +148,8 @@ U_CFUNC PHP_FUNCTION(intltz_create_enumeration) se = TimeZone::createEnumeration(); } else if (Z_TYPE_P(arg) == IS_LONG) { int_offset: - if (Z_LVAL_P(arg) < (zend_long)INT32_MIN || - Z_LVAL_P(arg) > (zend_long)INT32_MAX) { + if (UNEXPECTED(Z_LVAL_P(arg) < (zend_long)INT32_MIN || + Z_LVAL_P(arg) > (zend_long)INT32_MAX)) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intltz_create_enumeration: value is out of range", 0); RETURN_FALSE; @@ -241,7 +241,7 @@ U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration) } if (!arg3isnull) { - if (offset_arg < (zend_long)INT32_MIN || offset_arg > (zend_long)INT32_MAX) { + if (UNEXPECTED(offset_arg < (zend_long)INT32_MIN || offset_arg > (zend_long)INT32_MAX)) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "intltz_create_time_zone_id_enumeration: offset out of bounds", 0); RETURN_FALSE; @@ -350,7 +350,7 @@ U_CFUNC PHP_FUNCTION(intltz_get_equivalent_id) RETURN_THROWS(); } - if (index < (zend_long)INT32_MIN || index > (zend_long)INT32_MAX) { + if (UNEXPECTED(index < (zend_long)INT32_MIN || index > (zend_long)INT32_MAX)) { RETURN_FALSE; } @@ -475,7 +475,7 @@ U_CFUNC PHP_FUNCTION(intltz_has_same_rules) RETURN_BOOL(to->utimezone->hasSameRules(*other_to->utimezone)); } -static const TimeZone::EDisplayType display_types[] = { +static constexpr TimeZone::EDisplayType display_types[] = { TimeZone::SHORT, TimeZone::LONG, TimeZone::SHORT_GENERIC, TimeZone::LONG_GENERIC, TimeZone::SHORT_GMT, TimeZone::LONG_GMT, diff --git a/ext/intl/uchar/uchar.c b/ext/intl/uchar/uchar.c index 771805925827f..c85bcb3fcffd4 100644 --- a/ext/intl/uchar/uchar.c +++ b/ext/intl/uchar/uchar.c @@ -309,11 +309,12 @@ IC_METHOD(enumCharNames) { ZEND_PARSE_PARAMETERS_END(); if (convert_cp(&start, string_start, int_start) == FAILURE || convert_cp(&limit, string_limit, int_limit) == FAILURE) { - RETURN_NULL(); + RETURN_FALSE; } u_enumCharNames(start, limit, (UEnumCharNamesFn*)enumCharNames_callback, &context, nameChoice, &error); INTL_CHECK_STATUS(error, NULL); + RETURN_TRUE; } /* }}} */ diff --git a/ext/intl/uchar/uchar.stub.php b/ext/intl/uchar/uchar.stub.php index d789684fc8f95..58e8434b2eed6 100644 --- a/ext/intl/uchar/uchar.stub.php +++ b/ext/intl/uchar/uchar.stub.php @@ -3411,7 +3411,7 @@ public static function chr(int|string $codepoint): ?string {} public static function digit(int|string $codepoint, int $base = 10): int|false|null {} /** @tentative-return-type */ - public static function enumCharNames(int|string $start, int|string $end, callable $callback, int $type = IntlChar::UNICODE_CHAR_NAME): ?bool {} // TODO return values just don't make sense + public static function enumCharNames(int|string $start, int|string $end, callable $callback, int $type = IntlChar::UNICODE_CHAR_NAME): bool {} /** @tentative-return-type */ public static function enumCharTypes(callable $callback): void {} diff --git a/ext/intl/uchar/uchar_arginfo.h b/ext/intl/uchar/uchar_arginfo.h index a052ae927cd0b..8b29463cf0ed6 100644 --- a/ext/intl/uchar/uchar_arginfo.h +++ b/ext/intl/uchar/uchar_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e8d6cf16660b6389922160f8a2c9c07ca2d58404 */ + * Stub hash: 59e9bd9f059c27835f78c5b95372731d265a228a */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_IntlChar_hasBinaryProperty, 0, 2, _IS_BOOL, 1) ZEND_ARG_TYPE_MASK(0, codepoint, MAY_BE_LONG|MAY_BE_STRING, NULL) @@ -41,7 +41,7 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_IntlChar_digit, ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, base, IS_LONG, 0, "10") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_IntlChar_enumCharNames, 0, 3, _IS_BOOL, 1) +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_IntlChar_enumCharNames, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_MASK(0, start, MAY_BE_LONG|MAY_BE_STRING, NULL) ZEND_ARG_TYPE_MASK(0, end, MAY_BE_LONG|MAY_BE_STRING, NULL) ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) diff --git a/ext/json/Makefile.frag b/ext/json/Makefile.frag index f5fe3c3306598..45687a11b7bf5 100644 --- a/ext/json/Makefile.frag +++ b/ext/json/Makefile.frag @@ -1,5 +1,5 @@ -$(srcdir)/json_scanner.c: $(srcdir)/json_scanner.re - @$(RE2C) $(RE2C_FLAGS) -t $(srcdir)/php_json_scanner_defs.h --no-generation-date -bci -o $@ $(srcdir)/json_scanner.re +$(srcdir)/json_scanner.c $(srcdir)/php_json_scanner_defs.h: $(srcdir)/json_scanner.re $(srcdir)/json_parser.tab.h + @$(RE2C) $(RE2C_FLAGS) -t $(srcdir)/php_json_scanner_defs.h --no-generation-date -bci -o $(srcdir)/json_scanner.c $(srcdir)/json_scanner.re -$(srcdir)/json_parser.tab.c: $(srcdir)/json_parser.y - @$(YACC) $(YFLAGS) --defines -l $(srcdir)/json_parser.y -o $@ +$(srcdir)/json_parser.tab.c $(srcdir)/json_parser.tab.h: $(srcdir)/json_parser.y + @$(YACC) $(YFLAGS) --defines -l $(srcdir)/json_parser.y -o $(srcdir)/json_parser.tab.c diff --git a/ext/json/Makefile.frag.w32 b/ext/json/Makefile.frag.w32 index 1463eda70b7ad..75250626dce68 100644 --- a/ext/json/Makefile.frag.w32 +++ b/ext/json/Makefile.frag.w32 @@ -1,5 +1,5 @@ -ext\json\json_scanner.c: ext\json\json_scanner.re +ext\json\json_scanner.c ext\json\php_json_scanner_defs.h: ext\json\json_scanner.re ext\json\json_parser.tab.h $(RE2C) $(RE2C_FLAGS) -t ext/json/php_json_scanner_defs.h --no-generation-date -bci -o ext/json/json_scanner.c ext/json/json_scanner.re -ext\json\json_parser.tab.c: ext\json\json_parser.y +ext\json\json_parser.tab.c ext\json\json_parser.tab.h: ext\json\json_parser.y $(BISON) --defines -l ext/json/json_parser.y -o ext/json/json_parser.tab.c diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 4727280f549b8..d570cddc91e4b 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -370,7 +370,7 @@ PHP_JSON_API int php_json_parse(php_json_parser *parser) return php_json_yyparse(parser); } -const php_json_parser_methods* php_json_get_validate_methods() +const php_json_parser_methods* php_json_get_validate_methods(void) { return &validate_parser_methods; } diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index ecd94c2da509e..715bde8bd13e3 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -120,7 +120,7 @@ static zend_object *ldap_link_create_object(zend_class_entry *class_type) { } static zend_function *ldap_link_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct LDAP\\Connection, use ldap_create() instead"); + zend_throw_error(NULL, "Cannot directly construct LDAP\\Connection, use ldap_connect() instead"); return NULL; } @@ -1602,7 +1602,7 @@ static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope) result->result = ldap_res; } } else { - zend_argument_type_error(1, "must be of type LDAP|array, %s given", zend_zval_type_name(link)); + zend_argument_type_error(1, "must be of type LDAP|array, %s given", zend_zval_value_name(link)); } cleanup: @@ -2568,7 +2568,7 @@ PHP_FUNCTION(ldap_modify_batch) /* does the value type match the key? */ if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_ATTRIB)) { if (Z_TYPE_P(modinfo) != IS_STRING) { - zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_ATTRIB "\" must be of type string, %s given", get_active_function_name(), zend_zval_type_name(modinfo)); + zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_ATTRIB "\" must be of type string, %s given", get_active_function_name(), zend_zval_value_name(modinfo)); RETURN_THROWS(); } @@ -2579,7 +2579,7 @@ PHP_FUNCTION(ldap_modify_batch) } else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_MODTYPE)) { if (Z_TYPE_P(modinfo) != IS_LONG) { - zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_MODTYPE "\" must be of type int, %s given", get_active_function_name(), zend_zval_type_name(modinfo)); + zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_MODTYPE "\" must be of type int, %s given", get_active_function_name(), zend_zval_value_name(modinfo)); RETURN_THROWS(); } @@ -2611,7 +2611,7 @@ PHP_FUNCTION(ldap_modify_batch) } else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_VALUES)) { if (Z_TYPE_P(modinfo) != IS_ARRAY) { - zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_VALUES "\" must be of type array, %s given", get_active_function_name(), zend_zval_type_name(modinfo)); + zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_VALUES "\" must be of type array, %s given", get_active_function_name(), zend_zval_value_name(modinfo)); RETURN_THROWS(); } @@ -3200,7 +3200,7 @@ PHP_FUNCTION(ldap_set_option) int rc; if (Z_TYPE_P(newval) != IS_ARRAY) { - zend_argument_type_error(3, "must be of type array for the LDAP_OPT_CLIENT_CONTROLS option, %s given", zend_zval_type_name(newval)); + zend_argument_type_error(3, "must be of type array for the LDAP_OPT_CLIENT_CONTROLS option, %s given", zend_zval_value_name(newval)); RETURN_THROWS(); } diff --git a/ext/ldap/tests/ldap_constructor.phpt b/ext/ldap/tests/ldap_constructor.phpt index 37db6112dcee5..6c79dee8b3982 100644 --- a/ext/ldap/tests/ldap_constructor.phpt +++ b/ext/ldap/tests/ldap_constructor.phpt @@ -11,4 +11,4 @@ try { echo "Exception: ", $ex->getMessage(), "\n"; } --EXPECT-- -Exception: Cannot directly construct LDAP\Connection, use ldap_create() instead +Exception: Cannot directly construct LDAP\Connection, use ldap_connect() instead diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index e4b78939ddd79..634195cb57624 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -707,7 +707,7 @@ PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...) va_end(args); } -PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error) +static void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error) { _php_list_set_error_structure(error, NULL); diff --git a/ext/mbstring/common_codepoints.txt b/ext/mbstring/common_codepoints.txt index d89426cedfa27..66c49c5a94ca8 100644 --- a/ext/mbstring/common_codepoints.txt +++ b/ext/mbstring/common_codepoints.txt @@ -6,10 +6,13 @@ 0x0104 0x0107 # Polish 0x010C 0x010F # Czech 0x0118 0x011B # Polish, Czech +0x011F 0x011F # Turkish +0x0130 0x0131 # Turkish 0x0141 0x0144 # Polish 0x0147 0x0148 # Czech 0x0150 0x0151 # Hungarian 0x0158 0x015B # Czech, Polish +0x015F 0x015F # Turkish 0x0160 0x0161 # Used in Slavic names 0x0164 0x0165 # Czech 0x016E 0x016F # Czech diff --git a/ext/mbstring/gen_rare_cp_bitvec.php b/ext/mbstring/gen_rare_cp_bitvec.php index 741c3827de509..ca1e85cb3d89a 100755 --- a/ext/mbstring/gen_rare_cp_bitvec.php +++ b/ext/mbstring/gen_rare_cp_bitvec.php @@ -40,7 +40,7 @@ * as less likely to be the correct one. */ -static uint32_t rare_codepoint_bitvec[] = { +static const uint32_t rare_codepoint_bitvec[] = { HEADER; for ($i = 0; $i < 0xFFFF / 32; $i++) { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_7bit.c b/ext/mbstring/libmbfl/filters/mbfilter_7bit.c index 208792720af46..54744aa4b8ed7 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_7bit.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_7bit.c @@ -64,7 +64,8 @@ const mbfl_encoding mbfl_encoding_7bit = { &vtbl_7bit_wchar, &vtbl_wchar_7bit, mb_7bit_to_wchar, - mb_wchar_to_7bit + mb_wchar_to_7bit, + NULL }; #define CK(statement) do { if ((statement) < 0) return (-1); } while (0) @@ -79,7 +80,7 @@ int mbfl_filt_conv_any_7bit(int c, mbfl_convert_filter *filter) if (c >= 0 && c < 0x80) { CK((*filter->output_function)(c, filter->data)); } else { - mbfl_filt_conv_illegal_output(c, filter); + CK(mbfl_filt_conv_illegal_output(c, filter)); } return 0; } diff --git a/ext/mbstring/libmbfl/filters/mbfilter_base64.c b/ext/mbstring/libmbfl/filters/mbfilter_base64.c index ede3eef18ce7c..b5a732224f003 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_base64.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_base64.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by Moriyoshi Koizumi on 4 Dec 2002. The file * mbfilter.c is included in this package . * @@ -44,7 +44,8 @@ const mbfl_encoding mbfl_encoding_base64 = { NULL, NULL, mb_base64_to_wchar, - mb_wchar_to_base64 + mb_wchar_to_base64, + NULL }; const struct mbfl_convert_vtbl vtbl_8bit_b64 = { @@ -99,15 +100,13 @@ int mbfl_filt_conv_base64enc(int c, mbfl_convert_filter *filter) filter->cache |= (c & 0xff) << 8; } else { filter->status &= ~0xff; - if ((filter->status & MBFL_BASE64_STS_MIME_HEADER) == 0) { - n = (filter->status & 0xff00) >> 8; - if (n > 72) { - CK((*filter->output_function)(0x0d, filter->data)); /* CR */ - CK((*filter->output_function)(0x0a, filter->data)); /* LF */ - filter->status &= ~0xff00; - } - filter->status += 0x400; + n = (filter->status & 0xff00) >> 8; + if (n > 72) { + CK((*filter->output_function)(0x0d, filter->data)); /* CR */ + CK((*filter->output_function)(0x0a, filter->data)); /* LF */ + filter->status &= ~0xff00; } + filter->status += 0x400; n = filter->cache | (c & 0xff); CK((*filter->output_function)(mbfl_base64_table[(n >> 18) & 0x3f], filter->data)); CK((*filter->output_function)(mbfl_base64_table[(n >> 12) & 0x3f], filter->data)); @@ -129,11 +128,9 @@ int mbfl_filt_conv_base64enc_flush(mbfl_convert_filter *filter) filter->cache = 0; /* flush fragments */ if (status >= 1) { - if ((filter->status & MBFL_BASE64_STS_MIME_HEADER) == 0) { - if (len > 72){ - CK((*filter->output_function)(0x0d, filter->data)); /* CR */ - CK((*filter->output_function)(0x0a, filter->data)); /* LF */ - } + if (len > 72){ + CK((*filter->output_function)(0x0d, filter->data)); /* CR */ + CK((*filter->output_function)(0x0a, filter->data)); /* LF */ } CK((*filter->output_function)(mbfl_base64_table[(cache >> 18) & 0x3f], filter->data)); CK((*filter->output_function)(mbfl_base64_table[(cache >> 12) & 0x3f], filter->data)); diff --git a/ext/mbstring/libmbfl/filters/mbfilter_big5.c b/ext/mbstring/libmbfl/filters/mbfilter_big5.c index 58f89d1b5759e..ab10c6a5df3e4 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_big5.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_big5.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter_tw.c + * The source code included in this file was separated from mbfilter_tw.c * by moriyoshi koizumi on 4 dec 2002. * */ @@ -69,7 +69,8 @@ const mbfl_encoding mbfl_encoding_big5 = { &vtbl_big5_wchar, &vtbl_wchar_big5, mb_big5_to_wchar, - mb_wchar_to_big5 + mb_wchar_to_big5, + NULL }; const mbfl_encoding mbfl_encoding_cp950 = { @@ -82,7 +83,8 @@ const mbfl_encoding mbfl_encoding_cp950 = { &vtbl_cp950_wchar, &vtbl_wchar_cp950, mb_cp950_to_wchar, - mb_wchar_to_cp950 + mb_wchar_to_cp950, + NULL }; const struct mbfl_convert_vtbl vtbl_big5_wchar = { @@ -391,19 +393,28 @@ static size_t mb_big5_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf unsigned char *p = *in, *e = p + *in_len; uint32_t *out = buf, *limit = buf + bufsize; + e--; /* Stop the main loop 1 byte short of the end of the input */ + while (p < e && out < limit) { unsigned char c = *p++; if (c <= 0x7F) { *out++ = c; - } else if (c > 0xA0 && c <= 0xF9 && c != 0xC8 && p < e) { + } else if (c > 0xA0 && c <= 0xF9) { + /* We don't need to check p < e here; it's not possible that this pointer dereference + * will be outside the input string, because of e-- above */ unsigned char c2 = *p++; if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0xA1 && c2 <= 0xFE)) { - unsigned int w = ((c - 0xA1)*157) + c2 - ((c2 <= 0x7E) ? 0x40 : 0xA1 - 0x3F); - w = (w < big5_ucs_table_size) ? big5_ucs_table[w] : 0; - if (!w) + unsigned int w = (c - 0xA1)*157 + c2 - ((c2 <= 0x7E) ? 0x40 : 0xA1 - 0x3F); + ZEND_ASSERT(w < big5_ucs_table_size); + w = big5_ucs_table[w]; + if (!w) { + if (c == 0xC8) { + p--; + } w = MBFL_BAD_INPUT; + } *out++ = w; } else { *out++ = MBFL_BAD_INPUT; @@ -413,7 +424,13 @@ static size_t mb_big5_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf } } - *in_len = e - p; + /* Finish up last byte of input string if there is one */ + if (p == e && out < limit) { + unsigned char c = *p++; + *out++ = (c <= 0x7F) ? c : MBFL_BAD_INPUT; + } + + *in_len = e - p + 1; *in = p; return out - buf; } diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c b/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c index 32a8bdf15f59a..93c33da9543d0 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c @@ -61,7 +61,8 @@ const mbfl_encoding mbfl_encoding_cp50220 = { &vtbl_cp50220_wchar, &vtbl_wchar_cp50220, mb_cp5022x_to_wchar, - mb_wchar_to_cp50220 + mb_wchar_to_cp50220, + NULL }; const mbfl_encoding mbfl_encoding_cp50221 = { @@ -74,7 +75,8 @@ const mbfl_encoding mbfl_encoding_cp50221 = { &vtbl_cp50221_wchar, &vtbl_wchar_cp50221, mb_cp5022x_to_wchar, - mb_wchar_to_cp50221 + mb_wchar_to_cp50221, + NULL }; const mbfl_encoding mbfl_encoding_cp50222 = { @@ -87,7 +89,8 @@ const mbfl_encoding mbfl_encoding_cp50222 = { &vtbl_cp50222_wchar, &vtbl_wchar_cp50222, mb_cp5022x_to_wchar, - mb_wchar_to_cp50222 + mb_wchar_to_cp50222, + NULL }; const struct mbfl_convert_vtbl vtbl_cp50220_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp51932.c b/ext/mbstring/libmbfl/filters/mbfilter_cp51932.c index 6311f9b72139a..d3aae8b10f56e 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp51932.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp51932.c @@ -69,7 +69,8 @@ const mbfl_encoding mbfl_encoding_cp51932 = { &vtbl_cp51932_wchar, &vtbl_wchar_cp51932, mb_cp51932_to_wchar, - mb_wchar_to_cp51932 + mb_wchar_to_cp51932, + NULL }; const struct mbfl_convert_vtbl vtbl_cp51932_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp932.c b/ext/mbstring/libmbfl/filters/mbfilter_cp932.c index cf8e461e1d9c0..506c24393906d 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp932.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp932.c @@ -100,7 +100,8 @@ const mbfl_encoding mbfl_encoding_cp932 = { &vtbl_cp932_wchar, &vtbl_wchar_cp932, mb_cp932_to_wchar, - mb_wchar_to_cp932 + mb_wchar_to_cp932, + NULL }; const struct mbfl_convert_vtbl vtbl_cp932_wchar = { @@ -133,7 +134,8 @@ const mbfl_encoding mbfl_encoding_sjiswin = { &vtbl_sjiswin_wchar, &vtbl_wchar_sjiswin, mb_cp932_to_wchar, - mb_wchar_to_sjiswin + mb_wchar_to_sjiswin, + NULL }; const struct mbfl_convert_vtbl vtbl_sjiswin_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp936.c b/ext/mbstring/libmbfl/filters/mbfilter_cp936.c index 40ae8c86f9119..ba3e6c6436708 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp936.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp936.c @@ -22,7 +22,7 @@ * */ /* - * the source code included in this files was separated from mbfilter_cn.c + * the source code included in this file was separated from mbfilter_cn.c * by moriyoshi koizumi on 4 dec 2002. * */ @@ -68,7 +68,8 @@ const mbfl_encoding mbfl_encoding_cp936 = { &vtbl_cp936_wchar, &vtbl_wchar_cp936, mb_cp936_to_wchar, - mb_wchar_to_cp936 + mb_wchar_to_cp936, + NULL }; const struct mbfl_convert_vtbl vtbl_cp936_wchar = { @@ -291,37 +292,45 @@ static size_t mb_cp936_to_wchar(unsigned char **in, size_t *in_len, uint32_t *bu } unsigned char c2 = *p++; + if (c2 < 0x40 || c2 == 0x7F || c2 == 0xFF) { + *out++ = MBFL_BAD_INPUT; + continue; + } - if (((c >= 0xAA && c <= 0xAF) || (c >= 0xF8 && c <= 0xFE)) && (c2 >= 0xA1 && c2 <= 0xFE)) { + if (((c >= 0xAA && c <= 0xAF) || (c >= 0xF8 && c <= 0xFE)) && c2 >= 0xA1) { /* UDA part 1, 2: U+E000-U+E4C5 */ *out++ = 94*(c >= 0xF8 ? c - 0xF2 : c - 0xAA) + (c2 - 0xA1) + 0xE000; - } else if (c >= 0xA1 && c <= 0xA7 && c2 >= 0x40 && c2 < 0xA1 && c2 != 0x7F) { + } else if (c >= 0xA1 && c <= 0xA7 && c2 < 0xA1) { /* UDA part 3: U+E4C6-U+E765*/ *out++ = 96*(c - 0xA1) + c2 - (c2 >= 0x80 ? 0x41 : 0x40) + 0xE4C6; } else { - unsigned int w = (c << 8) | c2; - - if ((w >= 0xA2AB && w <= 0xA9FE) || (w >= 0xD7FA && w <= 0xD7FE) || (w >= 0xFE50 && w <= 0xFEA0)) { - for (int k = 0; k < mbfl_cp936_pua_tbl_max; k++) { - if (w >= mbfl_cp936_pua_tbl[k][2] && w <= mbfl_cp936_pua_tbl[k][2] + mbfl_cp936_pua_tbl[k][1] - mbfl_cp936_pua_tbl[k][0]) { - *out++ = w - mbfl_cp936_pua_tbl[k][2] + mbfl_cp936_pua_tbl[k][0]; - goto next_iteration; + unsigned int w = (c - 0x81)*192 + c2 - 0x40; /* Convert c, c2 into GB 2312 table lookup index */ + + /* For CP936 and GB18030, certain GB 2312 byte combinations are mapped to PUA codepoints, + * whereas the same combinations aren't mapped to any codepoint for HZ and EUC-CN + * To avoid duplicating the entire GB 2312 -> Unicode lookup table, we have three + * auxiliary tables which are consulted instead for specific ranges of lookup indices */ + if (w >= 0x192B) { + if (w <= 0x1EBE) { + *out++ = cp936_pua_tbl1[w - 0x192B]; + continue; + } else if (w >= 0x413A) { + if (w <= 0x413E) { + *out++ = cp936_pua_tbl2[w - 0x413A]; + continue; + } else if (w >= 0x5DD0 && w <= 0x5E20) { + *out++ = cp936_pua_tbl3[w - 0x5DD0]; + continue; } } } - if (c < 0xFF && c > 0x80 && c2 >= 0x40 && c2 < 0xFF && c2 != 0x7F) { - w = (c - 0x81)*192 + c2 - 0x40; - ZEND_ASSERT(w < cp936_ucs_table_size); - *out++ = cp936_ucs_table[w]; - } else { - *out++ = MBFL_BAD_INPUT; - } + ZEND_ASSERT(w < cp936_ucs_table_size); + *out++ = cp936_ucs_table[w]; } } else { *out++ = 0xF8F5; } -next_iteration: ; } *in_len = e - p; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_cn.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_cn.c index 50a0368a923f4..d8181d7f7c30d 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_cn.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_cn.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter_cn.c + * The source code included in this file was separated from mbfilter_cn.c * by Moriyoshi Koizumi on 4 Dec 2002. * */ @@ -67,7 +67,8 @@ const mbfl_encoding mbfl_encoding_euc_cn = { &vtbl_euccn_wchar, &vtbl_wchar_euccn, mb_euccn_to_wchar, - mb_wchar_to_euccn + mb_wchar_to_euccn, + NULL }; const struct mbfl_convert_vtbl vtbl_euccn_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp.c index 2b0ae77534d56..d9b1362d15f93 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter_ja.c + * The source code included in this file was separated from mbfilter_ja.c * by moriyoshi koizumi on 4 dec 2002. * */ @@ -68,7 +68,8 @@ const mbfl_encoding mbfl_encoding_euc_jp = { &vtbl_eucjp_wchar, &vtbl_wchar_eucjp, mb_eucjp_to_wchar, - mb_wchar_to_eucjp + mb_wchar_to_eucjp, + NULL }; const struct mbfl_convert_vtbl vtbl_eucjp_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_win.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_win.c index 09287a9d8f634..96b9546dde105 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_win.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_win.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter_ja.c + * The source code included in this file was separated from mbfilter_ja.c * by moriyoshi koizumi on 4 dec 2002. * */ @@ -69,7 +69,8 @@ const mbfl_encoding mbfl_encoding_eucjp_win = { &vtbl_eucjpwin_wchar, &vtbl_wchar_eucjpwin, mb_eucjpwin_to_wchar, - mb_wchar_to_eucjpwin + mb_wchar_to_eucjpwin, + NULL }; const struct mbfl_convert_vtbl vtbl_eucjpwin_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_kr.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_kr.c index 69e6811922e30..2c95a80ba965c 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_kr.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_kr.c @@ -66,7 +66,8 @@ const mbfl_encoding mbfl_encoding_euc_kr = { &vtbl_euckr_wchar, &vtbl_wchar_euckr, mb_euckr_to_wchar, - mb_wchar_to_euckr + mb_wchar_to_euckr, + NULL }; const struct mbfl_convert_vtbl vtbl_euckr_wchar = { @@ -118,9 +119,9 @@ int mbfl_filt_conv_euckr_wchar(int c, mbfl_convert_filter *filter) } if (flag > 0 && c >= 0xa1 && c <= 0xfe) { if (flag == 1) { /* 1st: 0xa1..0xc6, 2nd: 0x41..0x7a, 0x81..0xfe */ - w = (c1 - 0xa1)*190 + c - 0x41; - ZEND_ASSERT(w < uhc2_ucs_table_size); - w = uhc2_ucs_table[w]; + w = (c1 - 0x81)*190 + c - 0x41; + ZEND_ASSERT(w < uhc1_ucs_table_size); + w = uhc1_ucs_table[w]; } else { /* 1st: 0xc7..0xc8,0xca..0xfe, 2nd: 0xa1..0xfe */ w = (c1 - 0xc7)*94 + c - 0xa1; ZEND_ASSERT(w < uhc3_ucs_table_size); @@ -216,23 +217,25 @@ static size_t mb_euckr_to_wchar(unsigned char **in, size_t *in_len, uint32_t *bu *out++ = c; } else if (((c >= 0xA1 && c <= 0xAC) || (c >= 0xB0 && c <= 0xFD)) && c != 0xC9 && p < e) { unsigned char c2 = *p++; + if (c2 < 0xA1 || c2 == 0xFF) { + *out++ = MBFL_BAD_INPUT; + continue; + } - if (c >= 0xA1 && c <= 0xC6 && c2 >= 0xA1 && c2 <= 0xFE) { - unsigned int w = (c - 0xA1)*190 + c2 - 0x41; - ZEND_ASSERT(w < uhc2_ucs_table_size); - w = uhc2_ucs_table[w]; + if (c <= 0xC6) { + unsigned int w = (c - 0x81)*190 + c2 - 0x41; + ZEND_ASSERT(w < uhc1_ucs_table_size); + w = uhc1_ucs_table[w]; if (!w) w = MBFL_BAD_INPUT; *out++ = w; - } else if (c >= 0xC7 && c <= 0xFE && c != 0xC9 && c2 >= 0xA1 && c2 <= 0xFE) { + } else { unsigned int w = (c - 0xC7)*94 + c2 - 0xA1; ZEND_ASSERT(w < uhc3_ucs_table_size); w = uhc3_ucs_table[w]; if (!w) w = MBFL_BAD_INPUT; *out++ = w; - } else { - *out++ = MBFL_BAD_INPUT; } } else { *out++ = MBFL_BAD_INPUT; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_tw.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_tw.c index de1deb47705f1..522f5f4a05a5b 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_tw.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_tw.c @@ -68,7 +68,8 @@ const mbfl_encoding mbfl_encoding_euc_tw = { &vtbl_euctw_wchar, &vtbl_wchar_euctw, mb_euctw_to_wchar, - mb_wchar_to_euctw + mb_wchar_to_euctw, + NULL }; const struct mbfl_convert_vtbl vtbl_euctw_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_gb18030.c b/ext/mbstring/libmbfl/filters/mbfilter_gb18030.c index 492df6046244f..6485e735ed4ba 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_gb18030.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_gb18030.c @@ -22,7 +22,7 @@ * */ /* - * the source code included in this files was separated from mbfilter_cp936.c + * the source code included in this file was separated from mbfilter_cp936.c * by rui hirokawa on 11 Aug 2011. * */ @@ -49,7 +49,8 @@ const mbfl_encoding mbfl_encoding_gb18030 = { &vtbl_gb18030_wchar, &vtbl_wchar_gb18030, mb_gb18030_to_wchar, - mb_wchar_to_gb18030 + mb_wchar_to_gb18030, + NULL }; const struct mbfl_convert_vtbl vtbl_gb18030_wchar = { @@ -388,6 +389,22 @@ int mbfl_filt_conv_wchar_gb18030(int c, mbfl_convert_filter *filter) return 0; } +static const unsigned short gb18030_pua_tbl3[] = { +/* 0xFE50 */ +0x0000,0xE816,0xE817,0xE818,0x0000,0x0000,0x0000,0x0000, +0x0000,0xE81E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0xE826,0x0000,0x0000,0x0000,0x0000,0xE82B,0xE82C, +0x0000,0x0000,0x0000,0x0000,0xE831,0xE832,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xE83B,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xE843,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0xE854,0xE855,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +/* 0xFEA0 */ +0xE864 +}; + static size_t mb_gb18030_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -398,9 +415,14 @@ static size_t mb_gb18030_to_wchar(unsigned char **in, size_t *in_len, uint32_t * if (c < 0x80) { *out++ = c; - } else if (c > 0x80 && c < 0xFF && p < e) { + } else if (c == 0x80 || c == 0xFF) { + *out++ = MBFL_BAD_INPUT; + } else { + if (p == e) { + *out++ = MBFL_BAD_INPUT; + break; + } unsigned char c2 = *p++; - unsigned int s = (c << 8) | c2; if (((c >= 0x81 && c <= 0x84) || (c >= 0x90 && c <= 0xE3)) && c2 >= 0x30 && c2 <= 0x39) { if (p >= e) { @@ -437,32 +459,39 @@ static size_t mb_gb18030_to_wchar(unsigned char **in, size_t *in_len, uint32_t * } else if (c >= 0xA1 && c <= 0xA7 && c2 >= 0x40 && c2 < 0xA1 && c2 != 0x7F) { /* UDA part 3: U+E4C6-U+E765 */ *out++ = 96*(c - 0xA1) + c2 - (c2 >= 0x80 ? 0x41 : 0x40) + 0xE4C6; - } else { - if ((s >= 0xA2AB && s <= 0xA9FE) || (s >= 0xD7FA && s <= 0xD7FE) || (s >= 0xFE50 && s <= 0xFEA0)) { - for (int i = 0; i < mbfl_gb18030_pua_tbl_max; i++) { - if (s >= mbfl_gb18030_pua_tbl[i][2] && s <= mbfl_gb18030_pua_tbl[i][2] + mbfl_gb18030_pua_tbl[i][1] - mbfl_gb18030_pua_tbl[i][0]) { - *out++ = s - mbfl_gb18030_pua_tbl[i][2] + mbfl_gb18030_pua_tbl[i][0]; - goto next_iteration; + } else if (c2 >= 0x40 && c2 != 0x7F && c2 != 0xFF) { + unsigned int w = (c - 0x81)*192 + c2 - 0x40; + + if (w >= 0x192B) { + if (w <= 0x1EBE) { + if (w != 0x1963 && w != 0x1DBF && (w < 0x1E49 || w > 0x1E55) && w != 0x1E7F) { + *out++ = cp936_pua_tbl1[w - 0x192B]; + continue; + } + } else if (w >= 0x413A) { + if (w <= 0x413E) { + *out++ = cp936_pua_tbl2[w - 0x413A]; + continue; + } else if (w >= 0x5DD0 && w <= 0x5E20) { + unsigned int c = gb18030_pua_tbl3[w - 0x5DD0]; + if (c) { + *out++ = c; + continue; + } } } } - if ((c >= 0xA1 && c <= 0xA9 && c2 >= 0xA1 && c2 <= 0xFE) || - (c >= 0xB0 && c <= 0xf7 && c2 >= 0xa1 && c2 <= 0xfe) || - (c >= 0x81 && c <= 0xa0 && c2 >= 0x40 && c2 <= 0xfe && c2 != 0x7f) || - (c >= 0xAA && c <= 0xfe && c2 >= 0x40 && c2 <= 0xa0 && c2 != 0x7f) || - (c >= 0xA8 && c <= 0xa9 && c2 >= 0x40 && c2 <= 0xa0 && c2 != 0x7F)) { - unsigned int w = (c - 0x81)*192 + c2 - 0x40; + if ((c >= 0x81 && c <= 0xA9) || (c >= 0xB0 && c <= 0xF7 && c2 >= 0xA1) || (c >= 0xAA && c <= 0xFE && c2 <= 0xA0)) { ZEND_ASSERT(w < cp936_ucs_table_size); *out++ = cp936_ucs_table[w]; } else { *out++ = MBFL_BAD_INPUT; } + } else { + *out++ = MBFL_BAD_INPUT; } - } else { - *out++ = MBFL_BAD_INPUT; } -next_iteration: ; } *in_len = e - p; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c b/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c index afebdfd00811f..a75a9c757cb83 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c @@ -66,7 +66,8 @@ const mbfl_encoding mbfl_encoding_html_ent = { &vtbl_html_wchar, &vtbl_wchar_html, mb_htmlent_to_wchar, - mb_wchar_to_htmlent + mb_wchar_to_htmlent, + NULL }; const struct mbfl_convert_vtbl vtbl_wchar_html = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_hz.c b/ext/mbstring/libmbfl/filters/mbfilter_hz.c index 72e5963acfc18..b047bfc8b7b27 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_hz.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_hz.c @@ -47,7 +47,8 @@ const mbfl_encoding mbfl_encoding_hz = { &vtbl_hz_wchar, &vtbl_wchar_hz, mb_hz_to_wchar, - mb_wchar_to_hz + mb_wchar_to_hz, + NULL }; const struct mbfl_convert_vtbl vtbl_hz_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_iso2022_jp_ms.c b/ext/mbstring/libmbfl/filters/mbfilter_iso2022_jp_ms.c index 65b6d66d2ec2e..e3676d30e2904 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_iso2022_jp_ms.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_iso2022_jp_ms.c @@ -51,7 +51,8 @@ const mbfl_encoding mbfl_encoding_2022jpms = { &vtbl_2022jpms_wchar, &vtbl_wchar_2022jpms, mb_iso2022jpms_to_wchar, - mb_wchar_to_iso2022jpms + mb_wchar_to_iso2022jpms, + NULL }; const struct mbfl_convert_vtbl vtbl_2022jpms_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_iso2022_kr.c b/ext/mbstring/libmbfl/filters/mbfilter_iso2022_kr.c index c4b2bf0b9f1b9..dcf8fc51b6637 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_iso2022_kr.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_iso2022_kr.c @@ -54,7 +54,8 @@ const mbfl_encoding mbfl_encoding_2022kr = { &vtbl_2022kr_wchar, &vtbl_wchar_2022kr, mb_iso2022kr_to_wchar, - mb_wchar_to_iso2022kr + mb_wchar_to_iso2022kr, + NULL }; const struct mbfl_convert_vtbl vtbl_wchar_2022kr = { @@ -119,9 +120,9 @@ int mbfl_filt_conv_2022kr_wchar(int c, mbfl_convert_filter *filter) if (flag > 0 && c > 0x20 && c < 0x7f) { if (flag == 1) { if (c1 != 0x22 || c <= 0x65) { - w = (c1 - 0x21)*190 + (c - 0x41) + 0x80; - ZEND_ASSERT(w < uhc2_ucs_table_size); - w = uhc2_ucs_table[w]; + w = (c1 - 1)*190 + (c - 0x41) + 0x80; + ZEND_ASSERT(w < uhc1_ucs_table_size); + w = uhc1_ucs_table[w]; } } else { w = (c1 - 0x47)*94 + c - 0x21; @@ -329,9 +330,9 @@ static size_t mb_iso2022kr_to_wchar(unsigned char **in, size_t *in_len, uint32_t if (c < 0x47) { if (c != 0x22 || c2 <= 0x65) { - w = (c - 0x21)*190 + (c2 - 0x41) + 0x80; - ZEND_ASSERT(w < uhc2_ucs_table_size); - w = uhc2_ucs_table[w]; + w = (c - 1)*190 + c2 - 0x41 + 0x80; + ZEND_ASSERT(w < uhc1_ucs_table_size); + w = uhc1_ucs_table[w]; } } else if (c != 0x49 && c <= 0x7D) { w = (c - 0x47)*94 + c2 - 0x21; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_mobile.c b/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_mobile.c index ded492cafc13a..79b7a4714af23 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_mobile.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_mobile.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter_iso2022_jp_ms.c + * The source code included in this file was separated from mbfilter_iso2022_jp_ms.c * by Rui Hirokawa on 25 July 2011. * */ @@ -71,7 +71,8 @@ const mbfl_encoding mbfl_encoding_2022jp_kddi = { &vtbl_2022jp_kddi_wchar, &vtbl_wchar_2022jp_kddi, mb_iso2022jp_kddi_to_wchar, - mb_wchar_to_iso2022jp_kddi + mb_wchar_to_iso2022jp_kddi, + NULL }; const struct mbfl_convert_vtbl vtbl_2022jp_kddi_wchar = { @@ -414,7 +415,7 @@ static int mbfl_filt_conv_wchar_2022jp_mobile(int c, mbfl_convert_filter *filter } } - if (mbfilter_unicode2sjis_emoji_kddi(c, &s1, filter)) { + if (mbfilter_unicode2sjis_emoji_kddi(c, &s1, filter) > 0) { /* A KDDI emoji was detected and stored in s1 */ CODE2JIS(c1,c2,s1,s2); s1 -= 0x1600; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_jis.c b/ext/mbstring/libmbfl/filters/mbfilter_jis.c index fc5f18aeb5d1c..80af0e695644c 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_jis.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_jis.c @@ -37,6 +37,8 @@ static int mbfl_filt_conv_jis_wchar_flush(mbfl_convert_filter *filter); static size_t mb_iso2022jp_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static void mb_wchar_to_iso2022jp(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); static void mb_wchar_to_jis(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static bool mb_check_iso2022jp(unsigned char *in, size_t in_len); +static bool mb_check_jis(unsigned char *in, size_t in_len); const mbfl_encoding mbfl_encoding_jis = { mbfl_no_encoding_jis, @@ -49,6 +51,7 @@ const mbfl_encoding mbfl_encoding_jis = { &vtbl_wchar_jis, mb_iso2022jp_to_wchar, mb_wchar_to_jis, + mb_check_jis }; const mbfl_encoding mbfl_encoding_2022jp = { @@ -61,7 +64,8 @@ const mbfl_encoding mbfl_encoding_2022jp = { &vtbl_2022jp_wchar, &vtbl_wchar_2022jp, mb_iso2022jp_to_wchar, - mb_wchar_to_iso2022jp + mb_wchar_to_iso2022jp, + mb_check_iso2022jp }; const struct mbfl_convert_vtbl vtbl_jis_wchar = { @@ -780,3 +784,161 @@ static void mb_wchar_to_jis(uint32_t *in, size_t len, mb_convert_buf *buf, bool MB_CONVERT_BUF_STORE(buf, out, limit); } + +#define JISX_0201_KANA_SO 5 + +static bool mb_check_jis(unsigned char *in, size_t in_len) +{ + unsigned char *p = in, *e = p + in_len; + unsigned int state = ASCII; + + while (p < e) { + unsigned char c = *p++; + if (c == 0x1B) { + /* ESC seen; this is an escape sequence */ + if (state == JISX_0201_KANA_SO) { + return false; + } + if ((e - p) < 2) { + return false; + } + unsigned char c2 = *p++; + if (c2 == '$') { + unsigned char c3 = *p++; + if (c3 == '@' || c3 == 'B') { + state = JISX_0208; + } else if (c3 == '(') { + if (p == e) { + return false; + } + unsigned char c4 = *p++; + if (c4 == '@' || c4 == 'B') { + state = JISX_0208; + } else if (c4 == 'D') { + state = JISX_0212; + } else { + return false; + } + } else { + return false; + } + } else if (c2 == '(') { + unsigned char c3 = *p++; + /* ESC ( H is treated as a sequence transitioning to ASCII for historical reasons. + * see https://github.com/php/php-src/pull/10828#issuecomment-1478342432. */ + if (c3 == 'B' || c3 == 'H') { + state = ASCII; + } else if (c3 == 'J') { + state = JISX_0201_LATIN; + } else if (c3 == 'I') { + state = JISX_0201_KANA; + } else { + return false; + } + } else { + return false; + } + } else if (c == 0xE) { + /* "Kana In" marker */ + if (state != ASCII) { + return false; + } + state = JISX_0201_KANA_SO; + } else if (c == 0xF) { + /* "Kana Out" marker */ + if (state != JISX_0201_KANA_SO) { + return false; + } + state = ASCII; + } else if ((state == JISX_0208 || state == JISX_0212) && (c > 0x20 && c < 0x7F)) { + if (p == e) { + return false; + } + unsigned char c2 = *p++; + if (c2 > 0x20 && c2 < 0x7F) { + unsigned int s = (c - 0x21)*94 + c2 - 0x21; + if (state == JISX_0208) { + if (s < jisx0208_ucs_table_size && jisx0208_ucs_table[s]) { + continue; + } + } else { + if (s < jisx0212_ucs_table_size && jisx0212_ucs_table[s]) { + continue; + } + } + return false; + } else { + return false; + } + } else if (c < 0x80) { + continue; + } else if (c >= 0xA1 && c <= 0xDF) { + /* GR-invoked Kana */ + continue; + } else { + return false; + } + } + + return state == ASCII; +} + + +static bool mb_check_iso2022jp(unsigned char *in, size_t in_len) +{ + unsigned char *p = in, *e = p + in_len; + unsigned int state = ASCII; + + while (p < e) { + unsigned char c = *p++; + if (c == 0x1B) { + /* ESC seen; this is an escape sequence */ + if ((e - p) < 2) { + return false; + } + unsigned char c2 = *p++; + if (c2 == '$') { + unsigned char c3 = *p++; + if (c3 == '@' || c3 == 'B') { + state = JISX_0208; + } else { + return false; + } + } else if (c2 == '(') { + unsigned char c3 = *p++; + if (c3 == 'B') { + state = ASCII; + } else if (c3 == 'J') { + state = JISX_0201_LATIN; + } else { + return false; + } + } else { + return false; + } + } else if (c == 0xE || c == 0xF) { + /* "Kana In" or "Kana Out" marker; ISO-2022-JP is not accepted. */ + return false; + } else if (state == JISX_0208 && (c > 0x20 && c < 0x7F)) { + if (p == e) { + return false; + } + unsigned char c2 = *p++; + if (c2 > 0x20 && c2 < 0x7F) { + unsigned int s = (c - 0x21)*94 + c2 - 0x21; + if (s < jisx0208_ucs_table_size && jisx0208_ucs_table[s]) { + continue; + } + return false; + } else { + return false; + } + } else if (c < 0x80) { + continue; + } else { + return false; + } + } + + return state == ASCII; +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_qprint.c b/ext/mbstring/libmbfl/filters/mbfilter_qprint.c index 5fde30ee80935..c743942d0c5c4 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_qprint.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_qprint.c @@ -22,14 +22,13 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by moriyoshi koizumi on 4 dec 2002. * */ #include "mbfilter.h" #include "mbfilter_qprint.h" -#include "unicode_prop.h" static size_t mb_qprint_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static void mb_wchar_to_qprint(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); @@ -46,7 +45,8 @@ const mbfl_encoding mbfl_encoding_qprint = { NULL, NULL, mb_qprint_to_wchar, - mb_wchar_to_qprint + mb_wchar_to_qprint, + NULL }; const struct mbfl_convert_vtbl vtbl_8bit_qprint = { @@ -96,28 +96,25 @@ int mbfl_filt_conv_qprintenc(int c, mbfl_convert_filter *filter) break; } - if ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) == 0) { - if (s == 0x0a || (s == 0x0d && c != 0x0a)) { /* line feed */ - CK((*filter->output_function)(0x0d, filter->data)); /* CR */ - CK((*filter->output_function)(0x0a, filter->data)); /* LF */ - filter->status &= ~0xff00; - break; - } else if (s == 0x0d) { - break; - } + if (s == '\n' || (s == '\r' && c != '\n')) { /* line feed */ + CK((*filter->output_function)('\r', filter->data)); + CK((*filter->output_function)('\n', filter->data)); + filter->status &= ~0xff00; + break; + } else if (s == 0x0d) { + break; } - if ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) == 0 && n >= 72) { /* soft line feed */ - CK((*filter->output_function)(0x3d, filter->data)); /* '=' */ - CK((*filter->output_function)(0x0d, filter->data)); /* CR */ - CK((*filter->output_function)(0x0a, filter->data)); /* LF */ + if (n >= 72) { /* soft line feed */ + CK((*filter->output_function)('=', filter->data)); + CK((*filter->output_function)('\r', filter->data)); + CK((*filter->output_function)('\n', filter->data)); filter->status &= ~0xff00; } - if (s <= 0 || s >= 0x80 || s == 0x3d /* not ASCII or '=' */ - || ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) && mime_char_needs_qencode[s])) { + if (s <= 0 || s >= 0x80 || s == '=') { /* not ASCII or '=' */ /* hex-octet */ - CK((*filter->output_function)(0x3d, filter->data)); /* '=' */ + CK((*filter->output_function)('=', filter->data)); n = (s >> 4) & 0xf; if (n < 10) { n += 48; /* '0' */ @@ -132,14 +129,10 @@ int mbfl_filt_conv_qprintenc(int c, mbfl_convert_filter *filter) n += 55; } CK((*filter->output_function)(n, filter->data)); - if ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) == 0) { - filter->status += 0x300; - } + filter->status += 0x300; } else { CK((*filter->output_function)(s, filter->data)); - if ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) == 0) { - filter->status += 0x100; - } + filter->status += 0x100; } break; } diff --git a/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c b/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c index 56c9b2dbc85d9..c5872335a8526 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c @@ -86,7 +86,8 @@ static int mbfl_conv_reverselookup_table(int c, mbfl_convert_filter *filter, int &vtbl_##id##_wchar, \ &vtbl_wchar_##id, \ mb_##id##_to_wchar, \ - mb_wchar_to_##id \ + mb_wchar_to_##id, \ + NULL \ } /* For single-byte encodings which use a conversion table */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_sjis.c b/ext/mbstring/libmbfl/filters/mbfilter_sjis.c index 688c82727a4ff..4db34c56b0e57 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_sjis.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_sjis.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter_ja.c + * The source code included in this file was separated from mbfilter_ja.c * by moriyoshi koizumi on 4 dec 2002. * */ @@ -61,7 +61,7 @@ static void mb_wchar_to_sjis_kddi(uint32_t *in, size_t len, mb_convert_buf *buf, static size_t mb_sjis_sb_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static void mb_wchar_to_sjis_sb(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); -const unsigned char mblen_table_sjis[] = { /* 0x80-0x9f,0xE0-0xFF */ +const unsigned char mblen_table_sjis[] = { /* 0x81-0x9F,0xE0-0xEF */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -70,14 +70,52 @@ const unsigned char mblen_table_sjis[] = { /* 0x80-0x9f,0xE0-0xFF */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +const unsigned char mblen_table_sjismac[] = { /* 0x81-0x9F,0xE0-0xED */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +const unsigned char mblen_table_sjis_mobile[] = { /* 0x81-0x9F,0xE0-0xFC */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 }; static const char *mbfl_encoding_sjis_aliases[] = {"x-sjis", "SHIFT-JIS", NULL}; @@ -92,7 +130,8 @@ const mbfl_encoding mbfl_encoding_sjis = { &vtbl_sjis_wchar, &vtbl_wchar_sjis, mb_sjis_to_wchar, - mb_wchar_to_sjis + mb_wchar_to_sjis, + NULL }; const struct mbfl_convert_vtbl vtbl_sjis_wchar = { @@ -122,12 +161,13 @@ const mbfl_encoding mbfl_encoding_sjis_mac = { "SJIS-mac", "Shift_JIS", mbfl_encoding_sjis_mac_aliases, - mblen_table_sjis, + mblen_table_sjismac, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_mac_wchar, &vtbl_wchar_sjis_mac, mb_sjismac_to_wchar, - mb_wchar_to_sjismac + mb_wchar_to_sjismac, + NULL }; const struct mbfl_convert_vtbl vtbl_sjis_mac_wchar = { @@ -159,12 +199,13 @@ const mbfl_encoding mbfl_encoding_sjis_docomo = { "SJIS-Mobile#DOCOMO", "Shift_JIS", mbfl_encoding_sjis_docomo_aliases, - mblen_table_sjis, + mblen_table_sjis_mobile, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_docomo_wchar, &vtbl_wchar_sjis_docomo, mb_sjis_docomo_to_wchar, - mb_wchar_to_sjis_docomo + mb_wchar_to_sjis_docomo, + NULL }; const mbfl_encoding mbfl_encoding_sjis_kddi = { @@ -172,12 +213,13 @@ const mbfl_encoding mbfl_encoding_sjis_kddi = { "SJIS-Mobile#KDDI", "Shift_JIS", mbfl_encoding_sjis_kddi_aliases, - mblen_table_sjis, + mblen_table_sjis_mobile, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_kddi_wchar, &vtbl_wchar_sjis_kddi, mb_sjis_kddi_to_wchar, - mb_wchar_to_sjis_kddi + mb_wchar_to_sjis_kddi, + NULL }; const mbfl_encoding mbfl_encoding_sjis_sb = { @@ -185,12 +227,13 @@ const mbfl_encoding mbfl_encoding_sjis_sb = { "SJIS-Mobile#SOFTBANK", "Shift_JIS", mbfl_encoding_sjis_sb_aliases, - mblen_table_sjis, + mblen_table_sjis_mobile, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_sb_wchar, &vtbl_wchar_sjis_sb, mb_sjis_sb_to_wchar, - mb_wchar_to_sjis_sb + mb_wchar_to_sjis_sb, + NULL }; const struct mbfl_convert_vtbl vtbl_sjis_docomo_wchar = { @@ -410,7 +453,7 @@ int mbfl_filt_conv_wchar_sjis(int c, mbfl_convert_filter *filter) } static const unsigned short sjis_decode_tbl1[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 376, 564, 752, 940, 1128, 1316, 1504, 1692, 1880, 2068, 2256, 2444, 2632, 2820, 3008, 3196, 3384, 3572, 3760, 3948, 4136, 4324, 4512, 4700, 4888, 5076, 5264, 5452, 5640, -6204, -6016, -5828, -5640, -5452, -5264, -5076, -4888, -4700, -4512, -4324, -4136, -3948, -3760, -3572, -3384, -3196, -3008, -2820, -2632, -2444, -2256, -2068, -1880, -1692, -1504, -1316, -1128, -940, -752, -564, -376, -188, 0, 188, 376, 564, 752, 940, 1128, 1316, 1504, 1692, 1880, 2068, 2256, 2444, 2632, 2820, 3008, 3196, 3384, 3572, 3760, 3948, 4136, 4324, 4512, 4700, 4888, 5076, 5264, 5452, 5640, 5828, 6016, 6204, 6392, 6580, 6768, 6956, 7144, 7332, 7520, 7708, 7896, 8084, 8272, 8460, 8648, 8836, 9024, 9212, 9400, 9588, 9776, 9964, 10152, 10340, 10528, 10716, 10904, 11092 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFFFF, 0, 188, 376, 564, 752, 940, 1128, 1316, 1504, 1692, 1880, 2068, 2256, 2444, 2632, 2820, 3008, 3196, 3384, 3572, 3760, 3948, 4136, 4324, 4512, 4700, 4888, 5076, 5264, 5452, 5640, 0xFFFF, -6016, -5828, -5640, -5452, -5264, -5076, -4888, -4700, -4512, -4324, -4136, -3948, -3760, -3572, -3384, -3196, -3008, -2820, -2632, -2444, -2256, -2068, -1880, -1692, -1504, -1316, -1128, -940, -752, -564, -376, -188, 0, 188, 376, 564, 752, 940, 1128, 1316, 1504, 1692, 1880, 2068, 2256, 2444, 2632, 2820, 3008, 3196, 3384, 3572, 3760, 3948, 4136, 4324, 4512, 4700, 4888, 5076, 5264, 5452, 5640, 5828, 6016, 6204, 6392, 6580, 6768, 6956, 7144, 7332, 7520, 7708, 7896, 8084, 8272, 8460, 8648, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; static const unsigned short sjis_decode_tbl2[] = { @@ -422,6 +465,8 @@ static size_t mb_sjis_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf unsigned char *p = *in, *e = p + *in_len; uint32_t *out = buf, *limit = buf + bufsize; + e--; /* Stop the main loop 1 byte short of the end of the input */ + while (p < e && out < limit) { unsigned char c = *p++; @@ -429,12 +474,15 @@ static size_t mb_sjis_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf *out++ = c; } else if (c >= 0xA1 && c <= 0xDF) { /* Kana */ *out++ = 0xFEC0 + c; - } else if (c > 0x80 && c <= 0xEF && c != 0xA0 && p < e) { + } else { + /* Don't need to check p < e; it's not possible to go out of bounds here, due to e-- above */ unsigned char c2 = *p++; /* This is only legal if c2 >= 0x40 && c2 <= 0xFC && c2 != 0x7F * But the values in the above conversion tables have been chosen such that * illegal values of c2 will always result in w > jisx0208_ucs_table_size, - * so we don't need to do a separate bounds check on c2 */ + * so we don't need to do a separate bounds check on c2 + * Likewise, the values in the conversion tables are such that illegal values + * for c will always result in w > jisx0208_ucs_table_size */ uint32_t w = sjis_decode_tbl1[c] + sjis_decode_tbl2[c2]; if (w < jisx0208_ucs_table_size) { w = jisx0208_ucs_table[w]; @@ -442,14 +490,27 @@ static size_t mb_sjis_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf w = MBFL_BAD_INPUT; *out++ = w; } else { + if (c == 0x80 || c == 0xA0 || c > 0xEF) { + p--; + } *out++ = MBFL_BAD_INPUT; } + } + } + + /* Finish up last byte of input string if there is one */ + if (p == e && out < limit) { + unsigned char c = *p++; + if (c <= 0x7F) { + *out++ = c; + } else if (c >= 0xA1 && c <= 0xDF) { + *out++ = 0xFEC0 + c; } else { *out++ = MBFL_BAD_INPUT; } } - *in_len = e - p; + *in_len = e - p + 1; *in = p; return out - buf; } @@ -1057,11 +1118,17 @@ static size_t mb_sjismac_to_wchar(unsigned char **in, size_t *in_len, uint32_t * while (p < e && out < limit) { unsigned char c = *p++; - if (c < 0x80 && c != 0x5C) { - *out++ = c; + if (c <= 0x80 || c == 0xA0) { + if (c == 0x5C) { + *out++ = 0xA5; + } else if (c == 0x80) { + *out++ = 0x5C; + } else { + *out++ = c; + } } else if (c >= 0xA1 && c <= 0xDF) { *out++ = 0xFEC0 + c; - } else if (c > 0x80 && c <= 0xED && c != 0xA0) { + } else if (c <= 0xED) { if (p == e) { *out++ = MBFL_BAD_INPUT; break; @@ -1162,12 +1229,6 @@ static size_t mb_sjismac_to_wchar(unsigned char **in, size_t *in_len, uint32_t * } else { *out++ = MBFL_BAD_INPUT; } - } else if (c == 0x5C) { - *out++ = 0xA5; - } else if (c == 0x80) { - *out++ = 0x5C; - } else if (c == 0xA0) { - *out++ = 0xA0; } else if (c == 0xFD) { *out++ = 0xA9; } else if (c == 0xFE) { @@ -1339,8 +1400,8 @@ process_codepoint: ; /* This might be a valid transcoding hint sequence */ int index = 3; -resume_transcoding_hint: if (buf->state) { +resume_transcoding_hint: i = buf->state >> 24; index = (buf->state >> 16) & 0xFF; buf->state = 0; @@ -2095,6 +2156,10 @@ int mbfl_filt_conv_sjis_mobile_flush(mbfl_convert_filter *filter) return 0; } +static const unsigned short sjis_mobile_decode_tbl1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFFFF, 0, 188, 376, 564, 752, 940, 1128, 1316, 1504, 1692, 1880, 2068, 2256, 2444, 2632, 2820, 3008, 3196, 3384, 3572, 3760, 3948, 4136, 4324, 4512, 4700, 4888, 5076, 5264, 5452, 5640, 0xFFFF, -6016, -5828, -5640, -5452, -5264, -5076, -4888, -4700, -4512, -4324, -4136, -3948, -3760, -3572, -3384, -3196, -3008, -2820, -2632, -2444, -2256, -2068, -1880, -1692, -1504, -1316, -1128, -940, -752, -564, -376, -188, 0, 188, 376, 564, 752, 940, 1128, 1316, 1504, 1692, 1880, 2068, 2256, 2444, 2632, 2820, 3008, 3196, 3384, 3572, 3760, 3948, 4136, 4324, 4512, 4700, 4888, 5076, 5264, 5452, 5640, 5828, 6016, 6204, 6392, 6580, 6768, 6956, 7144, 7332, 7520, 7708, 7896, 8084, 8272, 8460, 8648, 8836, 9024, 9212, 9400, 9588, 9776, 9964, 10152, 10340, 10528, 10716, 10904, 11092, 0xFFFF, 0xFFFF, 0xFFFF +}; + static size_t mb_sjis_docomo_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -2110,14 +2175,14 @@ static size_t mb_sjis_docomo_to_wchar(unsigned char **in, size_t *in_len, uint32 } else if (c >= 0xA1 && c <= 0xDF) { /* Kana */ *out++ = 0xFEC0 + c; - } else if (c > 0x80 && c < 0xFD && c != 0xA0) { + } else { /* Kanji */ if (p == e) { *out++ = MBFL_BAD_INPUT; break; } unsigned char c2 = *p++; - uint32_t w = sjis_decode_tbl1[c] + sjis_decode_tbl2[c2]; + uint32_t w = sjis_mobile_decode_tbl1[c] + sjis_decode_tbl2[c2]; if (w <= 137) { if (w == 31) { @@ -2161,13 +2226,14 @@ static size_t mb_sjis_docomo_to_wchar(unsigned char **in, size_t *in_len, uint32 } else if (w >= (94*94) && w < (114*94)) { w = w - (94*94) + 0xE000; } else { + if (c == 0x80 || c == 0xA0 || c >= 0xFD) { + p--; + } *out++ = MBFL_BAD_INPUT; continue; } *out++ = w ? w : MBFL_BAD_INPUT; - } else { - *out++ = MBFL_BAD_INPUT; } } @@ -2189,11 +2255,7 @@ static void mb_wchar_to_sjis_docomo(uint32_t *in, size_t len, mb_convert_buf *bu /* Continue what we were doing on the previous call */ w = buf->state; buf->state = 0; - if (len) { - goto reprocess_wchar; - } else { - goto emit_output; - } + goto reprocess_wchar; } while (len--) { @@ -2337,14 +2399,14 @@ static size_t mb_sjis_kddi_to_wchar(unsigned char **in, size_t *in_len, uint32_t } else if (c >= 0xA1 && c <= 0xDF) { /* Kana */ *out++ = 0xFEC0 + c; - } else if (c > 0x80 && c < 0xFD && c != 0xA0) { + } else { /* Kanji */ if (p == e) { *out++ = MBFL_BAD_INPUT; break; } unsigned char c2 = *p++; - uint32_t w = sjis_decode_tbl1[c] + sjis_decode_tbl2[c2]; + uint32_t w = sjis_mobile_decode_tbl1[c] + sjis_decode_tbl2[c2]; if (w <= 137) { if (w == 31) { @@ -2375,7 +2437,7 @@ static size_t mb_sjis_kddi_to_wchar(unsigned char **in, size_t *in_len, uint32_t int snd = 0; w = mbfilter_sjis_emoji_kddi2unicode(w, &snd); if (!w) { - w = sjis_decode_tbl1[c] + sjis_decode_tbl2[c2]; + w = sjis_mobile_decode_tbl1[c] + sjis_decode_tbl2[c2]; if (w >= (94*94) && w < (114*94)) { w = w - (94*94) + 0xE000; } @@ -2393,13 +2455,14 @@ static size_t mb_sjis_kddi_to_wchar(unsigned char **in, size_t *in_len, uint32_t } else if (w >= (94*94) && w < (114*94)) { w = w - (94*94) + 0xE000; } else { + if (c == 0x80 || c == 0xA0 || c >= 0xFD) { + p--; + } *out++ = MBFL_BAD_INPUT; continue; } *out++ = w ? w : MBFL_BAD_INPUT; - } else { - *out++ = MBFL_BAD_INPUT; } } @@ -2420,11 +2483,7 @@ static void mb_wchar_to_sjis_kddi(uint32_t *in, size_t len, mb_convert_buf *buf, if (buf->state) { w = buf->state; buf->state = 0; - if (len) { - goto reprocess_wchar; - } else { - goto emit_output; - } + goto reprocess_wchar; } while (len--) { @@ -2645,14 +2704,14 @@ static size_t mb_sjis_sb_to_wchar(unsigned char **in, size_t *in_len, uint32_t * } else if (c >= 0xA1 && c <= 0xDF) { /* Kana */ *out++ = 0xFEC0 + c; - } else if (c > 0x80 && c < 0xFD && c != 0xA0) { + } else { /* Kanji */ if (p == e) { *out++ = MBFL_BAD_INPUT; break; } unsigned char c2 = *p++; - uint32_t w = sjis_decode_tbl1[c] + sjis_decode_tbl2[c2]; + uint32_t w = sjis_mobile_decode_tbl1[c] + sjis_decode_tbl2[c2]; if (w <= 137) { if (w == 31) { @@ -2683,7 +2742,7 @@ static size_t mb_sjis_sb_to_wchar(unsigned char **in, size_t *in_len, uint32_t * int snd = 0; w = mbfilter_sjis_emoji_sb2unicode(w, &snd); if (!w) { - w = sjis_decode_tbl1[c] + sjis_decode_tbl2[c2]; + w = sjis_mobile_decode_tbl1[c] + sjis_decode_tbl2[c2]; if (w >= cp932ext3_ucs_table_min && w < cp932ext3_ucs_table_max) { w = cp932ext3_ucs_table[w - cp932ext3_ucs_table_min]; } else if (w >= (94*94) && w < (114*94)) { @@ -2703,13 +2762,14 @@ static size_t mb_sjis_sb_to_wchar(unsigned char **in, size_t *in_len, uint32_t * } else if (w >= (94*94) && w < (114*94)) { w = w - (94*94) + 0xE000; } else { + if (c == 0x80 || c == 0xA0 || c >= 0xFD) { + p--; + } *out++ = MBFL_BAD_INPUT; continue; } *out++ = w ? w : MBFL_BAD_INPUT; - } else { - *out++ = MBFL_BAD_INPUT; } } @@ -2730,11 +2790,7 @@ static void mb_wchar_to_sjis_sb(uint32_t *in, size_t len, mb_convert_buf *buf, b if (buf->state) { w = buf->state; buf->state = 0; - if (len) { - goto reprocess_wchar; - } else { - goto emit_output; - } + goto reprocess_wchar; } while (len--) { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_sjis_2004.c b/ext/mbstring/libmbfl/filters/mbfilter_sjis_2004.c index 78d4bd431071f..bc4d932187061 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_sjis_2004.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_sjis_2004.c @@ -41,7 +41,7 @@ #include "unicode_table_jis2004.h" #include "unicode_table_jis.h" -extern const unsigned char mblen_table_sjis[]; +extern const unsigned char mblen_table_sjis_mobile[]; extern const unsigned char mblen_table_eucjp[]; static size_t mb_sjis2004_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); @@ -62,12 +62,13 @@ const mbfl_encoding mbfl_encoding_sjis2004 = { "SJIS-2004", "Shift_JIS", mbfl_encoding_sjis2004_aliases, - mblen_table_sjis, + mblen_table_sjis_mobile, /* Leading byte values used for SJIS-2004 are the same as mobile SJIS variants */ MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis2004_wchar, &vtbl_wchar_sjis2004, mb_sjis2004_to_wchar, - mb_wchar_to_sjis2004 + mb_wchar_to_sjis2004, + NULL }; const struct mbfl_convert_vtbl vtbl_sjis2004_wchar = { @@ -100,7 +101,8 @@ const mbfl_encoding mbfl_encoding_eucjp2004 = { &vtbl_eucjp2004_wchar, &vtbl_wchar_eucjp2004, mb_eucjp2004_to_wchar, - mb_wchar_to_eucjp2004 + mb_wchar_to_eucjp2004, + NULL }; const struct mbfl_convert_vtbl vtbl_eucjp2004_wchar = { @@ -133,7 +135,8 @@ const mbfl_encoding mbfl_encoding_2022jp_2004 = { &vtbl_2022jp_2004_wchar, &vtbl_wchar_2022jp_2004, mb_iso2022jp2004_to_wchar, - mb_wchar_to_iso2022jp2004 + mb_wchar_to_iso2022jp2004, + NULL }; const struct mbfl_convert_vtbl vtbl_2022jp_2004_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c b/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c index 3e0d0828cfa62..e6711d82f8a70 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c @@ -56,7 +56,8 @@ const mbfl_encoding mbfl_encoding_ucs2 = { &vtbl_ucs2_wchar, &vtbl_wchar_ucs2, mb_ucs2_to_wchar, - mb_wchar_to_ucs2be + mb_wchar_to_ucs2be, + NULL }; const mbfl_encoding mbfl_encoding_ucs2be = { @@ -69,7 +70,8 @@ const mbfl_encoding mbfl_encoding_ucs2be = { &vtbl_ucs2be_wchar, &vtbl_wchar_ucs2be, mb_ucs2be_to_wchar, - mb_wchar_to_ucs2be + mb_wchar_to_ucs2be, + NULL }; const mbfl_encoding mbfl_encoding_ucs2le = { @@ -82,7 +84,8 @@ const mbfl_encoding mbfl_encoding_ucs2le = { &vtbl_ucs2le_wchar, &vtbl_wchar_ucs2le, mb_ucs2le_to_wchar, - mb_wchar_to_ucs2le + mb_wchar_to_ucs2le, + NULL }; const struct mbfl_convert_vtbl vtbl_ucs2_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c b/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c index 90312b8d501d5..1585cb82e3ff9 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by moriyoshi koizumi on 4 dec 2002. * */ @@ -56,7 +56,8 @@ const mbfl_encoding mbfl_encoding_ucs4 = { &vtbl_ucs4_wchar, &vtbl_wchar_ucs4, mb_ucs4_to_wchar, - mb_wchar_to_ucs4be + mb_wchar_to_ucs4be, + NULL }; const mbfl_encoding mbfl_encoding_ucs4be = { @@ -69,7 +70,8 @@ const mbfl_encoding mbfl_encoding_ucs4be = { &vtbl_ucs4be_wchar, &vtbl_wchar_ucs4be, mb_ucs4be_to_wchar, - mb_wchar_to_ucs4be + mb_wchar_to_ucs4be, + NULL }; const mbfl_encoding mbfl_encoding_ucs4le = { @@ -82,7 +84,8 @@ const mbfl_encoding mbfl_encoding_ucs4le = { &vtbl_ucs4le_wchar, &vtbl_wchar_ucs4le, mb_ucs4le_to_wchar, - mb_wchar_to_ucs4le + mb_wchar_to_ucs4le, + NULL }; const struct mbfl_convert_vtbl vtbl_ucs4_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_uhc.c b/ext/mbstring/libmbfl/filters/mbfilter_uhc.c index 2ac351d644cdb..8d611adb5ac3e 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_uhc.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_uhc.c @@ -71,7 +71,8 @@ const mbfl_encoding mbfl_encoding_uhc = { &vtbl_uhc_wchar, &vtbl_wchar_uhc, mb_uhc_to_wchar, - mb_wchar_to_uhc + mb_wchar_to_uhc, + NULL }; const struct mbfl_convert_vtbl vtbl_uhc_wchar = { @@ -114,16 +115,11 @@ int mbfl_filt_conv_uhc_wchar(int c, mbfl_convert_filter *filter) filter->status = 0; int c1 = filter->cache, w = 0; - if (c1 >= 0x81 && c1 <= 0xa0 && c >= 0x41 && c <= 0xfe) { + if (c1 >= 0x81 && c1 <= 0xc6 && c >= 0x41 && c <= 0xfe) { w = (c1 - 0x81)*190 + (c - 0x41); if (w >= 0 && w < uhc1_ucs_table_size) { w = uhc1_ucs_table[w]; } - } else if (c1 >= 0xa1 && c1 <= 0xc6 && c >= 0x41 && c <= 0xfe) { - w = (c1 - 0xa1)*190 + (c - 0x41); - if (w >= 0 && w < uhc2_ucs_table_size) { - w = uhc2_ucs_table[w]; - } } else if (c1 >= 0xc7 && c1 < 0xfe && c >= 0xa1 && c <= 0xfe) { w = (c1 - 0xc7)*94 + (c - 0xa1); if (w >= 0 && w < uhc3_ucs_table_size) { @@ -201,29 +197,39 @@ static size_t mb_uhc_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, unsigned char *p = *in, *e = p + *in_len; uint32_t *out = buf, *limit = buf + bufsize; + e--; /* Stop the main loop 1 byte short of the end of the input */ + while (p < e && out < limit) { unsigned char c = *p++; if (c < 0x80) { *out++ = c; - } else if (c > 0x80 && c < 0xFE && c != 0xC9 && p < e) { + } else if (c > 0x80 && c < 0xFE) { + /* We don't need to check p < e here; it's not possible that this pointer dereference + * will be outside the input string, because of e-- above */ unsigned char c2 = *p++; + if (c2 < 0x41 || c2 == 0xFF) { + *out++ = MBFL_BAD_INPUT; + continue; + } unsigned int w = 0; - if (c >= 0x81 && c <= 0xA0 && c2 >= 0x41 && c2 <= 0xFE) { - w = (c - 0x81)*190 + (c2 - 0x41); - if (w < uhc1_ucs_table_size) { - w = uhc1_ucs_table[w]; - } - } else if (c >= 0xA1 && c <= 0xC6 && c2 >= 0x41 && c2 <= 0xFE) { - w = (c - 0xA1)*190 + (c2 - 0x41); - if (w < uhc2_ucs_table_size) { - w = uhc2_ucs_table[w]; - } - } else if (c >= 0xC7 && c < 0xFE && c2 >= 0xA1 && c2 <= 0xFE) { - w = (c - 0xC7)*94 + (c2 - 0xA1); - if (w < uhc3_ucs_table_size) { - w = uhc3_ucs_table[w]; + if (c <= 0xC6) { + w = (c - 0x81)*190 + c2 - 0x41; + ZEND_ASSERT(w < uhc1_ucs_table_size); + w = uhc1_ucs_table[w]; + } else if (c2 >= 0xA1) { + w = (c - 0xC7)*94 + c2 - 0xA1; + ZEND_ASSERT(w < uhc3_ucs_table_size); + w = uhc3_ucs_table[w]; + if (!w) { + /* If c == 0xC9, we shouldn't have tried to read a 2-byte char at all... but it is faster + * to fix up that rare case here rather than include an extra check in the hot path */ + if (c == 0xC9) { + p--; + } + *out++ = MBFL_BAD_INPUT; + continue; } } if (!w) { @@ -235,7 +241,13 @@ static size_t mb_uhc_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, } } - *in_len = e - p; + /* Finish up last byte of input string if there is one */ + if (p == e && out < limit) { + unsigned char c = *p++; + *out++ = (c < 0x80) ? c : MBFL_BAD_INPUT; + } + + *in_len = e - p + 1; *in = p; return out - buf; } diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf16.c b/ext/mbstring/libmbfl/filters/mbfilter_utf16.c index eddd56f362756..9e584cb354c2c 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf16.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf16.c @@ -22,20 +22,159 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by moriyoshi koizumi on 4 dec 2002. * */ +#include "zend_bitset.h" #include "mbfilter.h" #include "mbfilter_utf16.h" +#ifdef ZEND_INTRIN_AVX2_NATIVE + +/* We are building AVX2-only binary */ +# include +# define mb_utf16be_to_wchar mb_utf16be_to_wchar_avx2 +# define mb_utf16le_to_wchar mb_utf16le_to_wchar_avx2 +# define mb_wchar_to_utf16be mb_wchar_to_utf16be_avx2 +# define mb_wchar_to_utf16le mb_wchar_to_utf16le_avx2 + +static size_t mb_utf16be_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16be_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static size_t mb_utf16le_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16le_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); + +#elif defined(ZEND_INTRIN_AVX2_RESOLVER) + +/* We are building binary which works with or without AVX2; whether or not to use + * AVX2-accelerated functions will be determined at runtime */ +# include +# include "Zend/zend_cpuinfo.h" + +static size_t mb_utf16be_to_wchar_default(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16be_default(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static size_t mb_utf16le_to_wchar_default(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16le_default(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); + +# ifdef ZEND_INTRIN_AVX2_FUNC_PROTO +/* Dynamic linker will decide whether or not to use AVX2-based functions and + * resolve symbols accordingly */ + +ZEND_INTRIN_AVX2_FUNC_DECL(size_t mb_utf16be_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state)); +ZEND_INTRIN_AVX2_FUNC_DECL(void mb_wchar_to_utf16be_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end)); +ZEND_INTRIN_AVX2_FUNC_DECL(size_t mb_utf16le_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state)); +ZEND_INTRIN_AVX2_FUNC_DECL(void mb_wchar_to_utf16le_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end)); + +size_t mb_utf16be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) __attribute__((ifunc("resolve_utf16be_wchar"))); +void mb_wchar_to_utf16be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) __attribute__((ifunc("resolve_wchar_utf16be"))); +size_t mb_utf16le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) __attribute__((ifunc("resolve_utf16le_wchar"))); +void mb_wchar_to_utf16le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) __attribute__((ifunc("resolve_wchar_utf16le"))); + +ZEND_NO_SANITIZE_ADDRESS +ZEND_ATTRIBUTE_UNUSED +static mb_to_wchar_fn resolve_utf16be_wchar(void) +{ + return zend_cpu_supports_avx2() ? mb_utf16be_to_wchar_avx2 : mb_utf16be_to_wchar_default; +} + +ZEND_NO_SANITIZE_ADDRESS +ZEND_ATTRIBUTE_UNUSED +static mb_from_wchar_fn resolve_wchar_utf16be(void) +{ + return zend_cpu_supports_avx2() ? mb_wchar_to_utf16be_avx2 : mb_wchar_to_utf16be_default; +} + +ZEND_NO_SANITIZE_ADDRESS +ZEND_ATTRIBUTE_UNUSED +static mb_to_wchar_fn resolve_utf16le_wchar(void) +{ + return zend_cpu_supports_avx2() ? mb_utf16le_to_wchar_avx2 : mb_utf16le_to_wchar_default; +} + +ZEND_NO_SANITIZE_ADDRESS +ZEND_ATTRIBUTE_UNUSED +static mb_from_wchar_fn resolve_wchar_utf16le(void) +{ + return zend_cpu_supports_avx2() ? mb_wchar_to_utf16le_avx2 : mb_wchar_to_utf16le_default; +} + +# else /* ZEND_INTRIN_AVX2_FUNC_PTR */ +/* We are compiling for a target where the dynamic linker will not be able to + * resolve symbols according to whether the host supports AVX2 or not; so instead, + * we can make calls go through a function pointer and set the function pointer + * on module load */ + +#ifdef HAVE_FUNC_ATTRIBUTE_TARGET +static size_t mb_utf16be_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) __attribute__((target("avx2"))); +static void mb_wchar_to_utf16be_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) __attribute__((target("avx2"))); +static size_t mb_utf16le_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) __attribute__((target("avx2"))); +static void mb_wchar_to_utf16le_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) __attribute__((target("avx2"))); +#else +static size_t mb_utf16be_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16be_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static size_t mb_utf16le_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16le_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +#endif + +static mb_to_wchar_fn utf16be_to_wchar_ptr = NULL; +static mb_from_wchar_fn wchar_to_utf16be_ptr = NULL; +static mb_to_wchar_fn utf16le_to_wchar_ptr = NULL; +static mb_from_wchar_fn wchar_to_utf16le_ptr = NULL; + +static size_t mb_utf16be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + return utf16be_to_wchar_ptr(in, in_len, buf, bufsize, NULL); +} + +static void mb_wchar_to_utf16be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + wchar_to_utf16be_ptr(in, len, buf, end); +} + +static size_t mb_utf16le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + return utf16le_to_wchar_ptr(in, in_len, buf, bufsize, NULL); +} + +static void mb_wchar_to_utf16le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + wchar_to_utf16le_ptr(in, len, buf, end); +} + +void init_convert_utf16(void) +{ + if (zend_cpu_supports_avx2()) { + utf16be_to_wchar_ptr = mb_utf16be_to_wchar_avx2; + wchar_to_utf16be_ptr = mb_wchar_to_utf16be_avx2; + utf16le_to_wchar_ptr = mb_utf16le_to_wchar_avx2; + wchar_to_utf16le_ptr = mb_wchar_to_utf16le_avx2; + } else { + utf16be_to_wchar_ptr = mb_utf16be_to_wchar_default; + wchar_to_utf16be_ptr = mb_wchar_to_utf16be_default; + utf16le_to_wchar_ptr = mb_utf16le_to_wchar_default; + wchar_to_utf16le_ptr = mb_wchar_to_utf16le_default; + } +} +# endif + +#else + +/* No AVX2 support */ +# define mb_utf16be_to_wchar mb_utf16be_to_wchar_default +# define mb_utf16le_to_wchar mb_utf16le_to_wchar_default +# define mb_wchar_to_utf16be mb_wchar_to_utf16be_default +# define mb_wchar_to_utf16le mb_wchar_to_utf16le_default + +static size_t mb_utf16be_to_wchar_default(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16be_default(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static size_t mb_utf16le_to_wchar_default(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16le_default(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); + +#endif + static int mbfl_filt_conv_utf16_wchar_flush(mbfl_convert_filter *filter); static size_t mb_utf16_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); -static size_t mb_utf16be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); -static void mb_wchar_to_utf16be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); -static size_t mb_utf16le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); -static void mb_wchar_to_utf16le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); static const char *mbfl_encoding_utf16_aliases[] = {"utf16", NULL}; @@ -49,7 +188,8 @@ const mbfl_encoding mbfl_encoding_utf16 = { &vtbl_utf16_wchar, &vtbl_wchar_utf16, mb_utf16_to_wchar, - mb_wchar_to_utf16be + mb_wchar_to_utf16be, + NULL }; const mbfl_encoding mbfl_encoding_utf16be = { @@ -62,7 +202,8 @@ const mbfl_encoding mbfl_encoding_utf16be = { &vtbl_utf16be_wchar, &vtbl_wchar_utf16be, mb_utf16be_to_wchar, - mb_wchar_to_utf16be + mb_wchar_to_utf16be, + NULL }; const mbfl_encoding mbfl_encoding_utf16le = { @@ -75,7 +216,8 @@ const mbfl_encoding mbfl_encoding_utf16le = { &vtbl_utf16le_wchar, &vtbl_wchar_utf16le, mb_utf16le_to_wchar, - mb_wchar_to_utf16le + mb_wchar_to_utf16le, + NULL }; const struct mbfl_convert_vtbl vtbl_utf16_wchar = { @@ -366,7 +508,7 @@ static size_t mb_utf16_to_wchar(unsigned char **in, size_t *in_len, uint32_t *bu return mb_utf16be_to_wchar(in, in_len, buf, bufsize, NULL); } -static size_t mb_utf16be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +static size_t mb_utf16be_to_wchar_default(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { /* We only want to read 16-bit words out of `str`; any trailing byte will be handled at the end */ unsigned char *p = *in, *e = p + (*in_len & ~1); @@ -419,7 +561,7 @@ static size_t mb_utf16be_to_wchar(unsigned char **in, size_t *in_len, uint32_t * return out - buf; } -static void mb_wchar_to_utf16be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +static void mb_wchar_to_utf16be_default(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) { unsigned char *out, *limit; MB_CONVERT_BUF_LOAD(buf, out, limit); @@ -436,7 +578,7 @@ static void mb_wchar_to_utf16be(uint32_t *in, size_t len, mb_convert_buf *buf, b MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); out = mb_convert_buf_add4(out, (n1 >> 8) & 0xFF, n1 & 0xFF, (n2 >> 8) & 0xFF, n2 & 0xFF); } else { - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf16be); + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf16be_default); MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); } } @@ -444,7 +586,7 @@ static void mb_wchar_to_utf16be(uint32_t *in, size_t len, mb_convert_buf *buf, b MB_CONVERT_BUF_STORE(buf, out, limit); } -static size_t mb_utf16le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +static size_t mb_utf16le_to_wchar_default(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { /* We only want to read 16-bit words out of `str`; any trailing byte will be handled at the end */ unsigned char *p = *in, *e = p + (*in_len & ~1); @@ -497,7 +639,7 @@ static size_t mb_utf16le_to_wchar(unsigned char **in, size_t *in_len, uint32_t * return out - buf; } -static void mb_wchar_to_utf16le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +static void mb_wchar_to_utf16le_default(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) { unsigned char *out, *limit; MB_CONVERT_BUF_LOAD(buf, out, limit); @@ -514,10 +656,387 @@ static void mb_wchar_to_utf16le(uint32_t *in, size_t len, mb_convert_buf *buf, b MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); out = mb_convert_buf_add4(out, n1 & 0xFF, (n1 >> 8) & 0xFF, n2 & 0xFF, (n2 >> 8) & 0xFF); } else { - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf16le); + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf16le_default); MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); } } MB_CONVERT_BUF_STORE(buf, out, limit); } + +#if defined(ZEND_INTRIN_AVX2_NATIVE) || defined(ZEND_INTRIN_AVX2_RESOLVER) + +#ifdef ZEND_INTRIN_AVX2_FUNC_PROTO +size_t mb_utf16be_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +#else +static size_t mb_utf16be_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +#endif +{ + size_t len = *in_len; + + if (len >= 32 && bufsize >= 16) { + unsigned char *p = *in; + uint32_t *out = buf; + + /* Used to determine if a block of input bytes contains any surrogates */ + const __m256i _f8 = _mm256_set1_epi16(0xF8); + const __m256i _d8 = _mm256_set1_epi16(0xD8); + /* wchars must be in host byte order, which is little-endian on x86; + * Since we are reading in (big-endian) UTF-16BE, use this vector to swap byte order for output */ + const __m256i swap_bytes = _mm256_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1); + + do { + __m256i operand = _mm256_loadu_si256((__m256i*)p); /* Load 32 bytes */ + + uint32_t surrogate_bitvec = _mm256_movemask_epi8(_mm256_cmpeq_epi16(_mm256_and_si256(operand, _f8), _d8)); + if (surrogate_bitvec == 0) { + /* There are no surrogates among these 16 characters + * So converting the UTF-16 input to wchars is very simple; just extend each 16-bit value + * to a 32-bit value, filling in zero bits in the high end */ + operand = _mm256_shuffle_epi8(operand, swap_bytes); + _mm256_storeu_si256((__m256i*)out, _mm256_cvtepu16_epi32(_mm256_castsi256_si128(operand))); + _mm256_storeu_si256((__m256i*)(out + 8), _mm256_cvtepu16_epi32(_mm256_extracti128_si256(operand, 1))); + out += 16; + bufsize -= 16; + p += sizeof(__m256i); + len -= sizeof(__m256i); + } else if ((surrogate_bitvec & 1) == 0) { + /* Some prefix of the current block is non-surrogates; output those */ + uint8_t n_chars = zend_ulong_ntz(surrogate_bitvec) >> 1; + operand = _mm256_shuffle_epi8(operand, swap_bytes); + /* We know that the output buffer has at least 64 bytes of space available + * So don't bother trimming the output down to only include the non-surrogate prefix; + * rather, write out an entire block of 64 (or 32) bytes, then bump our output pointer + * forward just past the 'good part', so the 'bad part' will be overwritten on the next + * iteration of this loop */ + _mm256_storeu_si256((__m256i*)out, _mm256_cvtepu16_epi32(_mm256_castsi256_si128(operand))); + if (n_chars > 8) { + _mm256_storeu_si256((__m256i*)(out + 8), _mm256_cvtepu16_epi32(_mm256_extracti128_si256(operand, 1))); + } + out += n_chars; + bufsize -= n_chars; + p += n_chars * 2; + len -= n_chars * 2; + } else { + /* Some prefix of the current block is (valid or invalid) surrogates + * Handle those using non-vectorized code */ + surrogate_bitvec = ~surrogate_bitvec; + unsigned int n_chars = surrogate_bitvec ? zend_ulong_ntz(surrogate_bitvec) >> 1 : 16; + do { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + + if (c1 & 0x4 || len < 4) { + /* 2nd part of surrogate pair has come first OR string ended abruptly + * after 1st part of surrogate pair */ + *out++ = MBFL_BAD_INPUT; + bufsize--; + n_chars--; + len -= 2; + continue; + } + + uint16_t n = (c1 << 8) | c2; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + + if ((c3 & 0xFC) == 0xDC) { + /* Valid surrogate pair */ + uint16_t n2 = (c3 << 8) | c4; + *out++ = (((n & 0x3FF) << 10) | (n2 & 0x3FF)) + 0x10000; + bufsize--; + len -= 4; +#ifdef PHP_HAVE_BUILTIN_USUB_OVERFLOW + /* Subtracting 2 from `n_chars` will automatically set the CPU's flags; + * branch directly off the appropriate flag (CF on x86) rather than using + * another instruction (CMP on x86) to check for underflow */ + if (__builtin_usub_overflow(n_chars, 2, &n_chars)) { + /* The last 2 bytes of this block and the first 2 bytes of the following + * block form a valid surrogate pair; now just make sure we don't get + * stuck in this loop due to underflow of the loop index */ + break; + } +#else + n_chars -= 2; + if (n_chars == UINT_MAX) { + break; + } +#endif + } else { + /* First half of surrogate pair was followed by another first half + * OR by a non-surrogate character */ + *out++ = MBFL_BAD_INPUT; + bufsize--; + n_chars--; + len -= 2; + p -= 2; /* Back up so the last 2 bytes will be processed again */ + } + } while (n_chars); + } + } while (len >= 32 && bufsize >= 16); + + if (len && bufsize >= 4) { + /* Finish up trailing bytes which don't fill a 32-byte block */ + out += mb_utf16be_to_wchar_default(&p, &len, out, bufsize, NULL); + } + + *in = p; + *in_len = len; + return out - buf; + } else if (len) { + return mb_utf16be_to_wchar_default(in, in_len, buf, bufsize, NULL); + } else { + return 0; + } +} + +#ifdef ZEND_INTRIN_AVX2_FUNC_PROTO +void mb_wchar_to_utf16be_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +#else +static void mb_wchar_to_utf16be_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +#endif +{ + if (len >= 8) { + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + /* Used to find wchars which are outside the Unicode BMP (Basic Multilingual Plane) */ + const __m256i bmp_mask = _mm256_set1_epi32(0xFFFF); + /* Used to extract 16 bits which we want from each of eight 32-bit values */ + const __m256i pack_8x16 = _mm256_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 12, 13, 8, 9, 4, 5, 0, 1, 12, 13, 8, 9, 4, 5, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1); + + do { + __m256i operand = _mm256_loadu_si256((__m256i*)in); /* Load 32 bytes */ + + uint32_t bmp_bitvec = _mm256_movemask_epi8(_mm256_cmpeq_epi32(_mm256_and_si256(operand, bmp_mask), operand)); + if (bmp_bitvec == 0xFFFFFFFF) { + /* All eight wchars are in the BMP + * Shuffle bytes around to get the 16 bytes we want into the low 16 bytes of YMM register + * (which is equivalent to an XMM register) */ + operand = _mm256_shuffle_epi8(operand, pack_8x16); + __m256i operand2 = _mm256_permute2x128_si256(operand, operand, 1); + operand = _mm256_alignr_epi8(operand2, operand, 8); + _mm_storeu_si128((__m128i*)out, _mm256_castsi256_si128(operand)); /* Store 16 bytes */ + out += 16; + len -= 8; + in += 8; + } else if (bmp_bitvec & 1) { + /* Some prefix of this block are codepoints in the BMP */ + unsigned int n_bytes = zend_ulong_ntz(~bmp_bitvec); + operand = _mm256_shuffle_epi8(operand, pack_8x16); + __m256i operand2 = _mm256_permute2x128_si256(operand, operand, 1); + operand = _mm256_alignr_epi8(operand2, operand, 8); + /* Store 16 bytes, but bump output pointer forward just past the 'good part', + * so the 'bad part' will be overwritten on the next iteration of this loop */ + _mm_storeu_si128((__m128i*)out, _mm256_castsi256_si128(operand)); + out += n_bytes >> 1; + len -= n_bytes >> 2; + in += n_bytes >> 2; + } else { + /* Some prefix of this block is codepoints outside the BMP OR error markers + * Handle them using non-vectorized code */ + unsigned int n_words = bmp_bitvec ? zend_ulong_ntz(bmp_bitvec) >> 2 : 8; + do { + uint32_t w = *in++; + n_words--; + len--; + + if (w < MBFL_WCSPLANE_UTF32MAX) { + uint16_t n1 = ((w >> 10) - 0x40) | 0xD800; + uint16_t n2 = (w & 0x3FF) | 0xDC00; + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); + out = mb_convert_buf_add4(out, (n1 >> 8) & 0xFF, n1 & 0xFF, (n2 >> 8) & 0xFF, n2 & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf16be_default); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + } + } while (n_words); + } + } while (len >= 8); + + MB_CONVERT_BUF_STORE(buf, out, limit); + } + + if (len) { + mb_wchar_to_utf16be_default(in, len, buf, end); + } +} + +#ifdef ZEND_INTRIN_AVX2_FUNC_PROTO +size_t mb_utf16le_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +#else +static size_t mb_utf16le_to_wchar_avx2(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +#endif +{ + /* Most of this function is the same as `mb_utf16be_to_wchar_avx2`, above; + * See it for more detailed code comments */ + + size_t len = *in_len; + + if (len >= 32 && bufsize >= 16) { + unsigned char *p = *in; + uint32_t *out = buf; + + const __m256i _f8 = _mm256_set1_epi16(0xF800); + const __m256i _d8 = _mm256_set1_epi16(0xD800); + + do { + __m256i operand = _mm256_loadu_si256((__m256i*)p); + + uint32_t surrogate_bitvec = _mm256_movemask_epi8(_mm256_cmpeq_epi16(_mm256_and_si256(operand, _f8), _d8)); + if (surrogate_bitvec == 0) { + /* There are no surrogates among these 16 characters */ + _mm256_storeu_si256((__m256i*)out, _mm256_cvtepu16_epi32(_mm256_castsi256_si128(operand))); + _mm256_storeu_si256((__m256i*)(out + 8), _mm256_cvtepu16_epi32(_mm256_extracti128_si256(operand, 1))); + out += 16; + bufsize -= 16; + p += sizeof(__m256i); + len -= sizeof(__m256i); + } else if ((surrogate_bitvec & 1) == 0) { + /* Some prefix of the current block is non-surrogates */ + uint8_t n_chars = zend_ulong_ntz(surrogate_bitvec) >> 1; + _mm256_storeu_si256((__m256i*)out, _mm256_cvtepu16_epi32(_mm256_castsi256_si128(operand))); + if (n_chars > 8) { + _mm256_storeu_si256((__m256i*)(out + 8), _mm256_cvtepu16_epi32(_mm256_extracti128_si256(operand, 1))); + } + out += n_chars; + bufsize -= n_chars; + p += n_chars * 2; + len -= n_chars * 2; + } else { + /* Some prefix of the current block is (valid or invalid) surrogates */ + surrogate_bitvec = ~surrogate_bitvec; + unsigned int n_chars = surrogate_bitvec ? zend_ulong_ntz(surrogate_bitvec) >> 1 : 16; + do { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + + if (c2 & 0x4 || len < 4) { + /* 2nd part of surrogate pair has come first OR string ended abruptly + * after 1st part of surrogate pair */ + *out++ = MBFL_BAD_INPUT; + bufsize--; + n_chars--; + len -= 2; + continue; + } + + uint16_t n = (c2 << 8) | c1; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + + if ((c4 & 0xFC) == 0xDC) { + /* Valid surrogate pair */ + uint16_t n2 = (c4 << 8) | c3; + *out++ = (((n & 0x3FF) << 10) | (n2 & 0x3FF)) + 0x10000; + bufsize--; + len -= 4; +#ifdef PHP_HAVE_BUILTIN_USUB_OVERFLOW + if (__builtin_usub_overflow(n_chars, 2, &n_chars)) { + break; + } +#else + n_chars -= 2; + if (n_chars == UINT_MAX) { + break; + } +#endif + } else { + /* First half of surrogate pair was followed by another first half + * OR by a non-surrogate character */ + *out++ = MBFL_BAD_INPUT; + bufsize--; + n_chars--; + len -= 2; + p -= 2; /* Back up so the last 2 bytes will be processed again */ + } + } while (n_chars); + } + } while (len >= 32 && bufsize >= 16); + + if (len && bufsize >= 4) { + out += mb_utf16le_to_wchar_default(&p, &len, out, bufsize, NULL); + } + + *in = p; + *in_len = len; + return out - buf; + } else if (len) { + return mb_utf16le_to_wchar_default(in, in_len, buf, bufsize, NULL); + } else { + return 0; + } +} + +#ifdef ZEND_INTRIN_AVX2_FUNC_PROTO +void mb_wchar_to_utf16le_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +#else +static void mb_wchar_to_utf16le_avx2(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +#endif +{ + if (len >= 8) { + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + /* Used to find wchars which are outside the Unicode BMP (Basic Multilingual Plane) */ + const __m256i bmp_mask = _mm256_set1_epi32(0xFFFF); + /* Used to extract 16 bits which we want from each of eight 32-bit values */ + const __m256i pack_8x16 = _mm256_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 13, 12, 9, 8, 5, 4, 1, 0, 13, 12, 9, 8, 5, 4, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1); + + do { + __m256i operand = _mm256_loadu_si256((__m256i*)in); + + uint32_t bmp_bitvec = _mm256_movemask_epi8(_mm256_cmpeq_epi32(_mm256_and_si256(operand, bmp_mask), operand)); + if (bmp_bitvec == 0xFFFFFFFF) { + /* All eight wchars are in the BMP + * Shuffle bytes around to get the 16 bytes we want into the low 16 bytes of YMM register + * (which is equivalent to an XMM register) */ + operand = _mm256_shuffle_epi8(operand, pack_8x16); + __m256i operand2 = _mm256_permute2x128_si256(operand, operand, 1); + operand = _mm256_alignr_epi8(operand2, operand, 8); + _mm_storeu_si128((__m128i*)out, _mm256_castsi256_si128(operand)); + out += 16; + len -= 8; + in += 8; + } else if (bmp_bitvec & 1) { + /* Some prefix of this block are codepoints in the BMP */ + unsigned int n_bytes = zend_ulong_ntz(~bmp_bitvec); + operand = _mm256_shuffle_epi8(operand, pack_8x16); + __m256i operand2 = _mm256_permute2x128_si256(operand, operand, 1); + operand = _mm256_alignr_epi8(operand2, operand, 8); + _mm_storeu_si128((__m128i*)out, _mm256_castsi256_si128(operand)); + out += n_bytes >> 1; + len -= n_bytes >> 2; + in += n_bytes >> 2; + } else { + /* Some prefix of this block is codepoints outside the BMP OR error markers */ + unsigned int n_words = bmp_bitvec ? zend_ulong_ntz(bmp_bitvec) >> 2 : 8; + do { + uint32_t w = *in++; + n_words--; + len--; + + if (w < MBFL_WCSPLANE_UTF32MAX) { + uint16_t n1 = ((w >> 10) - 0x40) | 0xD800; + uint16_t n2 = (w & 0x3FF) | 0xDC00; + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); + out = mb_convert_buf_add4(out, n1 & 0xFF, (n1 >> 8) & 0xFF, n2 & 0xFF, (n2 >> 8) & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf16le_default); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + } + } while (n_words); + } + } while (len >= 8); + + MB_CONVERT_BUF_STORE(buf, out, limit); + } + + if (len) { + mb_wchar_to_utf16le_default(in, len, buf, end); + } +} + +#endif /* defined(ZEND_INTRIN_AVX2_NATIVE) || defined(ZEND_INTRIN_AVX2_RESOLVER) */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf16.h b/ext/mbstring/libmbfl/filters/mbfilter_utf16.h index 727c231b3479e..291628549debe 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf16.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf16.h @@ -47,4 +47,8 @@ int mbfl_filt_conv_wchar_utf16be(int c, mbfl_convert_filter *filter); int mbfl_filt_conv_utf16le_wchar(int c, mbfl_convert_filter *filter); int mbfl_filt_conv_wchar_utf16le(int c, mbfl_convert_filter *filter); +#ifdef ZEND_INTRIN_AVX2_FUNC_PTR +void init_convert_utf16(void); +#endif + #endif /* MBFL_MBFILTER_UTF16_H */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf32.c b/ext/mbstring/libmbfl/filters/mbfilter_utf32.c index e8cd4ad454f2e..b49f5df5369e4 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf32.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf32.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by moriyoshi koizumi on 20 dec 2002. * */ @@ -49,7 +49,8 @@ const mbfl_encoding mbfl_encoding_utf32 = { &vtbl_utf32_wchar, &vtbl_wchar_utf32, mb_utf32_to_wchar, - mb_wchar_to_utf32be + mb_wchar_to_utf32be, + NULL }; const mbfl_encoding mbfl_encoding_utf32be = { @@ -62,7 +63,8 @@ const mbfl_encoding mbfl_encoding_utf32be = { &vtbl_utf32be_wchar, &vtbl_wchar_utf32be, mb_utf32be_to_wchar, - mb_wchar_to_utf32be + mb_wchar_to_utf32be, + NULL }; const mbfl_encoding mbfl_encoding_utf32le = { @@ -75,7 +77,8 @@ const mbfl_encoding mbfl_encoding_utf32le = { &vtbl_utf32le_wchar, &vtbl_wchar_utf32le, mb_utf32le_to_wchar, - mb_wchar_to_utf32le + mb_wchar_to_utf32le, + NULL }; const struct mbfl_convert_vtbl vtbl_utf32_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf7.c b/ext/mbstring/libmbfl/filters/mbfilter_utf7.c index f5fe261f69d00..af84602ae1880 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf7.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf7.c @@ -22,17 +22,19 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by moriyoshi koizumi on 4 dec 2002. * */ #include "mbfilter.h" #include "mbfilter_utf7.h" +#include "utf7_helper.h" static int mbfl_filt_conv_utf7_wchar_flush(mbfl_convert_filter *filter); static size_t mb_utf7_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static void mb_wchar_to_utf7(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static bool mb_check_utf7(unsigned char *in, size_t in_len); static const unsigned char mbfl_base64_table[] = { /* 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', */ @@ -59,7 +61,8 @@ const mbfl_encoding mbfl_encoding_utf7 = { &vtbl_utf7_wchar, &vtbl_wchar_utf7, mb_utf7_to_wchar, - mb_wchar_to_utf7 + mb_wchar_to_utf7, + mb_check_utf7 }; const struct mbfl_convert_vtbl vtbl_utf7_wchar = { @@ -408,16 +411,24 @@ int mbfl_filt_conv_wchar_utf7_flush(mbfl_convert_filter *filter) return 0; } -/* Ways which a Base64-encoded section can end: */ -#define DASH 0xFD -#define ASCII 0xFE -#define ILLEGAL 0xFF - static inline bool is_base64_end(unsigned char c) { return c >= DASH; } +static bool is_optional_direct(unsigned char c) +{ + /* Characters that are allowed to be encoded by Base64 or directly encoded */ + return c == '!' || c == '"' || c == '#' || c == '$' || c == '%' || c == '&' || c == '*' || c == ';' || c == '<' || + c == '=' || c == '>' || c == '@' || c == '[' || c == ']' || c == '^' || c == '_' || c == '`' || c == '{' || + c == '|' || c == '}'; +} + +static bool can_end_base64(uint32_t c) +{ + return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\'' || c == '(' || c == ')' || c == ',' || c == '.' || c == ':' || c == '?'; +} + static unsigned char decode_base64(unsigned char c) { if (c >= 'A' && c <= 'Z') { @@ -432,6 +443,8 @@ static unsigned char decode_base64(unsigned char c) return 63; } else if (c == '-') { return DASH; + } else if (can_end_base64(c) || is_optional_direct(c) || c == '\0') { + return DIRECT; } else if (c <= 0x7F) { return ASCII; } @@ -470,7 +483,7 @@ static uint32_t* handle_base64_end(unsigned char n, unsigned char **p, uint32_t if (n == ILLEGAL) { *out++ = MBFL_BAD_INPUT; - } else if (n == ASCII) { + } else if (n == DIRECT || n == ASCII) { (*p)--; /* Unconsume byte */ } @@ -524,8 +537,10 @@ static size_t mb_utf7_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf if (p == e) { /* It is an error if trailing padding bits are not zeroes or if we were * expecting the 2nd part of a surrogate pair when Base64 section ends */ - if ((n3 & 0x3) || surrogate1) + if ((n3 & 0x3) || surrogate1) { *out++ = MBFL_BAD_INPUT; + surrogate1 = 0; + } break; } @@ -549,8 +564,10 @@ static size_t mb_utf7_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf } out = handle_utf16_cp((n3 << 14) | (n4 << 8) | (n5 << 2) | ((n6 & 0x30) >> 4), out, &surrogate1); if (p == e) { - if ((n6 & 0xF) || surrogate1) + if ((n6 & 0xF) || surrogate1) { *out++ = MBFL_BAD_INPUT; + surrogate1 = 0; + } break; } @@ -590,17 +607,17 @@ static size_t mb_utf7_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf } } + if (p == e && surrogate1) { + ZEND_ASSERT(out < limit); + *out++ = MBFL_BAD_INPUT; + } + *state = (surrogate1 << 1) | base64; *in_len = e - p; *in = p; return out - buf; } -static bool can_end_base64(uint32_t c) -{ - return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\'' || c == '(' || c == ')' || c == ',' || c == '.' || c == ':' || c == '?'; -} - static bool should_direct_encode(uint32_t c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '\0' || c == '/' || c == '-' || can_end_base64(c); @@ -700,3 +717,129 @@ static void mb_wchar_to_utf7(uint32_t *in, size_t len, mb_convert_buf *buf, bool MB_CONVERT_BUF_STORE(buf, out, limit); } + +static bool is_utf16_cp_valid(uint16_t cp, bool is_surrogate) +{ + if (is_surrogate) { + return cp >= 0xDC00 && cp <= 0xDFFF; + } else { + /* 2nd part of surrogate pair came unexpectedly */ + return !(cp >= 0xDC00 && cp <= 0xDFFF); + } +} + +static bool can_encode_directly(unsigned char c) +{ + return should_direct_encode(c) || is_optional_direct(c) || c == '\0'; +} + +static bool mb_check_utf7(unsigned char *in, size_t in_len) +{ + unsigned char *p = in, *e = p + in_len; + bool base64 = false; + bool is_surrogate = false; + + while (p < e) { + if (base64) { + unsigned char n1 = decode_base64(*p++); + if (is_base64_end(n1)) { + if (!is_base64_end_valid(n1, false, is_surrogate)) { + return false; + } + base64 = false; + continue; + } else if (p == e) { + return false; + } + unsigned char n2 = decode_base64(*p++); + if (is_base64_end(n2) || p == e) { + return false; + } + unsigned char n3 = decode_base64(*p++); + if (is_base64_end(n3)) { + return false; + } + uint16_t cp1 = (n1 << 10) | (n2 << 4) | ((n3 & 0x3C) >> 2); + if (!is_utf16_cp_valid(cp1, is_surrogate)) { + return false; + } + is_surrogate = has_surrogate(cp1, is_surrogate); + if (p == e) { + /* It is an error if trailing padding bits are not zeroes or if we were + * expecting the 2nd part of a surrogate pair when Base64 section ends */ + return !((n3 & 0x3) || is_surrogate); + } + + unsigned char n4 = decode_base64(*p++); + if (is_base64_end(n4)) { + if (!is_base64_end_valid(n4, n3 & 0x3, is_surrogate)) { + return false; + } + base64 = false; + continue; + } else if (p == e) { + return false; + } + unsigned char n5 = decode_base64(*p++); + if (is_base64_end(n5) || p == e) { + return false; + } + unsigned char n6 = decode_base64(*p++); + if (is_base64_end(n6)) { + return false; + } + uint16_t cp2 = (n3 << 14) | (n4 << 8) | (n5 << 2) | ((n6 & 0x30) >> 4); + if (!is_utf16_cp_valid(cp2, is_surrogate)) { + return false; + } + is_surrogate = has_surrogate(cp2, is_surrogate); + if (p == e) { + return !((n6 & 0xF) || is_surrogate); + } + + unsigned char n7 = decode_base64(*p++); + if (is_base64_end(n7)) { + if (!is_base64_end_valid(n7, n6 & 0xF, is_surrogate)) { + return false; + } + base64 = false; + continue; + } else if (p == e) { + return false; + } + unsigned char n8 = decode_base64(*p++); + if (is_base64_end(n8)) { + return false; + } + uint16_t cp3 = (n6 << 12) | (n7 << 6) | n8; + if (!is_utf16_cp_valid(cp3, is_surrogate)) { + return false; + } + is_surrogate = has_surrogate(cp3, is_surrogate); + } else { + /* ASCII text section */ + unsigned char c = *p++; + + if (c == '+') { + if (p == e) { + base64 = true; + return !is_surrogate; + } + unsigned char n = decode_base64(*p); + if (n == DASH) { + p++; + } else if (n > DASH) { + /* If a "+" character followed immediately by any character other than base64 or "-" */ + return false; + } else { + base64 = true; + } + } else if (can_encode_directly(c)) { + continue; + } else { + return false; + } + } + } + return !is_surrogate; +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf7imap.c b/ext/mbstring/libmbfl/filters/mbfilter_utf7imap.c index 850edfbd63a1e..d8af71686a1f3 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf7imap.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf7imap.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by moriyoshi koizumi on 4 dec 2002. * */ @@ -77,11 +77,13 @@ #include "mbfilter.h" #include "mbfilter_utf7imap.h" +#include "utf7_helper.h" static int mbfl_filt_conv_wchar_utf7imap_flush(mbfl_convert_filter *filter); static int mbfl_filt_conv_utf7imap_wchar_flush(mbfl_convert_filter *filter); static size_t mb_utf7imap_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static void mb_wchar_to_utf7imap(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static bool mb_check_utf7imap(unsigned char *in, size_t in_len); static const char *mbfl_encoding_utf7imap_aliases[] = {"mUTF-7", NULL}; @@ -95,7 +97,8 @@ const mbfl_encoding mbfl_encoding_utf7imap = { &vtbl_utf7imap_wchar, &vtbl_wchar_utf7imap, mb_utf7imap_to_wchar, - mb_wchar_to_utf7imap + mb_wchar_to_utf7imap, + mb_check_utf7imap }; const struct mbfl_convert_vtbl vtbl_utf7imap_wchar = { @@ -444,10 +447,6 @@ static int mbfl_filt_conv_wchar_utf7imap_flush(mbfl_convert_filter *filter) return 0; } -/* Ways which a Base64-encoded section can end: */ -#define DASH 0xFE -#define ILLEGAL 0xFF - static inline bool is_base64_end(unsigned char c) { return c >= DASH; @@ -732,3 +731,124 @@ static void mb_wchar_to_utf7imap(uint32_t *in, size_t len, mb_convert_buf *buf, MB_CONVERT_BUF_STORE(buf, out, limit); } + +static bool is_utf16_cp_valid(uint16_t cp, bool is_surrogate) +{ + if (is_surrogate) { + return cp >= 0xDC00 && cp <= 0xDFFF; + } else if (cp >= 0xDC00 && cp <= 0xDFFF) { + /* 2nd part of surrogate pair came unexpectedly */ + return false; + } else if (cp >= 0x20 && cp <= 0x7E && cp != '&') { + return false; + } + return true; +} + +static bool mb_check_utf7imap(unsigned char *in, size_t in_len) +{ + unsigned char *p = in, *e = p + in_len; + bool base64 = false; + bool is_surrogate = false; + + while (p < e) { + if (base64) { + /* Base64 section */ + unsigned char n1 = decode_base64(*p++); + if (is_base64_end(n1)) { + if (!is_base64_end_valid(n1, false, is_surrogate)) { + return false; + } + base64 = false; + continue; + } else if (p == e) { + return false; + } + unsigned char n2 = decode_base64(*p++); + if (is_base64_end(n2) || p == e) { + return false; + } + unsigned char n3 = decode_base64(*p++); + if (is_base64_end(n3)) { + return false; + } + uint16_t cp1 = (n1 << 10) | (n2 << 4) | ((n3 & 0x3C) >> 2); + if (!is_utf16_cp_valid(cp1, is_surrogate)) { + return false; + } + is_surrogate = has_surrogate(cp1, is_surrogate); + if (p == e) { + return false; + } + + unsigned char n4 = decode_base64(*p++); + if (is_base64_end(n4)) { + if (!is_base64_end_valid(n4, n3 & 0x3, is_surrogate)) { + return false; + } + base64 = false; + continue; + } else if (p == e) { + return false; + } + unsigned char n5 = decode_base64(*p++); + if (is_base64_end(n5) || p == e) { + return false; + } + unsigned char n6 = decode_base64(*p++); + if (is_base64_end(n6)) { + return false; + } + uint16_t cp2 = (n3 << 14) | (n4 << 8) | (n5 << 2) | ((n6 & 0x30) >> 4); + if (!is_utf16_cp_valid(cp2, is_surrogate)) { + return false; + } + is_surrogate = has_surrogate(cp2, is_surrogate); + if (p == e) { + return false; + } + + unsigned char n7 = decode_base64(*p++); + if (is_base64_end(n7)) { + if (!is_base64_end_valid(n7, n6 & 0xF, is_surrogate)) { + return false; + } + base64 = false; + continue; + } else if (p == e) { + return false; + } + unsigned char n8 = decode_base64(*p++); + if (is_base64_end(n8)) { + return false; + } + uint16_t cp3 = (n6 << 12) | (n7 << 6) | n8; + if (!is_utf16_cp_valid(cp3, is_surrogate)) { + return false; + } + is_surrogate = has_surrogate(cp3, is_surrogate); + } else { + /* ASCII text section */ + unsigned char c = *p++; + + if (c == '&') { + if (p == e) { + return false; + } + unsigned char n = decode_base64(*p); + if (n == DASH) { + p++; + } else if (n == ILLEGAL) { + return false; + } else { + base64 = true; + } + } else if (c >= 0x20 && c <= 0x7E) { + continue; + } else { + return false; + } + } + } + return !base64; +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8.c b/ext/mbstring/libmbfl/filters/mbfilter_utf8.c index 46bddd17a7365..92d7c38930981 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8.c @@ -64,7 +64,8 @@ const mbfl_encoding mbfl_encoding_utf8 = { &vtbl_utf8_wchar, &vtbl_wchar_utf8, mb_utf8_to_wchar, - mb_wchar_to_utf8 + mb_wchar_to_utf8, + NULL }; const struct mbfl_convert_vtbl vtbl_utf8_wchar = { @@ -225,7 +226,9 @@ static size_t mb_utf8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf if (c < 0x80) { *out++ = c; - } else if (c >= 0xC2 && c <= 0xDF) { /* 2 byte character */ + } else if (c < 0xC2) { + *out++ = MBFL_BAD_INPUT; + } else if (c <= 0xDF) { /* 2 byte character */ if (p < e) { unsigned char c2 = *p++; if ((c2 & 0xC0) != 0x80) { @@ -237,7 +240,7 @@ static size_t mb_utf8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf } else { *out++ = MBFL_BAD_INPUT; } - } else if (c >= 0xE0 && c <= 0xEF) { /* 3 byte character */ + } else if (c <= 0xEF) { /* 3 byte character */ if ((e - p) >= 2) { unsigned char c2 = *p++; unsigned char c3 = *p++; @@ -262,7 +265,7 @@ static size_t mb_utf8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf } } } - } else if (c >= 0xF0 && c <= 0xF4) { /* 4 byte character */ + } else if (c <= 0xF4) { /* 4 byte character */ if ((e - p) >= 3) { unsigned char c2 = *p++; unsigned char c3 = *p++; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c b/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c index c573ec70f3bc9..7d5fdc3e0a469 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by rui hrokawa on 8 aug 2011. * */ @@ -63,7 +63,8 @@ const mbfl_encoding mbfl_encoding_utf8_docomo = { &vtbl_utf8_docomo_wchar, &vtbl_wchar_utf8_docomo, mb_utf8_docomo_to_wchar, - mb_wchar_to_utf8_docomo + mb_wchar_to_utf8_docomo, + NULL }; const mbfl_encoding mbfl_encoding_utf8_kddi_a = { @@ -76,7 +77,8 @@ const mbfl_encoding mbfl_encoding_utf8_kddi_a = { &vtbl_utf8_kddi_a_wchar, &vtbl_wchar_utf8_kddi_a, mb_utf8_kddi_a_to_wchar, - mb_wchar_to_utf8_kddi_a + mb_wchar_to_utf8_kddi_a, + NULL }; const mbfl_encoding mbfl_encoding_utf8_kddi_b = { @@ -89,7 +91,8 @@ const mbfl_encoding mbfl_encoding_utf8_kddi_b = { &vtbl_utf8_kddi_b_wchar, &vtbl_wchar_utf8_kddi_b, mb_utf8_kddi_b_to_wchar, - mb_wchar_to_utf8_kddi_b + mb_wchar_to_utf8_kddi_b, + NULL }; const mbfl_encoding mbfl_encoding_utf8_sb = { @@ -102,7 +105,8 @@ const mbfl_encoding mbfl_encoding_utf8_sb = { &vtbl_utf8_sb_wchar, &vtbl_wchar_utf8_sb, mb_utf8_sb_to_wchar, - mb_wchar_to_utf8_sb + mb_wchar_to_utf8_sb, + NULL }; const struct mbfl_convert_vtbl vtbl_utf8_docomo_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_uuencode.c b/ext/mbstring/libmbfl/filters/mbfilter_uuencode.c index cc90997c2fcae..83a56977d3e0e 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_uuencode.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_uuencode.c @@ -43,7 +43,8 @@ const mbfl_encoding mbfl_encoding_uuencode = { NULL, NULL, mb_uuencode_to_wchar, - mb_wchar_to_uuencode + mb_wchar_to_uuencode, + NULL }; const struct mbfl_convert_vtbl vtbl_uuencode_8bit = { diff --git a/ext/mbstring/libmbfl/filters/unicode_table_big5.h b/ext/mbstring/libmbfl/filters/unicode_table_big5.h index 88f71d808d58a..44daf3595a46b 100644 --- a/ext/mbstring/libmbfl/filters/unicode_table_big5.h +++ b/ext/mbstring/libmbfl/filters/unicode_table_big5.h @@ -27,6 +27,7 @@ /* Big5 -> UCS */ static const unsigned short big5_ucs_table[] = { +/* 0xA140 */ 0x3000,0xff0c,0x3001,0x3002,0xff0e,0x2022,0xff1b,0xff1a, 0xff1f,0xff01,0xfe30,0x2026,0x2025,0xfe50,0xff64,0xfe52, 0x00b7,0xfe54,0xfe55,0xfe56,0xfe57,0xff5c,0x2013,0xfe31, @@ -46,7 +47,9 @@ static const unsigned short big5_ucs_table[] = { 0xfe66,0x223c,0x2229,0x222a,0x22a5,0x2220,0x221f,0x22bf, 0x33d2,0x33d1,0x222b,0x222e,0x2235,0x2234,0x2640,0x2642, 0x2641,0x2609,0x2191,0x2193,0x2190,0x2192,0x2196,0x2197, -0x2199,0x2198,0x2225,0x2223,0x0000,0x0000,0xff0f,0xff3c, +0x2199,0x2198,0x2225,0x2223,0x0000, +/* 0xA240 */ +0x0000,0xff0f,0xff3c, 0xff04,0xffe5,0x3012,0x00a2,0x00a3,0xff05,0xff20,0x2103, 0x2109,0xfe69,0xfe6a,0xfe6b,0x33d5,0x339c,0x339d,0x339e, 0x33ce,0x33a1,0x338e,0x338f,0x33c4,0x00b0,0x5159,0x515b, @@ -66,7 +69,9 @@ static const unsigned short big5_ucs_table[] = { 0xff37,0xff38,0xff39,0xff3a,0xff41,0xff42,0xff43,0xff44, 0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c, 0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54, -0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0x0391,0x0392, +0xff55,0xff56, +/* 0xA340 */ +0xff57,0xff58,0xff59,0xff5a,0x0391,0x0392, 0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a, 0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3, 0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2, @@ -85,7 +90,9 @@ static const unsigned short big5_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4e00, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +/* 0xA440 */ +0x4e00, 0x4e59,0x4e01,0x4e03,0x4e43,0x4e5d,0x4e86,0x4e8c,0x4eba, 0x513f,0x5165,0x516b,0x51e0,0x5200,0x5201,0x529b,0x5315, 0x5341,0x535c,0x53c8,0x4e09,0x4e0b,0x4e08,0x4e0a,0x4e2b, @@ -105,7 +112,9 @@ static const unsigned short big5_ucs_table[] = { 0x624e,0x652f,0x6587,0x6597,0x65a4,0x65b9,0x65e5,0x66f0, 0x6708,0x6728,0x6b20,0x6b62,0x6b79,0x6bcb,0x6bd4,0x6bdb, 0x6c0f,0x6c34,0x706b,0x722a,0x7236,0x723b,0x7247,0x7259, -0x725b,0x72ac,0x738b,0x4e19,0x4e16,0x4e15,0x4e14,0x4e18, +0x725b,0x72ac,0x738b,0x4e19, +/* 0xA540 */ +0x4e16,0x4e15,0x4e14,0x4e18, 0x4e3b,0x4e4d,0x4e4f,0x4e4e,0x4ee5,0x4ed8,0x4ed4,0x4ed5, 0x4ed6,0x4ed7,0x4ee3,0x4ee4,0x4ed9,0x4ede,0x5145,0x5144, 0x5189,0x518a,0x51ac,0x51f9,0x51fa,0x51f8,0x520a,0x52a0, @@ -125,7 +134,9 @@ static const unsigned short big5_ucs_table[] = { 0x4ea4,0x4ea6,0x4ea5,0x4eff,0x4f09,0x4f19,0x4f0a,0x4f15, 0x4f0d,0x4f10,0x4f11,0x4f0f,0x4ef2,0x4ef6,0x4efb,0x4ef0, 0x4ef3,0x4efd,0x4f01,0x4f0b,0x5149,0x5147,0x5146,0x5148, -0x5168,0x5171,0x518d,0x51b0,0x5217,0x5211,0x5212,0x520e, +0x5168, +/* 0xA640 */ +0x5171,0x518d,0x51b0,0x5217,0x5211,0x5212,0x520e, 0x5216,0x52a3,0x5308,0x5321,0x5320,0x5370,0x5371,0x5409, 0x540f,0x540c,0x540a,0x5410,0x5401,0x540b,0x5404,0x5411, 0x540d,0x5408,0x5403,0x540e,0x5406,0x5412,0x56e0,0x56de, @@ -144,7 +155,9 @@ static const unsigned short big5_ucs_table[] = { 0x826e,0x8272,0x827e,0x866b,0x8840,0x884c,0x8863,0x897f, 0x9621,0x4e32,0x4ea8,0x4f4d,0x4f4f,0x4f47,0x4f57,0x4f5e, 0x4f34,0x4f5b,0x4f55,0x4f30,0x4f50,0x4f51,0x4f3d,0x4f3a, -0x4f38,0x4f43,0x4f54,0x4f3c,0x4f46,0x4f63,0x4f5c,0x4f60, +0x4f38,0x4f43,0x4f54,0x4f3c,0x4f46,0x4f63, +/* 0xA740 */ +0x4f5c,0x4f60, 0x4f2f,0x4f4e,0x4f36,0x4f59,0x4f5d,0x4f48,0x4f5a,0x514c, 0x514b,0x514d,0x5175,0x51b6,0x51b7,0x5225,0x5224,0x5229, 0x522a,0x5228,0x52ab,0x52a9,0x52aa,0x52ac,0x5323,0x5373, @@ -164,7 +177,9 @@ static const unsigned short big5_ucs_table[] = { 0x627e,0x6279,0x6273,0x6292,0x626f,0x6298,0x626e,0x6295, 0x6293,0x6291,0x6286,0x6539,0x653b,0x6538,0x65f1,0x66f4, 0x675f,0x674e,0x674f,0x6750,0x6751,0x675c,0x6756,0x675e, -0x6749,0x6746,0x6760,0x6753,0x6757,0x6b65,0x6bcf,0x6c42, +0x6749,0x6746,0x6760, +/* 0xA840 */ +0x6753,0x6757,0x6b65,0x6bcf,0x6c42, 0x6c5e,0x6c99,0x6c81,0x6c88,0x6c89,0x6c85,0x6c9b,0x6c6a, 0x6c7a,0x6c90,0x6c70,0x6c8c,0x6c68,0x6c96,0x6c92,0x6c7d, 0x6c83,0x6c72,0x6c7e,0x6c74,0x6c86,0x6c76,0x6c8d,0x6c94, @@ -184,6 +199,7 @@ static const unsigned short big5_ucs_table[] = { 0x51fd,0x523b,0x5238,0x5237,0x523a,0x5230,0x522e,0x5236, 0x5241,0x52be,0x52bb,0x5352,0x5354,0x5353,0x5351,0x5366, 0x5377,0x5378,0x5379,0x53d6,0x53d4,0x53d7,0x5473,0x5475, +/* 0xA940 */ 0x5496,0x5478,0x5495,0x5480,0x547b,0x5477,0x5484,0x5492, 0x5486,0x547c,0x5490,0x5471,0x5476,0x548c,0x549a,0x5462, 0x5468,0x548b,0x547d,0x548e,0x56fa,0x5783,0x5777,0x576a, @@ -203,7 +219,9 @@ static const unsigned short big5_ucs_table[] = { 0x62bd,0x62bc,0x62d0,0x62d9,0x62c7,0x62cd,0x62b5,0x62da, 0x62b1,0x62d8,0x62d6,0x62d7,0x62c6,0x62ac,0x62ce,0x653e, 0x65a7,0x65bc,0x65fa,0x6614,0x6613,0x660c,0x6606,0x6602, -0x660e,0x6600,0x660f,0x6615,0x660a,0x6607,0x670d,0x670b, +0x660e,0x6600,0x660f,0x6615,0x660a, +/* 0xAA40 */ +0x6607,0x670d,0x670b, 0x676d,0x678b,0x6795,0x6771,0x679c,0x6773,0x6777,0x6787, 0x679d,0x6797,0x676f,0x6770,0x677f,0x6789,0x677e,0x6790, 0x6775,0x679a,0x6793,0x677c,0x676a,0x6772,0x6b23,0x6b66, @@ -223,7 +241,9 @@ static const unsigned short big5_ucs_table[] = { 0x82b8,0x82a3,0x82b0,0x82be,0x82b7,0x864e,0x8671,0x521d, 0x8868,0x8ecb,0x8fce,0x8fd4,0x8fd1,0x90b5,0x90b8,0x90b1, 0x90b6,0x91c7,0x91d1,0x9577,0x9580,0x961c,0x9640,0x963f, -0x963b,0x9644,0x9642,0x96b9,0x96e8,0x9752,0x975e,0x4e9f, +0x963b,0x9644, +/* 0xAB40 */ +0x9642,0x96b9,0x96e8,0x9752,0x975e,0x4e9f, 0x4ead,0x4eae,0x4fe1,0x4fb5,0x4faf,0x4fbf,0x4fe0,0x4fd1, 0x4fcf,0x4fdd,0x4fc3,0x4fb6,0x4fd8,0x4fdf,0x4fca,0x4fd7, 0x4fae,0x4fd0,0x4fc4,0x4fc2,0x4fda,0x4fce,0x4fde,0x4fb7, @@ -242,7 +262,9 @@ static const unsigned short big5_ucs_table[] = { 0x5f87,0x5f8c,0x5f89,0x6012,0x601d,0x6020,0x6025,0x600e, 0x6028,0x604d,0x6070,0x6068,0x6062,0x6046,0x6043,0x606c, 0x606b,0x606a,0x6064,0x6241,0x62dc,0x6316,0x6309,0x62fc, -0x62ed,0x6301,0x62ee,0x62fd,0x6307,0x62f1,0x62f7,0x62ef, +0x62ed,0x6301,0x62ee,0x62fd,0x6307,0x62f1,0x62f7, +/* 0xAC40 */ +0x62ef, 0x62ec,0x62fe,0x62f4,0x6311,0x6302,0x653f,0x6545,0x65ab, 0x65bd,0x65e2,0x6625,0x662d,0x6620,0x6627,0x662f,0x661f, 0x6628,0x6631,0x6624,0x66f7,0x67ff,0x67d3,0x67f1,0x67d4, @@ -262,7 +284,9 @@ static const unsigned short big5_ucs_table[] = { 0x7814,0x780c,0x780d,0x7946,0x7949,0x7948,0x7947,0x79b9, 0x79ba,0x79d1,0x79d2,0x79cb,0x7a7f,0x7a81,0x7aff,0x7afd, 0x7c7d,0x7d02,0x7d05,0x7d00,0x7d09,0x7d07,0x7d04,0x7d06, -0x7f38,0x7f8e,0x7fbf,0x8004,0x8010,0x800d,0x8011,0x8036, +0x7f38,0x7f8e,0x7fbf,0x8004, +/* 0xAD40 */ +0x8010,0x800d,0x8011,0x8036, 0x80d6,0x80e5,0x80da,0x80c3,0x80c4,0x80cc,0x80e1,0x80db, 0x80ce,0x80de,0x80e4,0x80dd,0x81f4,0x8222,0x82e7,0x8303, 0x8305,0x82e3,0x82db,0x82e6,0x8304,0x82e5,0x8302,0x8309, @@ -282,7 +306,9 @@ static const unsigned short big5_ucs_table[] = { 0x525c,0x5254,0x525b,0x525d,0x532a,0x537f,0x539f,0x539d, 0x53df,0x54e8,0x5510,0x5501,0x5537,0x54fc,0x54e5,0x54f2, 0x5506,0x54fa,0x5514,0x54e9,0x54ed,0x54e1,0x5509,0x54ee, -0x54ea,0x54e6,0x5527,0x5507,0x54fd,0x550f,0x5703,0x5704, +0x54ea, +/* 0xAE40 */ +0x54e6,0x5527,0x5507,0x54fd,0x550f,0x5703,0x5704, 0x57c2,0x57d4,0x57cb,0x57c3,0x5809,0x590f,0x5957,0x5958, 0x595a,0x5a11,0x5a18,0x5a1c,0x5a1f,0x5a1b,0x5a13,0x59ec, 0x5a20,0x5a23,0x5a29,0x5a25,0x5a0c,0x5a09,0x5b6b,0x5c58, @@ -301,7 +327,9 @@ static const unsigned short big5_ucs_table[] = { 0x6851,0x683d,0x67f4,0x6850,0x6840,0x683c,0x6843,0x682a, 0x6845,0x6813,0x6818,0x6841,0x6b8a,0x6b89,0x6bb7,0x6c23, 0x6c27,0x6c28,0x6c26,0x6c24,0x6cf0,0x6d6a,0x6d95,0x6d88, -0x6d87,0x6d66,0x6d78,0x6d77,0x6d59,0x6d93,0x6d6c,0x6d89, +0x6d87,0x6d66,0x6d78,0x6d77,0x6d59,0x6d93, +/* 0xAF40 */ +0x6d6c,0x6d89, 0x6d6e,0x6d5a,0x6d74,0x6d69,0x6d8c,0x6d8a,0x6d79,0x6d85, 0x6d65,0x6d94,0x70ca,0x70d8,0x70e4,0x70d9,0x70c8,0x70cf, 0x7239,0x7279,0x72fc,0x72f9,0x72fd,0x72f8,0x72f7,0x7386, @@ -321,7 +349,9 @@ static const unsigned short big5_ucs_table[] = { 0x81ed,0x81ec,0x8200,0x8210,0x822a,0x822b,0x8228,0x822c, 0x82bb,0x832b,0x8352,0x8354,0x834a,0x8338,0x8350,0x8349, 0x8335,0x8334,0x834f,0x8332,0x8339,0x8336,0x8317,0x8340, -0x8331,0x8328,0x8343,0x8654,0x868a,0x86aa,0x8693,0x86a4, +0x8331,0x8328,0x8343, +/* 0xB040 */ +0x8654,0x868a,0x86aa,0x8693,0x86a4, 0x86a9,0x868c,0x86a3,0x869c,0x8870,0x8877,0x8881,0x8882, 0x887d,0x8879,0x8a18,0x8a10,0x8a0e,0x8a0c,0x8a15,0x8a0a, 0x8a17,0x8a13,0x8a16,0x8a0f,0x8a11,0x8c48,0x8c7a,0x8c79, @@ -341,6 +371,7 @@ static const unsigned short big5_ucs_table[] = { 0x5541,0x5557,0x5708,0x570b,0x5709,0x57df,0x5805,0x580a, 0x5806,0x57e0,0x57e4,0x57fa,0x5802,0x5835,0x57f7,0x57f9, 0x5920,0x5962,0x5a36,0x5a41,0x5a49,0x5a66,0x5a6a,0x5a40, +/* 0xB140 */ 0x5a3c,0x5a62,0x5a5a,0x5a46,0x5a4a,0x5b70,0x5bc7,0x5bc5, 0x5bc4,0x5bc2,0x5bbf,0x5bc6,0x5c09,0x5c08,0x5c07,0x5c60, 0x5c5c,0x5c5d,0x5d07,0x5d06,0x5d0e,0x5d1b,0x5d16,0x5d22, @@ -360,7 +391,9 @@ static const unsigned short big5_ucs_table[] = { 0x6666,0x665e,0x66f9,0x52d7,0x671b,0x6881,0x68af,0x68a2, 0x6893,0x68b5,0x687f,0x6876,0x68b1,0x68a7,0x6897,0x68b0, 0x6883,0x68c4,0x68ad,0x6886,0x6885,0x6894,0x689d,0x68a8, -0x689f,0x68a1,0x6882,0x6b32,0x6bba,0x6beb,0x6bec,0x6c2b, +0x689f,0x68a1,0x6882,0x6b32,0x6bba, +/* 0xB240 */ +0x6beb,0x6bec,0x6c2b, 0x6d8e,0x6dbc,0x6df3,0x6dd9,0x6db2,0x6de1,0x6dcc,0x6de4, 0x6dfb,0x6dfa,0x6e05,0x6dc7,0x6dcb,0x6daf,0x6dd1,0x6dae, 0x6dde,0x6df9,0x6db8,0x6df7,0x6df5,0x6dc5,0x6dd2,0x6e1a, @@ -380,7 +413,9 @@ static const unsigned short big5_ucs_table[] = { 0x8123,0x812b,0x8129,0x8130,0x8124,0x8202,0x8235,0x8237, 0x8236,0x8239,0x838e,0x839e,0x8398,0x8378,0x83a2,0x8396, 0x83bd,0x83ab,0x8392,0x838a,0x8393,0x8389,0x83a0,0x8377, -0x837b,0x837c,0x8386,0x83a7,0x8655,0x5f6a,0x86c7,0x86c0, +0x837b,0x837c, +/* 0xB340 */ +0x8386,0x83a7,0x8655,0x5f6a,0x86c7,0x86c0, 0x86b6,0x86c4,0x86b5,0x86c6,0x86cb,0x86b1,0x86af,0x86c9, 0x8853,0x889e,0x8888,0x88ab,0x8892,0x8896,0x888d,0x888b, 0x8993,0x898f,0x8a2a,0x8a1d,0x8a23,0x8a25,0x8a31,0x8a2d, @@ -399,7 +434,9 @@ static const unsigned short big5_ucs_table[] = { 0x55aa,0x5594,0x5587,0x558b,0x5583,0x55b3,0x55ae,0x559f, 0x553e,0x55b2,0x559a,0x55bb,0x55ac,0x55b1,0x557e,0x5589, 0x55ab,0x5599,0x570d,0x582f,0x582a,0x5834,0x5824,0x5830, -0x5831,0x5821,0x581d,0x5820,0x58f9,0x58fa,0x5960,0x5a77, +0x5831,0x5821,0x581d,0x5820,0x58f9,0x58fa,0x5960, +/* 0xB440 */ +0x5a77, 0x5a9a,0x5a7f,0x5a92,0x5a9b,0x5aa7,0x5b73,0x5b71,0x5bd2, 0x5bcc,0x5bd3,0x5bd0,0x5c0a,0x5c0b,0x5c31,0x5d4c,0x5d50, 0x5d34,0x5d47,0x5dfd,0x5e45,0x5e3d,0x5e40,0x5e43,0x5e7e, @@ -419,7 +456,9 @@ static const unsigned short big5_ucs_table[] = { 0x6c2c,0x6e2f,0x6e38,0x6e54,0x6e21,0x6e32,0x6e67,0x6e4a, 0x6e20,0x6e25,0x6e23,0x6e1b,0x6e5b,0x6e58,0x6e24,0x6e56, 0x6e6e,0x6e2d,0x6e26,0x6e6f,0x6e34,0x6e4d,0x6e3a,0x6e2c, -0x6e43,0x6e1d,0x6e3e,0x6ecb,0x6e89,0x6e19,0x6e4e,0x6e63, +0x6e43,0x6e1d,0x6e3e,0x6ecb, +/* 0xB540 */ +0x6e89,0x6e19,0x6e4e,0x6e63, 0x6e44,0x6e72,0x6e69,0x6e5f,0x7119,0x711a,0x7126,0x7130, 0x7121,0x7136,0x716e,0x711c,0x724c,0x7284,0x7280,0x7336, 0x7325,0x7334,0x7329,0x743a,0x742a,0x7433,0x7422,0x7425, @@ -439,7 +478,9 @@ static const unsigned short big5_ucs_table[] = { 0x83dc,0x8407,0x83d4,0x83df,0x865b,0x86df,0x86d9,0x86ed, 0x86d4,0x86db,0x86e4,0x86d0,0x86de,0x8857,0x88c1,0x88c2, 0x88b1,0x8983,0x8996,0x8a3b,0x8a60,0x8a55,0x8a5e,0x8a3c, -0x8a41,0x8a54,0x8a5b,0x8a50,0x8a46,0x8a34,0x8a3a,0x8a36, +0x8a41, +/* 0xB640 */ +0x8a54,0x8a5b,0x8a50,0x8a46,0x8a34,0x8a3a,0x8a36, 0x8a56,0x8c61,0x8c82,0x8caf,0x8cbc,0x8cb3,0x8cbd,0x8cc1, 0x8cbb,0x8cc0,0x8cb4,0x8cb7,0x8cb6,0x8cbf,0x8cb8,0x8d8a, 0x8d85,0x8d81,0x8dce,0x8ddd,0x8dcb,0x8dda,0x8dd1,0x8dcc, @@ -458,7 +499,9 @@ static const unsigned short big5_ucs_table[] = { 0x55e4,0x55ef,0x55da,0x55e1,0x55c5,0x55c6,0x55e5,0x55c9, 0x5712,0x5713,0x585e,0x5851,0x5858,0x5857,0x585a,0x5854, 0x586b,0x584c,0x586d,0x584a,0x5862,0x5852,0x584b,0x5967, -0x5ac1,0x5ac9,0x5acc,0x5abe,0x5abd,0x5abc,0x5ab3,0x5ac2, +0x5ac1,0x5ac9,0x5acc,0x5abe,0x5abd,0x5abc, +/* 0xB740 */ +0x5ab3,0x5ac2, 0x5ab2,0x5d69,0x5d6f,0x5e4c,0x5e79,0x5ec9,0x5ec8,0x5f12, 0x5f59,0x5fac,0x5fae,0x611a,0x610f,0x6148,0x611f,0x60f3, 0x611b,0x60f9,0x6101,0x6108,0x614e,0x614c,0x6144,0x614d, @@ -478,7 +521,9 @@ static const unsigned short big5_ucs_table[] = { 0x745a,0x7455,0x745f,0x745e,0x7441,0x743f,0x7459,0x745b, 0x745c,0x7576,0x7578,0x7600,0x75f0,0x7601,0x75f2,0x75f1, 0x75fa,0x75ff,0x75f4,0x75f3,0x76de,0x76df,0x775b,0x776b, -0x7766,0x775e,0x7763,0x7779,0x776a,0x776c,0x775c,0x7765, +0x7766,0x775e,0x7763, +/* 0xB840 */ +0x7779,0x776a,0x776c,0x775c,0x7765, 0x7768,0x7762,0x77ee,0x788e,0x78b0,0x7897,0x7898,0x788c, 0x7889,0x787c,0x7891,0x7893,0x787f,0x797a,0x797f,0x7981, 0x842c,0x79bd,0x7a1c,0x7a1a,0x7a20,0x7a14,0x7a1f,0x7a1e, @@ -498,6 +543,7 @@ static const unsigned short big5_ucs_table[] = { 0x8c8a,0x8c89,0x8cca,0x8cc7,0x8cc8,0x8cc4,0x8cb2,0x8cc3, 0x8cc2,0x8cc5,0x8de1,0x8ddf,0x8de8,0x8def,0x8df3,0x8dfa, 0x8dea,0x8de4,0x8de6,0x8eb2,0x8f03,0x8f09,0x8efe,0x8f0a, +/* 0xB940 */ 0x8f9f,0x8fb2,0x904b,0x904a,0x9053,0x9042,0x9054,0x903c, 0x9055,0x9050,0x9047,0x904f,0x904e,0x904d,0x9051,0x903e, 0x9041,0x9112,0x9117,0x916c,0x916a,0x9169,0x91c9,0x9237, @@ -517,7 +563,9 @@ static const unsigned short big5_ucs_table[] = { 0x5ad6,0x5ad8,0x5ae3,0x5b75,0x5bde,0x5be7,0x5be1,0x5be5, 0x5be6,0x5be8,0x5be2,0x5be4,0x5bdf,0x5c0d,0x5c62,0x5d84, 0x5d87,0x5e5b,0x5e63,0x5e55,0x5e57,0x5e54,0x5ed3,0x5ed6, -0x5f0a,0x5f46,0x5f70,0x5fb9,0x6147,0x613f,0x614b,0x6177, +0x5f0a,0x5f46,0x5f70,0x5fb9,0x6147, +/* 0xBA40 */ +0x613f,0x614b,0x6177, 0x6162,0x6163,0x615f,0x615a,0x6158,0x6175,0x622a,0x6487, 0x6458,0x6454,0x64a4,0x6478,0x645f,0x647a,0x6451,0x6467, 0x6434,0x646d,0x647b,0x6572,0x65a1,0x65d7,0x65d6,0x66a2, @@ -537,7 +585,9 @@ static const unsigned short big5_ucs_table[] = { 0x7b8f,0x7bb8,0x7b87,0x7b84,0x7cb9,0x7cbd,0x7cbe,0x7dbb, 0x7db0,0x7d9c,0x7dbd,0x7dbe,0x7da0,0x7dca,0x7db4,0x7db2, 0x7db1,0x7dba,0x7da2,0x7dbf,0x7db5,0x7db8,0x7dad,0x7dd2, -0x7dc7,0x7dac,0x7f70,0x7fe0,0x7fe1,0x7fdf,0x805e,0x805a, +0x7dc7,0x7dac, +/* 0xBB40 */ +0x7f70,0x7fe0,0x7fe1,0x7fdf,0x805e,0x805a, 0x8087,0x8150,0x8180,0x818f,0x8188,0x818a,0x817f,0x8182, 0x81e7,0x81fa,0x8207,0x8214,0x821e,0x824b,0x84c9,0x84bf, 0x84c6,0x84c4,0x8499,0x849e,0x84b2,0x849c,0x84cb,0x84b8, @@ -556,7 +606,9 @@ static const unsigned short big5_ucs_table[] = { 0x97f6,0x9817,0x9818,0x98af,0x98b1,0x9903,0x9905,0x990c, 0x9909,0x99c1,0x9aaf,0x9ab0,0x9ae6,0x9b41,0x9b42,0x9cf4, 0x9cf6,0x9cf3,0x9ebc,0x9f3b,0x9f4a,0x5104,0x5100,0x50fb, -0x50f5,0x50f9,0x5102,0x5108,0x5109,0x5105,0x51dc,0x5287, +0x50f5,0x50f9,0x5102,0x5108,0x5109,0x5105,0x51dc, +/* 0xBC40 */ +0x5287, 0x5288,0x5289,0x528d,0x528a,0x52f0,0x53b2,0x562e,0x563b, 0x5639,0x5632,0x563f,0x5634,0x5629,0x5653,0x564e,0x5657, 0x5674,0x5636,0x562f,0x5630,0x5880,0x589f,0x589e,0x58b3, @@ -576,7 +628,9 @@ static const unsigned short big5_ucs_table[] = { 0x6f66,0x6f54,0x6f86,0x6f6d,0x6f5b,0x6f78,0x6f6e,0x6f8e, 0x6f7a,0x6f70,0x6f64,0x6f97,0x6f58,0x6ed5,0x6f6f,0x6f60, 0x6f5f,0x719f,0x71ac,0x71b1,0x71a8,0x7256,0x729b,0x734e, -0x7357,0x7469,0x748b,0x7483,0x747e,0x7480,0x757f,0x7620, +0x7357,0x7469,0x748b,0x7483, +/* 0xBD40 */ +0x747e,0x7480,0x757f,0x7620, 0x7629,0x761f,0x7624,0x7626,0x7621,0x7622,0x769a,0x76ba, 0x76e4,0x778e,0x7787,0x778c,0x7791,0x778b,0x78cb,0x78c5, 0x78ba,0x78ca,0x78be,0x78d5,0x78bc,0x78d0,0x7a3f,0x7a3c, @@ -596,7 +650,9 @@ static const unsigned short big5_ucs_table[] = { 0x8ce3,0x8cdc,0x8cea,0x8ce1,0x8d6d,0x8d9f,0x8da3,0x8e2b, 0x8e10,0x8e1d,0x8e22,0x8e0f,0x8e29,0x8e1f,0x8e21,0x8e1e, 0x8eba,0x8f1d,0x8f1b,0x8f1f,0x8f29,0x8f26,0x8f2a,0x8f1c, -0x8f1e,0x8f25,0x9069,0x906e,0x9068,0x906d,0x9077,0x9130, +0x8f1e, +/* 0xBE40 */ +0x8f25,0x9069,0x906e,0x9068,0x906d,0x9077,0x9130, 0x912d,0x9127,0x9131,0x9187,0x9189,0x918b,0x9183,0x92c5, 0x92bb,0x92b7,0x92ea,0x92ac,0x92e4,0x92c1,0x92b3,0x92bc, 0x92d2,0x92c7,0x92f0,0x92b2,0x95ad,0x95b1,0x9704,0x9706, @@ -615,7 +671,9 @@ static const unsigned short big5_ucs_table[] = { 0x64d4,0x64be,0x6574,0x66c6,0x66c9,0x66b9,0x66c4,0x66c7, 0x66b8,0x6a3d,0x6a38,0x6a3a,0x6a59,0x6a6b,0x6a58,0x6a39, 0x6a44,0x6a62,0x6a61,0x6a4b,0x6a47,0x6a35,0x6a5f,0x6a48, -0x6b59,0x6b77,0x6c05,0x6fc2,0x6fb1,0x6fa1,0x6fc3,0x6fa4, +0x6b59,0x6b77,0x6c05,0x6fc2,0x6fb1,0x6fa1, +/* 0xBF40 */ +0x6fc3,0x6fa4, 0x6fc1,0x6fa7,0x6fb3,0x6fc0,0x6fb9,0x6fb6,0x6fa6,0x6fa0, 0x6fb4,0x71be,0x71c9,0x71d0,0x71d2,0x71c8,0x71d5,0x71b9, 0x71ce,0x71d9,0x71dc,0x71c3,0x71c4,0x7368,0x749c,0x74a3, @@ -635,7 +693,9 @@ static const unsigned short big5_ucs_table[] = { 0x8e42,0x8e39,0x8e35,0x8f3b,0x8f2f,0x8f38,0x8f33,0x8fa8, 0x8fa6,0x9075,0x9074,0x9078,0x9072,0x907c,0x907a,0x9134, 0x9192,0x9320,0x9336,0x92f8,0x9333,0x932f,0x9322,0x92fc, -0x932b,0x9304,0x931a,0x9310,0x9326,0x9321,0x9315,0x932e, +0x932b,0x9304,0x931a, +/* 0xC040 */ +0x9310,0x9326,0x9321,0x9315,0x932e, 0x9319,0x95bb,0x96a7,0x96a8,0x96aa,0x96d5,0x970e,0x9711, 0x9716,0x970d,0x9713,0x970f,0x975b,0x975c,0x9766,0x9798, 0x9830,0x9838,0x983b,0x9837,0x982d,0x9839,0x9824,0x9910, @@ -655,6 +715,7 @@ static const unsigned short big5_ucs_table[] = { 0x71df,0x71ee,0x71e6,0x71e5,0x71ed,0x71ec,0x71f4,0x71e0, 0x7235,0x7246,0x7370,0x7372,0x74a9,0x74b0,0x74a6,0x74a8, 0x7646,0x7642,0x764c,0x76ea,0x77b3,0x77aa,0x77b0,0x77ac, +/* 0xC140 */ 0x77a7,0x77ad,0x77ef,0x78f7,0x78fa,0x78f4,0x78ef,0x7901, 0x79a7,0x79aa,0x7a57,0x7abf,0x7c07,0x7c0d,0x7bfe,0x7bf7, 0x7c0c,0x7be0,0x7ce0,0x7cdc,0x7cde,0x7ce2,0x7cdf,0x7cd9, @@ -674,7 +735,9 @@ static const unsigned short big5_ucs_table[] = { 0x9382,0x9328,0x9375,0x934a,0x9365,0x934b,0x9318,0x937e, 0x936c,0x935b,0x9370,0x935a,0x9354,0x95ca,0x95cb,0x95cc, 0x95c8,0x95c6,0x96b1,0x96b8,0x96d6,0x971c,0x971e,0x97a0, -0x97d3,0x9846,0x98b6,0x9935,0x9a01,0x99ff,0x9bae,0x9bab, +0x97d3,0x9846,0x98b6,0x9935,0x9a01, +/* 0xC240 */ +0x99ff,0x9bae,0x9bab, 0x9baa,0x9bad,0x9d3b,0x9d3f,0x9e8b,0x9ecf,0x9ede,0x9edc, 0x9edd,0x9edb,0x9f3e,0x9f4b,0x53e2,0x5695,0x56ae,0x58d9, 0x58d8,0x5b38,0x5f5d,0x61e3,0x6233,0x64f4,0x64f2,0x64fe, @@ -694,7 +757,9 @@ static const unsigned short big5_ucs_table[] = { 0x91ab,0x91ac,0x91d0,0x9394,0x938a,0x9396,0x93a2,0x93b3, 0x93ae,0x93ac,0x93b0,0x9398,0x939a,0x9397,0x95d4,0x95d6, 0x95d0,0x95d5,0x96e2,0x96dc,0x96d9,0x96db,0x96de,0x9724, -0x97a3,0x97a6,0x97ad,0x97f9,0x984d,0x984f,0x984c,0x984e, +0x97a3,0x97a6, +/* 0xC340 */ +0x97ad,0x97f9,0x984d,0x984f,0x984c,0x984e, 0x9853,0x98ba,0x993e,0x993f,0x993d,0x992e,0x99a5,0x9a0e, 0x9ac1,0x9b03,0x9b06,0x9b4f,0x9b4e,0x9b4d,0x9bca,0x9bc9, 0x9bfd,0x9bc8,0x9bc0,0x9d51,0x9d5d,0x9d60,0x9ee0,0x9f15, @@ -713,7 +778,9 @@ static const unsigned short big5_ucs_table[] = { 0x8e74,0x8f54,0x8f4e,0x8fad,0x908a,0x908b,0x91b1,0x91ae, 0x93e1,0x93d1,0x93df,0x93c3,0x93c8,0x93dc,0x93dd,0x93d6, 0x93e2,0x93cd,0x93d8,0x93e4,0x93d7,0x93e8,0x95dc,0x96b4, -0x96e3,0x972a,0x9727,0x9761,0x97dc,0x97fb,0x985e,0x9858, +0x96e3,0x972a,0x9727,0x9761,0x97dc,0x97fb,0x985e, +/* 0xC440 */ +0x9858, 0x985b,0x98bc,0x9945,0x9949,0x9a16,0x9a19,0x9b0d,0x9be8, 0x9be7,0x9bd6,0x9bdb,0x9d89,0x9d61,0x9d72,0x9d6a,0x9d6c, 0x9e92,0x9e97,0x9e93,0x9eb4,0x52f8,0x56a8,0x56b7,0x56b6, @@ -733,7 +800,9 @@ static const unsigned short big5_ucs_table[] = { 0x6595,0x66e9,0x6afb,0x6b04,0x6afa,0x6bb2,0x704c,0x721b, 0x72a7,0x74d6,0x74d4,0x7669,0x77d3,0x7c50,0x7e8f,0x7e8c, 0x7fbc,0x8617,0x862d,0x861a,0x8823,0x8822,0x8821,0x881f, -0x896a,0x896c,0x89bd,0x8b74,0x8b77,0x8b7d,0x8d13,0x8e8a, +0x896a,0x896c,0x89bd,0x8b74, +/* 0xC540 */ +0x8b77,0x8b7d,0x8d13,0x8e8a, 0x8e8d,0x8e8b,0x8f5f,0x8faf,0x91ba,0x942e,0x9433,0x9435, 0x943a,0x9438,0x9432,0x942b,0x95e2,0x9738,0x9739,0x9732, 0x97ff,0x9867,0x9865,0x9957,0x9a45,0x9a43,0x9a40,0x9a3e, @@ -753,7 +822,9 @@ static const unsigned short big5_ucs_table[] = { 0x9a5b,0x9a57,0x9ad3,0x9ad4,0x9ad1,0x9c54,0x9c57,0x9c56, 0x9de5,0x9e9f,0x9ef4,0x56d1,0x58e9,0x652c,0x705e,0x7671, 0x7672,0x77d7,0x7f50,0x7f88,0x8836,0x8839,0x8862,0x8b93, -0x8b92,0x8b96,0x8277,0x8d1b,0x91c0,0x946a,0x9742,0x9748, +0x8b92, +/* 0xC640 */ +0x8b96,0x8277,0x8d1b,0x91c0,0x946a,0x9742,0x9748, 0x9744,0x97c6,0x9870,0x9a5f,0x9b22,0x9b58,0x9c5f,0x9df9, 0x9dfa,0x9e7c,0x9e7d,0x9f07,0x9f77,0x9f72,0x5ef3,0x6b16, 0x7063,0x7c6c,0x7c6e,0x883b,0x89c0,0x8ea1,0x91c1,0x9472, @@ -772,7 +843,9 @@ static const unsigned short big5_ucs_table[] = { 0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,0x3083,0x3084, 0x3085,0x3086,0x3087,0x3088,0x3089,0x308a,0x308b,0x308c, 0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,0x30a1, -0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9, +0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7, +/* 0xC740 */ +0x30a8,0x30a9, 0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1, 0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,0x30b8,0x30b9, 0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1, @@ -792,26 +865,29 @@ static const unsigned short big5_ucs_table[] = { 0x044b,0x044c,0x044d,0x044e,0x044f,0x2460,0x2461,0x2462, 0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,0x2474, 0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,0x247b,0x247c, -0x247d,0x0000,0x0000,0xf7ac,0xf7ad,0xf7ae,0xf7af,0xf7b0, -0xf7b1,0xf7b2,0xf7b3,0xf7b4,0xf7b5,0xf7b6,0xf7b7,0xf7b8, -0xf7b9,0xf7ba,0xf7bb,0xf7bc,0xf7bd,0xf7be,0xf7bf,0xf7c0, -0xf7c1,0xf7c2,0xf7c3,0xf7c4,0xf7c5,0xf7c6,0xf7c7,0xf7c8, -0xf7c9,0xf7ca,0xf7cb,0xf7cc,0xf7cd,0xf7ce,0xf7cf,0xf7d0, -0xf7d1,0xf7d2,0xf7d3,0xf7d4,0xf7d5,0xf7d6,0xf7d7,0xf7d8, -0xf7d9,0xf7da,0xf7db,0xf7dc,0xf7dd,0xf7de,0xf7df,0xf7e0, -0xf7e1,0xf7e2,0xf7e3,0xf7e4,0xf7e5,0xf7e6,0xf7e7,0xf7e8, -0xf7e9,0xf7ea,0xf7eb,0xf7ec,0xf7ed,0xf7ee,0xf7ef,0xf7f0, -0xf7f1,0xf7f2,0xf7f3,0xf7f4,0xf7f5,0xf7f6,0xf7f7,0xf7f8, -0xf7f9,0xf7fa,0xf7fb,0xf7fc,0xf7fd,0xf7fe,0xf7ff,0xf800, -0xf801,0xf802,0xf803,0xf804,0xf805,0xf806,0xf807,0xf808, -0xf809,0xf80a,0xf80b,0xf80c,0xf80d,0xf80e,0xf80f,0xf810, -0xf811,0xf812,0xf813,0xf814,0xf815,0xf816,0xf817,0xf818, -0xf819,0xf81a,0xf81b,0xf81c,0xf81d,0xf81e,0xf81f,0xf820, -0xf821,0xf822,0xf823,0xf824,0xf825,0xf826,0xf827,0xf828, -0xf829,0xf82a,0xf82b,0xf82c,0xf82d,0xf82e,0xf82f,0xf830, -0xf831,0xf832,0xf833,0xf834,0xf835,0xf836,0xf837,0xf838, -0xf839,0xf83a,0xf83b,0xf83c,0xf83d,0xf83e,0xf83f,0xf840, -0xf841,0xf842,0xf843,0xf844,0xf845,0xf846,0xf847,0xf848, +0x247d,0x0000,0x0000, +/* 0xC840 */ +0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +/* 0xC940 */ 0x4e42,0x4e5c,0x51f5,0x531a,0x5382,0x4e07,0x4e0c,0x4e47, 0x4e8d,0x56d7,0xfa0c,0x5c6e,0x5f73,0x4e0f,0x5187,0x4e0e, 0x4e2e,0x4e93,0x4ec2,0x4ec9,0x4ec8,0x5198,0x52fc,0x536c, @@ -831,7 +907,9 @@ static const unsigned short big5_ucs_table[] = { 0x5fcf,0x625c,0x625e,0x6264,0x6261,0x6266,0x6262,0x6259, 0x6260,0x625a,0x6265,0x65ef,0x65ee,0x673e,0x6739,0x6738, 0x673b,0x673a,0x673f,0x673c,0x6733,0x6c18,0x6c46,0x6c52, -0x6c5c,0x6c4f,0x6c4a,0x6c54,0x6c4b,0x6c4c,0x7071,0x725e, +0x6c5c,0x6c4f,0x6c4a,0x6c54,0x6c4b, +/* 0xCA40 */ +0x6c4c,0x7071,0x725e, 0x72b4,0x72b5,0x738e,0x752a,0x767f,0x7a75,0x7f51,0x8278, 0x827c,0x8280,0x827d,0x827f,0x864d,0x897e,0x9099,0x9097, 0x9098,0x909b,0x9094,0x9622,0x9624,0x9620,0x9623,0x4f56, @@ -851,7 +929,9 @@ static const unsigned short big5_ucs_table[] = { 0x5ff4,0x623a,0x6283,0x628c,0x628e,0x628f,0x6294,0x6287, 0x6271,0x627b,0x627a,0x6270,0x6281,0x6288,0x6277,0x627d, 0x6272,0x6274,0x6537,0x65f0,0x65f4,0x65f3,0x65f2,0x65f5, -0x6745,0x6747,0x6759,0x6755,0x674c,0x6748,0x675d,0x674d, +0x6745,0x6747, +/* 0xCB40 */ +0x6759,0x6755,0x674c,0x6748,0x675d,0x674d, 0x675a,0x674b,0x6bd0,0x6c19,0x6c1a,0x6c78,0x6c67,0x6c6b, 0x6c84,0x6c8b,0x6c8f,0x6c71,0x6c6f,0x6c69,0x6c9a,0x6c6d, 0x6c87,0x6c95,0x6c9c,0x6c66,0x6c73,0x6c65,0x6c7b,0x6c8e, @@ -870,7 +950,9 @@ static const unsigned short big5_ucs_table[] = { 0x5488,0x546b,0x547a,0x547e,0x5465,0x546c,0x5474,0x5466, 0x548d,0x546f,0x5461,0x5460,0x5498,0x5463,0x5467,0x5464, 0x56f7,0x56f9,0x576f,0x5772,0x576d,0x576b,0x5771,0x5770, -0x5776,0x5780,0x5775,0x577b,0x5773,0x5774,0x5762,0x5768, +0x5776,0x5780,0x5775,0x577b,0x5773,0x5774,0x5762, +/* 0xCC40 */ +0x5768, 0x577d,0x590c,0x5945,0x59b5,0x59ba,0x59cf,0x59ce,0x59b2, 0x59cc,0x59c1,0x59b6,0x59bc,0x59c3,0x59d6,0x59b1,0x59bd, 0x59c0,0x59c8,0x59b4,0x59c7,0x5b62,0x5b65,0x5b93,0x5b95, @@ -890,7 +972,9 @@ static const unsigned short big5_ucs_table[] = { 0x6783,0x677d,0x6781,0x6778,0x6779,0x6794,0x6b25,0x6b80, 0x6b7e,0x6bde,0x6c1d,0x6c93,0x6cec,0x6ceb,0x6cee,0x6cd9, 0x6cb6,0x6cd4,0x6cad,0x6ce7,0x6cb7,0x6cd0,0x6cc2,0x6cba, -0x6cc3,0x6cc6,0x6ced,0x6cf2,0x6cd2,0x6cdd,0x6cb4,0x6c8a, +0x6cc3,0x6cc6,0x6ced,0x6cf2, +/* 0xCD40 */ +0x6cd2,0x6cdd,0x6cb4,0x6c8a, 0x6c9d,0x6c80,0x6cde,0x6cc0,0x6d30,0x6ccd,0x6cc7,0x6cb0, 0x6cf9,0x6ccf,0x6ce9,0x6cd1,0x7094,0x7098,0x7085,0x7093, 0x7086,0x7084,0x7091,0x7096,0x7082,0x709a,0x7083,0x726a, @@ -910,7 +994,9 @@ static const unsigned short big5_ucs_table[] = { 0x4fd9,0x4fbb,0x4fb3,0x4fdb,0x4fc7,0x4fd6,0x4fba,0x4fc0, 0x4fb9,0x4fec,0x5244,0x5249,0x52c0,0x52c2,0x533d,0x537c, 0x5397,0x5396,0x5399,0x5398,0x54ba,0x54a1,0x54ad,0x54a5, -0x54cf,0x54c3,0x830d,0x54b7,0x54ae,0x54d6,0x54b6,0x54c5, +0x54cf, +/* 0xCE40 */ +0x54c3,0x830d,0x54b7,0x54ae,0x54d6,0x54b6,0x54c5, 0x54c6,0x54a0,0x5470,0x54bc,0x54a2,0x54be,0x5472,0x54de, 0x54b0,0x57b5,0x579e,0x579f,0x57a4,0x578c,0x5797,0x579d, 0x579b,0x5794,0x5798,0x578f,0x5799,0x57a5,0x579a,0x5795, @@ -929,7 +1015,9 @@ static const unsigned short big5_ucs_table[] = { 0x6313,0x6314,0x62fa,0x6315,0x62fb,0x62f0,0x6541,0x6543, 0x65aa,0x65bf,0x6636,0x6621,0x6632,0x6635,0x661c,0x6626, 0x6622,0x6633,0x662b,0x663a,0x661d,0x6634,0x6639,0x662e, -0x670f,0x6710,0x67c1,0x67f2,0x67c8,0x67ba,0x67dc,0x67bb, +0x670f,0x6710,0x67c1,0x67f2,0x67c8,0x67ba, +/* 0xCF40 */ +0x67dc,0x67bb, 0x67f8,0x67d8,0x67c0,0x67b7,0x67c5,0x67eb,0x67e4,0x67df, 0x67b5,0x67cd,0x67b3,0x67f7,0x67f6,0x67ee,0x67e3,0x67c2, 0x67b9,0x67ce,0x67e7,0x67f0,0x67b2,0x67fc,0x67c6,0x67ed, @@ -949,7 +1037,9 @@ static const unsigned short big5_ucs_table[] = { 0x770a,0x76f7,0x76fb,0x76fa,0x77e7,0x77e8,0x7806,0x7811, 0x7812,0x7805,0x7810,0x780f,0x780e,0x7809,0x7803,0x7813, 0x794a,0x794c,0x794b,0x7945,0x7944,0x79d5,0x79cd,0x79cf, -0x79d6,0x79ce,0x7a80,0x7a7e,0x7ad1,0x7b00,0x7b01,0x7c7a, +0x79d6,0x79ce,0x7a80, +/* 0xD040 */ +0x7a7e,0x7ad1,0x7b00,0x7b01,0x7c7a, 0x7c78,0x7c79,0x7c7f,0x7c80,0x7c81,0x7d03,0x7d08,0x7d01, 0x7f58,0x7f91,0x7f8d,0x7fbe,0x8007,0x800e,0x800f,0x8014, 0x8037,0x80d8,0x80c7,0x80e0,0x80d1,0x80c8,0x80c2,0x80d0, @@ -969,6 +1059,7 @@ static const unsigned short big5_ucs_table[] = { 0x525a,0x5252,0x525e,0x525f,0x5255,0x5262,0x52cd,0x530e, 0x539e,0x5526,0x54e2,0x5517,0x5512,0x54e7,0x54f3,0x54e4, 0x551a,0x54ff,0x5504,0x5508,0x54eb,0x5511,0x5505,0x54f1, +/* 0xD140 */ 0x550a,0x54fb,0x54f7,0x54f8,0x54e0,0x550e,0x5503,0x550b, 0x5701,0x5702,0x57cc,0x5832,0x57d5,0x57d2,0x57ba,0x57c6, 0x57bd,0x57bc,0x57b8,0x57b6,0x57bf,0x57c7,0x57d0,0x57b9, @@ -988,7 +1079,9 @@ static const unsigned short big5_ucs_table[] = { 0x6831,0x681c,0x6835,0x682b,0x682d,0x682f,0x684e,0x6844, 0x6834,0x681d,0x6812,0x6814,0x6826,0x6828,0x682e,0x684d, 0x683a,0x6825,0x6820,0x6b2c,0x6b2f,0x6b2d,0x6b31,0x6b34, -0x6b6d,0x8082,0x6b88,0x6be6,0x6be4,0x6be8,0x6be3,0x6be2, +0x6b6d,0x8082,0x6b88,0x6be6,0x6be4, +/* 0xD240 */ +0x6be8,0x6be3,0x6be2, 0x6be7,0x6c25,0x6d7a,0x6d63,0x6d64,0x6d76,0x6d0d,0x6d61, 0x6d92,0x6d58,0x6d62,0x6d6d,0x6d6f,0x6d91,0x6d8d,0x6def, 0x6d7f,0x6d86,0x6d5e,0x6d67,0x6d60,0x6d97,0x6d70,0x6d7c, @@ -1008,7 +1101,9 @@ static const unsigned short big5_ucs_table[] = { 0x7831,0x7954,0x795b,0x794f,0x795c,0x7953,0x7952,0x7951, 0x79eb,0x79ec,0x79e0,0x79ee,0x79ed,0x79ea,0x79dc,0x79de, 0x79dd,0x7a86,0x7a89,0x7a85,0x7a8b,0x7a8c,0x7a8a,0x7a87, -0x7ad8,0x7b10,0x7b04,0x7b13,0x7b05,0x7b0f,0x7b08,0x7b0a, +0x7ad8,0x7b10, +/* 0xD340 */ +0x7b04,0x7b13,0x7b05,0x7b0f,0x7b08,0x7b0a, 0x7b0e,0x7b09,0x7b12,0x7c84,0x7c91,0x7c8a,0x7c8c,0x7c88, 0x7c8d,0x7c85,0x7d1e,0x7d1d,0x7d11,0x7d0e,0x7d18,0x7d16, 0x7d13,0x7d1f,0x7d12,0x7d0f,0x7d0c,0x7f5c,0x7f61,0x7f5e, @@ -1027,7 +1122,9 @@ static const unsigned short big5_ucs_table[] = { 0x8c7b,0x8ca4,0x8ca3,0x8d76,0x8d78,0x8db5,0x8db7,0x8db6, 0x8ed1,0x8ed3,0x8ffe,0x8ff5,0x9002,0x8fff,0x8ffb,0x9004, 0x8ffc,0x8ff6,0x90d6,0x90e0,0x90d9,0x90da,0x90e3,0x90df, -0x90e5,0x90d8,0x90db,0x90d7,0x90dc,0x90e4,0x9150,0x914e, +0x90e5,0x90d8,0x90db,0x90d7,0x90dc,0x90e4,0x9150, +/* 0xD440 */ +0x914e, 0x914f,0x91d5,0x91e2,0x91da,0x965c,0x965f,0x96bc,0x98e3, 0x9adf,0x9b2f,0x4e7f,0x5070,0x506a,0x5061,0x505e,0x5060, 0x5053,0x504b,0x505d,0x5072,0x5048,0x504d,0x5041,0x505b, @@ -1047,7 +1144,9 @@ static const unsigned short big5_ucs_table[] = { 0x5a8e,0x5a3e,0x5a4d,0x5a39,0x5a4c,0x5a70,0x5a69,0x5a47, 0x5a51,0x5a56,0x5a42,0x5a5c,0x5b72,0x5b6e,0x5bc1,0x5bc0, 0x5c59,0x5d1e,0x5d0b,0x5d1d,0x5d1a,0x5d20,0x5d0c,0x5d28, -0x5d0d,0x5d26,0x5d25,0x5d0f,0x5d30,0x5d12,0x5d23,0x5d1f, +0x5d0d,0x5d26,0x5d25,0x5d0f, +/* 0xD540 */ +0x5d30,0x5d12,0x5d23,0x5d1f, 0x5d2e,0x5e3e,0x5e34,0x5eb1,0x5eb4,0x5eb9,0x5eb2,0x5eb3, 0x5f36,0x5f38,0x5f9b,0x5f96,0x5f9f,0x608a,0x6090,0x6086, 0x60be,0x60b0,0x60ba,0x60d3,0x60d4,0x60cf,0x60e4,0x60d9, @@ -1067,7 +1166,9 @@ static const unsigned short big5_ucs_table[] = { 0x6de9,0x6de2,0x6db7,0x6df6,0x6dd4,0x6e00,0x6dc8,0x6de0, 0x6ddf,0x6dd6,0x6dbe,0x6de5,0x6ddc,0x6ddd,0x6ddb,0x6df4, 0x6dca,0x6dbd,0x6ded,0x6df0,0x6dba,0x6dd5,0x6dc2,0x6dcf, -0x6dc9,0x6dd0,0x6df2,0x6dd3,0x6dfd,0x6dd7,0x6dcd,0x6de3, +0x6dc9, +/* 0xD640 */ +0x6dd0,0x6df2,0x6dd3,0x6dfd,0x6dd7,0x6dcd,0x6de3, 0x6dbb,0x70fa,0x710d,0x70f7,0x7117,0x70f4,0x710c,0x70f0, 0x7104,0x70f3,0x7110,0x70fc,0x70ff,0x7106,0x7113,0x7100, 0x70f8,0x70f6,0x710b,0x7102,0x710e,0x727e,0x727b,0x727c, @@ -1086,7 +1187,9 @@ static const unsigned short big5_ucs_table[] = { 0x7ca3,0x7d35,0x7d3d,0x7d38,0x7d36,0x7d3a,0x7d45,0x7d2c, 0x7d29,0x7d41,0x7d47,0x7d3e,0x7d3f,0x7d4a,0x7d3b,0x7d28, 0x7f63,0x7f95,0x7f9c,0x7f9d,0x7f9b,0x7fca,0x7fcb,0x7fcd, -0x7fd0,0x7fd1,0x7fc7,0x7fcf,0x7fc9,0x801f,0x801e,0x801b, +0x7fd0,0x7fd1,0x7fc7,0x7fcf,0x7fc9,0x801f, +/* 0xD740 */ +0x801e,0x801b, 0x8047,0x8043,0x8048,0x8118,0x8125,0x8119,0x811b,0x812d, 0x811f,0x812c,0x811e,0x8121,0x8115,0x8127,0x811d,0x8122, 0x8211,0x8238,0x8233,0x823a,0x8234,0x8232,0x8274,0x8390, @@ -1106,7 +1209,9 @@ static const unsigned short big5_ucs_table[] = { 0x9011,0x901c,0x900c,0x9021,0x90ef,0x90ea,0x90f0,0x90f4, 0x90f2,0x90f3,0x90d4,0x90eb,0x90ec,0x90e9,0x9156,0x9158, 0x915a,0x9153,0x9155,0x91ec,0x91f4,0x91f1,0x91f3,0x91f8, -0x91e4,0x91f9,0x91ea,0x91eb,0x91f7,0x91e8,0x91ee,0x957a, +0x91e4,0x91f9,0x91ea, +/* 0xD840 */ +0x91eb,0x91f7,0x91e8,0x91ee,0x957a, 0x9586,0x9588,0x967c,0x966d,0x966b,0x9671,0x966f,0x96bf, 0x976a,0x9804,0x98e5,0x9997,0x509b,0x5095,0x5094,0x509e, 0x508b,0x50a3,0x5083,0x508c,0x508e,0x509d,0x5068,0x509c, @@ -1126,6 +1231,7 @@ static const unsigned short big5_ucs_table[] = { 0x5d31,0x5d59,0x5d42,0x5d39,0x5d49,0x5d38,0x5d3c,0x5d32, 0x5d36,0x5d40,0x5d45,0x5e44,0x5e41,0x5f58,0x5fa6,0x5fa5, 0x5fab,0x60c9,0x60b9,0x60cc,0x60e2,0x60ce,0x60c4,0x6114, +/* 0xD940 */ 0x60f2,0x610a,0x6116,0x6105,0x60f5,0x6113,0x60f8,0x60fc, 0x60fe,0x60c1,0x6103,0x6118,0x611d,0x6110,0x60ff,0x6104, 0x610b,0x624a,0x6394,0x63b1,0x63b0,0x63ce,0x63e5,0x63e8, @@ -1145,7 +1251,9 @@ static const unsigned short big5_ucs_table[] = { 0x6bbd,0x6bf0,0x6bf2,0x6bf3,0x6c30,0x6dfc,0x6e46,0x6e47, 0x6e1f,0x6e49,0x6e88,0x6e3c,0x6e3d,0x6e45,0x6e62,0x6e2b, 0x6e3f,0x6e41,0x6e5d,0x6e73,0x6e1c,0x6e33,0x6e4b,0x6e40, -0x6e51,0x6e3b,0x6e03,0x6e2e,0x6e5e,0x6e68,0x6e5c,0x6e61, +0x6e51,0x6e3b,0x6e03,0x6e2e,0x6e5e, +/* 0xDA40 */ +0x6e68,0x6e5c,0x6e61, 0x6e31,0x6e28,0x6e60,0x6e71,0x6e6b,0x6e39,0x6e22,0x6e30, 0x6e53,0x6e65,0x6e27,0x6e78,0x6e64,0x6e77,0x6e55,0x6e79, 0x6e52,0x6e66,0x6e35,0x6e36,0x6e5a,0x7120,0x711e,0x712f, @@ -1165,7 +1273,9 @@ static const unsigned short big5_ucs_table[] = { 0x7b58,0x7b45,0x7ca2,0x7c9e,0x7ca8,0x7ca1,0x7d58,0x7d6f, 0x7d63,0x7d53,0x7d56,0x7d67,0x7d6a,0x7d4f,0x7d6d,0x7d5c, 0x7d6b,0x7d52,0x7d54,0x7d69,0x7d51,0x7d5f,0x7d4e,0x7f3e, -0x7f3f,0x7f65,0x7f66,0x7fa2,0x7fa0,0x7fa1,0x7fd7,0x8051, +0x7f3f,0x7f65, +/* 0xDB40 */ +0x7f66,0x7fa2,0x7fa0,0x7fa1,0x7fd7,0x8051, 0x804f,0x8050,0x80fe,0x80d4,0x8143,0x814a,0x8152,0x814f, 0x8147,0x813d,0x814d,0x813a,0x81e6,0x81ee,0x81f7,0x81f8, 0x81f9,0x8204,0x823c,0x823d,0x823f,0x8275,0x833b,0x83cf, @@ -1184,7 +1294,9 @@ static const unsigned short big5_ucs_table[] = { 0x8a48,0x8a51,0x8a4a,0x8a4c,0x8a4f,0x8c5f,0x8c81,0x8c80, 0x8cba,0x8cbe,0x8cb0,0x8cb9,0x8cb5,0x8d84,0x8d80,0x8d89, 0x8dd8,0x8dd3,0x8dcd,0x8dc7,0x8dd6,0x8ddc,0x8dcf,0x8dd5, -0x8dd9,0x8dc8,0x8dd7,0x8dc5,0x8eef,0x8ef7,0x8efa,0x8ef9, +0x8dd9,0x8dc8,0x8dd7,0x8dc5,0x8eef,0x8ef7,0x8efa, +/* 0xDC40 */ +0x8ef9, 0x8ee6,0x8eee,0x8ee5,0x8ef5,0x8ee7,0x8ee8,0x8ef6,0x8eeb, 0x8ef1,0x8eec,0x8ef4,0x8ee9,0x902d,0x9034,0x902f,0x9106, 0x912c,0x9104,0x90ff,0x90fc,0x9108,0x90f9,0x90fb,0x9101, @@ -1204,7 +1316,9 @@ static const unsigned short big5_ucs_table[] = { 0x5868,0x5864,0x584f,0x584d,0x5849,0x586f,0x5855,0x584e, 0x585d,0x5859,0x5865,0x585b,0x583d,0x5863,0x5871,0x58fc, 0x5ac7,0x5ac4,0x5acb,0x5aba,0x5ab8,0x5ab1,0x5ab5,0x5ab0, -0x5abf,0x5ac8,0x5abb,0x5ac6,0x5ab7,0x5ac0,0x5aca,0x5ab4, +0x5abf,0x5ac8,0x5abb,0x5ac6, +/* 0xDD40 */ +0x5ab7,0x5ac0,0x5aca,0x5ab4, 0x5ab6,0x5acd,0x5ab9,0x5a90,0x5bd6,0x5bd8,0x5bd9,0x5c1f, 0x5c33,0x5d71,0x5d63,0x5d4a,0x5d65,0x5d72,0x5d6c,0x5d5e, 0x5d68,0x5d67,0x5d62,0x5df0,0x5e4f,0x5e4e,0x5e4a,0x5e4d, @@ -1224,7 +1338,9 @@ static const unsigned short big5_ucs_table[] = { 0x6958,0x6941,0x6974,0x694c,0x693b,0x694b,0x6937,0x695c, 0x694f,0x6951,0x6932,0x6952,0x692f,0x697b,0x693c,0x6b46, 0x6b45,0x6b43,0x6b42,0x6b48,0x6b41,0x6b9b,0xfa0d,0x6bfb, -0x6bfc,0x6bf9,0x6bf7,0x6bf8,0x6e9b,0x6ed6,0x6ec8,0x6e8f, +0x6bfc, +/* 0xDE40 */ +0x6bf9,0x6bf7,0x6bf8,0x6e9b,0x6ed6,0x6ec8,0x6e8f, 0x6ec0,0x6e9f,0x6e93,0x6e94,0x6ea0,0x6eb1,0x6eb9,0x6ec6, 0x6ed2,0x6ebd,0x6ec1,0x6e9e,0x6ec9,0x6eb7,0x6eb0,0x6ecd, 0x6ea6,0x6ecf,0x6eb2,0x6ebe,0x6ec3,0x6edc,0x6ed8,0x6e99, @@ -1243,7 +1359,9 @@ static const unsigned short big5_ucs_table[] = { 0x7759,0x776d,0x77e0,0x7887,0x789a,0x7894,0x788f,0x7884, 0x7895,0x7885,0x7886,0x78a1,0x7883,0x7879,0x7899,0x7880, 0x7896,0x787b,0x797c,0x7982,0x797d,0x7979,0x7a11,0x7a18, -0x7a19,0x7a12,0x7a17,0x7a15,0x7a22,0x7a13,0x7a1b,0x7a10, +0x7a19,0x7a12,0x7a17,0x7a15,0x7a22,0x7a13, +/* 0xDF40 */ +0x7a1b,0x7a10, 0x7aa3,0x7aa2,0x7a9e,0x7aeb,0x7b66,0x7b64,0x7b6d,0x7b74, 0x7b69,0x7b72,0x7b65,0x7b73,0x7b71,0x7b70,0x7b61,0x7b78, 0x7b76,0x7b63,0x7cb2,0x7cb4,0x7caf,0x7d88,0x7d86,0x7d80, @@ -1263,7 +1381,9 @@ static const unsigned short big5_ucs_table[] = { 0x86f7,0x870c,0x86fa,0x86d6,0x86f5,0x874d,0x86f8,0x870e, 0x8709,0x8701,0x86f6,0x870d,0x8705,0x88d6,0x88cb,0x88cd, 0x88ce,0x88de,0x88db,0x88da,0x88cc,0x88d0,0x8985,0x899b, -0x89df,0x89e5,0x89e4,0x89e1,0x89e0,0x89e2,0x89dc,0x89e6, +0x89df,0x89e5,0x89e4, +/* 0xE040 */ +0x89e1,0x89e0,0x89e2,0x89dc,0x89e6, 0x8a76,0x8a86,0x8a7f,0x8a61,0x8a3f,0x8a77,0x8a82,0x8a84, 0x8a75,0x8a83,0x8a81,0x8a74,0x8a7a,0x8c3c,0x8c4b,0x8c4a, 0x8c65,0x8c64,0x8c66,0x8c86,0x8c84,0x8c85,0x8ccc,0x8d68, @@ -1283,6 +1403,7 @@ static const unsigned short big5_ucs_table[] = { 0x99b5,0x9aad,0x9aab,0x9b5b,0x9cea,0x9ced,0x9ce7,0x9e80, 0x9efd,0x50e6,0x50d4,0x50d7,0x50e8,0x50f3,0x50db,0x50ea, 0x50dd,0x50e4,0x50d3,0x50ec,0x50f0,0x50ef,0x50e3,0x50e0, +/* 0xE140 */ 0x51d8,0x5280,0x5281,0x52e9,0x52eb,0x5330,0x53ac,0x5627, 0x5615,0x560c,0x5612,0x55fc,0x560f,0x561c,0x5601,0x5613, 0x5602,0x55fa,0x561d,0x5604,0x55ff,0x55f9,0x5889,0x587c, @@ -1302,7 +1423,9 @@ static const unsigned short big5_ucs_table[] = { 0x6475,0x6466,0x64a6,0x644e,0x6482,0x645e,0x645c,0x644b, 0x6453,0x6460,0x6450,0x647f,0x643f,0x646c,0x646b,0x6459, 0x6465,0x6477,0x6573,0x65a0,0x66a1,0x66a0,0x669f,0x6705, -0x6704,0x6722,0x69b1,0x69b6,0x69c9,0x69a0,0x69ce,0x6996, +0x6704,0x6722,0x69b1,0x69b6,0x69c9, +/* 0xE240 */ +0x69a0,0x69ce,0x6996, 0x69b0,0x69ac,0x69bc,0x6991,0x6999,0x698e,0x69a7,0x698d, 0x69a9,0x69be,0x69af,0x69bf,0x69c4,0x69bd,0x69a4,0x69d4, 0x69b9,0x69ca,0x699a,0x69cf,0x69b3,0x6993,0x69aa,0x69a1, @@ -1322,7 +1445,9 @@ static const unsigned short big5_ucs_table[] = { 0x7782,0x776e,0x7780,0x776f,0x777e,0x7783,0x78b2,0x78aa, 0x78b4,0x78ad,0x78a8,0x787e,0x78ab,0x789e,0x78a5,0x78a0, 0x78ac,0x78a2,0x78a4,0x7998,0x798a,0x798b,0x7996,0x7995, -0x7994,0x7993,0x7997,0x7988,0x7992,0x7990,0x7a2b,0x7a4a, +0x7994,0x7993, +/* 0xE340 */ +0x7997,0x7988,0x7992,0x7990,0x7a2b,0x7a4a, 0x7a30,0x7a2f,0x7a28,0x7a26,0x7aa8,0x7aab,0x7aac,0x7aee, 0x7b88,0x7b9c,0x7b8a,0x7b91,0x7b90,0x7b96,0x7b8d,0x7b8c, 0x7b9b,0x7b8e,0x7b85,0x7b98,0x5284,0x7b99,0x7ba4,0x7b82, @@ -1341,7 +1466,9 @@ static const unsigned short big5_ucs_table[] = { 0x872c,0x8741,0x873e,0x8746,0x8720,0x8732,0x872a,0x872d, 0x873c,0x8712,0x873a,0x8731,0x8735,0x8742,0x8726,0x8727, 0x8738,0x8724,0x871a,0x8730,0x8711,0x88f7,0x88e7,0x88f1, -0x88f2,0x88fa,0x88fe,0x88ee,0x88fc,0x88f6,0x88fb,0x88f0, +0x88f2,0x88fa,0x88fe,0x88ee,0x88fc,0x88f6,0x88fb, +/* 0xE440 */ +0x88f0, 0x88ec,0x88eb,0x899d,0x89a1,0x899f,0x899e,0x89e9,0x89eb, 0x89e8,0x8aab,0x8a99,0x8a8b,0x8a92,0x8a8f,0x8a96,0x8c3d, 0x8c68,0x8c69,0x8cd5,0x8ccf,0x8cd7,0x8d96,0x8e09,0x8e02, @@ -1361,7 +1488,9 @@ static const unsigned short big5_ucs_table[] = { 0x9cf2,0x9cf5,0x9ea7,0x50ff,0x5103,0x5130,0x50f8,0x5106, 0x5107,0x50f6,0x50fe,0x510b,0x510c,0x50fd,0x510a,0x528b, 0x528c,0x52f1,0x52ef,0x5648,0x5642,0x564c,0x5635,0x5641, -0x564a,0x5649,0x5646,0x5658,0x565a,0x5640,0x5633,0x563d, +0x564a,0x5649,0x5646,0x5658, +/* 0xE540 */ +0x565a,0x5640,0x5633,0x563d, 0x562c,0x563e,0x5638,0x562a,0x563a,0x571a,0x58ab,0x589d, 0x58b1,0x58a0,0x58a3,0x58af,0x58ac,0x58a5,0x58a1,0x58ff, 0x5aff,0x5af4,0x5afd,0x5af7,0x5af6,0x5b03,0x5af8,0x5b02, @@ -1381,7 +1510,9 @@ static const unsigned short big5_ucs_table[] = { 0x6a09,0x6a04,0x6a18,0x6a25,0x6a0f,0x69f6,0x6a26,0x6a07, 0x69f4,0x6a16,0x6b51,0x6ba5,0x6ba3,0x6ba2,0x6ba6,0x6c01, 0x6c00,0x6bff,0x6c02,0x6f41,0x6f26,0x6f7e,0x6f87,0x6fc6, -0x6f92,0x6f8d,0x6f89,0x6f8c,0x6f62,0x6f4f,0x6f85,0x6f5a, +0x6f92, +/* 0xE640 */ +0x6f8d,0x6f89,0x6f8c,0x6f62,0x6f4f,0x6f85,0x6f5a, 0x6f96,0x6f76,0x6f6c,0x6f82,0x6f55,0x6f72,0x6f52,0x6f50, 0x6f57,0x6f94,0x6f93,0x6f5d,0x6f00,0x6f61,0x6f6b,0x6f7d, 0x6f67,0x6f90,0x6f53,0x6f8b,0x6f69,0x6f7f,0x6f95,0x6f63, @@ -1400,7 +1531,9 @@ static const unsigned short big5_ucs_table[] = { 0x7ccc,0x7ccb,0x7df7,0x7ddb,0x7dea,0x7de7,0x7dd7,0x7de1, 0x7e03,0x7dfa,0x7de6,0x7df6,0x7df1,0x7df0,0x7dee,0x7ddf, 0x7f76,0x7fac,0x7fb0,0x7fad,0x7fed,0x7feb,0x7fea,0x7fec, -0x7fe6,0x7fe8,0x8064,0x8067,0x81a3,0x819f,0x819e,0x8195, +0x7fe6,0x7fe8,0x8064,0x8067,0x81a3,0x819f, +/* 0xE740 */ +0x819e,0x8195, 0x81a2,0x8199,0x8197,0x8216,0x824f,0x8253,0x8252,0x8250, 0x824e,0x8251,0x8524,0x853b,0x850f,0x8500,0x8529,0x850e, 0x8509,0x850d,0x851f,0x850a,0x8527,0x851c,0x84fb,0x852b, @@ -1420,7 +1553,9 @@ static const unsigned short big5_ucs_table[] = { 0x8ad9,0x8c3e,0x8c4d,0x8c8f,0x8ce5,0x8cdf,0x8cd9,0x8ce8, 0x8cda,0x8cdd,0x8ce7,0x8da0,0x8d9c,0x8da1,0x8d9b,0x8e20, 0x8e23,0x8e25,0x8e24,0x8e2e,0x8e15,0x8e1b,0x8e16,0x8e11, -0x8e19,0x8e26,0x8e27,0x8e14,0x8e12,0x8e18,0x8e13,0x8e1c, +0x8e19,0x8e26,0x8e27, +/* 0xE840 */ +0x8e14,0x8e12,0x8e18,0x8e13,0x8e1c, 0x8e17,0x8e1a,0x8f2c,0x8f24,0x8f18,0x8f1a,0x8f20,0x8f23, 0x8f16,0x8f17,0x9073,0x9070,0x906f,0x9067,0x906b,0x912f, 0x912b,0x9129,0x912a,0x9132,0x9126,0x912e,0x9185,0x9186, @@ -1440,6 +1575,7 @@ static const unsigned short big5_ucs_table[] = { 0x9cff,0x9cf7,0x9d07,0x9d00,0x9cf9,0x9cfb,0x9d08,0x9d05, 0x9d04,0x9e83,0x9ed3,0x9f0f,0x9f10,0x511c,0x5113,0x5117, 0x511a,0x5111,0x51de,0x5334,0x53e1,0x5670,0x5660,0x566e, +/* 0xE940 */ 0x5673,0x5666,0x5663,0x566d,0x5672,0x565e,0x5677,0x571c, 0x571b,0x58c8,0x58bd,0x58c9,0x58bf,0x58ba,0x58c2,0x58bc, 0x58c6,0x5b17,0x5b19,0x5b1b,0x5b21,0x5b14,0x5b13,0x5b10, @@ -1459,7 +1595,9 @@ static const unsigned short big5_ucs_table[] = { 0x6baa,0x6bab,0x6bc8,0x6bc7,0x6c04,0x6c03,0x6c06,0x6fad, 0x6fcb,0x6fa3,0x6fc7,0x6fbc,0x6fce,0x6fc8,0x6f5e,0x6fc4, 0x6fbd,0x6f9e,0x6fca,0x6fa8,0x7004,0x6fa5,0x6fae,0x6fba, -0x6fac,0x6faa,0x6fcf,0x6fbf,0x6fb8,0x6fa2,0x6fc9,0x6fab, +0x6fac,0x6faa,0x6fcf,0x6fbf,0x6fb8, +/* 0xEA40 */ +0x6fa2,0x6fc9,0x6fab, 0x6fcd,0x6faf,0x6fb2,0x6fb0,0x71c5,0x71c2,0x71bf,0x71b8, 0x71d6,0x71c0,0x71c1,0x71cb,0x71d4,0x71ca,0x71c7,0x71cf, 0x71bd,0x71d8,0x71bc,0x71c6,0x71da,0x71db,0x729d,0x729e, @@ -1479,7 +1617,9 @@ static const unsigned short big5_ucs_table[] = { 0x802a,0x8029,0x806c,0x81b1,0x81a6,0x81ae,0x81b9,0x81b5, 0x81ab,0x81b0,0x81ac,0x81b4,0x81b2,0x81b7,0x81a7,0x81f2, 0x8255,0x8256,0x8257,0x8556,0x8545,0x856b,0x854d,0x8553, -0x8561,0x8558,0x8540,0x8546,0x8564,0x8541,0x8562,0x8544, +0x8561,0x8558, +/* 0xEB40 */ +0x8540,0x8546,0x8564,0x8541,0x8562,0x8544, 0x8551,0x8547,0x8563,0x853e,0x855b,0x8571,0x854e,0x856e, 0x8575,0x8555,0x8567,0x8560,0x858c,0x8566,0x855d,0x8554, 0x8565,0x856c,0x8663,0x8665,0x8664,0x879b,0x878f,0x8797, @@ -1498,7 +1638,9 @@ static const unsigned short big5_ucs_table[] = { 0x931f,0x9306,0x930f,0x937a,0x9338,0x933c,0x931b,0x9323, 0x9312,0x9301,0x9346,0x932d,0x930e,0x930d,0x92cb,0x931d, 0x92fa,0x9325,0x9313,0x92f9,0x92f7,0x9334,0x9302,0x9324, -0x92ff,0x9329,0x9339,0x9335,0x932a,0x9314,0x930c,0x930b, +0x92ff,0x9329,0x9339,0x9335,0x932a,0x9314,0x930c, +/* 0xEC40 */ +0x930b, 0x92fe,0x9309,0x9300,0x92fb,0x9316,0x95bc,0x95cd,0x95be, 0x95b9,0x95ba,0x95b6,0x95bf,0x95b5,0x95bd,0x96a9,0x96d4, 0x970b,0x9712,0x9710,0x9799,0x9797,0x9794,0x97f0,0x97f8, @@ -1518,7 +1660,9 @@ static const unsigned short big5_ucs_table[] = { 0x61e0,0x61e5,0x61e4,0x61e8,0x61de,0x64ef,0x64e9,0x64e3, 0x64eb,0x64e4,0x64e8,0x6581,0x6580,0x65b6,0x65da,0x66d2, 0x6a8d,0x6a96,0x6a81,0x6aa5,0x6a89,0x6a9f,0x6a9b,0x6aa1, -0x6a9e,0x6a87,0x6a93,0x6a8e,0x6a95,0x6a83,0x6aa8,0x6aa4, +0x6a9e,0x6a87,0x6a93,0x6a8e, +/* 0xED40 */ +0x6a95,0x6a83,0x6aa8,0x6aa4, 0x6a91,0x6a7f,0x6aa6,0x6a9a,0x6a85,0x6a8c,0x6a92,0x6b5b, 0x6bad,0x6c09,0x6fcc,0x6fa9,0x6ff4,0x6fd4,0x6fe3,0x6fdc, 0x6fed,0x6fe7,0x6fe6,0x6fde,0x6ff2,0x6fdd,0x6fe2,0x6fe8, @@ -1538,7 +1682,9 @@ static const unsigned short big5_ucs_table[] = { 0x7ff2,0x802c,0x81bb,0x81c4,0x81cc,0x81ca,0x81c5,0x81c7, 0x81bc,0x81e9,0x825b,0x825a,0x825c,0x8583,0x8580,0x858f, 0x85a7,0x8595,0x85a0,0x858b,0x85a3,0x857b,0x85a4,0x859a, -0x859e,0x8577,0x857c,0x8589,0x85a1,0x857a,0x8578,0x8557, +0x859e, +/* 0xEE40 */ +0x8577,0x857c,0x8589,0x85a1,0x857a,0x8578,0x8557, 0x858e,0x8596,0x8586,0x858d,0x8599,0x859d,0x8581,0x85a2, 0x8582,0x8588,0x8585,0x8579,0x8576,0x8598,0x8590,0x859f, 0x8668,0x87be,0x87aa,0x87ad,0x87c5,0x87b0,0x87ac,0x87b9, @@ -1557,7 +1703,9 @@ static const unsigned short big5_ucs_table[] = { 0x9355,0x9352,0x934f,0x9371,0x9377,0x937b,0x9361,0x935e, 0x9363,0x9367,0x9380,0x934e,0x9359,0x95c7,0x95c0,0x95c9, 0x95c3,0x95c5,0x95b7,0x96ae,0x96b0,0x96ac,0x9720,0x971f, -0x9718,0x971d,0x9719,0x979a,0x97a1,0x979c,0x979e,0x979d, +0x9718,0x971d,0x9719,0x979a,0x97a1,0x979c, +/* 0xEF40 */ +0x979e,0x979d, 0x97d5,0x97d4,0x97f1,0x9841,0x9844,0x984a,0x9849,0x9845, 0x9843,0x9925,0x992b,0x992c,0x992a,0x9933,0x9932,0x992f, 0x992d,0x9931,0x9930,0x9998,0x99a3,0x99a1,0x9a02,0x99fa, @@ -1577,7 +1725,9 @@ static const unsigned short big5_ucs_table[] = { 0x6ab7,0x6ac7,0x6ab4,0x6aad,0x6b5e,0x6bc9,0x6c0b,0x7007, 0x700c,0x700d,0x7001,0x7005,0x7014,0x700e,0x6fff,0x7000, 0x6ffb,0x7026,0x6ffc,0x6ff7,0x700a,0x7201,0x71ff,0x71f9, -0x7203,0x71fd,0x7376,0x74b8,0x74c0,0x74b5,0x74c1,0x74be, +0x7203,0x71fd,0x7376, +/* 0xF040 */ +0x74b8,0x74c0,0x74b5,0x74c1,0x74be, 0x74b6,0x74bb,0x74c2,0x7514,0x7513,0x765c,0x7664,0x7659, 0x7650,0x7653,0x7657,0x765a,0x76a6,0x76bd,0x76ec,0x77c2, 0x77ba,0x78ff,0x790c,0x7913,0x7914,0x7909,0x7910,0x7912, @@ -1597,6 +1747,7 @@ static const unsigned short big5_ucs_table[] = { 0x8b26,0x8b36,0x8b2e,0x8b24,0x8b3b,0x8b3d,0x8b3a,0x8c42, 0x8c75,0x8c99,0x8c98,0x8c97,0x8cfe,0x8d04,0x8d02,0x8d00, 0x8e5c,0x8e62,0x8e60,0x8e57,0x8e56,0x8e5e,0x8e65,0x8e67, +/* 0xF140 */ 0x8e5b,0x8e5a,0x8e61,0x8e5d,0x8e69,0x8e54,0x8f46,0x8f47, 0x8f48,0x8f4b,0x9128,0x913a,0x913b,0x913e,0x91a8,0x91a5, 0x91a7,0x91af,0x91aa,0x93b5,0x938c,0x9392,0x93b7,0x939b, @@ -1616,7 +1767,9 @@ static const unsigned short big5_ucs_table[] = { 0x9f00,0x9f16,0x9f25,0x9f2b,0x9f2a,0x9f29,0x9f28,0x9f4c, 0x9f55,0x5134,0x5135,0x5296,0x52f7,0x53b4,0x56ab,0x56ad, 0x56a6,0x56a7,0x56aa,0x56ac,0x58da,0x58dd,0x58db,0x5912, -0x5b3d,0x5b3e,0x5b3f,0x5dc3,0x5e70,0x5fbf,0x61fb,0x6507, +0x5b3d,0x5b3e,0x5b3f,0x5dc3,0x5e70, +/* 0xF240 */ +0x5fbf,0x61fb,0x6507, 0x6510,0x650d,0x6509,0x650c,0x650e,0x6584,0x65de,0x65dd, 0x66de,0x6ae7,0x6ae0,0x6acc,0x6ad1,0x6ad9,0x6acb,0x6adf, 0x6adc,0x6ad0,0x6aeb,0x6acf,0x6acd,0x6ade,0x6b60,0x6bb0, @@ -1636,7 +1789,9 @@ static const unsigned short big5_ucs_table[] = { 0x8808,0x87ff,0x880a,0x8802,0x8962,0x895a,0x895b,0x8957, 0x8961,0x895c,0x8958,0x895d,0x8959,0x8988,0x89b7,0x89b6, 0x89f6,0x8b50,0x8b48,0x8b4a,0x8b40,0x8b53,0x8b56,0x8b54, -0x8b4b,0x8b55,0x8b51,0x8b42,0x8b52,0x8b57,0x8c43,0x8c77, +0x8b4b,0x8b55, +/* 0xF340 */ +0x8b51,0x8b42,0x8b52,0x8b57,0x8c43,0x8c77, 0x8c76,0x8c9a,0x8d06,0x8d07,0x8d09,0x8dac,0x8daa,0x8dad, 0x8dab,0x8e6d,0x8e78,0x8e73,0x8e6a,0x8e6f,0x8e7b,0x8ec2, 0x8f52,0x8f51,0x8f4f,0x8f50,0x8f53,0x8fb4,0x9140,0x913f, @@ -1655,7 +1810,9 @@ static const unsigned short big5_ucs_table[] = { 0x9d86,0x9d8b,0x9d8c,0x9d7d,0x9d6b,0x9d74,0x9d75,0x9d70, 0x9d69,0x9d85,0x9d73,0x9d7b,0x9d82,0x9d6f,0x9d79,0x9d7f, 0x9d87,0x9d68,0x9e94,0x9e91,0x9ec0,0x9efc,0x9f2d,0x9f40, -0x9f41,0x9f4d,0x9f56,0x9f57,0x9f58,0x5337,0x56b2,0x56b5, +0x9f41,0x9f4d,0x9f56,0x9f57,0x9f58,0x5337,0x56b2, +/* 0xF440 */ +0x56b5, 0x56b3,0x58e3,0x5b45,0x5dc6,0x5dc7,0x5eee,0x5eef,0x5fc0, 0x5fc1,0x61f9,0x6517,0x6516,0x6515,0x6513,0x65df,0x66e8, 0x66e3,0x66e4,0x6af3,0x6af0,0x6aea,0x6ae8,0x6af9,0x6af1, @@ -1675,7 +1832,9 @@ static const unsigned short big5_ucs_table[] = { 0x91b7,0x91b5,0x91b2,0x91b3,0x940b,0x9413,0x93fb,0x9420, 0x940f,0x9414,0x93fe,0x9415,0x9410,0x9428,0x9419,0x940d, 0x93f5,0x9400,0x93f7,0x9407,0x940e,0x9416,0x9412,0x93fa, -0x9409,0x93f8,0x940a,0x93ff,0x93fc,0x940c,0x93f6,0x9411, +0x9409,0x93f8,0x940a,0x93ff, +/* 0xF540 */ +0x93fc,0x940c,0x93f6,0x9411, 0x9406,0x95de,0x95e0,0x95df,0x972e,0x972f,0x97b9,0x97bb, 0x97fd,0x97fe,0x9860,0x9862,0x9863,0x985f,0x98c1,0x98c2, 0x9950,0x994e,0x9959,0x994c,0x994b,0x9953,0x9a32,0x9a34, @@ -1695,7 +1854,9 @@ static const unsigned short big5_ucs_table[] = { 0x7cf2,0x7e8a,0x7e87,0x7e88,0x7e8b,0x7e86,0x7e8d,0x7f4d, 0x7fbb,0x8030,0x81dd,0x8618,0x862a,0x8626,0x861f,0x8623, 0x861c,0x8619,0x8627,0x862e,0x8621,0x8620,0x8629,0x861e, -0x8625,0x8829,0x881d,0x881b,0x8820,0x8824,0x881c,0x882b, +0x8625, +/* 0xF640 */ +0x8829,0x881d,0x881b,0x8820,0x8824,0x881c,0x882b, 0x884a,0x896d,0x8969,0x896e,0x896b,0x89fa,0x8b79,0x8b78, 0x8b45,0x8b7a,0x8b7b,0x8d10,0x8d14,0x8daf,0x8e8e,0x8e8c, 0x8f5e,0x8f5b,0x8f5d,0x9146,0x9144,0x9145,0x91b9,0x943f, @@ -1714,7 +1875,9 @@ static const unsigned short big5_ucs_table[] = { 0x6520,0x6526,0x6522,0x6b0b,0x6b08,0x6b09,0x6c0d,0x7055, 0x7056,0x7057,0x7052,0x721e,0x721f,0x72a9,0x737f,0x74d8, 0x74d5,0x74d9,0x74d7,0x766d,0x76ad,0x7935,0x79b4,0x7a70, -0x7a71,0x7c57,0x7c5c,0x7c59,0x7c5b,0x7c5a,0x7cf4,0x7cf1, +0x7a71,0x7c57,0x7c5c,0x7c59,0x7c5b,0x7c5a, +/* 0xF740 */ +0x7cf4,0x7cf1, 0x7e91,0x7f4f,0x7f87,0x81de,0x826b,0x8634,0x8635,0x8633, 0x862c,0x8632,0x8636,0x882c,0x8828,0x8826,0x882a,0x8825, 0x8971,0x89bf,0x89be,0x89fb,0x8b7e,0x8b84,0x8b82,0x8b86, @@ -1734,7 +1897,9 @@ static const unsigned short big5_ucs_table[] = { 0x705b,0x705a,0x7222,0x7382,0x7381,0x7383,0x7670,0x77d4, 0x7c67,0x7c66,0x7e95,0x826c,0x863a,0x8640,0x8639,0x863c, 0x8631,0x863b,0x863e,0x8830,0x8832,0x882e,0x8833,0x8976, -0x8974,0x8973,0x89fe,0x8b8c,0x8b8e,0x8b8b,0x8b88,0x8c45, +0x8974,0x8973,0x89fe, +/* 0xF840 */ +0x8b8c,0x8b8e,0x8b8b,0x8b88,0x8c45, 0x8d19,0x8e98,0x8f64,0x8f63,0x91bc,0x9462,0x9455,0x945d, 0x9457,0x945e,0x97c4,0x97c5,0x9800,0x9a56,0x9a59,0x9b1e, 0x9b1f,0x9b20,0x9c52,0x9c58,0x9c50,0x9c4a,0x9c4d,0x9c4b, @@ -1754,6 +1919,7 @@ static const unsigned short big5_ucs_table[] = { 0x9e04,0x9ea0,0x9f1e,0x9f46,0x9f74,0x9f75,0x9f76,0x56d4, 0x652e,0x65b8,0x6b18,0x6b19,0x6b17,0x6b1a,0x7062,0x7226, 0x72aa,0x77d8,0x77d9,0x7939,0x7c69,0x7c6b,0x7cf6,0x7e9a, +/* 0xF940 */ 0x7e98,0x7e9b,0x7e99,0x81e0,0x81e1,0x8646,0x8647,0x8648, 0x8979,0x897a,0x897c,0x897b,0x89ff,0x8b98,0x8b99,0x8ea5, 0x8ea4,0x8ea3,0x946e,0x946d,0x946f,0x9471,0x9473,0x9749, diff --git a/ext/mbstring/libmbfl/filters/unicode_table_cp936.h b/ext/mbstring/libmbfl/filters/unicode_table_cp936.h index 754a6ec89c1c1..c225c586ffb35 100644 --- a/ext/mbstring/libmbfl/filters/unicode_table_cp936.h +++ b/ext/mbstring/libmbfl/filters/unicode_table_cp936.h @@ -30,8 +30,9 @@ */ #ifdef UNICODE_TABLE_CP936_DEF +/* CP936 -> Unicode, but without PUA codepoints used in CP936 and GB18030 */ const unsigned short cp936_ucs_table[] = { -/* 0x8100 */ +/* 0x8140 */ 0x4e02,0x4e04,0x4e05,0x4e06,0x4e0f,0x4e12,0x4e17,0x4e1f, 0x4e20,0x4e21,0x4e23,0x4e26,0x4e29,0x4e2e,0x4e2f,0x4e31, 0x4e33,0x4e35,0x4e37,0x4e3c,0x4e40,0x4e41,0x4e42,0x4e44, @@ -56,7 +57,7 @@ const unsigned short cp936_ucs_table[] = { 0x4f7d,0x4f80,0x4f81,0x4f82,0x4f85,0x4f86,0x4f87,0x4f8a, 0x4f8c,0x4f8e,0x4f90,0x4f92,0x4f93,0x4f95,0x4f96,0x4f98, 0x4f99,0x4f9a,0x4f9c,0x4f9e,0x4f9f,0x4fa1,0x4fa2,0x0000, -/* 0x8200 */ +/* 0x8240 */ 0x4fa4,0x4fab,0x4fad,0x4fb0,0x4fb1,0x4fb2,0x4fb3,0x4fb4, 0x4fb6,0x4fb7,0x4fb8,0x4fb9,0x4fba,0x4fbb,0x4fbc,0x4fbd, 0x4fbe,0x4fc0,0x4fc1,0x4fc2,0x4fc6,0x4fc7,0x4fc8,0x4fc9, @@ -81,7 +82,7 @@ const unsigned short cp936_ucs_table[] = { 0x509d,0x509e,0x509f,0x50a0,0x50a1,0x50a2,0x50a4,0x50a6, 0x50aa,0x50ab,0x50ad,0x50ae,0x50af,0x50b0,0x50b1,0x50b3, 0x50b4,0x50b5,0x50b6,0x50b7,0x50b8,0x50b9,0x50bc,0x0000, -/* 0x8300 */ +/* 0x8340 */ 0x50bd,0x50be,0x50bf,0x50c0,0x50c1,0x50c2,0x50c3,0x50c4, 0x50c5,0x50c6,0x50c7,0x50c8,0x50c9,0x50ca,0x50cb,0x50cc, 0x50cd,0x50ce,0x50d0,0x50d1,0x50d2,0x50d3,0x50d4,0x50d5, @@ -106,7 +107,7 @@ const unsigned short cp936_ucs_table[] = { 0x51ad,0x51ae,0x51b4,0x51b8,0x51b9,0x51ba,0x51be,0x51bf, 0x51c1,0x51c2,0x51c3,0x51c5,0x51c8,0x51ca,0x51cd,0x51ce, 0x51d0,0x51d2,0x51d3,0x51d4,0x51d5,0x51d6,0x51d7,0x0000, -/* 0x8400 */ +/* 0x8440 */ 0x51d8,0x51d9,0x51da,0x51dc,0x51de,0x51df,0x51e2,0x51e3, 0x51e5,0x51e6,0x51e7,0x51e8,0x51e9,0x51ea,0x51ec,0x51ee, 0x51f1,0x51f2,0x51f4,0x51f7,0x51fe,0x5204,0x5205,0x5209, @@ -131,7 +132,7 @@ const unsigned short cp936_ucs_table[] = { 0x52ee,0x52ef,0x52f1,0x52f2,0x52f3,0x52f4,0x52f5,0x52f6, 0x52f7,0x52f8,0x52fb,0x52fc,0x52fd,0x5301,0x5302,0x5303, 0x5304,0x5307,0x5309,0x530a,0x530b,0x530c,0x530e,0x0000, -/* 0x8500 */ +/* 0x8540 */ 0x5311,0x5312,0x5313,0x5314,0x5318,0x531b,0x531c,0x531e, 0x531f,0x5322,0x5324,0x5325,0x5327,0x5328,0x5329,0x532b, 0x532c,0x532d,0x532f,0x5330,0x5331,0x5332,0x5333,0x5334, @@ -156,7 +157,7 @@ const unsigned short cp936_ucs_table[] = { 0x5470,0x5474,0x5479,0x547a,0x547e,0x547f,0x5481,0x5483, 0x5485,0x5487,0x5488,0x5489,0x548a,0x548d,0x5491,0x5493, 0x5497,0x5498,0x549c,0x549e,0x549f,0x54a0,0x54a1,0x0000, -/* 0x8600 */ +/* 0x8640 */ 0x54a2,0x54a5,0x54ae,0x54b0,0x54b2,0x54b5,0x54b6,0x54b7, 0x54b9,0x54ba,0x54bc,0x54be,0x54c3,0x54c5,0x54ca,0x54cb, 0x54d6,0x54d8,0x54db,0x54e0,0x54e1,0x54e2,0x54e3,0x54e4, @@ -181,7 +182,7 @@ const unsigned short cp936_ucs_table[] = { 0x55da,0x55db,0x55de,0x55e0,0x55e2,0x55e7,0x55e9,0x55ed, 0x55ee,0x55f0,0x55f1,0x55f4,0x55f6,0x55f8,0x55f9,0x55fa, 0x55fb,0x55fc,0x55ff,0x5602,0x5603,0x5604,0x5605,0x0000, -/* 0x8700 */ +/* 0x8740 */ 0x5606,0x5607,0x560a,0x560b,0x560d,0x5610,0x5611,0x5612, 0x5613,0x5614,0x5615,0x5616,0x5617,0x5619,0x561a,0x561c, 0x561d,0x5620,0x5621,0x5622,0x5625,0x5626,0x5628,0x5629, @@ -206,7 +207,7 @@ const unsigned short cp936_ucs_table[] = { 0x56ea,0x56ec,0x56ee,0x56ef,0x56f2,0x56f3,0x56f6,0x56f7, 0x56f8,0x56fb,0x56fc,0x5700,0x5701,0x5702,0x5705,0x5707, 0x570b,0x570c,0x570d,0x570e,0x570f,0x5710,0x5711,0x0000, -/* 0x8800 */ +/* 0x8840 */ 0x5712,0x5713,0x5714,0x5715,0x5716,0x5717,0x5718,0x5719, 0x571a,0x571b,0x571d,0x571e,0x5720,0x5721,0x5722,0x5724, 0x5725,0x5726,0x5727,0x572b,0x5731,0x5732,0x5734,0x5735, @@ -231,7 +232,7 @@ const unsigned short cp936_ucs_table[] = { 0x5823,0x5825,0x5826,0x5827,0x5828,0x5829,0x582b,0x582c, 0x582d,0x582e,0x582f,0x5831,0x5832,0x5833,0x5834,0x5836, 0x5837,0x5838,0x5839,0x583a,0x583b,0x583c,0x583d,0x0000, -/* 0x8900 */ +/* 0x8940 */ 0x583e,0x583f,0x5840,0x5841,0x5842,0x5843,0x5845,0x5846, 0x5847,0x5848,0x5849,0x584a,0x584b,0x584e,0x584f,0x5850, 0x5852,0x5853,0x5855,0x5856,0x5857,0x5859,0x585a,0x585b, @@ -256,7 +257,7 @@ const unsigned short cp936_ucs_table[] = { 0x590e,0x5910,0x5911,0x5912,0x5913,0x5917,0x5918,0x591b, 0x591d,0x591e,0x5920,0x5921,0x5922,0x5923,0x5926,0x5928, 0x592c,0x5930,0x5932,0x5933,0x5935,0x5936,0x593b,0x0000, -/* 0x8a00 */ +/* 0x8A40 */ 0x593d,0x593e,0x593f,0x5940,0x5943,0x5945,0x5946,0x594a, 0x594c,0x594d,0x5950,0x5952,0x5953,0x5959,0x595b,0x595c, 0x595d,0x595e,0x595f,0x5961,0x5963,0x5964,0x5966,0x5967, @@ -281,7 +282,7 @@ const unsigned short cp936_ucs_table[] = { 0x5a45,0x5a47,0x5a48,0x5a4b,0x5a4c,0x5a4d,0x5a4e,0x5a4f, 0x5a50,0x5a51,0x5a52,0x5a53,0x5a54,0x5a56,0x5a57,0x5a58, 0x5a59,0x5a5b,0x5a5c,0x5a5d,0x5a5e,0x5a5f,0x5a60,0x0000, -/* 0x8b00 */ +/* 0x8B40 */ 0x5a61,0x5a63,0x5a64,0x5a65,0x5a66,0x5a68,0x5a69,0x5a6b, 0x5a6c,0x5a6d,0x5a6e,0x5a6f,0x5a70,0x5a71,0x5a72,0x5a73, 0x5a78,0x5a79,0x5a7b,0x5a7c,0x5a7d,0x5a7e,0x5a80,0x5a81, @@ -306,7 +307,7 @@ const unsigned short cp936_ucs_table[] = { 0x5b2d,0x5b2e,0x5b2f,0x5b30,0x5b31,0x5b33,0x5b35,0x5b36, 0x5b38,0x5b39,0x5b3a,0x5b3b,0x5b3c,0x5b3d,0x5b3e,0x5b3f, 0x5b41,0x5b42,0x5b43,0x5b44,0x5b45,0x5b46,0x5b47,0x0000, -/* 0x8c00 */ +/* 0x8C40 */ 0x5b48,0x5b49,0x5b4a,0x5b4b,0x5b4c,0x5b4d,0x5b4e,0x5b4f, 0x5b52,0x5b56,0x5b5e,0x5b60,0x5b61,0x5b67,0x5b68,0x5b6b, 0x5b6d,0x5b6e,0x5b6f,0x5b72,0x5b74,0x5b76,0x5b77,0x5b78, @@ -331,7 +332,7 @@ const unsigned short cp936_ucs_table[] = { 0x5c83,0x5c84,0x5c85,0x5c86,0x5c87,0x5c89,0x5c8a,0x5c8b, 0x5c8e,0x5c8f,0x5c92,0x5c93,0x5c95,0x5c9d,0x5c9e,0x5c9f, 0x5ca0,0x5ca1,0x5ca4,0x5ca5,0x5ca6,0x5ca7,0x5ca8,0x0000, -/* 0x8d00 */ +/* 0x8D40 */ 0x5caa,0x5cae,0x5caf,0x5cb0,0x5cb2,0x5cb4,0x5cb6,0x5cb9, 0x5cba,0x5cbb,0x5cbc,0x5cbe,0x5cc0,0x5cc2,0x5cc3,0x5cc5, 0x5cc6,0x5cc7,0x5cc8,0x5cc9,0x5cca,0x5ccc,0x5ccd,0x5cce, @@ -356,7 +357,7 @@ const unsigned short cp936_ucs_table[] = { 0x5d88,0x5d89,0x5d8a,0x5d8b,0x5d8c,0x5d8d,0x5d8e,0x5d8f, 0x5d90,0x5d91,0x5d92,0x5d93,0x5d94,0x5d95,0x5d96,0x5d97, 0x5d98,0x5d9a,0x5d9b,0x5d9c,0x5d9e,0x5d9f,0x5da0,0x0000, -/* 0x8e00 */ +/* 0x8E40 */ 0x5da1,0x5da2,0x5da3,0x5da4,0x5da5,0x5da6,0x5da7,0x5da8, 0x5da9,0x5daa,0x5dab,0x5dac,0x5dad,0x5dae,0x5daf,0x5db0, 0x5db1,0x5db2,0x5db3,0x5db4,0x5db5,0x5db6,0x5db8,0x5db9, @@ -381,7 +382,7 @@ const unsigned short cp936_ucs_table[] = { 0x5ea4,0x5ea8,0x5ea9,0x5eaa,0x5eab,0x5eac,0x5eae,0x5eaf, 0x5eb0,0x5eb1,0x5eb2,0x5eb4,0x5eba,0x5ebb,0x5ebc,0x5ebd, 0x5ebf,0x5ec0,0x5ec1,0x5ec2,0x5ec3,0x5ec4,0x5ec5,0x0000, -/* 0x8f00 */ +/* 0x8F40 */ 0x5ec6,0x5ec7,0x5ec8,0x5ecb,0x5ecc,0x5ecd,0x5ece,0x5ecf, 0x5ed0,0x5ed4,0x5ed5,0x5ed7,0x5ed8,0x5ed9,0x5eda,0x5edc, 0x5edd,0x5ede,0x5edf,0x5ee0,0x5ee1,0x5ee2,0x5ee3,0x5ee4, @@ -406,7 +407,7 @@ const unsigned short cp936_ucs_table[] = { 0x5fda,0x5fdb,0x5fdc,0x5fde,0x5fdf,0x5fe2,0x5fe3,0x5fe5, 0x5fe6,0x5fe8,0x5fe9,0x5fec,0x5fef,0x5ff0,0x5ff2,0x5ff3, 0x5ff4,0x5ff6,0x5ff7,0x5ff9,0x5ffa,0x5ffc,0x6007,0x0000, -/* 0x9000 */ +/* 0x9040 */ 0x6008,0x6009,0x600b,0x600c,0x6010,0x6011,0x6013,0x6017, 0x6018,0x601a,0x601e,0x601f,0x6022,0x6023,0x6024,0x602c, 0x602d,0x602e,0x6030,0x6031,0x6032,0x6033,0x6034,0x6036, @@ -431,7 +432,7 @@ const unsigned short cp936_ucs_table[] = { 0x612f,0x6130,0x6131,0x6132,0x6133,0x6134,0x6135,0x6136, 0x6137,0x6138,0x6139,0x613a,0x613b,0x613c,0x613d,0x613e, 0x6140,0x6141,0x6142,0x6143,0x6144,0x6145,0x6146,0x0000, -/* 0x9100 */ +/* 0x9140 */ 0x6147,0x6149,0x614b,0x614d,0x614f,0x6150,0x6152,0x6153, 0x6154,0x6156,0x6157,0x6158,0x6159,0x615a,0x615b,0x615c, 0x615e,0x615f,0x6160,0x6161,0x6163,0x6164,0x6165,0x6166, @@ -456,7 +457,7 @@ const unsigned short cp936_ucs_table[] = { 0x6223,0x6226,0x6227,0x6228,0x6229,0x622b,0x622d,0x622f, 0x6230,0x6231,0x6232,0x6235,0x6236,0x6238,0x6239,0x623a, 0x623b,0x623c,0x6242,0x6244,0x6245,0x6246,0x624a,0x0000, -/* 0x9200 */ +/* 0x9240 */ 0x624f,0x6250,0x6255,0x6256,0x6257,0x6259,0x625a,0x625c, 0x625d,0x625e,0x625f,0x6260,0x6261,0x6262,0x6264,0x6265, 0x6268,0x6271,0x6272,0x6274,0x6275,0x6277,0x6278,0x627a, @@ -481,7 +482,7 @@ const unsigned short cp936_ucs_table[] = { 0x6395,0x6397,0x6399,0x639a,0x639b,0x639c,0x639d,0x639e, 0x639f,0x63a1,0x63a4,0x63a6,0x63ab,0x63af,0x63b1,0x63b2, 0x63b5,0x63b6,0x63b9,0x63bb,0x63bd,0x63bf,0x63c0,0x0000, -/* 0x9300 */ +/* 0x9340 */ 0x63c1,0x63c2,0x63c3,0x63c5,0x63c7,0x63c8,0x63ca,0x63cb, 0x63cc,0x63d1,0x63d3,0x63d4,0x63d5,0x63d7,0x63d8,0x63d9, 0x63da,0x63db,0x63dc,0x63dd,0x63df,0x63e2,0x63e4,0x63e5, @@ -506,7 +507,7 @@ const unsigned short cp936_ucs_table[] = { 0x64b9,0x64bb,0x64bd,0x64be,0x64bf,0x64c1,0x64c3,0x64c4, 0x64c6,0x64c7,0x64c8,0x64c9,0x64ca,0x64cb,0x64cc,0x64cf, 0x64d1,0x64d3,0x64d4,0x64d5,0x64d6,0x64d9,0x64da,0x0000, -/* 0x9400 */ +/* 0x9440 */ 0x64db,0x64dc,0x64dd,0x64df,0x64e0,0x64e1,0x64e3,0x64e5, 0x64e7,0x64e8,0x64e9,0x64ea,0x64eb,0x64ec,0x64ed,0x64ee, 0x64ef,0x64f0,0x64f1,0x64f2,0x64f3,0x64f4,0x64f5,0x64f6, @@ -531,7 +532,7 @@ const unsigned short cp936_ucs_table[] = { 0x65c7,0x65c8,0x65c9,0x65ca,0x65cd,0x65d0,0x65d1,0x65d3, 0x65d4,0x65d5,0x65d8,0x65d9,0x65da,0x65db,0x65dc,0x65dd, 0x65de,0x65df,0x65e1,0x65e3,0x65e4,0x65ea,0x65eb,0x0000, -/* 0x9500 */ +/* 0x9540 */ 0x65f2,0x65f3,0x65f4,0x65f5,0x65f8,0x65f9,0x65fb,0x65fc, 0x65fd,0x65fe,0x65ff,0x6601,0x6604,0x6605,0x6607,0x6608, 0x6609,0x660b,0x660d,0x6610,0x6611,0x6612,0x6616,0x6617, @@ -556,7 +557,7 @@ const unsigned short cp936_ucs_table[] = { 0x66e1,0x66e2,0x66e3,0x66e4,0x66e5,0x66e7,0x66e8,0x66ea, 0x66eb,0x66ec,0x66ed,0x66ee,0x66ef,0x66f1,0x66f5,0x66f6, 0x66f8,0x66fa,0x66fb,0x66fd,0x6701,0x6702,0x6703,0x0000, -/* 0x9600 */ +/* 0x9640 */ 0x6704,0x6705,0x6706,0x6707,0x670c,0x670e,0x670f,0x6711, 0x6712,0x6713,0x6716,0x6718,0x6719,0x671a,0x671c,0x671e, 0x6720,0x6721,0x6722,0x6723,0x6724,0x6725,0x6727,0x6729, @@ -581,7 +582,7 @@ const unsigned short cp936_ucs_table[] = { 0x682c,0x682d,0x682e,0x682f,0x6830,0x6831,0x6834,0x6835, 0x6836,0x683a,0x683b,0x683f,0x6847,0x684b,0x684d,0x684f, 0x6852,0x6856,0x6857,0x6858,0x6859,0x685a,0x685b,0x0000, -/* 0x9700 */ +/* 0x9740 */ 0x685c,0x685d,0x685e,0x685f,0x686a,0x686c,0x686d,0x686e, 0x686f,0x6870,0x6871,0x6872,0x6873,0x6875,0x6878,0x6879, 0x687a,0x687b,0x687c,0x687d,0x687e,0x687f,0x6880,0x6882, @@ -606,7 +607,7 @@ const unsigned short cp936_ucs_table[] = { 0x6944,0x6945,0x6946,0x6947,0x6948,0x6949,0x694a,0x694b, 0x694c,0x694d,0x694e,0x694f,0x6950,0x6951,0x6952,0x6953, 0x6955,0x6956,0x6958,0x6959,0x695b,0x695c,0x695f,0x0000, -/* 0x9800 */ +/* 0x9840 */ 0x6961,0x6962,0x6964,0x6965,0x6967,0x6968,0x6969,0x696a, 0x696c,0x696d,0x696f,0x6970,0x6972,0x6973,0x6974,0x6975, 0x6976,0x697a,0x697b,0x697d,0x697e,0x697f,0x6981,0x6983, @@ -631,7 +632,7 @@ const unsigned short cp936_ucs_table[] = { 0x6a3f,0x6a40,0x6a41,0x6a42,0x6a43,0x6a45,0x6a46,0x6a48, 0x6a49,0x6a4a,0x6a4b,0x6a4c,0x6a4d,0x6a4e,0x6a4f,0x6a51, 0x6a52,0x6a53,0x6a54,0x6a55,0x6a56,0x6a57,0x6a5a,0x0000, -/* 0x9900 */ +/* 0x9940 */ 0x6a5c,0x6a5d,0x6a5e,0x6a5f,0x6a60,0x6a62,0x6a63,0x6a64, 0x6a66,0x6a67,0x6a68,0x6a69,0x6a6a,0x6a6b,0x6a6c,0x6a6d, 0x6a6e,0x6a6f,0x6a70,0x6a72,0x6a73,0x6a74,0x6a75,0x6a76, @@ -656,7 +657,7 @@ const unsigned short cp936_ucs_table[] = { 0x6b12,0x6b13,0x6b14,0x6b15,0x6b16,0x6b17,0x6b18,0x6b19, 0x6b1a,0x6b1b,0x6b1c,0x6b1d,0x6b1e,0x6b1f,0x6b25,0x6b26, 0x6b28,0x6b29,0x6b2a,0x6b2b,0x6b2c,0x6b2d,0x6b2e,0x0000, -/* 0x9a00 */ +/* 0x9A40 */ 0x6b2f,0x6b30,0x6b31,0x6b33,0x6b34,0x6b35,0x6b36,0x6b38, 0x6b3b,0x6b3c,0x6b3d,0x6b3f,0x6b40,0x6b41,0x6b42,0x6b44, 0x6b45,0x6b48,0x6b4a,0x6b4b,0x6b4d,0x6b4e,0x6b4f,0x6b50, @@ -681,7 +682,7 @@ const unsigned short cp936_ucs_table[] = { 0x6c33,0x6c36,0x6c37,0x6c39,0x6c3a,0x6c3b,0x6c3c,0x6c3e, 0x6c3f,0x6c43,0x6c44,0x6c45,0x6c48,0x6c4b,0x6c4c,0x6c4d, 0x6c4e,0x6c4f,0x6c51,0x6c52,0x6c53,0x6c56,0x6c58,0x0000, -/* 0x9b00 */ +/* 0x9B40 */ 0x6c59,0x6c5a,0x6c62,0x6c63,0x6c65,0x6c66,0x6c67,0x6c6b, 0x6c6c,0x6c6d,0x6c6e,0x6c6f,0x6c71,0x6c73,0x6c75,0x6c77, 0x6c78,0x6c7a,0x6c7b,0x6c7c,0x6c7f,0x6c80,0x6c84,0x6c87, @@ -706,7 +707,7 @@ const unsigned short cp936_ucs_table[] = { 0x6d9c,0x6da2,0x6da5,0x6dac,0x6dad,0x6db0,0x6db1,0x6db3, 0x6db4,0x6db6,0x6db7,0x6db9,0x6dba,0x6dbb,0x6dbc,0x6dbd, 0x6dbe,0x6dc1,0x6dc2,0x6dc3,0x6dc8,0x6dc9,0x6dca,0x0000, -/* 0x9c00 */ +/* 0x9C40 */ 0x6dcd,0x6dce,0x6dcf,0x6dd0,0x6dd2,0x6dd3,0x6dd4,0x6dd5, 0x6dd7,0x6dda,0x6ddb,0x6ddc,0x6ddf,0x6de2,0x6de3,0x6de5, 0x6de7,0x6de8,0x6de9,0x6dea,0x6ded,0x6def,0x6df0,0x6df2, @@ -731,7 +732,7 @@ const unsigned short cp936_ucs_table[] = { 0x6ec6,0x6ec8,0x6ec9,0x6eca,0x6ecc,0x6ecd,0x6ece,0x6ed0, 0x6ed2,0x6ed6,0x6ed8,0x6ed9,0x6edb,0x6edc,0x6edd,0x6ee3, 0x6ee7,0x6eea,0x6eeb,0x6eec,0x6eed,0x6eee,0x6eef,0x0000, -/* 0x9d00 */ +/* 0x9D40 */ 0x6ef0,0x6ef1,0x6ef2,0x6ef3,0x6ef5,0x6ef6,0x6ef7,0x6ef8, 0x6efa,0x6efb,0x6efc,0x6efd,0x6efe,0x6eff,0x6f00,0x6f01, 0x6f03,0x6f04,0x6f05,0x6f07,0x6f08,0x6f0a,0x6f0b,0x6f0c, @@ -756,7 +757,7 @@ const unsigned short cp936_ucs_table[] = { 0x6fca,0x6fcb,0x6fcc,0x6fcd,0x6fce,0x6fcf,0x6fd0,0x6fd3, 0x6fd4,0x6fd5,0x6fd6,0x6fd7,0x6fd8,0x6fd9,0x6fda,0x6fdb, 0x6fdc,0x6fdd,0x6fdf,0x6fe2,0x6fe3,0x6fe4,0x6fe5,0x0000, -/* 0x9e00 */ +/* 0x9E40 */ 0x6fe6,0x6fe7,0x6fe8,0x6fe9,0x6fea,0x6feb,0x6fec,0x6fed, 0x6ff0,0x6ff1,0x6ff2,0x6ff3,0x6ff4,0x6ff5,0x6ff6,0x6ff7, 0x6ff8,0x6ff9,0x6ffa,0x6ffb,0x6ffc,0x6ffd,0x6ffe,0x6fff, @@ -781,7 +782,7 @@ const unsigned short cp936_ucs_table[] = { 0x70b6,0x70ba,0x70be,0x70bf,0x70c4,0x70c5,0x70c6,0x70c7, 0x70c9,0x70cb,0x70cc,0x70cd,0x70ce,0x70cf,0x70d0,0x70d1, 0x70d2,0x70d3,0x70d4,0x70d5,0x70d6,0x70d7,0x70da,0x0000, -/* 0x9f00 */ +/* 0x9F40 */ 0x70dc,0x70dd,0x70de,0x70e0,0x70e1,0x70e2,0x70e3,0x70e5, 0x70ea,0x70ee,0x70f0,0x70f1,0x70f2,0x70f3,0x70f4,0x70f5, 0x70f6,0x70f8,0x70fa,0x70fb,0x70fc,0x70fe,0x70ff,0x7100, @@ -806,7 +807,7 @@ const unsigned short cp936_ucs_table[] = { 0x71bb,0x71bc,0x71bd,0x71be,0x71bf,0x71c0,0x71c1,0x71c2, 0x71c4,0x71c5,0x71c6,0x71c7,0x71c8,0x71c9,0x71ca,0x71cb, 0x71cc,0x71cd,0x71cf,0x71d0,0x71d1,0x71d2,0x71d3,0x0000, -/* 0xa000 */ +/* 0xA040 */ 0x71d6,0x71d7,0x71d8,0x71d9,0x71da,0x71db,0x71dc,0x71dd, 0x71de,0x71df,0x71e1,0x71e2,0x71e3,0x71e4,0x71e6,0x71e8, 0x71e9,0x71ea,0x71eb,0x71ec,0x71ed,0x71ef,0x71f0,0x71f1, @@ -831,7 +832,7 @@ const unsigned short cp936_ucs_table[] = { 0x72ba,0x72bb,0x72bc,0x72bd,0x72be,0x72bf,0x72c0,0x72c5, 0x72c6,0x72c7,0x72c9,0x72ca,0x72cb,0x72cc,0x72cf,0x72d1, 0x72d3,0x72d4,0x72d5,0x72d6,0x72d8,0x72da,0x72db,0x0000, -/* 0xa100 */ +/* 0xA140 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -856,7 +857,7 @@ const unsigned short cp936_ucs_table[] = { 0x00a4,0xffe0,0xffe1,0x2030,0x00a7,0x2116,0x2606,0x2605, 0x25cb,0x25cf,0x25ce,0x25c7,0x25c6,0x25a1,0x25a0,0x25b3, 0x25b2,0x203b,0x2192,0x2190,0x2191,0x2193,0x3013,0x0000, -/* 0xa200 */ +/* 0xA240 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -881,7 +882,7 @@ const unsigned short cp936_ucs_table[] = { 0x3223,0x3224,0x3225,0x3226,0x3227,0x3228,0x3229,0x0000, 0x0000,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166, 0x2167,0x2168,0x2169,0x216a,0x216b,0x0000,0x0000,0x0000, -/* 0xa300 */ +/* 0xA340 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -906,7 +907,7 @@ const unsigned short cp936_ucs_table[] = { 0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f, 0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57, 0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xffe3,0x0000, -/* 0xa400 */ +/* 0xA440 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -931,7 +932,7 @@ const unsigned short cp936_ucs_table[] = { 0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f, 0x3090,0x3091,0x3092,0x3093,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xa500 */ +/* 0xA540 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -956,7 +957,7 @@ const unsigned short cp936_ucs_table[] = { 0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef, 0x30f0,0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xa600 */ +/* 0xA640 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -981,7 +982,7 @@ const unsigned short cp936_ucs_table[] = { 0xfe41,0xfe42,0xfe43,0xfe44,0x0000,0x0000,0xfe3b,0xfe3c, 0xfe37,0xfe38,0xfe31,0x0000,0xfe33,0xfe34,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xa700 */ +/* 0xA740 */ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, @@ -1006,7 +1007,7 @@ const unsigned short cp936_ucs_table[] = { 0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d, 0x044e,0x044f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xa800 */ +/* 0xA840 */ 0x02ca,0x02cb,0x02d9,0x2013,0x2015,0x2025,0x2035,0x2105, 0x2109,0x2196,0x2197,0x2198,0x2199,0x2215,0x221f,0x2223, 0x2252,0x2266,0x2267,0x22bf,0x2550,0x2551,0x2552,0x2553, @@ -1031,7 +1032,7 @@ const unsigned short cp936_ucs_table[] = { 0x3128,0x3129,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xa900 */ +/* 0xA940 */ 0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028, 0x3029,0x32a3,0x338e,0x338f,0x339c,0x339d,0x339e,0x33a1, 0x33c4,0x33ce,0x33d1,0x33d2,0x33d5,0xfe30,0xffe2,0xffe4, @@ -1056,7 +1057,7 @@ const unsigned short cp936_ucs_table[] = { 0x2544,0x2545,0x2546,0x2547,0x2548,0x2549,0x254a,0x254b, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xaa00 */ +/* 0xAA40 */ 0x72dc,0x72dd,0x72df,0x72e2,0x72e3,0x72e4,0x72e5,0x72e6, 0x72e7,0x72ea,0x72eb,0x72f5,0x72f6,0x72f9,0x72fd,0x72fe, 0x72ff,0x7300,0x7302,0x7304,0x7305,0x7306,0x7307,0x7308, @@ -1081,7 +1082,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xab00 */ +/* 0xAB40 */ 0x7372,0x7373,0x7374,0x7375,0x7376,0x7377,0x7378,0x7379, 0x737a,0x737b,0x737c,0x737d,0x737f,0x7380,0x7381,0x7382, 0x7383,0x7385,0x7386,0x7388,0x738a,0x738c,0x738d,0x738f, @@ -1106,7 +1107,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xac00 */ +/* 0xAC40 */ 0x73f8,0x73f9,0x73fa,0x73fb,0x73fc,0x73fd,0x73fe,0x73ff, 0x7400,0x7401,0x7402,0x7404,0x7407,0x7408,0x740b,0x740c, 0x740d,0x740e,0x7411,0x7412,0x7413,0x7414,0x7415,0x7416, @@ -1131,7 +1132,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xad00 */ +/* 0xAD40 */ 0x747b,0x747c,0x747d,0x747f,0x7482,0x7484,0x7485,0x7486, 0x7488,0x7489,0x748a,0x748c,0x748d,0x748f,0x7491,0x7492, 0x7493,0x7494,0x7495,0x7496,0x7497,0x7498,0x7499,0x749a, @@ -1156,7 +1157,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xae00 */ +/* 0xAE40 */ 0x74f3,0x74f5,0x74f8,0x74f9,0x74fa,0x74fb,0x74fc,0x74fd, 0x74fe,0x7500,0x7501,0x7502,0x7503,0x7505,0x7506,0x7507, 0x7508,0x7509,0x750a,0x750b,0x750c,0x750e,0x7510,0x7512, @@ -1181,7 +1182,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xaf00 */ +/* 0xAF40 */ 0x7588,0x7589,0x758a,0x758c,0x758d,0x758e,0x7590,0x7593, 0x7595,0x7598,0x759b,0x759c,0x759e,0x75a2,0x75a6,0x75a7, 0x75a8,0x75a9,0x75aa,0x75ad,0x75b6,0x75b7,0x75ba,0x75bb, @@ -1206,7 +1207,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xb000 */ +/* 0xB040 */ 0x7645,0x7646,0x7647,0x7648,0x7649,0x764a,0x764b,0x764e, 0x764f,0x7650,0x7651,0x7652,0x7653,0x7655,0x7657,0x7658, 0x7659,0x765a,0x765b,0x765d,0x765f,0x7660,0x7661,0x7662, @@ -1231,7 +1232,7 @@ const unsigned short cp936_ucs_table[] = { 0x62cc,0x4f34,0x74e3,0x534a,0x529e,0x7eca,0x90a6,0x5e2e, 0x6886,0x699c,0x8180,0x7ed1,0x68d2,0x78c5,0x868c,0x9551, 0x508d,0x8c24,0x82de,0x80de,0x5305,0x8912,0x5265,0x0000, -/* 0xb100 */ +/* 0xB140 */ 0x76c4,0x76c7,0x76c9,0x76cb,0x76cc,0x76d3,0x76d5,0x76d9, 0x76da,0x76dc,0x76dd,0x76de,0x76e0,0x76e1,0x76e2,0x76e3, 0x76e4,0x76e6,0x76e7,0x76e8,0x76e9,0x76ea,0x76eb,0x76ec, @@ -1256,7 +1257,7 @@ const unsigned short cp936_ucs_table[] = { 0x8fab,0x904d,0x6807,0x5f6a,0x8198,0x8868,0x9cd6,0x618b, 0x522b,0x762a,0x5f6c,0x658c,0x6fd2,0x6ee8,0x5bbe,0x6448, 0x5175,0x51b0,0x67c4,0x4e19,0x79c9,0x997c,0x70b3,0x0000, -/* 0xb200 */ +/* 0xB240 */ 0x775d,0x775e,0x775f,0x7760,0x7764,0x7767,0x7769,0x776a, 0x776d,0x776e,0x776f,0x7770,0x7771,0x7772,0x7773,0x7774, 0x7775,0x7776,0x7777,0x7778,0x777a,0x777b,0x777c,0x7781, @@ -1281,7 +1282,7 @@ const unsigned short cp936_ucs_table[] = { 0x8336,0x67e5,0x78b4,0x643d,0x5bdf,0x5c94,0x5dee,0x8be7, 0x62c6,0x67f4,0x8c7a,0x6400,0x63ba,0x8749,0x998b,0x8c17, 0x7f20,0x94f2,0x4ea7,0x9610,0x98a4,0x660c,0x7316,0x0000, -/* 0xb300 */ +/* 0xB340 */ 0x77e6,0x77e8,0x77ea,0x77ef,0x77f0,0x77f1,0x77f2,0x77f4, 0x77f5,0x77f7,0x77f9,0x77fa,0x77fb,0x77fc,0x7803,0x7804, 0x7805,0x7806,0x7807,0x7808,0x780a,0x780b,0x780e,0x780f, @@ -1306,7 +1307,7 @@ const unsigned short cp936_ucs_table[] = { 0x5ba0,0x62bd,0x916c,0x7574,0x8e0c,0x7a20,0x6101,0x7b79, 0x4ec7,0x7ef8,0x7785,0x4e11,0x81ed,0x521d,0x51fa,0x6a71, 0x53a8,0x8e87,0x9504,0x96cf,0x6ec1,0x9664,0x695a,0x0000, -/* 0xb400 */ +/* 0xB440 */ 0x7884,0x7885,0x7886,0x7888,0x788a,0x788b,0x788f,0x7890, 0x7892,0x7894,0x7895,0x7896,0x7899,0x789d,0x789e,0x78a0, 0x78a2,0x78a4,0x78a6,0x78a8,0x78a9,0x78aa,0x78ab,0x78ac, @@ -1331,7 +1332,7 @@ const unsigned short cp936_ucs_table[] = { 0x78cb,0x64ae,0x6413,0x63aa,0x632b,0x9519,0x642d,0x8fbe, 0x7b54,0x7629,0x6253,0x5927,0x5446,0x6b79,0x50a3,0x6234, 0x5e26,0x6b86,0x4ee3,0x8d37,0x888b,0x5f85,0x902e,0x0000, -/* 0xb500 */ +/* 0xB540 */ 0x790d,0x790e,0x790f,0x7910,0x7911,0x7912,0x7914,0x7915, 0x7916,0x7917,0x7918,0x7919,0x791a,0x791b,0x791c,0x791d, 0x791f,0x7920,0x7921,0x7922,0x7923,0x7925,0x7926,0x7927, @@ -1356,7 +1357,7 @@ const unsigned short cp936_ucs_table[] = { 0x4f43,0x7538,0x5e97,0x60e6,0x5960,0x6dc0,0x6bbf,0x7889, 0x53fc,0x96d5,0x51cb,0x5201,0x6389,0x540a,0x9493,0x8c03, 0x8dcc,0x7239,0x789f,0x8776,0x8fed,0x8c0d,0x53e0,0x0000, -/* 0xb600 */ +/* 0xB640 */ 0x7993,0x7994,0x7995,0x7996,0x7997,0x7998,0x7999,0x799b, 0x799c,0x799d,0x799e,0x799f,0x79a0,0x79a1,0x79a2,0x79a3, 0x79a4,0x79a5,0x79a6,0x79a8,0x79a9,0x79aa,0x79ab,0x79ac, @@ -1381,7 +1382,7 @@ const unsigned short cp936_ucs_table[] = { 0x60f0,0x5815,0x86fe,0x5ce8,0x9e45,0x4fc4,0x989d,0x8bb9, 0x5a25,0x6076,0x5384,0x627c,0x904f,0x9102,0x997f,0x6069, 0x800c,0x513f,0x8033,0x5c14,0x9975,0x6d31,0x4e8c,0x0000, -/* 0xb700 */ +/* 0xB740 */ 0x7a1d,0x7a1f,0x7a21,0x7a22,0x7a24,0x7a25,0x7a26,0x7a27, 0x7a28,0x7a29,0x7a2a,0x7a2b,0x7a2c,0x7a2d,0x7a2e,0x7a2f, 0x7a30,0x7a31,0x7a32,0x7a34,0x7a35,0x7a36,0x7a38,0x7a3a, @@ -1406,7 +1407,7 @@ const unsigned short cp936_ucs_table[] = { 0x75af,0x70fd,0x9022,0x51af,0x7f1d,0x8bbd,0x5949,0x51e4, 0x4f5b,0x5426,0x592b,0x6577,0x80a4,0x5b75,0x6276,0x62c2, 0x8f90,0x5e45,0x6c1f,0x7b26,0x4f0f,0x4fd8,0x670d,0x0000, -/* 0xb800 */ +/* 0xB840 */ 0x7aa3,0x7aa4,0x7aa7,0x7aa9,0x7aaa,0x7aab,0x7aae,0x7aaf, 0x7ab0,0x7ab1,0x7ab2,0x7ab4,0x7ab5,0x7ab6,0x7ab7,0x7ab8, 0x7ab9,0x7aba,0x7abb,0x7abc,0x7abd,0x7abe,0x7ac0,0x7ac1, @@ -1431,7 +1432,7 @@ const unsigned short cp936_ucs_table[] = { 0x6b4c,0x6401,0x6208,0x9e3d,0x80f3,0x7599,0x5272,0x9769, 0x845b,0x683c,0x86e4,0x9601,0x9694,0x94ec,0x4e2a,0x5404, 0x7ed9,0x6839,0x8ddf,0x8015,0x66f4,0x5e9a,0x7fb9,0x0000, -/* 0xb900 */ +/* 0xB940 */ 0x7b2f,0x7b30,0x7b32,0x7b34,0x7b35,0x7b36,0x7b37,0x7b39, 0x7b3b,0x7b3d,0x7b3f,0x7b40,0x7b41,0x7b42,0x7b43,0x7b44, 0x7b46,0x7b48,0x7b4a,0x7b4d,0x7b4e,0x7b53,0x7b55,0x7b57, @@ -1456,7 +1457,7 @@ const unsigned short cp936_ucs_table[] = { 0x7845,0x5f52,0x9f9f,0x95fa,0x8f68,0x9b3c,0x8be1,0x7678, 0x6842,0x67dc,0x8dea,0x8d35,0x523d,0x8f8a,0x6eda,0x68cd, 0x9505,0x90ed,0x56fd,0x679c,0x88f9,0x8fc7,0x54c8,0x0000, -/* 0xba00 */ +/* 0xBA40 */ 0x7bc5,0x7bc8,0x7bc9,0x7bca,0x7bcb,0x7bcd,0x7bce,0x7bcf, 0x7bd0,0x7bd2,0x7bd4,0x7bd5,0x7bd6,0x7bd7,0x7bd8,0x7bdb, 0x7bdc,0x7bde,0x7bdf,0x7be0,0x7be2,0x7be3,0x7be4,0x7be7, @@ -1481,7 +1482,7 @@ const unsigned short cp936_ucs_table[] = { 0x9e3f,0x6d2a,0x5b8f,0x5f18,0x7ea2,0x5589,0x4faf,0x7334, 0x543c,0x539a,0x5019,0x540e,0x547c,0x4e4e,0x5ffd,0x745a, 0x58f6,0x846b,0x80e1,0x8774,0x72d0,0x7cca,0x6e56,0x0000, -/* 0xbb00 */ +/* 0xBB40 */ 0x7c43,0x7c44,0x7c45,0x7c46,0x7c47,0x7c48,0x7c49,0x7c4a, 0x7c4b,0x7c4c,0x7c4e,0x7c4f,0x7c50,0x7c51,0x7c52,0x7c53, 0x7c54,0x7c55,0x7c56,0x7c57,0x7c58,0x7c59,0x7c5a,0x7c5b, @@ -1506,7 +1507,7 @@ const unsigned short cp936_ucs_table[] = { 0x660f,0x5a5a,0x9b42,0x6d51,0x6df7,0x8c41,0x6d3b,0x4f19, 0x706b,0x83b7,0x6216,0x60d1,0x970d,0x8d27,0x7978,0x51fb, 0x573e,0x57fa,0x673a,0x7578,0x7a3d,0x79ef,0x7b95,0x0000, -/* 0xbc00 */ +/* 0xBC40 */ 0x7cbf,0x7cc0,0x7cc2,0x7cc3,0x7cc4,0x7cc6,0x7cc9,0x7ccb, 0x7cce,0x7ccf,0x7cd0,0x7cd1,0x7cd2,0x7cd3,0x7cd4,0x7cd8, 0x7cda,0x7cdb,0x7cdd,0x7cde,0x7ce1,0x7ce2,0x7ce3,0x7ce4, @@ -1531,7 +1532,7 @@ const unsigned short cp936_ucs_table[] = { 0x8270,0x5978,0x7f04,0x8327,0x68c0,0x67ec,0x78b1,0x7877, 0x62e3,0x6361,0x7b80,0x4fed,0x526a,0x51cf,0x8350,0x69db, 0x9274,0x8df5,0x8d31,0x89c1,0x952e,0x7bad,0x4ef6,0x0000, -/* 0xbd00 */ +/* 0xBD40 */ 0x7d37,0x7d38,0x7d39,0x7d3a,0x7d3b,0x7d3c,0x7d3d,0x7d3e, 0x7d3f,0x7d40,0x7d41,0x7d42,0x7d43,0x7d44,0x7d45,0x7d46, 0x7d47,0x7d48,0x7d49,0x7d4a,0x7d4b,0x7d4c,0x7d4d,0x7d4e, @@ -1556,7 +1557,7 @@ const unsigned short cp936_ucs_table[] = { 0x501f,0x4ecb,0x75a5,0x8beb,0x5c4a,0x5dfe,0x7b4b,0x65a4, 0x91d1,0x4eca,0x6d25,0x895f,0x7d27,0x9526,0x4ec5,0x8c28, 0x8fdb,0x9773,0x664b,0x7981,0x8fd1,0x70ec,0x6d78,0x0000, -/* 0xbe00 */ +/* 0xBE40 */ 0x7d99,0x7d9a,0x7d9b,0x7d9c,0x7d9d,0x7d9e,0x7d9f,0x7da0, 0x7da1,0x7da2,0x7da3,0x7da4,0x7da5,0x7da7,0x7da8,0x7da9, 0x7daa,0x7dab,0x7dac,0x7dad,0x7daf,0x7db0,0x7db1,0x7db2, @@ -1581,7 +1582,7 @@ const unsigned short cp936_ucs_table[] = { 0x6350,0x9e43,0x5a1f,0x5026,0x7737,0x5377,0x7ee2,0x6485, 0x652b,0x6289,0x6398,0x5014,0x7235,0x89c9,0x51b3,0x8bc0, 0x7edd,0x5747,0x83cc,0x94a7,0x519b,0x541b,0x5cfb,0x0000, -/* 0xbf00 */ +/* 0xBF40 */ 0x7dfb,0x7dfc,0x7dfd,0x7dfe,0x7dff,0x7e00,0x7e01,0x7e02, 0x7e03,0x7e04,0x7e05,0x7e06,0x7e07,0x7e08,0x7e09,0x7e0a, 0x7e0b,0x7e0c,0x7e0d,0x7e0e,0x7e0f,0x7e10,0x7e11,0x7e12, @@ -1606,7 +1607,7 @@ const unsigned short cp936_ucs_table[] = { 0x80ef,0x5757,0x7b77,0x4fa9,0x5feb,0x5bbd,0x6b3e,0x5321, 0x7b50,0x72c2,0x6846,0x77ff,0x7736,0x65f7,0x51b5,0x4e8f, 0x76d4,0x5cbf,0x7aa5,0x8475,0x594e,0x9b41,0x5080,0x0000, -/* 0xc000 */ +/* 0xC040 */ 0x7e5e,0x7e5f,0x7e60,0x7e61,0x7e62,0x7e63,0x7e64,0x7e65, 0x7e66,0x7e67,0x7e68,0x7e69,0x7e6a,0x7e6b,0x7e6c,0x7e6d, 0x7e6e,0x7e6f,0x7e70,0x7e71,0x7e72,0x7e73,0x7e74,0x7e75, @@ -1631,7 +1632,7 @@ const unsigned short cp936_ucs_table[] = { 0x9ece,0x7bf1,0x72f8,0x79bb,0x6f13,0x7406,0x674e,0x91cc, 0x9ca4,0x793c,0x8389,0x8354,0x540f,0x6817,0x4e3d,0x5389, 0x52b1,0x783e,0x5386,0x5229,0x5088,0x4f8b,0x4fd0,0x0000, -/* 0xc100 */ +/* 0xC140 */ 0x7f56,0x7f59,0x7f5b,0x7f5c,0x7f5d,0x7f5e,0x7f60,0x7f63, 0x7f64,0x7f65,0x7f66,0x7f67,0x7f6b,0x7f6c,0x7f6d,0x7f6f, 0x7f70,0x7f73,0x7f75,0x7f76,0x7f77,0x7f78,0x7f7a,0x7f7b, @@ -1656,7 +1657,7 @@ const unsigned short cp936_ucs_table[] = { 0x51cc,0x7075,0x9675,0x5cad,0x9886,0x53e6,0x4ee4,0x6e9c, 0x7409,0x69b4,0x786b,0x998f,0x7559,0x5218,0x7624,0x6d41, 0x67f3,0x516d,0x9f99,0x804b,0x5499,0x7b3c,0x7abf,0x0000, -/* 0xc200 */ +/* 0xC240 */ 0x7fe4,0x7fe7,0x7fe8,0x7fea,0x7feb,0x7fec,0x7fed,0x7fef, 0x7ff2,0x7ff4,0x7ff5,0x7ff6,0x7ff7,0x7ff8,0x7ff9,0x7ffa, 0x7ffd,0x7ffe,0x7fff,0x8002,0x8007,0x8008,0x8009,0x800a, @@ -1681,7 +1682,7 @@ const unsigned short cp936_ucs_table[] = { 0x5988,0x9ebb,0x739b,0x7801,0x8682,0x9a6c,0x9a82,0x561b, 0x5417,0x57cb,0x4e70,0x9ea6,0x5356,0x8fc8,0x8109,0x7792, 0x9992,0x86ee,0x6ee1,0x8513,0x66fc,0x6162,0x6f2b,0x0000, -/* 0xc300 */ +/* 0xC340 */ 0x807e,0x8081,0x8082,0x8085,0x8088,0x808a,0x808d,0x808e, 0x808f,0x8090,0x8091,0x8092,0x8094,0x8095,0x8097,0x8099, 0x809e,0x80a3,0x80a6,0x80a7,0x80a8,0x80ac,0x80b0,0x80b3, @@ -1706,7 +1707,7 @@ const unsigned short cp936_ucs_table[] = { 0x63cf,0x7784,0x85d0,0x79d2,0x6e3a,0x5e99,0x5999,0x8511, 0x706d,0x6c11,0x62bf,0x76bf,0x654f,0x60af,0x95fd,0x660e, 0x879f,0x9e23,0x94ed,0x540d,0x547d,0x8c2c,0x6478,0x0000, -/* 0xc400 */ +/* 0xC440 */ 0x8140,0x8141,0x8142,0x8143,0x8144,0x8145,0x8147,0x8149, 0x814d,0x814e,0x814f,0x8152,0x8156,0x8157,0x8158,0x815b, 0x815c,0x815d,0x815e,0x815f,0x8161,0x8162,0x8163,0x8164, @@ -1731,7 +1732,7 @@ const unsigned short cp936_ucs_table[] = { 0x852b,0x62c8,0x5e74,0x78be,0x64b5,0x637b,0x5ff5,0x5a18, 0x917f,0x9e1f,0x5c3f,0x634f,0x8042,0x5b7d,0x556e,0x954a, 0x954d,0x6d85,0x60a8,0x67e0,0x72de,0x51dd,0x5b81,0x0000, -/* 0xc500 */ +/* 0xC540 */ 0x81d4,0x81d5,0x81d6,0x81d7,0x81d8,0x81d9,0x81da,0x81db, 0x81dc,0x81dd,0x81de,0x81df,0x81e0,0x81e1,0x81e2,0x81e4, 0x81e5,0x81e6,0x81e8,0x81e9,0x81eb,0x81ee,0x81ef,0x81f0, @@ -1756,7 +1757,7 @@ const unsigned short cp936_ucs_table[] = { 0x76c6,0x7830,0x62a8,0x70f9,0x6f8e,0x5f6d,0x84ec,0x68da, 0x787c,0x7bf7,0x81a8,0x670b,0x9e4f,0x6367,0x78b0,0x576f, 0x7812,0x9739,0x6279,0x62ab,0x5288,0x7435,0x6bd7,0x0000, -/* 0xc600 */ +/* 0xC640 */ 0x826a,0x826b,0x826c,0x826d,0x8271,0x8275,0x8276,0x8277, 0x8278,0x827b,0x827c,0x8280,0x8281,0x8283,0x8285,0x8286, 0x8287,0x8289,0x828c,0x8290,0x8293,0x8294,0x8295,0x8296, @@ -1781,7 +1782,7 @@ const unsigned short cp936_ucs_table[] = { 0x7566,0x5d0e,0x8110,0x9f50,0x65d7,0x7948,0x7941,0x9a91, 0x8d77,0x5c82,0x4e5e,0x4f01,0x542f,0x5951,0x780c,0x5668, 0x6c14,0x8fc4,0x5f03,0x6c7d,0x6ce3,0x8bab,0x6390,0x0000, -/* 0xc700 */ +/* 0xC740 */ 0x833e,0x833f,0x8341,0x8342,0x8344,0x8345,0x8348,0x834a, 0x834b,0x834c,0x834d,0x834e,0x8353,0x8355,0x8356,0x8357, 0x8358,0x8359,0x835d,0x8362,0x8370,0x8371,0x8372,0x8373, @@ -1806,7 +1807,7 @@ const unsigned short cp936_ucs_table[] = { 0x6c30,0x60c5,0x9877,0x8bf7,0x5e86,0x743c,0x7a77,0x79cb, 0x4e18,0x90b1,0x7403,0x6c42,0x56da,0x914b,0x6cc5,0x8d8b, 0x533a,0x86c6,0x66f2,0x8eaf,0x5c48,0x9a71,0x6e20,0x0000, -/* 0xc800 */ +/* 0xC840 */ 0x83ee,0x83ef,0x83f3,0x83f4,0x83f5,0x83f6,0x83f7,0x83fa, 0x83fb,0x83fc,0x83fe,0x83ff,0x8400,0x8402,0x8405,0x8407, 0x8408,0x8409,0x840a,0x8410,0x8412,0x8413,0x8414,0x8415, @@ -1831,7 +1832,7 @@ const unsigned short cp936_ucs_table[] = { 0x8fb1,0x4e73,0x6c5d,0x5165,0x8925,0x8f6f,0x962e,0x854a, 0x745e,0x9510,0x95f0,0x6da6,0x82e5,0x5f31,0x6492,0x6d12, 0x8428,0x816e,0x9cc3,0x585e,0x8d5b,0x4e09,0x53c1,0x0000, -/* 0xc900 */ +/* 0xC940 */ 0x847d,0x847e,0x847f,0x8480,0x8481,0x8483,0x8484,0x8485, 0x8486,0x848a,0x848d,0x848f,0x8490,0x8491,0x8492,0x8493, 0x8494,0x8495,0x8496,0x8498,0x849a,0x849b,0x849d,0x849e, @@ -1856,7 +1857,7 @@ const unsigned short cp936_ucs_table[] = { 0x8bbe,0x7837,0x7533,0x547b,0x4f38,0x8eab,0x6df1,0x5a20, 0x7ec5,0x795e,0x6c88,0x5ba1,0x5a76,0x751a,0x80be,0x614e, 0x6e17,0x58f0,0x751f,0x7525,0x7272,0x5347,0x7ef3,0x0000, -/* 0xca00 */ +/* 0xCA40 */ 0x8503,0x8504,0x8505,0x8506,0x8507,0x8508,0x8509,0x850a, 0x850b,0x850d,0x850e,0x850f,0x8510,0x8512,0x8514,0x8515, 0x8516,0x8518,0x8519,0x851b,0x851c,0x851d,0x851e,0x8520, @@ -1881,7 +1882,7 @@ const unsigned short cp936_ucs_table[] = { 0x758f,0x4e66,0x8d4e,0x5b70,0x719f,0x85af,0x6691,0x66d9, 0x7f72,0x8700,0x9ecd,0x9f20,0x5c5e,0x672f,0x8ff0,0x6811, 0x675f,0x620d,0x7ad6,0x5885,0x5eb6,0x6570,0x6f31,0x0000, -/* 0xcb00 */ +/* 0xCB40 */ 0x8582,0x8583,0x8586,0x8588,0x8589,0x858a,0x858b,0x858c, 0x858d,0x858e,0x8590,0x8591,0x8592,0x8593,0x8594,0x8595, 0x8596,0x8597,0x8598,0x8599,0x859a,0x859d,0x859e,0x859f, @@ -1906,7 +1907,7 @@ const unsigned short cp936_ucs_table[] = { 0x9ad3,0x788e,0x5c81,0x7a57,0x9042,0x96a7,0x795f,0x5b59, 0x635f,0x7b0b,0x84d1,0x68ad,0x5506,0x7f29,0x7410,0x7d22, 0x9501,0x6240,0x584c,0x4ed6,0x5b83,0x5979,0x5854,0x0000, -/* 0xcc00 */ +/* 0xCC40 */ 0x85f9,0x85fa,0x85fc,0x85fd,0x85fe,0x8600,0x8601,0x8602, 0x8603,0x8604,0x8606,0x8607,0x8608,0x8609,0x860a,0x860b, 0x860c,0x860d,0x860e,0x860f,0x8610,0x8612,0x8613,0x8614, @@ -1931,7 +1932,7 @@ const unsigned short cp936_ucs_table[] = { 0x60d5,0x6d95,0x5243,0x5c49,0x5929,0x6dfb,0x586b,0x7530, 0x751c,0x606c,0x8214,0x8146,0x6311,0x6761,0x8fe2,0x773a, 0x8df3,0x8d34,0x94c1,0x5e16,0x5385,0x542c,0x70c3,0x0000, -/* 0xcd00 */ +/* 0xCD40 */ 0x866d,0x866f,0x8670,0x8672,0x8673,0x8674,0x8675,0x8676, 0x8677,0x8678,0x8683,0x8684,0x8685,0x8686,0x8687,0x8688, 0x8689,0x868e,0x868f,0x8690,0x8691,0x8692,0x8694,0x8696, @@ -1956,7 +1957,7 @@ const unsigned short cp936_ucs_table[] = { 0x4e38,0x70f7,0x5b8c,0x7897,0x633d,0x665a,0x7696,0x60cb, 0x5b9b,0x5a49,0x4e07,0x8155,0x6c6a,0x738b,0x4ea1,0x6789, 0x7f51,0x5f80,0x65fa,0x671b,0x5fd8,0x5984,0x5a01,0x0000, -/* 0xce00 */ +/* 0xCE40 */ 0x8719,0x871b,0x871d,0x871f,0x8720,0x8724,0x8726,0x8727, 0x8728,0x872a,0x872b,0x872c,0x872d,0x872f,0x8730,0x8732, 0x8733,0x8735,0x8736,0x8738,0x8739,0x873a,0x873c,0x873d, @@ -1981,7 +1982,7 @@ const unsigned short cp936_ucs_table[] = { 0x821e,0x4f0d,0x4fae,0x575e,0x620a,0x96fe,0x6664,0x7269, 0x52ff,0x52a1,0x609f,0x8bef,0x6614,0x7199,0x6790,0x897f, 0x7852,0x77fd,0x6670,0x563b,0x5438,0x9521,0x727a,0x0000, -/* 0xcf00 */ +/* 0xCF40 */ 0x87a5,0x87a6,0x87a7,0x87a9,0x87aa,0x87ae,0x87b0,0x87b1, 0x87b2,0x87b4,0x87b6,0x87b7,0x87b8,0x87b9,0x87bb,0x87bc, 0x87be,0x87bf,0x87c1,0x87c2,0x87c3,0x87c4,0x87c5,0x87c7, @@ -2006,7 +2007,7 @@ const unsigned short cp936_ucs_table[] = { 0x7fd4,0x7965,0x8be6,0x60f3,0x54cd,0x4eab,0x9879,0x5df7, 0x6a61,0x50cf,0x5411,0x8c61,0x8427,0x785d,0x9704,0x524a, 0x54ee,0x56a3,0x9500,0x6d88,0x5bb5,0x6dc6,0x6653,0x0000, -/* 0xd000 */ +/* 0xD040 */ 0x8824,0x8825,0x8826,0x8827,0x8828,0x8829,0x882a,0x882b, 0x882c,0x882d,0x882e,0x882f,0x8830,0x8831,0x8833,0x8834, 0x8835,0x8836,0x8837,0x8838,0x883a,0x883b,0x883d,0x883e, @@ -2031,7 +2032,7 @@ const unsigned short cp936_ucs_table[] = { 0x9700,0x865a,0x5618,0x987b,0x5f90,0x8bb8,0x84c4,0x9157, 0x53d9,0x65ed,0x5e8f,0x755c,0x6064,0x7d6e,0x5a7f,0x7eea, 0x7eed,0x8f69,0x55a7,0x5ba3,0x60ac,0x65cb,0x7384,0x0000, -/* 0xd100 */ +/* 0xD140 */ 0x88ac,0x88ae,0x88af,0x88b0,0x88b2,0x88b3,0x88b4,0x88b5, 0x88b6,0x88b8,0x88b9,0x88ba,0x88bb,0x88bd,0x88be,0x88bf, 0x88c0,0x88c3,0x88c4,0x88c7,0x88c8,0x88ca,0x88cb,0x88cc, @@ -2056,7 +2057,7 @@ const unsigned short cp936_ucs_table[] = { 0x8c1a,0x9a8c,0x6b83,0x592e,0x9e2f,0x79e7,0x6768,0x626c, 0x4f6f,0x75a1,0x7f8a,0x6d0b,0x9633,0x6c27,0x4ef0,0x75d2, 0x517b,0x6837,0x6f3e,0x9080,0x8170,0x5996,0x7476,0x0000, -/* 0xd200 */ +/* 0xD240 */ 0x8938,0x8939,0x893a,0x893b,0x893c,0x893d,0x893e,0x893f, 0x8940,0x8942,0x8943,0x8945,0x8946,0x8947,0x8948,0x8949, 0x894a,0x894b,0x894c,0x894d,0x894e,0x894f,0x8950,0x8951, @@ -2081,7 +2082,7 @@ const unsigned short cp936_ucs_table[] = { 0x8be3,0x8bae,0x8c0a,0x8bd1,0x5f02,0x7ffc,0x7fcc,0x7ece, 0x8335,0x836b,0x56e0,0x6bb7,0x97f3,0x9634,0x59fb,0x541f, 0x94f6,0x6deb,0x5bc5,0x996e,0x5c39,0x5f15,0x9690,0x0000, -/* 0xd300 */ +/* 0xD340 */ 0x89a2,0x89a3,0x89a4,0x89a5,0x89a6,0x89a7,0x89a8,0x89a9, 0x89aa,0x89ab,0x89ac,0x89ad,0x89ae,0x89af,0x89b0,0x89b1, 0x89b2,0x89b3,0x89b4,0x89b5,0x89b6,0x89b7,0x89b8,0x89b9, @@ -2106,7 +2107,7 @@ const unsigned short cp936_ucs_table[] = { 0x4e88,0x5a31,0x96e8,0x4e0e,0x5c7f,0x79b9,0x5b87,0x8bed, 0x7fbd,0x7389,0x57df,0x828b,0x90c1,0x5401,0x9047,0x55bb, 0x5cea,0x5fa1,0x6108,0x6b32,0x72f1,0x80b2,0x8a89,0x0000, -/* 0xd400 */ +/* 0xD440 */ 0x8a1e,0x8a1f,0x8a20,0x8a21,0x8a22,0x8a23,0x8a24,0x8a25, 0x8a26,0x8a27,0x8a28,0x8a29,0x8a2a,0x8a2b,0x8a2c,0x8a2d, 0x8a2e,0x8a2f,0x8a30,0x8a31,0x8a32,0x8a33,0x8a34,0x8a35, @@ -2131,7 +2132,7 @@ const unsigned short cp936_ucs_table[] = { 0x6fa1,0x86a4,0x8e81,0x566a,0x9020,0x7682,0x7076,0x71e5, 0x8d23,0x62e9,0x5219,0x6cfd,0x8d3c,0x600e,0x589e,0x618e, 0x66fe,0x8d60,0x624e,0x55b3,0x6e23,0x672d,0x8f67,0x0000, -/* 0xd500 */ +/* 0xD540 */ 0x8a81,0x8a82,0x8a83,0x8a84,0x8a85,0x8a86,0x8a87,0x8a88, 0x8a8b,0x8a8c,0x8a8d,0x8a8e,0x8a8f,0x8a90,0x8a91,0x8a92, 0x8a94,0x8a95,0x8a96,0x8a97,0x8a98,0x8a99,0x8a9a,0x8a9b, @@ -2156,7 +2157,7 @@ const unsigned short cp936_ucs_table[] = { 0x7827,0x81fb,0x8d1e,0x9488,0x4fa6,0x6795,0x75b9,0x8bca, 0x9707,0x632f,0x9547,0x9635,0x84b8,0x6323,0x7741,0x5f81, 0x72f0,0x4e89,0x6014,0x6574,0x62ef,0x6b63,0x653f,0x0000, -/* 0xd600 */ +/* 0xD640 */ 0x8ae4,0x8ae5,0x8ae6,0x8ae7,0x8ae8,0x8ae9,0x8aea,0x8aeb, 0x8aec,0x8aed,0x8aee,0x8aef,0x8af0,0x8af1,0x8af2,0x8af3, 0x8af4,0x8af5,0x8af6,0x8af7,0x8af8,0x8af9,0x8afa,0x8afb, @@ -2181,7 +2182,7 @@ const unsigned short cp936_ucs_table[] = { 0x9aa4,0x73e0,0x682a,0x86db,0x6731,0x732a,0x8bf8,0x8bdb, 0x9010,0x7af9,0x70db,0x716e,0x62c4,0x77a9,0x5631,0x4e3b, 0x8457,0x67f1,0x52a9,0x86c0,0x8d2e,0x94f8,0x7b51,0x0000, -/* 0xd700 */ +/* 0xD740 */ 0x8b46,0x8b47,0x8b48,0x8b49,0x8b4a,0x8b4b,0x8b4c,0x8b4d, 0x8b4e,0x8b4f,0x8b50,0x8b51,0x8b52,0x8b53,0x8b54,0x8b55, 0x8b56,0x8b57,0x8b58,0x8b59,0x8b5a,0x8b5b,0x8b5c,0x8b5d, @@ -2206,7 +2207,7 @@ const unsigned short cp936_ucs_table[] = { 0x963b,0x7ec4,0x94bb,0x7e82,0x5634,0x9189,0x6700,0x7f6a, 0x5c0a,0x9075,0x6628,0x5de6,0x4f50,0x67de,0x505a,0x4f5c, 0x5750,0x5ea7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xd800 */ +/* 0xD840 */ 0x8c38,0x8c39,0x8c3a,0x8c3b,0x8c3c,0x8c3d,0x8c3e,0x8c3f, 0x8c40,0x8c42,0x8c43,0x8c44,0x8c45,0x8c48,0x8c4a,0x8c4b, 0x8c4d,0x8c4e,0x8c4f,0x8c50,0x8c51,0x8c52,0x8c53,0x8c54, @@ -2231,7 +2232,7 @@ const unsigned short cp936_ucs_table[] = { 0x7f54,0x4ebb,0x4ec3,0x4ec9,0x4ec2,0x4ee8,0x4ee1,0x4eeb, 0x4ede,0x4f1b,0x4ef3,0x4f22,0x4f64,0x4ef5,0x4f25,0x4f27, 0x4f09,0x4f2b,0x4f5e,0x4f67,0x6538,0x4f5a,0x4f5d,0x0000, -/* 0xd900 */ +/* 0xD940 */ 0x8cae,0x8caf,0x8cb0,0x8cb1,0x8cb2,0x8cb3,0x8cb4,0x8cb5, 0x8cb6,0x8cb7,0x8cb8,0x8cb9,0x8cba,0x8cbb,0x8cbc,0x8cbd, 0x8cbe,0x8cbf,0x8cc0,0x8cc1,0x8cc2,0x8cc3,0x8cc4,0x8cc5, @@ -2256,7 +2257,7 @@ const unsigned short cp936_ucs_table[] = { 0x52f9,0x530d,0x8a07,0x5310,0x51eb,0x5919,0x5155,0x4ea0, 0x5156,0x4eb3,0x886e,0x88a4,0x4eb5,0x8114,0x88d2,0x7980, 0x5b34,0x8803,0x7fb8,0x51ab,0x51b1,0x51bd,0x51bc,0x0000, -/* 0xda00 */ +/* 0xDA40 */ 0x8d0e,0x8d0f,0x8d10,0x8d11,0x8d12,0x8d13,0x8d14,0x8d15, 0x8d16,0x8d17,0x8d18,0x8d19,0x8d1a,0x8d1b,0x8d1c,0x8d20, 0x8d51,0x8d52,0x8d57,0x8d5f,0x8d65,0x8d68,0x8d69,0x8d6a, @@ -2281,7 +2282,7 @@ const unsigned short cp936_ucs_table[] = { 0x963c,0x9642,0x9649,0x9654,0x965f,0x9667,0x966c,0x9672, 0x9674,0x9688,0x968d,0x9697,0x96b0,0x9097,0x909b,0x909d, 0x9099,0x90ac,0x90a1,0x90b4,0x90b3,0x90b6,0x90ba,0x0000, -/* 0xdb00 */ +/* 0xDB40 */ 0x8dd5,0x8dd8,0x8dd9,0x8ddc,0x8de0,0x8de1,0x8de2,0x8de5, 0x8de6,0x8de7,0x8de9,0x8ded,0x8dee,0x8df0,0x8df1,0x8df2, 0x8df4,0x8df6,0x8dfc,0x8dfe,0x8dff,0x8e00,0x8e01,0x8e02, @@ -2306,7 +2307,7 @@ const unsigned short cp936_ucs_table[] = { 0x576d,0x5776,0x5773,0x57ad,0x57a4,0x578c,0x57b2,0x57cf, 0x57a7,0x57b4,0x5793,0x57a0,0x57d5,0x57d8,0x57da,0x57d9, 0x57d2,0x57b8,0x57f4,0x57ef,0x57f8,0x57e4,0x57dd,0x0000, -/* 0xdc00 */ +/* 0xDC40 */ 0x8e73,0x8e75,0x8e77,0x8e78,0x8e79,0x8e7a,0x8e7b,0x8e7d, 0x8e7e,0x8e80,0x8e82,0x8e83,0x8e84,0x8e86,0x8e88,0x8e89, 0x8e8a,0x8e8b,0x8e8c,0x8e8d,0x8e8e,0x8e91,0x8e92,0x8e93, @@ -2331,7 +2332,7 @@ const unsigned short cp936_ucs_table[] = { 0x8351,0x835b,0x835c,0x8308,0x8392,0x833c,0x8334,0x8331, 0x839b,0x835e,0x832f,0x834f,0x8347,0x8343,0x835f,0x8340, 0x8317,0x8360,0x832d,0x833a,0x8333,0x8366,0x8365,0x0000, -/* 0xdd00 */ +/* 0xDD40 */ 0x8ee5,0x8ee6,0x8ee7,0x8ee8,0x8ee9,0x8eea,0x8eeb,0x8eec, 0x8eed,0x8eee,0x8eef,0x8ef0,0x8ef1,0x8ef2,0x8ef3,0x8ef4, 0x8ef5,0x8ef6,0x8ef7,0x8ef8,0x8ef9,0x8efa,0x8efb,0x8efc, @@ -2356,7 +2357,7 @@ const unsigned short cp936_ucs_table[] = { 0x84c1,0x84cd,0x84d0,0x84e6,0x84bd,0x84d3,0x84ca,0x84bf, 0x84ba,0x84e0,0x84a1,0x84b9,0x84b4,0x8497,0x84e5,0x84e3, 0x850c,0x750d,0x8538,0x84f0,0x8539,0x851f,0x853a,0x0000, -/* 0xde00 */ +/* 0xDE40 */ 0x8f45,0x8f46,0x8f47,0x8f48,0x8f49,0x8f4a,0x8f4b,0x8f4c, 0x8f4d,0x8f4e,0x8f4f,0x8f50,0x8f51,0x8f52,0x8f53,0x8f54, 0x8f55,0x8f56,0x8f57,0x8f58,0x8f59,0x8f5a,0x8f5b,0x8f5c, @@ -2381,7 +2382,7 @@ const unsigned short cp936_ucs_table[] = { 0x63bc,0x63f2,0x63f8,0x63e0,0x63ff,0x63c4,0x63de,0x63ce, 0x6452,0x63c6,0x63be,0x6445,0x6441,0x640b,0x641b,0x6420, 0x640c,0x6426,0x6421,0x645e,0x6484,0x646d,0x6496,0x0000, -/* 0xdf00 */ +/* 0xDF40 */ 0x9019,0x901c,0x9023,0x9024,0x9025,0x9027,0x9028,0x9029, 0x902a,0x902b,0x902c,0x9030,0x9031,0x9032,0x9033,0x9034, 0x9037,0x9039,0x903a,0x903d,0x903f,0x9040,0x9043,0x9045, @@ -2406,7 +2407,7 @@ const unsigned short cp936_ucs_table[] = { 0x54de,0x551b,0x54e7,0x5520,0x54fd,0x5514,0x54f3,0x5522, 0x5523,0x550f,0x5511,0x5527,0x552a,0x5567,0x558f,0x55b5, 0x5549,0x556d,0x5541,0x5555,0x553f,0x5550,0x553c,0x0000, -/* 0xe000 */ +/* 0xE040 */ 0x90c2,0x90c3,0x90c6,0x90c8,0x90c9,0x90cb,0x90cc,0x90cd, 0x90d2,0x90d4,0x90d5,0x90d6,0x90d8,0x90d9,0x90da,0x90de, 0x90df,0x90e0,0x90e3,0x90e4,0x90e5,0x90e9,0x90ea,0x90ec, @@ -2431,7 +2432,7 @@ const unsigned short cp936_ucs_table[] = { 0x567c,0x5685,0x5693,0x56af,0x56d4,0x56d7,0x56dd,0x56e1, 0x56f5,0x56eb,0x56f9,0x56ff,0x5704,0x570a,0x5709,0x571c, 0x5e0f,0x5e19,0x5e14,0x5e11,0x5e31,0x5e3b,0x5e3c,0x0000, -/* 0xe100 */ +/* 0xE140 */ 0x9145,0x9147,0x9148,0x9151,0x9153,0x9154,0x9155,0x9156, 0x9158,0x9159,0x915b,0x915c,0x915f,0x9160,0x9166,0x9167, 0x9168,0x916b,0x916d,0x9173,0x917a,0x917b,0x917c,0x9180, @@ -2456,7 +2457,7 @@ const unsigned short cp936_ucs_table[] = { 0x5fbc,0x8862,0x5f61,0x72ad,0x72b0,0x72b4,0x72b7,0x72b8, 0x72c3,0x72c1,0x72ce,0x72cd,0x72d2,0x72e8,0x72ef,0x72e9, 0x72f2,0x72f4,0x72f7,0x7301,0x72f3,0x7303,0x72fa,0x0000, -/* 0xe200 */ +/* 0xE240 */ 0x91e6,0x91e7,0x91e8,0x91e9,0x91ea,0x91eb,0x91ec,0x91ed, 0x91ee,0x91ef,0x91f0,0x91f1,0x91f2,0x91f3,0x91f4,0x91f5, 0x91f6,0x91f7,0x91f8,0x91f9,0x91fa,0x91fb,0x91fc,0x91fd, @@ -2481,7 +2482,7 @@ const unsigned short cp936_ucs_table[] = { 0x5fe4,0x5ffe,0x6005,0x6006,0x5fea,0x5fed,0x5ff8,0x6019, 0x6035,0x6026,0x601b,0x600f,0x600d,0x6029,0x602b,0x600a, 0x603f,0x6021,0x6078,0x6079,0x607b,0x607a,0x6042,0x0000, -/* 0xe300 */ +/* 0xE340 */ 0x9246,0x9247,0x9248,0x9249,0x924a,0x924b,0x924c,0x924d, 0x924e,0x924f,0x9250,0x9251,0x9252,0x9253,0x9254,0x9255, 0x9256,0x9257,0x9258,0x9259,0x925a,0x925b,0x925c,0x925d, @@ -2506,7 +2507,7 @@ const unsigned short cp936_ucs_table[] = { 0x6c68,0x6c69,0x6c74,0x6c76,0x6c86,0x6ca9,0x6cd0,0x6cd4, 0x6cad,0x6cf7,0x6cf8,0x6cf1,0x6cd7,0x6cb2,0x6ce0,0x6cd6, 0x6cfa,0x6ceb,0x6cee,0x6cb1,0x6cd3,0x6cef,0x6cfe,0x0000, -/* 0xe400 */ +/* 0xE440 */ 0x92a8,0x92a9,0x92aa,0x92ab,0x92ac,0x92ad,0x92af,0x92b0, 0x92b1,0x92b2,0x92b3,0x92b4,0x92b5,0x92b6,0x92b7,0x92b8, 0x92b9,0x92ba,0x92bb,0x92bc,0x92bd,0x92be,0x92bf,0x92c0, @@ -2531,7 +2532,7 @@ const unsigned short cp936_ucs_table[] = { 0x6ec2,0x6e9f,0x6f62,0x6f46,0x6f47,0x6f24,0x6f15,0x6ef9, 0x6f2f,0x6f36,0x6f4b,0x6f74,0x6f2a,0x6f09,0x6f29,0x6f89, 0x6f8d,0x6f8c,0x6f78,0x6f72,0x6f7c,0x6f7a,0x6fd1,0x0000, -/* 0xe500 */ +/* 0xE540 */ 0x930a,0x930b,0x930c,0x930d,0x930e,0x930f,0x9310,0x9311, 0x9312,0x9313,0x9314,0x9315,0x9316,0x9317,0x9318,0x9319, 0x931a,0x931b,0x931c,0x931d,0x931e,0x931f,0x9320,0x9321, @@ -2556,7 +2557,7 @@ const unsigned short cp936_ucs_table[] = { 0x5f56,0x5f58,0x5c3b,0x54ab,0x5c50,0x5c59,0x5b71,0x5c63, 0x5c66,0x7fbc,0x5f2a,0x5f29,0x5f2d,0x8274,0x5f3c,0x9b3b, 0x5c6e,0x5981,0x5983,0x598d,0x59a9,0x59aa,0x59a3,0x0000, -/* 0xe600 */ +/* 0xE640 */ 0x936c,0x936d,0x936e,0x936f,0x9370,0x9371,0x9372,0x9373, 0x9374,0x9375,0x9376,0x9377,0x9378,0x9379,0x937a,0x937b, 0x937c,0x937d,0x937e,0x937f,0x9380,0x9381,0x9382,0x9383, @@ -2581,7 +2582,7 @@ const unsigned short cp936_ucs_table[] = { 0x9a85,0x9a88,0x9a8a,0x9a90,0x9a92,0x9a93,0x9a96,0x9a98, 0x9a9b,0x9a9c,0x9a9d,0x9a9f,0x9aa0,0x9aa2,0x9aa3,0x9aa5, 0x9aa7,0x7e9f,0x7ea1,0x7ea3,0x7ea5,0x7ea8,0x7ea9,0x0000, -/* 0xe700 */ +/* 0xE740 */ 0x93ce,0x93cf,0x93d0,0x93d1,0x93d2,0x93d3,0x93d4,0x93d5, 0x93d7,0x93d8,0x93d9,0x93da,0x93db,0x93dc,0x93dd,0x93de, 0x93df,0x93e0,0x93e1,0x93e2,0x93e3,0x93e4,0x93e5,0x93e6, @@ -2606,7 +2607,7 @@ const unsigned short cp936_ucs_table[] = { 0x73b7,0x73b3,0x73c0,0x73c9,0x73c8,0x73e5,0x73d9,0x987c, 0x740a,0x73e9,0x73e7,0x73de,0x73ba,0x73f2,0x740f,0x742a, 0x745b,0x7426,0x7425,0x7428,0x7430,0x742e,0x742c,0x0000, -/* 0xe800 */ +/* 0xE840 */ 0x942f,0x9430,0x9431,0x9432,0x9433,0x9434,0x9435,0x9436, 0x9437,0x9438,0x9439,0x943a,0x943b,0x943c,0x943d,0x943f, 0x9440,0x9441,0x9442,0x9443,0x9444,0x9445,0x9446,0x9447, @@ -2631,7 +2632,7 @@ const unsigned short cp936_ucs_table[] = { 0x6883,0x681d,0x6855,0x6866,0x6841,0x6867,0x6840,0x683e, 0x684a,0x6849,0x6829,0x68b5,0x688f,0x6874,0x6877,0x6893, 0x686b,0x68c2,0x696e,0x68fc,0x691f,0x6920,0x68f9,0x0000, -/* 0xe900 */ +/* 0xE940 */ 0x9527,0x9533,0x953d,0x9543,0x9548,0x954b,0x9555,0x955a, 0x9560,0x956e,0x9574,0x9575,0x9577,0x9578,0x9579,0x957a, 0x957b,0x957c,0x957d,0x957e,0x9580,0x9581,0x9582,0x9583, @@ -2656,7 +2657,7 @@ const unsigned short cp936_ucs_table[] = { 0x6b8d,0x6b9a,0x6b9b,0x6ba1,0x6baa,0x8f6b,0x8f6d,0x8f71, 0x8f72,0x8f73,0x8f75,0x8f76,0x8f78,0x8f77,0x8f79,0x8f7a, 0x8f7c,0x8f7e,0x8f81,0x8f82,0x8f84,0x8f87,0x8f8b,0x0000, -/* 0xea00 */ +/* 0xEA40 */ 0x95cc,0x95cd,0x95ce,0x95cf,0x95d0,0x95d1,0x95d2,0x95d3, 0x95d4,0x95d5,0x95d6,0x95d7,0x95d8,0x95d9,0x95da,0x95db, 0x95dc,0x95dd,0x95de,0x95df,0x95e0,0x95e1,0x95e2,0x95e3, @@ -2681,7 +2682,7 @@ const unsigned short cp936_ucs_table[] = { 0x89c7,0x89ca,0x89cb,0x89cc,0x89ce,0x89cf,0x89d0,0x89d1, 0x726e,0x729f,0x725d,0x7266,0x726f,0x727e,0x727f,0x7284, 0x728b,0x728d,0x728f,0x7292,0x6308,0x6332,0x63b0,0x0000, -/* 0xeb00 */ +/* 0xEB40 */ 0x968c,0x968e,0x9691,0x9692,0x9693,0x9695,0x9696,0x969a, 0x969b,0x969d,0x969e,0x969f,0x96a0,0x96a1,0x96a2,0x96a3, 0x96a4,0x96a5,0x96a6,0x96a8,0x96a9,0x96aa,0x96ab,0x96ac, @@ -2706,7 +2707,7 @@ const unsigned short cp936_ucs_table[] = { 0x8153,0x8174,0x8159,0x815a,0x8171,0x8160,0x8169,0x817c, 0x817d,0x816d,0x8167,0x584d,0x5ab5,0x8188,0x8182,0x8191, 0x6ed5,0x81a3,0x81aa,0x81cc,0x6726,0x81ca,0x81bb,0x0000, -/* 0xec00 */ +/* 0xEC40 */ 0x9721,0x9722,0x9723,0x9724,0x9725,0x9726,0x9727,0x9728, 0x9729,0x972b,0x972c,0x972e,0x972f,0x9731,0x9733,0x9734, 0x9735,0x9736,0x9737,0x973a,0x973b,0x973c,0x973d,0x973f, @@ -2731,7 +2732,7 @@ const unsigned short cp936_ucs_table[] = { 0x6248,0x6249,0x793b,0x7940,0x7946,0x7949,0x795b,0x795c, 0x7953,0x795a,0x7962,0x7957,0x7960,0x796f,0x7967,0x797a, 0x7985,0x798a,0x799a,0x79a7,0x79b3,0x5fd1,0x5fd0,0x0000, -/* 0xed00 */ +/* 0xED40 */ 0x979e,0x979f,0x97a1,0x97a2,0x97a4,0x97a5,0x97a6,0x97a7, 0x97a8,0x97a9,0x97aa,0x97ac,0x97ae,0x97b0,0x97b1,0x97b3, 0x97b5,0x97b6,0x97b7,0x97b8,0x97b9,0x97ba,0x97bb,0x97bc, @@ -2756,7 +2757,7 @@ const unsigned short cp936_ucs_table[] = { 0x9f9b,0x9ef9,0x9efb,0x9efc,0x76f1,0x7704,0x770d,0x76f9, 0x7707,0x7708,0x771a,0x7722,0x7719,0x772d,0x7726,0x7735, 0x7738,0x7750,0x7751,0x7747,0x7743,0x775a,0x7768,0x0000, -/* 0xee00 */ +/* 0xEE40 */ 0x980f,0x9810,0x9811,0x9812,0x9813,0x9814,0x9815,0x9816, 0x9817,0x9818,0x9819,0x981a,0x981b,0x981c,0x981d,0x981e, 0x981f,0x9820,0x9821,0x9822,0x9823,0x9824,0x9825,0x9826, @@ -2781,7 +2782,7 @@ const unsigned short cp936_ucs_table[] = { 0x94ca,0x94cb,0x94cc,0x94cd,0x94ce,0x94d0,0x94d1,0x94d2, 0x94d5,0x94d6,0x94d7,0x94d9,0x94d8,0x94db,0x94de,0x94df, 0x94e0,0x94e2,0x94e4,0x94e5,0x94e7,0x94e8,0x94ea,0x0000, -/* 0xef00 */ +/* 0xEF40 */ 0x986f,0x9870,0x9871,0x9872,0x9873,0x9874,0x988b,0x988e, 0x9892,0x9895,0x9899,0x98a3,0x98a8,0x98a9,0x98aa,0x98ab, 0x98ac,0x98ad,0x98ae,0x98af,0x98b0,0x98b1,0x98b2,0x98b3, @@ -2806,7 +2807,7 @@ const unsigned short cp936_ucs_table[] = { 0x9568,0x9569,0x956a,0x956b,0x956c,0x956f,0x9571,0x9572, 0x9573,0x953a,0x77e7,0x77ec,0x96c9,0x79d5,0x79ed,0x79e3, 0x79eb,0x7a06,0x5d47,0x7a03,0x7a02,0x7a1e,0x7a14,0x0000, -/* 0xf000 */ +/* 0xF040 */ 0x9908,0x9909,0x990a,0x990b,0x990c,0x990e,0x990f,0x9911, 0x9912,0x9913,0x9914,0x9915,0x9916,0x9917,0x9918,0x9919, 0x991a,0x991b,0x991c,0x991d,0x991e,0x991f,0x9920,0x9921, @@ -2831,7 +2832,7 @@ const unsigned short cp936_ucs_table[] = { 0x75c2,0x75d6,0x75cd,0x75e3,0x75e8,0x75e6,0x75e4,0x75eb, 0x75e7,0x7603,0x75f1,0x75fc,0x75ff,0x7610,0x7600,0x7605, 0x760c,0x7617,0x760a,0x7625,0x7618,0x7615,0x7619,0x0000, -/* 0xf100 */ +/* 0xF140 */ 0x998c,0x998e,0x999a,0x999b,0x999c,0x999d,0x999e,0x999f, 0x99a0,0x99a1,0x99a2,0x99a3,0x99a4,0x99a6,0x99a7,0x99a9, 0x99aa,0x99ab,0x99ac,0x99ad,0x99ae,0x99af,0x99b0,0x99b1, @@ -2856,7 +2857,7 @@ const unsigned short cp936_ucs_table[] = { 0x8014,0x8016,0x801c,0x8020,0x8022,0x8025,0x8026,0x8027, 0x8029,0x8028,0x8031,0x800b,0x8035,0x8043,0x8046,0x804d, 0x8052,0x8069,0x8071,0x8983,0x9878,0x9880,0x9883,0x0000, -/* 0xf200 */ +/* 0xF240 */ 0x99fa,0x99fb,0x99fc,0x99fd,0x99fe,0x99ff,0x9a00,0x9a01, 0x9a02,0x9a03,0x9a04,0x9a05,0x9a06,0x9a07,0x9a08,0x9a09, 0x9a0a,0x9a0b,0x9a0c,0x9a0d,0x9a0e,0x9a0f,0x9a10,0x9a11, @@ -2881,7 +2882,7 @@ const unsigned short cp936_ucs_table[] = { 0x8729,0x8737,0x873f,0x8782,0x8722,0x877d,0x877e,0x877b, 0x8760,0x8770,0x874c,0x876e,0x878b,0x8753,0x8763,0x877c, 0x8764,0x8759,0x8765,0x8793,0x87af,0x87a8,0x87d2,0x0000, -/* 0xf300 */ +/* 0xF340 */ 0x9a5a,0x9a5b,0x9a5c,0x9a5d,0x9a5e,0x9a5f,0x9a60,0x9a61, 0x9a62,0x9a63,0x9a64,0x9a65,0x9a66,0x9a67,0x9a68,0x9a69, 0x9a6a,0x9a6b,0x9a72,0x9a83,0x9a89,0x9a8d,0x9a8e,0x9a94, @@ -2906,7 +2907,7 @@ const unsigned short cp936_ucs_table[] = { 0x7bac,0x7b9d,0x7ba8,0x7b85,0x7baa,0x7b9c,0x7ba2,0x7bab, 0x7bb4,0x7bd1,0x7bc1,0x7bcc,0x7bdd,0x7bda,0x7be5,0x7be6, 0x7bea,0x7c0c,0x7bfe,0x7bfc,0x7c0f,0x7c16,0x7c0b,0x0000, -/* 0xf400 */ +/* 0xF440 */ 0x9b07,0x9b09,0x9b0a,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b10, 0x9b11,0x9b12,0x9b14,0x9b15,0x9b16,0x9b17,0x9b18,0x9b19, 0x9b1a,0x9b1b,0x9b1c,0x9b1d,0x9b1e,0x9b20,0x9b21,0x9b22, @@ -2931,7 +2932,7 @@ const unsigned short cp936_ucs_table[] = { 0x7ff3,0x7cf8,0x7d77,0x7da6,0x7dae,0x7e47,0x7e9b,0x9eb8, 0x9eb4,0x8d73,0x8d84,0x8d94,0x8d91,0x8db1,0x8d67,0x8d6d, 0x8c47,0x8c49,0x914a,0x9150,0x914e,0x914f,0x9164,0x0000, -/* 0xf500 */ +/* 0xF540 */ 0x9b7c,0x9b7d,0x9b7e,0x9b7f,0x9b80,0x9b81,0x9b82,0x9b83, 0x9b84,0x9b85,0x9b86,0x9b87,0x9b88,0x9b89,0x9b8a,0x9b8b, 0x9b8c,0x9b8d,0x9b8e,0x9b8f,0x9b90,0x9b91,0x9b92,0x9b93, @@ -2956,7 +2957,7 @@ const unsigned short cp936_ucs_table[] = { 0x8e4a,0x8e70,0x8e76,0x8e7c,0x8e6f,0x8e74,0x8e85,0x8e8f, 0x8e94,0x8e90,0x8e9c,0x8e9e,0x8c78,0x8c82,0x8c8a,0x8c85, 0x8c98,0x8c94,0x659b,0x89d6,0x89de,0x89da,0x89dc,0x0000, -/* 0xf600 */ +/* 0xF640 */ 0x9bdc,0x9bdd,0x9bde,0x9bdf,0x9be0,0x9be1,0x9be2,0x9be3, 0x9be4,0x9be5,0x9be6,0x9be7,0x9be8,0x9be9,0x9bea,0x9beb, 0x9bec,0x9bed,0x9bee,0x9bef,0x9bf0,0x9bf1,0x9bf2,0x9bf3, @@ -2981,7 +2982,7 @@ const unsigned short cp936_ucs_table[] = { 0x9ca8,0x9ca9,0x9cab,0x9cad,0x9cae,0x9cb0,0x9cb1,0x9cb2, 0x9cb3,0x9cb4,0x9cb5,0x9cb6,0x9cb7,0x9cba,0x9cbb,0x9cbc, 0x9cbd,0x9cc4,0x9cc5,0x9cc6,0x9cc7,0x9cca,0x9ccb,0x0000, -/* 0xf700 */ +/* 0xF740 */ 0x9c3c,0x9c3d,0x9c3e,0x9c3f,0x9c40,0x9c41,0x9c42,0x9c43, 0x9c44,0x9c45,0x9c46,0x9c47,0x9c48,0x9c49,0x9c4a,0x9c4b, 0x9c4c,0x9c4d,0x9c4e,0x9c4f,0x9c50,0x9c51,0x9c52,0x9c53, @@ -3006,7 +3007,7 @@ const unsigned short cp936_ucs_table[] = { 0x9e92,0x93d6,0x9e9d,0x9e9f,0x9edb,0x9edc,0x9edd,0x9ee0, 0x9edf,0x9ee2,0x9ee9,0x9ee7,0x9ee5,0x9eea,0x9eef,0x9f22, 0x9f2c,0x9f2f,0x9f39,0x9f37,0x9f3d,0x9f3e,0x9f44,0x0000, -/* 0xf800 */ +/* 0xF840 */ 0x9ce3,0x9ce4,0x9ce5,0x9ce6,0x9ce7,0x9ce8,0x9ce9,0x9cea, 0x9ceb,0x9cec,0x9ced,0x9cee,0x9cef,0x9cf0,0x9cf1,0x9cf2, 0x9cf3,0x9cf4,0x9cf5,0x9cf6,0x9cf7,0x9cf8,0x9cf9,0x9cfa, @@ -3031,7 +3032,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xf900 */ +/* 0xF940 */ 0x9d43,0x9d44,0x9d45,0x9d46,0x9d47,0x9d48,0x9d49,0x9d4a, 0x9d4b,0x9d4c,0x9d4d,0x9d4e,0x9d4f,0x9d50,0x9d51,0x9d52, 0x9d53,0x9d54,0x9d55,0x9d56,0x9d57,0x9d58,0x9d59,0x9d5a, @@ -3056,7 +3057,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xfa00 */ +/* 0xFA40 */ 0x9da3,0x9da4,0x9da5,0x9da6,0x9da7,0x9da8,0x9da9,0x9daa, 0x9dab,0x9dac,0x9dad,0x9dae,0x9daf,0x9db0,0x9db1,0x9db2, 0x9db3,0x9db4,0x9db5,0x9db6,0x9db7,0x9db8,0x9db9,0x9dba, @@ -3081,7 +3082,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xfb00 */ +/* 0xFB40 */ 0x9e03,0x9e04,0x9e05,0x9e06,0x9e07,0x9e08,0x9e09,0x9e0a, 0x9e0b,0x9e0c,0x9e0d,0x9e0e,0x9e0f,0x9e10,0x9e11,0x9e12, 0x9e13,0x9e14,0x9e15,0x9e16,0x9e17,0x9e18,0x9e19,0x9e1a, @@ -3106,7 +3107,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xfc00 */ +/* 0xFC40 */ 0x9eab,0x9eac,0x9ead,0x9eae,0x9eaf,0x9eb0,0x9eb1,0x9eb2, 0x9eb3,0x9eb5,0x9eb6,0x9eb7,0x9eb9,0x9eba,0x9ebc,0x9ebf, 0x9ec0,0x9ec1,0x9ec2,0x9ec3,0x9ec5,0x9ec6,0x9ec7,0x9ec8, @@ -3131,7 +3132,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xfd00 */ +/* 0xFD40 */ 0x9f32,0x9f33,0x9f34,0x9f35,0x9f36,0x9f38,0x9f3a,0x9f3c, 0x9f3f,0x9f40,0x9f41,0x9f42,0x9f43,0x9f45,0x9f46,0x9f47, 0x9f48,0x9f49,0x9f4a,0x9f4b,0x9f4c,0x9f4d,0x9f4e,0x9f4f, @@ -3156,7 +3157,7 @@ const unsigned short cp936_ucs_table[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, -/* 0xfe00 */ +/* 0xFE40 */ 0xfa0c,0xfa0d,0xfa0e,0xfa0f,0xfa11,0xfa13,0xfa14,0xfa18, 0xfa1f,0xfa20,0xfa21,0xfa23,0xfa24,0xfa27,0xfa28,0xfa29, 0x2e81,0x0000,0x0000,0x0000,0x2e84,0x3473,0x3447,0x2e88, @@ -3173,6 +3174,216 @@ const unsigned short cp936_ucs_table[] = { const int cp936_ucs_table_size = (sizeof(cp936_ucs_table)/sizeof(unsigned short)); +const unsigned short cp936_pua_tbl1[] = { +/* 0xA2AB */ +0xE766,0xE767,0xE768,0xE769,0xE76A, +0xE76B,0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e, +0x248f,0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496, +0x2497,0x2498,0x2499,0x249a,0x249b,0x2474,0x2475,0x2476, +0x2477,0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e, +0x247f,0x2480,0x2481,0x2482,0x2483,0x2484,0x2485,0x2486, +0x2487,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466, +0x2467,0x2468,0x2469,0xE76C,0xE76D,0x3220,0x3221,0x3222, +0x3223,0x3224,0x3225,0x3226,0x3227,0x3228,0x3229,0xE76E, +0xE76F,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166, +0x2167,0x2168,0x2169,0x216a,0x216b,0xE770,0xE771,0x0000, +/* 0xA340 */ +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0xff01,0xff02,0xff03,0xffe5,0xff05,0xff06,0xff07, +0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e,0xff0f, +0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17, +0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f, +0xff20,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27, +0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f, +0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37, +0xff38,0xff39,0xff3a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f, +0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47, +0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f, +0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57, +0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xffe3,0x0000, +/* 0xA440 */ +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047, +0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,0x304f, +0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057, +0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f, +0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067, +0x3068,0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f, +0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077, +0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f, +0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087, +0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f, +0x3090,0x3091,0x3092,0x3093,0xE772,0xE773,0xE774,0xE775, +0xE776,0xE777,0xE778,0xE779,0xE77A,0xE77B,0xE77C,0x0000, +/* 0xA540 */ +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7, +0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,0x30af, +0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7, +0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf, +0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7, +0x30c8,0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf, +0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6,0x30d7, +0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df, +0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7, +0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef, +0x30f0,0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,0xE77D, +0xE77E,0xE77F,0xE780,0xE781,0xE782,0xE783,0xE784,0x0000, +/* 0xA640 */ +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397, +0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f, +0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8, +0x03a9,0xE785,0xE786,0xE787,0xE788,0xE789,0xE78A,0xE78B, +0xE78C,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7, +0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf, +0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8, +0x03c9,0xE78D,0xE78E,0xE78F,0xE790,0xE791,0xE792,0xE793, +0xfe35,0xfe36,0xfe39,0xfe3a,0xfe3f,0xfe40,0xfe3d,0xfe3e, +0xfe41,0xfe42,0xfe43,0xfe44,0xE794,0xE795,0xfe3b,0xfe3c, +0xfe37,0xfe38,0xfe31,0xE796,0xfe33,0xfe34,0xE797,0xE798, +0xE799,0xE79A,0xE79B,0xE79C,0xE79D,0xE79E,0xE79F,0x0000, +/* 0xA740 */ +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, +0x0000,0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401, +0x0416,0x0417,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d, +0x041e,0x041f,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425, +0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d, +0x042e,0x042f,0xE7A0,0xE7A1,0xE7A2,0xE7A3,0xE7A4,0xE7A5, +0xE7A6,0xE7A7,0xE7A8,0xE7A9,0xE7AA,0xE7AB,0xE7AC,0xE7AD, +0xE7AE,0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0451, +0x0436,0x0437,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d, +0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445, +0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d, +0x044e,0x044f,0xE7AF,0xE7B0,0xE7B1,0xE7B2,0xE7B3,0xE7B4, +0xE7B5,0xE7B6,0xE7B7,0xE7B8,0xE7B9,0xE7BA,0xE7BB,0x0000, +/* 0xA840 */ +0x02ca,0x02cb,0x02d9,0x2013,0x2015,0x2025,0x2035,0x2105, +0x2109,0x2196,0x2197,0x2198,0x2199,0x2215,0x221f,0x2223, +0x2252,0x2266,0x2267,0x22bf,0x2550,0x2551,0x2552,0x2553, +0x2554,0x2555,0x2556,0x2557,0x2558,0x2559,0x255a,0x255b, +0x255c,0x255d,0x255e,0x255f,0x2560,0x2561,0x2562,0x2563, +0x2564,0x2565,0x2566,0x2567,0x2568,0x2569,0x256a,0x256b, +0x256c,0x256d,0x256e,0x256f,0x2570,0x2571,0x2572,0x2573, +0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587,0x0000, +0x2588,0x2589,0x258a,0x258b,0x258c,0x258d,0x258e,0x258f, +0x2593,0x2594,0x2595,0x25bc,0x25bd,0x25e2,0x25e3,0x25e4, +0x25e5,0x2609,0x2295,0x3012,0x301d,0x301e,0xE7BC,0xE7BD, +0xE7BE,0xE7BF,0xE7C0,0xE7C1,0xE7C2,0xE7C3,0xE7C4,0xE7C5, +0xE7C6,0x0101,0x00e1,0x01ce,0x00e0,0x0113,0x00e9,0x011b, +0x00e8,0x012b,0x00ed,0x01d0,0x00ec,0x014d,0x00f3,0x01d2, +0x00f2,0x016b,0x00fa,0x01d4,0x00f9,0x01d6,0x01d8,0x01da, +0x01dc,0x00fc,0x00ea,0x0251,0xE7C7,0x0144,0x0148,0xE7C8, +0x0261,0xE7C9,0xE7CA,0xE7CB,0xE7CC,0x3105,0x3106,0x3107, +0x3108,0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f, +0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117, +0x3118,0x3119,0x311a,0x311b,0x311c,0x311d,0x311e,0x311f, +0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,0x3127, +0x3128,0x3129,0xE7CD,0xE7CE,0xE7CF,0xE7D0,0xE7D1,0xE7D2, +0xE7D3,0xE7D4,0xE7D5,0xE7D6,0xE7D7,0xE7D8,0xE7D9,0xE7DA, +0xE7DB,0xE7DC,0xE7DD,0xE7DE,0xE7DF,0xE7E0,0xE7E1,0x0000, +/* 0xA940 */ +0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028, +0x3029,0x32a3,0x338e,0x338f,0x339c,0x339d,0x339e,0x33a1, +0x33c4,0x33ce,0x33d1,0x33d2,0x33d5,0xfe30,0xffe2,0xffe4, +0xE7E2,0x2121,0x3231,0xE7E3,0x2010,0xE7E4,0xE7E5,0xE7E6, +0x30fc,0x309b,0x309c,0x30fd,0x30fe,0x3006,0x309d,0x309e, +0xfe49,0xfe4a,0xfe4b,0xfe4c,0xfe4d,0xfe4e,0xfe4f,0xfe50, +0xfe51,0xfe52,0xfe54,0xfe55,0xfe56,0xfe57,0xfe59,0xfe5a, +0xfe5b,0xfe5c,0xfe5d,0xfe5e,0xfe5f,0xfe60,0xfe61,0x0000, +0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0xfe68,0xfe69,0xfe6a, +0xfe6b,0xE7E7,0xE7E8,0xE7E9,0xE7EA,0xE7EB,0xE7EC,0xE7ED, +0xE7EE,0xE7EF,0xE7F0,0xE7F1,0xE7F2,0xE7F3,0x3007,0xE7F4, +0xE7F5,0xE7F6,0xE7F7,0xE7F8,0xE7F9,0xE7FA,0xE7FB,0xE7FC, +0xE7FD,0xE7FE,0xE7FF,0xE800,0x2500,0x2501,0x2502,0x2503, +0x2504,0x2505,0x2506,0x2507,0x2508,0x2509,0x250a,0x250b, +0x250c,0x250d,0x250e,0x250f,0x2510,0x2511,0x2512,0x2513, +0x2514,0x2515,0x2516,0x2517,0x2518,0x2519,0x251a,0x251b, +0x251c,0x251d,0x251e,0x251f,0x2520,0x2521,0x2522,0x2523, +0x2524,0x2525,0x2526,0x2527,0x2528,0x2529,0x252a,0x252b, +0x252c,0x252d,0x252e,0x252f,0x2530,0x2531,0x2532,0x2533, +0x2534,0x2535,0x2536,0x2537,0x2538,0x2539,0x253a,0x253b, +0x253c,0x253d,0x253e,0x253f,0x2540,0x2541,0x2542,0x2543, +0x2544,0x2545,0x2546,0x2547,0x2548,0x2549,0x254a,0x254b, +0xE801,0xE802,0xE803,0xE804,0xE805,0xE806,0xE807,0xE808, +0xE809,0xE80A,0xE80B,0xE80C,0xE80D,0xE80E,0xE80F,0x0000, +}; + +const unsigned short cp936_pua_tbl2[] = { +/* 0xD7FA */ +0xE810,0xE811,0xE812,0xE813,0xE814 +}; + +const unsigned short cp936_pua_tbl3[] = { +/* 0xFE50 */ +0xE815,0xE816,0xE817,0xE818,0xE819,0xE81A,0xE81B,0xE81C, +0xE81D,0xE81E,0xE81F,0xE820,0xE821,0xE822,0xE823,0xE824, +0xE825,0xE826,0xE827,0xE828,0xE829,0xE82A,0xE82B,0xE82C, +0xE82D,0xE82E,0xE82F,0xE830,0xE831,0xE832,0xE833,0xE834, +0xE835,0xE836,0xE837,0xE838,0xE839,0xE83A,0xE83B,0xE83C, +0xE83D,0xE83E,0xE83F,0xE840,0xE841,0xE842,0xE843,0x0000, +0xE844,0xE845,0xE846,0xE847,0xE848,0xE849,0xE84A,0xE84B, +0xE84C,0xE84D,0xE84E,0xE84F,0xE850,0xE851,0xE852,0xE853, +0xE854,0xE855,0xE856,0xE857,0xE858,0xE859,0xE85A,0xE85B, +0xE85C,0xE85D,0xE85E,0xE85F,0xE860,0xE861,0xE862,0xE863, +/* 0xFEA0 */ +0xE864 +}; /* UCS -> CP936 */ const unsigned short ucs_a1_cp936_table[] = { @@ -6426,6 +6637,10 @@ static const int mbfl_cp936_pua_tbl_max = sizeof(mbfl_cp936_pua_tbl)/(sizeof(uns #else extern const unsigned short cp936_ucs_table[]; +extern const unsigned short cp936_pua_tbl1[]; +extern const unsigned short cp936_pua_tbl2[]; +extern const unsigned short cp936_pua_tbl3[]; + extern const unsigned short ucs_a1_cp936_table[]; extern const unsigned short ucs_a2_cp936_table[]; extern const unsigned short ucs_a3_cp936_table[]; diff --git a/ext/mbstring/libmbfl/filters/unicode_table_uhc.h b/ext/mbstring/libmbfl/filters/unicode_table_uhc.h index a205d1fedf9b1..737d7921619eb 100644 --- a/ext/mbstring/libmbfl/filters/unicode_table_uhc.h +++ b/ext/mbstring/libmbfl/filters/unicode_table_uhc.h @@ -790,12 +790,8 @@ const unsigned short uhc1_ucs_table[] = { 0xc876,0xc877,0xc879,0xc87b,0xc87c,0xc87d,0xc87e,0xc87f, 0xc882,0xc884,0xc888,0xc889,0xc88a,0xc88e,0xc88f,0xc890, 0xc891,0xc892,0xc893,0xc895,0xc896,0xc897,0xc898,0xc899, -0xc89a,0xc89b,0xc89c,0xc89e,0xc8a0,0xc8a2,0xc8a3,0xc8a4 -}; - -const int uhc1_ucs_table_size = (sizeof(uhc1_ucs_table)/sizeof(unsigned short)); +0xc89a,0xc89b,0xc89c,0xc89e,0xc8a0,0xc8a2,0xc8a3,0xc8a4, -const unsigned short uhc2_ucs_table[] = { 0xc8a5,0xc8a6,0xc8a7,0xc8a9,0xc8aa,0xc8ab,0xc8ac,0xc8ad, 0xc8ae,0xc8af,0xc8b0,0xc8b1,0xc8b2,0xc8b3,0xc8b4,0xc8b5, 0xc8b6,0xc8b7,0xc8b8,0xc8b9,0xc8ba,0xc8bb,0xc8be,0xc8bf, @@ -1698,9 +1694,10 @@ const unsigned short uhc2_ucs_table[] = { 0xd391,0xd398,0xd399,0xd39c,0xd3a0,0xd3a8,0xd3a9,0xd3ab, 0xd3ad,0xd3b4,0xd3b8,0xd3bc,0xd3c4,0xd3c5,0xd3c8,0xd3c9, 0xd3d0,0xd3d8,0xd3e1,0xd3e3,0xd3ec,0xd3ed,0xd3f0,0xd3f4, -0xd3fc,0xd3fd,0xd3ff,0xd401}; +0xd3fc,0xd3fd,0xd3ff,0xd401 +}; -const int uhc2_ucs_table_size = (sizeof(uhc2_ucs_table)/sizeof(unsigned short)); +const int uhc1_ucs_table_size = (sizeof(uhc1_ucs_table)/sizeof(unsigned short)); const unsigned short uhc3_ucs_table[] = { 0xd408,0xd41d,0xd440,0xd444,0xd45c,0xd460,0xd464,0xd46d, diff --git a/ext/mbstring/libmbfl/filters/utf7_helper.h b/ext/mbstring/libmbfl/filters/utf7_helper.h new file mode 100644 index 0000000000000..0e71a5a449031 --- /dev/null +++ b/ext/mbstring/libmbfl/filters/utf7_helper.h @@ -0,0 +1,22 @@ +#ifndef MBFL_UTF7_HELPER_H +#define MBFL_UTF7_HELPER_H + +#include "mbfilter.h" + +/* Ways which a Base64-encoded section can end: */ +#define DASH 0xFC +#define DIRECT 0xFD +#define ASCII 0xFE +#define ILLEGAL 0xFF + +static inline bool is_base64_end_valid(unsigned char n, bool gap, bool is_surrogate) +{ + return !(gap || is_surrogate || n == ASCII || n == ILLEGAL); +} + +static inline bool has_surrogate(uint16_t cp, bool is_surrogate) +{ + return !is_surrogate && cp >= 0xD800 && cp <= 0xDBFF; +} + +#endif /* MBFL_UTF7_HELPER_H */ diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter.c b/ext/mbstring/libmbfl/mbfl/mbfilter.c index 22a64d3210415..1c30c9f417755 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter.c @@ -93,474 +93,6 @@ #include "filters/mbfilter_singlebyte.h" #include "filters/mbfilter_utf8.h" -#include "rare_cp_bitvec.h" - -/* - * buffering converter - */ -mbfl_buffer_converter * -mbfl_buffer_converter_new( - const mbfl_encoding *from, - const mbfl_encoding *to, - size_t buf_initsz) -{ - mbfl_buffer_converter *convd = emalloc(sizeof(mbfl_buffer_converter)); - convd->to = to; - - /* create convert filter */ - convd->filter1 = NULL; - convd->filter2 = NULL; - if (mbfl_convert_filter_get_vtbl(from, to) != NULL) { - convd->filter1 = mbfl_convert_filter_new(from, to, mbfl_memory_device_output, NULL, &convd->device); - } else { - convd->filter2 = mbfl_convert_filter_new(&mbfl_encoding_wchar, to, mbfl_memory_device_output, NULL, &convd->device); - if (convd->filter2 != NULL) { - convd->filter1 = mbfl_convert_filter_new(from, - &mbfl_encoding_wchar, - (output_function_t)convd->filter2->filter_function, - (flush_function_t)convd->filter2->filter_flush, - convd->filter2); - if (convd->filter1 == NULL) { - mbfl_convert_filter_delete(convd->filter2); - } - } - } - if (convd->filter1 == NULL) { - efree(convd); - return NULL; - } - - mbfl_memory_device_init(&convd->device, buf_initsz, buf_initsz/4); - - return convd; -} - -void mbfl_buffer_converter_delete(mbfl_buffer_converter *convd) -{ - mbfl_convert_filter_delete(convd->filter1); - if (convd->filter2) { - mbfl_convert_filter_delete(convd->filter2); - } - mbfl_memory_device_clear(&convd->device); - efree((void*)convd); -} - -void mbfl_buffer_converter_illegal_mode(mbfl_buffer_converter *convd, int mode) -{ - if (convd->filter2) { - convd->filter2->illegal_mode = mode; - } else { - convd->filter1->illegal_mode = mode; - } -} - -void mbfl_buffer_converter_illegal_substchar(mbfl_buffer_converter *convd, uint32_t substchar) -{ - if (convd->filter2) { - convd->filter2->illegal_substchar = substchar; - } else { - convd->filter1->illegal_substchar = substchar; - } -} - -size_t mbfl_buffer_converter_feed(mbfl_buffer_converter *convd, mbfl_string *string) -{ - size_t n; - unsigned char *p; - mbfl_convert_filter *filter; - - ZEND_ASSERT(convd); - ZEND_ASSERT(string); - - mbfl_memory_device_realloc(&convd->device, convd->device.pos + string->len, string->len/4); - /* feed data */ - n = string->len; - p = string->val; - - filter = convd->filter1; - if (filter != NULL) { - while (n > 0) { - if ((*filter->filter_function)(*p++, filter) < 0) { - return p - string->val; - } - n--; - } - } - return p - string->val; -} - -void mbfl_buffer_converter_flush(mbfl_buffer_converter *convd) -{ - mbfl_convert_filter_flush(convd->filter1); -} - -mbfl_string* mbfl_buffer_converter_result(mbfl_buffer_converter *convd, mbfl_string *result) -{ - result->encoding = convd->to; - return mbfl_memory_device_result(&convd->device, result); -} - -mbfl_string* mbfl_buffer_converter_feed_result(mbfl_buffer_converter *convd, mbfl_string *string, mbfl_string *result) -{ - mbfl_buffer_converter_feed(convd, string); - mbfl_convert_filter_flush(convd->filter1); - result->encoding = convd->to; - return mbfl_memory_device_result(&convd->device, result); -} - -size_t mbfl_buffer_illegalchars(mbfl_buffer_converter *convd) -{ - size_t num_illegalchars = convd->filter1->num_illegalchar; - - if (convd->filter2) { - num_illegalchars += convd->filter2->num_illegalchar; - } - - return num_illegalchars; -} - -/* - * encoding detector - */ -static int mbfl_estimate_encoding_likelihood(int input_cp, void *void_data) -{ - mbfl_encoding_detector_data *data = void_data; - unsigned int c = input_cp; - - /* Receive wchars decoded from input string using candidate encoding. - * If the string was invalid in the candidate encoding, we assume - * it's the wrong one. Otherwise, give the candidate many 'demerits' - * for each 'rare' codepoint found, a smaller number for each ASCII - * punctuation character, and 1 for all other codepoints. - * - * The 'common' codepoints should cover the vast majority of - * codepoints we are likely to see in practice, while only covering - * a small minority of the entire Unicode encoding space. Why? - * Well, if the test string happens to be valid in an incorrect - * candidate encoding, the bogus codepoints which it decodes to will - * be more or less random. By treating the majority of codepoints as - * 'rare', we ensure that in almost all such cases, the bogus - * codepoints will include plenty of 'rares', thus giving the - * incorrect candidate encoding lots of demerits. See - * common_codepoints.txt for the actual list used. - * - * So, why give extra demerits for ASCII punctuation characters? It's - * because there are some text encodings, like UTF-7, HZ, and ISO-2022, - * which deliberately only use bytes in the ASCII range. When - * misinterpreted as ASCII/UTF-8, strings in these encodings will - * have an unusually high number of ASCII punctuation characters. - * So giving extra demerits for such characters will improve - * detection accuracy for UTF-7 and similar encodings. - * - * Finally, why 1 demerit for all other characters? That penalizes - * long strings, meaning we will tend to choose a candidate encoding - * in which the test string decodes to a smaller number of - * codepoints. That prevents single-byte encodings in which almost - * every possible input byte decodes to a 'common' codepoint from - * being favored too much. */ - if (c == MBFL_BAD_INPUT) { - data->num_illegalchars++; - } else if (c > 0xFFFF) { - data->score += 40; - } else if (c >= 0x21 && c <= 0x2F) { - data->score += 6; - } else if ((rare_codepoint_bitvec[c >> 5] >> (c & 0x1F)) & 1) { - data->score += 30; - } else { - data->score += 1; - } - return 0; -} - -mbfl_encoding_detector *mbfl_encoding_detector_new(const mbfl_encoding **elist, int elistsz, int strict) -{ - if (!elistsz) { - return NULL; - } - - mbfl_encoding_detector *identd = emalloc(sizeof(mbfl_encoding_detector)); - identd->filter_list = ecalloc(elistsz, sizeof(mbfl_convert_filter*)); - identd->filter_data = ecalloc(elistsz, sizeof(mbfl_encoding_detector_data)); - - int filter_list_size = 0; - for (int i = 0; i < elistsz; i++) { - mbfl_convert_filter *filter = mbfl_convert_filter_new(elist[i], &mbfl_encoding_wchar, - mbfl_estimate_encoding_likelihood, NULL, &identd->filter_data[filter_list_size]); - if (filter) { - identd->filter_list[filter_list_size++] = filter; - } - } - identd->filter_list_size = filter_list_size; - identd->strict = strict; - return identd; -} - -void mbfl_encoding_detector_delete(mbfl_encoding_detector *identd) -{ - for (int i = 0; i < identd->filter_list_size; i++) { - mbfl_convert_filter_delete(identd->filter_list[i]); - } - efree(identd->filter_list); - efree(identd->filter_data); - efree(identd); -} - -int mbfl_encoding_detector_feed(mbfl_encoding_detector *identd, mbfl_string *string) -{ - int num = identd->filter_list_size; - size_t n = string->len; - unsigned char *p = string->val; - int bad = 0; - - while (n--) { - for (int i = 0; i < num; i++) { - mbfl_convert_filter *filter = identd->filter_list[i]; - mbfl_encoding_detector_data *data = &identd->filter_data[i]; - if (!data->num_illegalchars) { - (*filter->filter_function)(*p, filter); - if (data->num_illegalchars) { - bad++; - } - } - } - if ((num - 1) <= bad && !identd->strict) { - return 1; - } - p++; - } - - for (int i = 0; i < num; i++) { - mbfl_convert_filter *filter = identd->filter_list[i]; - (filter->filter_flush)(filter); - } - - return 0; -} - -const mbfl_encoding *mbfl_encoding_detector_judge(mbfl_encoding_detector *identd) -{ - size_t best_score = SIZE_MAX; /* Low score is 'better' */ - const mbfl_encoding *enc = NULL; - - for (int i = 0; i < identd->filter_list_size; i++) { - mbfl_convert_filter *filter = identd->filter_list[i]; - mbfl_encoding_detector_data *data = &identd->filter_data[i]; - if (!data->num_illegalchars && data->score < best_score) { - enc = filter->from; - best_score = data->score; - } - } - - return enc; -} - -/* - * encoding converter - */ -mbfl_string * -mbfl_convert_encoding( - mbfl_string *string, - mbfl_string *result, - const mbfl_encoding *toenc) -{ - size_t n; - unsigned char *p; - mbfl_memory_device device; - mbfl_convert_filter *filter1 = NULL; - mbfl_convert_filter *filter2 = NULL; - - /* initialize */ - if (mbfl_convert_filter_get_vtbl(string->encoding, toenc) != NULL) { - filter1 = mbfl_convert_filter_new(string->encoding, toenc, mbfl_memory_device_output, 0, &device); - } else { - filter2 = mbfl_convert_filter_new(&mbfl_encoding_wchar, toenc, mbfl_memory_device_output, 0, &device); - if (filter2 != NULL) { - filter1 = mbfl_convert_filter_new(string->encoding, &mbfl_encoding_wchar, (int (*)(int, void*))filter2->filter_function, NULL, filter2); - if (filter1 == NULL) { - mbfl_convert_filter_delete(filter2); - } - } - } - if (filter1 == NULL) { - return NULL; - } - - if (filter2 != NULL) { - filter2->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR; - filter2->illegal_substchar = '?'; - } - - mbfl_memory_device_init(&device, string->len, (string->len >> 2) + 8); - - /* feed data */ - n = string->len; - p = string->val; - if (p != NULL) { - while (n > 0) { - if ((*filter1->filter_function)(*p++, filter1) < 0) { - break; - } - n--; - } - } - - mbfl_convert_filter_flush(filter1); - mbfl_convert_filter_delete(filter1); - if (filter2 != NULL) { - mbfl_convert_filter_flush(filter2); - mbfl_convert_filter_delete(filter2); - } - - return mbfl_memory_device_result(&device, result); -} - -/* - * identify encoding - */ -const mbfl_encoding *mbfl_identify_encoding(mbfl_string *string, const mbfl_encoding **elist, int elistsz, int strict) -{ - if (!elistsz) { - return NULL; - } - mbfl_encoding_detector *identd = mbfl_encoding_detector_new(elist, elistsz, strict); - mbfl_encoding_detector_feed(identd, string); - const mbfl_encoding *enc = mbfl_encoding_detector_judge(identd); - mbfl_encoding_detector_delete(identd); - return enc; -} - -/* - * strpos - */ -struct collector_strpos_data { - mbfl_convert_filter *next_filter; - mbfl_wchar_device needle; - size_t needle_len; - size_t start; - size_t output; - size_t found_pos; - size_t needle_pos; - size_t matched_pos; -}; - -static int -collector_strpos(int c, void* data) -{ - int *p, *h, *m; - ssize_t n; - struct collector_strpos_data *pc = (struct collector_strpos_data*)data; - - if (pc->output >= pc->start) { - if (c == (int)pc->needle.buffer[pc->needle_pos]) { - if (pc->needle_pos == 0) { - pc->found_pos = pc->output; /* found position */ - } - pc->needle_pos++; /* needle pointer */ - if (pc->needle_pos >= pc->needle_len) { - pc->matched_pos = pc->found_pos; /* matched position */ - pc->needle_pos--; - goto retry; - } - } else if (pc->needle_pos != 0) { -retry: - h = (int *)pc->needle.buffer; - h++; - for (;;) { - pc->found_pos++; - p = h; - m = (int *)pc->needle.buffer; - n = pc->needle_pos - 1; - while (n > 0 && *p == *m) { - n--; - p++; - m++; - } - if (n <= 0) { - if (*m != c) { - pc->needle_pos = 0; - } - break; - } else { - h++; - pc->needle_pos--; - } - } - } - } - - pc->output++; - return 0; -} - -/* - * substr_count - */ - -size_t -mbfl_substr_count( - mbfl_string *haystack, - mbfl_string *needle - ) -{ - size_t n, result = 0; - unsigned char *p; - mbfl_convert_filter *filter; - struct collector_strpos_data pc; - - /* needle is converted into wchar */ - mbfl_wchar_device_init(&pc.needle); - filter = mbfl_convert_filter_new( - needle->encoding, - &mbfl_encoding_wchar, - mbfl_wchar_device_output, 0, &pc.needle); - ZEND_ASSERT(filter); - mbfl_convert_filter_feed_string(filter, needle->val, needle->len); - mbfl_convert_filter_flush(filter); - mbfl_convert_filter_delete(filter); - pc.needle_len = pc.needle.pos; - if (pc.needle.buffer == NULL) { - return MBFL_ERROR_ENCODING; - } - if (pc.needle_len == 0) { - mbfl_wchar_device_clear(&pc.needle); - return MBFL_ERROR_EMPTY; - } - /* initialize filter and collector data */ - filter = mbfl_convert_filter_new( - haystack->encoding, - &mbfl_encoding_wchar, - collector_strpos, 0, &pc); - ZEND_ASSERT(filter); - pc.start = 0; - pc.output = 0; - pc.needle_pos = 0; - pc.found_pos = 0; - pc.matched_pos = MBFL_ERROR_NOT_FOUND; - - /* feed data */ - p = haystack->val; - n = haystack->len; - if (p != NULL) { - while (n > 0) { - if ((*filter->filter_function)(*p++, filter) < 0) { - pc.matched_pos = MBFL_ERROR_ENCODING; - break; - } - if (pc.matched_pos != MBFL_ERROR_NOT_FOUND) { - ++result; - pc.matched_pos = MBFL_ERROR_NOT_FOUND; - pc.needle_pos = 0; - } - n--; - } - } - mbfl_convert_filter_flush(filter); - mbfl_convert_filter_delete(filter); - mbfl_wchar_device_clear(&pc.needle); - - return result; -} - /* * strcut */ @@ -854,585 +386,3 @@ mbfl_strcut( return result; } - - -/* - * MIME header encode - */ -struct mime_header_encoder_data { - mbfl_convert_filter *conv1_filter; - mbfl_convert_filter *block_filter; - mbfl_convert_filter *conv2_filter; - mbfl_convert_filter *conv2_filter_backup; - mbfl_convert_filter *encod_filter; - mbfl_convert_filter *encod_filter_backup; - mbfl_memory_device outdev; - mbfl_memory_device tmpdev; - int status1; - int status2; - size_t prevpos; - size_t linehead; - size_t firstindent; - int encnamelen; - int lwsplen; - char encname[128]; - char lwsp[16]; -}; - -static int -mime_header_encoder_block_collector(int c, void *data) -{ - size_t n; - struct mime_header_encoder_data *pe = (struct mime_header_encoder_data *)data; - - switch (pe->status2) { - case 1: /* encoded word */ - pe->prevpos = pe->outdev.pos; - mbfl_convert_filter_copy(pe->conv2_filter, pe->conv2_filter_backup); - mbfl_convert_filter_copy(pe->encod_filter, pe->encod_filter_backup); - (*pe->conv2_filter->filter_function)(c, pe->conv2_filter); - (*pe->conv2_filter->filter_flush)(pe->conv2_filter); - (*pe->encod_filter->filter_flush)(pe->encod_filter); - n = pe->outdev.pos - pe->linehead + pe->firstindent; - pe->outdev.pos = pe->prevpos; - mbfl_convert_filter_copy(pe->conv2_filter_backup, pe->conv2_filter); - mbfl_convert_filter_copy(pe->encod_filter_backup, pe->encod_filter); - if (n >= 74) { - (*pe->conv2_filter->filter_flush)(pe->conv2_filter); - (*pe->encod_filter->filter_flush)(pe->encod_filter); - mbfl_memory_device_strncat(&pe->outdev, "\x3f\x3d", 2); /* ?= */ - mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen); - pe->linehead = pe->outdev.pos; - pe->firstindent = 0; - mbfl_memory_device_strncat(&pe->outdev, pe->encname, pe->encnamelen); - c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter); - } else { - c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter); - } - break; - - default: - mbfl_memory_device_strncat(&pe->outdev, pe->encname, pe->encnamelen); - c = (*pe->conv2_filter->filter_function)(c, pe->conv2_filter); - pe->status2 = 1; - break; - } - - return 0; -} - -static int -mime_header_encoder_collector(int c, void *data) -{ - static int qp_table[256] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 */ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ - 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 1, 0, 1, /* 0x10 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0x50 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0x70 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xA0 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xB0 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xC0 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xD0 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xE0 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* 0xF0 */ - }; - - size_t n; - struct mime_header_encoder_data *pe = (struct mime_header_encoder_data *)data; - - switch (pe->status1) { - case 11: /* encoded word */ - (*pe->block_filter->filter_function)(c, pe->block_filter); - break; - - default: /* ASCII */ - if (c <= 0x00ff && !qp_table[(c & 0xff)]) { /* ordinary characters */ - mbfl_memory_device_output(c, &pe->tmpdev); - pe->status1 = 1; - } else if (pe->status1 == 0 && c == 0x20) { /* repeat SPACE */ - mbfl_memory_device_output(c, &pe->tmpdev); - } else { - if (pe->tmpdev.pos < 74 && c == 0x20) { - n = pe->outdev.pos - pe->linehead + pe->tmpdev.pos + pe->firstindent; - if (n > 74) { - mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen); /* LWSP */ - pe->linehead = pe->outdev.pos; - pe->firstindent = 0; - } else if (pe->outdev.pos > 0) { - mbfl_memory_device_output(0x20, &pe->outdev); - } - mbfl_memory_device_devcat(&pe->outdev, &pe->tmpdev); - mbfl_memory_device_reset(&pe->tmpdev); - pe->status1 = 0; - } else { - n = pe->outdev.pos - pe->linehead + pe->encnamelen + pe->firstindent; - if (n > 60) { - mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen); /* LWSP */ - pe->linehead = pe->outdev.pos; - pe->firstindent = 0; - } else if (pe->outdev.pos > 0) { - mbfl_memory_device_output(0x20, &pe->outdev); - } - mbfl_convert_filter_devcat(pe->block_filter, &pe->tmpdev); - mbfl_memory_device_reset(&pe->tmpdev); - (*pe->block_filter->filter_function)(c, pe->block_filter); - pe->status1 = 11; - } - } - break; - } - - return 0; -} - -mbfl_string * -mime_header_encoder_result(struct mime_header_encoder_data *pe, mbfl_string *result) -{ - if (pe->status1 >= 10) { - (*pe->conv2_filter->filter_flush)(pe->conv2_filter); - (*pe->encod_filter->filter_flush)(pe->encod_filter); - mbfl_memory_device_strncat(&pe->outdev, "\x3f\x3d", 2); /* ?= */ - } else if (pe->tmpdev.pos > 0) { - if (pe->outdev.pos > 0) { - if ((pe->outdev.pos - pe->linehead + pe->tmpdev.pos + pe->firstindent) > 74) { - mbfl_memory_device_strncat(&pe->outdev, pe->lwsp, pe->lwsplen); - } else { - mbfl_memory_device_output(0x20, &pe->outdev); - } - } - mbfl_memory_device_devcat(&pe->outdev, &pe->tmpdev); - } - mbfl_memory_device_reset(&pe->tmpdev); - pe->prevpos = 0; - pe->linehead = 0; - pe->status1 = 0; - pe->status2 = 0; - - return mbfl_memory_device_result(&pe->outdev, result); -} - -struct mime_header_encoder_data* -mime_header_encoder_new( - const mbfl_encoding *incode, - const mbfl_encoding *outcode, - const mbfl_encoding *transenc) -{ - size_t n; - const char *s; - struct mime_header_encoder_data *pe; - - /* get output encoding and check MIME charset name */ - if (outcode->mime_name == NULL || outcode->mime_name[0] == '\0') { - return NULL; - } - - pe = emalloc(sizeof(struct mime_header_encoder_data)); - mbfl_memory_device_init(&pe->outdev, 0, 0); - mbfl_memory_device_init(&pe->tmpdev, 0, 0); - pe->prevpos = 0; - pe->linehead = 0; - pe->firstindent = 0; - pe->status1 = 0; - pe->status2 = 0; - - /* make the encoding description string exp. "=?ISO-2022-JP?B?" */ - n = 0; - pe->encname[n++] = 0x3d; - pe->encname[n++] = 0x3f; - s = outcode->mime_name; - while (*s) { - pe->encname[n++] = *s++; - } - pe->encname[n++] = 0x3f; - if (transenc->no_encoding == mbfl_no_encoding_qprint) { - pe->encname[n++] = 0x51; - } else { - pe->encname[n++] = 0x42; - transenc = &mbfl_encoding_base64; - } - pe->encname[n++] = 0x3f; - pe->encname[n] = '\0'; - pe->encnamelen = n; - - n = 0; - pe->lwsp[n++] = 0x0d; - pe->lwsp[n++] = 0x0a; - pe->lwsp[n++] = 0x20; - pe->lwsp[n] = '\0'; - pe->lwsplen = n; - - /* transfer encode filter */ - pe->encod_filter = mbfl_convert_filter_new(outcode, transenc, mbfl_memory_device_output, 0, &(pe->outdev)); - pe->encod_filter_backup = mbfl_convert_filter_new(outcode, transenc, mbfl_memory_device_output, 0, &(pe->outdev)); - - /* Output code filter */ - pe->conv2_filter = mbfl_convert_filter_new(&mbfl_encoding_wchar, outcode, mbfl_filter_output_pipe, 0, pe->encod_filter); - pe->conv2_filter_backup = mbfl_convert_filter_new(&mbfl_encoding_wchar, outcode, mbfl_filter_output_pipe, 0, pe->encod_filter); - - /* encoded block filter */ - pe->block_filter = mbfl_convert_filter_new(&mbfl_encoding_wchar, &mbfl_encoding_wchar, mime_header_encoder_block_collector, 0, pe); - - /* Input code filter */ - pe->conv1_filter = mbfl_convert_filter_new(incode, &mbfl_encoding_wchar, mime_header_encoder_collector, 0, pe); - - if (pe->encod_filter == NULL || - pe->encod_filter_backup == NULL || - pe->conv2_filter == NULL || - pe->conv2_filter_backup == NULL || - pe->conv1_filter == NULL) { - mime_header_encoder_delete(pe); - return NULL; - } - - if (transenc->no_encoding == mbfl_no_encoding_qprint) { - pe->encod_filter->status |= MBFL_QPRINT_STS_MIME_HEADER; - pe->encod_filter_backup->status |= MBFL_QPRINT_STS_MIME_HEADER; - } else { - pe->encod_filter->status |= MBFL_BASE64_STS_MIME_HEADER; - pe->encod_filter_backup->status |= MBFL_BASE64_STS_MIME_HEADER; - } - - return pe; -} - -void -mime_header_encoder_delete(struct mime_header_encoder_data *pe) -{ - if (pe) { - mbfl_convert_filter_delete(pe->conv1_filter); - mbfl_convert_filter_delete(pe->block_filter); - mbfl_convert_filter_delete(pe->conv2_filter); - mbfl_convert_filter_delete(pe->conv2_filter_backup); - mbfl_convert_filter_delete(pe->encod_filter); - mbfl_convert_filter_delete(pe->encod_filter_backup); - mbfl_memory_device_clear(&pe->outdev); - mbfl_memory_device_clear(&pe->tmpdev); - efree((void*)pe); - } -} - -mbfl_string * -mbfl_mime_header_encode( - mbfl_string *string, - mbfl_string *result, - const mbfl_encoding *outcode, - const mbfl_encoding *encoding, - const char *linefeed, - int indent) -{ - size_t n; - unsigned char *p; - struct mime_header_encoder_data *pe; - - mbfl_string_init(result); - result->encoding = &mbfl_encoding_ascii; - - pe = mime_header_encoder_new(string->encoding, outcode, encoding); - if (pe == NULL) { - return NULL; - } - - if (linefeed != NULL) { - n = 0; - while (*linefeed && n < 8) { - pe->lwsp[n++] = *linefeed++; - } - pe->lwsp[n++] = 0x20; - pe->lwsp[n] = '\0'; - pe->lwsplen = n; - } - if (indent > 0 && indent < 74) { - pe->firstindent = indent; - } - - n = string->len; - p = string->val; - while (n > 0) { - (*pe->conv1_filter->filter_function)(*p++, pe->conv1_filter); - n--; - } - - result = mime_header_encoder_result(pe, result); - mime_header_encoder_delete(pe); - - return result; -} - - -/* - * MIME header decode - */ -struct mime_header_decoder_data { - mbfl_convert_filter *deco_filter; - mbfl_convert_filter *conv1_filter; - mbfl_convert_filter *conv2_filter; - mbfl_memory_device outdev; - mbfl_memory_device tmpdev; - size_t cspos; - int status; - const mbfl_encoding *encoding; - const mbfl_encoding *incode; - const mbfl_encoding *outcode; -}; - -static int -mime_header_decoder_collector(int c, void* data) -{ - const mbfl_encoding *encoding; - struct mime_header_decoder_data *pd = (struct mime_header_decoder_data*)data; - - switch (pd->status) { - case 1: - if (c == 0x3f) { /* ? */ - mbfl_memory_device_output(c, &pd->tmpdev); - pd->cspos = pd->tmpdev.pos; - pd->status = 2; - } else { - mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev); - mbfl_memory_device_reset(&pd->tmpdev); - if (c == 0x3d) { /* = */ - mbfl_memory_device_output(c, &pd->tmpdev); - } else if (c == 0x0d || c == 0x0a) { /* CR or LF */ - pd->status = 9; - } else { - (*pd->conv1_filter->filter_function)(c, pd->conv1_filter); - pd->status = 0; - } - } - break; - case 2: /* store charset string */ - if (c == 0x3f) { /* ? */ - /* identify charset */ - mbfl_memory_device_output('\0', &pd->tmpdev); - encoding = mbfl_name2encoding((const char *)&pd->tmpdev.buffer[pd->cspos]); - if (encoding != NULL) { - pd->incode = encoding; - pd->status = 3; - } - mbfl_memory_device_unput(&pd->tmpdev); - mbfl_memory_device_output(c, &pd->tmpdev); - } else { - mbfl_memory_device_output(c, &pd->tmpdev); - if (pd->tmpdev.pos > 100) { /* too long charset string */ - pd->status = 0; - } else if (c == 0x0d || c == 0x0a) { /* CR or LF */ - mbfl_memory_device_unput(&pd->tmpdev); - pd->status = 9; - } - if (pd->status != 2) { - mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev); - mbfl_memory_device_reset(&pd->tmpdev); - } - } - break; - case 3: /* identify encoding */ - mbfl_memory_device_output(c, &pd->tmpdev); - if (c == 0x42 || c == 0x62) { /* 'B' or 'b' */ - pd->encoding = &mbfl_encoding_base64; - pd->status = 4; - } else if (c == 0x51 || c == 0x71) { /* 'Q' or 'q' */ - pd->encoding = &mbfl_encoding_qprint; - pd->status = 4; - } else { - if (c == 0x0d || c == 0x0a) { /* CR or LF */ - mbfl_memory_device_unput(&pd->tmpdev); - pd->status = 9; - } else { - pd->status = 0; - } - mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev); - mbfl_memory_device_reset(&pd->tmpdev); - } - break; - case 4: /* reset filter */ - mbfl_memory_device_output(c, &pd->tmpdev); - if (c == 0x3f) { /* ? */ - /* charset convert filter */ - mbfl_convert_filter_reset(pd->conv1_filter, pd->incode, &mbfl_encoding_wchar); - /* decode filter */ - mbfl_convert_filter_reset(pd->deco_filter, pd->encoding, &mbfl_encoding_8bit); - pd->status = 5; - } else { - if (c == 0x0d || c == 0x0a) { /* CR or LF */ - mbfl_memory_device_unput(&pd->tmpdev); - pd->status = 9; - } else { - pd->status = 0; - } - mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev); - } - mbfl_memory_device_reset(&pd->tmpdev); - break; - case 5: /* encoded block */ - if (c == 0x3f) { /* ? */ - pd->status = 6; - } else { - (*pd->deco_filter->filter_function)(c, pd->deco_filter); - } - break; - case 6: /* check end position */ - if (c == 0x3d) { /* = */ - /* flush and reset filter */ - (*pd->deco_filter->filter_flush)(pd->deco_filter); - (*pd->conv1_filter->filter_flush)(pd->conv1_filter); - mbfl_convert_filter_reset(pd->conv1_filter, &mbfl_encoding_ascii, &mbfl_encoding_wchar); - pd->status = 7; - } else { - (*pd->deco_filter->filter_function)(0x3f, pd->deco_filter); - if (c != 0x3f) { /* ? */ - (*pd->deco_filter->filter_function)(c, pd->deco_filter); - pd->status = 5; - } - } - break; - case 7: /* after encoded block */ - if (c == 0x0d || c == 0x0a) { /* CR LF */ - pd->status = 8; - } else { - mbfl_memory_device_output(c, &pd->tmpdev); - if (c == 0x3d) { /* = */ - pd->status = 1; - } else if (c != 0x20 && c != 0x09) { /* not space */ - mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev); - mbfl_memory_device_reset(&pd->tmpdev); - pd->status = 0; - } - } - break; - case 8: /* folding */ - case 9: /* folding */ - if (c != 0x0d && c != 0x0a && c != 0x20 && c != 0x09) { - if (c == 0x3d) { /* = */ - if (pd->status == 8) { - mbfl_memory_device_output(0x20, &pd->tmpdev); /* SPACE */ - } else { - (*pd->conv1_filter->filter_function)(0x20, pd->conv1_filter); - } - mbfl_memory_device_output(c, &pd->tmpdev); - pd->status = 1; - } else { - mbfl_memory_device_output(0x20, &pd->tmpdev); - mbfl_memory_device_output(c, &pd->tmpdev); - mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev); - mbfl_memory_device_reset(&pd->tmpdev); - pd->status = 0; - } - } - break; - default: /* non encoded block */ - if (c == 0x0d || c == 0x0a) { /* CR LF */ - pd->status = 9; - } else if (c == 0x3d) { /* = */ - mbfl_memory_device_output(c, &pd->tmpdev); - pd->status = 1; - } else { - (*pd->conv1_filter->filter_function)(c, pd->conv1_filter); - } - break; - } - - return 0; -} - -mbfl_string * -mime_header_decoder_result(struct mime_header_decoder_data *pd, mbfl_string *result) -{ - switch (pd->status) { - case 1: - case 2: - case 3: - case 4: - case 7: - case 8: - case 9: - mbfl_convert_filter_devcat(pd->conv1_filter, &pd->tmpdev); - break; - case 5: - case 6: - (*pd->deco_filter->filter_flush)(pd->deco_filter); - (*pd->conv1_filter->filter_flush)(pd->conv1_filter); - break; - } - (*pd->conv2_filter->filter_flush)(pd->conv2_filter); - mbfl_memory_device_reset(&pd->tmpdev); - pd->status = 0; - - return mbfl_memory_device_result(&pd->outdev, result); -} - -struct mime_header_decoder_data* -mime_header_decoder_new(const mbfl_encoding *outcode) -{ - struct mime_header_decoder_data *pd = emalloc(sizeof(struct mime_header_decoder_data)); - - mbfl_memory_device_init(&pd->outdev, 0, 0); - mbfl_memory_device_init(&pd->tmpdev, 0, 0); - pd->cspos = 0; - pd->status = 0; - pd->encoding = &mbfl_encoding_8bit; - pd->incode = &mbfl_encoding_ascii; - pd->outcode = outcode; - /* charset convert filter */ - pd->conv2_filter = mbfl_convert_filter_new(&mbfl_encoding_wchar, pd->outcode, mbfl_memory_device_output, 0, &pd->outdev); - pd->conv1_filter = mbfl_convert_filter_new(pd->incode, &mbfl_encoding_wchar, mbfl_filter_output_pipe, 0, pd->conv2_filter); - /* decode filter */ - pd->deco_filter = mbfl_convert_filter_new(pd->encoding, &mbfl_encoding_8bit, mbfl_filter_output_pipe, 0, pd->conv1_filter); - - if (pd->conv1_filter == NULL || pd->conv2_filter == NULL || pd->deco_filter == NULL) { - mime_header_decoder_delete(pd); - return NULL; - } - - return pd; -} - -void -mime_header_decoder_delete(struct mime_header_decoder_data *pd) -{ - if (pd) { - mbfl_convert_filter_delete(pd->conv2_filter); - mbfl_convert_filter_delete(pd->conv1_filter); - mbfl_convert_filter_delete(pd->deco_filter); - mbfl_memory_device_clear(&pd->outdev); - mbfl_memory_device_clear(&pd->tmpdev); - efree((void*)pd); - } -} - -mbfl_string * -mbfl_mime_header_decode( - mbfl_string *string, - mbfl_string *result, - const mbfl_encoding *outcode) -{ - size_t n; - unsigned char *p; - struct mime_header_decoder_data *pd; - - mbfl_string_init(result); - result->encoding = outcode; - - pd = mime_header_decoder_new(outcode); - if (pd == NULL) { - return NULL; - } - - /* feed data */ - n = string->len; - p = string->val; - while (n > 0) { - mime_header_decoder_collector(*p++, pd); - n--; - } - - result = mime_header_decoder_result(pd, result); - mime_header_decoder_delete(pd); - - return result; -} diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter.h b/ext/mbstring/libmbfl/mbfl/mbfilter.h index b986aaaee6bb7..786bab677916f 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter.h +++ b/ext/mbstring/libmbfl/mbfl/mbfilter.h @@ -112,13 +112,11 @@ #define MBFL_VERSION_MINOR 3 #define MBFL_VERSION_TEENY 2 -/* - * convert filter - */ #define MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE 0 #define MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR 1 #define MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG 2 #define MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY 3 +#define MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8 4 /* For internal use only; deliberately uses invalid UTF-8 byte sequence as error marker */ /* * convenience macros @@ -127,64 +125,6 @@ #define MIN(a,b) ((a)<(b)?(a):(b)) #endif -/* - * buffering converter - */ -typedef struct _mbfl_buffer_converter mbfl_buffer_converter; - -struct _mbfl_buffer_converter { - mbfl_convert_filter *filter1; - mbfl_convert_filter *filter2; - mbfl_memory_device device; - const mbfl_encoding *to; -}; - -MBFLAPI extern mbfl_buffer_converter * mbfl_buffer_converter_new(const mbfl_encoding *from, const mbfl_encoding *to, size_t buf_initsz); -MBFLAPI extern void mbfl_buffer_converter_delete(mbfl_buffer_converter *convd); -MBFLAPI extern void mbfl_buffer_converter_illegal_mode(mbfl_buffer_converter *convd, int mode); -MBFLAPI extern void mbfl_buffer_converter_illegal_substchar(mbfl_buffer_converter *convd, uint32_t substchar); -MBFLAPI extern size_t mbfl_buffer_converter_feed(mbfl_buffer_converter *convd, mbfl_string *string); -MBFLAPI extern void mbfl_buffer_converter_flush(mbfl_buffer_converter *convd); -MBFLAPI extern mbfl_string * mbfl_buffer_converter_result(mbfl_buffer_converter *convd, mbfl_string *result); -MBFLAPI extern mbfl_string * mbfl_buffer_converter_feed_result(mbfl_buffer_converter *convd, mbfl_string *string, mbfl_string *result); -MBFLAPI extern size_t mbfl_buffer_illegalchars(mbfl_buffer_converter *convd); - -/* - * encoding detector - */ -typedef struct _mbfl_encoding_detector mbfl_encoding_detector; - -typedef struct { - size_t num_illegalchars; - size_t score; -} mbfl_encoding_detector_data; - -struct _mbfl_encoding_detector { - mbfl_convert_filter **filter_list; - mbfl_encoding_detector_data *filter_data; - int filter_list_size; - int strict; -}; - -MBFLAPI extern mbfl_encoding_detector * mbfl_encoding_detector_new(const mbfl_encoding **elist, int elistsz, int strict); -MBFLAPI extern void mbfl_encoding_detector_delete(mbfl_encoding_detector *identd); -MBFLAPI extern int mbfl_encoding_detector_feed(mbfl_encoding_detector *identd, mbfl_string *string); -MBFLAPI extern const mbfl_encoding *mbfl_encoding_detector_judge(mbfl_encoding_detector *identd); - - -/* - * encoding converter - */ -MBFLAPI extern mbfl_string * -mbfl_convert_encoding(mbfl_string *string, mbfl_string *result, const mbfl_encoding *toenc); - - -/* - * identify encoding - */ -MBFLAPI extern const mbfl_encoding * -mbfl_identify_encoding(mbfl_string *string, const mbfl_encoding **elist, int elistsz, int strict); - /* Lengths -1 through -16 are reserved for error return values */ static inline int mbfl_is_error(size_t len) { return len >= (size_t) -16; @@ -195,12 +135,6 @@ static inline int mbfl_is_error(size_t len) { #define MBFL_ERROR_EMPTY ((size_t) -8) #define MBFL_ERROR_OFFSET ((size_t) -16) -/* - * substr_count - */ -MBFLAPI extern size_t -mbfl_substr_count(mbfl_string *haystack, mbfl_string *needle); - /* * If specified as length, the substr until the end of the string is taken. */ @@ -212,49 +146,4 @@ mbfl_substr_count(mbfl_string *haystack, mbfl_string *needle); MBFLAPI extern mbfl_string * mbfl_strcut(mbfl_string *string, mbfl_string *result, size_t from, size_t length); -/* - * MIME header encode - */ -struct mime_header_encoder_data; /* forward declaration */ - -MBFLAPI extern struct mime_header_encoder_data * -mime_header_encoder_new( - const mbfl_encoding *incode, - const mbfl_encoding *outcode, - const mbfl_encoding *encoding); - -MBFLAPI extern void -mime_header_encoder_delete(struct mime_header_encoder_data *pe); - -MBFLAPI extern mbfl_string * -mime_header_encoder_result(struct mime_header_encoder_data *pe, mbfl_string *result); - -MBFLAPI extern mbfl_string * -mbfl_mime_header_encode( - mbfl_string *string, mbfl_string *result, - const mbfl_encoding *outcode, - const mbfl_encoding *encoding, - const char *linefeed, - int indent); - -/* - * MIME header decode - */ -struct mime_header_decoder_data; /* forward declaration */ - -MBFLAPI extern struct mime_header_decoder_data * -mime_header_decoder_new(const mbfl_encoding *outcode); - -MBFLAPI extern void -mime_header_decoder_delete(struct mime_header_decoder_data *pd); - -MBFLAPI extern mbfl_string * -mime_header_decoder_result(struct mime_header_decoder_data *pd, mbfl_string *result); - -MBFLAPI extern mbfl_string * -mbfl_mime_header_decode( - mbfl_string *string, - mbfl_string *result, - const mbfl_encoding *outcode); - #endif /* MBFL_MBFILTER_H */ diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c b/ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c index 8fe51c9fd4cbb..43db2f7f5b20b 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c @@ -51,7 +51,8 @@ const mbfl_encoding mbfl_encoding_8bit = { &vtbl_8bit_wchar, &vtbl_wchar_8bit, mb_8bit_to_wchar, - mb_wchar_to_8bit + mb_wchar_to_8bit, + NULL }; const struct mbfl_convert_vtbl vtbl_8bit_wchar = { diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter_pass.c b/ext/mbstring/libmbfl/mbfl/mbfilter_pass.c index 3fb7e991141cd..b932603e1c5f4 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter_pass.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter_pass.c @@ -44,6 +44,7 @@ const mbfl_encoding mbfl_encoding_pass = { NULL, NULL, NULL, + NULL, NULL }; diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c b/ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c index 5472d792a83cb..93a8d91e7a552 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by Moriyoshi Koizumi on 20 Dec 2002. The file * mbfilter.c is included in this package . * @@ -42,5 +42,6 @@ const mbfl_encoding mbfl_encoding_wchar = { NULL, NULL, NULL, + NULL, NULL }; diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_consts.h b/ext/mbstring/libmbfl/mbfl/mbfl_consts.h index 36588ad259311..c5fa66f6e6ece 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_consts.h +++ b/ext/mbstring/libmbfl/mbfl/mbfl_consts.h @@ -44,7 +44,10 @@ /* Marker for an erroneous input byte (or sequence of bytes) */ #define MBFL_BAD_INPUT (-1) -#define MBFL_QPRINT_STS_MIME_HEADER 0x1000000 -#define MBFL_BASE64_STS_MIME_HEADER 0x1000000 +#define MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE 0 +#define MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR 1 +#define MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG 2 +#define MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY 3 +#define MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8 4 /* For internal use only; deliberately uses invalid UTF-8 byte sequence as error marker */ #endif /* MBFL_CONSTS_H */ diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_convert.c b/ext/mbstring/libmbfl/mbfl/mbfl_convert.c index bda704a529bab..edad3a3b57599 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_convert.c +++ b/ext/mbstring/libmbfl/mbfl/mbfl_convert.c @@ -365,7 +365,7 @@ zend_string* mb_fast_convert(unsigned char *in, size_t in_len, const mbfl_encodi } *num_errors = buf.errors; - return mb_convert_buf_result(&buf); + return mb_convert_buf_result(&buf, to); } static uint32_t* convert_cp_to_hex(uint32_t cp, uint32_t *out) @@ -394,9 +394,15 @@ static size_t mb_illegal_marker(uint32_t bad_cp, uint32_t *out, unsigned int err { uint32_t *start = out; - if (bad_cp == MBFL_BAD_INPUT && err_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) { - *out++ = replacement_char; + if (bad_cp == MBFL_BAD_INPUT) { + /* Input string contained a byte sequence which was invalid in the 'from' encoding + * Unless the error handling mode is set to NONE, insert the replacement character */ + if (err_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) { + *out++ = replacement_char; + } } else { + /* Input string contained a byte sequence which was valid in the 'from' encoding, + * but decoded to a Unicode codepoint which cannot be represented in the 'to' encoding */ switch (err_mode) { case MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR: *out++ = replacement_char; @@ -427,6 +433,17 @@ void mb_illegal_output(uint32_t bad_cp, mb_from_wchar_fn fn, mb_convert_buf* buf uint32_t repl_char = buf->replacement_char; unsigned int err_mode = buf->error_mode; + if (err_mode == MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8) { + /* This mode is for internal use only, when converting a string to + * UTF-8 before searching it; it uses a byte which is illegal in + * UTF-8 as an error marker. This ensures that error markers will + * never 'accidentally' match valid text, as could happen when a + * character like '?' is used as an error marker. */ + MB_CONVERT_BUF_ENSURE(buf, buf->out, buf->limit, 1); + buf->out = mb_convert_buf_add(buf->out, 0xFF); + return; + } + size_t len = mb_illegal_marker(bad_cp, temp, err_mode, repl_char); /* Avoid infinite loop if `fn` is not able to handle `repl_char` */ diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.c b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.c index 2495f7447aa3a..1d44756ee051a 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.c +++ b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.c @@ -212,12 +212,6 @@ const mbfl_encoding *mbfl_no2encoding(enum mbfl_no_encoding no_encoding) return NULL; } -enum mbfl_no_encoding mbfl_name2no_encoding(const char *name) -{ - const mbfl_encoding *encoding = mbfl_name2encoding(name); - return encoding ? encoding->no_encoding : mbfl_no_encoding_invalid; -} - const char *mbfl_no_encoding2name(enum mbfl_no_encoding no_encoding) { const mbfl_encoding *encoding = mbfl_no2encoding(no_encoding); @@ -229,11 +223,6 @@ const mbfl_encoding **mbfl_get_supported_encodings(void) return mbfl_encoding_ptr_list; } -const char *mbfl_no2preferred_mime_name(enum mbfl_no_encoding no_encoding) -{ - return mbfl_encoding_preferred_mime_name(mbfl_no2encoding(no_encoding)); -} - const char *mbfl_encoding_preferred_mime_name(const mbfl_encoding *encoding) { if (encoding->mime_name && encoding->mime_name[0] != '\0') { diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h index e5ae285098ea0..b25ec71eef9de 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h +++ b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h @@ -32,6 +32,7 @@ #define MBFL_ENCODING_H #include "mbfl_defs.h" +#include "mbfl_consts.h" #include "zend.h" enum mbfl_no_encoding { @@ -143,6 +144,7 @@ typedef struct { typedef size_t (*mb_to_wchar_fn)(unsigned char **in, size_t *in_len, uint32_t *out, size_t out_len, unsigned int *state); typedef void (*mb_from_wchar_fn)(uint32_t *in, size_t in_len, mb_convert_buf *out, bool end); +typedef bool (*mb_check_fn)(unsigned char *in, size_t in_len); /* When converting encoded text to a buffer of wchars (Unicode codepoints) using `mb_to_wchar_fn`, * the buffer must be at least this size (to work with all supported text encodings) */ @@ -161,17 +163,17 @@ static inline void mb_convert_buf_init(mb_convert_buf *buf, size_t initsize, uin #define MB_CONVERT_BUF_ENSURE(buf, out, limit, needed) \ ZEND_ASSERT(out <= limit); \ if ((limit - out) < (needed)) { \ - size_t oldsize = limit - (unsigned char*)ZSTR_VAL(buf->str); \ + size_t oldsize = limit - (unsigned char*)ZSTR_VAL((buf)->str); \ size_t newsize = oldsize + MAX(oldsize >> 1, needed); \ - zend_string *newstr = erealloc(buf->str, _ZSTR_STRUCT_SIZE(newsize)); \ - out = (unsigned char*)ZSTR_VAL(newstr) + (out - (unsigned char*)ZSTR_VAL(buf->str)); \ + zend_string *newstr = erealloc((buf)->str, _ZSTR_STRUCT_SIZE(newsize)); \ + out = (unsigned char*)ZSTR_VAL(newstr) + (out - (unsigned char*)ZSTR_VAL((buf)->str)); \ limit = (unsigned char*)ZSTR_VAL(newstr) + newsize; \ - buf->str = newstr; \ + (buf)->str = newstr; \ } -#define MB_CONVERT_BUF_STORE(buf, _out, _limit) buf->out = _out; buf->limit = _limit +#define MB_CONVERT_BUF_STORE(buf, _out, _limit) (buf)->out = _out; (buf)->limit = _limit -#define MB_CONVERT_BUF_LOAD(buf, _out, _limit) _out = buf->out; _limit = buf->limit +#define MB_CONVERT_BUF_LOAD(buf, _out, _limit) _out = (buf)->out; _limit = (buf)->limit #define MB_CONVERT_ERROR(buf, out, limit, bad_cp, conv_fn) \ MB_CONVERT_BUF_STORE(buf, out, limit); \ @@ -208,7 +210,23 @@ static inline unsigned char* mb_convert_buf_add4(unsigned char *out, char c1, ch return out; } -static inline zend_string* mb_convert_buf_result(mb_convert_buf *buf) +static inline unsigned char* mb_convert_buf_appends(unsigned char *out, const char *s) +{ + while (*s) { + *out++ = *s++; + } + return out; +} + +static inline unsigned char* mb_convert_buf_appendn(unsigned char *out, const char *s, size_t n) +{ + while (n--) { + *out++ = *s++; + } + return out; +} + +static inline zend_string* mb_convert_buf_result_raw(mb_convert_buf *buf) { ZEND_ASSERT(buf->out <= buf->limit); zend_string *ret = buf->str; @@ -232,14 +250,42 @@ typedef struct { const struct mbfl_convert_vtbl *output_filter; mb_to_wchar_fn to_wchar; mb_from_wchar_fn from_wchar; + mb_check_fn check; } mbfl_encoding; +extern const mbfl_encoding mbfl_encoding_utf8; + +static inline zend_string* mb_convert_buf_result(mb_convert_buf *buf, const mbfl_encoding *enc) +{ + zend_string *ret = mb_convert_buf_result_raw(buf); + if (enc == &mbfl_encoding_utf8 && buf->error_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8) { + GC_ADD_FLAGS(ret, IS_STR_VALID_UTF8); + } + return ret; +} + +/* Used if we initialize an `mb_convert_buf` but then discover we don't actually + * want to return `zend_string` */ +static inline void mb_convert_buf_free(mb_convert_buf *buf) +{ + efree(buf->str); +} + +static inline size_t mb_convert_buf_len(mb_convert_buf *buf) +{ + return buf->out - (unsigned char*)ZSTR_VAL(buf->str); +} + +static inline void mb_convert_buf_reset(mb_convert_buf *buf, size_t len) +{ + buf->out = (unsigned char*)ZSTR_VAL(buf->str) + len; + ZEND_ASSERT(buf->out <= buf->limit); +} + MBFLAPI extern const mbfl_encoding *mbfl_name2encoding(const char *name); MBFLAPI extern const mbfl_encoding *mbfl_no2encoding(enum mbfl_no_encoding no_encoding); -MBFLAPI extern enum mbfl_no_encoding mbfl_name2no_encoding(const char *name); MBFLAPI extern const mbfl_encoding **mbfl_get_supported_encodings(void); MBFLAPI extern const char *mbfl_no_encoding2name(enum mbfl_no_encoding no_encoding); -MBFLAPI extern const char *mbfl_no2preferred_mime_name(enum mbfl_no_encoding no_encoding); MBFLAPI extern const char *mbfl_encoding_preferred_mime_name(const mbfl_encoding *encoding); #endif /* MBFL_ENCODING_H */ diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_filter_output.c b/ext/mbstring/libmbfl/mbfl/mbfl_filter_output.c index aab0a17daa96e..41572faa568e8 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_filter_output.c +++ b/ext/mbstring/libmbfl/mbfl/mbfl_filter_output.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by Moriyoshi Koizumi on 20 Dec 2002. The file * mbfilter.c is included in this package . * diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_language.c b/ext/mbstring/libmbfl/mbfl/mbfl_language.c index ba1855aed109e..05be288ab77f8 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_language.c +++ b/ext/mbstring/libmbfl/mbfl/mbfl_language.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by Moriyoshi Koizumi on 20 Dec 2002. The file * mbfilter.c is included in this package . * diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_string.c b/ext/mbstring/libmbfl/mbfl/mbfl_string.c index 760634e65d06d..6485ceac74db8 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_string.c +++ b/ext/mbstring/libmbfl/mbfl/mbfl_string.c @@ -22,7 +22,7 @@ * */ /* - * The source code included in this files was separated from mbfilter.c + * The source code included in this file was separated from mbfilter.c * by Moriyoshi Koizumi on 20 Dec 2002. The file * mbfilter.c is included in this package . * diff --git a/ext/mbstring/mb_gpc.c b/ext/mbstring/mb_gpc.c index 99a8ff903a1e4..1ffe0af56bc7e 100644 --- a/ext/mbstring/mb_gpc.c +++ b/ext/mbstring/mb_gpc.c @@ -177,7 +177,6 @@ const mbfl_encoding *_php_mb_encoding_handler_ex(const php_mb_encoding_handler_i size_t n, num = 1, *len_list = NULL; size_t new_val_len; const mbfl_encoding *from_encoding = NULL; - mbfl_encoding_detector *identd = NULL; if (!res || *res == '\0') { goto out; @@ -235,23 +234,7 @@ const mbfl_encoding *_php_mb_encoding_handler_ex(const php_mb_encoding_handler_i } else if (info->num_from_encodings == 1) { from_encoding = info->from_encodings[0]; } else { - /* auto detect */ - from_encoding = NULL; - identd = mbfl_encoding_detector_new(info->from_encodings, info->num_from_encodings, MBSTRG(strict_detection)); - if (identd != NULL) { - n = 0; - while (n < num) { - mbfl_string string; - string.val = (unsigned char *)val_list[n]; - string.len = len_list[n]; - if (mbfl_encoding_detector_feed(identd, &string)) { - break; - } - n++; - } - from_encoding = mbfl_encoding_detector_judge(identd); - mbfl_encoding_detector_delete(identd); - } + from_encoding = mb_guess_encoding_for_strings((const unsigned char**)val_list, len_list, num, info->from_encodings, info->num_from_encodings, MBSTRG(strict_detection)); if (!from_encoding) { if (info->report_errors) { php_error_docref(NULL, E_WARNING, "Unable to detect encoding"); diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index a73247cb64eaa..73dea4e5c6b81 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -18,6 +18,8 @@ */ /* {{{ includes */ +#include + #include "libmbfl/config.h" #include "php.h" #include "php_ini.h" @@ -41,8 +43,10 @@ #include "libmbfl/filters/mbfilter_uuencode.h" #include "libmbfl/filters/mbfilter_ucs4.h" #include "libmbfl/filters/mbfilter_utf8.h" +#include "libmbfl/filters/mbfilter_utf16.h" #include "libmbfl/filters/mbfilter_singlebyte.h" #include "libmbfl/filters/translit_kana_jisx0201_jisx0208.h" +#include "libmbfl/filters/unicode_prop.h" #include "php_variables.h" #include "php_globals.h" @@ -58,8 +62,12 @@ # include "php_mbregex.h" #endif +#include "zend_smart_str.h" #include "zend_multibyte.h" #include "mbstring_arginfo.h" + +#include "rare_cp_bitvec.h" + /* }}} */ /* {{{ prototypes */ @@ -82,6 +90,10 @@ static inline bool php_mb_is_no_encoding_utf8(enum mbfl_no_encoding no_enc); static bool mb_check_str_encoding(zend_string *str, const mbfl_encoding *encoding); +static const mbfl_encoding* mb_guess_encoding(unsigned char *in, size_t in_len, const mbfl_encoding **elist, unsigned int elist_size, bool strict); + +static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encoding *incode, const mbfl_encoding *outcode, bool base64, char *linefeed, size_t linefeed_len, zend_long indent); + /* See mbfilter_cp5022x.c */ uint32_t mb_convert_kana_codepoint(uint32_t c, uint32_t next, bool *consumed, uint32_t *second, int mode); /* }}} */ @@ -435,55 +447,25 @@ static bool php_mb_zend_encoding_lexer_compatibility_checker(const zend_encoding static const zend_encoding *php_mb_zend_encoding_detector(const unsigned char *arg_string, size_t arg_length, const zend_encoding **list, size_t list_size) { - mbfl_string string; - if (!list) { - list = (const zend_encoding **)MBSTRG(current_detect_order_list); + list = (const zend_encoding**)MBSTRG(current_detect_order_list); list_size = MBSTRG(current_detect_order_list_size); } - mbfl_string_init(&string); - string.val = (unsigned char *)arg_string; - string.len = arg_length; - return (const zend_encoding *) mbfl_identify_encoding(&string, (const mbfl_encoding **)list, list_size, 0); + return (const zend_encoding*)mb_guess_encoding((unsigned char*)arg_string, arg_length, (const mbfl_encoding **)list, list_size, false); } static size_t php_mb_zend_encoding_converter(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length, const zend_encoding *encoding_to, const zend_encoding *encoding_from) { - mbfl_string string, result; - mbfl_buffer_converter *convd; - - /* new encoding */ - /* initialize string */ - string.encoding = (const mbfl_encoding*)encoding_from; - string.val = (unsigned char*)from; - string.len = from_length; - - /* initialize converter */ - convd = mbfl_buffer_converter_new((const mbfl_encoding *)encoding_from, (const mbfl_encoding *)encoding_to, string.len); - if (convd == NULL) { - return (size_t) -1; - } - - mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode)); - mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar)); - - /* do it */ - size_t loc = mbfl_buffer_converter_feed(convd, &string); - - mbfl_buffer_converter_flush(convd); - mbfl_string_init(&result); - if (!mbfl_buffer_converter_result(convd, &result)) { - mbfl_buffer_converter_delete(convd); - return (size_t)-1; - } - - *to = result.val; - *to_length = result.len; + unsigned int num_errors = 0; + zend_string *result = mb_fast_convert((unsigned char*)from, from_length, (const mbfl_encoding*)encoding_from, (const mbfl_encoding*)encoding_to, MBSTRG(current_filter_illegal_substchar), MBSTRG(current_filter_illegal_mode), &num_errors); - mbfl_buffer_converter_delete(convd); + *to_length = ZSTR_LEN(result); + *to = emalloc(ZSTR_LEN(result) + 1); /* Include terminating null byte */ + memcpy(*to, ZSTR_VAL(result), ZSTR_LEN(result) + 1); + zend_string_free(result); - return loc; + return from_length; } static zend_result php_mb_zend_encoding_list_parser(const char *encoding_list, size_t encoding_list_len, const zend_encoding ***return_list, size_t *return_size, bool persistent) @@ -763,7 +745,7 @@ static PHP_INI_MH(OnUpdate_mbstring_http_input) php_error_docref("ref.mbstring", E_DEPRECATED, "Use of mbstring.http_input is deprecated"); } - if (!new_value) { + if (!new_value || !ZSTR_LEN(new_value)) { const char *encoding = php_get_input_encoding(); MBSTRG(http_input_set) = 0; _php_mb_ini_mbstring_http_input_set(encoding, strlen(encoding)); @@ -1023,7 +1005,8 @@ ZEND_TSRMLS_CACHE_UPDATE(); mbstring_globals->illegalchars = 0; mbstring_globals->encoding_translation = 0; mbstring_globals->strict_detection = 0; - mbstring_globals->outconv = NULL; + mbstring_globals->outconv_enabled = false; + mbstring_globals->outconv_state = 0; mbstring_globals->http_output_conv_mimetypes = NULL; #ifdef HAVE_MBREGEX mbstring_globals->mb_regex_globals = php_mb_regex_globals_alloc(); @@ -1054,6 +1037,10 @@ static PHP_GSHUTDOWN_FUNCTION(mbstring) } /* }}} */ +#ifdef ZEND_INTRIN_AVX2_FUNC_PTR +static void init_check_utf8(void); +#endif + /* {{{ PHP_MINIT_FUNCTION(mbstring) */ PHP_MINIT_FUNCTION(mbstring) { @@ -1094,6 +1081,11 @@ ZEND_TSRMLS_CACHE_UPDATE(); php_mb_rfc1867_getword_conf, php_mb_rfc1867_basename); +#ifdef ZEND_INTRIN_AVX2_FUNC_PTR + init_check_utf8(); + init_convert_utf16(); +#endif + return SUCCESS; } /* }}} */ @@ -1144,11 +1136,6 @@ PHP_RSHUTDOWN_FUNCTION(mbstring) MBSTRG(current_detect_order_list) = NULL; MBSTRG(current_detect_order_list_size) = 0; } - if (MBSTRG(outconv) != NULL) { - MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv)); - mbfl_buffer_converter_delete(MBSTRG(outconv)); - MBSTRG(outconv) = NULL; - } /* clear http input identification. */ MBSTRG(http_input_identify) = NULL; @@ -1166,6 +1153,9 @@ PHP_RSHUTDOWN_FUNCTION(mbstring) MBSTRG(http_output_set) = 0; MBSTRG(http_input_set) = 0; + MBSTRG(outconv_enabled) = false; + MBSTRG(outconv_state) = 0; + #ifdef HAVE_MBREGEX PHP_RSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU); #endif @@ -1213,7 +1203,7 @@ PHP_FUNCTION(mb_language) if (name == NULL) { RETVAL_STRING((char *)mbfl_no_language2name(MBSTRG(language))); } else { - zend_string *ini_name = zend_string_init("mbstring.language", sizeof("mbstring.language") - 1, 0); + zend_string *ini_name = ZSTR_INIT_LITERAL("mbstring.language", 0); if (FAILURE == zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME)) { zend_argument_value_error(1, "must be a valid language, \"%s\" given", ZSTR_VAL(name)); zend_string_release_ex(ini_name, 0); @@ -1305,19 +1295,15 @@ PHP_FUNCTION(mb_http_input) if (n == 0) { RETURN_FALSE; } - // TODO Use smart_str instead. - mbfl_string result; - mbfl_memory_device device; - mbfl_memory_device_init(&device, n * 12, 0); + + smart_str result = {0}; for (size_t i = 0; i < n; i++, entry++) { - mbfl_memory_device_strcat(&device, (*entry)->name); - mbfl_memory_device_output(',', &device); + if (i > 0) { + smart_str_appendc(&result, ','); + } + smart_str_appends(&result, (*entry)->name); } - mbfl_memory_device_unput(&device); /* Remove trailing comma */ - mbfl_memory_device_result(&device, &result); - RETVAL_STRINGL((const char*)result.val, result.len); - mbfl_string_clear(&result); - return; + RETURN_STR(smart_str_extract(&result)); default: zend_argument_value_error(1, "must be one of \"G\", \"P\", \"C\", \"S\", \"I\", or \"L\""); @@ -1362,7 +1348,7 @@ PHP_FUNCTION(mb_http_output) } /* }}} */ -/* {{{ Sets the current detect_order or Return the current detect_order as a array */ +/* {{{ Sets the current detect_order or Return the current detect_order as an array */ PHP_FUNCTION(mb_detect_order) { zend_string *order_str = NULL; @@ -1486,7 +1472,6 @@ PHP_FUNCTION(mb_substitute_character) /* {{{ Return the preferred MIME name (charset) as a string */ PHP_FUNCTION(mb_preferred_mime_name) { - enum mbfl_no_encoding no_encoding; char *name = NULL; size_t name_len; @@ -1494,13 +1479,13 @@ PHP_FUNCTION(mb_preferred_mime_name) Z_PARAM_STRING(name, name_len) ZEND_PARSE_PARAMETERS_END(); - no_encoding = mbfl_name2no_encoding(name); - if (no_encoding == mbfl_no_encoding_invalid) { + const mbfl_encoding *enc = mbfl_name2encoding(name); + if (enc == NULL) { zend_argument_value_error(1, "must be a valid encoding, \"%s\" given", name); RETURN_THROWS(); } - const char *preferred_name = mbfl_no2preferred_mime_name(no_encoding); + const char *preferred_name = mbfl_encoding_preferred_mime_name(enc); if (preferred_name == NULL || *preferred_name == '\0') { php_error_docref(NULL, E_WARNING, "No MIME preferred name corresponding to \"%s\"", name); RETVAL_FALSE; @@ -1548,171 +1533,106 @@ PHP_FUNCTION(mb_parse_str) } /* }}} */ -/* {{{ Returns string in output buffer converted to the http_output encoding */ PHP_FUNCTION(mb_output_handler) { - char *arg_string; - size_t arg_string_len; + zend_string *str; zend_long arg_status; - mbfl_string string, result; - const char *charset; - char *p; - const mbfl_encoding *encoding; - int last_feed; - size_t len; - unsigned char send_text_mimetype = 0; - char *s, *mimetype = NULL; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_STRING(arg_string, arg_string_len) + Z_PARAM_STR(str) Z_PARAM_LONG(arg_status) ZEND_PARSE_PARAMETERS_END(); - encoding = MBSTRG(current_http_output_encoding); - - /* start phase only */ - if ((arg_status & PHP_OUTPUT_HANDLER_START) != 0) { - /* delete the converter just in case. */ - if (MBSTRG(outconv)) { - MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv)); - mbfl_buffer_converter_delete(MBSTRG(outconv)); - MBSTRG(outconv) = NULL; - } + const mbfl_encoding *encoding = MBSTRG(current_http_output_encoding); + if (encoding == &mbfl_encoding_pass) { + RETURN_STR_COPY(str); + } - if (encoding == &mbfl_encoding_pass) { - RETURN_STRINGL(arg_string, arg_string_len); - } + if (arg_status & PHP_OUTPUT_HANDLER_START) { + bool free_mimetype = false; + char *mimetype = NULL; - /* analyze mime type */ - if (SG(sapi_headers).mimetype && - _php_mb_match_regex( - MBSTRG(http_output_conv_mimetypes), - SG(sapi_headers).mimetype, - strlen(SG(sapi_headers).mimetype))) { - if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL) { + /* Analyze mime type */ + if (SG(sapi_headers).mimetype && _php_mb_match_regex(MBSTRG(http_output_conv_mimetypes), SG(sapi_headers).mimetype, strlen(SG(sapi_headers).mimetype))) { + char *s; + if ((s = strchr(SG(sapi_headers).mimetype, ';')) == NULL) { mimetype = estrdup(SG(sapi_headers).mimetype); } else { - mimetype = estrndup(SG(sapi_headers).mimetype,s-SG(sapi_headers).mimetype); + mimetype = estrndup(SG(sapi_headers).mimetype, s - SG(sapi_headers).mimetype); } - send_text_mimetype = 1; + free_mimetype = true; } else if (SG(sapi_headers).send_default_content_type) { mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE; } - /* if content-type is not yet set, set it and activate the converter */ - if (SG(sapi_headers).send_default_content_type || send_text_mimetype) { - charset = encoding->mime_name; + /* If content-type is not yet set, set it and enable conversion */ + if (SG(sapi_headers).send_default_content_type || free_mimetype) { + const char *charset = encoding->mime_name; if (charset) { - len = spprintf( &p, 0, "Content-Type: %s; charset=%s", mimetype, charset ); + char *p; + size_t len = spprintf(&p, 0, "Content-Type: %s; charset=%s", mimetype, charset); if (sapi_add_header(p, len, 0) != FAILURE) { SG(sapi_headers).send_default_content_type = 0; } } - /* activate the converter */ - MBSTRG(outconv) = mbfl_buffer_converter_new(MBSTRG(current_internal_encoding), encoding, 0); - if (send_text_mimetype){ - efree(mimetype); - } + + MBSTRG(outconv_enabled) = true; + } + + if (free_mimetype) { + efree(mimetype); } } - /* just return if the converter is not activated. */ - if (MBSTRG(outconv) == NULL) { - RETURN_STRINGL(arg_string, arg_string_len); + if (!MBSTRG(outconv_enabled)) { + RETURN_STR_COPY(str); } - /* flag */ - last_feed = ((arg_status & PHP_OUTPUT_HANDLER_END) != 0); - /* mode */ - mbfl_buffer_converter_illegal_mode(MBSTRG(outconv), MBSTRG(current_filter_illegal_mode)); - mbfl_buffer_converter_illegal_substchar(MBSTRG(outconv), MBSTRG(current_filter_illegal_substchar)); + mb_convert_buf buf; + mb_convert_buf_init(&buf, ZSTR_LEN(str), MBSTRG(current_filter_illegal_substchar), MBSTRG(current_filter_illegal_mode)); - /* feed the string */ - mbfl_string_init(&string); - /* these are not needed. convd has encoding info. - string.encoding = MBSTRG(current_internal_encoding); - */ - string.val = (unsigned char *)arg_string; - string.len = arg_string_len; + uint32_t wchar_buf[128]; + unsigned char *in = (unsigned char*)ZSTR_VAL(str); + size_t in_len = ZSTR_LEN(str); + bool last_feed = ((arg_status & PHP_OUTPUT_HANDLER_END) != 0); - mbfl_buffer_converter_feed(MBSTRG(outconv), &string); - if (last_feed) { - mbfl_buffer_converter_flush(MBSTRG(outconv)); + while (in_len) { + size_t out_len = MBSTRG(current_internal_encoding)->to_wchar(&in, &in_len, wchar_buf, 128, &MBSTRG(outconv_state)); + ZEND_ASSERT(out_len <= 128); + encoding->from_wchar(wchar_buf, out_len, &buf, !in_len && last_feed); } - /* get the converter output, and return it */ - mbfl_buffer_converter_result(MBSTRG(outconv), &result); - // TODO: avoid reallocation ??? - RETVAL_STRINGL((char *)result.val, result.len); /* the string is already strdup()'ed */ - efree(result.val); + MBSTRG(illegalchars) += buf.errors; + RETVAL_STR(mb_convert_buf_result_raw(&buf)); - /* delete the converter if it is the last feed. */ if (last_feed) { - MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv)); - mbfl_buffer_converter_delete(MBSTRG(outconv)); - MBSTRG(outconv) = NULL; - } -} -/* }}} */ - -/* {{{ Convert a multibyte string to an array. If split_length is specified, - break the string down into chunks each split_length characters long. */ - -/* structure to pass split params to the callback */ -struct mbfl_split_params { - zval *return_value; /* php function return value structure pointer */ - mbfl_string *result_string; /* string to store result chunk */ - size_t mb_chunk_length; /* actual chunk length in chars */ - size_t split_length; /* split length in chars */ - mbfl_convert_filter *next_filter; /* widechar to encoding converter */ -}; - -/* callback function to fill split array */ -static int mbfl_split_output(int c, void *data) -{ - struct mbfl_split_params *params = (struct mbfl_split_params *)data; /* cast passed data */ - - (*params->next_filter->filter_function)(c, params->next_filter); /* decoder filter */ - - if (params->split_length == ++params->mb_chunk_length) { /* if current chunk size reached defined chunk size or last char reached */ - mbfl_convert_filter_flush(params->next_filter);/* concatenate separate decoded chars to the solid string */ - mbfl_memory_device *device = (mbfl_memory_device *)params->next_filter->data; /* chars container */ - mbfl_string *chunk = params->result_string; - mbfl_memory_device_result(device, chunk); /* make chunk */ - add_next_index_stringl(params->return_value, (const char *)chunk->val, chunk->len); /* add chunk to the array */ - efree(chunk->val); - params->mb_chunk_length = 0; /* reset mb_chunk size */ + MBSTRG(outconv_enabled) = false; + MBSTRG(outconv_state) = 0; } - - return 0; } PHP_FUNCTION(mb_str_split) { zend_string *str, *encoding = NULL; - size_t mb_len, chunks, chunk_len; - const char *p, *last; /* pointer for the string cursor and last string char */ - mbfl_string string, result_string; - const mbfl_encoding *mbfl_encoding; - zend_long split_length = 1; + zend_long split_len = 1; ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STR(str) Z_PARAM_OPTIONAL - Z_PARAM_LONG(split_length) + Z_PARAM_LONG(split_len) Z_PARAM_STR_OR_NULL(encoding) ZEND_PARSE_PARAMETERS_END(); - if (split_length <= 0) { + if (split_len <= 0) { zend_argument_value_error(2, "must be greater than 0"); RETURN_THROWS(); + } else if (split_len > UINT_MAX / 4) { + zend_argument_value_error(2, "is too large"); + RETURN_THROWS(); } - /* fill mbfl_string structure */ - string.val = (unsigned char *) ZSTR_VAL(str); - string.len = ZSTR_LEN(str); - string.encoding = php_mb_get_encoding(encoding, 3); - if (!string.encoding) { + const mbfl_encoding *enc = php_mb_get_encoding(encoding, 3); + if (!enc) { RETURN_THROWS(); } @@ -1720,138 +1640,188 @@ PHP_FUNCTION(mb_str_split) RETURN_EMPTY_ARRAY(); } - p = ZSTR_VAL(str); /* string cursor pointer */ - last = ZSTR_VAL(str) + ZSTR_LEN(str); /* last string char pointer */ - - mbfl_encoding = string.encoding; - - /* first scenario: 1,2,4-bytes fixed width encodings (head part) */ - if (mbfl_encoding->flag & MBFL_ENCTYPE_SBCS) { /* 1 byte */ - mb_len = string.len; - chunk_len = (size_t)split_length; /* chunk length in bytes */ - } else if (mbfl_encoding->flag & MBFL_ENCTYPE_WCS2) { /* 2 bytes */ - mb_len = string.len / 2; - chunk_len = split_length * 2; - } else if (mbfl_encoding->flag & MBFL_ENCTYPE_WCS4) { /* 4 bytes */ - mb_len = string.len / 4; - chunk_len = split_length * 4; - } else if (mbfl_encoding->mblen_table != NULL) { - /* second scenario: variable width encodings with length table */ - char unsigned const *mbtab = mbfl_encoding->mblen_table; - - /* assume that we have 1-bytes characters */ - array_init_size(return_value, (string.len + split_length) / split_length); /* round up */ - - while (p < last) { /* split cycle work until the cursor has reached the last byte */ - char const *chunk_p = p; /* chunk first byte pointer */ - chunk_len = 0; /* chunk length in bytes */ - zend_long char_count; - - for (char_count = 0; char_count < split_length && p < last; ++char_count) { - char unsigned const m = mbtab[*(const unsigned char *)p]; /* single character length table */ - chunk_len += m; - p += m; - } - if (p >= last) chunk_len -= p - last; /* check if chunk is in bounds */ - add_next_index_stringl(return_value, chunk_p, chunk_len); + unsigned char *p = (unsigned char*)ZSTR_VAL(str), *e = p + ZSTR_LEN(str); + + unsigned int char_len = enc->flag & (MBFL_ENCTYPE_SBCS | MBFL_ENCTYPE_WCS2 | MBFL_ENCTYPE_WCS4); + if (char_len) { + unsigned int chunk_len = char_len * split_len; + unsigned int chunks = ((ZSTR_LEN(str) / chunk_len) + split_len - 1) / split_len; /* round up */ + array_init_size(return_value, chunks); + while (p < e) { + add_next_index_stringl(return_value, (const char*)p, MIN(chunk_len, e - p)); + p += chunk_len; } - return; - } else { - /* third scenario: other multibyte encodings */ - mbfl_convert_filter *filter, *decoder; - - /* assume that we have 1-bytes characters */ - array_init_size(return_value, (string.len + split_length) / split_length); /* round up */ - - /* decoder filter to decode wchar to encoding */ - mbfl_memory_device device; - mbfl_memory_device_init(&device, split_length + 1, 0); - - decoder = mbfl_convert_filter_new( - &mbfl_encoding_wchar, - string.encoding, - mbfl_memory_device_output, - NULL, - &device); - /* assert that nothing is wrong with the decoder */ - ZEND_ASSERT(decoder != NULL); - - /* wchar filter */ - mbfl_string_init(&result_string); /* mbfl_string to store chunk in the callback */ - struct mbfl_split_params params = { /* init callback function params structure */ - .return_value = return_value, - .result_string = &result_string, - .mb_chunk_length = 0, - .split_length = (size_t)split_length, - .next_filter = decoder, - }; - - filter = mbfl_convert_filter_new( - string.encoding, - &mbfl_encoding_wchar, - mbfl_split_output, - NULL, - ¶ms); - /* assert that nothing is wrong with the filter */ - ZEND_ASSERT(filter != NULL); - - while (p < last - 1) { /* cycle each byte except last with callback function */ - (*filter->filter_function)(*p++, filter); - } - params.mb_chunk_length = split_length - 1; /* force to finish current chunk */ - (*filter->filter_function)(*p++, filter); /* process last char */ - - mbfl_convert_filter_delete(decoder); - mbfl_convert_filter_delete(filter); - mbfl_memory_device_clear(&device); - return; - } - - /* first scenario: 1,2,4-bytes fixed width encodings (tail part) */ - chunks = (mb_len + split_length - 1) / split_length; /* (round up idiom) */ - array_init_size(return_value, chunks); - if (chunks != 0) { - zend_long i; - - for (i = 0; i < chunks - 1; p += chunk_len, ++i) { - add_next_index_stringl(return_value, p, chunk_len); - } - add_next_index_stringl(return_value, p, last - p); - } -} -/* }}} */ + } else if (enc->mblen_table) { + unsigned char const *mbtab = enc->mblen_table; -static size_t mb_get_strlen(zend_string *string, const mbfl_encoding *encoding) -{ - size_t len = 0; + /* Assume that we have 1-byte characters */ + array_init_size(return_value, (ZSTR_LEN(str) + split_len - 1) / split_len); - if (encoding->flag & MBFL_ENCTYPE_SBCS) { - return ZSTR_LEN(string); - } else if (encoding->flag & MBFL_ENCTYPE_WCS2) { - return ZSTR_LEN(string) / 2; - } else if (encoding->flag & MBFL_ENCTYPE_WCS4) { - return ZSTR_LEN(string) / 4; - } else if (encoding->mblen_table) { - const unsigned char *mbtab = encoding->mblen_table; - unsigned char *p = (unsigned char*)ZSTR_VAL(string), *e = p + ZSTR_LEN(string); while (p < e) { - p += mbtab[*p]; - len++; + unsigned char *chunk = p; /* start of chunk */ + + for (int char_count = 0; char_count < split_len && p < e; char_count++) { + p += mbtab[*p]; + } + if (p > e) { + p = e; /* ensure chunk is in bounds */ + } + add_next_index_stringl(return_value, (const char*)chunk, p - chunk); } } else { + /* Assume that we have 1-byte characters */ + array_init_size(return_value, (ZSTR_LEN(str) + split_len - 1) / split_len); + uint32_t wchar_buf[128]; - unsigned char *in = (unsigned char*)ZSTR_VAL(string); - size_t in_len = ZSTR_LEN(string); - unsigned int state = 0; + size_t in_len = ZSTR_LEN(str); + unsigned int state = 0, char_count = 0; + + mb_convert_buf buf; while (in_len) { - len += encoding->to_wchar(&in, &in_len, wchar_buf, 128, &state); + size_t out_len = enc->to_wchar(&p, &in_len, wchar_buf, 128, &state); + ZEND_ASSERT(out_len <= 128); + size_t i = 0; + + /* Is there some output remaining from the previous iteration? */ + if (char_count) { + if (out_len >= split_len - char_count) { + /* Finish off an incomplete chunk from previous iteration + * ('buf' was already initialized; we don't need to do it again) */ + enc->from_wchar(wchar_buf, split_len - char_count, &buf, true); + i += split_len - char_count; + char_count = 0; + add_next_index_str(return_value, mb_convert_buf_result(&buf, enc)); + } else { + /* Output from this iteration is not enough to finish the next chunk; + * output what we can, and leave 'buf' to be used again on next iteration */ + enc->from_wchar(wchar_buf, out_len, &buf, !in_len); + char_count += out_len; + continue; + } + } + + while (i < out_len) { + /* Prepare for the next chunk */ + mb_convert_buf_init(&buf, split_len, MBSTRG(current_filter_illegal_substchar), MBSTRG(current_filter_illegal_mode)); + + if (out_len - i >= split_len) { + enc->from_wchar(wchar_buf + i, split_len, &buf, true); + i += split_len; + add_next_index_str(return_value, mb_convert_buf_result(&buf, enc)); + } else { + /* The remaining codepoints in wchar_buf aren't enough to finish a chunk; + * leave them for the next iteration */ + enc->from_wchar(wchar_buf + i, out_len - i, &buf, !in_len); + char_count = out_len - i; + break; + } + } + } + + if (char_count) { + /* The main loop above has finished processing the input string, but + * has left a partial chunk in 'buf' */ + add_next_index_str(return_value, mb_convert_buf_result(&buf, enc)); + } + } +} + +#ifdef __SSE2__ +/* Thanks to StackOverflow user 'Paul R' (https://stackoverflow.com/users/253056/paul-r) + * From: https://stackoverflow.com/questions/36998538/fastest-way-to-horizontally-sum-sse-unsigned-byte-vector + * Takes a 128-bit XMM register, treats each byte as an 8-bit integer, and sums up all + * 16 of them, returning the sum in an ordinary scalar register */ +static inline uint32_t _mm_sum_epu8(const __m128i v) +{ + /* We don't have any dedicated instruction to sum up 8-bit values from a 128-bit register + * _mm_sad_epu8 takes the differences between corresponding bytes of two different XMM registers, + * sums up those differences, and stores them as two 16-byte integers in the top and bottom + * halves of the destination XMM register + * By using a zeroed-out XMM register as one operand, we ensure the "differences" which are + * summed up will actually just be the 8-bit values from `v` */ + __m128i vsum = _mm_sad_epu8(v, _mm_setzero_si128()); + /* If _mm_sad_epu8 had stored the sum of those bytes as a single integer, we would just have + * to extract it here; but it stored the sum as two different 16-bit values + * _mm_cvtsi128_si32 extracts one of those values into a scalar register + * _mm_extract_epi16 extracts the other one into another scalar register; then we just add them */ + return _mm_cvtsi128_si32(vsum) + _mm_extract_epi16(vsum, 4); +} +#endif + +/* This assumes that `string` is valid UTF-8 + * In UTF-8, the only bytes which do not start a new codepoint are 0x80-0xBF (continuation bytes) + * Interpreted as signed integers, those are all byte values less than -64 + * A fast way to get the length of a UTF-8 string is to start with its byte length, + * then subtract off the number of continuation bytes */ +static size_t mb_fast_strlen_utf8(unsigned char *p, size_t len) +{ + unsigned char *e = p + len; + +#ifdef __SSE2__ + if (len >= sizeof(__m128i)) { + e -= sizeof(__m128i); + + const __m128i threshold = _mm_set1_epi8(-64); + const __m128i delta = _mm_set1_epi8(1); + __m128i counter = _mm_setzero_si128(); /* Vector of 16 continuation-byte counters */ + + int reset_counter = 255; + do { + __m128i operand = _mm_loadu_si128((__m128i*)p); /* Load 16 bytes */ + __m128i lt = _mm_cmplt_epi8(operand, threshold); /* Find all which are continuation bytes */ + counter = _mm_add_epi8(counter, _mm_and_si128(lt, delta)); /* Update the 16 counters */ + + /* The counters can only go up to 255, so every 255 iterations, fold them into `len` + * and reset them to zero */ + if (--reset_counter == 0) { + len -= _mm_sum_epu8(counter); + counter = _mm_setzero_si128(); + reset_counter = 255; + } + + p += sizeof(__m128i); + } while (p <= e); + + e += sizeof(__m128i); + len -= _mm_sum_epu8(counter); /* Fold in any remaining non-zero values in the 16 counters */ + } +#endif + + /* Check for continuation bytes in the 0-15 remaining bytes at the end of the string */ + while (p < e) { + signed char c = *p++; + if (c < -64) { + len--; } } return len; } +static size_t mb_get_strlen(zend_string *string, const mbfl_encoding *encoding) +{ + unsigned int char_len = encoding->flag & (MBFL_ENCTYPE_SBCS | MBFL_ENCTYPE_WCS2 | MBFL_ENCTYPE_WCS4); + if (char_len) { + return ZSTR_LEN(string) / char_len; + } else if (php_mb_is_no_encoding_utf8(encoding->no_encoding) && GC_FLAGS(string) & IS_STR_VALID_UTF8) { + return mb_fast_strlen_utf8((unsigned char*)ZSTR_VAL(string), ZSTR_LEN(string)); + } + + + uint32_t wchar_buf[128]; + unsigned char *in = (unsigned char*)ZSTR_VAL(string); + size_t in_len = ZSTR_LEN(string); + unsigned int state = 0; + size_t len = 0; + + while (in_len) { + len += encoding->to_wchar(&in, &in_len, wchar_buf, 128, &state); + } + + return len; +} + /* {{{ Get character numbers of a string */ PHP_FUNCTION(mb_strlen) { @@ -1906,14 +1876,7 @@ static unsigned char* offset_to_pointer_utf8(unsigned char *str, unsigned char * } static size_t pointer_to_offset_utf8(unsigned char *start, unsigned char *pos) { - size_t result = 0; - while (pos > start) { - unsigned char c = *--pos; - if (c < 0x80 || (c & 0xC0) != 0x80) { - result++; - } - } - return result; + return mb_fast_strlen_utf8(start, pos - start); } static size_t mb_find_strpos(zend_string *haystack, zend_string *needle, const mbfl_encoding *enc, ssize_t offset, bool reverse) @@ -1923,8 +1886,9 @@ static size_t mb_find_strpos(zend_string *haystack, zend_string *needle, const m unsigned char *offset_pointer; if (!php_mb_is_no_encoding_utf8(enc->no_encoding)) { - haystack_u8 = php_mb_convert_encoding_ex(ZSTR_VAL(haystack), ZSTR_LEN(haystack), &mbfl_encoding_utf8, enc); - needle_u8 = php_mb_convert_encoding_ex(ZSTR_VAL(needle), ZSTR_LEN(needle), &mbfl_encoding_utf8, enc); + unsigned int num_errors = 0; + haystack_u8 = mb_fast_convert((unsigned char*)ZSTR_VAL(haystack), ZSTR_LEN(haystack), enc, &mbfl_encoding_utf8, 0, MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8, &num_errors); + needle_u8 = mb_fast_convert((unsigned char*)ZSTR_VAL(needle), ZSTR_LEN(needle), enc, &mbfl_encoding_utf8, 0, MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8, &num_errors); } else { haystack_u8 = haystack; needle_u8 = needle; @@ -1961,10 +1925,10 @@ static size_t mb_find_strpos(zend_string *haystack, zend_string *needle, const m } out: - if (haystack_u8 != NULL && haystack_u8 != haystack) { + if (haystack_u8 != haystack) { zend_string_free(haystack_u8); } - if (needle_u8 != NULL && needle_u8 != needle) { + if (needle_u8 != needle) { zend_string_free(needle_u8); } return result; @@ -2127,7 +2091,7 @@ static zend_string* mb_get_substr_slow(unsigned char *in, size_t in_len, size_t } } - return mb_convert_buf_result(&buf); + return mb_convert_buf_result(&buf, enc); } static zend_string* mb_get_substr(zend_string *input, size_t from, size_t len, const mbfl_encoding *enc) @@ -2157,7 +2121,10 @@ static zend_string* mb_get_substr(zend_string *input, size_t from, size_t len, c len = in_len; } return zend_string_init_fast((const char*)in, len); - } else if (enc->mblen_table != NULL) { + } else if (enc->mblen_table) { + /* The use of the `mblen_table` means that for encodings like MacJapanese, + * we treat each character in its native charset as "1 character", even if it + * maps to a sequence of several codepoints */ const unsigned char *mbtab = enc->mblen_table; unsigned char *limit = in + in_len; while (from && in < limit) { @@ -2263,42 +2230,89 @@ PHP_FUNCTION(mb_strrichr) #undef MB_STRISTR #undef MB_STRRICHR -/* {{{ Count the number of substring occurrences */ PHP_FUNCTION(mb_substr_count) { - mbfl_string haystack, needle; - char *haystack_val, *needle_val; - zend_string *enc_name = NULL; + zend_string *haystack, *needle, *enc_name = NULL, *haystack_u8 = NULL, *needle_u8 = NULL; ZEND_PARSE_PARAMETERS_START(2, 3) - Z_PARAM_STRING(haystack_val, haystack.len) - Z_PARAM_STRING(needle_val, needle.len) + Z_PARAM_STR(haystack) + Z_PARAM_STR(needle) Z_PARAM_OPTIONAL Z_PARAM_STR_OR_NULL(enc_name) ZEND_PARSE_PARAMETERS_END(); - haystack.val = (unsigned char*)haystack_val; - needle.val = (unsigned char*)needle_val; - - if (needle.len == 0) { + if (ZSTR_LEN(needle) == 0) { zend_argument_value_error(2, "must not be empty"); RETURN_THROWS(); } - haystack.encoding = needle.encoding = php_mb_get_encoding(enc_name, 3); - if (!haystack.encoding) { + const mbfl_encoding *enc = php_mb_get_encoding(enc_name, 3); + if (!enc) { RETURN_THROWS(); } - size_t n = mbfl_substr_count(&haystack, &needle); - /* An error can only occur if needle is empty, - * an encoding error happens (which should not happen at this stage and is a bug) - * or the haystack is more than sizeof(size_t) bytes - * If one of these things occur this is a bug and should be flagged as such */ - ZEND_ASSERT(!mbfl_is_error(n)); - RETVAL_LONG(n); + if (php_mb_is_no_encoding_utf8(enc->no_encoding)) { + /* No need to do any conversion if haystack/needle are already known-valid UTF-8 + * (If they are not valid, then not passing them through conversion filters could affect output) */ + if (GC_FLAGS(haystack) & IS_STR_VALID_UTF8) { + haystack_u8 = haystack; + } else { + unsigned int num_errors = 0; + haystack_u8 = mb_fast_convert((unsigned char*)ZSTR_VAL(haystack), ZSTR_LEN(haystack), enc, &mbfl_encoding_utf8, 0, MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8, &num_errors); + if (!num_errors && !ZSTR_IS_INTERNED(haystack)) { + GC_ADD_FLAGS(haystack, IS_STR_VALID_UTF8); + } + } + + if (GC_FLAGS(needle) & IS_STR_VALID_UTF8) { + needle_u8 = needle; + } else { + unsigned int num_errors = 0; + needle_u8 = mb_fast_convert((unsigned char*)ZSTR_VAL(needle), ZSTR_LEN(needle), enc, &mbfl_encoding_utf8, 0, MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8, &num_errors); + if (!num_errors && !ZSTR_IS_INTERNED(needle)) { + GC_ADD_FLAGS(needle, IS_STR_VALID_UTF8); + } + } + } else { + unsigned int num_errors = 0; + haystack_u8 = mb_fast_convert((unsigned char*)ZSTR_VAL(haystack), ZSTR_LEN(haystack), enc, &mbfl_encoding_utf8, 0, MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8, &num_errors); + needle_u8 = mb_fast_convert((unsigned char*)ZSTR_VAL(needle), ZSTR_LEN(needle), enc, &mbfl_encoding_utf8, 0, MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8, &num_errors); + /* A string with >0 bytes may convert to 0 codepoints; for example, the contents + * may be only escape sequences */ + if (ZSTR_LEN(needle_u8) == 0) { + zend_string_free(haystack_u8); + zend_string_free(needle_u8); + zend_argument_value_error(2, "must not be empty"); + RETURN_THROWS(); + } + } + + size_t result = 0; + + if (ZSTR_LEN(haystack_u8) < ZSTR_LEN(needle_u8)) { + goto out; + } + + const char *p = ZSTR_VAL(haystack_u8), *e = p + ZSTR_LEN(haystack_u8); + while (true) { + p = zend_memnstr(p, ZSTR_VAL(needle_u8), ZSTR_LEN(needle_u8), e); + if (!p) { + break; + } + p += ZSTR_LEN(needle_u8); + result++; + } + +out: + if (haystack_u8 != haystack) { + zend_string_free(haystack_u8); + } + if (needle_u8 != needle) { + zend_string_free(needle_u8); + } + + RETVAL_LONG(result); } -/* }}} */ /* {{{ Returns part of a string */ PHP_FUNCTION(mb_substr) @@ -2323,7 +2337,21 @@ PHP_FUNCTION(mb_substr) size_t mblen = 0; if (from < 0 || (!len_is_null && len < 0)) { - mblen = mb_get_strlen(str, enc); + if (enc->mblen_table) { + /* Because we use the `mblen_table` when iterating over the string and + * extracting the requested part, we also need to use it here for counting + * the "length" of the string + * Otherwise, we can get wrong results for text encodings like MacJapanese, + * where one native 'character' can map to a sequence of several codepoints */ + const unsigned char *mbtab = enc->mblen_table; + unsigned char *p = (unsigned char*)ZSTR_VAL(str), *e = p + ZSTR_LEN(str); + while (p < e) { + p += mbtab[*p]; + mblen++; + } + } else { + mblen = mb_get_strlen(str, enc); + } } /* if "from" position is negative, count start position from the end @@ -2577,7 +2605,9 @@ static zend_string* mb_trim_string(zend_string *input, zend_string *marker, cons buf.out += ZSTR_LEN(marker); } - return mb_convert_buf_result(&buf); + /* Even if `enc` is UTF-8, don't mark the output string as valid UTF-8, because + * we have no guarantee that the trim marker string is valid UTF-8 */ + return mb_convert_buf_result_raw(&buf); } /* Trim the string to terminal width; optional, add a 'trim marker' if it was truncated */ @@ -2657,12 +2687,7 @@ MBSTRING_API zend_string* php_mb_convert_encoding(const char *input, size_t leng from_encoding = *from_encodings; } else { /* auto detect */ - mbfl_string string; - mbfl_string_init(&string); - string.val = (unsigned char *)input; - string.len = length; - from_encoding = mbfl_identify_encoding( - &string, from_encodings, num_from_encodings, MBSTRG(strict_detection)); + from_encoding = mb_guess_encoding((unsigned char*)input, length, from_encodings, num_from_encodings, MBSTRG(strict_detection)); if (!from_encoding) { php_error_docref(NULL, E_WARNING, "Unable to detect character encoding"); return NULL; @@ -2693,15 +2718,27 @@ MBSTRING_API HashTable *php_mb_convert_encoding_recursive(HashTable *input, cons ZEND_HASH_FOREACH_KEY_VAL(input, idx, key, entry) { /* convert key */ if (key) { - key = php_mb_convert_encoding(ZSTR_VAL(key), ZSTR_LEN(key), to_encoding, from_encodings, num_from_encodings); + zend_string *converted_key = php_mb_convert_encoding(ZSTR_VAL(key), ZSTR_LEN(key), to_encoding, from_encodings, num_from_encodings); + if (!converted_key) { + continue; + } + key = converted_key; } /* convert value */ ZEND_ASSERT(entry); try_again: switch(Z_TYPE_P(entry)) { - case IS_STRING: - ZVAL_STR(&entry_tmp, php_mb_convert_encoding(Z_STRVAL_P(entry), Z_STRLEN_P(entry), to_encoding, from_encodings, num_from_encodings)); + case IS_STRING: { + zend_string *converted_key = php_mb_convert_encoding(Z_STRVAL_P(entry), Z_STRLEN_P(entry), to_encoding, from_encodings, num_from_encodings); + if (!converted_key) { + if (key) { + zend_string_release(key); + } + continue; + } + ZVAL_STR(&entry_tmp, converted_key); break; + } case IS_NULL: case IS_TRUE: case IS_FALSE: @@ -2767,7 +2804,7 @@ PHP_FUNCTION(mb_convert_encoding) HashTable *input_ht, *from_encodings_ht = NULL; const mbfl_encoding **from_encodings; size_t num_from_encodings; - bool free_from_encodings; + bool free_from_encodings = false; ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_ARRAY_HT_OR_STR(input_ht, input_str) @@ -2785,18 +2822,17 @@ PHP_FUNCTION(mb_convert_encoding) if (php_mb_parse_encoding_array(from_encodings_ht, &from_encodings, &num_from_encodings, 3) == FAILURE) { RETURN_THROWS(); } - free_from_encodings = 1; + free_from_encodings = true; } else if (from_encodings_str) { if (php_mb_parse_encoding_list(ZSTR_VAL(from_encodings_str), ZSTR_LEN(from_encodings_str), &from_encodings, &num_from_encodings, /* persistent */ 0, /* arg_num */ 3, /* allow_pass_encoding */ 0) == FAILURE) { RETURN_THROWS(); } - free_from_encodings = 1; + free_from_encodings = true; } else { from_encodings = &MBSTRG(current_internal_encoding); num_from_encodings = 1; - free_from_encodings = 0; } if (num_from_encodings > 1) { @@ -2831,7 +2867,7 @@ PHP_FUNCTION(mb_convert_encoding) static zend_string *mbstring_convert_case(php_case_mode case_mode, const char *str, size_t str_len, const mbfl_encoding *enc) { - return php_unicode_convert_case(case_mode, str, str_len, enc, MBSTRG(current_filter_illegal_mode), MBSTRG(current_filter_illegal_substchar)); + return php_unicode_convert_case(case_mode, str, str_len, enc, enc, MBSTRG(current_filter_illegal_mode), MBSTRG(current_filter_illegal_substchar)); } PHP_FUNCTION(mb_convert_case) @@ -2902,16 +2938,213 @@ static const mbfl_encoding **duplicate_elist(const mbfl_encoding **elist, size_t return new_elist; } +static unsigned int estimate_demerits(uint32_t w) +{ + /* Receive wchars decoded from input string using candidate encoding. + * Give the candidate many 'demerits' for each 'rare' codepoint found, + * a smaller number for each ASCII punctuation character, and 1 for + * all other codepoints. + * + * The 'common' codepoints should cover the vast majority of + * codepoints we are likely to see in practice, while only covering + * a small minority of the entire Unicode encoding space. Why? + * Well, if the test string happens to be valid in an incorrect + * candidate encoding, the bogus codepoints which it decodes to will + * be more or less random. By treating the majority of codepoints as + * 'rare', we ensure that in almost all such cases, the bogus + * codepoints will include plenty of 'rares', thus giving the + * incorrect candidate encoding lots of demerits. See + * common_codepoints.txt for the actual list used. + * + * So, why give extra demerits for ASCII punctuation characters? It's + * because there are some text encodings, like UTF-7, HZ, and ISO-2022, + * which deliberately only use bytes in the ASCII range. When + * misinterpreted as ASCII/UTF-8, strings in these encodings will + * have an unusually high number of ASCII punctuation characters. + * So giving extra demerits for such characters will improve + * detection accuracy for UTF-7 and similar encodings. + * + * Finally, why 1 demerit for all other characters? That penalizes + * long strings, meaning we will tend to choose a candidate encoding + * in which the test string decodes to a smaller number of + * codepoints. That prevents single-byte encodings in which almost + * every possible input byte decodes to a 'common' codepoint from + * being favored too much. */ + if (w > 0xFFFF) { + return 40; + } else if (w >= 0x21 && w <= 0x2F) { + return 6; + } else if ((rare_codepoint_bitvec[w >> 5] >> (w & 0x1F)) & 1) { + return 30; + } else { + return 1; + } + return 0; +} + +struct candidate { + const mbfl_encoding *enc; + const unsigned char *in; + size_t in_len; + uint64_t demerits; /* Wide bit size to prevent overflow */ + unsigned int state; +}; + +static size_t init_candidate_array(struct candidate *array, size_t length, const mbfl_encoding **encodings, const unsigned char **in, size_t *in_len, size_t n, bool strict) +{ + size_t j = 0; + + for (size_t i = 0; i < length; i++) { + const mbfl_encoding *enc = encodings[i]; + + /* If any candidate encodings have specialized validation functions, use them + * to eliminate as many candidates as possible */ + if (strict && enc->check != NULL) { + for (size_t k = 0; k < n; k++) { + if (!enc->check((unsigned char*)in[k], in_len[k])) { + goto skip_to_next; + } + } + } + + array[j].enc = enc; + array[j].state = 0; + array[j].demerits = 0; + j++; +skip_to_next: ; + } + + return j; +} + +static void start_string(struct candidate *array, size_t length, const unsigned char *in, size_t in_len) +{ + for (size_t i = 0; i < length; i++) { + const mbfl_encoding *enc = array[i].enc; + + array[i].in = in; + array[i].in_len = in_len; + + /* Skip byte order mark for UTF-8, UTF-16BE, or UTF-16LE */ + if (enc == &mbfl_encoding_utf8) { + if (in_len >= 3 && in[0] == 0xEF && in[1] == 0xBB && in[2] == 0xBF) { + array[i].in_len -= 3; + array[i].in += 3; + } + } else if (enc == &mbfl_encoding_utf16be) { + if (in_len >= 2 && in[0] == 0xFE && in[1] == 0xFF) { + array[i].in_len -= 2; + array[i].in += 2; + } + } else if (enc == &mbfl_encoding_utf16le) { + if (in_len >= 2 && in[0] == 0xFF && in[1] == 0xFE) { + array[i].in_len -= 2; + array[i].in += 2; + } + } + } +} + +static size_t count_demerits(struct candidate *array, size_t length, bool strict) +{ + uint32_t wchar_buf[128]; + unsigned int finished = 0; /* For how many candidate encodings have we processed all the input? */ + + while ((strict || length > 1) && finished < length) { + for (size_t i = 0; i < length; i++) { +try_next_encoding: + /* Do we still have more input to process for this candidate encoding? */ + if (array[i].in_len) { + const mbfl_encoding *enc = array[i].enc; + size_t out_len = enc->to_wchar((unsigned char**)&array[i].in, &array[i].in_len, wchar_buf, 128, &array[i].state); + ZEND_ASSERT(out_len <= 128); + /* Check this batch of decoded codepoints; are there any error markers? + * Also sum up the number of demerits */ + while (out_len) { + uint32_t w = wchar_buf[--out_len]; + if (w == MBFL_BAD_INPUT) { + if (strict) { + /* This candidate encoding is not valid, eliminate it from consideration */ + length--; + if (length == 0) { + return 0; + } + memmove(&array[i], &array[i+1], (length - i) * sizeof(struct candidate)); + goto try_next_encoding; + } else { + array[i].demerits += 1000; + } + } else { + array[i].demerits += estimate_demerits(w); + } + } + if (array[i].in_len == 0) { + finished++; + } + } + } + } + + return length; +} + +MBSTRING_API const mbfl_encoding* mb_guess_encoding_for_strings(const unsigned char **strings, size_t *str_lengths, size_t n, const mbfl_encoding **elist, unsigned int elist_size, bool strict) +{ + if (elist_size == 0) { + return NULL; + } + if (elist_size == 1) { + if (strict) { + while (n--) { + if (!php_mb_check_encoding((const char*)strings[n], str_lengths[n], *elist)) { + return NULL; + } + } + } + return *elist; + } + if (n == 1 && *str_lengths == 0) { + return *elist; + } + + /* Allocate on stack; when we return, this array is automatically freed */ + struct candidate *array = alloca(elist_size * sizeof(struct candidate)); + elist_size = init_candidate_array(array, elist_size, elist, strings, str_lengths, n, strict); + + while (n--) { + start_string(array, elist_size, strings[n], str_lengths[n]); + elist_size = count_demerits(array, elist_size, strict); + if (elist_size == 0) { + /* All candidates were eliminated */ + return NULL; + } + } + + /* See which remaining candidate encoding has the least demerits */ + unsigned int best = 0; + for (unsigned int i = 1; i < elist_size; i++) { + if (array[i].demerits < array[best].demerits) { + best = i; + } + } + return array[best].enc; +} + +/* When doing 'strict' detection, any string which is invalid in the candidate encoding + * is rejected. With non-strict detection, we just continue, but apply demerits for + * each invalid byte sequence */ +static const mbfl_encoding* mb_guess_encoding(unsigned char *in, size_t in_len, const mbfl_encoding **elist, unsigned int elist_size, bool strict) +{ + return mb_guess_encoding_for_strings((const unsigned char**)&in, &in_len, 1, elist, elist_size, strict); +} + /* {{{ Encodings of the given string is returned (as a string) */ PHP_FUNCTION(mb_detect_encoding) { zend_string *str, *encoding_str = NULL; HashTable *encoding_ht = NULL; bool strict = false; - - mbfl_string string; - const mbfl_encoding *ret; - const mbfl_encoding **elist; + const mbfl_encoding *ret, **elist; size_t size; ZEND_PARSE_PARAMETERS_START(1, 3) @@ -2951,14 +3184,10 @@ PHP_FUNCTION(mb_detect_encoding) strict = MBSTRG(strict_detection); } - if (strict && size == 1) { - /* If there is only a single candidate encoding, mb_check_encoding is faster */ - ret = (mb_check_str_encoding(str, *elist)) ? *elist : NULL; + if (size == 1 && *elist == &mbfl_encoding_utf8 && (GC_FLAGS(str) & IS_STR_VALID_UTF8)) { + ret = &mbfl_encoding_utf8; } else { - mbfl_string_init(&string); - string.val = (unsigned char*)ZSTR_VAL(str); - string.len = ZSTR_LEN(str); - ret = mbfl_identify_encoding(&string, elist, size, strict); + ret = mb_guess_encoding((unsigned char*)ZSTR_VAL(str), ZSTR_LEN(str), elist, size, strict); } efree(ZEND_VOIDP(elist)); @@ -3007,99 +3236,20 @@ PHP_FUNCTION(mb_encoding_aliases) } /* }}} */ -/* {{{ Converts the string to MIME "encoded-word" in the format of =?charset?(B|Q)?encoded_string?= */ -PHP_FUNCTION(mb_encode_mimeheader) +static zend_string* jp_kana_convert(zend_string *input, const mbfl_encoding *encoding, unsigned int mode) { - const mbfl_encoding *charset, *transenc; - mbfl_string string, result, *ret; - zend_string *charset_name = NULL; - char *trans_enc_name = NULL, *string_val; - size_t trans_enc_name_len; - char *linefeed = "\r\n"; - size_t linefeed_len; - zend_long indent = 0; + /* Each wchar may potentially expand to 2 when we perform kana conversion... + * if we are converting zenkaku kana to hankaku kana + * Make the buffer for converted kana big enough that we never need to + * perform bounds checks */ + uint32_t wchar_buf[64], converted_buf[64 * 2]; + unsigned int buf_offset = 0; + unsigned int state = 0; + unsigned char *in = (unsigned char*)ZSTR_VAL(input); + size_t in_len = ZSTR_LEN(input); - string.encoding = MBSTRG(current_internal_encoding); - - ZEND_PARSE_PARAMETERS_START(1, 5) - Z_PARAM_STRING(string_val, string.len) - Z_PARAM_OPTIONAL - Z_PARAM_STR(charset_name) - Z_PARAM_STRING(trans_enc_name, trans_enc_name_len) - Z_PARAM_STRING(linefeed, linefeed_len) - Z_PARAM_LONG(indent) - ZEND_PARSE_PARAMETERS_END(); - - string.val = (unsigned char*)string_val; - charset = &mbfl_encoding_pass; - transenc = &mbfl_encoding_base64; - - if (charset_name != NULL) { - charset = php_mb_get_encoding(charset_name, 2); - if (!charset) { - RETURN_THROWS(); - } - } else { - const mbfl_language *lang = mbfl_no2language(MBSTRG(language)); - if (lang != NULL) { - charset = mbfl_no2encoding(lang->mail_charset); - transenc = mbfl_no2encoding(lang->mail_header_encoding); - } - } - - if (trans_enc_name != NULL) { - if (*trans_enc_name == 'B' || *trans_enc_name == 'b') { - transenc = &mbfl_encoding_base64; - } else if (*trans_enc_name == 'Q' || *trans_enc_name == 'q') { - transenc = &mbfl_encoding_qprint; - } - } - - mbfl_string_init(&result); - ret = mbfl_mime_header_encode(&string, &result, charset, transenc, linefeed, indent); - ZEND_ASSERT(ret != NULL); - // TODO: avoid reallocation ??? - RETVAL_STRINGL((char *)ret->val, ret->len); /* the string is already strdup()'ed */ - efree(ret->val); -} -/* }}} */ - -/* {{{ Decodes the MIME "encoded-word" in the string */ -PHP_FUNCTION(mb_decode_mimeheader) -{ - char *string_val; - mbfl_string string, result, *ret; - - string.encoding = MBSTRG(current_internal_encoding); - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(string_val, string.len) - ZEND_PARSE_PARAMETERS_END(); - - string.val = (unsigned char*)string_val; - mbfl_string_init(&result); - ret = mbfl_mime_header_decode(&string, &result, MBSTRG(current_internal_encoding)); - ZEND_ASSERT(ret != NULL); - // TODO: avoid reallocation ??? - RETVAL_STRINGL((char *)ret->val, ret->len); /* the string is already strdup()'ed */ - efree(ret->val); -} -/* }}} */ - -static zend_string* jp_kana_convert(zend_string *input, const mbfl_encoding *encoding, unsigned int mode) -{ - /* Each wchar may potentially expand to 2 when we perform kana conversion... - * if we are converting zenkaku kana to hankaku kana - * Make the buffer for converted kana big enough that we never need to - * perform bounds checks */ - uint32_t wchar_buf[64], converted_buf[64 * 2]; - unsigned int buf_offset = 0; - unsigned int state = 0; - unsigned char *in = (unsigned char*)ZSTR_VAL(input); - size_t in_len = ZSTR_LEN(input); - - mb_convert_buf buf; - mb_convert_buf_init(&buf, in_len, MBSTRG(current_filter_illegal_substchar), MBSTRG(current_filter_illegal_mode)); + mb_convert_buf buf; + mb_convert_buf_init(&buf, in_len, MBSTRG(current_filter_illegal_substchar), MBSTRG(current_filter_illegal_mode)); while (in_len) { uint32_t *converted = converted_buf; @@ -3148,7 +3298,7 @@ static zend_string* jp_kana_convert(zend_string *input, const mbfl_encoding *enc encoding->from_wchar(converted_buf, converted - converted_buf, &buf, !in_len); } - return mb_convert_buf_result(&buf); + return mb_convert_buf_result(&buf, encoding); } char mb_convert_kana_flags[17] = { @@ -3223,10 +3373,7 @@ PHP_FUNCTION(mb_convert_kana) * or all FW hiragana to FW katakana, or all FW katakana to FW hiragana, but not * more than one of these */ if (opt & MBFL_ZEN2HAN_HIRAGANA) { - if (opt & MBFL_ZEN2HAN_KATAKANA) { - zend_argument_value_error(2, "must not combine 'h' and 'k' flags"); - RETURN_THROWS(); - } else if (opt & MBFL_ZENKAKU_HIRA2KATA) { + if (opt & MBFL_ZENKAKU_HIRA2KATA) { zend_argument_value_error(2, "must not combine 'h' and 'C' flags"); RETURN_THROWS(); } else if (opt & MBFL_ZENKAKU_KATA2HIRA) { @@ -3254,41 +3401,62 @@ PHP_FUNCTION(mb_convert_kana) RETVAL_STR(jp_kana_convert(str, enc, opt)); } -static int mb_recursive_encoder_detector_feed(mbfl_encoding_detector *identd, zval *var, bool *recursion_error) /* {{{ */ +static unsigned int mb_recursive_count_strings(zval *var) { - mbfl_string string; - HashTable *ht; - zval *entry; - + unsigned int count = 0; ZVAL_DEREF(var); + if (Z_TYPE_P(var) == IS_STRING) { - string.val = (unsigned char *)Z_STRVAL_P(var); - string.len = Z_STRLEN_P(var); - if (mbfl_encoding_detector_feed(identd, &string)) { - return 1; /* complete detecting */ + count++; + } else if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) { + if (Z_REFCOUNTED_P(var)) { + if (Z_IS_RECURSIVE_P(var)) { + return count; + } + Z_PROTECT_RECURSION_P(var); } + + HashTable *ht = HASH_OF(var); + if (ht != NULL) { + zval *entry; + ZEND_HASH_FOREACH_VAL_IND(ht, entry) { + count += mb_recursive_count_strings(entry); + } ZEND_HASH_FOREACH_END(); + } + + if (Z_REFCOUNTED_P(var)) { + Z_UNPROTECT_RECURSION_P(var); + } + } + + return count; +} + +static bool mb_recursive_find_strings(zval *var, const unsigned char **val_list, size_t *len_list, unsigned int *count) +{ + ZVAL_DEREF(var); + + if (Z_TYPE_P(var) == IS_STRING) { + val_list[*count] = (const unsigned char*)Z_STRVAL_P(var); + len_list[*count] = Z_STRLEN_P(var); + (*count)++; } else if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) { if (Z_REFCOUNTED_P(var)) { if (Z_IS_RECURSIVE_P(var)) { - *recursion_error = true; - return 0; + return true; } Z_PROTECT_RECURSION_P(var); } - ht = HASH_OF(var); + HashTable *ht = HASH_OF(var); if (ht != NULL) { + zval *entry; ZEND_HASH_FOREACH_VAL_IND(ht, entry) { - if (mb_recursive_encoder_detector_feed(identd, entry, recursion_error)) { - if (Z_REFCOUNTED_P(var)) { - Z_UNPROTECT_RECURSION_P(var); - } - return 1; - } else if (*recursion_error) { + if (mb_recursive_find_strings(entry, val_list, len_list, count)) { if (Z_REFCOUNTED_P(var)) { Z_UNPROTECT_RECURSION_P(var); + return true; } - return 0; } } ZEND_HASH_FOREACH_END(); } @@ -3297,12 +3465,12 @@ static int mb_recursive_encoder_detector_feed(mbfl_encoding_detector *identd, zv Z_UNPROTECT_RECURSION_P(var); } } - return 0; -} /* }}} */ + + return false; +} static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_encoding, const mbfl_encoding* to_encoding) { - HashTable *ht; zval *entry, *orig_var; orig_var = var; @@ -3323,7 +3491,7 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e Z_PROTECT_RECURSION_P(var); } - ht = HASH_OF(var); + HashTable *ht = HASH_OF(var); if (ht != NULL) { ZEND_HASH_FOREACH_VAL_IND(ht, entry) { if (mb_recursive_convert_variable(entry, from_encoding, to_encoding)) { @@ -3343,7 +3511,6 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e return false; } -/* {{{ Converts the string resource in variables to desired encoding */ PHP_FUNCTION(mb_convert_variables) { zval *args; @@ -3351,11 +3518,9 @@ PHP_FUNCTION(mb_convert_variables) zend_string *from_enc_str; HashTable *from_enc_ht; const mbfl_encoding *from_encoding, *to_encoding; - mbfl_encoding_detector *identd; - int n, argc; + uint32_t argc; size_t elistsz; const mbfl_encoding **elist; - bool recursion_error = false; ZEND_PARSE_PARAMETERS_START(3, -1) Z_PARAM_STR(to_enc_str) @@ -3392,54 +3557,49 @@ PHP_FUNCTION(mb_convert_variables) from_encoding = *elist; } else { /* auto detect */ - from_encoding = NULL; - identd = mbfl_encoding_detector_new(elist, elistsz, MBSTRG(strict_detection)); - if (identd != NULL) { - n = 0; - while (n < argc) { - if (mb_recursive_encoder_detector_feed(identd, &args[n], &recursion_error)) { - break; - } - n++; - } - from_encoding = mbfl_encoding_detector_judge(identd); - mbfl_encoding_detector_delete(identd); - if (recursion_error) { + unsigned int num = 0; + for (size_t n = 0; n < argc; n++) { + zval *zv = &args[n]; + num += mb_recursive_count_strings(zv); + } + const unsigned char **val_list = (const unsigned char**)ecalloc(num, sizeof(char *)); + size_t *len_list = (size_t*)ecalloc(num, sizeof(size_t)); + unsigned int i = 0; + for (size_t n = 0; n < argc; n++) { + zval *zv = &args[n]; + if (mb_recursive_find_strings(zv, val_list, len_list, &i)) { efree(ZEND_VOIDP(elist)); + efree(ZEND_VOIDP(val_list)); + efree(len_list); php_error_docref(NULL, E_WARNING, "Cannot handle recursive references"); RETURN_FALSE; } } - + from_encoding = mb_guess_encoding_for_strings(val_list, len_list, num, elist, elistsz, MBSTRG(strict_detection)); + efree(ZEND_VOIDP(val_list)); + efree(len_list); if (!from_encoding) { php_error_docref(NULL, E_WARNING, "Unable to detect encoding"); efree(ZEND_VOIDP(elist)); RETURN_FALSE; } + } efree(ZEND_VOIDP(elist)); /* convert */ - n = 0; - while (n < argc) { + for (size_t n = 0; n < argc; n++) { zval *zv = &args[n]; ZVAL_DEREF(zv); - recursion_error = mb_recursive_convert_variable(zv, from_encoding, to_encoding); - if (recursion_error) { - break; + if (mb_recursive_convert_variable(zv, from_encoding, to_encoding)) { + php_error_docref(NULL, E_WARNING, "Cannot handle recursive references"); + RETURN_FALSE; } - n++; - } - - if (recursion_error) { - php_error_docref(NULL, E_WARNING, "Cannot handle recursive references"); - RETURN_FALSE; } RETURN_STRING(from_encoding->name); } -/* }}} */ /* HTML numeric entities */ @@ -3550,7 +3710,7 @@ static zend_string* html_numeric_entity_encode(zend_string *input, const mbfl_en encoding->from_wchar(converted_buf, converted - converted_buf, &buf, !in_len); } - return mb_convert_buf_result(&buf); + return mb_convert_buf_result(&buf, encoding); } /* {{{ Converts specified characters to HTML numeric entities */ @@ -3782,7 +3942,7 @@ static zend_string* html_numeric_entity_decode(zend_string *input, const mbfl_en encoding->from_wchar(converted_buf, converted - converted_buf, &buf, !in_len); } - return mb_convert_buf_result(&buf); + return mb_convert_buf_result(&buf, encoding); } /* {{{ Converts HTML numeric entities to character code */ @@ -3984,12 +4144,11 @@ PHP_FUNCTION(mb_send_mail) size_t to_len; char *message; size_t message_len; - char *subject; - size_t subject_len; + zend_string *subject; zend_string *extra_cmd = NULL; HashTable *headers_ht = NULL; zend_string *str_headers = NULL; - size_t n, i; + size_t i; char *to_r = NULL; char *force_extra_parameters = INI_STR("mail.force_extra_parameters"); struct { @@ -3997,24 +4156,15 @@ PHP_FUNCTION(mb_send_mail) int cnt_trans_enc:1; } suppressed_hdrs = { 0, 0 }; - char *message_buf = NULL, *subject_buf = NULL, *p; - mbfl_string orig_str, conv_str; - mbfl_string *pstr; /* pointer to mbfl string for return value */ + char *p; enum mbfl_no_encoding; const mbfl_encoding *tran_cs, /* transfer text charset */ *head_enc, /* header transfer encoding */ *body_enc; /* body transfer encoding */ - mbfl_memory_device device; /* automatic allocateable buffer for additional header */ const mbfl_language *lang; int err = 0; HashTable ht_headers; zval *s; - extern void mbfl_memory_device_unput(mbfl_memory_device *device); - - /* initialize */ - mbfl_memory_device_init(&device, 0, 0); - mbfl_string_init(&orig_str); - mbfl_string_init(&conv_str); /* character-set, transfer-encoding */ tran_cs = &mbfl_encoding_utf8; @@ -4029,7 +4179,7 @@ PHP_FUNCTION(mb_send_mail) ZEND_PARSE_PARAMETERS_START(3, 5) Z_PARAM_PATH(to, to_len) - Z_PARAM_PATH(subject, subject_len) + Z_PARAM_PATH_STR(subject) Z_PARAM_PATH(message, message_len) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_HT_OR_STR(headers_ht, str_headers) @@ -4141,86 +4291,85 @@ PHP_FUNCTION(mb_send_mail) } /* Subject: */ - orig_str.val = (unsigned char *)subject; - orig_str.len = subject_len; - orig_str.encoding = MBSTRG(current_internal_encoding); - if (orig_str.encoding->no_encoding == mbfl_no_encoding_invalid - || orig_str.encoding->no_encoding == mbfl_no_encoding_pass) { - orig_str.encoding = mbfl_identify_encoding(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection)); - } - pstr = mbfl_mime_header_encode(&orig_str, &conv_str, tran_cs, head_enc, CRLF, sizeof("Subject: [PHP-jp nnnnnnnn]" CRLF) - 1); - if (pstr != NULL) { - subject_buf = subject = (char *)pstr->val; + const mbfl_encoding *enc = MBSTRG(current_internal_encoding); + if (enc == &mbfl_encoding_pass) { + enc = mb_guess_encoding((unsigned char*)ZSTR_VAL(subject), ZSTR_LEN(subject), MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection)); } + const char *line_sep = PG(mail_mixed_lf_and_crlf) ? "\n" : CRLF; + size_t line_sep_len = strlen(line_sep); - /* message body */ - orig_str.val = (unsigned char *)message; - orig_str.len = message_len; - orig_str.encoding = MBSTRG(current_internal_encoding); + subject = mb_mime_header_encode(subject, enc, tran_cs, head_enc == &mbfl_encoding_base64, (char*)line_sep, line_sep_len, strlen("Subject: [PHP-jp nnnnnnnn]") + line_sep_len); - if (orig_str.encoding->no_encoding == mbfl_no_encoding_invalid - || orig_str.encoding->no_encoding == mbfl_no_encoding_pass) { - orig_str.encoding = mbfl_identify_encoding(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection)); + /* message body */ + const mbfl_encoding *msg_enc = MBSTRG(current_internal_encoding); + if (msg_enc == &mbfl_encoding_pass) { + msg_enc = mb_guess_encoding((unsigned char*)message, message_len, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection)); } - pstr = NULL; - { - mbfl_string tmpstr; - - if (mbfl_convert_encoding(&orig_str, &tmpstr, tran_cs) != NULL) { - tmpstr.encoding = &mbfl_encoding_8bit; - pstr = mbfl_convert_encoding(&tmpstr, &conv_str, body_enc); - efree(tmpstr.val); - } - } - if (pstr != NULL) { - message_buf = message = (char *)pstr->val; - } + unsigned int num_errors = 0; + zend_string *tmpstr = mb_fast_convert((unsigned char*)message, message_len, msg_enc, tran_cs, '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR, &num_errors); + zend_string *conv = mb_fast_convert((unsigned char*)ZSTR_VAL(tmpstr), ZSTR_LEN(tmpstr), &mbfl_encoding_8bit, body_enc, '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR, &num_errors); + zend_string_free(tmpstr); + message = ZSTR_VAL(conv); /* other headers */ #define PHP_MBSTR_MAIL_MIME_HEADER1 "MIME-Version: 1.0" #define PHP_MBSTR_MAIL_MIME_HEADER2 "Content-Type: text/plain" #define PHP_MBSTR_MAIL_MIME_HEADER3 "; charset=" #define PHP_MBSTR_MAIL_MIME_HEADER4 "Content-Transfer-Encoding: " + + smart_str str = {0}; + bool empty = true; + if (str_headers != NULL) { - p = ZSTR_VAL(str_headers); - n = ZSTR_LEN(str_headers); - mbfl_memory_device_strncat(&device, p, n); - if (n > 0 && p[n - 1] != '\n') { - mbfl_memory_device_strncat(&device, CRLF, sizeof(CRLF)-1); + /* Strip trailing CRLF from `str_headers`; we will add CRLF back if necessary */ + size_t len = ZSTR_LEN(str_headers); + if (ZSTR_VAL(str_headers)[len-1] == '\n') { + len--; + } + if (ZSTR_VAL(str_headers)[len-1] == '\r') { + len--; } + smart_str_appendl(&str, ZSTR_VAL(str_headers), len); + empty = false; zend_string_release_ex(str_headers, 0); } if (!zend_hash_str_exists(&ht_headers, "mime-version", sizeof("mime-version") - 1)) { - mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER1, sizeof(PHP_MBSTR_MAIL_MIME_HEADER1) - 1); - mbfl_memory_device_strncat(&device, CRLF, sizeof(CRLF)-1); + if (!empty) { + smart_str_appendl(&str, line_sep, line_sep_len); + } + smart_str_appendl(&str, PHP_MBSTR_MAIL_MIME_HEADER1, sizeof(PHP_MBSTR_MAIL_MIME_HEADER1) - 1); + empty = false; } if (!suppressed_hdrs.cnt_type) { - mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER2, sizeof(PHP_MBSTR_MAIL_MIME_HEADER2) - 1); + if (!empty) { + smart_str_appendl(&str, line_sep, line_sep_len); + } + smart_str_appendl(&str, PHP_MBSTR_MAIL_MIME_HEADER2, sizeof(PHP_MBSTR_MAIL_MIME_HEADER2) - 1); p = (char *)mbfl_encoding_preferred_mime_name(tran_cs); if (p != NULL) { - mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER3, sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1); - mbfl_memory_device_strcat(&device, p); + smart_str_appendl(&str, PHP_MBSTR_MAIL_MIME_HEADER3, sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1); + smart_str_appends(&str, p); } - mbfl_memory_device_strncat(&device, CRLF, sizeof(CRLF)-1); + empty = false; } + if (!suppressed_hdrs.cnt_trans_enc) { - mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER4, sizeof(PHP_MBSTR_MAIL_MIME_HEADER4) - 1); + if (!empty) { + smart_str_appendl(&str, line_sep, line_sep_len); + } + smart_str_appendl(&str, PHP_MBSTR_MAIL_MIME_HEADER4, sizeof(PHP_MBSTR_MAIL_MIME_HEADER4) - 1); p = (char *)mbfl_encoding_preferred_mime_name(body_enc); if (p == NULL) { p = "7bit"; } - mbfl_memory_device_strcat(&device, p); - mbfl_memory_device_strncat(&device, CRLF, sizeof(CRLF)-1); + smart_str_appends(&str, p); } - mbfl_memory_device_unput(&device); - mbfl_memory_device_unput(&device); - mbfl_memory_device_output('\0', &device); - str_headers = zend_string_init((char *)device.buffer, strlen((char *)device.buffer), 0); + str_headers = smart_str_extract(&str); if (force_extra_parameters) { extra_cmd = php_escape_shell_cmd(force_extra_parameters); @@ -4228,26 +4377,16 @@ PHP_FUNCTION(mb_send_mail) extra_cmd = php_escape_shell_cmd(ZSTR_VAL(extra_cmd)); } - if (!err && php_mail(to_r, subject, message, ZSTR_VAL(str_headers), extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)) { - RETVAL_TRUE; - } else { - RETVAL_FALSE; - } + RETVAL_BOOL(!err && php_mail(to_r, ZSTR_VAL(subject), message, ZSTR_VAL(str_headers), extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)); if (extra_cmd) { zend_string_release_ex(extra_cmd, 0); } - if (to_r != to) { efree(to_r); } - if (subject_buf) { - efree((void *)subject_buf); - } - if (message_buf) { - efree((void *)message_buf); - } - mbfl_memory_device_clear(&device); + zend_string_release(subject); + zend_string_free(conv); zend_hash_destroy(&ht_headers); if (str_headers) { zend_string_release_ex(str_headers, 0); @@ -4416,6 +4555,10 @@ MBSTRING_API bool php_mb_check_encoding(const char *input, size_t length, const unsigned char *in = (unsigned char*)input; unsigned int state = 0; + if (encoding->check != NULL) { + return encoding->check(in, length); + } + /* If the input string is not encoded in the given encoding, there is a significant chance * that this will be seen in the first bytes. Therefore, rather than converting an entire * buffer of 128 codepoints, convert and check just a few codepoints first */ @@ -4440,13 +4583,648 @@ MBSTRING_API bool php_mb_check_encoding(const char *input, size_t length, const return true; } +/* If we are building an AVX2-only binary, don't compile the next function */ +#ifndef ZEND_INTRIN_AVX2_NATIVE + +/* SSE2-based function for validating UTF-8 strings + * A faster implementation which uses AVX2 instructions follows */ +static bool mb_fast_check_utf8_default(zend_string *str) +{ + unsigned char *p = (unsigned char*)ZSTR_VAL(str); +# ifdef __SSE2__ + /* `e` points 1 byte past the last full 16-byte block of string content + * Note that we include the terminating null byte which is included in each zend_string + * as part of the content to check; this ensures that multi-byte characters which are + * truncated abruptly at the end of the string will be detected as invalid */ + unsigned char *e = p + ((ZSTR_LEN(str) + 1) & ~(sizeof(__m128i) - 1)); + + /* For checking for illegal bytes 0xF5-FF */ + const __m128i over_f5 = _mm_set1_epi8(-117); + /* For checking for overlong 3-byte code units and reserved codepoints U+D800-DFFF */ + const __m128i over_9f = _mm_set1_epi8(-97); + /* For checking for overlong 4-byte code units and invalid codepoints > U+10FFFF */ + const __m128i over_8f = _mm_set1_epi8(-113); + /* For checking for illegal bytes 0xC0-C1 */ + const __m128i find_c0 = _mm_set1_epi8(-64); + const __m128i c0_to_c1 = _mm_set1_epi8(-126); + /* For checking structure of continuation bytes */ + const __m128i find_e0 = _mm_set1_epi8(-32); + const __m128i find_f0 = _mm_set1_epi8(-16); + + __m128i last_block = _mm_setzero_si128(); + __m128i operand; + + while (p < e) { + operand = _mm_loadu_si128((__m128i*)p); /* Load 16 bytes */ + +check_operand: + /* If all 16 bytes are single-byte characters, then a number of checks can be skipped */ + if (!_mm_movemask_epi8(operand)) { + /* Even if this block only contains single-byte characters, there may have been a + * multi-byte character at the end of the previous block, which was supposed to + * have continuation bytes in this block + * This bitmask will pick out a 2/3/4-byte character starting from the last byte of + * the previous block, a 3/4-byte starting from the 2nd last, or a 4-byte starting + * from the 3rd last */ + __m128i bad_mask = _mm_set_epi8(-64, -32, -16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + __m128i bad = _mm_cmpeq_epi8(_mm_and_si128(last_block, bad_mask), bad_mask); + if (_mm_movemask_epi8(bad)) { + return false; + } + + /* Consume as many full blocks of single-byte characters as we can */ + while (true) { + p += sizeof(__m128i); + if (p >= e) { + goto finish_up_remaining_bytes; + } + operand = _mm_loadu_si128((__m128i*)p); + if (_mm_movemask_epi8(operand)) { + break; + } + } + } + + /* Check for >= 0xF5, which are illegal byte values in UTF-8 + * AVX512 has instructions for vectorized unsigned compare, but SSE2 only has signed compare + * So we add an offset to shift 0xF5-FF to the far low end of the signed byte range + * Then a single signed compare will pick out any bad bytes + * `bad` is a vector of 16 good/bad values, where 0x00 means good and 0xFF means bad */ + __m128i bad = _mm_cmplt_epi8(_mm_add_epi8(operand, over_f5), over_f5); + + /* Check for overlong 3-byte code units AND reserved codepoints U+D800-DFFF + * 0xE0 followed by a byte < 0xA0 indicates an overlong 3-byte code unit, and + * 0xED followed by a byte >= 0xA0 indicates a reserved codepoint + * We can check for both problems at once by generating a vector where each byte < 0xA0 + * is mapped to 0xE0, and each byte >= 0xA0 is mapped to 0xED + * Shift the original block right by one byte, and compare the shifted block with the bitmask */ + __m128i operand2 = _mm_or_si128(_mm_slli_si128(operand, 1), _mm_srli_si128(last_block, 15)); + __m128i mask1 = _mm_or_si128(find_e0, _mm_and_si128(_mm_set1_epi8(0xD), _mm_cmpgt_epi8(operand, over_9f))); + bad = _mm_or_si128(bad, _mm_cmpeq_epi8(operand2, mask1)); + + /* Check for overlong 4-byte code units AND invalid codepoints > U+10FFFF + * Similar to the previous check; 0xF0 followed by < 0x90 indicates an overlong 4-byte + * code unit, and 0xF4 followed by >= 0x90 indicates a codepoint over U+10FFFF + * Build the bitmask and compare it with the shifted block */ + __m128i mask2 = _mm_or_si128(find_f0, _mm_and_si128(_mm_set1_epi8(0x4), _mm_cmpgt_epi8(operand, over_8f))); + bad = _mm_or_si128(bad, _mm_cmpeq_epi8(operand2, mask2)); + + /* Check for overlong 2-byte code units + * Any 0xC0 or 0xC1 byte can only be the first byte of an overlong 2-byte code unit + * Same deal as before; add an offset to shift 0xC0-C1 to the far low end of the signed + * byte range, do a signed compare to pick out any bad bytes */ + bad = _mm_or_si128(bad, _mm_cmplt_epi8(_mm_add_epi8(operand, find_c0), c0_to_c1)); + + /* Check structure of continuation bytes + * A UTF-8 byte should be a continuation byte if, and only if, it is: + * 1) 1 byte after the start of a 2-byte, 3-byte, or 4-byte character + * 2) 2 bytes after the start of a 3-byte or 4-byte character + * 3) 3 bytes after the start of a 4-byte character + * We build 3 bitmasks with 0xFF in each such position, and OR them together to + * get a single bitmask with 0xFF in each position where a continuation byte should be */ + __m128i cont_mask = _mm_cmpeq_epi8(_mm_and_si128(operand2, find_c0), find_c0); + __m128i operand3 = _mm_or_si128(_mm_slli_si128(operand, 2), _mm_srli_si128(last_block, 14)); + cont_mask = _mm_or_si128(cont_mask, _mm_cmpeq_epi8(_mm_and_si128(operand3, find_e0), find_e0)); + __m128i operand4 = _mm_or_si128(_mm_slli_si128(operand, 3), _mm_srli_si128(last_block, 13)); + cont_mask = _mm_or_si128(cont_mask, _mm_cmpeq_epi8(_mm_and_si128(operand4, find_f0), find_f0)); + + /* Now, use a signed comparison to get another bitmask with 0xFF in each position where + * a continuation byte actually is + * XOR those two bitmasks together; if everything is good, the result should be zero + * However, if a byte which should have been a continuation wasn't, or if a byte which + * shouldn't have been a continuation was, we will get 0xFF in that position */ + __m128i continuation = _mm_cmplt_epi8(operand, find_c0); + bad = _mm_or_si128(bad, _mm_xor_si128(continuation, cont_mask)); + + /* Pick out the high bit of each byte in `bad` as a 16-bit value (into a scalar register) + * If that value is non-zero, then we found a bad byte somewhere! */ + if (_mm_movemask_epi8(bad)) { + return false; + } + + last_block = operand; + p += sizeof(__m128i); + } + +finish_up_remaining_bytes: + /* Finish up 1-15 remaining bytes */ + if (p == e) { + uint8_t remaining_bytes = ZSTR_LEN(str) & (sizeof(__m128i) - 1); /* Not including terminating null */ + + /* Crazy hack here for cases where 9 or more bytes are remaining... + * We want to use the above vectorized code to check a block of less than 16 bytes, + * but there is no good way to read a variable number of bytes into an XMM register + * However, we know that these bytes are part of a zend_string, and a zend_string has some + * 'header' fields which occupy the memory just before its content + * And, those header fields occupy more than 16 bytes... + * So if we go back 16 bytes from the end of the zend_string content, and load 16 bytes from there, + * we may pick up some 'junk' bytes from the zend_string header fields, but we will get the 1-15 + * bytes we wanted in the tail end of our XMM register, and this will never cause a segfault. + * Then, we do a left shift to get rid of the unwanted bytes + * Conveniently, the same left shift also zero-fills the tail end of the XMM register + * + * The following `switch` looks useless, but it's not + * The PSRLDQ instruction used for the 128-bit left shift requires an immediate (literal) + * shift distance, so the compiler will choke on _mm_srli_si128(operand, shift_dist) + */ + switch (remaining_bytes) { + case 0: ; + __m128i bad_mask = _mm_set_epi8(-64, -32, -16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); + __m128i bad = _mm_cmpeq_epi8(_mm_and_si128(last_block, bad_mask), bad_mask); + return _mm_movemask_epi8(bad) == 0; + case 1: + case 2: + operand = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, *((uint16_t*)p)); + goto check_operand; + case 3: + case 4: + operand = _mm_set_epi32(0, 0, 0, *((uint32_t*)p)); + goto check_operand; + case 5: + operand = _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 10)), 10); + goto check_operand; + case 6: + operand = _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 9)), 9); + goto check_operand; + case 7: + case 8: + operand = _mm_set_epi64x(0, *((uint64_t*)p)); + goto check_operand; + case 9: + operand = _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 6)), 6); + goto check_operand; + case 10: + operand = _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 5)), 5); + goto check_operand; + case 11: + operand = _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 4)), 4); + goto check_operand; + case 12: + operand = _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 3)), 3); + goto check_operand; + case 13: + operand = _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 2)), 2); + goto check_operand; + case 14: + operand = _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 1)), 1); + goto check_operand; + case 15: + /* No trailing bytes are left which need to be checked + * We get 15 because we did not include the terminating null when + * calculating `remaining_bytes`, so the value wraps around */ + return true; + } + + ZEND_UNREACHABLE(); + } + + return true; +# else + /* This UTF-8 validation function is derived from PCRE2 */ + size_t length = ZSTR_LEN(str); + /* Table of the number of extra bytes, indexed by the first byte masked with + 0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */ + static const uint8_t utf8_table[] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3 + }; + + for (; length > 0; p++) { + uint32_t d; + unsigned char c = *p; + length--; + + if (c < 128) { + /* ASCII character */ + continue; + } + + if (c < 0xc0) { + /* Isolated 10xx xxxx byte */ + return false; + } + + if (c >= 0xf5) { + return false; + } + + uint32_t ab = utf8_table[c & 0x3f]; /* Number of additional bytes (1-3) */ + if (length < ab) { + /* Missing bytes */ + return false; + } + length -= ab; + + /* Check top bits in the second byte */ + if (((d = *(++p)) & 0xc0) != 0x80) { + return false; + } + + /* For each length, check that the remaining bytes start with the 0x80 bit + * set and not the 0x40 bit. Then check for an overlong sequence, and for the + * excluded range 0xd800 to 0xdfff. */ + switch (ab) { + case 1: + /* 2-byte character. No further bytes to check for 0x80. Check first byte + * for xx00 000x (overlong sequence). */ + if ((c & 0x3e) == 0) { + return false; + } + break; + + case 2: + /* 3-byte character. Check third byte for 0x80. Then check first 2 bytes for + * 1110 0000, xx0x xxxx (overlong sequence) or 1110 1101, 1010 xxxx (0xd800-0xdfff) */ + if ((*(++p) & 0xc0) != 0x80 || (c == 0xe0 && (d & 0x20) == 0) || (c == 0xed && d >= 0xa0)) { + return false; + } + break; + + case 3: + /* 4-byte character. Check 3rd and 4th bytes for 0x80. Then check first 2 + * bytes for 1111 0000, xx00 xxxx (overlong sequence), then check for a + * character greater than 0x0010ffff (f4 8f bf bf) */ + if ((*(++p) & 0xc0) != 0x80 || (*(++p) & 0xc0) != 0x80 || (c == 0xf0 && (d & 0x30) == 0) || (c > 0xf4 || (c == 0xf4 && d > 0x8f))) { + return false; + } + break; + + EMPTY_SWITCH_DEFAULT_CASE(); + } + } + + return true; +# endif +} + +#endif /* #ifndef ZEND_INTRIN_AVX2_NATIVE */ + +#ifdef ZEND_INTRIN_AVX2_NATIVE + +/* We are building AVX2-only binary */ +# include +# define mb_fast_check_utf8 mb_fast_check_utf8_avx2 + +#elif defined(ZEND_INTRIN_AVX2_RESOLVER) + +/* We are building binary which works with or without AVX2; whether or not to use + * AVX2-accelerated functions will be determined at runtime */ +# include +# include "Zend/zend_cpuinfo.h" + +# ifdef ZEND_INTRIN_AVX2_FUNC_PROTO +/* Dynamic linker will decide whether or not to use AVX2-based functions and + * resolve symbols accordingly */ + +ZEND_INTRIN_AVX2_FUNC_DECL(bool mb_fast_check_utf8_avx2(zend_string *str)); + +bool mb_fast_check_utf8(zend_string *str) __attribute__((ifunc("resolve_check_utf8"))); + +typedef bool (*check_utf8_func_t)(zend_string*); + +ZEND_NO_SANITIZE_ADDRESS +ZEND_ATTRIBUTE_UNUSED +static check_utf8_func_t resolve_check_utf8(void) +{ + if (zend_cpu_supports_avx2()) { + return mb_fast_check_utf8_avx2; + } + return mb_fast_check_utf8_default; +} + +# else /* ZEND_INTRIN_AVX2_FUNC_PTR */ +/* We are compiling for a target where the dynamic linker will not be able to + * resolve symbols according to whether the host supports AVX2 or not; so instead, + * we can make calls go through a function pointer and set the function pointer + * on module load */ + +#ifdef HAVE_FUNC_ATTRIBUTE_TARGET +static bool mb_fast_check_utf8_avx2(zend_string *str) __attribute__((target("avx2"))); +#else +static bool mb_fast_check_utf8_avx2(zend_string *str); +#endif + +static bool (*check_utf8_ptr)(zend_string *str) = NULL; + +static bool mb_fast_check_utf8(zend_string *str) +{ + return check_utf8_ptr(str); +} + +static void init_check_utf8(void) +{ + if (zend_cpu_supports_avx2()) { + check_utf8_ptr = mb_fast_check_utf8_avx2; + } else { + check_utf8_ptr = mb_fast_check_utf8_default; + } +} +# endif + +#else + +/* No AVX2 support */ +#define mb_fast_check_utf8 mb_fast_check_utf8_default + +#endif + +#if defined(ZEND_INTRIN_AVX2_NATIVE) || defined(ZEND_INTRIN_AVX2_RESOLVER) + +/* Take (256-bit) `hi` and `lo` as a 512-bit value, shift down by some + * number of bytes, then take the low 256 bits + * This is used to take some number of trailing bytes from the previous 32-byte + * block followed by some number of leading bytes from the current 32-byte block + * + * _mm256_alignr_epi8 (VPALIGNR) is used to shift out bytes from a 256-bit + * YMM register while shifting in bytes from another YMM register... but + * it works separately on respective 128-bit halves of the YMM registers, + * which is not what we want. + * To make it work as desired, we first do _mm256_permute2x128_si256 + * (VPERM2I128) to combine the low 128 bits from the previous block and + * the high 128 bits of the current block in one YMM register. + * Then VPALIGNR will do what is needed. */ +#define _mm256_shift_epi8(hi, lo, shift) _mm256_alignr_epi8(lo, _mm256_permute2x128_si256(hi, lo, 33), 16 - shift) + +/* AVX2-based UTF-8 validation function; validates text in 32-byte chunks + * + * Some parts of this function are the same as `mb_fast_check_utf8`; code comments + * are not repeated, so consult `mb_fast_check_utf8` for information on uncommented + * sections. */ +#ifdef ZEND_INTRIN_AVX2_FUNC_PROTO +ZEND_API bool mb_fast_check_utf8_avx2(zend_string *str) +#else +static bool mb_fast_check_utf8_avx2(zend_string *str) +#endif +{ + unsigned char *p = (unsigned char*)ZSTR_VAL(str); + unsigned char *e = p + ((ZSTR_LEN(str) + 1) & ~(sizeof(__m256i) - 1)); + + /* The algorithm used here for UTF-8 validation is partially adapted from the + * paper "Validating UTF-8 In Less Than One Instruction Per Byte", by John Keiser + * and Daniel Lemire. + * Ref: https://arxiv.org/pdf/2010.03090.pdf + * + * Most types of invalid UTF-8 text can be detected by examining pairs of + * successive bytes. Specifically: + * + * • Overlong 2-byte code units start with 0xC0 or 0xC1. + * No valid UTF-8 string ever uses these byte values. + * • Overlong 3-byte code units start with 0xE0, followed by a byte < 0xA0. + * • Overlong 4-byte code units start with 0xF0, followed by a byte < 0x90. + * • 5-byte or 6-byte code units, which should never be used, start with + * 0xF8-FE. + * • A codepoint value higher than U+10FFFF, which is the highest value for + * any Unicode codepoint, would either start with 0xF4, followed by a + * byte >= 0x90, or else would start with 0xF5-F7, followed by any value. + * • A codepoint value from U+D800-DFFF, which are reserved and should never + * be used, would start with 0xED, followed by a byte >= 0xA0. + * • The byte value 0xFF is also illegal and is never used in valid UTF-8. + * + * To detect all these problems, for each pair of successive bytes, we do + * table lookups using the high nibble of the first byte, the low nibble of + * the first byte, and the high nibble of the second byte. Each table lookup + * retrieves a bitmask, in which each 1 bit indicates a possible invalid + * combination; AND those three bitmasks together, and any 1 bit in the result + * will indicate an actual invalid byte combination was found. + */ + +#define BAD_BYTE 0x1 +#define OVERLONG_2BYTE 0x2 +#define _1BYTE (BAD_BYTE | OVERLONG_2BYTE) +#define OVERLONG_3BYTE 0x4 +#define SURROGATE 0x8 +#define OVERLONG_4BYTE 0x10 +#define INVALID_CP 0x20 + + /* Each of these are 16-entry tables, repeated twice; this is required by the + * VPSHUFB instruction which we use to perform 32 table lookups in parallel + * The first entry is for 0xF, the second is for 0xE, and so on down to 0x0 + * + * So, for example, notice that the 4th entry in the 1st table is OVERLONG_2BYTE; + * that means that high nibble 0xC is consistent with the byte pair being part of + * an overlong 2-byte code unit */ + const __m256i bad_hi_nibble2 = _mm256_set_epi8( + BAD_BYTE | OVERLONG_4BYTE | INVALID_CP, OVERLONG_3BYTE | SURROGATE, 0, OVERLONG_2BYTE, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + BAD_BYTE | OVERLONG_4BYTE | INVALID_CP, OVERLONG_3BYTE | SURROGATE, 0, OVERLONG_2BYTE, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0); + const __m256i bad_lo_nibble2 = _mm256_set_epi8( + BAD_BYTE, BAD_BYTE, BAD_BYTE | SURROGATE, BAD_BYTE, + BAD_BYTE, BAD_BYTE, BAD_BYTE, BAD_BYTE, + BAD_BYTE, BAD_BYTE, BAD_BYTE, INVALID_CP, + 0, 0, OVERLONG_2BYTE, OVERLONG_2BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + BAD_BYTE, BAD_BYTE, BAD_BYTE | SURROGATE, BAD_BYTE, + BAD_BYTE, BAD_BYTE, BAD_BYTE, BAD_BYTE, + BAD_BYTE, BAD_BYTE, BAD_BYTE, INVALID_CP, + 0, 0, OVERLONG_2BYTE, OVERLONG_2BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE); + const __m256i bad_hi_nibble = _mm256_set_epi8( + _1BYTE | SURROGATE | INVALID_CP, _1BYTE | SURROGATE | INVALID_CP, + _1BYTE | SURROGATE | INVALID_CP, _1BYTE | SURROGATE | INVALID_CP, + _1BYTE | SURROGATE | INVALID_CP, _1BYTE | SURROGATE | INVALID_CP, + _1BYTE | OVERLONG_3BYTE | INVALID_CP, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | SURROGATE | INVALID_CP, _1BYTE | SURROGATE | INVALID_CP, + _1BYTE | SURROGATE | INVALID_CP, _1BYTE | SURROGATE | INVALID_CP, + _1BYTE | SURROGATE | INVALID_CP, _1BYTE | SURROGATE | INVALID_CP, + _1BYTE | OVERLONG_3BYTE | INVALID_CP, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, + _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE, _1BYTE | OVERLONG_3BYTE | OVERLONG_4BYTE); + + const __m256i find_continuation = _mm256_set1_epi8(-64); + const __m256i _b = _mm256_set1_epi8(0xB); + const __m256i _d = _mm256_set1_epi8(0xD); + const __m256i _f = _mm256_set1_epi8(0xF); + + __m256i last_hi_nibbles = _mm256_setzero_si256(), last_lo_nibbles = _mm256_setzero_si256(); + __m256i operand; + + while (p < e) { + operand = _mm256_loadu_si256((__m256i*)p); + +check_operand: + if (!_mm256_movemask_epi8(operand)) { + /* Entire 32-byte block is ASCII characters; the only thing we need to validate is that + * the previous block didn't end with an incomplete multi-byte character + * (This will also confirm that the previous block didn't end with a bad byte like 0xFF) */ + __m256i bad_mask = _mm256_set_epi8(0xB, 0xD, 0xE, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127); + __m256i bad = _mm256_cmpgt_epi8(last_hi_nibbles, bad_mask); + if (_mm256_movemask_epi8(bad)) { + return false; + } + + /* Consume as many full blocks of single-byte characters as we can */ + while (true) { + p += sizeof(__m256i); + if (p >= e) { + goto finish_up_remaining_bytes; + } + operand = _mm256_loadu_si256((__m256i*)p); + if (_mm256_movemask_epi8(operand)) { + break; + } + } + } + + __m256i hi_nibbles = _mm256_and_si256(_mm256_srli_epi16(operand, 4), _f); + __m256i lo_nibbles = _mm256_and_si256(operand, _f); + + __m256i lo_nibbles2 = _mm256_shift_epi8(last_lo_nibbles, lo_nibbles, 1); + __m256i hi_nibbles2 = _mm256_shift_epi8(last_hi_nibbles, hi_nibbles, 1); + + /* Do parallel table lookups in all 3 tables */ + __m256i bad = _mm256_cmpgt_epi8( + _mm256_and_si256( + _mm256_and_si256( + _mm256_shuffle_epi8(bad_lo_nibble2, lo_nibbles2), + _mm256_shuffle_epi8(bad_hi_nibble2, hi_nibbles2)), + _mm256_shuffle_epi8(bad_hi_nibble, hi_nibbles)), + _mm256_setzero_si256()); + + __m256i cont_mask = _mm256_cmpgt_epi8(hi_nibbles2, _b); + __m256i hi_nibbles3 = _mm256_shift_epi8(last_hi_nibbles, hi_nibbles, 2); + cont_mask = _mm256_or_si256(cont_mask, _mm256_cmpgt_epi8(hi_nibbles3, _d)); + __m256i hi_nibbles4 = _mm256_shift_epi8(last_hi_nibbles, hi_nibbles, 3); + cont_mask = _mm256_or_si256(cont_mask, _mm256_cmpeq_epi8(hi_nibbles4, _f)); + + __m256i continuation = _mm256_cmpgt_epi8(find_continuation, operand); + bad = _mm256_or_si256(bad, _mm256_xor_si256(continuation, cont_mask)); + + if (_mm256_movemask_epi8(bad)) { + return false; + } + + last_hi_nibbles = hi_nibbles; + last_lo_nibbles = lo_nibbles; + p += sizeof(__m256i); + } + +finish_up_remaining_bytes: + if (p == e) { + uint8_t remaining_bytes = ZSTR_LEN(str) & (sizeof(__m256i) - 1); /* Not including terminating null */ + + switch (remaining_bytes) { + case 0: ; + /* No actual data bytes are remaining */ + __m256i bad_mask = _mm256_set_epi8(0xB, 0xD, 0xE, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127); + __m256i bad = _mm256_cmpgt_epi8(last_hi_nibbles, bad_mask); + return _mm256_movemask_epi8(bad) == 0; + case 1: + case 2: + operand = _mm256_set_epi16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, *((int16_t*)p)); + goto check_operand; + case 3: + case 4: + operand = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, *((int32_t*)p)); + goto check_operand; + case 5: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 10)), 10)); + goto check_operand; + case 6: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 9)), 9)); + goto check_operand; + case 7: + case 8: + /* This was originally: operand = _mm256_set_epi64x(0, 0, 0, *((int64_t*)p)); + * However, that caused test failures on 32-bit MS Windows + * (Bad 7/8-byte UTF-8 strings would be wrongly passed through as 'valid') + * It seems this is caused by a bug in MS Visual C++ + * Ref: https://stackoverflow.com/questions/37509129/potential-bug-in-visual-studio-c-compiler-or-in-intel-intrinsics-avx2-mm256-s */ + operand = _mm256_set_epi32(0, 0, 0, 0, 0, 0, ((int32_t*)p)[1], ((int32_t*)p)[0]); + goto check_operand; + case 9: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 6)), 6)); + goto check_operand; + case 10: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 5)), 5)); + goto check_operand; + case 11: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 4)), 4)); + goto check_operand; + case 12: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 3)), 3)); + goto check_operand; + case 13: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 2)), 2)); + goto check_operand; + case 14: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_srli_si128(_mm_loadu_si128((__m128i*)(p - 1)), 1)); + goto check_operand; + case 15: + case 16: + operand = _mm256_set_m128i(_mm_setzero_si128(), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 17: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 2)), 14), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 18: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 3)), 13), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 19: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 4)), 12), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 20: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 5)), 11), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 21: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 6)), 10), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 22: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 7)), 9), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 23: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 8)), 8), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 24: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 9)), 7), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 25: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 10)), 6), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 26: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 11)), 5), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 27: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 12)), 4), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 28: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 13)), 3), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 29: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 14)), 2), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 30: + operand = _mm256_set_m128i(_mm_srli_si128(_mm_loadu_si128((__m128i*)(p + 15)), 1), _mm_loadu_si128((__m128i*)p)); + goto check_operand; + case 31: + return true; + } + + ZEND_UNREACHABLE(); + } + + return true; +} + +#endif /* defined(ZEND_INTRIN_AVX2_NATIVE) || defined(ZEND_INTRIN_AVX2_RESOLVER) */ + static bool mb_check_str_encoding(zend_string *str, const mbfl_encoding *encoding) { if (encoding == &mbfl_encoding_utf8) { if (GC_FLAGS(str) & IS_STR_VALID_UTF8) { return true; } - bool result = php_mb_check_encoding(ZSTR_VAL(str), ZSTR_LEN(str), encoding); + bool result = mb_fast_check_utf8(str); if (result && !ZSTR_IS_INTERNED(str)) { GC_ADD_FLAGS(str, IS_STR_VALID_UTF8); } @@ -4539,7 +5317,6 @@ PHP_FUNCTION(mb_check_encoding) } /* }}} */ - static inline zend_long php_mb_ord(const char *str, size_t str_len, zend_string *enc_name, const uint32_t enc_name_arg_num) { @@ -4572,7 +5349,6 @@ static inline zend_long php_mb_ord(const char *str, size_t str_len, zend_string return wchar_buf[0]; } - /* {{{ */ PHP_FUNCTION(mb_ord) { @@ -4605,7 +5381,6 @@ PHP_FUNCTION(mb_ord) } /* }}} */ - static inline zend_string *php_mb_chr(zend_long cp, zend_string *enc_name, uint32_t enc_name_arg_num) { const mbfl_encoding *enc; @@ -4676,7 +5451,6 @@ static inline zend_string *php_mb_chr(zend_long cp, zend_string *enc_name, uint3 return ret; } - /* {{{ */ PHP_FUNCTION(mb_chr) { @@ -4701,12 +5475,10 @@ PHP_FUNCTION(mb_chr) /* {{{ */ PHP_FUNCTION(mb_scrub) { - char* str; - size_t str_len; - zend_string *enc_name = NULL; + zend_string *str, *enc_name = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_STRING(str, str_len) + Z_PARAM_STR(str) Z_PARAM_OPTIONAL Z_PARAM_STR_OR_NULL(enc_name) ZEND_PARSE_PARAMETERS_END(); @@ -4716,11 +5488,15 @@ PHP_FUNCTION(mb_scrub) RETURN_THROWS(); } - RETURN_STR(php_mb_convert_encoding_ex(str, str_len, enc, enc)); + if (enc == &mbfl_encoding_utf8 && (GC_FLAGS(str) & IS_STR_VALID_UTF8)) { + /* A valid UTF-8 string will not be changed by mb_scrub; so just increment the refcount and return it */ + RETURN_STR_COPY(str); + } + + RETURN_STR(php_mb_convert_encoding_ex(ZSTR_VAL(str), ZSTR_LEN(str), enc, enc)); } /* }}} */ - /* {{{ php_mb_populate_current_detect_order_list */ static void php_mb_populate_current_detect_order_list(void) { @@ -4811,10 +5587,10 @@ MBSTRING_API size_t php_mb_stripos(bool mode, zend_string *haystack, zend_string { /* We're using simple case-folding here, because we'd have to deal with remapping of * offsets otherwise. */ - zend_string *haystack_conv = mbstring_convert_case(PHP_UNICODE_CASE_FOLD_SIMPLE, ZSTR_VAL(haystack), ZSTR_LEN(haystack), enc); - zend_string *needle_conv = mbstring_convert_case(PHP_UNICODE_CASE_FOLD_SIMPLE, ZSTR_VAL(needle), ZSTR_LEN(needle), enc); + zend_string *haystack_conv = php_unicode_convert_case(PHP_UNICODE_CASE_FOLD_SIMPLE, ZSTR_VAL(haystack), ZSTR_LEN(haystack), enc, &mbfl_encoding_utf8, MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8, 0); + zend_string *needle_conv = php_unicode_convert_case(PHP_UNICODE_CASE_FOLD_SIMPLE, ZSTR_VAL(needle), ZSTR_LEN(needle), enc, &mbfl_encoding_utf8, MBFL_OUTPUTFILTER_ILLEGAL_MODE_BADUTF8, 0); - size_t n = mb_find_strpos(haystack_conv, needle_conv, enc, offset, mode); + size_t n = mb_find_strpos(haystack_conv, needle_conv, &mbfl_encoding_utf8, offset, mode); zend_string_free(haystack_conv); zend_string_free(needle_conv); @@ -4834,3 +5610,647 @@ static void php_mb_gpc_set_input_encoding(const zend_encoding *encoding) /* {{{ MBSTRG(http_input_identify) = (const mbfl_encoding*)encoding; } /* }}} */ + +static const unsigned char base64_table[] = { + /* 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', */ + 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d, + /* 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', */ + 0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a, + /* 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', */ + 0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d, + /* 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', */ + 0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a, + /* '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' */ + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x2b,0x2f,0x00 +}; + +static size_t transfer_encoded_size(mb_convert_buf *tmpbuf, bool base64) +{ + if (base64) { + return ((mb_convert_buf_len(tmpbuf) + 2) / 3) * 4; + } else { + size_t enc_size = 0; + unsigned char *p = (unsigned char*)ZSTR_VAL(tmpbuf->str); + while (p < tmpbuf->out) { + unsigned char c = *p++; + enc_size += (c > 0x7F || c == '=' || mime_char_needs_qencode[c]) ? 3 : 1; + } + return enc_size; + } +} + +static void transfer_encode_mime_bytes(mb_convert_buf *tmpbuf, mb_convert_buf *outbuf, bool base64) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(outbuf, out, limit); + unsigned char *p = (unsigned char*)ZSTR_VAL(tmpbuf->str), *e = tmpbuf->out; + + if (base64) { + MB_CONVERT_BUF_ENSURE(outbuf, out, limit, ((e - p) + 2) / 3 * 4); + while ((e - p) >= 3) { + unsigned char a = *p++; + unsigned char b = *p++; + unsigned char c = *p++; + uint32_t bits = (a << 16) | (b << 8) | c; + out = mb_convert_buf_add4(out, + base64_table[(bits >> 18) & 0x3F], + base64_table[(bits >> 12) & 0x3F], + base64_table[(bits >> 6) & 0x3F], + base64_table[bits & 0x3F]); + } + if (p != e) { + if ((e - p) == 1) { + uint32_t bits = *p++; + out = mb_convert_buf_add4(out, base64_table[(bits >> 2) & 0x3F], base64_table[(bits & 0x3) << 4], '=', '='); + } else { + unsigned char a = *p++; + unsigned char b = *p++; + uint32_t bits = (a << 8) | b; + out = mb_convert_buf_add4(out, base64_table[(bits >> 10) & 0x3F], base64_table[(bits >> 4) & 0x3F], base64_table[(bits & 0xF) << 2], '='); + } + } + } else { + MB_CONVERT_BUF_ENSURE(outbuf, out, limit, (e - p) * 3); + while (p < e) { + unsigned char c = *p++; + if (c > 0x7F || c == '=' || mime_char_needs_qencode[c]) { + out = mb_convert_buf_add3(out, '=', "0123456789ABCDEF"[(c >> 4) & 0xF], "0123456789ABCDEF"[c & 0xF]); + } else { + out = mb_convert_buf_add(out, c); + } + } + } + + mb_convert_buf_reset(tmpbuf, 0); + MB_CONVERT_BUF_STORE(outbuf, out, limit); +} + +static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encoding *incode, const mbfl_encoding *outcode, bool base64, char *linefeed, size_t linefeed_len, zend_long indent) +{ + unsigned char *in = (unsigned char*)ZSTR_VAL(input); + size_t in_len = ZSTR_LEN(input); + + if (!in_len) { + return zend_empty_string; + } + + if (indent < 0 || indent >= 74) { + indent = 0; + } + + if (linefeed_len > 8) { + linefeed_len = 8; + } + /* Maintain legacy behavior as regards embedded NUL (zero) bytes in linefeed string */ + for (size_t i = 0; i < linefeed_len; i++) { + if (linefeed[i] == '\0') { + linefeed_len = i; + break; + } + } + + unsigned int state = 0; + /* wchar_buf should be big enough that when it is full, we definitely have enough + * wchars to fill an entire line of output */ + uint32_t wchar_buf[80]; + uint32_t *p, *e; + /* What part of wchar_buf is filled with still-unprocessed data which should not + * be overwritten? */ + unsigned int offset = 0; + size_t line_start = 0; + + /* If the entire input string is ASCII with no spaces (except possibly leading + * spaces), just pass it through unchanged */ + bool checking_leading_spaces = true; + while (in_len) { + size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf, 80, &state); + p = wchar_buf; + e = wchar_buf + out_len; + + while (p < e) { + uint32_t w = *p++; + if (checking_leading_spaces) { + if (w == ' ') { + continue; + } else { + checking_leading_spaces = false; + } + } + if (w < 0x21 || w > 0x7E || w == '=' || w == '?' || w == '_') { + /* We cannot simply pass input string through unchanged; start again */ + in = (unsigned char*)ZSTR_VAL(input); + in_len = ZSTR_LEN(input); + goto no_passthrough; + } + } + } + + return zend_string_copy(input); /* This just increments refcount */ + +no_passthrough: ; + + mb_convert_buf buf; + mb_convert_buf_init(&buf, in_len, '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR); + + /* Encode some prefix of the input string as plain ASCII if possible + * If we find it necessary to switch to Base64/QPrint encoding, we will + * do so all the way to the end of the string */ + while (in_len) { + /* Decode part of the input string, refill wchar_buf */ + ZEND_ASSERT(offset < 80); + size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, 80 - offset, &state); + ZEND_ASSERT(out_len <= 80 - offset); + p = wchar_buf; + e = wchar_buf + offset + out_len; + /* ASCII output is broken into space-delimited 'words' + * If we find a non-ASCII character in the middle of a word, we will + * transfer-encode the entire word */ + uint32_t *word_start = p; + + /* Don't consider adding line feed for spaces at the beginning of a word */ + while (p < e && *p == ' ' && (p - word_start) <= 74) { + p++; + } + + while (p < e) { + uint32_t w = *p++; + + if (w < 0x20 || w > 0x7E || w == '?' || w == '=' || w == '_' || (w == ' ' && (p - word_start) > 74)) { + /* Non-ASCII character (or line too long); switch to Base64/QPrint encoding + * If we are already too far along on a line to include Base64/QPrint encoded data + * on the same line (without overrunning max line length), then add a line feed + * right now */ + if (mb_convert_buf_len(&buf) - line_start + indent + strlen(outcode->mime_name) > 55) { + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, (e - word_start) + linefeed_len + 1); + buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len); + buf.out = mb_convert_buf_add(buf.out, ' '); + indent = 0; + line_start = mb_convert_buf_len(&buf); + } else if (mb_convert_buf_len(&buf) > 0) { + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, 1); + buf.out = mb_convert_buf_add(buf.out, ' '); + } + p = word_start; /* Back up to where MIME encoding of input chars should start */ + goto mime_encoding_needed; + } else if (w == ' ') { + /* When we see a space, check whether we should insert a line break */ + if (mb_convert_buf_len(&buf) - line_start + (p - word_start) + indent > 75) { + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, (e - word_start) + linefeed_len + 1); + buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len); + buf.out = mb_convert_buf_add(buf.out, ' '); + indent = 0; + line_start = mb_convert_buf_len(&buf); + } else if (mb_convert_buf_len(&buf) > 0) { + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, (e - word_start) + 1); + buf.out = mb_convert_buf_add(buf.out, ' '); + } + /* Output one (space-delimited) word as plain ASCII */ + while (word_start < p-1) { + buf.out = mb_convert_buf_add(buf.out, *word_start++ & 0xFF); + } + word_start++; + while (p < e && *p == ' ') { + p++; + } + } + } + + if (in_len) { + /* Copy chars which are part of an incomplete 'word' to the beginning + * of wchar_buf and reprocess them on the next iteration */ + offset = e - word_start; + if (offset) { + memmove(wchar_buf, word_start, offset * sizeof(uint32_t)); + } + } else { + /* We have reached the end of the input string while still in 'ASCII mode'; + * process any trailing ASCII chars which were not followed by a space */ + if (word_start < e && mb_convert_buf_len(&buf) > 0) { + /* The whole input string was not just one big ASCII 'word' with no spaces + * consider adding a line feed if necessary to prevent output lines from + * being too long */ + if (mb_convert_buf_len(&buf) - line_start + (p - word_start) + indent > 74) { + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, (e - word_start) + linefeed_len + 1); + buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len); + buf.out = mb_convert_buf_add(buf.out, ' '); + } else { + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, (e - word_start) + 1); + buf.out = mb_convert_buf_add(buf.out, ' '); + } + } + while (word_start < e) { + buf.out = mb_convert_buf_add(buf.out, *word_start++ & 0xFF); + } + } + } + + /* Ensure output string is marked as valid UTF-8 (ASCII strings are always 'valid UTF-8') */ + return mb_convert_buf_result(&buf, &mbfl_encoding_utf8); + +mime_encoding_needed: ; + + /* We will generate the output line by line, first converting wchars to bytes + * in the requested output encoding, then transfer-encoding those bytes as + * Base64 or QPrint + * 'tmpbuf' will receive the bytes which need to be transfer-encoded before + * sending them to 'buf' */ + mb_convert_buf tmpbuf; + mb_convert_buf_init(&tmpbuf, in_len, '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR); + + /* Do we need to refill wchar_buf to make sure we don't run out of wchars + * in the middle of a line? */ + if (p == wchar_buf) { + goto start_new_line; + } + offset = e - p; + memmove(wchar_buf, p, offset * sizeof(uint32_t)); + + while(true) { +refill_wchar_buf: ; + ZEND_ASSERT(offset < 80); + size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, 80 - offset, &state); + ZEND_ASSERT(out_len <= 80 - offset); + p = wchar_buf; + e = wchar_buf + offset + out_len; + +start_new_line: ; + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, strlen(outcode->mime_name) + 5); + buf.out = mb_convert_buf_add2(buf.out, '=', '?'); + buf.out = mb_convert_buf_appends(buf.out, outcode->mime_name); + buf.out = mb_convert_buf_add3(buf.out, '?', base64 ? 'B' : 'Q', '?'); + + /* How many wchars should we try converting to Base64/QPrint-encoded bytes? + * We do something like a 'binary search' to find the greatest number which + * can be included on this line without exceeding max line length */ + unsigned int n = 12; + size_t space_available = 73 - indent - (mb_convert_buf_len(&buf) - line_start); + + while (true) { + ZEND_ASSERT(p < e); + + /* Remember where we were in process of generating output, so we can back + * up if necessary */ + size_t tmppos = mb_convert_buf_len(&tmpbuf); + unsigned int tmpstate = tmpbuf.state; + + /* Try encoding 'n' wchars in output text encoding and sending output + * bytes to 'tmpbuf'. Hopefully this is not too many to fit on the + * current line. */ + n = MIN(n, e - p); + outcode->from_wchar(p, n, &tmpbuf, false); + + /* For some output text encodings, there may be a few ending bytes + * which need to be emitted to output before we break a line. + * Again, remember where we were so we can back up */ + size_t tmppos2 = mb_convert_buf_len(&tmpbuf); + unsigned int tmpstate2 = tmpbuf.state; + outcode->from_wchar(NULL, 0, &tmpbuf, true); + + if (transfer_encoded_size(&tmpbuf, base64) <= space_available || (n == 1 && tmppos == 0)) { + /* If we convert 'n' more wchars on the current line, it will not + * overflow the maximum line length */ + p += n; + + if (p == e) { + /* We are done; we shouldn't reach here if there is more remaining + * of the input string which needs to be processed */ + ZEND_ASSERT(!in_len); + transfer_encode_mime_bytes(&tmpbuf, &buf, base64); + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, 2); + buf.out = mb_convert_buf_add2(buf.out, '?', '='); + mb_convert_buf_free(&tmpbuf); + return mb_convert_buf_result(&buf, &mbfl_encoding_utf8); + } else { + /* It's possible that more chars might fit on the current line, + * so back up to where we were before emitting any ending bytes */ + mb_convert_buf_reset(&tmpbuf, tmppos2); + tmpbuf.state = tmpstate2; + } + } else { + /* Converting 'n' more wchars on this line would be too much. + * Back up to where we were before we tried that. */ + mb_convert_buf_reset(&tmpbuf, tmppos); + tmpbuf.state = tmpstate; + + if (n == 1) { + /* We have found the exact number of chars which will fit on the + * current line. Finish up and move to a new line. */ + outcode->from_wchar(NULL, 0, &tmpbuf, true); + transfer_encode_mime_bytes(&tmpbuf, &buf, base64); + tmpbuf.state = 0; + + MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, 3 + linefeed_len); + buf.out = mb_convert_buf_add2(buf.out, '?', '='); + + indent = 0; /* Indent argument must only affect the first line */ + + if (in_len) { + /* We still have more of input string remaining to decode */ + buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len); + buf.out = mb_convert_buf_add(buf.out, ' '); + line_start = mb_convert_buf_len(&buf); + /* Copy remaining wchars to beginning of buffer so they will be + * processed on the next iteration of outer 'do' loop */ + offset = e - p; + memmove(wchar_buf, p, offset * sizeof(uint32_t)); + goto refill_wchar_buf; + } else if (p < e) { + /* Input string is finished, but we still have trailing wchars + * remaining to be processed in wchar_buf */ + buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len); + buf.out = mb_convert_buf_add(buf.out, ' '); + line_start = mb_convert_buf_len(&buf); + goto start_new_line; + } else { + /* We are done! */ + mb_convert_buf_free(&tmpbuf); + return mb_convert_buf_result(&buf, &mbfl_encoding_utf8); + } + } else { + /* Try a smaller number of wchars */ + n = MAX(n >> 1, 1); + } + } + } + } +} + +PHP_FUNCTION(mb_encode_mimeheader) +{ + const mbfl_encoding *charset = &mbfl_encoding_pass; + zend_string *str, *charset_name = NULL, *transenc_name = NULL; + char *linefeed = "\r\n"; + size_t linefeed_len = 2; + zend_long indent = 0; + bool base64 = true; + + ZEND_PARSE_PARAMETERS_START(1, 5) + Z_PARAM_STR(str) + Z_PARAM_OPTIONAL + Z_PARAM_STR(charset_name) + Z_PARAM_STR(transenc_name) + Z_PARAM_STRING(linefeed, linefeed_len) + Z_PARAM_LONG(indent) + ZEND_PARSE_PARAMETERS_END(); + + if (charset_name != NULL) { + charset = php_mb_get_encoding(charset_name, 2); + if (!charset) { + RETURN_THROWS(); + } else if (charset->mime_name == NULL || charset->mime_name[0] == '\0') { + zend_argument_value_error(2, "\"%s\" cannot be used for MIME header encoding", ZSTR_VAL(charset_name)); + RETURN_THROWS(); + } + } else { + const mbfl_language *lang = mbfl_no2language(MBSTRG(language)); + if (lang != NULL) { + charset = mbfl_no2encoding(lang->mail_charset); + const mbfl_encoding *transenc = mbfl_no2encoding(lang->mail_header_encoding); + char t = transenc->name[0]; + if (t == 'Q' || t == 'q') { + base64 = false; + } + } + } + + if (transenc_name != NULL && ZSTR_LEN(transenc_name) > 0) { + char t = ZSTR_VAL(transenc_name)[0]; + if (t == 'Q' || t == 'q') { + base64 = false; + } + } + + RETURN_STR(mb_mime_header_encode(str, MBSTRG(current_internal_encoding), charset, base64, linefeed, linefeed_len, indent)); +} + +static int8_t decode_base64(unsigned char c) +{ + if (c >= 'A' && c <= 'Z') { + return c - 'A'; + } else if (c >= 'a' && c <= 'z') { + return c - 'a' + 26; + } else if (c >= '0' && c <= '9') { + return c - '0' + 52; + } else if (c == '+') { + return 62; + } else if (c == '/') { + return 63; + } + return -1; +} + +static int8_t qprint_map[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/* Decode MIME encoded word as defined in RFC 2047 */ +static unsigned char* mime_header_decode_encoded_word(unsigned char *p, unsigned char *e, const mbfl_encoding *outcode, mb_convert_buf *outbuf, unsigned int *state) +{ + if ((e - p) < 6) { + return NULL; + } + + ZEND_ASSERT(p[0] == '='); + ZEND_ASSERT(p[1] == '?'); + p += 2; + + unsigned char *charset = p; + unsigned char *charset_end = memchr(charset, '?', e - charset); + if (charset_end == NULL) { + return NULL; + } + + unsigned char *encoding = charset_end + 1; + p = encoding + 1; + if (p >= e || *p++ != '?') { + return NULL; + } + + char *charset_name = estrndup((const char*)charset, charset_end - charset); + const mbfl_encoding *incode = mbfl_name2encoding(charset_name); + efree(charset_name); + if (incode == NULL) { + return NULL; + } + + unsigned char *end_marker = (unsigned char*)zend_memnstr((const char*)p, "?=", 2, (const char*)e); + if (end_marker) { + e = end_marker; + } else if (p < e && *(e-1) == '?') { + /* If encoded word is not properly terminated, but last byte is '?', + * take that as a terminator (legacy behavior) */ + e--; + } + + unsigned char *buf = emalloc(e - p), *bufp = buf; + if (*encoding == 'Q' || *encoding == 'q') { + /* Fill `buf` with bytes from decoding QPrint */ + while (p < e) { + unsigned char c = *p++; + if (c == '_') { + *bufp++ = ' '; + continue; + } else if (c == '=' && (e - p) >= 2) { + unsigned char c2 = *p++; + unsigned char c3 = *p++; + if (qprint_map[c2] >= 0 && qprint_map[c3] >= 0) { + *bufp++ = (qprint_map[c2] << 4) | (qprint_map[c3] & 0xF); + continue; + } else if (c2 == '\r') { + if (c3 != '\n') { + p--; + } + continue; + } else if (c2 == '\n') { + p--; + continue; + } + } + *bufp++ = c; + } + } else if (*encoding == 'B' || *encoding == 'b') { + /* Fill `buf` with bytes from decoding Base64 */ + unsigned int bits = 0, cache = 0; + while (p < e) { + unsigned char c = *p++; + if (c == '\r' || c == '\n' || c == ' ' || c == '\t' || c == '=') { + continue; + } + int8_t decoded = decode_base64(c); + if (decoded == -1) { + *bufp++ = '?'; + continue; + } + bits += 6; + cache = (cache << 6) | (decoded & 0x3F); + if (bits == 24) { + *bufp++ = (cache >> 16) & 0xFF; + *bufp++ = (cache >> 8) & 0xFF; + *bufp++ = cache & 0xFF; + bits = cache = 0; + } + } + if (bits == 18) { + *bufp++ = (cache >> 10) & 0xFF; + *bufp++ = (cache >> 2) & 0xFF; + } else if (bits == 12) { + *bufp++ = (cache >> 4) & 0xFF; + } + } else { + efree(buf); + return NULL; + } + + size_t in_len = bufp - buf; + uint32_t wchar_buf[128]; + + bufp = buf; + while (in_len) { + size_t out_len = incode->to_wchar(&bufp, &in_len, wchar_buf, 128, state); + ZEND_ASSERT(out_len <= 128); + outcode->from_wchar(wchar_buf, out_len, outbuf, false); + } + + efree(buf); + return e + 2; +} + +static zend_string* mb_mime_header_decode(zend_string *input, const mbfl_encoding *outcode) +{ + unsigned char *p = (unsigned char*)ZSTR_VAL(input), *e = p + ZSTR_LEN(input); + unsigned int state = 0; + bool space_pending = false; + + mb_convert_buf buf; + mb_convert_buf_init(&buf, ZSTR_LEN(input), '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR); + + while (p < e) { + unsigned char c = *p; + + if (c == '=' && *(p + 1) == '?' && (e - p) >= 6) { + /* Does this look like a MIME encoded word? If so, try to decode it as one */ + unsigned char *incode_end = memchr(p + 2, '?', e - p - 2); + if (incode_end && (e - incode_end) >= 3) { + unsigned char *temp = mime_header_decode_encoded_word(p, e, outcode, &buf, &state); + if (temp) { + p = temp; + /* Decoding of MIME encoded word was successful; + * Try to collapse a run of whitespace */ + if (p < e && (*p == '\n' || *p == '\r')) { + do { + p++; + } while (p < e && (*p == '\n' || *p == '\r' || *p == '\t' || *p == ' ')); + /* We will only actually output a space if this is not immediately followed + * by another valid encoded word */ + space_pending = true; + } + continue; + } + } + } + + if (space_pending) { + uint32_t space = ' '; + outcode->from_wchar(&space, 1, &buf, false); + space_pending = false; + } + + /* Consume a run of plain ASCII characters */ + if (c != '\n' && c != '\r') { + unsigned char *end = p + 1; + while (end < e && (*end != '=' && *end != '\n' && *end != '\r')) { + end++; + } + uint32_t wchar_buf[128]; + size_t in_len = end - p; + while (in_len) { + size_t out_len = mbfl_encoding_ascii.to_wchar(&p, &in_len, wchar_buf, 128, &state); + ZEND_ASSERT(out_len <= 128); + outcode->from_wchar(wchar_buf, out_len, &buf, false); + } + } + /* Collapse a run of whitespace into a single space */ + if (p < e && (*p == '\n' || *p == '\r')) { + do { + p++; + } while (p < e && (*p == '\n' || *p == '\r' || *p == '\t' || *p == ' ')); + if (p < e) { + /* Emulating legacy behavior of mb_decode_mimeheader here; + * a run of whitespace is not converted to a space at the very + * end of the input string */ + uint32_t space = ' '; + outcode->from_wchar(&space, 1, &buf, false); + } + } + } + + outcode->from_wchar(NULL, 0, &buf, true); + + return mb_convert_buf_result(&buf, outcode); +} + +PHP_FUNCTION(mb_decode_mimeheader) +{ + zend_string *str; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + RETURN_STR(mb_mime_header_decode(str, MBSTRG(current_internal_encoding))); +} diff --git a/ext/mbstring/mbstring.h b/ext/mbstring/mbstring.h index aa5b8024cb74b..0837e45cf327a 100644 --- a/ext/mbstring/mbstring.h +++ b/ext/mbstring/mbstring.h @@ -67,6 +67,8 @@ MBSTRING_API size_t php_mb_mbchar_bytes(const char *s, const mbfl_encoding *enc) MBSTRING_API size_t php_mb_stripos(bool mode, zend_string *haystack, zend_string *needle, zend_long offset, const mbfl_encoding *enc); MBSTRING_API bool php_mb_check_encoding(const char *input, size_t length, const mbfl_encoding *encoding); +MBSTRING_API const mbfl_encoding* mb_guess_encoding_for_strings(const unsigned char **strings, size_t *str_lengths, size_t n, const mbfl_encoding **elist, unsigned int elist_size, bool strict); + ZEND_BEGIN_MODULE_GLOBALS(mbstring) char *internal_encoding_name; const mbfl_encoding *internal_encoding; @@ -94,7 +96,8 @@ ZEND_BEGIN_MODULE_GLOBALS(mbstring) bool encoding_translation; bool strict_detection; size_t illegalchars; - mbfl_buffer_converter *outconv; + bool outconv_enabled; + unsigned int outconv_state; void *http_output_conv_mimetypes; #ifdef HAVE_MBREGEX struct _zend_mb_regex_globals *mb_regex_globals; diff --git a/ext/mbstring/php_unicode.c b/ext/mbstring/php_unicode.c index e07490c884e7d..af48ba4287f5f 100644 --- a/ext/mbstring/php_unicode.c +++ b/ext/mbstring/php_unicode.c @@ -35,6 +35,8 @@ #include "php_unicode.h" #include "unicode_data.h" +extern const mbfl_encoding mbfl_encoding_8859_9; + ZEND_EXTERN_MODULE_GLOBALS(mbstring) static bool prop_lookup(unsigned long code, unsigned long n) @@ -118,14 +120,14 @@ static inline unsigned mph_lookup( mph_lookup(code, _uccase_##type##_g, _uccase_##type##_g_size, \ _uccase_##type##_table, _uccase_##type##_table_size) -static unsigned php_unicode_toupper_raw(unsigned code, enum mbfl_no_encoding enc) +static unsigned php_unicode_toupper_raw(unsigned code, const mbfl_encoding *enc) { /* After the ASCII characters, the first codepoint with an uppercase version * is 0xB5 (MICRO SIGN) */ if (code < 0xB5) { /* Fast path for ASCII */ if (code >= 0x61 && code <= 0x7A) { - if (UNEXPECTED(enc == mbfl_no_encoding_8859_9 && code == 0x69)) { + if (UNEXPECTED(enc == &mbfl_encoding_8859_9 && code == 0x69)) { return 0x130; } return code - 0x20; @@ -140,14 +142,14 @@ static unsigned php_unicode_toupper_raw(unsigned code, enum mbfl_no_encoding enc } } -static unsigned php_unicode_tolower_raw(unsigned code, enum mbfl_no_encoding enc) +static unsigned php_unicode_tolower_raw(unsigned code, const mbfl_encoding *enc) { /* After the ASCII characters, the first codepoint with a lowercase version * is 0xC0 (LATIN CAPITAL LETTER A WITH GRAVE) */ if (code < 0xC0) { /* Fast path for ASCII */ if (code >= 0x41 && code <= 0x5A) { - if (UNEXPECTED(enc == mbfl_no_encoding_8859_9 && code == 0x0049L)) { + if (UNEXPECTED(enc == &mbfl_encoding_8859_9 && code == 0x0049L)) { return 0x0131L; } return code + 0x20; @@ -156,7 +158,7 @@ static unsigned php_unicode_tolower_raw(unsigned code, enum mbfl_no_encoding enc } else { unsigned new_code = CASE_LOOKUP(code, lower); if (new_code != CODE_NOT_FOUND) { - if (UNEXPECTED(enc == mbfl_no_encoding_8859_9 && code == 0x130)) { + if (UNEXPECTED(enc == &mbfl_encoding_8859_9 && code == 0x130)) { return 0x69; } return new_code; @@ -165,7 +167,7 @@ static unsigned php_unicode_tolower_raw(unsigned code, enum mbfl_no_encoding enc } } -static unsigned php_unicode_totitle_raw(unsigned code, enum mbfl_no_encoding enc) +static unsigned php_unicode_totitle_raw(unsigned code, const mbfl_encoding *enc) { unsigned new_code = CASE_LOOKUP(code, title); if (new_code != CODE_NOT_FOUND) { @@ -176,12 +178,12 @@ static unsigned php_unicode_totitle_raw(unsigned code, enum mbfl_no_encoding enc return php_unicode_toupper_raw(code, enc); } -static unsigned php_unicode_tofold_raw(unsigned code, enum mbfl_no_encoding enc) +static unsigned php_unicode_tofold_raw(unsigned code, const mbfl_encoding *enc) { if (code < 0x80) { /* Fast path for ASCII */ if (code >= 0x41 && code <= 0x5A) { - if (UNEXPECTED(enc == mbfl_no_encoding_8859_9 && code == 0x49)) { + if (UNEXPECTED(enc == &mbfl_encoding_8859_9 && code == 0x49)) { return 0x131; } return code + 0x20; @@ -190,7 +192,7 @@ static unsigned php_unicode_tofold_raw(unsigned code, enum mbfl_no_encoding enc) } else { unsigned new_code = CASE_LOOKUP(code, fold); if (new_code != CODE_NOT_FOUND) { - if (UNEXPECTED(enc == mbfl_no_encoding_8859_9 && code == 0x130)) { + if (UNEXPECTED(enc == &mbfl_encoding_8859_9 && code == 0x130)) { return 0x69; } return new_code; @@ -199,28 +201,28 @@ static unsigned php_unicode_tofold_raw(unsigned code, enum mbfl_no_encoding enc) } } -static inline unsigned php_unicode_tolower_simple(unsigned code, enum mbfl_no_encoding enc) { +static inline unsigned php_unicode_tolower_simple(unsigned code, const mbfl_encoding *enc) { code = php_unicode_tolower_raw(code, enc); if (UNEXPECTED(code > 0xffffff)) { return _uccase_extra_table[code & 0xffffff]; } return code; } -static inline unsigned php_unicode_toupper_simple(unsigned code, enum mbfl_no_encoding enc) { +static inline unsigned php_unicode_toupper_simple(unsigned code, const mbfl_encoding *enc) { code = php_unicode_toupper_raw(code, enc); if (UNEXPECTED(code > 0xffffff)) { return _uccase_extra_table[code & 0xffffff]; } return code; } -static inline unsigned php_unicode_totitle_simple(unsigned code, enum mbfl_no_encoding enc) { +static inline unsigned php_unicode_totitle_simple(unsigned code, const mbfl_encoding *enc) { code = php_unicode_totitle_raw(code, enc); if (UNEXPECTED(code > 0xffffff)) { return _uccase_extra_table[code & 0xffffff]; } return code; } -static inline unsigned php_unicode_tofold_simple(unsigned code, enum mbfl_no_encoding enc) { +static inline unsigned php_unicode_tofold_simple(unsigned code, const mbfl_encoding *enc) { code = php_unicode_tofold_raw(code, enc); if (UNEXPECTED(code > 0xffffff)) { return _uccase_extra_table[code & 0xffffff]; @@ -238,14 +240,55 @@ static uint32_t *emit_special_casing_sequence(uint32_t w, uint32_t *out) return out; } -MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, const char *srcstr, size_t in_len, const mbfl_encoding *src_encoding, int illegal_mode, uint32_t illegal_substchar) +/* Used when determining whether special casing rules should be applied to Greek letter sigma */ +static bool scan_ahead_for_cased_letter(unsigned char *in, size_t in_len, unsigned int state, const mbfl_encoding *encoding) +{ + uint32_t wchar_buf[64]; + + while (in_len) { + size_t out_len = encoding->to_wchar(&in, &in_len, wchar_buf, 64, &state); + ZEND_ASSERT(out_len <= 64); + for (unsigned int i = 0; i < out_len; i++) { + uint32_t w = wchar_buf[i]; + if (php_unicode_is_cased(w)) { + return true; + } + if (!php_unicode_is_case_ignorable(w)) { + return false; + } + } + } + + return false; +} + +/* Used when determining whether special casing rules should be applied to Greek letter sigma */ +static bool scan_back_for_cased_letter(uint32_t *begin, uint32_t *end) +{ + if (end != NULL) { + while (--end >= begin) { + uint32_t w = *end; + if (php_unicode_is_cased(w)) { + return true; + } + if (!php_unicode_is_case_ignorable(w)) { + return false; + } + } + } + return false; +} + +MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, const char *srcstr, size_t in_len, const mbfl_encoding *src_encoding, const mbfl_encoding *dst_encoding, int illegal_mode, uint32_t illegal_substchar) { /* A Unicode codepoint can expand out to up to 3 codepoints when uppercased, lowercased, or title cased * See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt */ uint32_t wchar_buf[64], converted_buf[192]; unsigned int state = 0, title_mode = 0; unsigned char *in = (unsigned char*)srcstr; - enum mbfl_no_encoding enc = src_encoding->no_encoding; + /* In rare cases, we need to scan backwards through the previously converted codepoints to see + * if special conversion rules should be used for the Greek letter sigma */ + uint32_t *converted_end = NULL; mb_convert_buf buf; mb_convert_buf_init(&buf, in_len + 1, illegal_substchar, illegal_mode); @@ -260,21 +303,21 @@ MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, cons case PHP_UNICODE_CASE_UPPER_SIMPLE: for (int i = 0; i < out_len; i++) { uint32_t w = wchar_buf[i]; - *p++ = (UNEXPECTED(w > 0xFFFFFF)) ? w : php_unicode_toupper_simple(w, enc); + *p++ = (UNEXPECTED(w > 0xFFFFFF)) ? w : php_unicode_toupper_simple(w, src_encoding); } break; case PHP_UNICODE_CASE_LOWER_SIMPLE: for (int i = 0; i < out_len; i++) { uint32_t w = wchar_buf[i]; - *p++ = (UNEXPECTED(w > 0xFFFFFF)) ? w : php_unicode_tolower_simple(w, enc); + *p++ = (UNEXPECTED(w > 0xFFFFFF)) ? w : php_unicode_tolower_simple(w, src_encoding); } break; case PHP_UNICODE_CASE_FOLD_SIMPLE: for (int i = 0; i < out_len; i++) { uint32_t w = wchar_buf[i]; - *p++ = (UNEXPECTED(w > 0xFFFFFF)) ? w : php_unicode_tofold_simple(w, enc); + *p++ = (UNEXPECTED(w > 0xFFFFFF)) ? w : php_unicode_tofold_simple(w, src_encoding); } break; @@ -285,7 +328,7 @@ MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, cons *p++ = w; continue; } - *p++ = title_mode ? php_unicode_tolower_simple(w, enc) : php_unicode_totitle_simple(w, enc); + *p++ = title_mode ? php_unicode_tolower_simple(w, src_encoding) : php_unicode_totitle_simple(w, src_encoding); if (!php_unicode_is_case_ignorable(w)) { title_mode = php_unicode_is_cased(w); } @@ -299,7 +342,7 @@ MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, cons *p++ = w; continue; } - w = php_unicode_toupper_raw(w, enc); + w = php_unicode_toupper_raw(w, src_encoding); if (UNEXPECTED(w > 0xFFFFFF)) { p = emit_special_casing_sequence(w, p); } else { @@ -315,7 +358,44 @@ MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, cons *p++ = w; continue; } - w = php_unicode_tolower_raw(w, enc); + if (w == 0x3A3) { + /* For Greek capital letter sigma, there is a special casing rule; + * if it is the last letter in a word, it should be downcased to U+03C2 + * (GREEK SMALL LETTER FINAL SIGMA) + * Specifically, we need to check if this codepoint is preceded by any + * number of case-ignorable codepoints, preceded by a cased letter, AND + * is NOT followed by any number of case-ignorable codepoints followed + * by a cased letter. + * Ref: http://www.unicode.org/reports/tr21/tr21-5.html + * Ref: https://unicode.org/Public/UNIDATA/SpecialCasing.txt + * + * While the special casing rules say we should scan backwards through "any number" + * of case-ignorable codepoints, that is a great implementation burden + * It would basically mean we need to keep all the codepoints in a big buffer + * during this conversion operation, but we don't want to do that (to reduce the + * amount of temporary scratch memory used) + * Hence, we only scan back through the codepoints in wchar_buf, and if we hit the + * beginning of the buffer, whatever codepoints have not yet been overwritten in + * the latter part of converted_buf */ + int j = i - 1; + while (j >= 0 && php_unicode_is_case_ignorable(wchar_buf[j])) { + j--; + } + if (j >= 0 ? php_unicode_is_cased(wchar_buf[j]) : scan_back_for_cased_letter(p, converted_end)) { + /* Now scan ahead to look for a cased letter */ + j = i + 1; + while (j < out_len && php_unicode_is_case_ignorable(wchar_buf[j])) { + j++; + } + /* If we hit the end of wchar_buf, convert more of the input string into + * codepoints and continue scanning */ + if (j >= out_len ? !scan_ahead_for_cased_letter(in, in_len, state, src_encoding) : !php_unicode_is_cased(wchar_buf[j])) { + *p++ = 0x3C2; + continue; + } + } + } + w = php_unicode_tolower_raw(w, src_encoding); if (UNEXPECTED(w > 0xFFFFFF)) { p = emit_special_casing_sequence(w, p); } else { @@ -331,7 +411,7 @@ MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, cons *p++ = w; continue; } - w = php_unicode_tofold_raw(w, enc); + w = php_unicode_tofold_raw(w, src_encoding); if (UNEXPECTED(w > 0xFFFFFF)) { p = emit_special_casing_sequence(w, p); } else { @@ -347,12 +427,34 @@ MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, cons *p++ = w; continue; } - uint32_t w2 = title_mode ? php_unicode_tolower_raw(w, enc) : php_unicode_totitle_raw(w, enc); + uint32_t w2; + if (title_mode) { + if (w == 0x3A3) { + int j = i - 1; + while (j >= 0 && php_unicode_is_case_ignorable(wchar_buf[j])) { + j--; + } + if (j >= 0 ? php_unicode_is_cased(wchar_buf[j]) : scan_back_for_cased_letter(p, converted_end)) { + j = i + 1; + while (j < out_len && php_unicode_is_case_ignorable(wchar_buf[j])) { + j++; + } + if (j >= out_len ? !scan_ahead_for_cased_letter(in, in_len, state, src_encoding) : !php_unicode_is_cased(wchar_buf[j])) { + *p++ = 0x3C2; + goto set_title_mode; + } + } + } + w2 = php_unicode_tolower_raw(w, src_encoding); + } else { + w2 = php_unicode_totitle_raw(w, src_encoding); + } if (UNEXPECTED(w2 > 0xFFFFFF)) { p = emit_special_casing_sequence(w2, p); } else { *p++ = w2; } +set_title_mode: if (!php_unicode_is_case_ignorable(w)) { title_mode = php_unicode_is_cased(w); } @@ -362,9 +464,10 @@ MBSTRING_API zend_string *php_unicode_convert_case(php_case_mode case_mode, cons EMPTY_SWITCH_DEFAULT_CASE() } + converted_end = p; ZEND_ASSERT(p - converted_buf <= 192); - src_encoding->from_wchar(converted_buf, p - converted_buf, &buf, !in_len); + dst_encoding->from_wchar(converted_buf, p - converted_buf, &buf, !in_len); } - return mb_convert_buf_result(&buf); + return mb_convert_buf_result(&buf, dst_encoding); } diff --git a/ext/mbstring/php_unicode.h b/ext/mbstring/php_unicode.h index b65b347df1ba0..1326761943dc5 100644 --- a/ext/mbstring/php_unicode.h +++ b/ext/mbstring/php_unicode.h @@ -91,7 +91,7 @@ typedef enum { MBSTRING_API zend_string *php_unicode_convert_case( php_case_mode case_mode, const char *srcstr, size_t srclen, - const mbfl_encoding *src_encoding, int illegal_mode, uint32_t illegal_substchar); + const mbfl_encoding *src_encoding, const mbfl_encoding *dst_encoding, int illegal_mode, uint32_t illegal_substchar); /* Optimize the common ASCII case for lower/upper */ diff --git a/ext/mbstring/rare_cp_bitvec.h b/ext/mbstring/rare_cp_bitvec.h index 451c588bd64d6..dec97a7d74f50 100644 --- a/ext/mbstring/rare_cp_bitvec.h +++ b/ext/mbstring/rare_cp_bitvec.h @@ -9,9 +9,9 @@ * as less likely to be the correct one. */ -static uint32_t rare_codepoint_bitvec[] = { +static const uint32_t rare_codepoint_bitvec[] = { 0xffffd9ff, 0x00000000, 0x00000000, 0x80000000, 0xffffffff, 0x00002001, 0x00000000, 0x00000000, -0xf0ff0f0f, 0xffffffff, 0xf0fcfe61, 0x81fc3fcc, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, +0x70ff0f0f, 0xfffcffff, 0x70fcfe61, 0x81fc3fcc, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff800, 0xffffffff, 0xffffffff, 0x0300ffff, 0x0000280f, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/ext/mbstring/tests/bug49536.phpt b/ext/mbstring/tests/bug49536.phpt index 1980dc4988b75..a16a0657a5c90 100644 --- a/ext/mbstring/tests/bug49536.phpt +++ b/ext/mbstring/tests/bug49536.phpt @@ -12,9 +12,16 @@ var_dump(mb_detect_encoding("A\x81", "SJIS", true)); var_dump(mb_detect_encoding("\xc0\x00", "UTF-8", false)); // strict mode var_dump(mb_detect_encoding("\xc0\x00", "UTF-8", true)); + +// Strict mode with multiple candidate encodings +// This input string is invalid in ALL the candidate encodings: +echo "== INVALID STRING - UTF-8 and SJIS ==\n"; +var_dump(mb_detect_encoding("\xFF\xFF", ['SJIS', 'UTF-8'], true)); ?> --EXPECT-- string(4) "SJIS" bool(false) +string(5) "UTF-8" bool(false) +== INVALID STRING - UTF-8 and SJIS == bool(false) diff --git a/ext/mbstring/tests/casemapping.phpt b/ext/mbstring/tests/casemapping.phpt index 85f5140e2bfef..050ebc94e25d1 100644 --- a/ext/mbstring/tests/casemapping.phpt +++ b/ext/mbstring/tests/casemapping.phpt @@ -58,6 +58,12 @@ echo bin2hex(mb_convert_case($str, MB_CASE_UPPER_SIMPLE)), "\n"; echo bin2hex(mb_convert_case($str, MB_CASE_FOLD)), "\n"; echo bin2hex(mb_convert_case($str, MB_CASE_FOLD_SIMPLE)), "\n"; +// Check handling of Greek letter capital sigma +echo mb_convert_case("ΚΑΛΗΣΠΕΡΑ ΣΑΣ", MB_CASE_TITLE, "UTF-8"), "\n"; +echo mb_convert_case("ΚΑΛΗΣΠΕΡΑ ΣΑΣ", MB_CASE_TITLE_SIMPLE, "UTF-8"), "\n"; +echo mb_convert_case("ΚΑΛΗΣΠΕΡΑ ΣΑΣ", MB_CASE_LOWER, "UTF-8"), "\n"; +echo mb_convert_case("ΚΑΛΗΣΠΕΡΑ ΣΑΣ", MB_CASE_LOWER_SIMPLE, "UTF-8"), "\n"; + ?> --EXPECT-- String: ß @@ -109,3 +115,7 @@ dd dd 69 69 +Καλησπερα Σας +Καλησπερα Σασ +καλησπερα σας +καλησπερα σασ diff --git a/ext/mbstring/tests/encoding_tests.inc b/ext/mbstring/tests/encoding_tests.inc index cbf5071456df2..978cb8db399c0 100644 --- a/ext/mbstring/tests/encoding_tests.inc +++ b/ext/mbstring/tests/encoding_tests.inc @@ -3,6 +3,26 @@ // Common code for tests which focus on conversion and verification of text // in some specific encoding +// Test failed limit. If you want to execute all tests, set to -1. +$testFailedLimit = 1000; +// Test failed counter +$testFailedCounter = 0; + +// Count tests failed. If tests failed are more than $testFailedLimit, stop testing. +function testFailedIncrement() { + global $testFailedCounter, $testFailedLimit; + + // $testFailedLimit is -1, no limit. + if ($testFailedLimit === -1) + return; + + $testFailedCounter++; + if ($testFailedCounter < $testFailedLimit) + return; + + die("=== Failed test " . $testFailedLimit . " times exceeded, stop testing ==="); +} + // Read a file with one character and its equivalent Unicode codepoint on each // line, delimited by tabs function readConversionTable($path, &$from, &$to, $utf32 = false) { @@ -51,27 +71,33 @@ function dbgPrint($str) { function identifyValidString($goodString, $encoding) { $result = mb_check_encoding($goodString, $encoding); - if (!$result) - die("mb_check_encoding failed on good $encoding string: " . dbgPrint($goodString)); + if (!$result) { + echo "mb_check_encoding failed on good $encoding string: " . dbgPrint($goodString) . PHP_EOL; + testFailedIncrement(); + } } function identifyInvalidString($badString, $encoding) { $result = mb_check_encoding($badString, $encoding); if ($result) - die("mb_check_encoding passed on bad $encoding string: " . dbgPrint($badString)); + echo "mb_check_encoding passed on bad $encoding string: " . dbgPrint($badString) . PHP_EOL; } function testConversion($fromString, $toString, $fromEncoding, $toEncoding) { $result = mb_convert_encoding($fromString, $toEncoding, $fromEncoding); - if ($result !== $toString) - die("mb_convert_encoding not working on $fromEncoding input: " . dbgPrint($fromString) . "\nExpected $toEncoding: " . dbgPrint($toString) . "\nActually got: " . dbgPrint($result)); + if ($result !== $toString) { + echo "mb_convert_encoding not working on $fromEncoding input: " . dbgPrint($fromString) . "\nExpected $toEncoding: " . dbgPrint($toString) . "\nActually got: " . dbgPrint($result) . PHP_EOL; + testFailedIncrement(); + } } function testValidConversion($fromString, $toString, $fromEncoding, $toEncoding) { $illegalChars = mb_get_info('illegal_chars'); testConversion($fromString, $toString, $fromEncoding, $toEncoding); - if (mb_get_info('illegal_chars') !== $illegalChars) - die("mb_convert_encoding incremented illegal_chars on valid $fromEncoding string: " . dbgPrint($fromString) . " when converting to $toEncoding"); + if (mb_get_info('illegal_chars') !== $illegalChars) { + echo "mb_convert_encoding incremented illegal_chars on valid $fromEncoding string: " . dbgPrint($fromString) . " when converting to $toEncoding" . PHP_EOL; + testFailedIncrement(); + } } function convertValidString($fromString, $toString, $fromEncoding, $toEncoding, $bothWays = true) { @@ -83,8 +109,10 @@ function convertValidString($fromString, $toString, $fromEncoding, $toEncoding, function convertInvalidString($fromString, $toString, $fromEncoding, $toEncoding) { $illegalChars = mb_get_info('illegal_chars'); testConversion($fromString, $toString, $fromEncoding, $toEncoding); - if (mb_get_info('illegal_chars') <= $illegalChars) - die("mb_convert_encoding did not increment illegal_chars on invalid $fromEncoding string: " . dbgPrint($fromString) . " when converting to $toEncoding"); + if (mb_get_info('illegal_chars') <= $illegalChars) { + echo "mb_convert_encoding did not increment illegal_chars on invalid $fromEncoding string: " . dbgPrint($fromString) . " when converting to $toEncoding" . PHP_EOL; + testFailedIncrement(); + } } function testValidString($fromString, $toString, $fromEncoding, $toEncoding, $bothWays = true) { diff --git a/ext/mbstring/tests/gh10192_utf7.phpt b/ext/mbstring/tests/gh10192_utf7.phpt new file mode 100644 index 0000000000000..2930942c12c5a --- /dev/null +++ b/ext/mbstring/tests/gh10192_utf7.phpt @@ -0,0 +1,542 @@ +--TEST-- +GH-10192 (mb_detect_encoding() results for UTF-7 differ between PHP 8.0 and 8.1) +--EXTENSIONS-- +mbstring +--FILE-- + 'A + B', + 'non-base64 character after -' => 'A - B', + 'base64 character before +' => 'A 1+ B', + 'base64 character before -' => 'A 1- B', + 'base64 character after +' => 'A +1 B', + 'base64 character after -' => 'A -1 B', + 'base64 character before and after +' => 'A 1+1 B', + 'base64 character before and after -' => 'A 1-1 B', + 'string ends with +' => 'A +', + 'string ends with -' => 'A -', + '+ and -' => 'A +- B', + '- and +' => 'A -+ B', + 'valid direct encoding character =' => 'A = B', + 'invalid direct encoding character ~' => 'A ~ B', + 'invalid direct encoding character \\' => 'A \\ B', + 'invalid direct encoding character ESC' => "A \x1b B", + 'valid direct encoding character = after +' => 'A += B', + 'invalid direct encoding character ~ after +' => 'A +~ B', + 'invalid direct encoding character \\ after +' => 'A +\\ B', + 'invalid direct encoding character ESC after +' => "A +\x1b B", + 'valid base64 character between + and -' => 'A +ZeVnLIqe- B', // 日本語 in UTF-16BE + 'invalid base64 character between + and -' => 'A +ZeVnLIq- B', // 日本語 in UTF-16BE without the last character + 'valid base64 character between + and non-base64 character' => 'A +ZeVnLIqe B', + 'invalid base64 character between + and non-base64 character' => 'A +ZeVnLIq B', + 'valid base64 character between + and base64 character' => 'A +ZeVnLIqe1 B', + 'invalid base64 character between + and base64 character' => 'A +ZeVnLIq1 B', + 'valid base64 character between + and end of string' => 'A +ZeVnLIqe', + 'invalid base64 character between + and end of string' => 'A +ZeVnLIq', + 'valid base64 character consisting only of + between + and -' => 'A +++++++++- B', + 'invalid base64 character consisting only of + between + and -' => 'A +++++++++- B', + 'valid base64 character consisting only of + between + and non-base64 character' => 'A +++++++++ B', + 'invalid base64 character consisting only of + between + and non-base64 character' => 'A +++++++++ B', + 'valid base64 character consisting only of + between + and base64 character' => 'A +++++++++1 B', + 'invalid base64 character consisting only of + between + and base64 character' => 'A +++++++++1 B', + 'valid base64 character consisting only of + between + and end of string' => 'A +++++++++', + 'invalid base64 character consisting only of + between + and end of string' => 'A +++++++++', + 'valid base64 character using surrogate pair between + and -' => 'A +2GfePQ- B', // 𩸽 in UTF-16BE + 'first 16 bits of base64 character using surrogate pair between + and -' => 'A +2Gc- B', // first 16 bits of 𩸽 in UTF-16BE + 'valid base64 character using surrogate pair between + and non-base64 character' => 'A +2GfePQ B', + 'first 16 bits of base64 character using surrogate pair between + and non-base64 character' => 'A +2Gc B', + 'valid base64 character using surrogate pair between + and base64 character' => 'A +2GfePQ1 B', + 'first 16 bits of base64 character using surrogate pair between + and base64 character' => 'A +2Gc1 B', + 'valid base64 character using surrogate pair between + and end of string' => 'A +2GfePQ', + 'first 16 bits of base64 character using surrogate pair between + and end of string' => 'A +2Gc', + 'invalid base64 character using surrogate pair in reverse order between + and -' => 'A +3j3YZw- B', // 𩸽 in reverse order in UTF-16BE + 'last 16 bits of base64 character using surrogate pair in reverse order between + and -' => 'A +3j0- B', // last 16 bits of 𩸽 in UTF-16BE + 'invalid base64 character using surrogate pair in reverse order between + and non-base64 character' => 'A +3j3YZw B', + 'last 16 bits of base64 character using surrogate pair in reverse order between + and non-base64 character' => 'A +3j0 B', + 'invalid base64 character using surrogate pair in reverse order between + and base64 character' => 'A +3j3YZw1 B', + 'last 16 bits of base64 character using surrogate pair in reverse order between + and base64 character' => 'A +3j01 B', + 'invalid base64 character using surrogate pair in reverse order between + and end of string' => 'A +3j3YZw', + 'last 16 bits of base64 character using surrogate pair in reverse order between + and end of string' => 'A +3j0' +]; + +foreach ($testcases as $title => $case) { + echo $title . PHP_EOL; + var_dump(mb_detect_encoding($case, 'UTF-8, UTF-7', true)); + var_dump(mb_detect_encoding($case, 'UTF-8, UTF-7', false)); + var_dump(mb_detect_encoding($case, 'UTF-7', true)); + var_dump(mb_detect_encoding($case, 'UTF-7', false)); + var_dump(mb_check_encoding($case, 'UTF-7')); + var_dump(addcslashes(mb_convert_encoding($case, 'UTF-8', 'UTF-7'), "\0..\37\177")); + var_dump(mb_get_info('illegal_chars')); + echo PHP_EOL; +} +?> +--EXPECT-- +non-base64 character after + +string(5) "UTF-8" +string(5) "UTF-7" +bool(false) +string(5) "UTF-7" +bool(false) +string(4) "A B" +int(0) + +non-base64 character after - +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(5) "A - B" +int(0) + +base64 character before + +string(5) "UTF-8" +string(5) "UTF-7" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A 1 B" +int(0) + +base64 character before - +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(6) "A 1- B" +int(0) + +base64 character after + +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A ? B" +int(1) + +base64 character after - +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(6) "A -1 B" +int(1) + +base64 character before and after + +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(6) "A 1? B" +int(2) + +base64 character before and after - +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(7) "A 1-1 B" +int(2) + +string ends with + +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(2) "A " +int(2) + +string ends with - +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(3) "A -" +int(2) + ++ and - +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(5) "A + B" +int(2) + +- and + +string(5) "UTF-8" +string(5) "UTF-7" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A - B" +int(2) + +valid direct encoding character = +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(5) "A = B" +int(2) + +invalid direct encoding character ~ +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A ~ B" +int(2) + +invalid direct encoding character \ +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A \ B" +int(2) + +invalid direct encoding character ESC +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(8) "A \033 B" +int(2) + +valid direct encoding character = after + +string(5) "UTF-8" +string(5) "UTF-7" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A = B" +int(2) + +invalid direct encoding character ~ after + +string(5) "UTF-8" +string(5) "UTF-7" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A ~ B" +int(2) + +invalid direct encoding character \ after + +string(5) "UTF-8" +string(5) "UTF-7" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A \ B" +int(2) + +invalid direct encoding character ESC after + +string(5) "UTF-8" +string(5) "UTF-7" +bool(false) +string(5) "UTF-7" +bool(false) +string(8) "A \033 B" +int(2) + +valid base64 character between + and - +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(13) "A 日本語 B" +int(2) + +invalid base64 character between + and - +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(11) "A 日本? B" +int(3) + +valid base64 character between + and non-base64 character +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(13) "A 日本語 B" +int(3) + +invalid base64 character between + and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(11) "A 日本? B" +int(4) + +valid base64 character between + and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(14) "A 日本語? B" +int(5) + +invalid base64 character between + and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(13) "A 日本誵 B" +int(5) + +valid base64 character between + and end of string +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(11) "A 日本語" +int(5) + +invalid base64 character between + and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(9) "A 日本?" +int(6) + +valid base64 character consisting only of + between + and - +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(13) "A ﯯ뻻 B" +int(6) + +invalid base64 character consisting only of + between + and - +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(13) "A ﯯ뻻 B" +int(6) + +valid base64 character consisting only of + between + and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(13) "A ﯯ뻻 B" +int(6) + +invalid base64 character consisting only of + between + and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(13) "A ﯯ뻻 B" +int(6) + +valid base64 character consisting only of + between + and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(14) "A ﯯ뻻? B" +int(7) + +invalid base64 character consisting only of + between + and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(14) "A ﯯ뻻? B" +int(8) + +valid base64 character consisting only of + between + and end of string +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(11) "A ﯯ뻻" +int(8) + +invalid base64 character consisting only of + between + and end of string +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(11) "A ﯯ뻻" +int(8) + +valid base64 character using surrogate pair between + and - +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(8) "A 𩸽 B" +int(8) + +first 16 bits of base64 character using surrogate pair between + and - +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A ? B" +int(9) + +valid base64 character using surrogate pair between + and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(8) "A 𩸽 B" +int(9) + +first 16 bits of base64 character using surrogate pair between + and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A ? B" +int(10) + +valid base64 character using surrogate pair between + and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(9) "A 𩸽? B" +int(11) + +first 16 bits of base64 character using surrogate pair between + and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A ? B" +int(12) + +valid base64 character using surrogate pair between + and end of string +string(5) "UTF-8" +string(5) "UTF-8" +string(5) "UTF-7" +string(5) "UTF-7" +bool(true) +string(6) "A 𩸽" +int(12) + +first 16 bits of base64 character using surrogate pair between + and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(3) "A ?" +int(13) + +invalid base64 character using surrogate pair in reverse order between + and - +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(6) "A ?? B" +int(15) + +last 16 bits of base64 character using surrogate pair in reverse order between + and - +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A ? B" +int(16) + +invalid base64 character using surrogate pair in reverse order between + and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(6) "A ?? B" +int(18) + +last 16 bits of base64 character using surrogate pair in reverse order between + and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(5) "A ? B" +int(19) + +invalid base64 character using surrogate pair in reverse order between + and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(6) "A ?? B" +int(21) + +last 16 bits of base64 character using surrogate pair in reverse order between + and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(6) "A ?? B" +int(23) + +invalid base64 character using surrogate pair in reverse order between + and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(4) "A ??" +int(25) + +last 16 bits of base64 character using surrogate pair in reverse order between + and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(5) "UTF-7" +bool(false) +string(3) "A ?" +int(26) diff --git a/ext/mbstring/tests/gh10192_utf7imap.phpt b/ext/mbstring/tests/gh10192_utf7imap.phpt new file mode 100644 index 0000000000000..c4f50884f6daf --- /dev/null +++ b/ext/mbstring/tests/gh10192_utf7imap.phpt @@ -0,0 +1,423 @@ +--TEST-- +GH-10192 (mb_detect_encoding() results for UTF-7 differ between PHP 8.0 and 8.1) +--EXTENSIONS-- +mbstring +--FILE-- + 'A & B', + 'non-base64 character after -' => 'A - B', + 'base64 character before &' => 'A 1& B', + 'base64 character before -' => 'A 1- B', + 'base64 character after &' => 'A &1 B', + 'base64 character after -' => 'A -1 B', + 'base64 character before and after &' => 'A 1&1 B', + 'base64 character before and after -' => 'A 1-1 B', + 'string ends with &' => 'A &', + 'string ends with -' => 'A -', + '& and -' => 'A &- B', + '- and &' => 'A -& B', + 'valid direct encoding character ~' => 'A ~ B', + 'invalid direct encoding character ESC' => "A \x1b B", + 'valid direct encoding character ~ after &' => 'A &~ B', + 'invalid direct encoding character ESC after &' => "A &\x1b B", + 'valid base64 character between & and -' => 'A &ZeVnLIqe- B', // 日本語 in UTF-16BE + 'invalid base64 character between & and -' => 'A &ZeVnLIq- B', // 日本語 in UTF-16BE without the last character + 'valid base64 character between & and non-base64 character' => 'A &ZeVnLIqe B', + 'invalid base64 character between & and non-base64 character' => 'A &ZeVnLIq B', + 'valid base64 character between & and base64 character' => 'A &ZeVnLIqe1 B', + 'invalid base64 character between & and base64 character' => 'A &ZeVnLIq1 B', + 'valid base64 character between & and end of string' => 'A &ZeVnLIqe', + 'invalid base64 character between & and end of string' => 'A &ZeVnLIq', + 'valid base64 character using surrogate pair between & and -' => 'A &2GfePQ- B', // 𩸽 in UTF-16BE + 'first 16 bits of base64 character using surrogate pair between & and -' => 'A &2Gc- B', // first 16 bits of 𩸽 in UTF-16BE + 'valid base64 character using surrogate pair between & and non-base64 character' => 'A &2GfePQ B', + 'first 16 bits of base64 character using surrogate pair between & and non-base64 character' => 'A &2Gc B', + 'valid base64 character using surrogate pair between & and base64 character' => 'A &2GfePQ1 B', + 'first 16 bits of base64 character using surrogate pair between & and base64 character' => 'A &2Gc1 B', + 'valid base64 character using surrogate pair between & and end of string' => 'A &2GfePQ', + 'first 16 bits of base64 character using surrogate pair between & and end of string' => 'A &2Gc', + 'invalid base64 character using surrogate pair in reverse order between & and -' => 'A &3j3YZw- B', // 𩸽 in reverse order in UTF-16BE + 'last 16 bits of base64 character using surrogate pair in reverse order between & and -' => 'A &3j0- B', // last 16 bits of 𩸽 in UTF-16BE + 'invalid base64 character using surrogate pair in reverse order between & and non-base64 character' => 'A &3j3YZw B', + 'last 16 bits of base64 character using surrogate pair in reverse order between & and non-base64 character' => 'A &3j0 B', + 'invalid base64 character using surrogate pair in reverse order between & and base64 character' => 'A &3j3YZw1 B', + 'last 16 bits of base64 character using surrogate pair in reverse order between & and base64 character' => 'A &3j01 B', + 'invalid base64 character using surrogate pair in reverse order between & and end of string' => 'A &3j3YZw', + 'last 16 bits of base64 character using surrogate pair in reverse order between & and end of string' => 'A &3j0' +]; + +foreach ($testcases as $title => $case) { + echo $title . PHP_EOL; + var_dump(mb_detect_encoding($case, 'UTF-8, UTF7-IMAP', true)); + var_dump(mb_detect_encoding($case, 'UTF-8, UTF7-IMAP', false)); + var_dump(mb_detect_encoding($case, 'UTF7-IMAP', true)); + var_dump(mb_detect_encoding($case, 'UTF7-IMAP', false)); + var_dump(mb_check_encoding($case, 'UTF7-IMAP')); + var_dump(addcslashes(mb_convert_encoding($case, 'UTF-8', 'UTF7-IMAP'), "\0..\37\177")); + var_dump(mb_get_info('illegal_chars')); + echo PHP_EOL; +} + +?> +--EXPECT-- +non-base64 character after & +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(4) "A ?B" +int(1) + +non-base64 character after - +string(5) "UTF-8" +string(5) "UTF-8" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(5) "A - B" +int(1) + +base64 character before & +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A 1?B" +int(2) + +base64 character before - +string(5) "UTF-8" +string(5) "UTF-8" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(6) "A 1- B" +int(2) + +base64 character after & +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(4) "A ?B" +int(3) + +base64 character after - +string(5) "UTF-8" +string(5) "UTF-8" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(6) "A -1 B" +int(3) + +base64 character before and after & +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A 1?B" +int(4) + +base64 character before and after - +string(5) "UTF-8" +string(5) "UTF-8" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(7) "A 1-1 B" +int(4) + +string ends with & +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(3) "A ?" +int(5) + +string ends with - +string(5) "UTF-8" +string(5) "UTF-8" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(3) "A -" +int(5) + +& and - +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(5) "A & B" +int(5) + +- and & +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A -?B" +int(6) + +valid direct encoding character ~ +string(5) "UTF-8" +string(5) "UTF-8" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(5) "A ~ B" +int(6) + +invalid direct encoding character ESC +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ? B" +int(7) + +valid direct encoding character ~ after & +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ? B" +int(8) + +invalid direct encoding character ESC after & +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ? B" +int(9) + +valid base64 character between & and - +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(13) "A 日本語 B" +int(9) + +invalid base64 character between & and - +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(11) "A 日本? B" +int(10) + +valid base64 character between & and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(13) "A 日本語?B" +int(11) + +invalid base64 character between & and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(10) "A 日本?B" +int(12) + +valid base64 character between & and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(13) "A 日本語?B" +int(13) + +invalid base64 character between & and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(13) "A 日本誵?B" +int(14) + +valid base64 character between & and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(12) "A 日本語?" +int(15) + +invalid base64 character between & and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(9) "A 日本?" +int(16) + +valid base64 character using surrogate pair between & and - +string(5) "UTF-8" +string(5) "UTF-8" +string(9) "UTF7-IMAP" +string(9) "UTF7-IMAP" +bool(true) +string(8) "A 𩸽 B" +int(16) + +first 16 bits of base64 character using surrogate pair between & and - +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ? B" +int(17) + +valid base64 character using surrogate pair between & and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(8) "A 𩸽?B" +int(18) + +first 16 bits of base64 character using surrogate pair between & and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(4) "A ?B" +int(19) + +valid base64 character using surrogate pair between & and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(8) "A 𩸽?B" +int(20) + +first 16 bits of base64 character using surrogate pair between & and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(4) "A ?B" +int(21) + +valid base64 character using surrogate pair between & and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(7) "A 𩸽?" +int(22) + +first 16 bits of base64 character using surrogate pair between & and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(4) "A ??" +int(24) + +invalid base64 character using surrogate pair in reverse order between & and - +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(6) "A ?? B" +int(26) + +last 16 bits of base64 character using surrogate pair in reverse order between & and - +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ? B" +int(27) + +invalid base64 character using surrogate pair in reverse order between & and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ??B" +int(29) + +last 16 bits of base64 character using surrogate pair in reverse order between & and non-base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ??B" +int(31) + +invalid base64 character using surrogate pair in reverse order between & and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ??B" +int(33) + +last 16 bits of base64 character using surrogate pair in reverse order between & and base64 character +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ??B" +int(35) + +invalid base64 character using surrogate pair in reverse order between & and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(5) "A ???" +int(38) + +last 16 bits of base64 character using surrogate pair in reverse order between & and end of string +string(5) "UTF-8" +string(5) "UTF-8" +bool(false) +string(9) "UTF7-IMAP" +bool(false) +string(4) "A ??" +int(40) diff --git a/ext/mbstring/tests/gh10627.phpt b/ext/mbstring/tests/gh10627.phpt new file mode 100644 index 0000000000000..2f4af8c559e10 --- /dev/null +++ b/ext/mbstring/tests/gh10627.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-10627 (mb_convert_encoding crashes PHP on Windows) +--EXTENSIONS-- +mbstring +--INI-- +mbstring.strict_detection=1 +--FILE-- + 'abc', 'abc' => 'def']; +var_dump(mb_convert_encoding($data, 'UTF-8', 'auto')); +$data = ['abc' => $str, 'def' => 'abc']; +var_dump(mb_convert_encoding($data, 'UTF-8', 'auto')); + +?> +--EXPECTF-- +Warning: mb_convert_encoding(): Unable to detect character encoding in %s on line %d +array(1) { + [1]=> + string(3) "abc" +} + +Warning: mb_convert_encoding(): Unable to detect character encoding in %s on line %d +array(1) { + ["abc"]=> + string(3) "def" +} + +Warning: mb_convert_encoding(): Unable to detect character encoding in %s on line %d +array(1) { + ["def"]=> + string(3) "abc" +} diff --git a/ext/mbstring/tests/gh10648.phpt b/ext/mbstring/tests/gh10648.phpt new file mode 100644 index 0000000000000..9f0b4b4db153a --- /dev/null +++ b/ext/mbstring/tests/gh10648.phpt @@ -0,0 +1,155 @@ +--TEST-- +GH-10648 (mb_check_encoding() returns true for incorrect but interpretable ISO-2022-JP byte sequences) +--EXTENSIONS-- +mbstring +--FILE-- + '1b244224221b2842', // 'あ' in ISO-2022-JP + 'ISO-2022-JP bytes without escape sequence' => '1b24422422', // 'ア' in JIS + 'JIS X 0201 7bit kana with escape sequence' => '1b2849311b2842', // 'ア' in JIS + 'JIS X 0201 7bit kana with SO/SI' => '0e310f', // 'ア' in JIS + 'JIS X 0201 8bit kana' => 'b1', // 'ア' in JIS + 'JIS X 0201 7bit kana with SO and ESC' => '0e311b2842', // 'ア' in JIS + 'JIS X 0201 7bit kana with ESC and SI' => '1b2849310f', // 'ア' in JIS + 'JIS X 0208 character' => '1b244242641b2842', // '鯛' in JIS and ISO-2022-JP, included in JIS X 0208 + 'JIS X 0212 character' => '1b2428446a591b2842', // '鮋' in JIS, included in JIS X 0212 + 'JIS X 0213 character' => '1b2428507d4c1b2842', // '𩸽' in ISO-2022-JP-2004, included in JIS X 0213 + 'JIS C 6220-1969 ESC ( H' => '1b284a1b2848', // an escape sequence transitioning to ASCII + 'SO/SI when not in ASCII mode' => '1b284a0e0f1b2842', // an escape sequence transitioning to ASCII +]; + +foreach ($testcases as $title => $case) { + echo $title . PHP_EOL; + echo 'JIS:' . PHP_EOL; + var_dump(mb_check_encoding(hex2bin($case), 'JIS')); + echo mb_convert_encoding(hex2bin($case), 'UTF-8', 'JIS'). PHP_EOL; + var_dump(mb_get_info('illegal_chars')); + echo 'ISO-2022-JP:' . PHP_EOL; + var_dump(mb_check_encoding(hex2bin($case), 'ISO-2022-JP')); + echo mb_convert_encoding(hex2bin($case), 'UTF-8', 'ISO-2022-JP'). PHP_EOL; + var_dump(mb_get_info('illegal_chars')); + echo PHP_EOL; +} +?> +--EXPECT-- +ISO-2022-JP bytes +JIS: +bool(true) +あ +int(0) +ISO-2022-JP: +bool(true) +あ +int(0) + +ISO-2022-JP bytes without escape sequence +JIS: +bool(false) +あ +int(0) +ISO-2022-JP: +bool(false) +あ +int(0) + +JIS X 0201 7bit kana with escape sequence +JIS: +bool(true) +ア +int(0) +ISO-2022-JP: +bool(false) +ア +int(0) + +JIS X 0201 7bit kana with SO/SI +JIS: +bool(true) +ア +int(0) +ISO-2022-JP: +bool(false) +ア +int(0) + +JIS X 0201 8bit kana +JIS: +bool(true) +ア +int(0) +ISO-2022-JP: +bool(false) +ア +int(0) + +JIS X 0201 7bit kana with SO and ESC +JIS: +bool(false) +ア +int(0) +ISO-2022-JP: +bool(false) +ア +int(0) + +JIS X 0201 7bit kana with ESC and SI +JIS: +bool(false) +ア +int(0) +ISO-2022-JP: +bool(false) +ア +int(0) + +JIS X 0208 character +JIS: +bool(true) +鯛 +int(0) +ISO-2022-JP: +bool(true) +鯛 +int(0) + +JIS X 0212 character +JIS: +bool(true) +鮋 +int(0) +ISO-2022-JP: +bool(false) +鮋 +int(0) + +JIS X 0213 character +JIS: +bool(false) +?$(P}L +int(1) +ISO-2022-JP: +bool(false) +?$(P}L +int(2) + +JIS C 6220-1969 ESC ( H +JIS: +bool(true) + +int(2) +ISO-2022-JP: +bool(false) + +int(2) + +SO/SI when not in ASCII mode +JIS: +bool(false) + +int(2) +ISO-2022-JP: +bool(false) + +int(2) diff --git a/ext/mbstring/tests/gh7902.phpt b/ext/mbstring/tests/gh7902.phpt index d9a0fced7913d..7182731005ff6 100644 --- a/ext/mbstring/tests/gh7902.phpt +++ b/ext/mbstring/tests/gh7902.phpt @@ -1,8 +1,10 @@ --TEST-- GH-7902 (mb_send_mail may delimit headers with LF only) +--EXTENSIONS-- +mbstring --SKIPIF-- --INI-- sendmail_path={MAIL:{PWD}/gh7902.eml} diff --git a/ext/mbstring/tests/gh8086.phpt b/ext/mbstring/tests/gh8086.phpt new file mode 100644 index 0000000000000..2eeed67e5b483 --- /dev/null +++ b/ext/mbstring/tests/gh8086.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-8086 (mb_send_mail() function not working correctly in PHP 8.x) +--SKIPIF-- + +--INI-- +sendmail_path={MAIL:{PWD}/gh8086.eml} +mail.mixed_lf_and_crlf=on +--FILE-- + +--CLEAN-- + +--EXPECT-- +int(6) diff --git a/ext/mbstring/tests/gh9535b.phpt b/ext/mbstring/tests/gh9535b.phpt index 8e68e6becdbc1..7562c3a45ff4d 100644 --- a/ext/mbstring/tests/gh9535b.phpt +++ b/ext/mbstring/tests/gh9535b.phpt @@ -1,16 +1,9 @@ --TEST-- -Output of mb_strcut covers requested range of bytes even when output contains ending escape sequences +Test output of mb_strcut for text encodings which use escape sequences --EXTENSIONS-- mbstring --FILE-- ---XFAIL-- -Discussion: https://github.com/php/php-src/pull/9562 --EXPECTF-- -JIS: 宛如繁星般 -ISO-2022-JP: 宛如繁星般 +JIS: 宛如繁星 +ISO-2022-JP: 宛如繁星 ISO-2022-JP-2004: 宛如繁星 JIS: 星のように月の ISO-2022-JP: 星のように月の -ISO-2022-JP-2004: 星のように月の +ISO-2022-JP-2004: 星のように月 JIS: あa ISO-2022-JP: あa diff --git a/ext/mbstring/tests/iso2022jp_encoding.phpt b/ext/mbstring/tests/iso2022jp_encoding.phpt index 634f0976994c3..5da1899c855b1 100644 --- a/ext/mbstring/tests/iso2022jp_encoding.phpt +++ b/ext/mbstring/tests/iso2022jp_encoding.phpt @@ -50,11 +50,6 @@ function testValid($from, $to, $encoding, $bothWays = true) { /* ESC ( B at the beginning is redundant, since ASCII mode is the default */ if (substr($from, 0, 3) == "\x1B(B") $from = substr($from, 3, strlen($from) - 3); - /* If the string switches to a different charset, it should switch back to - * ASCII at the end */ - if (strpos($from, "\x1B\$B") !== false || strpos($from, "\x1B(J") !== false) - $from .= "\x1B(B"; - convertValidString($to, $from, 'UTF-16BE', $encoding, false); } } @@ -66,11 +61,11 @@ function testInvalid($from, $to, $encoding) { for ($i = 0; $i < 0x80; $i++) { if ($i == 0xE || $i == 0xF || $i == 0x1B) continue; - testValid(chr($i), "\x00" . chr($i), 'JIS'); - testValid("\x0F" . chr($i), "\x00" . chr($i), 'JIS'); /* 0xF is 'Shift Out' code */ - testValid("\x1B(B" . chr($i), "\x00" . chr($i), 'JIS'); - testValid(chr($i), "\x00" . chr($i), 'ISO-2022-JP'); - testValid("\x1B(B" . chr($i), "\x00" . chr($i), 'ISO-2022-JP'); + testValid(chr($i), "\x00" . chr($i), 'JIS'); + convertValidString("\x0F" . chr($i), "\x00" . chr($i), 'JIS', 'UTF-16BE', false); /* 0xF is 'Shift In' code */ + testValid("\x1B(B" . chr($i), "\x00" . chr($i), 'JIS'); + testValid(chr($i), "\x00" . chr($i), 'ISO-2022-JP'); + testValid("\x1B(B" . chr($i), "\x00" . chr($i), 'ISO-2022-JP'); } for ($i = 0x80; $i < 256; $i++) { @@ -92,27 +87,27 @@ echo "ASCII support OK\n"; foreach ($jisx0201Chars as $jisx0201 => $utf16BE) { if (ord($jisx0201) >= 128) { $kana = chr(ord($jisx0201) - 128); - testValid("\x1B(I" . $kana, $utf16BE, 'JIS', false); - testValid("\x0E" . $kana, $utf16BE, 'JIS', false); /* 0xE is 'Shift In' code */ + testValid("\x1B(I" . $kana . "\x1B(B", $utf16BE, 'JIS', false); + testValid("\x0E" . $kana . "\x0F", $utf16BE, 'JIS', false); /* 0xE is 'Shift Out' code */ testValid($jisx0201, $utf16BE, 'JIS', false); } else { - testValid("\x1B(J" . $jisx0201, $utf16BE, 'JIS', $utf16BE > "\x00\x80"); + testValid("\x1B(J" . $jisx0201 . "\x1B(B", $utf16BE, 'JIS', $utf16BE > "\x00\x80"); } } for ($i = 0x80; $i < 256; $i++) { if ($i >= 0xA1 && $i <= 0xDF) continue; - testInvalid("\x1B(I" . chr($i), "\x00%", 'JIS'); - testInvalid("\x1B(J" . chr($i), "\x00%", 'JIS'); + testInvalid("\x1B(I" . chr($i) . "\x1B(B", "\x00%", 'JIS'); + testInvalid("\x1B(J" . chr($i) . "\x1B(B", "\x00%", 'JIS'); } echo "JIS X 0201 support OK\n"; /* All valid JISX0208 characters */ foreach ($jisx0208Chars as $jisx0208 => $utf16BE) { - testValid("\x1B\$B" . $jisx0208, $utf16BE, 'JIS'); - testValid("\x1B\$B" . $jisx0208, $utf16BE, 'ISO-2022-JP'); + testValid("\x1B\$B" . $jisx0208 . "\x1B(B", $utf16BE, 'JIS'); + testValid("\x1B\$B" . $jisx0208 . "\x1B(B", $utf16BE, 'ISO-2022-JP'); } /* All invalid 2-byte JISX0208 characters */ @@ -120,8 +115,8 @@ for ($i = 0x21; $i <= 0x7E; $i++) { for ($j = 0; $j < 256; $j++) { $testString = chr($i) . chr($j); if (!isset($jisx0208Chars[$testString])) { - testInvalid("\x1B\$B" . $testString, "\x00%", 'JIS'); - testInvalid("\x1B\$B" . $testString, "\x00%", 'ISO-2022-JP'); + testInvalid("\x1B\$B" . $testString . "\x1B(B", "\x00%", 'JIS'); + testInvalid("\x1B\$B" . $testString . "\x1B(B", "\x00%", 'ISO-2022-JP'); } } } @@ -142,7 +137,7 @@ echo "JIS X 0208 support OK\n"; /* All valid JISX0212 characters */ foreach ($jisx0212Chars as $jisx0212 => $utf16BE) { - testValid("\x1B\$(D" . $jisx0212, $utf16BE, 'JIS', false); + testValid("\x1B\$(D" . $jisx0212 . "\x1B(B", $utf16BE, 'JIS', false); } /* All invalid 2-byte JISX0212 characters */ @@ -150,14 +145,14 @@ for ($i = 0x21; $i <= 0x7E; $i++) { for ($j = 0; $j < 256; $j++) { $testString = chr($i) . chr($j); if (!isset($jisx0212Chars[$testString])) { - testInvalid("\x1B\$(D" . $testString, "\x00%", 'JIS'); + testInvalid("\x1B\$(D" . $testString . "\x1B(B", "\x00%", 'JIS'); } } } /* Try truncated JISX0212 characters */ for ($i = 0x21; $i <= 0x7E; $i++) { - testInvalid("\x1B\$(D" . chr($i), "\x00%", 'JIS'); + testInvalid("\x1B\$(D" . chr($i) . "\x1B(B", "\x00%\x00%", 'JIS'); } testValidString("\x00\xA1", "\x1B\$(D\x22\x42\x1B(B", "UTF-16BE", "JIS", false); @@ -167,29 +162,36 @@ convertInvalidString("\x00\xA1", "%", "UTF-16BE", "ISO-2022-JP", false); echo "JIS X 0212 support OK\n"; /* All possible escape sequences */ -$validEscapes = ["\x1B\$@" => true, "\x1B\$B" => true, "\x1B\$(@" => true, "\x1B\$(B" => true, "\x1B\$(D" => true, "\x1B(B" => true, "\x1B(H" => true, "\x1B(J" => true, "\x1B(I" => true]; +$validJisEscapes = ["\x1B\$@" => true, "\x1B\$B" => true, "\x1B\$(@" => true, "\x1B\$(B" => true, "\x1B\$(D" => true, "\x1B(B" => true, "\x1B(H" => true, "\x1B(J" => true, "\x1B(I" => true]; +$validIso2022jpEscapes = ["\x1B\$@" => true, "\x1B\$B" => true, "\x1B(B" => true, "\x1B(J" => true]; for ($i = 0; $i <= 0xFF; $i++) { for ($j = 0; $j <= 0xFF; $j++) { $escapeSequence = "\x1B" . chr($i) . chr($j); if ($escapeSequence === "\x1B\$(") continue; - if (isset($validEscapes[$escapeSequence])) { - testValid($escapeSequence, "", 'JIS', false); - testValid($escapeSequence, "", 'ISO-2022-JP', false); + if (isset($validJisEscapes[$escapeSequence])) { + testValid($escapeSequence . "\x1B(B", "", 'JIS', false); + } else { + identifyInvalidString($escapeSequence . "\x1B(B", 'JIS'); + } + if (isset($validIso2022jpEscapes[$escapeSequence])) { + testValid($escapeSequence . "\x1B(B", "", 'ISO-2022-JP', false); } else { - identifyInvalidString($escapeSequence, 'JIS'); - identifyInvalidString($escapeSequence, 'ISO-2022-JP'); + identifyInvalidString($escapeSequence . "\x1B(B", 'ISO-2022-JP'); } } } for ($i = 0; $i <= 0xFF; $i++) { $escapeSequence = "\x1B\$(" . chr($i); - if (isset($validEscapes[$escapeSequence])) { - testValid($escapeSequence, "", 'JIS', false); - testValid($escapeSequence, "", 'ISO-2022-JP', false); + if (isset($validJisEscapes[$escapeSequence])) { + testValid($escapeSequence . "\x1B(B", "", 'JIS', false); + } else { + identifyInvalidString($escapeSequence . "\x1B(B", 'JIS'); + } + if (isset($validIso2022jpEscapes[$escapeSequence])) { + testValid($escapeSequence . "\x1B(B", "", 'ISO-2022-JP', false); } else { - identifyInvalidString($escapeSequence, 'JIS'); - identifyInvalidString($escapeSequence, 'ISO-2022-JP'); + identifyInvalidString($escapeSequence . "\x1B(B", 'ISO-2022-JP'); } } /* Also try a bare ESC */ diff --git a/ext/mbstring/tests/mb_convert_case_various_mode.phpt b/ext/mbstring/tests/mb_convert_case_various_mode.phpt index 10c5bdb3aa6c3..70dcbfcd66a25 100644 --- a/ext/mbstring/tests/mb_convert_case_various_mode.phpt +++ b/ext/mbstring/tests/mb_convert_case_various_mode.phpt @@ -21,6 +21,33 @@ try { echo $e->getMessage() . \PHP_EOL; } +echo "\n-- Greek letter sigma --\n"; +var_dump(mb_convert_case("Σ", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("aΣ", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("aΣb", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("aΣ b", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case(" ΣΣΣΣ ", MB_CASE_TITLE, 'UTF-8')); + +// Apostrophe, full stop, colon, etc. are "case-ignorable" +// When checking whether capital sigma is at the end of a word or not, we skip over +// any number of case-ignorable characters, both when scanning back and when scanning forward +var_dump(mb_convert_case("'Σ", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("ab'Σ", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("Σ'", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("Σ'a", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("a'Σ'a", MB_CASE_TITLE, 'UTF-8')); + +// We scan back by at least 63 characters when necessary, +// but there is no guarantee that we will scan back further than that +var_dump(mb_convert_case('a' . str_repeat('.', 63) . "Σ", MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case('a' . str_repeat('.', 64) . "Σ", MB_CASE_TITLE, 'UTF-8')); // Context-sensitive casing doesn't work here! + +// When scanning forward to confirm if capital sigma is at the end of a word or not, +// there is no limit as to how far we will scan +var_dump(mb_convert_case("abcΣ" . str_repeat('.', 64) . ' abc', MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("abcΣ" . str_repeat('.', 64) . 'a abc', MB_CASE_TITLE, 'UTF-8')); +var_dump(mb_convert_case("abcΣ" . str_repeat('.', 256) . ' abc', MB_CASE_TITLE, 'UTF-8')); + /* Regression test for new implementation; * When converting a codepoint, if we overwrite it with the converted version before * checking whether we should shift in/out of 'title mode', then the conversion will be incorrect */ @@ -38,5 +65,22 @@ string(13) "foo bar spaß" string(13) "Foo Bar Spaß" string(13) "foo bar spaß" mb_convert_case(): Argument #2 ($mode) must be one of the MB_CASE_* constants + +-- Greek letter sigma -- +string(2) "Σ" +string(3) "Aς" +string(4) "Aσb" +string(5) "Aς B" +string(10) " Σσσς " +string(3) "'Σ" +string(5) "Ab'ς" +string(3) "Σ'" +string(4) "Σ'a" +string(6) "A'σ'a" +string(66) "A...............................................................ς" +string(67) "A................................................................σ" +string(73) "Abcς................................................................ Abc" +string(74) "Abcσ................................................................a Abc" +string(265) "Abcς................................................................................................................................................................................................................................................................ Abc" string(12) "02bc004e012d" string(8) "0149012d" diff --git a/ext/mbstring/tests/mb_convert_kana.phpt b/ext/mbstring/tests/mb_convert_kana.phpt index 69ea5560d4803..b263fec0f1b67 100644 --- a/ext/mbstring/tests/mb_convert_kana.phpt +++ b/ext/mbstring/tests/mb_convert_kana.phpt @@ -78,6 +78,7 @@ echo bin2hex(mb_convert_kana("\x30\x9B", 'k', 'UTF-16BE')), "\n"; echo bin2hex(mb_convert_kana("\x30\x9C", 'k', 'UTF-16BE')), "\n"; echo bin2hex(mb_convert_kana("\x30\xFC", 'k', 'UTF-16BE')), "\n"; echo bin2hex(mb_convert_kana("\x30\xFB", 'k', 'UTF-16BE')), "\n"; +echo bin2hex(mb_convert_kana("fooあいうエオ", "rnaskh", "UTF-8")), "\n"; echo "Including one which will expand to two codepoints:\n"; echo bin2hex(mb_convert_kana("\x30\x52", 'h', 'UTF-16BE')), "\n\n"; @@ -117,7 +118,6 @@ tryIncompatibleFlags('R', 'r'); tryIncompatibleFlags('N', 'n'); tryIncompatibleFlags('S', 's'); tryIncompatibleFlags('K', 'H'); -tryIncompatibleFlags('k', 'h'); tryIncompatibleFlags('C', 'c'); tryIncompatibleFlags('M', 'm'); tryIncompatibleFlags('h', 'C'); @@ -204,6 +204,7 @@ ff9e ff9f ff70 ff65 +666f6fefbdb1efbdb2efbdb3efbdb4efbdb5 Including one which will expand to two codepoints: ff79ff9e @@ -237,8 +238,6 @@ mb_convert_kana(): Argument #2 ($mode) must not combine 'S' and 's' flags mb_convert_kana(): Argument #2 ($mode) must not combine 'S' and 's' flags mb_convert_kana(): Argument #2 ($mode) must not combine 'H' and 'K' flags mb_convert_kana(): Argument #2 ($mode) must not combine 'H' and 'K' flags -mb_convert_kana(): Argument #2 ($mode) must not combine 'h' and 'k' flags -mb_convert_kana(): Argument #2 ($mode) must not combine 'h' and 'k' flags mb_convert_kana(): Argument #2 ($mode) must not combine 'C' and 'c' flags mb_convert_kana(): Argument #2 ($mode) must not combine 'C' and 'c' flags mb_convert_kana(): Argument #2 ($mode) must not combine 'M' and 'm' flags diff --git a/ext/mbstring/tests/mb_convert_variables.phpt b/ext/mbstring/tests/mb_convert_variables.phpt index 1190e78a05b86..2eb45946b5e8f 100644 --- a/ext/mbstring/tests/mb_convert_variables.phpt +++ b/ext/mbstring/tests/mb_convert_variables.phpt @@ -41,7 +41,7 @@ $encoding = mb_convert_variables('JIS', 'EUC-JP', $s); print("$encoding\n"); // EUC-JP print(base64_encode($s)."\n"); // Converted to JIS (base64 encoded) -// Test for multiple slcaler +// Test for multiple scalar $s1 = $euc_jp; $s2 = $euc_jp; $s3 = $euc_jp; @@ -49,8 +49,7 @@ $encoding = mb_convert_variables('EUC-JP', 'auto', $s1, $s2, $s3); print("$encoding\n"); // EUC-JP echo bin2hex("$s1$s2$s3"), "\n"; // Converted to EUC-JP -// Note: Mixing encoding in array/object is not supported? -// Test for array +// Note: Mixing encoding in array/object is not supported echo "== ARRAY TEST ==\n"; $a = array($s3, $s2, $s1); $aa = $a; @@ -116,6 +115,7 @@ echo "== SCALAR, ARRAY AND OBJECT TEST ==\n"; $s1 = $euc_jp; $s2 = $euc_jp; $s3 = $euc_jp; +$a = array($s1, $s2, $s3); $aa = $a; $oo = $o; @@ -161,6 +161,17 @@ mb_convert_variables('UTF-16LE', 'UTF-8', $nested); echo bin2hex($nested[0]->inner), "\n"; echo "# of illegal characters detected: ", mb_get_info('illegal_chars') - $illegalCount, "\n"; +echo "== ENCODING AUTO-DETECTION TEST ==\n"; + +ini_set('mbstring.strict_detection', '1'); +$bad_utf7 = "abc + abc"; +var_dump(mb_convert_variables('UTF-8', 'UTF-7,UTF-8', $bad_utf7)); +var_dump($bad_utf7); + +$bad_utf7imap = "abc &"; +var_dump(mb_convert_variables('UTF-8', 'UTF7-IMAP,UTF-8', $bad_utf7imap)); +var_dump($bad_utf7imap); + ?> --EXPECT-- == SCALAR TEST == @@ -197,3 +208,8 @@ UTF-8 # of illegal characters detected: 1 2600 # of illegal characters detected: 1 +== ENCODING AUTO-DETECTION TEST == +string(5) "UTF-8" +string(9) "abc + abc" +string(5) "UTF-8" +string(5) "abc &" diff --git a/ext/mbstring/tests/mb_decode_mimeheader_variation4.phpt b/ext/mbstring/tests/mb_decode_mimeheader_variation4.phpt new file mode 100644 index 0000000000000..4579e6e834c83 --- /dev/null +++ b/ext/mbstring/tests/mb_decode_mimeheader_variation4.phpt @@ -0,0 +1,117 @@ +--TEST-- +Test mb_decode_mimeheader() function: weird variations found by fuzzer +--EXTENSIONS-- +mbstring +--FILE-- + +--EXPECT-- +string(36) "0032002c0020004700430047003f00470053" +string(6) "203869" +string(0) "" +string(0) "" +string(10) "2c13403d2c" +string(16) "3d3f493f423f3f3d" +string(200) "3d3f3d203f3d3f523f3d3f3d203f3f003d3d3d3d3f3d3d3d3f3f3d3f55432d523f3d3f3d203f3d3f3d3d3d3d3d3f3d203f3d3d3d3d3d3d3f3d3d3d3d3d3d3f3d203f3d3d3d3d3d3d3f3d3d3d3f3f3d3f55432d4b523f3d3f3d203f3d3f3d3d3d3f3d3d3f" +string(400) "003d003f003f003f007400660037002c0055000100000060004000000004007c003f004400180000000000000076003f003f003f003f003f003f003f003f003f003f003f003f001300660037002c0055002600000053000100000017002c0044003f003f003f003f003f003f003f0001000000000014003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f00000011000000000000000000000000" +string(0) "" +string(2) "3f" +string(2) "3f" +string(0) "" +string(2) "3f" +string(4) "3d3f" +string(6) "3d3f3d" +string(6) "3d3f2c" +string(42) "626567696e20303634342066696c656e616d650a20" +string(2) "36" +string(2) "36" +string(2) "36" diff --git a/ext/mbstring/tests/mb_decode_mimeheader_variation5.phpt b/ext/mbstring/tests/mb_decode_mimeheader_variation5.phpt new file mode 100644 index 0000000000000..a313ff14e0f15 --- /dev/null +++ b/ext/mbstring/tests/mb_decode_mimeheader_variation5.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test mb_decode_mimeheader() function: use of underscores in QPrint-encoded data +--EXTENSIONS-- +mbstring +--FILE-- + +--EXPECT-- +string(3) "abc" +string(7) "abc def" +string(9) "_abc def_" +string(10) " 汉字 " +string(1) "_" diff --git a/ext/mbstring/tests/mb_detect_encoding.phpt b/ext/mbstring/tests/mb_detect_encoding.phpt index a9d48ee5f9488..544375fbd2998 100644 --- a/ext/mbstring/tests/mb_detect_encoding.phpt +++ b/ext/mbstring/tests/mb_detect_encoding.phpt @@ -19,12 +19,21 @@ $hungarian = "Árvíztűrő tükörfúrógép"; echo "== BASIC TEST ==\n"; -print("SJIS: " . mb_detect_encoding($sjis, 'SJIS') . "\n"); -print("JIS: " . mb_detect_encoding($jis, 'JIS') . "\n"); -print("EUC-JP: " . mb_detect_encoding($euc_jp, 'UTF-8,EUC-JP,JIS') . "\n"); -print("EUC-JP: " . mb_detect_encoding($euc_jp, 'JIS,EUC-JP') . "\n"); -print("UTF-8: " . mb_detect_encoding($polish1, 'UTF-8,UTF-16,ISO-8859-1') . "\n"); -print("UTF-8: " . mb_detect_encoding($polish2, 'UTF-8,UTF-16,ISO-8859-1') . "\n"); +print("Empty String: " . mb_detect_encoding('') . "\n"); +print("Bad ASCII (non-strict): " . mb_detect_encoding("\xDD\x92", ['ASCII', 'UTF-8'], false) . "\n"); +print("Bad ASCII (strict): " . mb_detect_encoding("\xDD\x92", ['ASCII', 'UTF-8'], true) . "\n"); +print("Bad ASCII/UTF-8, with more errors for ASCII (non-strict): " . mb_detect_encoding("\xD6\x8A\x8A", ['ASCII', 'UTF-8'], false) . "\n"); +print("Bad ASCII/UTF-8, with more errors for ASCII (strict): " . var_export(mb_detect_encoding("\xD6\x8A\x8A", ['ASCII', 'UTF-8'], true), true) . "\n"); + +print("SJIS: " . mb_detect_encoding($sjis, 'SJIS', true) . "\n"); +print("JIS: " . mb_detect_encoding($jis, 'JIS', true) . "\n"); +print("EUC-JP (strict): " . mb_detect_encoding($euc_jp, 'UTF-8,EUC-JP,JIS', true) . "\n"); +print("EUC-JP (non-strict): " . mb_detect_encoding($euc_jp, 'UTF-8,EUC-JP,JIS', false) . "\n"); +print("EUC-JP (fewer choices): " . mb_detect_encoding($euc_jp, 'JIS,EUC-JP') . "\n"); +print("UTF-8, polish string 1 (strict): " . mb_detect_encoding($polish1, 'UTF-8,UTF-16,ISO-8859-1', true) . "\n"); +print("UTF-8, polish string 1 (non-strict): " . mb_detect_encoding($polish1, 'UTF-8,UTF-16,ISO-8859-1', false) . "\n"); +print("UTF-8, polish string 2 (strict): " . mb_detect_encoding($polish2, 'UTF-8,UTF-16,ISO-8859-1', true) . "\n"); +print("UTF-8, polish string 2 (non-strict): " . mb_detect_encoding($polish2, 'UTF-8,UTF-16,ISO-8859-1', false) . "\n"); echo "== ARRAY ENCODING LIST ==\n"; @@ -91,6 +100,30 @@ try { echo $e->getMessage() . \PHP_EOL; } +echo "== BOM TEST ==\n"; + +$str = chr(239).chr(187).chr(191).chr(195).chr(180); // UTF-8 BOM followed by ô +var_dump(mb_detect_encoding($str, ['UTF-8', 'ISO-8859-1'], true)); +// U+4E4E is the Chinese character 乎; normally it would be impossible to distinguish UTF-16LE from UTF-16BE +// But the BOM can tell us which one it is +var_dump(mb_detect_encoding("\xFE\xFF\x4E\x4E", ['UTF-8', 'ISO-8859-1', 'UTF-16LE', 'UTF-16BE'], true)); +var_dump(mb_detect_encoding("\xFF\xFE\x4E\x4E", ['UTF-8', 'ISO-8859-1', 'UTF-16LE', 'UTF-16BE'], true)); +// However, a BOM should only appear at the beginning of the string +$detected = mb_detect_encoding("\x4E\x4E\xFE\xFF\x4E\x4E", ['UTF-8', 'ISO-8859-1', 'UTF-16LE', 'UTF-16BE'], true); +if ($detected === 'UTF-16BE' || $detected === 'UTF-16LE') + die("Don't accept a BOM in the middle of a string"); + +echo "== CHECK FUNCTION TEST ==\n"; + +function testCheckFn($str, $encoding, $encodings) { + if (mb_check_encoding($str, $encoding)) + die("Input string " . bin2hex($str) . " should not be valid in " . $encoding); + if (mb_detect_encoding($str, $encodings, true) === $encoding) + die("mb_detect_encoding should never return " . $encoding . " for invalid input string " . bin2hex($str)); +} + +testCheckFn("abc + abc", "UTF-7", "UTF-7,UTF-8"); + echo "== TORTURE TEST ==\n"; function test($strings, $encodings) { @@ -149,6 +182,7 @@ $jpEncodings = [ test($jpStrings, $jpEncodings); $cnStrings = [ + // Headline randomly picked from Chinese news "日本宫内厅宣布,真子公主和小室圭将在10月26日完婚。", // The Dream of Red Mansions "此开卷第一回也。作者自云曾历过一番梦幻之后,故将真事隐去,而借“通灵”说此《石头记》一书也", @@ -312,17 +346,38 @@ test($czechStrings, $czechEncodings); test([$hungarian], ['UTF-8', 'UTF-16', 'Windows-1252']); +$turkishStrings = [ + // Random junk indiscriminately copied from randomly picked Wikipedia articles + "Samsun 19 Mayıs Stadyumu, Samsun'un Tekkeköy ilçesinde bulunan akıllı çok amaçlı stadyumdur. 33.919 koltuk kapasitesiyle Samsunspor'un iç saha maçlarına ev sahipliği yapmaktadır. Toplu Konut İdaresi tarafından yaptırılan ve 2017'de tamamlanan stadyum adını Mustafa Kemal'in Samsun'a çıktığı gün olan 19 Mayıs'tan almaktadır. İlk olarak Nisan 2011'de duyurulan proje 3 Aralık 2012'de Toplu Konut İdaresince yapılan ve Ali Acar İnşaat'ın kazandığı ihale ile resmiyete dökülmüş, 4 Ağustos 2013 tarihindeki temel atma töreni ile de inşa aşamasına geçilmiştir. İnşaatın başlangıç tarihinden itibaren en geç 800 gün içerisinde tamamlanması taahhüt edilse de UEFA'nın standartlarına uyum sağlamak için projede yenileme yapılması, çatının inşasıyla sorumlu şirketin iflas etmesi gibi sebeplerle tamamlanma süresi birkaç kez sarkmıştır. Bu bağlamda, ilk etapta 2014-15 sezonunda hazır hâle geleceği açıklanan stadyumun açılışı önce 2015-16, daha sonra 2016-17 sezonu başına ertelense de bu hedefler de yakalanamamıştır.", + "Lütf-i Celil (Osmanlı Türkçesi: ﻟﻄﻒ ﺟﻠﻴﻞ Anlamı: \"İlahi Lütuf\"), Osmanlı Donanması'nın Lütf-i Celil sınıfının öncü gemisi olan zırhlı savaş gemisidir. Başlangıçta Osmanlı İmparatorluğu'na bağlı özerk bir devlet olan Mısır Hidivliği tarafından sipariş edilen Lütf-i Celil, Osmanlı hükûmetinin Mısır'ı gemiyi teslim etmeye zorlaması ile Fransa'daki Forges et Chantiers de la Gironde tersanesinde yapım aşamasındayken Osmanlılara devredildi. Lütf-i Celil, 1877'de 93 Harbi sırasında aktif görevde bulundu ve Rus güçlerinin Tuna'yı geçmesini önlemek için operasyonlarda bulundu. 11 Mayıs'ta devriye gezerken bir Rus topçu bataryasıyla çatışmaya girdi.", + "Çoğu tarihçinin kanısına göre, ABD'nin üçüncü başkanı Jefferson, karısının ölümünün ardından kölesi Sally Hemings ile 38 yıl süren ilişkisi sırasında onun altı çocuğunun babası olmuştur.", + "2011 İran drama filmi Bir Ayrılık, 61. Berlin Film Festivali'nde Altın Ayı kazanarak, bu ödülü alan ilk İran filmi oldu.", + "Josef Bringas, isyan eden general Nikiforos Fokas'a karşı Konstantinopolis'e birlikler getirdi; asilerin Boğaziçi'ni geçmelerini engellemek için tüm gemileri tuttu; Nikiforos'un babası Bardas'ı rehin aldı ama başarılı olamadı." +]; +// ISO-8859-9 and Windows-1254 are very similar and we can't really distinguish them from each other +// But both of them should be distinguishable from UTF-8 +test($turkishStrings, ['UTF-8', 'UTF-16', 'ISO-8859-9']); +test($turkishStrings, ['UTF-8', 'Windows-1254']); + echo "Done!\n"; ?> --EXPECT-- == BASIC TEST == +Empty String: ASCII +Bad ASCII (non-strict): UTF-8 +Bad ASCII (strict): UTF-8 +Bad ASCII/UTF-8, with more errors for ASCII (non-strict): UTF-8 +Bad ASCII/UTF-8, with more errors for ASCII (strict): false SJIS: SJIS JIS: JIS -EUC-JP: EUC-JP -EUC-JP: EUC-JP -UTF-8: UTF-8 -UTF-8: UTF-8 +EUC-JP (strict): EUC-JP +EUC-JP (non-strict): EUC-JP +EUC-JP (fewer choices): EUC-JP +UTF-8, polish string 1 (strict): UTF-8 +UTF-8, polish string 1 (non-strict): UTF-8 +UTF-8, polish string 2 (strict): UTF-8 +UTF-8, polish string 2 (non-strict): UTF-8 == ARRAY ENCODING LIST == JIS: JIS EUC-JP: EUC-JP @@ -342,5 +397,10 @@ SJIS: SJIS INT: EUC-JP EUC-JP: EUC-JP mb_detect_encoding(): Argument #2 ($encodings) contains invalid encoding "BAD" +== BOM TEST == +string(5) "UTF-8" +string(8) "UTF-16BE" +string(8) "UTF-16LE" +== CHECK FUNCTION TEST == == TORTURE TEST == Done! diff --git a/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt b/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt new file mode 100644 index 0000000000000..7bf05b43ae36b --- /dev/null +++ b/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt @@ -0,0 +1,160 @@ +--TEST-- +Test mb_encode_mimeheader() function : test cases found by fuzzer +--EXTENSIONS-- +mbstring +--FILE-- +\x00\x00\x00\x00", "HZ", "Q", "", 71)); + +// ASCII strings with no spaces should pass through unchanged +var_dump(mb_encode_mimeheader("yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyBIG5", "BIG-5", "B")); + +// Regression test: After decoding part of a line as ASCII, before we switch into Base64/QPrint encoding mode, +// refill our buffer of wchars so we don't hit the end of the buffer in the middle of a line +var_dump(mb_encode_mimeheader("\x20\x20\x20\x202\x20\x20\x20sssssssssssssssssssssssssss\x20\x20\x20\x20W\x20\x20\x20\x20\x20\x20W\x20\x20\x20\x20\xb9S\x01\x00\xf0`\x00\x00\x20\x20\x20\x20mSCII\xee\x20\x20\x20\x20mSCII\xeeI\xee", "ArmSCII-8", "B", "")); + +// Regression test: Input string with a huge number of spaces +var_dump(mb_encode_mimeheader("\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x00", "CP936", "Q", "")); + +// Regression test: Long string, all ASCII, but with spaces at the beginning +var_dump(mb_encode_mimeheader("\x20\x201111111111111111111111111111111111111111111111111111111111111111111111111", "ASCII", "Q", "")); + +// Only a single character in input, but when we convert it to outcode and then +// transfer-encode it, it takes too many bytes to fit on a single line +// Legacy implementation would always include at least one wchar in each encoded word; +// imitate the same behavior +var_dump(mb_encode_mimeheader("\xe7\xad\xb5", "HZ", "Q", "", 44)); + +// Regression test: Exploring corner cases of when legacy implementation would output plain ASCII +// with no transfer encoding, and when it would transfer-encode +var_dump(mb_encode_mimeheader("2\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20!3", "GB18030", "Q", "")); +var_dump(mb_encode_mimeheader("\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20!3\x20", "GB18030", "Q", "")); + +// Change in behavior: The old implementation would output the following string as plain ASCII, +// but the new one transfer-encodes it +// In the general case, matching the old implementation's decision to transfer-encode or not +// perfectly would require allocating potentially unbounded scratch memory (up to the size of +// the input string), but we aim to only use a constant amount of temporarily allocated memory +var_dump(mb_encode_mimeheader("2\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20!3", "GB18030", "Q", "")); + +echo "Done"; +?> +--EXPECT-- +string(0) "" +string(21) "=?UTF-8?Q?abc=00abc?=" +string(16) "=?UTF-8?B?Pw==?=" +string(19) "=?US-ASCII?B?Pw==?=" +string(18) "=?US-ASCII?Q?=3F?=" +string(19) "=?US-ASCII?B?PQ==?=" +string(18) "=?US-ASCII?Q?=3D?=" +string(19) "=?US-ASCII?B?Xw==?=" +string(18) "=?US-ASCII?Q?=5F?=" +string(19) "=?US-ASCII?B?fw==?=" +string(1) " " +string(1) " " +string(3) " " +string(3) " " +string(8) "ab ab " +string(8) "ab ab " +string(1) "`" +string(1) "S" +string(2) "S4" +string(2) "S4" +string(61) "=?UCS-4?Q?=00=00=00=32=00=00=00=34?= =?UCS-4?Q?=00=00=00=0A?=" +string(21) "o =?US-ASCII?B?AA==?=" +string(68) "=?UCS-4?B?AAAAAAAAABEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==?=" +string(271) "=?UCS-2?B?AAEAAAA/AD8APwA/AD8APwA9AD8APwA/AD0APwABAAAAYQAAAAAAPwA/AD8=?= =?UCS-2?B?AD0APwA/AD8APwA/AD8APwA/AD8APwA/ADQAPwA0AD8APwA/AD8APwA9AD8=?= =?UCS-2?B?AAEAAAAAAAAAAQAAAAAABgA/AD8APwA/AD8APwA/AD8APwA9AD8APwA/AD8=?= =?UCS-2?B?AD8APwA/AD8APwA/AD8ANAA/AD8APwA/AD8APwA0?=" +string(27) "=aaaaaa= =?US-ASCII?Q?=3F?=" +string(9) "=aaaaaa=?" +string(55) ", =?ISO-2022-JP?Q?o=00=01=00=00?= =?ISO-2022-JP?Q?=28?=" +string(19) " =?US-ASCII?Q?=3F?=" +string(76) " =?HZ-GB-2312?Q?=3F=7E=7EH=7E=7E=3F=3F=00=00=3F=3F=3F=3F=3F=3E=00=00=00=00?=" +string(75) "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyBIG5" +string(108) " 2 sssssssssssssssssssssssssss W W =?ArmSCII-8?B?ICAgP1MBAD9gAAAgICAgbVNDSUk/ICAgIG1TQ0lJP0k/?=" +string(294) "=?CP936?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?CP936?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?CP936?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?CP936?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=00?=" +string(75) " 1111111111111111111111111111111111111111111111111111111111111111111111111" +string(33) "=?HZ-GB-2312?Q?=7E=7Bs=5B=7E=7D?=" +string(77) "2 !3" +string(282) "=?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20!=33=20?=" +string(296) "2 =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20!=33?=" +Done diff --git a/ext/mbstring/tests/mb_encode_mimeheader_crash.phpt b/ext/mbstring/tests/mb_encode_mimeheader_crash.phpt new file mode 100644 index 0000000000000..2505d4c4ad992 --- /dev/null +++ b/ext/mbstring/tests/mb_encode_mimeheader_crash.phpt @@ -0,0 +1,21 @@ +--TEST-- +Test mb_encode_mimeheader() function : text encoding with no MIME name +--EXTENSIONS-- +mbstring +--SKIPIF-- + +--FILE-- +getMessage() . \PHP_EOL; +} + +echo "Done\n"; +?> +--EXPECT-- +mb_encode_mimeheader(): Argument #2 ($charset) "UTF7-IMAP" cannot be used for MIME header encoding +Done diff --git a/ext/mbstring/tests/mb_http_input_multi_post.phpt b/ext/mbstring/tests/mb_http_input_multi_post.phpt new file mode 100644 index 0000000000000..64185e4b23ad5 --- /dev/null +++ b/ext/mbstring/tests/mb_http_input_multi_post.phpt @@ -0,0 +1,42 @@ +--TEST-- +mb_http_input() with POST method and multiple candidate encodings +--EXTENSIONS-- +mbstring +--POST-- +a=日本語&b=ελληνικά +--INI-- +mbstring.encoding_translation=1 +input_encoding=UTF-8,SJIS,EUC-JP,ISO-8859-1 +--FILE-- + +--EXPECT-- +日本語 +ελληνικά +string(5) "UTF-8" +bool(false) +bool(false) +bool(false) +array(4) { + [0]=> + string(5) "UTF-8" + [1]=> + string(4) "SJIS" + [2]=> + string(6) "EUC-JP" + [3]=> + string(10) "ISO-8859-1" +} +string(28) "UTF-8,SJIS,EUC-JP,ISO-8859-1" diff --git a/ext/mbstring/tests/mb_parse_str_multi.phpt b/ext/mbstring/tests/mb_parse_str_multi.phpt index e971627c6660c..1efb437f4a443 100644 --- a/ext/mbstring/tests/mb_parse_str_multi.phpt +++ b/ext/mbstring/tests/mb_parse_str_multi.phpt @@ -3,7 +3,7 @@ mb_parse_str() with multiple candidate encodings --EXTENSIONS-- mbstring --INI-- -mbstring.http_input=UTF-8,SJIS,EUC-JP +mbstring.http_input=UTF-8,SJIS,EUC-JP,ISO-8859-1,ISO-2022-JP --FILE-- 616263 Query: 82a082a282a43d9356 e38182e38184e38186=>e5a4a9 +Query: 666f6f3de6266261723d972662617a3da5 +666f6f=>c3a6 +626172=>c297 +62617a=>c2a5 +Query: 611f2428403d313233 +611f242840=>313233 +Query: 6162633d611f242840 +616263=>611f242840 diff --git a/ext/mbstring/tests/mb_scrub.phpt b/ext/mbstring/tests/mb_scrub.phpt index 1b2d8ab4e34e2..6eb580bf31cc9 100644 --- a/ext/mbstring/tests/mb_scrub.phpt +++ b/ext/mbstring/tests/mb_scrub.phpt @@ -8,7 +8,15 @@ var_dump( "?" === mb_scrub("\x80"), "?" === mb_scrub("\x80", 'UTF-8') ); + +$utf8str = "abc 日本語 Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞"; +// Check $utf8str so it is marked as 'valid UTF-8' +// This will enable optimized implementation of mb_scrub +if (!mb_check_encoding($utf8str, 'UTF-8')) + die("Test string should be valid UTF-8"); +var_dump(mb_scrub($utf8str)); ?> --EXPECT-- bool(true) bool(true) +string(122) "abc 日本語 Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞" diff --git a/ext/mbstring/tests/mb_str_split_error_conditions.phpt b/ext/mbstring/tests/mb_str_split_error_conditions.phpt index 7c4269f68a665..bb307e16fa41f 100644 --- a/ext/mbstring/tests/mb_str_split_error_conditions.phpt +++ b/ext/mbstring/tests/mb_str_split_error_conditions.phpt @@ -26,8 +26,34 @@ try { echo $e->getMessage() . \PHP_EOL; } +// For UTF-8, error markers are not inserted +echo "== INVALID UTF-8 ==\n"; +$array = mb_str_split("abc\xFFabc", 2, "UTF-8"); +echo "[", implode(', ', array_map('bin2hex', $array)), "]\n"; + +// For most other encodings, they are +echo "== INVALID HZ ==\n"; +// The last string emitted by mb_str_split will include '?' as an error marker, +// since ά cannot be represented in HZ +$array = mb_str_split(mb_convert_encoding("ελληνικά", "HZ", "UTF-8"), 2, "HZ"); +echo "[", implode(', ', array_map('bin2hex', $array)), "]\n"; + +// HTML entity error markers +mb_substitute_character("entity"); +echo "== INVALID HZ IN 'ENTITY' ERROR OUTPUT MODE ==\n"; +// The output here will actually include an HTML entity #x3AC; +// It will be split into segments of 2 characters each by mb_str_split +$array = mb_str_split(mb_convert_encoding("ελληνικά", "HZ", "UTF-8"), 2, "HZ"); +echo "[", implode(', ', array_map('bin2hex', $array)), "]\n"; + ?> --EXPECT-- mb_str_split(): Argument #2 ($length) must be greater than 0 mb_str_split(): Argument #2 ($length) must be greater than 0 mb_str_split(): Argument #3 ($encoding) must be a valid encoding, "BAD_ENCODING" given +== INVALID UTF-8 == +[6162, 63ff, 6162, 63] +== INVALID HZ == +[7e7b2645264b7e7d, 7e7b264b26477e7d, 7e7b264d26497e7d, 7e7b264a7e7d3f] +== INVALID HZ IN 'ENTITY' ERROR OUTPUT MODE == +[7e7b2645264b7e7d, 7e7b264b26477e7d, 7e7b264d26497e7d, 7e7b264a7e7d26, 2378, 3341, 433b] diff --git a/ext/mbstring/tests/mb_str_split_jp.phpt b/ext/mbstring/tests/mb_str_split_jp.phpt index 22f39539608c3..9e879f4fd96f2 100644 --- a/ext/mbstring/tests/mb_str_split_jp.phpt +++ b/ext/mbstring/tests/mb_str_split_jp.phpt @@ -69,6 +69,34 @@ if(end($array) !== $enc){ last array element: %s expected: %s\n", unpack("H*", end($array))[1],unpack("H*", $enc)[1]); } +/* SJIS byte 0x80 was previously wrongly treated as the starting byte for a 2-byte character */ +echo "== Regression test for SJIS byte 0x80 ==\n"; +foreach (['SJIS', 'SJIS-2004', 'MacJapanese', 'SJIS-Mobile#DOCOMO', 'SJIS-Mobile#KDDI', 'SJIS-Mobile#SoftBank'] as $encoding) { + $array = mb_str_split("\x80\xA1abc\x80\xA1", 2, $encoding); + echo "$encoding: [" . implode(', ', array_map('bin2hex', $array)) . "]\n"; + + // Also try bytes 0xFD, 0xFE, and 0xFF + $array = mb_str_split("abc\xFD\xFE\xFFab\xFD\xFE\xFF", 2, $encoding); + echo "$encoding: [" . implode(', ', array_map('bin2hex', $array)) . "]\n"; +} + +/* +Some MacJapanese characters map to a sequence of several Unicode codepoints. Examples: + +0x85AB 0xF862+0x0058+0x0049+0x0049+0x0049 # roman numeral thirteen +0x85AC 0xF861+0x0058+0x0049+0x0056 # roman numeral fourteen +0x85AD 0xF860+0x0058+0x0056 # roman numeral fifteen +0x85BF 0xF862+0x0078+0x0069+0x0069+0x0069 # small roman numeral thirteen +0x85C0 0xF861+0x0078+0x0069+0x0076 # small roman numeral fourteen +0x85C1 0xF860+0x0078+0x0076 # small roman numeral fifteen + +Even though they map to multiple codepoints, mb_str_split treats these as ONE character each +*/ + +echo "== MacJapanese characters which map to 3-5 codepoints each ==\n"; +echo "[", implode(', ', array_map('bin2hex', mb_str_split("abc\x85\xAB\x85\xAC\x85\xAD", 1, 'MacJapanese'))), "]\n"; +echo "[", implode(', ', array_map('bin2hex', mb_str_split("abc\x85\xBF\x85\xC0\x85\xC1", 2, 'MacJapanese'))), "]\n"; + ?> --EXPECT-- BIG-5: a4e9 a5bb @@ -80,3 +108,19 @@ UTF-16LE: e565 2c67 UTF-32BE: 000065e5 0000672c UTF-32LE: e5650000 2c670000 UTF-8: e697a5 e69cac +== Regression test for SJIS byte 0x80 == +SJIS: [80a1, 6162, 6380, a1] +SJIS: [6162, 63fd, feff, 6162, fdfe, ff] +SJIS-2004: [80a1, 6162, 6380, a1] +SJIS-2004: [6162, 63fd, feff, 6162, fdfe, ff] +MacJapanese: [80a1, 6162, 6380, a1] +MacJapanese: [6162, 63fd, feff, 6162, fdfe, ff] +SJIS-Mobile#DOCOMO: [80a1, 6162, 6380, a1] +SJIS-Mobile#DOCOMO: [6162, 63fd, feff, 6162, fdfe, ff] +SJIS-Mobile#KDDI: [80a1, 6162, 6380, a1] +SJIS-Mobile#KDDI: [6162, 63fd, feff, 6162, fdfe, ff] +SJIS-Mobile#SoftBank: [80a1, 6162, 6380, a1] +SJIS-Mobile#SoftBank: [6162, 63fd, feff, 6162, fdfe, ff] +== MacJapanese characters which map to 3-5 codepoints each == +[61, 62, 63, 85ab, 85ac, 85ad] +[6162, 6385bf, 85c085c1] diff --git a/ext/mbstring/tests/mb_str_split_other.phpt b/ext/mbstring/tests/mb_str_split_other.phpt index a237f80753c96..4b0f901a90387 100644 --- a/ext/mbstring/tests/mb_str_split_other.phpt +++ b/ext/mbstring/tests/mb_str_split_other.phpt @@ -6,6 +6,122 @@ mbstring getMessage() . \PHP_EOL; +} + ?> --EXPECT-- [00010203, 04050607] +== HZ == +[74, 65, 73, 74, 20, 7e7b252b7e7d, 7e7b253f7e7d, 7e7b252b7e7d, 7e7b254a7e7d, 20, 7e7b3a3a7e7d, 7e7b57567e7d] +[7465, 7374, 207e7b252b7e7d, 7e7b253f252b7e7d, 7e7b254a7e7d20, 7e7b3a3a57567e7d] +[746573, 74207e7b252b7e7d, 7e7b253f252b254a7e7d, 207e7b3a3a57567e7d] +[74657374, 207e7b252b253f252b7e7d, 7e7b254a7e7d207e7b3a3a57567e7d] +[7465737420, 7e7b252b253f252b254a7e7d20, 7e7b3a3a57567e7d] +[74657374207e7b252b7e7d, 7e7b253f252b254a7e7d207e7b3a3a57567e7d] +[74657374207e7b252b253f7e7d, 7e7b252b254a7e7d207e7b3a3a57567e7d] +[74657374207e7b252b253f252b7e7d, 7e7b254a7e7d207e7b3a3a57567e7d] +[74657374207e7b252b253f252b254a7e7d, 207e7b3a3a57567e7d] +[74657374207e7b252b253f252b254a7e7d20, 7e7b3a3a57567e7d] +[74657374207e7b252b253f252b254a7e7d207e7b3a3a7e7d, 7e7b57567e7d] +[74657374207e7b252b253f252b254a7e7d207e7b3a3a57567e7d] +== BIG-5 == +[74, 65, 73, 74, 20, c743, c757, c743, c762, 20, ba7e, a672] +[7465, 7374, 20c743, c757c743, c76220, ba7ea672] +[746573, 7420c743, c757c743c762, 20ba7ea672] +[74657374, 20c743c757c743, c76220ba7ea672] +[7465737420, c743c757c743c76220, ba7ea672] +[7465737420c743, c757c743c76220ba7ea672] +[7465737420c743c757, c743c76220ba7ea672] +[7465737420c743c757c743, c76220ba7ea672] +[7465737420c743c757c743c762, 20ba7ea672] +[7465737420c743c757c743c76220, ba7ea672] +[7465737420c743c757c743c76220ba7e, a672] +[7465737420c743c757c743c76220ba7ea672] +== ISO-8859-1 == +[74, 65, 73, 74, 20, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf] +[7465, 7374, 20c0, c1c2, c3c4, c5c6, c7c8, c9ca, cbcc, cdce, cf] +[746573, 7420c0, c1c2c3, c4c5c6, c7c8c9, cacbcc, cdcecf] +[74657374, 20c0c1c2, c3c4c5c6, c7c8c9ca, cbcccdce, cf] +[7465737420, c0c1c2c3c4, c5c6c7c8c9, cacbcccdce, cf] +[7465737420c0, c1c2c3c4c5c6, c7c8c9cacbcc, cdcecf] +[7465737420c0c1, c2c3c4c5c6c7c8, c9cacbcccdcecf] +[7465737420c0c1c2, c3c4c5c6c7c8c9ca, cbcccdcecf] +[7465737420c0c1c2c3, c4c5c6c7c8c9cacbcc, cdcecf] +[7465737420c0c1c2c3c4, c5c6c7c8c9cacbcccdce, cf] +[7465737420c0c1c2c3c4c5, c6c7c8c9cacbcccdcecf] +[7465737420c0c1c2c3c4c5c6, c7c8c9cacbcccdcecf] +[7465737420c0c1c2c3c4c5c6c7, c8c9cacbcccdcecf] +[7465737420c0c1c2c3c4c5c6c7c8, c9cacbcccdcecf] +[7465737420c0c1c2c3c4c5c6c7c8c9, cacbcccdcecf] +[7465737420c0c1c2c3c4c5c6c7c8c9ca, cbcccdcecf] +[7465737420c0c1c2c3c4c5c6c7c8c9cacb, cccdcecf] +[7465737420c0c1c2c3c4c5c6c7c8c9cacbcc, cdcecf] +[7465737420c0c1c2c3c4c5c6c7c8c9cacbcccd, cecf] +[7465737420c0c1c2c3c4c5c6c7c8c9cacbcccdce, cf] +[7465737420c0c1c2c3c4c5c6c7c8c9cacbcccdcecf] +== Regression tests == +[1b28494a4a1b2842, 1b28494a4a1b2842] +[5a] +mb_str_split(): Argument #2 ($length) is too large diff --git a/ext/mbstring/tests/mb_stripos.phpt b/ext/mbstring/tests/mb_stripos.phpt index 1383cd5ed2e7a..9e7e33dadd954 100644 --- a/ext/mbstring/tests/mb_stripos.phpt +++ b/ext/mbstring/tests/mb_stripos.phpt @@ -9,9 +9,8 @@ mbstring ini_set('include_path','.'); include_once('common.inc'); - // Test string -$euc_jp = '0123ʸܸǤEUC-JPȤäƤޤ0123ܸݽ'; +$euc_jp = "0123\xA4\xB3\xA4\xCE\xCA\xB8\xBB\xFA\xCE\xF3\xA4\xCF\xC6\xFC\xCB\xDC\xB8\xEC\xA4\xC7\xA4\xB9\xA1\xA3EUC-JP\xA4\xF2\xBB\xC8\xA4\xC3\xA4\xC6\xA4\xA4\xA4\xDE\xA4\xB9\xA1\xA30123\xC6\xFC\xCB\xDC\xB8\xEC\xA4\xCF\xCC\xCC\xC5\xDD\xBD\xAD\xA4\xA4\xA1\xA3"; $slen = mb_strlen($euc_jp, 'EUC-JP'); echo "String len: $slen\n"; @@ -21,11 +20,11 @@ mb_internal_encoding('UTF-8') or print("mb_internal_encoding() failed\n"); echo "== POSITIVE OFFSET ==\n"; -print mb_stripos($euc_jp, 'ܸ', 0, 'EUC-JP') . "\n"; +print mb_stripos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", 0, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, '0', 0, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, 3, 0, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, 0, 0, 'EUC-JP') . "\n"; -print mb_stripos($euc_jp, 'ܸ', 15, 'EUC-JP') . "\n"; +print mb_stripos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", 15, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, '0', 15, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, 3, 15, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, 0, 15, 'EUC-JP') . "\n"; @@ -34,7 +33,7 @@ print mb_stripos($euc_jp, 0, 15, 'EUC-JP') . "\n"; // Negative offset echo "== NEGATIVE OFFSET ==\n"; -print mb_stripos($euc_jp, 'ܸ', -15, 'EUC-JP') . "\n"; +print mb_stripos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", -15, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, '0', -15, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, 3, -15, 'EUC-JP') . "\n"; print mb_stripos($euc_jp, 0, -15, 'EUC-JP') . "\n"; @@ -42,9 +41,9 @@ print mb_stripos($euc_jp, 0, -43, 'EUC-JP') . "\n"; // Out of range - should return false -print ("== OUT OF RANGE ==\n"); +print "== OUT OF RANGE ==\n"; -$r = mb_stripos($euc_jp, 'ܸ', 40, 'EUC-JP'); +$r = mb_stripos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", 40, 'EUC-JP'); ($r === FALSE) ? print "OK_OUT_RANGE\n" : print "NG_OUT_RANGE\n"; $r = mb_stripos($euc_jp, '0', 40, 'EUC-JP'); ($r === FALSE) ? print "OK_OUT_RANGE\n" : print "NG_OUT_RANGE\n"; @@ -52,7 +51,7 @@ $r = mb_stripos($euc_jp, 3, 40, 'EUC-JP'); ($r === FALSE) ? print "OK_OUT_RANGE\n" : print "NG_OUT_RANGE\n"; $r = mb_stripos($euc_jp, 0, 40, 'EUC-JP'); ($r === FALSE) ? print "OK_OUT_RANGE\n" : print "NG_OUT_RANGE\n"; -$r = mb_stripos($euc_jp, 'ܸ', -3, 'EUC-JP'); +$r = mb_stripos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", -3, 'EUC-JP'); ($r === FALSE) ? print "OK_OUT_RANGE\n" : print "NG_OUT_RANGE\n"; $r = mb_stripos($euc_jp, '0', -3, 'EUC-JP'); ($r === FALSE) ? print "OK_OUT_RANGE\n" : print "NG_OUT_RANGE\n"; @@ -65,7 +64,7 @@ $r = mb_stripos($euc_jp, 0, -3, 'EUC-JP'); // Non-existent echo "== NON-EXISTENT ==\n"; -$r = mb_stripos($euc_jp, 'ڹ', 0, 'EUC-JP'); +$r = mb_stripos($euc_jp, "\xB4\xDA\xB9\xF1\xB8\xEC", 0, 'EUC-JP'); ($r === FALSE) ? print "OK_STR\n" : print "NG_STR\n"; $r = mb_stripos($euc_jp, "\n", 0, 'EUC-JP'); ($r === FALSE) ? print "OK_NEWLINE\n" : print "NG_NEWLINE\n"; @@ -76,12 +75,12 @@ echo "== NO ENCODING PARAMETER ==\n"; mb_internal_encoding('EUC-JP') or print("mb_internal_encoding() failed\n"); -print mb_stripos($euc_jp, 'ܸ', 0) . "\n"; +print mb_stripos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", 0) . "\n"; print mb_stripos($euc_jp, '0', 0) . "\n"; print mb_stripos($euc_jp, 3, 0) . "\n"; print mb_stripos($euc_jp, 0, 0) . "\n"; -$r = mb_stripos($euc_jp, 'ڹ', 0); +$r = mb_stripos($euc_jp, "\xB4\xDA\xB9\xF1\xB8\xEC", 0); ($r === FALSE) ? print "OK_STR\n" : print "NG_STR\n"; $r = mb_stripos($euc_jp, "\n", 0); ($r === FALSE) ? print "OK_NEWLINE\n" : print "NG_NEWLINE\n"; @@ -91,16 +90,32 @@ echo "== NO OFFSET AND ENCODING PARAMETER ==\n"; mb_internal_encoding('EUC-JP') or print("mb_internal_encoding() failed\n"); -print mb_stripos($euc_jp, 'ܸ') . "\n"; +print mb_stripos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC") . "\n"; print mb_stripos($euc_jp, '0') . "\n"; print mb_stripos($euc_jp, 3) . "\n"; print mb_stripos($euc_jp, 0) . "\n"; -$r = mb_stripos($euc_jp, 'ڹ'); +$r = mb_stripos($euc_jp, "\xB4\xDA\xB9\xF1\xB8\xEC"); ($r === FALSE) ? print "OK_STR\n" : print "NG_STR\n"; $r = mb_stripos($euc_jp, "\n"); ($r === FALSE) ? print "OK_NEWLINE\n" : print "NG_NEWLINE\n"; +echo "== INVALID STRINGS ==\n"; + +// Previously, mb_stripos would internally convert invalid byte sequences to the +// mb_substitute_char BEFORE performing search +// So invalid byte sequences would match the substitute char, both from haystack +// to needle and needle to haystack + +mb_substitute_character(0x25); // '%' +var_dump(mb_stripos("abc%%", "\xFF", 0, "UTF-8")); // should be false +var_dump(mb_stripos("abc\xFF", "%", 0, "UTF-8")); // should be false + +// However, invalid byte sequences can still match invalid byte sequences: +var_dump(mb_stripos("abc\x80\x80", "\xFF", 0, "UTF-8")); +var_dump(mb_stripos("abc\xFF", "c\x80", 0, "UTF-8")); + + ?> --EXPECT-- String len: 43 @@ -145,3 +160,8 @@ OK_NEWLINE 0 OK_STR OK_NEWLINE +== INVALID STRINGS == +bool(false) +bool(false) +int(3) +int(2) diff --git a/ext/mbstring/tests/mb_strlen.phpt b/ext/mbstring/tests/mb_strlen.phpt index 11225917140c2..b3fb28309bcbe 100644 --- a/ext/mbstring/tests/mb_strlen.phpt +++ b/ext/mbstring/tests/mb_strlen.phpt @@ -13,43 +13,75 @@ include_once('common.inc'); mb_detect_order('auto'); // Test string -$euc_jp = '0123ʸܸǤEUC-JPȤäƤޤ0123ܸݽ'; +$euc_jp = mb_convert_encoding("0123この文字列は日本語です。EUC-JPを使っています。0123日本語は面倒臭い。", 'EUC-JP', 'UTF-8'); $ascii = 'abcdefghijklmnopqrstuvwxyz;]=#0123456789'; -// ASCII echo "== ASCII ==\n"; -print mb_strlen($ascii,'ASCII') . "\n"; -print strlen($ascii) . "\n"; +print mb_strlen($ascii,'ASCII') . "\n"; +print strlen($ascii) . "\n"; -// EUC-JP echo "== EUC-JP ==\n"; -print mb_strlen($euc_jp,'EUC-JP') . "\n"; +print mb_strlen($euc_jp,'EUC-JP') . "\n"; mb_internal_encoding('EUC-JP') or print("mb_internal_encoding() failed\n"); -print strlen($euc_jp) . "\n"; +print strlen($euc_jp) . "\n"; -// SJIS echo "== SJIS ==\n"; $sjis = mb_convert_encoding($euc_jp, 'SJIS','EUC-JP'); -print mb_strlen($sjis,'SJIS') . "\n"; +print mb_strlen($sjis,'SJIS') . "\n"; mb_internal_encoding('SJIS') or print("mb_internal_encoding() failed\n"); -print strlen($sjis) . "\n"; +print strlen($sjis) . "\n"; +print "-- Testing illegal bytes 0x80,0xFD-FF --\n"; +// mb_strlen used to wrongly treat 0x80 as the starting byte of a 2-byte SJIS character +print mb_strlen("\x80\xA1", 'SJIS') . "\n"; +print mb_strlen("abc\xFD\xFE\xFF", 'SJIS') . "\n"; + +echo "== MacJapanese ==\n"; +print mb_strlen("\x80\xA1", 'MacJapanese') . "\n"; +print mb_strlen("abc\xFD\xFE\xFF", 'MacJapanese') . "\n"; + +echo "== SJIS-2004 ==\n"; +print mb_strlen("\x80\xA1", 'SJIS-2004') . "\n"; +print mb_strlen("abc\xFD\xFE\xFF", 'SJIS-2004') . "\n"; + +echo "== SJIS-Mobile#DOCOMO ==\n"; +print mb_strlen("\x80\xA1", 'SJIS-Mobile#DOCOMO') . "\n"; +print mb_strlen("abc\xFD\xFE\xFF", 'SJIS-Mobile#DOCOMO') . "\n"; + +echo "== SJIS-Mobile#KDDI ==\n"; +print mb_strlen("\x80\xA1", 'SJIS-Mobile#KDDI') . "\n"; +print mb_strlen("abc\xFD\xFE\xFF", 'SJIS-Mobile#KDDI') . "\n"; + +echo "== SJIS-Mobile#SoftBank ==\n"; +print mb_strlen("\x80\xA1", 'SJIS-Mobile#SoftBank') . "\n"; +print mb_strlen("abc\xFD\xFE\xFF", 'SJIS-Mobile#SoftBank') . "\n"; -// JIS -// Note: either convert_encoding or strlen has problem echo "== JIS ==\n"; $jis = mb_convert_encoding($euc_jp, 'JIS','EUC-JP'); -print mb_strlen($jis,'JIS') . "\n"; +print mb_strlen($jis,'JIS') . "\n"; mb_internal_encoding('JIS') or print("mb_internal_encoding() failed\n"); -print strlen($jis) . "\n"; +print strlen($jis) . "\n"; -// UTF-8 -// Note: either convert_encoding or strlen has problem echo "== UTF-8 ==\n"; -$utf8 = mb_convert_encoding($euc_jp, 'UTF-8','EUC-JP'); -print mb_strlen($utf8,'UTF-8') . "\n"; -mb_internal_encoding('UTF-8') or print("mb_internal_encoding() failed\n"); -print strlen($utf8) . "\n"; +$utf8 = mb_convert_encoding($euc_jp, 'UTF-8', 'EUC-JP'); +print mb_strlen($utf8,'UTF-8') . " codepoints\n"; +mb_internal_encoding('UTF-8') or print("mb_internal_encoding() failed\n"); +print strlen($utf8) . " bytes\n"; + +$utf8 = "abcde あいうえお 汉字 ελληνικά"; +$long_utf8 = str_repeat($utf8, 100); +print mb_strlen($utf8, 'UTF-8') . "\n"; +print mb_strlen($long_utf8, 'UTF-8') . "\n"; +echo "== UTF-8 with performance optimizations ==\n"; +// Optimized mb_strlen can be used on UTF-8 strings after they are checked for validity +mb_check_encoding($utf8); +mb_check_encoding($long_utf8); +print mb_strlen($utf8, 'UTF-8') . "\n"; +print mb_strlen($long_utf8, 'UTF-8') . "\n"; + +$str = str_repeat('Σ', 2048); // 2-byte UTF-8 character +mb_check_encoding($str, 'UTF-8'); +print mb_strlen($str, 'UTF-8') . "\n"; // Wrong Parameters echo "== WRONG PARAMETERS ==\n"; @@ -72,11 +104,35 @@ try { == SJIS == 43 72 +-- Testing illegal bytes 0x80,0xFD-FF -- +2 +6 +== MacJapanese == +2 +7 +== SJIS-2004 == +2 +6 +== SJIS-Mobile#DOCOMO == +2 +6 +== SJIS-Mobile#KDDI == +2 +6 +== SJIS-Mobile#SoftBank == +2 +6 == JIS == 43 90 == UTF-8 == -43 -101 +43 codepoints +101 bytes +23 +2300 +== UTF-8 with performance optimizations == +23 +2300 +2048 == WRONG PARAMETERS == mb_strlen(): Argument #2 ($encoding) must be a valid encoding, "BAD_NAME" given diff --git a/ext/mbstring/tests/mb_strpos.phpt b/ext/mbstring/tests/mb_strpos.phpt index 2b9e13543942e..f0f16a806e7b3 100644 --- a/ext/mbstring/tests/mb_strpos.phpt +++ b/ext/mbstring/tests/mb_strpos.phpt @@ -11,7 +11,7 @@ include_once('common.inc'); // Test string -$euc_jp = '0123ʸܸǤEUC-JPȤäƤޤ0123ܸݽ'; +$euc_jp = "0123\xA4\xB3\xA4\xCE\xCA\xB8\xBB\xFA\xCE\xF3\xA4\xCF\xC6\xFC\xCB\xDC\xB8\xEC\xA4\xC7\xA4\xB9\xA1\xA3EUC-JP\xA4\xF2\xBB\xC8\xA4\xC3\xA4\xC6\xA4\xA4\xA4\xDE\xA4\xB9\xA1\xA30123\xC6\xFC\xCB\xDC\xB8\xEC\xA4\xCF\xCC\xCC\xC5\xDD\xBD\xAD\xA4\xA4\xA1\xA3"; $slen = mb_strlen($euc_jp, 'EUC-JP'); echo "String len: $slen\n"; @@ -21,11 +21,11 @@ mb_internal_encoding('UTF-8') or print("mb_internal_encoding() failed\n"); echo "== POSITIVE OFFSET ==\n"; -print mb_strpos($euc_jp, 'ܸ', 0, 'EUC-JP') . "\n"; +print mb_strpos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", 0, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, '0', 0, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, 3, 0, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, 0, 0, 'EUC-JP') . "\n"; -print mb_strpos($euc_jp, 'ܸ', 15, 'EUC-JP') . "\n"; +print mb_strpos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", 15, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, '0', 15, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, 3, 15, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, 0, 15, 'EUC-JP') . "\n"; @@ -34,7 +34,7 @@ print mb_strpos($euc_jp, 0, 15, 'EUC-JP') . "\n"; // Negative offset echo "== NEGATIVE OFFSET ==\n"; -print mb_strpos($euc_jp, 'ܸ', -15, 'EUC-JP') . "\n"; +print mb_strpos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", -15, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, '0', -15, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, 3, -15, 'EUC-JP') . "\n"; print mb_strpos($euc_jp, 0, -15, 'EUC-JP') . "\n"; @@ -44,7 +44,7 @@ print mb_strpos($euc_jp, 0, -43, 'EUC-JP') . "\n"; // Non-existent echo "== NON-EXISTENT ==\n"; -$r = mb_strpos($euc_jp, 'ڹ', 0, 'EUC-JP'); +$r = mb_strpos($euc_jp, "\xB4\xDA\xB9\xF1\xB8\xEC", 0, 'EUC-JP'); ($r === FALSE) ? print "OK_STR\n" : print "NG_STR\n"; $r = mb_strpos($euc_jp, "\n", 0, 'EUC-JP'); ($r === FALSE) ? print "OK_NEWLINE\n" : print "NG_NEWLINE\n"; @@ -55,12 +55,12 @@ echo "== NO ENCODING PARAMETER ==\n"; mb_internal_encoding('EUC-JP') or print("mb_internal_encoding() failed\n"); -print mb_strpos($euc_jp, 'ܸ', 0) . "\n"; +print mb_strpos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC", 0) . "\n"; print mb_strpos($euc_jp, '0', 0) . "\n"; print mb_strpos($euc_jp, 3, 0) . "\n"; print mb_strpos($euc_jp, 0, 0) . "\n"; -$r = mb_strpos($euc_jp, 'ڹ', 0); +$r = mb_strpos($euc_jp, "\xB4\xDA\xB9\xF1\xB8\xEC", 0); ($r === FALSE) ? print "OK_STR\n" : print "NG_STR\n"; $r = mb_strpos($euc_jp, "\n", 0); ($r === FALSE) ? print "OK_NEWLINE\n" : print "NG_NEWLINE\n"; @@ -70,16 +70,39 @@ echo "== NO OFFSET AND ENCODING PARAMETER ==\n"; mb_internal_encoding('EUC-JP') or print("mb_internal_encoding() failed\n"); -print mb_strpos($euc_jp, 'ܸ') . "\n"; +print mb_strpos($euc_jp, "\xC6\xFC\xCB\xDC\xB8\xEC") . "\n"; print mb_strpos($euc_jp, '0') . "\n"; print mb_strpos($euc_jp, 3) . "\n"; print mb_strpos($euc_jp, 0) . "\n"; -$r = mb_strpos($euc_jp, 'ڹ'); +$r = mb_strpos($euc_jp, "\xB4\xDA\xB9\xF1\xB8\xEC"); ($r === FALSE) ? print "OK_STR\n" : print "NG_STR\n"; $r = mb_strpos($euc_jp, "\n"); ($r === FALSE) ? print "OK_NEWLINE\n" : print "NG_NEWLINE\n"; +echo "== INVALID STRINGS ==\n"; + +// Previously, mb_strpos would internally convert invalid byte sequences to '?' +// BEFORE performing search +// (This was regardless of the setting of mb_substitute_char) +// So invalid byte sequences would match '?', both from haystack to needle +// and needle to haystack + +var_dump(mb_strpos("abc??", "\xFF", 0, "UTF-8")); // should be false +var_dump(mb_strpos("abc\xFF", "?", 0, "UTF-8")); // should be false + +// However, invalid byte sequences can still match other invalid byte +// sequences for non-UTF-8 encodings only: +var_dump(mb_strpos("\x00a\x00b\x00c\xDF\xFF", "\xDB\x00", 0, "UTF-16BE")); + +// For UTF-8, invalid byte sequences match the exact same invalid sequence, +// but not a different one +var_dump(mb_strpos("abc\x80\x80", "\xFF", 0, "UTF-8")); // should be false +var_dump(mb_strpos("abc\xFF", "c\x80", 0, "UTF-8")); // should be false + +var_dump(mb_strpos("abc\x80\x80", "\x80", 0, "UTF-8")); +var_dump(mb_strpos("abc\xFF", "c\xFF", 0, "UTF-8")); + ?> --EXPECT-- String len: 43 @@ -115,3 +138,11 @@ OK_NEWLINE 0 OK_STR OK_NEWLINE +== INVALID STRINGS == +bool(false) +bool(false) +int(3) +bool(false) +bool(false) +int(3) +int(2) diff --git a/ext/mbstring/tests/mb_strstr.phpt b/ext/mbstring/tests/mb_strstr.phpt index 08fc966cd48d6..4cdbb3df24839 100644 --- a/ext/mbstring/tests/mb_strstr.phpt +++ b/ext/mbstring/tests/mb_strstr.phpt @@ -37,4 +37,4 @@ string(18) "おかきくけこ" string(18) "おかきくけこ" string(12) "あいうえ" string(4) "dd00" -string(0) "" +string(2) "00" diff --git a/ext/mbstring/tests/mb_strtolower_basic.phpt b/ext/mbstring/tests/mb_strtolower_basic.phpt index debb42cd9ed74..10b3282d33c99 100644 --- a/ext/mbstring/tests/mb_strtolower_basic.phpt +++ b/ext/mbstring/tests/mb_strtolower_basic.phpt @@ -35,6 +35,33 @@ if ($mb == $greek_lower) { echo "Incorrectly converted\n"; } +echo "\n-- Greek letter sigma --\n"; +var_dump(mb_strtolower("Σ", 'UTF-8')); +var_dump(mb_strtolower("aΣ", 'UTF-8')); +var_dump(mb_strtolower("aΣb", 'UTF-8')); +var_dump(mb_strtolower("aΣ b", 'UTF-8')); +var_dump(mb_strtolower(" ΣΣΣΣ ", 'UTF-8')); + +// Apostrophe, full stop, colon, etc. are "case-ignorable" +// When checking whether capital sigma is at the end of a word or not, we skip over +// any number of case-ignorable characters, both when scanning back and when scanning forward +var_dump(mb_strtolower("'Σ", 'UTF-8')); +var_dump(mb_strtolower("ab'Σ", 'UTF-8')); +var_dump(mb_strtolower("Σ'", 'UTF-8')); +var_dump(mb_strtolower("Σ'a", 'UTF-8')); +var_dump(mb_strtolower("a'Σ'a", 'UTF-8')); + +// We scan back by at least 63 characters when necessary, +// but there is no guarantee that we will scan back further than that +var_dump(mb_strtolower('a' . str_repeat('.', 63) . "Σ", 'UTF-8')); +var_dump(mb_strtolower('a' . str_repeat('.', 64) . "Σ", 'UTF-8')); // Context-sensitive casing doesn't work here! + +// When scanning forward to confirm if capital sigma is at the end of a word or not, +// there is no limit as to how far we will scan +var_dump(mb_strtolower("abcΣ" . str_repeat('.', 64) . ' abc', 'UTF-8')); +var_dump(mb_strtolower("abcΣ" . str_repeat('.', 64) . 'a abc', 'UTF-8')); +var_dump(mb_strtolower("abcΣ" . str_repeat('.', 256) . ' abc', 'UTF-8')); + echo "Done"; ?> --EXPECT-- @@ -47,4 +74,21 @@ Correctly converted -- Multibyte String -- string(64) "zrHOss6zzrTOtc62zrfOuM65zrrOu868zr3Ovs6/z4DPgc+Dz4TPhc+Gz4fPiM+J" Correctly converted + +-- Greek letter sigma -- +string(2) "σ" +string(3) "aς" +string(4) "aσb" +string(5) "aς b" +string(10) " σσσς " +string(3) "'σ" +string(5) "ab'ς" +string(3) "σ'" +string(4) "σ'a" +string(6) "a'σ'a" +string(66) "a...............................................................ς" +string(67) "a................................................................σ" +string(73) "abcς................................................................ abc" +string(74) "abcσ................................................................a abc" +string(265) "abcς................................................................................................................................................................................................................................................................ abc" Done diff --git a/ext/mbstring/tests/mb_substitute_character_variation_strict_types.phpt b/ext/mbstring/tests/mb_substitute_character_variation_strict_types.phpt index 2025941e0e77b..9526528a1851a 100644 --- a/ext/mbstring/tests/mb_substitute_character_variation_strict_types.phpt +++ b/ext/mbstring/tests/mb_substitute_character_variation_strict_types.phpt @@ -139,13 +139,13 @@ int(12345) --lowercase null-- int(12345) --lowercase true-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, bool given +TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, true given --lowercase false-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, bool given +TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, false given --uppercase TRUE-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, bool given +TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, true given --uppercase FALSE-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, bool given +TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, false given --empty string DQ-- ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint --empty string SQ-- diff --git a/ext/mbstring/tests/mb_substr.phpt b/ext/mbstring/tests/mb_substr.phpt index 1d0fa7e48d33c..ef37ca6dc192a 100644 --- a/ext/mbstring/tests/mb_substr.phpt +++ b/ext/mbstring/tests/mb_substr.phpt @@ -8,13 +8,13 @@ ini_set('include_path','.'); include_once('common.inc'); // EUC-JP -$euc_jp = "0123\xA4\xB3\xA4\xCE\xCA\xB8\xBB\xFA\xCE\xF3\xA4\xCF\xC6\xFC\xCB\xDC\xB8\xEC\xA4\xC7\xA4\xB9\xA1\xA3EUC-JP\xA4\xF2\xBB\xC8\xA4\xC3\xA4\xC6\xA4\xA4\xA4\xDE\xA4\xB9\xA1\xA3\xC6\xFC\xCB\xDC\xB8\xEC\xA4\xCF\xCC\xCC\xC5\xDD\xBD\xAD\xA4\xA4\xA1\xA3"; +$euc_jp = mb_convert_encoding('0123この文字列は日本語です。EUC-JPを使っています。日本語は面倒臭い。', 'EUC-JP', 'UTF-8'); // SJIS -$sjis = "\x93\xFA\x96{\x8C\xEA\x83e\x83L\x83X\x83g\x82\xC5\x82\xB7\x81B01234\x82T\x82U\x82V\x82W\x82X\x81B"; +$sjis = mb_convert_encoding('日本語テキストです。0123456789。', 'SJIS', 'UTF-8'); // ISO-2022-JP $iso2022jp = "\x1B\$B\x21\x21!r\x1B(BABC"; // GB-18030 -$gb18030 = "\xC3\xDC\xC2\xEB\xD3\xC3\xBB\xA7\xC3\xFB\xC3\xDC\xC2\xEB\xC3\xFB\xB3\xC6\xC3\xFB\xB3\xC6"; +$gb18030 = mb_convert_encoding('密码用户名密码名称名称', 'GB18030', 'UTF-8'); // HZ $hz = "The next sentence is in GB.~{<:Ky2;S{#,NpJ)l6HK!#~}Bye."; // UTF-8 @@ -40,6 +40,39 @@ print "2: " . bin2hex(mb_substr($sjis, -1, null, 'SJIS')) . "\n"; print "3: " . bin2hex(mb_substr($sjis, -5, 3, 'SJIS')) . "\n"; print "4: " . bin2hex(mb_substr($sjis, 1, null, 'SJIS')) . "\n"; print "5:" . bin2hex(mb_substr($sjis, 10, 0, 'SJIS')) . "\n"; +echo "-- Testing illegal SJIS byte 0x80 --\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 3, 2, 'SJIS')) . "\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 0, 3, 'SJIS')) . "\n"; + +echo "SJIS-2004:\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 3, 2, 'SJIS-2004')) . "\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 0, 3, 'SJIS-2004')) . "\n"; + +echo "MacJapanese:\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 3, 2, 'MacJapanese')) . "\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 0, 3, 'MacJapanese')) . "\n"; + +echo "SJIS-Mobile#DOCOMO:\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 3, 2, 'SJIS-Mobile#DOCOMO')) . "\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 0, 3, 'SJIS-Mobile#DOCOMO')) . "\n"; + +echo "SJIS-Mobile#KDDI:\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 3, 2, 'SJIS-Mobile#KDDI')) . "\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 0, 3, 'SJIS-Mobile#KDDI')) . "\n"; + +echo "SJIS-Mobile#SoftBank:\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 3, 2, 'SJIS-Mobile#SoftBank')) . "\n"; +print bin2hex(mb_substr("\x80abc\x80\xA1", 0, 3, 'SJIS-Mobile#SoftBank')) . "\n"; + +echo "-- Testing MacJapanese characters which map to 3-5 codepoints each --\n"; + +/* There are many characters in MacJapanese which map to sequences of several codepoints */ +print bin2hex(mb_substr("abc\x85\xAB\x85\xAC\x85\xAD", 0, 3, 'MacJapanese')) . "\n"; +print bin2hex(mb_substr("abc\x85\xAB\x85\xAC\x85\xAD", 3, 2, 'MacJapanese')) . "\n"; +print bin2hex(mb_substr("abc\x85\xAB\x85\xAC\x85\xAD", -2, 1, 'MacJapanese')) . "\n"; +print bin2hex(mb_substr("abc\x85\xBF\x85\xC0\x85\xC1", 0, 3, 'MacJapanese')) . "\n"; +print bin2hex(mb_substr("abc\x85\xBF\x85\xC0\x85\xC1", 3, 2, 'MacJapanese')) . "\n"; +print bin2hex(mb_substr("abc\x85\xBF\x85\xC0\x85\xC1", -2, 1, 'MacJapanese')) . "\n"; echo "ISO-2022-JP:\n"; print "1: " . bin2hex(mb_substr($iso2022jp, 0, 3, 'ISO-2022-JP')) . "\n"; @@ -104,6 +137,31 @@ SJIS: 3: 825582568257 4: 967b8cea8365834c8358836782c582b781423031323334825482558256825782588142 5: +-- Testing illegal SJIS byte 0x80 -- +6380 +806162 +SJIS-2004: +6380 +806162 +MacJapanese: +6380 +806162 +SJIS-Mobile#DOCOMO: +6380 +806162 +SJIS-Mobile#KDDI: +6380 +806162 +SJIS-Mobile#SoftBank: +6380 +806162 +-- Testing MacJapanese characters which map to 3-5 codepoints each -- +616263 +85ab85ac +85ac +616263 +85bf85c0 +85c0 ISO-2022-JP: 1: 1b2442212121721b284241 2: 43 diff --git a/ext/mbstring/tests/mb_substr_count.phpt b/ext/mbstring/tests/mb_substr_count.phpt index 0ccaa4e420eeb..2927419930b39 100644 --- a/ext/mbstring/tests/mb_substr_count.phpt +++ b/ext/mbstring/tests/mb_substr_count.phpt @@ -7,6 +7,8 @@ output_handler= --FILE-- getMessage() . \PHP_EOL; } + try { + // Although the needle below contains 3 bytes, it decodes to zero Unicode codepoints + // So the needle is actually 'empty', although it doesn't appear so + var_dump(mb_substr_count("abcdef", "\x1B(B", "ISO-2022-JP")); + } catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; + } - var_dump(mb_substr_count("", "")); - var_dump(mb_substr_count("", "")); + print "== Return value for empty haystack should always be zero ==\n"; + var_dump(mb_substr_count("", "\xA4\xA2")); var_dump(mb_substr_count("", chr(0))); + print "== Try searching using various encodings ==\n"; $a = str_repeat("abcacba", 100); - var_dump(@mb_substr_count($a, "bca")); + var_dump(mb_substr_count($a, "bca")); - $a = str_repeat("", 100); - $b = ""; - var_dump(@mb_substr_count($a, $b)); + $a = str_repeat("\xA4\xA2\xA4\xA4\xA4\xA6\xA4\xA2\xA4\xA6\xA4\xA4\xA4\xA2", 100); + $b = "\xA4\xA4\xA4\xA6\xA4\xA2"; + var_dump(mb_substr_count($a, $b)); $to_enc = "UTF-8"; - var_dump(@mb_substr_count(mb_convert_encoding($a, $to_enc), + var_dump(mb_substr_count(mb_convert_encoding($a, $to_enc), mb_convert_encoding($b, $to_enc), $to_enc)); $to_enc = "Shift_JIS"; - var_dump(@mb_substr_count(mb_convert_encoding($a, $to_enc), + var_dump(mb_substr_count(mb_convert_encoding($a, $to_enc), mb_convert_encoding($b, $to_enc), $to_enc)); $a = str_repeat("abcacbabca", 100); - var_dump(@mb_substr_count($a, "bca")); + var_dump(mb_substr_count($a, "bca")); + + print "== Regression tests ==\n"; + + // The old implementation had a bug; it could only recognize a maximum of one + // match for each byte that it fed into the decoder, even if feeding in that + // byte caused two codepoints to be emitted (because the decoder was holding + // cached data), and both of those codepoints matched a 1-codepoint needle + // (For this example, two error markers are emitted for the final byte 0xFF) + echo mb_substr_count("\xef\xff", "\xf8", "UTF-8"), "\n"; + + // Another thing about the old implementation: if a final codepoint was emitted + // by a decoder flush function, and that codepoint finished a match with the + // needle, that match would be disregarded and not counted in the returned value + // (In practice, the only thing emitted from decoder flush functions is an error + // marker, if the string ended in an illegal state) + echo mb_substr_count("+", "+", "UTF7-IMAP"), "\n"; + ?> --EXPECT-- +== Empty needle should raise an error == mb_substr_count(): Argument #2 ($needle) must not be empty mb_substr_count(): Argument #2 ($needle) must not be empty +mb_substr_count(): Argument #2 ($needle) must not be empty +== Return value for empty haystack should always be zero == int(0) int(0) -int(0) +== Try searching using various encodings == int(100) int(100) int(100) int(100) int(200) +== Regression tests == +2 +1 diff --git a/ext/mbstring/tests/utf_encodings.phpt b/ext/mbstring/tests/utf_encodings.phpt index 2f050c657c2f3..06c35b1546521 100644 --- a/ext/mbstring/tests/utf_encodings.phpt +++ b/ext/mbstring/tests/utf_encodings.phpt @@ -813,6 +813,20 @@ $invalid = array( testInvalidCodepoints($invalid, 'UTF-8'); +// Regression test for bug in SSE2-based accelerated UTF-8 validation function +$truncated16byte = [ + "k\x08`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6", + "k\x08`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef", + "k\x08`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xbf", + "k\x08`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0", + "k\x08`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xbf", + "k\x08`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xbf\xbf" +]; +foreach ($truncated16byte as $trunc) { + if (mb_check_encoding($trunc, 'UTF-8')) + die("UTF-8 validation was incorrect on 16-byte string with truncated multi-byte char at end"); +} + echo "== UTF-16 ==\n"; testValidCodepoints("UTF-16"); @@ -881,6 +895,17 @@ testValidString("\xDC\x00", "\x00\xDC", 'UCS-2BE', 'UTF-16LE', false); convertInvalidString("\x00\x11\x56\x78", "\x00%", 'UCS-4BE', 'UTF-16BE'); convertInvalidString("\x00\x11\x56\x78", "%\x00", 'UCS-4BE', 'UTF-16LE'); +// Regression tests for bugs with initial AVX2-accelerated implementation +convertInvalidString(str_repeat("a\x00", 15) . "\x00\xD8\x00\xFC", str_repeat("\x00a", 15) . "\x00%\xFC\x00", 'UTF-16LE', 'UCS-2BE'); +convertInvalidString(str_repeat("\x00a", 15) . "\xD8\x00\xFC\x00", str_repeat("\x00a", 15) . "\x00%\xFC\x00", 'UTF-16BE', 'UCS-2BE'); + +// This string caused an out-of-bounds read; it was found by a fuzzer +$str = "\xdb\xdb\xdb#\xdb\xdb\xdf\xdb\xdf\xdb\xdb\x0b\xdb\x00\xdc\xdb\xdf\xdb\xdf\xdb\xda\x0b\xdb\x00\xdcY\xdf\x03\xdb\x03\xd9\xd9\xd8"; +convertInvalidString($str, "\x00\x25\x00\x25\xdb\xdb\xdf\xdb\x00\x25\x00\x25\xdb\x00\xdc\xdb\x00\x25\x00\x25\x00\x25\xdb\x00\xdc\x59\x00\x25\x00\x25\x00\x25\x00\x25", 'UTF-16BE', 'UTF-16BE'); + +$str = "\xda\xda\xda\xda\xda\xda\xd9\xdb\xda\xda\xda\xda\xdd\xda\xda\xd9\xdb\xda\xda\xda\xda\xdd\xda\xdd\xd9\x0a\xda\xda\xda\xda\xdd\xda\xdd\xd9\xda\xda\xda\xda\xda\xda\xda\xda\xda\xd9\xdb\xda\xda\xda\xd9\xdb\xda\xda\xda\xda\xdd\xda\xda\xd9\xdb"; +convertInvalidString($str, "\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\xda\xda\xda\xdd\x25\x00\xd9\x0a\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00\x25\x00", 'UTF-16LE', 'UTF-16LE'); + echo "== UTF-32 ==\n"; testValidCodepoints("UTF-32LE"); @@ -1011,17 +1036,8 @@ testValidString('+' . encode('AB', 'ASCII') . '-+' . encode('CD', 'ASCII') . '-' // (Just trying to be exhaustive here) testValidString('+' . encode('AB', 'ASCII') . '-!+' . encode('CD', 'ASCII') . '-', "\x00A\x00B\x00!\x00C\x00D", 'UTF-7', 'UTF-16BE', false); -// + section terminated by a non-Base64 ASCII character which is NOT - -for ($i = 0; $i < 128; $i++) { - if ($i >= ord('A') && $i <= ord('Z')) - continue; - if ($i >= ord('a') && $i <= ord('z')) - continue; - if ($i >= ord('0') && $i <= ord('9')) - continue; - if ($i == ord('+') || $i == ord('/') || $i == ord('-') || $i == ord('\\') || $i == ord('~')) - continue; - $char = chr($i); +// + section terminated by a non-Base64 direct character which is NOT - +foreach (str_split(" \t\r\n'(),.:?!\"#$%&*;<=>@[]^_`{|}\x00") as $char) { testValidString('+' . encode("\x12\x34", 'UTF-16BE') . $char, "\x00\x00\x12\x34\x00\x00\x00" . $char, 'UTF-7', 'UTF-32BE', false); } @@ -1058,6 +1074,9 @@ testInvalidString('+' . rawEncode("\x00.\x00.\xD8\x01\xD9\x02") . '-', "\x00\x00 // First half of surrogate pair appearing at end of string testInvalidString('+' . rawEncode("\xD8\x01") . '-', "\x00\x00\x00%", 'UTF-7', 'UTF-32BE'); testInvalidString('+' . rawEncode("\xD8\x01"), "\x00\x00\x00%", 'UTF-7', 'UTF-32BE'); +testInvalidString("+999999uJ", "\xEF\x9F\x9F\xE7\xB7\xB7%", 'UTF-7', 'UTF-8'); +testInvalidString("+999euJ", "\xEF\x9F\x9F\xE5\xBA\xB8%", "UTF-7", "UTF-8"); +testInvalidString("+euJ", "\xE7\xAB\xA2%", "UTF-7", "UTF-8"); // Truncated string testInvalidString('+' . rawEncode("\x01") . '-', "\x00\x00\x00%", 'UTF-7', 'UTF-32BE'); diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index b42226a13f96c..f98ab2fc15f46 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -805,8 +805,7 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags zend_call_known_function(ce->constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), /* retval */ NULL, /* argc */ 0, /* params */ NULL, ctor_params); } else if (ctor_params && zend_hash_num_elements(ctor_params) > 0) { - /* TODO Convert this to a ValueError */ - zend_argument_error(zend_ce_exception, ERROR_ARG_POS(3), + zend_argument_value_error(ERROR_ARG_POS(3), "must be empty when the specified class (%s) does not have a constructor", ZSTR_VAL(ce->name) ); diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 99fb0154b4bfa..68b55e1d78d35 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -91,7 +91,7 @@ int mysqli_stmt_bind_param_do_bind(MY_STMT *stmt, unsigned int num_vars, zval *a goto end; } for (i = 0; i < num_vars; i++) { - zend_uchar type; + uint8_t type; switch (types[i]) { case 'd': /* Double */ type = MYSQL_TYPE_DOUBLE; @@ -1799,11 +1799,11 @@ PHP_FUNCTION(mysqli_stmt_attr_get) "MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, " "MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE"); RETURN_THROWS(); - } - + } if (attr == STMT_ATTR_UPDATE_MAX_LENGTH) - value = *((my_bool *)&value); + value = (my_bool)value; + RETURN_LONG((unsigned long)value); } /* }}} */ diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index bb8a130c41f65..406d928699784 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -650,7 +650,7 @@ static int mysqlnd_zval_array_to_mysqlnd_array(zval *in_array, MYSQLND ***out_ar i++; if (Z_TYPE_P(elem) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(elem), mysqli_link_class_entry)) { - zend_argument_type_error(i, "must be an instance of mysqli, %s given", zend_zval_type_name(elem)); + zend_argument_type_error(i, "must be an instance of mysqli, %s given", zend_zval_value_name(elem)); return FAILURE; } else { MY_MYSQL *mysql; @@ -673,12 +673,11 @@ static int mysqlnd_zval_array_to_mysqlnd_array(zval *in_array, MYSQLND ***out_ar /* }}} */ /* {{{ mysqlnd_zval_array_from_mysqlnd_array */ -static int mysqlnd_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *out_array) +static zend_result mysqlnd_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *out_array) { MYSQLND **p = in_array; zval dest_array; zval *elem, *dest_elem; - int ret = 0; array_init_size(&dest_array, zend_hash_num_elements(Z_ARRVAL_P(out_array))); @@ -701,7 +700,6 @@ static int mysqlnd_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *out_a if (dest_elem) { zval_add_ref(dest_elem); } - ret++; p++; } } @@ -711,16 +709,15 @@ static int mysqlnd_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *out_a zval_ptr_dtor(out_array); ZVAL_COPY_VALUE(out_array, &dest_array); - return 0; + return SUCCESS; } /* }}} */ /* {{{ mysqlnd_dont_poll_zval_array_from_mysqlnd_array */ -static int mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *in_zval_array, zval *out_array) +static void mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, zval *in_zval_array, zval *out_array) { MYSQLND **p = in_array; zval proxy, *elem, *dest_elem; - int ret = 0; array_init(&proxy); if (in_array) { @@ -733,7 +730,6 @@ static int mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, z if (dest_elem) { zval_add_ref(dest_elem); } - ret++; p++; } } ZEND_HASH_FOREACH_END(); @@ -742,8 +738,6 @@ static int mysqlnd_dont_poll_zval_array_from_mysqlnd_array(MYSQLND **in_array, z /* destroy old array and add new one */ zval_ptr_dtor(out_array); ZVAL_COPY_VALUE(out_array, &proxy); - - return 0; } /* }}} */ @@ -768,10 +762,9 @@ PHP_FUNCTION(mysqli_poll) RETURN_THROWS(); } - // TODO Error promotion if (!r_array && !e_array) { - php_error_docref(NULL, E_WARNING, "No stream arrays were passed"); - RETURN_FALSE; + zend_value_error("No stream arrays were passed"); + RETURN_THROWS(); } if (r_array != NULL) { diff --git a/ext/mysqli/mysqli_result_iterator.c b/ext/mysqli/mysqli_result_iterator.c index abd4930f55bd6..dff8d7c003ccf 100644 --- a/ext/mysqli/mysqli_result_iterator.c +++ b/ext/mysqli/mysqli_result_iterator.c @@ -120,7 +120,7 @@ static void php_mysqli_result_iterator_rewind(zend_object_iterator *iter) if (mysqli_result_is_unbuffered(result)) { if (result->unbuf->eof_reached) { - php_error_docref(NULL, E_WARNING, "Data fetched with MYSQLI_USE_RESULT can be iterated only once"); + zend_error(E_WARNING, "Data fetched with MYSQLI_USE_RESULT can be iterated only once"); return; } } else { diff --git a/ext/mysqli/tests/bug33491.phpt b/ext/mysqli/tests/bug33491.phpt index 89d6e67a21e19..0200222449e85 100644 --- a/ext/mysqli/tests/bug33491.phpt +++ b/ext/mysqli/tests/bug33491.phpt @@ -27,7 +27,7 @@ $DB->query_single('SELECT DATE()'); ?> --EXPECTF-- -Fatal error: Uncaught Error: Call to a member function fetch_row() on bool in %sbug33491.php:%d +Fatal error: Uncaught Error: Call to a member function fetch_row() on false in %sbug33491.php:%d Stack trace: #0 %s(%d): DB->query_single('SELECT DATE()') #1 {main} diff --git a/ext/mysqli/tests/bug62885.phpt b/ext/mysqli/tests/bug62885.phpt index 9674f8a5af00c..79ed0c6edde77 100644 --- a/ext/mysqli/tests/bug62885.phpt +++ b/ext/mysqli/tests/bug62885.phpt @@ -10,15 +10,23 @@ require_once("connect.inc"); getMessage() . \PHP_EOL; +} $test2 = array(); $test2 = array(); -$test1 = mysqli_poll($test2, $test3, $tablica, 0); +try { + $test1 = mysqli_poll($test2, $test3, $tablica, 0); +} catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; +} echo "okey"; ?> --EXPECTF-- -Warning: mysqli_poll(): No stream arrays were passed in %sbug62885.php on line %d +No stream arrays were passed -Warning: mysqli_poll(): No stream arrays were passed in %sbug62885.php on line %d +Warning: mysqli_poll(): No stream arrays were passed in %s on line %d okey diff --git a/ext/mysqli/tests/bug73462.phpt b/ext/mysqli/tests/bug73462.phpt index aa54dbbe5d5cc..a5ae94acffa80 100644 --- a/ext/mysqli/tests/bug73462.phpt +++ b/ext/mysqli/tests/bug73462.phpt @@ -11,14 +11,14 @@ require_once('skipifconnectfailure.inc'); require_once("connect.inc"); /* Initial persistent connection */ - $mysql_1 = new mysqli('p:'.$host, $user, $passwd, $db); + $mysql_1 = new mysqli('p:'.$host, $user, $passwd, $db, $port); $result = $mysql_1->query("SHOW STATUS LIKE 'Connections'"); $c1 = $result->fetch_row(); $result->free(); $mysql_1->close(); /* Failed connection to invalid host */ - $mysql_2 = @new mysqli(' !!! invalid !!! ', $user, $passwd, $db); + $mysql_2 = @new mysqli(' !!! invalid !!! ', $user, $passwd, $db, $port); try { $mysql_2->close(); } catch (Error $exception) { @@ -26,7 +26,7 @@ require_once('skipifconnectfailure.inc'); } /* Re-use persistent connection */ - $mysql_3 = new mysqli('p:'.$host, $user, $passwd, $db); + $mysql_3 = new mysqli('p:'.$host, $user, $passwd, $db, $port); $error = mysqli_connect_errno(); $result = $mysql_3->query("SHOW STATUS LIKE 'Connections'"); $c3 = $result->fetch_row(); diff --git a/ext/mysqli/tests/bug73949.phpt b/ext/mysqli/tests/bug73949.phpt index b706ab20e8819..7c5364c274730 100644 --- a/ext/mysqli/tests/bug73949.phpt +++ b/ext/mysqli/tests/bug73949.phpt @@ -14,7 +14,7 @@ class cc{ function __construct($c=null){ } }; -$i=mysqli_connect('p:'.$host, $user, $passwd, $db); +$i=mysqli_connect('p:'.$host, $user, $passwd, $db, $port); $res=mysqli_query($i, "SHOW STATUS LIKE 'Connections'"); $t=array(new stdClass); while($db= mysqli_fetch_object($res,'cc',$t)){} diff --git a/ext/mysqli/tests/mysqli_fetch_array_large.phpt b/ext/mysqli/tests/mysqli_fetch_array_large.phpt index 43cd0fab3fd92..21b74e8ab7ae6 100644 --- a/ext/mysqli/tests/mysqli_fetch_array_large.phpt +++ b/ext/mysqli/tests/mysqli_fetch_array_large.phpt @@ -7,6 +7,8 @@ mysqli if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); require_once('skipifconnectfailure.inc'); ?> +--CONFLICTS-- +all --INI-- memory_limit=-1 --FILE-- diff --git a/ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt b/ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt index 345eef6e28245..371299808ce25 100644 --- a/ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt +++ b/ext/mysqli/tests/mysqli_fetch_object_no_constructor.phpt @@ -32,11 +32,11 @@ require_once('skipifconnectfailure.inc'); printf("No exception with PHP:\n"); var_dump($obj = new mysqli_fetch_object_test(1, 2)); - printf("\nException with mysqli. Note that at all other places we throws errors but no exceptions unless the error mode has been changed:\n"); + printf("\nValueError with mysqli. Note that at all other places we throws errors but no exceptions unless the error mode has been changed:\n"); try { var_dump($obj = mysqli_fetch_object($res, 'mysqli_fetch_object_test', array(1, 2))); - } catch (Exception $e) { - printf("Exception: %s\n", $e->getMessage()); + } catch (ValueError $e) { + printf("ValueError: %s\n", $e->getMessage()); } printf("\nFatal error with PHP (but no exception!):\n"); @@ -62,8 +62,8 @@ object(mysqli_fetch_object_test)#%d (%d) { NULL } -Exception with mysqli. Note that at all other places we throws errors but no exceptions unless the error mode has been changed: -Exception: mysqli_fetch_object(): Argument #3 ($constructor_args) must be empty when the specified class (mysqli_fetch_object_test) does not have a constructor +ValueError with mysqli. Note that at all other places we throws errors but no exceptions unless the error mode has been changed: +ValueError: mysqli_fetch_object(): Argument #3 ($constructor_args) must be empty when the specified class (mysqli_fetch_object_test) does not have a constructor Fatal error with PHP (but no exception!): diff --git a/ext/mysqli/tests/mysqli_query_iterators.phpt b/ext/mysqli/tests/mysqli_query_iterators.phpt index 783a2b05aba80..0aebf7dc49028 100644 --- a/ext/mysqli/tests/mysqli_query_iterators.phpt +++ b/ext/mysqli/tests/mysqli_query_iterators.phpt @@ -151,7 +151,7 @@ array(1) { } ====== -Warning: main(): Data fetched with MYSQLI_USE_RESULT can be iterated only once in %s on line %d +Warning: Data fetched with MYSQLI_USE_RESULT can be iterated only once in %s on line %d --- Testing STORE_RESULT --- array(1) { ["id"]=> diff --git a/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt b/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt index 58a99c86e7f47..03a980d929c6e 100644 --- a/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt +++ b/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt @@ -6,6 +6,8 @@ mysqli +--CONFLICTS-- +all --FILE-- -#ifndef HAVE_INT8_T -#define HAVE_INT8_T -#endif -#ifndef HAVE_UINT8_T -#define HAVE_UINT8_T -#endif -#ifndef HAVE_INT16_T -#define HAVE_INT16_T -#endif -#ifndef HAVE_UINT16_T -#define HAVE_UINT16_T -#endif -#ifndef HAVE_INT32_T -#define HAVE_INT32_T -#endif -#ifndef HAVE_UINT32_T -#define HAVE_UINT32_T -#endif -#ifndef HAVE_INT64_T -#define HAVE_INT64_T -#endif -#ifndef HAVE_UINT64_T -#define HAVE_UINT64_T -#endif - - #ifndef _WIN64 #ifndef _WIN32 #define _WIN32 /* Compatible with old source */ diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h index 840d219248ae3..9afc2afeade9a 100644 --- a/ext/mysqlnd/mysqlnd.h +++ b/ext/mysqlnd/mysqlnd.h @@ -194,7 +194,6 @@ PHPAPI void mysqlnd_local_infile_default(MYSQLND_CONN_DATA * conn); #define mysqlnd_ping(conn) ((conn)->data)->m->ping((conn)->data) #define mysqlnd_kill(conn, pid) ((conn)->data)->m->kill_connection((conn)->data, (pid)) #define mysqlnd_refresh(conn, options) ((conn)->data)->m->refresh_server((conn)->data, (options)) -#define mysqlnd_shutdown(conn, level) ((conn)->data)->m->shutdown_server((conn)->data, (level)) #define mysqlnd_set_character_set(conn, cs) ((conn)->data)->m->set_charset((conn)->data, (cs)) #define mysqlnd_stat(conn, msg) ((conn)->data)->m->get_server_statistics(((conn)->data), (msg)) #define mysqlnd_options(conn, opt, value) ((conn)->data)->m->set_client_option((conn)->data, (opt), (value)) diff --git a/ext/mysqlnd/mysqlnd_commands.c b/ext/mysqlnd/mysqlnd_commands.c index 40821bb1efedd..eba60c2cb8e08 100644 --- a/ext/mysqlnd/mysqlnd_commands.c +++ b/ext/mysqlnd/mysqlnd_commands.c @@ -250,35 +250,6 @@ MYSQLND_METHOD(mysqlnd_command, refresh)(MYSQLND_CONN_DATA * const conn, const u /* }}} */ -/* {{{ mysqlnd_command::shutdown */ -static enum_func_status -MYSQLND_METHOD(mysqlnd_command, shutdown)(MYSQLND_CONN_DATA * const conn, const uint8_t level) -{ - const func_mysqlnd_protocol_payload_decoder_factory__send_command send_command = conn->payload_decoder_factory->m.send_command; - const func_mysqlnd_protocol_payload_decoder_factory__send_command_handle_response send_command_handle_response = conn->payload_decoder_factory->m.send_command_handle_response; - zend_uchar bits[1]; - enum_func_status ret = FAIL; - - DBG_ENTER("mysqlnd_command::shutdown"); - int1store(bits, level); - - ret = send_command(conn->payload_decoder_factory, COM_SHUTDOWN, bits, 1, FALSE, - &conn->state, - conn->error_info, - conn->upsert_status, - conn->stats, - conn->m->send_close, - conn); - if (PASS == ret) { - ret = send_command_handle_response(conn->payload_decoder_factory, PROT_OK_PACKET, FALSE, COM_SHUTDOWN, TRUE, - conn->error_info, conn->upsert_status, &conn->last_message); - } - - DBG_RETURN(ret); -} -/* }}} */ - - /* {{{ mysqlnd_command::quit */ static enum_func_status MYSQLND_METHOD(mysqlnd_command, quit)(MYSQLND_CONN_DATA * const conn) @@ -680,7 +651,6 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_command) MYSQLND_METHOD(mysqlnd_command, statistics), MYSQLND_METHOD(mysqlnd_command, process_kill), MYSQLND_METHOD(mysqlnd_command, refresh), - MYSQLND_METHOD(mysqlnd_command, shutdown), MYSQLND_METHOD(mysqlnd_command, quit), MYSQLND_METHOD(mysqlnd_command, query), MYSQLND_METHOD(mysqlnd_command, change_user), diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index ed4d1af277ddc..05b0dab63b007 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -289,7 +289,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, free_contents)(MYSQLND_CONN_DATA * conn) mysqlnd_set_persistent_string(&conn->unix_socket, NULL, 0, pers); DBG_INF_FMT("scheme=%s", conn->scheme.s); mysqlnd_set_persistent_string(&conn->scheme, NULL, 0, pers); - + if (conn->server_version) { mnd_pefree(conn->server_version, pers); conn->server_version = NULL; @@ -1045,17 +1045,6 @@ MYSQLND_METHOD(mysqlnd_conn_data, refresh)(MYSQLND_CONN_DATA * const conn, uint8 /* }}} */ -/* {{{ mysqlnd_conn_data::shutdown */ -static enum_func_status -MYSQLND_METHOD(mysqlnd_conn_data, shutdown)(MYSQLND_CONN_DATA * const conn, uint8_t level) -{ - DBG_ENTER("mysqlnd_conn_data::shutdown"); - DBG_INF_FMT("conn=%" PRIu64 " level=%u", conn->thread_id, level); - DBG_RETURN(conn->command->shutdown(conn, level)); -} -/* }}} */ - - /* {{{ mysqlnd_send_close */ static enum_func_status MYSQLND_METHOD(mysqlnd_conn_data, send_close)(MYSQLND_CONN_DATA * const conn) @@ -1954,7 +1943,6 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn_data) MYSQLND_METHOD(mysqlnd_conn_data, stmt_init), - MYSQLND_METHOD(mysqlnd_conn_data, shutdown), MYSQLND_METHOD(mysqlnd_conn_data, refresh), MYSQLND_METHOD(mysqlnd_conn_data, ping), diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 15ccec4522beb..1be10a0f20f18 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -1978,7 +1978,7 @@ MYSQLND_CLASS_METHODS_END; /* {{{ _mysqlnd_init_ps_subsystem */ -void _mysqlnd_init_ps_subsystem() +void _mysqlnd_init_ps_subsystem(void) { mysqlnd_stmt_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_stmt)); _mysqlnd_init_ps_fetch_subsystem(); diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index 3b38d86273b68..ca6c2112cffa5 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -355,7 +355,7 @@ ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pa /* {{{ _mysqlnd_init_ps_fetch_subsystem */ -void _mysqlnd_init_ps_fetch_subsystem() +void _mysqlnd_init_ps_fetch_subsystem(void) { memset(mysqlnd_ps_fetch_functions, 0, sizeof(mysqlnd_ps_fetch_functions)); mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].func = ps_fetch_null; @@ -691,7 +691,7 @@ mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval /* User hasn't sent anything, we will send empty string. Empty string has length of 0, encoded in 1 byte. No real - data will follows after it. + data will follow after it. */ (*data_size)++; } diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 9cad5247a7d39..d3314b366fecb 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -328,7 +328,7 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s) /* If SERVER_MORE_RESULTS_EXISTS is set then this is either MULTI_QUERY or a CALL() The first packet after sending the query/com_execute has the bit set only - in this cases. Not sure why it's a needed but it marks that the whole stream + in these cases. Not sure why it's a needed but it marks that the whole stream will include many result sets. What actually matters are the bits set at the end of every result set (the EOF packet). */ diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 57ab51b8c3b58..8e1425a5c6bf1 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -311,7 +311,6 @@ typedef enum_func_status (*func_mysqlnd_execute_com_ping)(MYSQLND_CONN_DATA * co typedef enum_func_status (*func_mysqlnd_execute_com_statistics)(MYSQLND_CONN_DATA * const conn, zend_string ** message); typedef enum_func_status (*func_mysqlnd_execute_com_process_kill)(MYSQLND_CONN_DATA * const conn, const unsigned int process_id, const bool read_response); typedef enum_func_status (*func_mysqlnd_execute_com_refresh)(MYSQLND_CONN_DATA * const conn, const uint8_t options); -typedef enum_func_status (*func_mysqlnd_execute_com_shutdown)(MYSQLND_CONN_DATA * const conn, const uint8_t level); typedef enum_func_status (*func_mysqlnd_execute_com_quit)(MYSQLND_CONN_DATA * const conn); typedef enum_func_status (*func_mysqlnd_execute_com_query)(MYSQLND_CONN_DATA * const conn, MYSQLND_CSTRING query); typedef enum_func_status (*func_mysqlnd_execute_com_change_user)(MYSQLND_CONN_DATA * const conn, const MYSQLND_CSTRING payload, const bool silent); @@ -335,7 +334,6 @@ MYSQLND_CLASS_METHODS_TYPE(mysqlnd_command) func_mysqlnd_execute_com_statistics statistics; func_mysqlnd_execute_com_process_kill process_kill; func_mysqlnd_execute_com_refresh refresh; - func_mysqlnd_execute_com_shutdown shutdown; func_mysqlnd_execute_com_quit quit; func_mysqlnd_execute_com_query query; func_mysqlnd_execute_com_change_user change_user; @@ -533,7 +531,6 @@ MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data) func_mysqlnd_conn_data__stmt_init stmt_init; - func_mysqlnd_conn_data__shutdown_server shutdown_server; func_mysqlnd_conn_data__refresh_server refresh_server; func_mysqlnd_conn_data__ping ping; diff --git a/ext/mysqlnd/mysqlnd_vio.c b/ext/mysqlnd/mysqlnd_vio.c index 65f6e54d84283..79fc92d500a25 100644 --- a/ext/mysqlnd/mysqlnd_vio.c +++ b/ext/mysqlnd/mysqlnd_vio.c @@ -561,6 +561,10 @@ MYSQLND_METHOD(mysqlnd_vio, enable_ssl)(MYSQLND_VIO * const net) } } php_stream_context_set(net_stream, context); + /* php_stream_context_set() increases the refcount of context, but we just want to transfer ownership + * hence the need to decrease the refcount so the refcount will be equal to 1. */ + ZEND_ASSERT(GC_REFCOUNT(context->res) == 2); + GC_DELREF(context->res); if (php_stream_xport_crypto_setup(net_stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL) < 0 || php_stream_xport_crypto_enable(net_stream, 1) < 0) { diff --git a/ext/oci8/LICENSE b/ext/oci8/LICENSE index dffd7eab225d7..47a594e38a4d2 100644 --- a/ext/oci8/LICENSE +++ b/ext/oci8/LICENSE @@ -1,6 +1,6 @@ -------------------------------------------------------------------- The PHP License, version 3.01 -Copyright (c) 1999 - 2022 The PHP Group. All rights reserved. +Copyright (c) 1999 - 2023 The PHP Group. All rights reserved. -------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without diff --git a/ext/oci8/README.md b/ext/oci8/README.md index eb2149e21dd95..d0c0c3be09609 100644 --- a/ext/oci8/README.md +++ b/ext/oci8/README.md @@ -4,16 +4,16 @@ Use the OCI8 extension to access Oracle Database. Documentation is at https://www.php.net/oci8 -Use `pecl install oci8` to install for PHP 8. +Use `pecl install oci8` to install for PHP 8.2. -Use `pecl install oci8-2.2.0` to install for PHP 7. +Use `pecl install oci8-3.2.1` to install for PHP 8.1. -Use `pecl install oci8-2.0.12` to install for PHP 5.2 - PHP 5.6. +Use `pecl install oci8-3.0.1` to install for PHP 8.0. -Use `pecl install oci8-1.4.10` to install for PHP 4.3.9 - PHP 5.1. +Use `pecl install oci8-2.2.0` to install for PHP 7. The OCI8 extension can be linked with Oracle client libraries from Oracle -Database 10.2 or later. These libraries are found in your database +Database 11.2 or later. These libraries are found in your database installation, or in the free Oracle Instant Client from https://www.oracle.com/database/technologies/instant-client.html Install the 'Basic' or 'Basic Light' Instant Client package. If building from diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c index 98e1821568d7d..01cb1c8ad9277 100644 --- a/ext/oci8/oci8.c +++ b/ext/oci8/oci8.c @@ -51,6 +51,8 @@ #error Use PHP OCI8 2.2 for your version of PHP #elif PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 1 #error Use PHP OCI8 3.0 for your version of PHP +#elif PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 2 +#error Use PHP OCI8 3.2 for your version of PHP #endif #include "php_oci8.h" diff --git a/ext/oci8/package.xml b/ext/oci8/package.xml index f5ba6005b61c3..63a020750623c 100644 --- a/ext/oci8/package.xml +++ b/ext/oci8/package.xml @@ -10,16 +10,14 @@ http://pear.php.net/dtd/package-2.0.xsd"> The OCI8 extension lets you access Oracle Database. -Use 'pecl install oci8' to install for PHP 8.1. +Use 'pecl install oci8' to install for PHP 8.2. + +Use 'pecl install oci8-3.2.1' to install for PHP 8.1. Use 'pecl install oci8-3.0.1' to install for PHP 8.0. Use 'pecl install oci8-2.2.0' to install for PHP 7. -Use 'pecl install oci8-2.0.12' to install for PHP 5.2 - PHP 5.6. - -Use 'pecl install oci8-1.4.10' to install for PHP 4.3.9 - PHP 5.1. - The current OCI8 extension can be linked with Oracle Client libraries from Oracle Database 11.2 or later. (OCI8 3.0 and earlier can be linked with 10g or later). The Oracle Client libraries are in the free Oracle Instant Client from https://www.oracle.com/database/technologies/instant-client.html. They are also included in your database installation. Oracle's standard cross-version connectivity applies. For example, PHP OCI8 linked with Oracle Client 19c can connect to Oracle Database 11.2 onward. See Oracle's note "Oracle Client / Server Interoperability Support" (ID 207303.1) for details. @@ -55,12 +53,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin no - 2021-12-12 + 2023-04-22 - 3.2.1 - 3.2.1 + 3.3.0 + 3.3.0 stable @@ -68,7 +66,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin PHP - This version is for PHP 8.1 only. + This version is for PHP 8.2 only. Requires Oracle Client libraries from 11.2 or later. @@ -91,14 +89,14 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - - + - + - + + @@ -111,12 +109,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - + - + @@ -148,8 +146,8 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - + @@ -173,43 +171,44 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - - + - + - + - + - + - + - + - + - + - + - + + - + + + - @@ -219,20 +218,19 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - + - + + - - @@ -240,6 +238,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin + @@ -258,21 +257,21 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - + - - + + @@ -281,7 +280,6 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - @@ -289,14 +287,15 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - + + - + @@ -375,33 +374,33 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - - + + - - + - - + + + - + @@ -412,8 +411,8 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - + @@ -452,6 +451,23 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin + + + 3.2.1 + 3.2.1 + + + stable + stable + + PHP + + This version is for PHP 8.1 only. + + Requires Oracle Client libraries from 11.2 or later. + + + 3.2.0 diff --git a/ext/oci8/php_oci8.h b/ext/oci8/php_oci8.h index 5ed8c7bbe72c5..c87c2084d7fd5 100644 --- a/ext/oci8/php_oci8.h +++ b/ext/oci8/php_oci8.h @@ -40,7 +40,7 @@ */ #undef PHP_OCI8_VERSION #endif -#define PHP_OCI8_VERSION "3.2.1" +#define PHP_OCI8_VERSION "3.3.0" extern zend_module_entry oci8_module_entry; #define phpext_oci8_ptr &oci8_module_entry diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h index f063843bb01dd..90a6331edb390 100644 --- a/ext/oci8/php_oci8_int.h +++ b/ext/oci8/php_oci8_int.h @@ -53,7 +53,9 @@ /* }}} */ #include "ext/standard/php_string.h" +ZEND_CGG_DIAGNOSTIC_IGNORED_START("-Wstrict-prototypes") #include +ZEND_CGG_DIAGNOSTIC_IGNORED_END #if !defined(OCI_MAJOR_VERSION) || OCI_MAJOR_VERSION < 11 || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION < 2)) #error This version of PHP OCI8 requires Oracle Client libraries from 11.2 or later. diff --git a/ext/oci8/tests/CONFLICTS b/ext/oci8/tests/CONFLICTS index 176b41ab8bb6f..ff6afc6fb0838 100644 --- a/ext/oci8/tests/CONFLICTS +++ b/ext/oci8/tests/CONFLICTS @@ -1 +1,2 @@ -oci8 +# OCI tests are network intensive and may cause timeouts in other tests +all diff --git a/ext/oci8/tests/driver_name.phpt b/ext/oci8/tests/driver_name.phpt index 80b4740bc140b..32cb75a5dc0eb 100644 --- a/ext/oci8/tests/driver_name.phpt +++ b/ext/oci8/tests/driver_name.phpt @@ -57,11 +57,11 @@ function get_attr($conn) ?> --EXPECT-- **Test 1.1 - Default values for the attribute ************** -The value of DRIVER_NAME is PHP OCI8 : 3.2.1 +The value of DRIVER_NAME is PHP OCI8 : 3.3.0 ***Test 1.2 - Get the values from different connections ************** Testing with oci_pconnect() -The value of DRIVER_NAME is PHP OCI8 : 3.2.1 +The value of DRIVER_NAME is PHP OCI8 : 3.3.0 Testing with oci_new_connect() -The value of DRIVER_NAME is PHP OCI8 : 3.2.1 +The value of DRIVER_NAME is PHP OCI8 : 3.3.0 Done diff --git a/ext/oci8/tests/privileged_connect1.phpt b/ext/oci8/tests/privileged_connect1.phpt index 09c5f047d1672..037c61e601ce5 100644 --- a/ext/oci8/tests/privileged_connect1.phpt +++ b/ext/oci8/tests/privileged_connect1.phpt @@ -4,7 +4,7 @@ privileged connect tests oci8 --SKIPIF-- --INI-- oci8.privileged_connect=1 diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index f71468549e6af..11ab472631b56 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -112,8 +112,8 @@ zend_accel_shared_globals *accel_shared_globals = NULL; char accel_uname_id[32]; #endif bool accel_startup_ok = false; -static char *zps_failure_reason = NULL; -char *zps_api_failure_reason = NULL; +static const char *zps_failure_reason = NULL; +const char *zps_api_failure_reason = NULL; bool file_cache_only = false; /* process uses file cache only */ #if ENABLE_FILE_CACHE_FALLBACK bool fallback_process = false; /* process uses file cache fallback */ @@ -129,7 +129,7 @@ static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL; static zend_result (*orig_post_startup_cb)(void); static zend_result accel_post_startup(void); -static int accel_finish_startup(void); +static zend_result accel_finish_startup(void); static void preload_shutdown(void); static void preload_activate(void); @@ -549,7 +549,7 @@ zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str) STRTAB_COLLISION(s) = *hash_slot; *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s); GC_SET_REFCOUNT(s, 2); - GC_TYPE_INFO(s) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT); + GC_TYPE_INFO(s) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT)| (ZSTR_IS_VALID_UTF8(str) ? IS_STR_VALID_UTF8 : 0); ZSTR_H(s) = h; ZSTR_LEN(s) = ZSTR_LEN(str); memcpy(ZSTR_VAL(s), ZSTR_VAL(str), ZSTR_LEN(s) + 1); @@ -731,9 +731,6 @@ static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_int p->key = new_interned_string(p->key); } c = (zend_constant*)Z_PTR(p->val); - if (c->name) { - c->name = new_interned_string(c->name); - } if (Z_TYPE(c->value) == IS_STRING) { ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value))); } @@ -893,11 +890,18 @@ static inline void kill_all_lockers(struct flock *mem_usage_check) } #endif -static inline int accel_is_inactive(void) +static inline bool accel_is_inactive(void) { #ifdef ZEND_WIN32 + /* on Windows, we don't need kill_all_lockers() because SAPIs + that work on Windows don't manage child processes (and we + can't do anything about hanging threads anyway); therefore + on Windows, we can simply manage this counter with atomics + instead of flocks (atomics are much faster but they don't + provide us with the PID of locker processes) */ + if (LOCKVAL(mem_usage) == 0) { - return SUCCESS; + return true; } #else struct flock mem_usage_check; @@ -909,10 +913,10 @@ static inline int accel_is_inactive(void) mem_usage_check.l_pid = -1; if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) { zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC: %s (%d)", strerror(errno), errno); - return FAILURE; + return false; } if (mem_usage_check.l_type == F_UNLCK) { - return SUCCESS; + return true; } if (ZCG(accel_directives).force_restart_timeout @@ -921,11 +925,11 @@ static inline int accel_is_inactive(void) zend_accel_error(ACCEL_LOG_WARNING, "Forced restart at %ld (after " ZEND_LONG_FMT " seconds), locked by %d", (long)time(NULL), ZCG(accel_directives).force_restart_timeout, mem_usage_check.l_pid); kill_all_lockers(&mem_usage_check); - return FAILURE; /* next request should be able to restart it */ + return false; /* next request should be able to restart it */ } #endif - return FAILURE; + return false; } static int zend_get_stream_timestamp(const char *filename, zend_stat_t *statbuf) @@ -1158,7 +1162,7 @@ static inline int do_validate_timestamps(zend_persistent_script *persistent_scri return ret; } -int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle) +zend_result validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle) { if (persistent_script->timestamp == 0) { return SUCCESS; /* Don't check timestamps of preloaded scripts */ @@ -1173,12 +1177,10 @@ int validate_timestamp_and_record(zend_persistent_script *persistent_script, zen } } -int validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle) +zend_result validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle) { - int ret; - SHM_UNPROTECT(); - ret = validate_timestamp_and_record(persistent_script, file_handle); + const zend_result ret = validate_timestamp_and_record(persistent_script, file_handle); SHM_PROTECT(); return ret; @@ -1391,7 +1393,7 @@ static void zend_accel_lock_discard_script(zend_persistent_script *persistent_sc zend_shared_alloc_unlock(); } -int zend_accel_invalidate(zend_string *filename, bool force) +zend_result zend_accel_invalidate(zend_string *filename, bool force) { zend_string *realpath; zend_persistent_script *persistent_script; @@ -1500,11 +1502,11 @@ static zend_persistent_script *store_script_in_file_cache(zend_persistent_script #if defined(__AVX__) || defined(__SSE2__) /* Align to 64-byte boundary */ ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 64); - ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L); + ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 63L) & ~63L); #elif ZEND_MM_NEED_EIGHT_BYTE_REALIGNMENT /* Align to 8-byte boundary */ ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 8); - ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 7L) & ~7L); + ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 7L) & ~7L); #else ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used); #endif @@ -2353,18 +2355,18 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, SHM_UNPROTECT(); zend_shared_alloc_lock(); - entry = ce->inheritance_cache; + entry = proto->inheritance_cache; while (entry) { - entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload); + entry = zend_accel_inheritance_cache_find(entry, proto, parent, traits_and_interfaces, &needs_autoload); if (entry) { + zend_shared_alloc_unlock(); + SHM_PROTECT(); if (!needs_autoload) { - zend_shared_alloc_unlock(); - SHM_PROTECT(); - zend_map_ptr_extend(ZCSG(map_ptr_last)); return entry->ce; + } else { + return NULL; } - ZEND_ASSERT(0); // entry = entry->next; // This shouldn't be possible ??? } } @@ -2403,7 +2405,7 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, #if ZEND_MM_NEED_EIGHT_BYTE_REALIGNMENT /* Align to 8-byte boundary */ - ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 7L) & ~7L); + ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 7L) & ~7L); #endif memset(ZCG(mem), 0, size); @@ -2469,7 +2471,7 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, } #ifdef ZEND_WIN32 -static int accel_gen_uname_id(void) +static zend_result accel_gen_uname_id(void) { PHP_MD5_CTX ctx; unsigned char digest[16]; @@ -2651,7 +2653,7 @@ zend_result accel_activate(INIT_FUNC_ARGS) ZCG(root_hash) = buf.st_ino; if (sizeof(buf.st_ino) > sizeof(ZCG(root_hash))) { if (ZCG(root_hash) != buf.st_ino) { - zend_string *key = zend_string_init("opcache.enable", sizeof("opcache.enable")-1, 0); + zend_string *key = ZSTR_INIT_LITERAL("opcache.enable", 0); zend_alter_ini_entry_chars(key, "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_RUNTIME); zend_string_release_ex(key, 0); zend_accel_error(ACCEL_LOG_WARNING, "Can't cache files in chroot() directory with too big inode"); @@ -2680,7 +2682,7 @@ zend_result accel_activate(INIT_FUNC_ARGS) if (ZCSG(restart_pending)) { zend_shared_alloc_lock(); if (ZCSG(restart_pending)) { /* check again, to ensure that the cache wasn't already cleaned by another process */ - if (accel_is_inactive() == SUCCESS) { + if (accel_is_inactive()) { zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!"); ZCSG(restart_pending) = false; switch ZCSG(restart_reason) { @@ -2804,7 +2806,7 @@ static int accelerator_remove_cb(zend_extension *element1, zend_extension *eleme return 0; } -static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_extension *, zend_extension *)) +static void zps_startup_failure(const char *reason, const char *api_reason, int (*cb)(zend_extension *, zend_extension *)) { accel_startup_ok = false; zps_failure_reason = reason; @@ -2812,7 +2814,7 @@ static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_e zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb); } -static inline int accel_find_sapi(void) +static inline zend_result accel_find_sapi(void) { static const char *supported_sapis[] = { "apache", @@ -2826,6 +2828,7 @@ static inline int accel_find_sapi(void) "uwsgi", "fuzzer", "frankenphp", + "ngx-php", NULL }; const char **sapi_name; @@ -2846,7 +2849,7 @@ static inline int accel_find_sapi(void) return FAILURE; } -static int zend_accel_init_shm(void) +static zend_result zend_accel_init_shm(void) { int i; size_t accel_shared_globals_size; @@ -3037,7 +3040,7 @@ static void accel_move_code_to_huge_pages(void) int ret; while (1) { - ret = fscanf(f, "%lx-%lx %4s %lx %9s %ld %s\n", &start, &end, perm, &offset, dev, &inode, name); + ret = fscanf(f, "%lx-%lx %4s %lx %9s %lu %s\n", &start, &end, perm, &offset, dev, &inode, name); if (ret == 7) { if (perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/') { long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size); @@ -3205,7 +3208,7 @@ static zend_result accel_post_startup(void) size_t page_size; page_size = zend_get_page_size(); - if (!page_size && (page_size & (page_size - 1))) { + if (!page_size || (page_size & (page_size - 1))) { zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can't get page size."); abort(); } @@ -3451,7 +3454,7 @@ static void accel_deactivate_now(void) if OK returns SUCCESS MUST call accelerator_shm_read_unlock after done lock operations */ -int accelerator_shm_read_lock(void) +zend_result accelerator_shm_read_lock(void) { if (ZCG(counted)) { /* counted means we are holding read lock for SHM, so that nothing bad can happen */ @@ -3746,15 +3749,16 @@ static bool preload_try_resolve_constants(zend_class_entry *ce) bool ok, changed, was_changed = false; zend_class_constant *c; zval *val; + zend_string *key; EG(exception) = (void*)(uintptr_t)-1; /* prevent error reporting */ do { ok = true; changed = false; - ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) { + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { val = &c->value; if (Z_TYPE_P(val) == IS_CONSTANT_AST) { - if (EXPECTED(zval_update_constant_ex(val, c->ce) == SUCCESS)) { + if (EXPECTED(zend_update_class_constant(c, key, c->ce) == SUCCESS)) { was_changed = changed = true; } else { ok = false; @@ -4009,7 +4013,7 @@ static void preload_link(void) zend_error_at( E_WARNING, ce->info.user.filename, ce->info.user.line_start, "Can't preload already declared class %s", ZSTR_VAL(ce->name)); - } else if (preload_resolve_deps(&error, ce)) { + } else if (preload_resolve_deps(&error, ce) == FAILURE) { zend_error_at( E_WARNING, ce->info.user.filename, ce->info.user.line_start, "Can't preload unlinked class %s: %s%s", @@ -4328,10 +4332,10 @@ static void preload_load(void) } } -static int accel_preload(const char *config, bool in_child) +static zend_result accel_preload(const char *config, bool in_child) { zend_file_handle file_handle; - int ret; + zend_result ret; char *orig_open_basedir; size_t orig_map_ptr_last; uint32_t orig_compiler_options; @@ -4412,6 +4416,8 @@ static int accel_preload(const char *config, bool in_child) if (PG(auto_globals_jit)) { ping_auto_globals_mask = zend_accel_get_auto_globals(); + } else { + ping_auto_globals_mask = 0; } if (EG(zend_constants)) { @@ -4472,7 +4478,7 @@ static int accel_preload(const char *config, bool in_child) script->ping_auto_globals_mask = ping_auto_globals_mask; /* Store all functions and classes in a single pseudo-file */ - CG(compiled_filename) = zend_string_init("$PRELOAD$", sizeof("$PRELOAD$") - 1, 0); + CG(compiled_filename) = ZSTR_INIT_LITERAL("$PRELOAD$", 0); #if ZEND_USE_ABS_CONST_ADDR init_op_array(&script->script.main_op_array, ZEND_USER_FUNCTION, 1); #else @@ -4576,10 +4582,9 @@ static void preload_send_header(sapi_header_struct *sapi_header, void *server_co } #ifndef ZEND_WIN32 -static int accel_finish_startup_preload(bool in_child) +static zend_result accel_finish_startup_preload(bool in_child) { - int ret = SUCCESS; - int rc; + zend_result ret = SUCCESS; int orig_error_reporting; int (*orig_activate)(void) = sapi_module.activate; @@ -4614,7 +4619,7 @@ static int accel_finish_startup_preload(bool in_child) orig_error_reporting = EG(error_reporting); EG(error_reporting) = 0; - rc = php_request_startup(); + const zend_result rc = php_request_startup(); EG(error_reporting) = orig_error_reporting; @@ -4674,7 +4679,7 @@ static int accel_finish_startup_preload(bool in_child) return ret; } -static int accel_finish_startup_preload_subprocess(pid_t *pid) +static zend_result accel_finish_startup_preload_subprocess(pid_t *pid) { uid_t euid = geteuid(); if (euid != 0) { @@ -4741,7 +4746,7 @@ static int accel_finish_startup_preload_subprocess(pid_t *pid) } #endif /* ZEND_WIN32 */ -static int accel_finish_startup(void) +static zend_result accel_finish_startup(void) { if (!ZCG(enabled) || !accel_startup_ok) { return SUCCESS; @@ -4779,9 +4784,10 @@ static int accel_finish_startup(void) } if (pid == -1) { /* no subprocess was needed */ + /* The called function unlocks the shared alloc lock */ return accel_finish_startup_preload(false); } else if (pid == 0) { /* subprocess */ - int ret = accel_finish_startup_preload(true); + const zend_result ret = accel_finish_startup_preload(true); exit(ret == SUCCESS ? 0 : 1); } else { /* parent */ @@ -4796,6 +4802,8 @@ static int accel_finish_startup(void) preload_load(); } + zend_shared_alloc_unlock(); + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { return SUCCESS; } else { diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index bc92854c35576..568d8f4972419 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -305,7 +305,7 @@ ZEND_TSRMLS_CACHE_EXTERN() extern zend_accel_globals accel_globals; #endif -extern char *zps_api_failure_reason; +extern const char *zps_api_failure_reason; BEGIN_EXTERN_C() @@ -315,10 +315,10 @@ zend_result accel_post_deactivate(void); void zend_accel_schedule_restart(zend_accel_restart_reason reason); void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason); accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size); -int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle); -int validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle); -int zend_accel_invalidate(zend_string *filename, bool force); -int accelerator_shm_read_lock(void); +zend_result validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle); +zend_result validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle); +zend_result zend_accel_invalidate(zend_string *filename, bool force); +zend_result accelerator_shm_read_lock(void); void accelerator_shm_read_unlock(void); zend_string *accel_make_persistent_key(zend_string *path); @@ -337,14 +337,14 @@ END_EXTERN_C() #define SHM_PROTECT() \ do { \ if (ZCG(accel_directives).protect_memory) { \ - zend_accel_shared_protect(1); \ + zend_accel_shared_protect(true); \ } \ } while (0) #define SHM_UNPROTECT() \ do { \ if (ZCG(accel_directives).protect_memory) { \ - zend_accel_shared_protect(0); \ + zend_accel_shared_protect(false); \ } \ } while (0) diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4 index 2a83fa2455974..9404e3e19d1d8 100644 --- a/ext/opcache/config.m4 +++ b/ext/opcache/config.m4 @@ -18,6 +18,12 @@ PHP_ARG_ENABLE([opcache-jit], [yes], [no]) +PHP_ARG_WITH([capstone],, + [AS_HELP_STRING([--with-capstone], + [support opcache JIT disassembly through capstone])], + [no], + [no]) + if test "$PHP_OPCACHE" != "no"; then dnl Always build as shared extension @@ -68,44 +74,21 @@ if test "$PHP_OPCACHE" != "no"; then DASM_FLAGS="$DASM_FLAGS -D ZTS=1" fi - PKG_CHECK_MODULES([CAPSTONE], [capstone >= 3.0.0], - [have_capstone="yes"], [have_capstone="no"]) - if test "$have_capstone" = "yes"; then - AC_DEFINE(HAVE_CAPSTONE, 1, [ ]) + AS_IF([test x"$with_capstone" = "xyes"],[ + PKG_CHECK_MODULES([CAPSTONE],[capstone >= 3.0.0],[ + AC_DEFINE([HAVE_CAPSTONE], [1], [Capstone is available]) PHP_EVAL_LIBLINE($CAPSTONE_LIBS, OPCACHE_SHARED_LIBADD) PHP_EVAL_INCLINE($CAPSTONE_CFLAGS) - fi - - PHP_SUBST(DASM_FLAGS) - PHP_SUBST(DASM_ARCH) - - AC_MSG_CHECKING(for opagent in default path) - for i in /usr/local /usr; do - if test -r $i/include/opagent.h; then - OPAGENT_DIR=$i - AC_MSG_RESULT(found in $i) - break - fi - done - if test -z "$OPAGENT_DIR"; then - AC_MSG_RESULT(not found) - else - PHP_CHECK_LIBRARY(opagent, op_write_native_code, - [ - AC_DEFINE(HAVE_OPROFILE,1,[ ]) - PHP_ADD_INCLUDE($OPAGENT_DIR/include) - PHP_ADD_LIBRARY_WITH_PATH(opagent, $OPAGENT_DIR/$PHP_LIBDIR/oprofile, OPCACHE_SHARED_LIBADD) - PHP_SUBST(OPCACHE_SHARED_LIBADD) - ],[ - AC_MSG_RESULT(not found) ],[ - -L$OPAGENT_DIR/$PHP_LIBDIR/oprofile + AC_MSG_ERROR([capstone >= 3.0 required but not found]) ]) - fi + ]) + PHP_SUBST(DASM_FLAGS) + PHP_SUBST(DASM_ARCH) fi - AC_CHECK_FUNCS([mprotect]) + AC_CHECK_FUNCS([mprotect memfd_create]) AC_MSG_CHECKING(for sysvipc shared memory support) AC_RUN_IFELSE([AC_LANG_SOURCE([[ @@ -116,7 +99,7 @@ if test "$PHP_OPCACHE" != "no"; then #include #include -int main() { +int main(void) { pid_t pid; int status; int ipc_id; @@ -195,7 +178,7 @@ int main() { # define MAP_FAILED ((void*)-1) #endif -int main() { +int main(void) { pid_t pid; int status; char *shm; @@ -257,7 +240,7 @@ int main() { # define MAP_FAILED ((void*)-1) #endif -int main() { +int main(void) { pid_t pid; int status; int fd; diff --git a/ext/opcache/jit/Makefile.frag b/ext/opcache/jit/Makefile.frag index 98c5cdaea2494..f9ae2e0cf4b99 100644 --- a/ext/opcache/jit/Makefile.frag +++ b/ext/opcache/jit/Makefile.frag @@ -11,7 +11,6 @@ $(builddir)/jit/zend_jit.lo: \ $(srcdir)/jit/zend_jit_disasm.c \ $(srcdir)/jit/zend_jit_gdb.c \ $(srcdir)/jit/zend_jit_perf_dump.c \ - $(srcdir)/jit/zend_jit_oprofile.c \ $(srcdir)/jit/zend_jit_vtune.c \ $(srcdir)/jit/zend_jit_trace.c \ $(srcdir)/jit/zend_elf.c diff --git a/ext/opcache/jit/Makefile.frag.w32 b/ext/opcache/jit/Makefile.frag.w32 index ed2b4ad4fec89..a9533e98edcea 100644 --- a/ext/opcache/jit/Makefile.frag.w32 +++ b/ext/opcache/jit/Makefile.frag.w32 @@ -12,6 +12,5 @@ $(BUILD_DIR)\ext\opcache\jit\zend_jit.obj: \ ext/opcache/jit/zend_jit_disasm.c \ ext/opcache/jit/zend_jit_gdb.c \ ext/opcache/jit/zend_jit_perf_dump.c \ - ext/opcache/jit/zend_jit_oprofile.c \ ext/opcache/jit/zend_jit_trace.c \ ext/opcache/jit/zend_jit_vtune.c diff --git a/ext/opcache/jit/README.md b/ext/opcache/jit/README.md index 3119f37811cf8..3ba6fe2abe3af 100644 --- a/ext/opcache/jit/README.md +++ b/ext/opcache/jit/README.md @@ -34,7 +34,7 @@ Running tests of the JIT ------------------------ Then, to test the JIT, e.g. with opcache.jit=tracing, an example command -based on what is used to test in Azure CI: +based on what is used to test in CI: ``` make test TESTS="-d opcache.jit_buffer_size=16M -d opcache.enable=1 -d opcache.enable_cli=1 -d opcache.protect_memory=1 -d opcache.jit=tracing --repeat 2 --show-diff -j$(nproc) ext/opcache Zend" @@ -75,7 +75,7 @@ For i386 (i.e. 32-bit): `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua ### How to build 32-bit builds on x86_64 environments -Refer to [../../../azure/i386](../../../azure/i386/apt.yml) for examples of +Refer to [../../../.github/workflows/push.yml](../../../.github/workflows/push.yml) for examples of dependencies to install. If you are running this natively (outside of Docker or a VM): @@ -93,7 +93,7 @@ set up prerequisites for regular development. ``` sudo dpkg --add-architecture i386 sudo apt-get update -y -# As well as anything else from azure/i386/apt.yml that you're testing locally +# As well as anything else from .github/actions/apt-x32/action.yml that you're testing locally sudo apt-get install \ gcc-multilib g++-multilib \ libxml2-dev:i386 \ diff --git a/ext/opcache/jit/dynasm/dasm_x86.h b/ext/opcache/jit/dynasm/dasm_x86.h index 618925c2d2572..098b226b06a11 100644 --- a/ext/opcache/jit/dynasm/dasm_x86.h +++ b/ext/opcache/jit/dynasm/dasm_x86.h @@ -124,7 +124,14 @@ void dasm_free(Dst_DECL) void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) { dasm_State *D = Dst_REF; +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Warray-bounds" +#endif D->globals = gl - 10; /* Negative bias to compensate for locals. */ +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); } diff --git a/ext/opcache/jit/vtune/jitprofiling.c b/ext/opcache/jit/vtune/jitprofiling.c index 86efe047c403d..3154611fec620 100644 --- a/ext/opcache/jit/vtune/jitprofiling.c +++ b/ext/opcache/jit/vtune/jitprofiling.c @@ -157,7 +157,7 @@ iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData) return ReturnValue; } -ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive() +ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void) { if (!iJIT_DLL_is_missing) { @@ -171,7 +171,7 @@ ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive() * on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1 * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0 */ -static int loadiJIT_Funcs() +static int loadiJIT_Funcs(void) { static int bDllWasLoaded = 0; char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */ @@ -301,7 +301,7 @@ static int loadiJIT_Funcs() return 1; } -ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID() +ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID(void) { static unsigned int methodID = 1; diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 181ab11615c82..e5a748d8355a8 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -150,7 +150,7 @@ static int zend_jit_assign_to_variable(dasm_State **Dst, zend_jit_addr var_addr, uint32_t var_info, uint32_t var_def_info, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, uint32_t val_info, zend_jit_addr res_addr, @@ -214,7 +214,7 @@ static bool zend_ival_is_last_use(const zend_lifetime_interval *ival, int use) return 0; } -static bool zend_is_commutative(zend_uchar opcode) +static bool zend_is_commutative(uint8_t opcode) { return opcode == ZEND_ADD || @@ -720,9 +720,6 @@ static int zend_jit_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int # include "jit/zend_jit_gdb.h" # include "jit/zend_jit_perf_dump.c" #endif -#ifdef HAVE_OPROFILE -# include "jit/zend_jit_oprofile.c" -#endif #include "Zend/zend_cpuinfo.h" @@ -898,7 +895,7 @@ static void *dasm_link_and_encode(dasm_State **dasm_state, size_t size; int ret; void *entry; -#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) +#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) zend_string *str = NULL; #endif @@ -1009,9 +1006,9 @@ static void *dasm_link_and_encode(dasm_State **dasm_state, } } -#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) +#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) if (!name) { - if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_OPROFILE|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_VTUNE|ZEND_JIT_DEBUG_PERF_DUMP)) { + if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_VTUNE|ZEND_JIT_DEBUG_PERF_DUMP)) { str = zend_jit_func_name(op_array); if (str) { name = ZSTR_VAL(str); @@ -1059,14 +1056,6 @@ static void *dasm_link_and_encode(dasm_State **dasm_state, } #endif -#ifdef HAVE_OPROFILE - if (JIT_G(debug) & ZEND_JIT_DEBUG_OPROFILE) { - zend_jit_oprofile_register( - name, - entry, - size); - } -#endif #ifdef HAVE_PERFTOOLS if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) { @@ -1096,7 +1085,7 @@ static void *dasm_link_and_encode(dasm_State **dasm_state, } #endif -#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) +#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) if (str) { zend_string_release(str); } @@ -2646,7 +2635,7 @@ static bool zend_jit_next_is_send_result(const zend_op *opline) return 0; } -static bool zend_jit_supported_binary_op(zend_uchar op, uint32_t op1_info, uint32_t op2_info) +static bool zend_jit_supported_binary_op(uint8_t op, uint32_t op1_info, uint32_t op2_info) { if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) { return false; @@ -2685,7 +2674,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op zend_lifetime_interval **ra = NULL; bool is_terminated = 1; /* previous basic block is terminated by jump */ bool recv_emitted = 0; /* emitted at least one RECV opcode */ - zend_uchar smart_branch_opcode; + uint8_t smart_branch_opcode; uint32_t target_label, target_label2; uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info; zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr; @@ -4259,7 +4248,7 @@ static int ZEND_FASTCALL zend_runtime_jit(void) /* perform real JIT for this function */ zend_real_jit_func(op_array, NULL, NULL); } zend_catch { - do_bailout = 0; + do_bailout = true; } zend_end_try(); zend_jit_protect(); @@ -4561,18 +4550,12 @@ ZEND_EXT_API int zend_jit_script(zend_script *script) } } - if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) { - for (i = 0; i < call_graph.op_arrays_count; i++) { - info = ZEND_FUNC_INFO(call_graph.op_arrays[i]); - if (info) { - zend_dump_op_array(call_graph.op_arrays[i], ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &info->ssa); - } - } - } - for (i = 0; i < call_graph.op_arrays_count; i++) { info = ZEND_FUNC_INFO(call_graph.op_arrays[i]); if (info) { + if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) { + zend_dump_op_array(call_graph.op_arrays[i], ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &info->ssa); + } if (zend_jit(call_graph.op_arrays[i], &info->ssa, NULL) != SUCCESS) { goto jit_failure; } @@ -4713,6 +4696,7 @@ static int zend_jit_make_stubs(void) for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) { dasm_setup(&dasm_state, dasm_actions); + zend_jit_align_stub(&dasm_state); if (!zend_jit_stubs[i].stub(&dasm_state)) { return 0; } @@ -4734,6 +4718,13 @@ static void zend_jit_globals_ctor(zend_jit_globals *jit_globals) zend_jit_trace_init_caches(); } +#ifdef ZTS +static void zend_jit_globals_dtor(zend_jit_globals *jit_globals) +{ + zend_jit_trace_free_caches(jit_globals); +} +#endif + static int zend_jit_parse_config_num(zend_long jit) { if (jit == 0) { @@ -4846,7 +4837,7 @@ ZEND_EXT_API int zend_jit_debug_config(zend_long old_val, zend_long new_val, int ZEND_EXT_API void zend_jit_init(void) { #ifdef ZTS - jit_globals_id = ts_allocate_id(&jit_globals_id, sizeof(zend_jit_globals), (ts_allocate_ctor) zend_jit_globals_ctor, NULL); + jit_globals_id = ts_allocate_id(&jit_globals_id, sizeof(zend_jit_globals), (ts_allocate_ctor) zend_jit_globals_ctor, (ts_allocate_dtor) zend_jit_globals_dtor); #else zend_jit_globals_ctor(&jit_globals); #endif @@ -4911,14 +4902,6 @@ ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, bool reattached) zend_jit_gdb_init(); #endif -#ifdef HAVE_OPROFILE - if (JIT_G(debug) & ZEND_JIT_DEBUG_OPROFILE) { - if (!zend_jit_oprofile_startup()) { - // TODO: error reporting and cleanup ??? - return FAILURE; - } - } -#endif #ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP zend_write_protect = pthread_jit_write_protect_supported_np(); #endif @@ -5033,12 +5016,6 @@ ZEND_EXT_API void zend_jit_shutdown(void) fprintf(stderr, "\nJIT memory usage: %td\n", (ptrdiff_t)((char*)*dasm_ptr - (char*)dasm_buf)); } -#ifdef HAVE_OPROFILE - if (JIT_G(debug) & ZEND_JIT_DEBUG_OPROFILE) { - zend_jit_oprofile_shutdown(); - } -#endif - #ifdef HAVE_GDB if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) { zend_jit_gdb_unregister(); @@ -5054,9 +5031,11 @@ ZEND_EXT_API void zend_jit_shutdown(void) zend_jit_perf_jitdump_close(); } #endif - if (JIT_G(exit_counters)) { - free(JIT_G(exit_counters)); - } +#ifdef ZTS + ts_free_id(jit_globals_id); +#else + zend_jit_trace_free_caches(&jit_globals); +#endif } static void zend_jit_reset_counters(void) diff --git a/ext/opcache/jit/zend_jit.h b/ext/opcache/jit/zend_jit.h index d22422181af9c..029bdd9a510a3 100644 --- a/ext/opcache/jit/zend_jit.h +++ b/ext/opcache/jit/zend_jit.h @@ -58,7 +58,6 @@ #define ZEND_JIT_DEBUG_PERF (1<<4) #define ZEND_JIT_DEBUG_PERF_DUMP (1<<5) -#define ZEND_JIT_DEBUG_OPROFILE (1<<6) #define ZEND_JIT_DEBUG_VTUNE (1<<7) #define ZEND_JIT_DEBUG_GDB (1<<8) @@ -116,6 +115,7 @@ typedef struct _zend_jit_globals { zend_long max_recursive_calls; /* max number of recursive inlined call unrolls */ zend_long max_recursive_returns; /* max number of recursive inlined return unrolls */ zend_long max_polymorphic_calls; /* max number of inlined polymorphic calls */ + zend_long max_trace_length; /* max length of a single trace */ zend_sym_node *symbols; /* symbols for disassembler */ diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index 712e3ba113606..b64711b59fb38 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -1464,7 +1464,7 @@ static bool logical_immediate_p(uint64_t value, uint32_t reg_size) || do { || if (!((var_info) & MAY_BE_GUARD) || && has_concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { -|| zend_uchar type = concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); +|| uint8_t type = concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); || if (type == IS_STRING && !ZEND_DEBUG) { | EXT_CALL _efree, tmp_reg || break; @@ -2854,6 +2854,12 @@ static int zend_jit_align_func(dasm_State **Dst) return 1; } +static int zend_jit_align_stub(dasm_State **Dst) +{ + |.align 16 + return 1; +} + static int zend_jit_prologue(dasm_State **Dst) { if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { @@ -3606,7 +3612,7 @@ static int zend_jit_load_var(dasm_State **Dst, uint32_t info, int var, zend_reg return zend_jit_load_reg(Dst, src, dst, info); } -static int zend_jit_invalidate_var_if_necessary(dasm_State **Dst, zend_uchar op_type, zend_jit_addr addr, znode_op op) +static int zend_jit_invalidate_var_if_necessary(dasm_State **Dst, uint8_t op_type, zend_jit_addr addr, znode_op op) { if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) { zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var); @@ -4001,7 +4007,7 @@ static int zend_jit_opline_uses_reg(const zend_op *opline, int8_t reg) static int zend_jit_math_long_long(dasm_State **Dst, const zend_op *opline, - zend_uchar opcode, + uint8_t opcode, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, @@ -4219,7 +4225,7 @@ static int zend_jit_math_long_long(dasm_State **Dst, } static int zend_jit_math_long_double(dasm_State **Dst, - zend_uchar opcode, + uint8_t opcode, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, @@ -4252,7 +4258,7 @@ static int zend_jit_math_long_double(dasm_State **Dst, } static int zend_jit_math_double_long(dasm_State **Dst, - zend_uchar opcode, + uint8_t opcode, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, @@ -4315,7 +4321,7 @@ static int zend_jit_math_double_long(dasm_State **Dst, } static int zend_jit_math_double_double(dasm_State **Dst, - zend_uchar opcode, + uint8_t opcode, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, @@ -4376,12 +4382,12 @@ static int zend_jit_math_double_double(dasm_State **Dst, static int zend_jit_math_helper(dasm_State **Dst, const zend_op *opline, - zend_uchar opcode, - zend_uchar op1_type, + uint8_t opcode, + uint8_t op1_type, znode_op op1, zend_jit_addr op1_addr, uint32_t op1_info, - zend_uchar op2_type, + uint8_t op2_type, znode_op op2, zend_jit_addr op2_addr, uint32_t op2_info, @@ -4654,13 +4660,13 @@ static int zend_jit_add_arrays(dasm_State **Dst, const zend_op *opline, uint32_t static int zend_jit_long_math_helper(dasm_State **Dst, const zend_op *opline, - zend_uchar opcode, - zend_uchar op1_type, + uint8_t opcode, + uint8_t op1_type, znode_op op1, zend_jit_addr op1_addr, uint32_t op1_info, zend_ssa_range *op1_range, - zend_uchar op2_type, + uint8_t op2_type, znode_op op2, zend_jit_addr op2_addr, uint32_t op2_info, @@ -4829,7 +4835,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst, op2_reg = Z_REG(op2_addr); } - if (!op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) { + if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) { | cbz Rx(op2_reg), >1 |.cold_code |1: @@ -4995,11 +5001,11 @@ static int zend_jit_long_math(dasm_State **Dst, const zend_op *opline, uint32_t static int zend_jit_concat_helper(dasm_State **Dst, const zend_op *opline, - zend_uchar op1_type, + uint8_t op1_type, znode_op op1, zend_jit_addr op1_addr, uint32_t op1_info, - zend_uchar op2_type, + uint8_t op2_type, znode_op op2, zend_jit_addr op2_addr, uint32_t op2_info, @@ -5569,7 +5575,7 @@ static int zend_jit_simple_assign(dasm_State **Dst, zend_jit_addr var_addr, uint32_t var_info, uint32_t var_def_info, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, uint32_t val_info, zend_jit_addr res_addr, @@ -5727,7 +5733,7 @@ static int zend_jit_simple_assign(dasm_State **Dst, static int zend_jit_assign_to_typed_ref(dasm_State **Dst, const zend_op *opline, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, zend_jit_addr res_addr, bool check_exception) @@ -5743,22 +5749,31 @@ static int zend_jit_assign_to_typed_ref(dasm_State **Dst, if (opline) { | SET_EX_OPLINE opline, REG0 } - if (val_type == IS_CONST) { - | EXT_CALL zend_jit_assign_const_to_typed_ref, REG0 - } else if (val_type == IS_TMP_VAR) { - | EXT_CALL zend_jit_assign_tmp_to_typed_ref, REG0 - } else if (val_type == IS_VAR) { - | EXT_CALL zend_jit_assign_var_to_typed_ref, REG0 - } else if (val_type == IS_CV) { - | EXT_CALL zend_jit_assign_cv_to_typed_ref, REG0 + if (!res_addr) { + if (val_type == IS_CONST) { + | EXT_CALL zend_jit_assign_const_to_typed_ref, REG0 + } else if (val_type == IS_TMP_VAR) { + | EXT_CALL zend_jit_assign_tmp_to_typed_ref, REG0 + } else if (val_type == IS_VAR) { + | EXT_CALL zend_jit_assign_var_to_typed_ref, REG0 + } else if (val_type == IS_CV) { + | EXT_CALL zend_jit_assign_cv_to_typed_ref, REG0 + } else { + ZEND_UNREACHABLE(); + } } else { - ZEND_UNREACHABLE(); - } - if (res_addr) { - zend_jit_addr ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_X0, 0); // RETVAL - - | ZVAL_COPY_VALUE res_addr, -1, ret_addr, -1, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF -1, REG1w, REG2, TMP1w + | LOAD_ZVAL_ADDR CARG3, res_addr + if (val_type == IS_CONST) { + | EXT_CALL zend_jit_assign_const_to_typed_ref2, REG0 + } else if (val_type == IS_TMP_VAR) { + | EXT_CALL zend_jit_assign_tmp_to_typed_ref2, REG0 + } else if (val_type == IS_VAR) { + | EXT_CALL zend_jit_assign_var_to_typed_ref2, REG0 + } else if (val_type == IS_CV) { + | EXT_CALL zend_jit_assign_cv_to_typed_ref2, REG0 + } else { + ZEND_UNREACHABLE(); + } } if (check_exception) { | // if (UNEXPECTED(EG(exception) != NULL)) { @@ -5779,7 +5794,7 @@ static int zend_jit_assign_to_variable_call(dasm_State **Dst, zend_jit_addr var_addr, uint32_t __var_info, uint32_t __var_def_info, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, uint32_t val_info, zend_jit_addr __res_addr, @@ -5862,7 +5877,7 @@ static int zend_jit_assign_to_variable(dasm_State **Dst, zend_jit_addr var_addr, uint32_t var_info, uint32_t var_def_info, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, uint32_t val_info, zend_jit_addr res_addr, @@ -6536,7 +6551,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, zend_ssa_range *op2_range, zend_jit_addr op2_addr, zend_jit_addr res_addr, - zend_uchar smart_branch_opcode, + uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr, @@ -6796,7 +6811,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, return 1; } -static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, bool swap, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, bool swap, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { if (smart_branch_opcode) { if (smart_branch_opcode == ZEND_JMPZ) { @@ -7095,7 +7110,7 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z return 1; } -static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { zend_reg tmp_reg = ZREG_FPR0; @@ -7105,7 +7120,7 @@ static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zen return zend_jit_cmp_double_common(Dst, opline, res_addr, 0, smart_branch_opcode, target_label, target_label2, exit_addr); } -static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { zend_reg tmp_reg = ZREG_FPR0; @@ -7115,7 +7130,7 @@ static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zen return zend_jit_cmp_double_common(Dst, opline, res_addr, /* swap */ 1, smart_branch_opcode, target_label, target_label2, exit_addr); } -static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { bool swap = 0; @@ -7134,7 +7149,7 @@ static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, z return zend_jit_cmp_double_common(Dst, opline, res_addr, swap, smart_branch_opcode, target_label, target_label2, exit_addr); } -static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { | tst RETVALw, RETVALw if (smart_branch_opcode) { @@ -7268,7 +7283,7 @@ static int zend_jit_cmp(dasm_State **Dst, zend_jit_addr op2_addr, zend_jit_addr res_addr, int may_throw, - zend_uchar smart_branch_opcode, + uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr, @@ -7496,7 +7511,7 @@ static int zend_jit_identical(dasm_State **Dst, zend_jit_addr op2_addr, zend_jit_addr res_addr, int may_throw, - zend_uchar smart_branch_opcode, + uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr, @@ -7623,7 +7638,6 @@ static int zend_jit_identical(dasm_State **Dst, } op1_addr = real_addr; } - | LOAD_ZVAL_ADDR FCARG1x, op1_addr } if (opline->op2_type != IS_CONST) { if (Z_MODE(op2_addr) == IS_REG) { @@ -7635,6 +7649,9 @@ static int zend_jit_identical(dasm_State **Dst, } | LOAD_ZVAL_ADDR FCARG2x, op2_addr } + if (opline->op1_type != IS_CONST) { + | LOAD_ZVAL_ADDR FCARG1x, op1_addr + } } if ((op1_info & op2_info & MAY_BE_ANY) == 0) { @@ -7876,7 +7893,7 @@ static int zend_jit_identical(dasm_State **Dst, return 1; } -static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, zend_uchar branch_opcode, const void *exit_addr) +static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, uint8_t branch_opcode, const void *exit_addr) { uint32_t true_label = -1; uint32_t false_label = -1; @@ -8732,7 +8749,17 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t | // if (CACHED_PTR(opline->result.num)) | ldr REG2, EX->run_time_cache | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG2, opline->result.num, TMP1 - | cbz REG0, >1 + if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE + && func + && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) + && opline->opcode != ZEND_INIT_FCALL) { + /* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */ + | LOAD_ADDR REG1, ((ptrdiff_t)func) + | cmp REG0, REG1 + | bne >1 + } else { + | cbz REG0, >1 + } |.cold_code |1: if (opline->opcode == ZEND_INIT_FCALL @@ -9584,13 +9611,17 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend zend_jit_reset_last_valid_opline(); - | // fbc->internal_function.handler(call, ret); + | // (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret); | mov FCARG1x, RX - if (func) { - | EXT_CALL func->internal_function.handler, REG0 + if (zend_execute_internal) { + | EXT_CALL zend_execute_internal, REG0 } else { - | ldr TMP1, [REG0, #offsetof(zend_internal_function, handler)] - | blr TMP1 + if (func) { + | EXT_CALL func->internal_function.handler, REG0 + } else { + | ldr TMP1, [REG0, #offsetof(zend_internal_function, handler)] + | blr TMP1 + } } if (ZEND_OBSERVER_ENABLED) { @@ -10185,7 +10216,7 @@ static int zend_jit_check_func_arg(dasm_State **Dst, const zend_op *opline) return 1; } -static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2) +static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2) { if (smart_branch_opcode) { if (smart_branch_opcode == ZEND_JMPZ) { @@ -10209,7 +10240,7 @@ static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, return 1; } -static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label) +static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp, uint8_t smart_branch_opcode, uint32_t target_label) { if (smart_branch_opcode) { if (smart_branch_opcode == ZEND_JMPZ) { @@ -10233,7 +10264,7 @@ static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp return 1; } -static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { uint32_t defined_label = (uint32_t)-1; uint32_t undefined_label = (uint32_t)-1; @@ -10324,7 +10355,7 @@ static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, zend_uchar return 1; } -static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { uint32_t mask; zend_jit_addr op1_addr = OP1_ADDR(); @@ -10390,7 +10421,7 @@ static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t } } else { bool invert = 0; - zend_uchar type; + uint8_t type; switch (mask) { case MAY_BE_NULL: type = IS_NULL; break; @@ -11616,7 +11647,7 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst, uint32_t op2_info, uint8_t dim_type, int may_throw, - zend_uchar smart_branch_opcode, + uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) @@ -12218,7 +12249,7 @@ static int zend_jit_fetch_obj(dasm_State **Dst, type_loaded = 1; prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); if (opline->opcode == ZEND_FETCH_OBJ_W - && (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS))) { + && (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) { uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS; | ldr REG0, EX->run_time_cache @@ -12240,6 +12271,17 @@ static int zend_jit_fetch_obj(dasm_State **Dst, | SET_ZVAL_TYPE_INFO res_addr, IS_OBJECT_EX, TMP1w, TMP2 | b >9 |2: + | ldr REG0w, [FCARG1x, #offsetof(zval, u2.extra)] + | TST_32_WITH_CONST REG0w, IS_PROP_REINITABLE, TMP1w + | beq >6 + | and REG0w, REG0w, #(~IS_PROP_REINITABLE) + | str REG0w, [FCARG1x, #offsetof(zval, u2.extra)] + if (flags) { + | b >3 + } else { + | b >4 + } + |6: | mov FCARG1x, FCARG2x | SET_EX_OPLINE opline, REG0 | EXT_CALL zend_readonly_property_modification_error, REG0 @@ -12293,12 +12335,20 @@ static int zend_jit_fetch_obj(dasm_State **Dst, | b >9 |.cold_code |4: + | ldr REG0w, [FCARG1x, #(prop_info->offset + offsetof(zval, u2.extra))] + | TST_32_WITH_CONST REG0w, IS_PROP_REINITABLE, TMP1w + | beq >6 + | and REG0w, REG0w, #(~IS_PROP_REINITABLE) + | str REG0w, [FCARG1x, #(prop_info->offset + offsetof(zval, u2.extra))] + | b >4 + |6: | LOAD_ADDR FCARG1x, prop_info | SET_EX_OPLINE opline, REG0 | EXT_CALL zend_readonly_property_modification_error, REG0 | SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR, TMP1w, TMP2 | b >9 |.code + |4: } if (opline->opcode == ZEND_FETCH_OBJ_W && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS) @@ -12702,7 +12752,7 @@ static int zend_jit_incdec_obj(dasm_State **Dst, | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)] | cmp REG2, TMP1 | bne >7 - if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { | MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, REG0, (opline->extended_value + sizeof(void*) * 2), TMP1 | cbnz TMP1, >7 } @@ -13136,7 +13186,7 @@ static int zend_jit_assign_obj_op(dasm_State **Dst, | ldr TMP2, [FCARG1x, #offsetof(zend_object, ce)] | cmp REG2, TMP2 | bne >7 - if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { | MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, REG0, ((opline+1)->extended_value + sizeof(void*) * 2), TMP1 | cbnz TMP1, >7 } @@ -13514,7 +13564,7 @@ static int zend_jit_assign_obj(dasm_State **Dst, | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)] | cmp REG2, TMP1 | bne >5 - if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, (opline->extended_value + sizeof(void*) * 2), TMP1 } | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->extended_value + sizeof(void*)), TMP1 @@ -13525,7 +13575,7 @@ static int zend_jit_assign_obj(dasm_State **Dst, | IF_TYPE TMP1w, IS_UNDEF, >5 | mov FCARG1x, TMP2 prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { | cbnz FCARG2x, >1 |.cold_code |1: @@ -14313,7 +14363,7 @@ static bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *opline, return 1; } -static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); @@ -14403,10 +14453,24 @@ static int zend_jit_fe_reset(dasm_State **Dst, const zend_op *opline, uint32_t o return 1; } -static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, zend_uchar exit_opcode, const void *exit_addr) +static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, uint8_t exit_opcode, const void *exit_addr) { zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); + if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) { + /* empty array */ + if (exit_addr) { + if (exit_opcode == ZEND_JMP) { + | b &exit_addr + } else { + | b >3 + } + } else { + | b =>target_label + } + return 1; + } + | // array = EX_VAR(opline->op1.var); | // fe_ht = Z_ARRVAL_P(array); | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 @@ -14682,7 +14746,7 @@ static int zend_jit_fetch_constant(dasm_State **Dst, return 1; } -static int zend_jit_in_array(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_in_array(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2)); zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); diff --git a/ext/opcache/jit/zend_jit_disasm.c b/ext/opcache/jit/zend_jit_disasm.c index 8ce35f198c0e4..41b75979c515d 100644 --- a/ext/opcache/jit/zend_jit_disasm.c +++ b/ext/opcache/jit/zend_jit_disasm.c @@ -21,7 +21,7 @@ #ifdef HAVE_CAPSTONE # define HAVE_DISASM 1 -# include +# include # define HAVE_CAPSTONE_ITER 1 #elif ZEND_JIT_TARGET_X86 # define HAVE_DISASM 1 @@ -262,7 +262,7 @@ static const char* zend_jit_disasm_resolver( ((void)ud); # endif const char *name; - void *a = (void*)(zend_uintptr_t)(addr); + void *a = (void*)(uintptr_t)(addr); Dl_info info; name = zend_jit_disasm_find_symbol(addr, offset); @@ -659,6 +659,10 @@ static int zend_jit_disasm_init(void) REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref); REGISTER_HELPER(zend_jit_assign_var_to_typed_ref); REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref); + REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2); + REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2); + REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2); + REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2); REGISTER_HELPER(zend_jit_pre_inc_typed_ref); REGISTER_HELPER(zend_jit_pre_dec_typed_ref); REGISTER_HELPER(zend_jit_post_inc_typed_ref); diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 6d9b7ec8ffdcd..41c7e14a804cb 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -21,20 +21,25 @@ static ZEND_COLD void undef_result_after_exception(void) { const zend_op *opline = EG(opline_before_exception); ZEND_ASSERT(EG(exception)); - if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { + if (opline && opline->result_type & (IS_VAR | IS_TMP_VAR)) { zend_execute_data *execute_data = EG(current_execute_data); ZVAL_UNDEF(EX_VAR(opline->result.var)); } } -static ZEND_COLD void zend_jit_illegal_offset(void) +static ZEND_COLD void zend_jit_illegal_array_offset(const zval *offset) { - zend_type_error("Illegal offset type"); + zend_type_error("Cannot access offset of type %s on array", zend_get_type_by_const(Z_TYPE_P(offset))); +} + +static ZEND_COLD void zend_jit_illegal_empty_or_isset_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s in isset or empty", zend_get_type_by_const(Z_TYPE_P(offset))); } static ZEND_COLD void zend_jit_illegal_string_offset(zval *offset) { - zend_type_error("Cannot access offset of type %s on string", zend_zval_type_name(offset)); + zend_type_error("Cannot access offset of type %s on string", zend_zval_value_name(offset)); } static zend_never_inline zend_function* ZEND_FASTCALL _zend_jit_init_func_run_time_cache(zend_op_array *op_array) /* {{{ */ @@ -112,7 +117,7 @@ static ZEND_COLD void ZEND_FASTCALL zend_jit_invalid_method_call(zval *object) object = &EG(uninitialized_zval); } zend_throw_error(NULL, "Call to a member function %s() on %s", - Z_STRVAL_P(function_name), zend_zval_type_name(object)); + Z_STRVAL_P(function_name), zend_zval_value_name(object)); } static ZEND_COLD void ZEND_FASTCALL zend_jit_invalid_method_call_tmp(zval *object) @@ -488,7 +493,7 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim, hval = 1; goto num_index; default: - zend_jit_illegal_offset(); + zend_jit_illegal_array_offset(dim); undef_result_after_exception(); return; } @@ -630,7 +635,7 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim hval = 1; goto num_index; default: - zend_jit_illegal_offset(); + zend_jit_illegal_array_offset(dim); undef_result_after_exception(); return; } @@ -732,7 +737,7 @@ static int ZEND_FASTCALL zend_jit_fetch_dim_isset_helper(zend_array *ht, zval *d hval = 1; goto num_index; default: - zend_type_error("Illegal offset type in isset or empty"); + zend_jit_illegal_empty_or_isset_offset(dim); return 0; } @@ -785,7 +790,7 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_rw_helper(zend_array *ht, zval *di if (UNEXPECTED(opline->opcode == ZEND_HANDLE_EXCEPTION)) { opline = EG(opline_before_exception); } - if (!zend_jit_undefined_op_helper_write(ht, opline->op2.var)) { + if (opline && !zend_jit_undefined_op_helper_write(ht, opline->op2.var)) { if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -868,7 +873,7 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_rw_helper(zend_array *ht, zval *di hval = 1; goto num_index; default: - zend_jit_illegal_offset(); + zend_jit_illegal_array_offset(dim); undef_result_after_exception(); return NULL; } @@ -1001,9 +1006,10 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim hval = 1; goto num_index; default: - zend_jit_illegal_offset(); + zend_jit_illegal_array_offset(dim); undef_result_after_exception(); - if ((EG(opline_before_exception)+1)->opcode == ZEND_OP_DATA + if (EG(opline_before_exception) + && (EG(opline_before_exception)+1)->opcode == ZEND_OP_DATA && ((EG(opline_before_exception)+1)->op1_type & (IS_VAR|IS_TMP_VAR))) { zend_execute_data *execute_data = EG(current_execute_data); @@ -1074,13 +1080,13 @@ static zend_always_inline zend_string* zend_jit_fetch_dim_str_offset(zend_string zend_long real_offset = (zend_long)ZSTR_LEN(str) + offset; if (EXPECTED(real_offset >= 0)) { - return ZSTR_CHAR((zend_uchar)ZSTR_VAL(str)[real_offset]); + return ZSTR_CHAR((uint8_t)ZSTR_VAL(str)[real_offset]); } } zend_error(E_WARNING, "Uninitialized string offset " ZEND_LONG_FMT, offset); return ZSTR_EMPTY_ALLOC(); } else { - return ZSTR_CHAR((zend_uchar)ZSTR_VAL(str)[offset]); + return ZSTR_CHAR((uint8_t)ZSTR_VAL(str)[offset]); } } @@ -1149,13 +1155,13 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_str_is_helper(zend_string *str, zva zend_long real_offset = (zend_long)ZSTR_LEN(str) + offset; if (real_offset >= 0) { - ZVAL_CHAR(result, (zend_uchar)ZSTR_VAL(str)[real_offset]); + ZVAL_CHAR(result, (uint8_t)ZSTR_VAL(str)[real_offset]); return; } } ZVAL_NULL(result); } else { - ZVAL_CHAR(result, (zend_uchar)ZSTR_VAL(str)[offset]); + ZVAL_CHAR(result, (uint8_t)ZSTR_VAL(str)[offset]); } } @@ -1215,7 +1221,7 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result) { - zend_uchar c; + uint8_t c; size_t string_len; zend_long offset; zend_string *s; @@ -1304,11 +1310,11 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, } string_len = ZSTR_LEN(tmp); - c = (zend_uchar)ZSTR_VAL(tmp)[0]; + c = (uint8_t)ZSTR_VAL(tmp)[0]; zend_string_release(tmp); } else { string_len = Z_STRLEN_P(value); - c = (zend_uchar)Z_STRVAL_P(value)[0]; + c = (uint8_t)Z_STRVAL_P(value)[0]; } @@ -1632,6 +1638,7 @@ static void ZEND_FASTCALL zend_jit_fast_assign_concat_helper(zval *op1, zval *op size_t op2_len = Z_STRLEN_P(op2); size_t result_len = op1_len + op2_len; zend_string *result_str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2)); if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) { zend_throw_error(NULL, "String size overflow"); @@ -1655,6 +1662,7 @@ static void ZEND_FASTCALL zend_jit_fast_assign_concat_helper(zval *op1, zval *op memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len); } while(0); + GC_ADD_FLAGS(result_str, flags); ZVAL_NEW_STR(op1, result_str); memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len); ZSTR_VAL(result_str)[result_len] = '\0'; @@ -1666,6 +1674,7 @@ static void ZEND_FASTCALL zend_jit_fast_concat_helper(zval *result, zval *op1, z size_t op2_len = Z_STRLEN_P(op2); size_t result_len = op1_len + op2_len; zend_string *result_str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2)); if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) { zend_throw_error(NULL, "String size overflow"); @@ -1673,6 +1682,7 @@ static void ZEND_FASTCALL zend_jit_fast_concat_helper(zval *result, zval *op1, z } result_str = zend_string_alloc(result_len, 0); + GC_ADD_FLAGS(result_str, flags); memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len); ZVAL_NEW_STR(result, result_str); @@ -1688,6 +1698,7 @@ static void ZEND_FASTCALL zend_jit_fast_concat_tmp_helper(zval *result, zval *op size_t op2_len = Z_STRLEN_P(op2); size_t result_len = op1_len + op2_len; zend_string *result_str; + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2)); if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) { zend_throw_error(NULL, "String size overflow"); @@ -1709,6 +1720,7 @@ static void ZEND_FASTCALL zend_jit_fast_concat_tmp_helper(zval *result, zval *op memcpy(ZSTR_VAL(result_str), ZSTR_VAL(op1_str), op1_len); } while (0); + GC_ADD_FLAGS(result_str, flags); ZVAL_NEW_STR(result, result_str); memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len); @@ -2134,7 +2146,7 @@ static void ZEND_FASTCALL zend_jit_vm_stack_free_args_helper(zend_execute_data * zend_vm_stack_free_args(call); } -static zend_always_inline zval* zend_jit_assign_to_typed_ref_helper(zend_reference *ref, zval *value, zend_uchar value_type) +static zend_always_inline zval* zend_jit_assign_to_typed_ref_helper(zend_reference *ref, zval *value, uint8_t value_type) { zval variable; @@ -2174,6 +2186,51 @@ static zval* ZEND_FASTCALL zend_jit_assign_cv_to_typed_ref(zend_reference *ref, return zend_jit_assign_to_typed_ref_helper(ref, value, IS_CV); } +static zend_always_inline zval* zend_jit_assign_to_typed_ref2_helper(zend_reference *ref, zval *value, zval *result, uint8_t value_type) +{ + zval variable, *ret; + zend_refcounted *garbage = NULL; + + ZVAL_REF(&variable, ref); + ret = zend_assign_to_variable_ex(&variable, value, value_type, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)), &garbage); + ZVAL_COPY(result, ret); + if (garbage) { + GC_DTOR(garbage); + } + return ret; +} + +static zval* ZEND_FASTCALL zend_jit_assign_const_to_typed_ref2(zend_reference *ref, zval *value, zval *result) +{ + return zend_jit_assign_to_typed_ref2_helper(ref, value, result, IS_CONST); +} + +static zval* ZEND_FASTCALL zend_jit_assign_tmp_to_typed_ref2(zend_reference *ref, zval *value, zval *result) +{ + return zend_jit_assign_to_typed_ref2_helper(ref, value, result, IS_TMP_VAR); +} + +static zval* ZEND_FASTCALL zend_jit_assign_var_to_typed_ref2(zend_reference *ref, zval *value, zval *result) +{ + return zend_jit_assign_to_typed_ref2_helper(ref, value, result, IS_VAR); +} + +static zval* ZEND_FASTCALL zend_jit_assign_cv_to_typed_ref2(zend_reference *ref, zval *value, zval *result) +{ + if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) { + const zend_op *opline = EG(current_execute_data)->opline; + uint32_t var; + if (opline->opcode == ZEND_ASSIGN) { + var = opline->op2.var; + } else { + ZEND_ASSERT((opline + 1)->opcode == ZEND_OP_DATA); + var = (opline + 1)->op1.var; + } + zend_jit_undefined_op_helper(var); + value = &EG(uninitialized_zval); + } + return zend_jit_assign_to_typed_ref2_helper(ref, value, result, IS_CV); +} static zend_property_info *zend_jit_get_prop_not_accepting_double(zend_reference *ref) { @@ -2342,19 +2399,19 @@ static void ZEND_FASTCALL zend_jit_only_vars_by_reference(zval *arg) static void ZEND_FASTCALL zend_jit_invalid_array_access(zval *container) { - zend_error(E_WARNING, "Trying to access array offset on value of type %s", zend_zval_type_name(container)); + zend_error(E_WARNING, "Trying to access array offset on %s", zend_zval_value_name(container)); } static void ZEND_FASTCALL zend_jit_invalid_property_read(zval *container, const char *property_name) { - zend_error(E_WARNING, "Attempt to read property \"%s\" on %s", property_name, zend_zval_type_name(container)); + zend_error(E_WARNING, "Attempt to read property \"%s\" on %s", property_name, zend_zval_value_name(container)); } static void ZEND_FASTCALL zend_jit_invalid_property_write(zval *container, const char *property_name) { zend_throw_error(NULL, "Attempt to modify property \"%s\" on %s", - property_name, zend_zval_type_name(container)); + property_name, zend_zval_value_name(container)); } static void ZEND_FASTCALL zend_jit_invalid_property_incdec(zval *container, const char *property_name) @@ -2372,7 +2429,7 @@ static void ZEND_FASTCALL zend_jit_invalid_property_incdec(zval *container, cons } zend_throw_error(NULL, "Attempt to increment/decrement property \"%s\" on %s", - property_name, zend_zval_type_name(container)); + property_name, zend_zval_value_name(container)); if (opline->op1_type == IS_VAR) { zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); } @@ -2382,7 +2439,7 @@ static void ZEND_FASTCALL zend_jit_invalid_property_assign(zval *container, cons { zend_throw_error(NULL, "Attempt to assign property \"%s\" on %s", - property_name, zend_zval_type_name(container)); + property_name, zend_zval_value_name(container)); } static void ZEND_FASTCALL zend_jit_invalid_property_assign_op(zval *container, const char *property_name) @@ -2484,7 +2541,7 @@ static void ZEND_FASTCALL zend_jit_assign_obj_helper(zend_object *zobj, zend_str ZVAL_DEREF(value); value = zobj->handlers->write_property(zobj, name, value, cache_slot); - if (result) { + if (result && value) { ZVAL_COPY_DEREF(result, value); } } @@ -2492,6 +2549,7 @@ static void ZEND_FASTCALL zend_jit_assign_obj_helper(zend_object *zobj, zend_str static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend_property_info *info, zval *value, zval *result) { zend_execute_data *execute_data = EG(current_execute_data); + zend_refcounted *garbage = NULL; zval tmp; if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) { @@ -2501,7 +2559,7 @@ static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend value = &EG(uninitialized_zval); } - if (UNEXPECTED(info->flags & ZEND_ACC_READONLY)) { + if (UNEXPECTED((info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE))) { zend_readonly_property_modification_error(info); if (result) { ZVAL_UNDEF(result); @@ -2520,10 +2578,15 @@ static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend return; } - value = zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE; + + value = zend_assign_to_variable_ex(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (result) { ZVAL_COPY_DEREF(result, value); } + if (garbage) { + GC_DTOR(garbage); + } } static zend_never_inline void _zend_jit_assign_op_overloaded_property(zend_object *object, zend_string *name, void **cache_slot, zval *value, binary_op_type binary_op) @@ -2558,7 +2621,7 @@ static void ZEND_FASTCALL zend_jit_assign_op_to_typed_prop(zval *zptr, zend_prop zend_execute_data *execute_data = EG(current_execute_data); zval z_copy; - if (UNEXPECTED(prop_info->flags & ZEND_ACC_READONLY)) { + if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(zptr) & IS_PROP_REINITABLE))) { zend_readonly_property_modification_error(prop_info); return; } @@ -2573,6 +2636,7 @@ static void ZEND_FASTCALL zend_jit_assign_op_to_typed_prop(zval *zptr, zend_prop binary_op(&z_copy, zptr, value); if (EXPECTED(zend_verify_property_type(prop_info, &z_copy, EX_USES_STRICT_TYPES()))) { + Z_PROP_FLAG_P(zptr) &= ~IS_PROP_REINITABLE; zval_ptr_dtor(zptr); ZVAL_COPY_VALUE(zptr, &z_copy); } else { @@ -2650,6 +2714,13 @@ static ZEND_COLD zend_long _zend_jit_throw_dec_prop_error(zend_property_info *pr static void ZEND_FASTCALL zend_jit_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info) { + ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF); + + if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(var_ptr) & IS_PROP_REINITABLE))) { + zend_readonly_property_modification_error(prop_info); + return; + } + zend_execute_data *execute_data = EG(current_execute_data); zval tmp; @@ -2662,17 +2733,27 @@ static void ZEND_FASTCALL zend_jit_inc_typed_prop(zval *var_ptr, zend_property_i if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) { zend_long val = _zend_jit_throw_inc_prop_error(prop_info); ZVAL_LONG(var_ptr, val); + } else { + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; } } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) { zval_ptr_dtor(var_ptr); ZVAL_COPY_VALUE(var_ptr, &tmp); } else { + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; zval_ptr_dtor(&tmp); } } static void ZEND_FASTCALL zend_jit_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info) { + ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF); + + if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(var_ptr) & IS_PROP_REINITABLE))) { + zend_readonly_property_modification_error(prop_info); + return; + } + zend_execute_data *execute_data = EG(current_execute_data); zval tmp; @@ -2685,11 +2766,14 @@ static void ZEND_FASTCALL zend_jit_dec_typed_prop(zval *var_ptr, zend_property_i if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) { zend_long val = _zend_jit_throw_dec_prop_error(prop_info); ZVAL_LONG(var_ptr, val); + } else { + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; } } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) { zval_ptr_dtor(var_ptr); ZVAL_COPY_VALUE(var_ptr, &tmp); } else { + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; zval_ptr_dtor(&tmp); } } @@ -2710,6 +2794,16 @@ static void ZEND_FASTCALL zend_jit_pre_dec_typed_prop(zval *var_ptr, zend_proper static void ZEND_FASTCALL zend_jit_post_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result) { + ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF); + + if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(var_ptr) & IS_PROP_REINITABLE))) { + zend_readonly_property_modification_error(prop_info); + if (result) { + ZVAL_UNDEF(result); + } + return; + } + zend_execute_data *execute_data = EG(current_execute_data); ZVAL_DEREF(var_ptr); @@ -2721,16 +2815,30 @@ static void ZEND_FASTCALL zend_jit_post_inc_typed_prop(zval *var_ptr, zend_prope if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) { zend_long val = _zend_jit_throw_inc_prop_error(prop_info); ZVAL_LONG(var_ptr, val); + } else { + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; } } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) { zval_ptr_dtor(var_ptr); ZVAL_COPY_VALUE(var_ptr, result); ZVAL_UNDEF(result); + } else { + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; } } static void ZEND_FASTCALL zend_jit_post_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result) { + ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF); + + if (UNEXPECTED((prop_info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(var_ptr) & IS_PROP_REINITABLE))) { + zend_readonly_property_modification_error(prop_info); + if (result) { + ZVAL_UNDEF(result); + } + return; + } + zend_execute_data *execute_data = EG(current_execute_data); ZVAL_DEREF(var_ptr); @@ -2742,11 +2850,15 @@ static void ZEND_FASTCALL zend_jit_post_dec_typed_prop(zval *var_ptr, zend_prope if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) { zend_long val = _zend_jit_throw_dec_prop_error(prop_info); ZVAL_LONG(var_ptr, val); + } else { + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; } } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) { zval_ptr_dtor(var_ptr); ZVAL_COPY_VALUE(var_ptr, result); ZVAL_UNDEF(result); + } else { + Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE; } } @@ -3041,13 +3153,16 @@ static zend_string* ZEND_FASTCALL zend_jit_rope_end(zend_string **rope, uint32_t zend_string *ret; uint32_t i; size_t len = 0; - char *target; + uint32_t flags = ZSTR_COPYABLE_CONCAT_PROPERTIES; for (i = 0; i <= count; i++) { + flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(rope[i]); len += ZSTR_LEN(rope[i]); } ret = zend_string_alloc(len, 0); - target = ZSTR_VAL(ret); + GC_ADD_FLAGS(ret, flags); + + char *target = ZSTR_VAL(ret); for (i = 0; i <= count; i++) { memcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i])); target += ZSTR_LEN(rope[i]); diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index fb640ff9b97ca..606efebe0ea9d 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -157,7 +157,7 @@ typedef uintptr_t zend_jit_addr; zend_ival_is_last_use(ra[ssa_op->op], ssa_op - ssa->ops) \ ) : ZREG_NONE) -static zend_always_inline zend_jit_addr _zend_jit_decode_op(zend_uchar op_type, znode_op op, const zend_op *opline, zend_reg reg) +static zend_always_inline zend_jit_addr _zend_jit_decode_op(uint8_t op_type, znode_op op, const zend_op *opline, zend_reg reg) { if (op_type == IS_CONST) { #if ZEND_USE_ABS_CONST_ADDR diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index ff7c84e07c6eb..ed8cdbc95b590 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -46,7 +46,7 @@ static zend_always_inline const char *zend_jit_trace_star_desc(uint8_t trace_fla } } -static int zend_jit_trace_startup(zend_bool reattached) +static int zend_jit_trace_startup(bool reattached) { if (!reattached) { zend_jit_traces = (zend_jit_trace_info*)zend_shared_alloc(sizeof(zend_jit_trace_info) * JIT_G(max_root_traces)); @@ -94,6 +94,7 @@ static const void *zend_jit_trace_allocate_exit_group(uint32_t n) dasm_init(&dasm_state, DASM_MAXSECTION); dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX); dasm_setup(&dasm_state, dasm_actions); + zend_jit_align_stub(&dasm_state); zend_jit_trace_exit_group_stub(&dasm_state, n); sprintf(name, "jit$$trace_exit_%d", n); @@ -247,6 +248,13 @@ static void zend_jit_trace_add_code(const void *start, uint32_t size) t->code_size = size; } +/** + * Locate a trace in the #zend_jit_traces array with the specified + * #code_start address. + * + * @return the #zend_jit_traces index or 0 if no such #code_start + * address was found + */ static uint32_t zend_jit_find_trace(const void *addr) { uint32_t i; @@ -256,7 +264,6 @@ static uint32_t zend_jit_find_trace(const void *addr) return i; } } - ZEND_UNREACHABLE(); return 0; } @@ -365,7 +372,7 @@ static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op return 0; } -static zend_always_inline uint32_t zend_jit_trace_type_to_info_ex(zend_uchar type, uint32_t info) +static zend_always_inline uint32_t zend_jit_trace_type_to_info_ex(uint8_t type, uint32_t info) { if (type == IS_UNKNOWN) { return info; @@ -380,7 +387,7 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info_ex(zend_uchar typ } } -static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type) +static zend_always_inline uint32_t zend_jit_trace_type_to_info(uint8_t type) { return zend_jit_trace_type_to_info_ex(type, -1); } @@ -473,7 +480,7 @@ static zend_jit_trace_stack_frame* zend_jit_trace_ret_frame(zend_jit_trace_stack return (zend_jit_trace_stack_frame*)((char*)frame - zend_jit_trace_frame_size(op_array)); } -static void zend_jit_trace_send_type(const zend_op *opline, zend_jit_trace_stack_frame *call, zend_uchar type) +static void zend_jit_trace_send_type(const zend_op *opline, zend_jit_trace_stack_frame *call, uint8_t type) { zend_jit_trace_stack *stack = call->stack; const zend_op_array *op_array = &call->func->op_array; @@ -858,7 +865,7 @@ static void zend_jit_trace_propagate_range(const zend_op_array *op_array, const int def = tssa->vars[ssa_var].definition; if (tssa->vars[ssa_var].alias == NO_ALIAS - && zend_inference_propagate_range(op_array, tssa, (zend_op*)tssa_opcodes[def], (zend_ssa_op*)&tssa->ops[def], ssa_var, &tmp)) { + && zend_inference_propagate_range(op_array, tssa, tssa_opcodes[def], &tssa->ops[def], ssa_var, &tmp)) { tssa->var_info[ssa_var].range.min = tmp.min; tssa->var_info[ssa_var].range.max = tmp.max; tssa->var_info[ssa_var].range.underflow = tmp.underflow; @@ -1140,6 +1147,7 @@ static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, u } else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) { return 0; } + return 1; } else if (opline->opcode == ZEND_PRE_DEC || opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_DEC @@ -1528,7 +1536,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin } else { ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i); } - if (op_array->arg_info) { + if (op_array->arg_info && i < trace_buffer[1].opline - op_array->opcodes) { zend_arg_info *arg_info = &op_array->arg_info[i]; zend_class_entry *ce; uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce); @@ -1588,7 +1596,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin } if (i < parent_vars_count) { /* Initialize TSSA variable from parent trace */ - zend_uchar op_type = STACK_TYPE(parent_stack, i); + uint8_t op_type = STACK_TYPE(parent_stack, i); if (op_type != IS_UNKNOWN) { ssa_var_info[i].type &= zend_jit_trace_type_to_info(op_type); @@ -3850,7 +3858,7 @@ static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const static bool zend_jit_may_skip_comparison(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array) { - zend_uchar prev_opcode; + uint8_t prev_opcode; if (opline->op1_type == IS_CONST && Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_LONG @@ -3986,7 +3994,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par int num_op_arrays = 0; zend_jit_trace_info *t; const zend_op_array *op_arrays[ZEND_JIT_TRACE_MAX_FUNCS]; - zend_uchar smart_branch_opcode; + uint8_t smart_branch_opcode; const void *exit_addr; uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info; bool send_result = 0; @@ -4003,7 +4011,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par uint32_t i; zend_jit_trace_stack_frame *frame, *top, *call; zend_jit_trace_stack *stack; - zend_uchar res_type = IS_UNKNOWN; + uint8_t res_type = IS_UNKNOWN; const zend_op *opline, *orig_opline; const zend_ssa_op *ssa_op, *orig_ssa_op; int checked_stack; @@ -4289,7 +4297,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par bool op1_indirect; zend_class_entry *op1_ce = NULL; zend_class_entry *op2_ce = NULL; - bool gen_handler; + bool gen_handler = false; opline = p->opline; if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) { @@ -4984,6 +4992,14 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par res_addr = 0; } else { res_addr = RES_REG_ADDR(); + if (Z_MODE(res_addr) != IS_REG + && zend_jit_trace_next_is_send_result(opline, p, frame)) { + send_result = 1; + res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var); + if (!zend_jit_reuse_ip(&dasm_state)) { + goto jit_failure; + } + } } if (!zend_jit_assign_to_typed_ref(&dasm_state, opline, opline->op2_type, op2_addr, res_addr, 1)) { goto jit_failure; @@ -5379,7 +5395,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par if (!left_frame) { for (j = 0 ; j < op_array->last_var; j++) { uint32_t info; - zend_uchar type; + uint8_t type; info = zend_ssa_cv_info(op_array, op_array_ssa, j); type = STACK_TYPE(stack, j); @@ -6218,7 +6234,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par /* Keep information about known types on abstract stack */ if (ssa_op->result_def >= 0) { - zend_uchar type = IS_UNKNOWN; + uint8_t type = IS_UNKNOWN; if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0 || send_result) { @@ -6274,7 +6290,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } if (type == IS_LONG - && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->result_def, &tmp)) { + && zend_inference_propagate_range(op_array, ssa, opline, ssa_op, ssa_op->result_def, &tmp)) { ssa->var_info[ssa_op->result_def].range.min = tmp.min; ssa->var_info[ssa_op->result_def].range.max = tmp.max; ssa->var_info[ssa_op->result_def].range.underflow = 0; @@ -6286,7 +6302,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par && (opline->opcode != ZEND_QM_ASSIGN || opline->result_type != IS_CV || opline->result.var != opline->op1.var)) { - zend_uchar type = IS_UNKNOWN; + uint8_t type = IS_UNKNOWN; if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD) && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) { @@ -6335,7 +6351,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } } if (type == IS_LONG - && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op1_def, &tmp)) { + && zend_inference_propagate_range(op_array, ssa, opline, ssa_op, ssa_op->op1_def, &tmp)) { ssa->var_info[ssa_op->op1_def].range.min = tmp.min; ssa->var_info[ssa_op->op1_def].range.max = tmp.max; ssa->var_info[ssa_op->op1_def].range.underflow = 0; @@ -6347,7 +6363,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par && (opline->opcode != ZEND_ASSIGN || opline->op1_type != IS_CV || opline->op1.var != opline->op2.var)) { - zend_uchar type = IS_UNKNOWN; + uint8_t type = IS_UNKNOWN; if (!(ssa->var_info[ssa_op->op2_def].type & MAY_BE_GUARD) && has_concrete_type(ssa->var_info[ssa_op->op2_def].type)) { @@ -6376,7 +6392,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } } if (type == IS_LONG - && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op2_def, &tmp)) { + && zend_inference_propagate_range(op_array, ssa, opline, ssa_op, ssa_op->op2_def, &tmp)) { ssa->var_info[ssa_op->op2_def].range.min = tmp.min; ssa->var_info[ssa_op->op2_def].range.max = tmp.max; ssa->var_info[ssa_op->op2_def].range.underflow = 0; @@ -6398,7 +6414,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par ssa_op++; opline++; if (ssa_op->op1_def >= 0) { - zend_uchar type = IS_UNKNOWN; + uint8_t type = IS_UNKNOWN; if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD) && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) { @@ -6419,7 +6435,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } } if (type == IS_LONG - && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op1_def, &tmp)) { + && zend_inference_propagate_range(op_array, ssa, opline, ssa_op, ssa_op->op1_def, &tmp)) { ssa->var_info[ssa_op->op1_def].range.min = tmp.min; ssa->var_info[ssa_op->op1_def].range.max = tmp.max; ssa->var_info[ssa_op->op1_def].range.underflow = 0; @@ -6434,7 +6450,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par opline++; while (opline->opcode == ZEND_RECV_INIT) { if (ssa_op->result_def >= 0) { - zend_uchar type = IS_UNKNOWN; + uint8_t type = IS_UNKNOWN; if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD) && has_concrete_type(ssa->var_info[ssa_op->result_def].type)) { @@ -6456,7 +6472,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par opline++; while (opline->opcode == ZEND_BIND_GLOBAL) { if (ssa_op->op1_def >= 0) { - zend_uchar type = IS_UNKNOWN; + uint8_t type = IS_UNKNOWN; if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD) && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) { @@ -6550,6 +6566,16 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par for (i = 0; i < op_array->last_var; i++,j++) { if (ra[j] && (ra[j]->flags & ZREG_LOAD) != 0) { + if ((ssa->var_info[j].type & MAY_BE_GUARD) != 0) { + uint8_t op_type; + + ssa->var_info[j].type &= ~MAY_BE_GUARD; + op_type = concrete_type(ssa->var_info[j].type); + if (!zend_jit_type_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), op_type)) { + goto jit_failure; + } + SET_STACK_TYPE(stack, i, op_type, 1); + } SET_STACK_REG_EX(stack, i, ra[j]->reg, ZREG_LOAD); if (!zend_jit_load_var(&dasm_state, ssa->var_info[j].type, i, ra[j]->reg)) { goto jit_failure; @@ -6832,6 +6858,15 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par const void *timeout_exit_addr = NULL; t->link = zend_jit_find_trace(p->opline->handler); + if (t->link == 0) { + /* this can happen if ZEND_JIT_EXIT_INVALIDATE was handled + * by zend_jit_trace_exit() in another thread after this + * thread set ZEND_JIT_TRACE_STOP_LINK in zend_jit_trace_execute(); + * ZEND_JIT_EXIT_INVALIDATE resets the opline handler to one of + * the "_counter_handler" functions, and these are not registered + * tracer functions */ + goto jit_failure; + } if ((zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_USES_INITIAL_IP) && !zend_jit_set_ip(&dasm_state, p->opline)) { goto jit_failure; @@ -7088,6 +7123,7 @@ static zend_jit_trace_stop zend_jit_compile_root_trace(zend_jit_trace_rec *trace if (t->stack_map_size) { zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack)); if (!shared_stack_map) { + efree(t->stack_map); ret = ZEND_JIT_TRACE_STOP_NO_SHM; goto exit; } @@ -7341,7 +7377,7 @@ static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa fprintf(stderr, " op1(%sobject of class %s)", ref, ZSTR_VAL(p->ce->name)); } else { - const char *type = (op1_type == 0) ? "undef" : zend_get_type_by_const(op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)); + const char *type = ((op1_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)); fprintf(stderr, " op1(%s%s%s)", ref, (op1_type & IS_TRACE_PACKED) ? "packed " : "", type); } } @@ -7354,7 +7390,7 @@ static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa fprintf(stderr, " op2(%sobject of class %s)", ref, ZSTR_VAL(p->ce->name)); } else { - const char *type = (op2_type == 0) ? "undef" : zend_get_type_by_const(op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)); + const char *type = ((op2_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)); fprintf(stderr, " op2(%s%s)", ref, type); } } @@ -7362,7 +7398,7 @@ static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa const char *ref = (op3_type & IS_TRACE_INDIRECT) ? ((op3_type & IS_TRACE_REFERENCE) ? "*&" : "*") : ((op3_type & IS_TRACE_REFERENCE) ? "&" : ""); - const char *type = (op3_type == 0) ? "undef" : zend_get_type_by_const(op3_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)); + const char *type = ((op3_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op3_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)); fprintf(stderr, " op3(%s%s)", ref, type); } } @@ -7512,7 +7548,7 @@ static void zend_jit_dump_exit_info(zend_jit_trace_info *t) fprintf(stderr, "/FREE_OP2"); } for (j = 0; j < stack_size; j++) { - zend_uchar type = STACK_TYPE(stack, j); + uint8_t type = STACK_TYPE(stack, j); if (type != IS_UNKNOWN) { fprintf(stderr, " "); zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j); @@ -8187,22 +8223,34 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf t = &zend_jit_traces[num]; } - SHM_UNPROTECT(); - zend_jit_unprotect(); + zend_shared_alloc_lock(); jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(t->op_array); - if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_LOOP) { - ((zend_op*)(t->opline))->handler = (const void*)zend_jit_loop_trace_counter_handler; - } else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_ENTER) { - ((zend_op*)(t->opline))->handler = (const void*)zend_jit_func_trace_counter_handler; - } else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_RETURN) { - ((zend_op*)(t->opline))->handler = (const void*)zend_jit_ret_trace_counter_handler; + + /* Checks under lock, just in case something has changed while we were waiting for the lock */ + if (!(ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED))) { + /* skip: not JIT-ed nor blacklisted */ + } else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) { + /* skip: too many root traces */ + } else { + SHM_UNPROTECT(); + zend_jit_unprotect(); + + if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_LOOP) { + ((zend_op*)(t->opline))->handler = (const void*)zend_jit_loop_trace_counter_handler; + } else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_ENTER) { + ((zend_op*)(t->opline))->handler = (const void*)zend_jit_func_trace_counter_handler; + } else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_RETURN) { + ((zend_op*)(t->opline))->handler = (const void*)zend_jit_ret_trace_counter_handler; + } + ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags &= + ZEND_JIT_TRACE_START_LOOP|ZEND_JIT_TRACE_START_ENTER|ZEND_JIT_TRACE_START_RETURN; + + zend_jit_protect(); + SHM_PROTECT(); } - ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags &= - ZEND_JIT_TRACE_START_LOOP|ZEND_JIT_TRACE_START_ENTER|ZEND_JIT_TRACE_START_RETURN; - zend_jit_protect(); - SHM_PROTECT(); + zend_shared_alloc_unlock(); return 0; } @@ -8357,6 +8405,13 @@ static void zend_jit_trace_reset_caches(void) #endif } +static void zend_jit_trace_free_caches(zend_jit_globals *jit_globals) +{ + if (jit_globals->exit_counters) { + free(jit_globals->exit_counters); + } +} + static void zend_jit_trace_restart(void) { ZEND_JIT_TRACE_NUM = 1; diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 5342731fc81b7..d78cde95e9641 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -183,7 +183,7 @@ bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D) zend_execute_data *execute_data = EG(current_execute_data); #endif const zend_op *opline = EG(opline_before_exception); - if (RETURN_VALUE_USED(opline)) { + if (opline && RETURN_VALUE_USED(opline)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); } @@ -282,7 +282,7 @@ static zend_always_inline zend_constant* _zend_quick_get_constant( if (!check_defined_only) { if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) { - zend_error(E_DEPRECATED, "Constant %s is deprecated", ZSTR_VAL(c->name)); + zend_error(E_DEPRECATED, "Constant %s is deprecated", ZSTR_VAL(Z_STR_P(key))); if (EG(exception)) { return NULL; } @@ -360,7 +360,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_trace_helper(ZEND_OPCODE_HAN trace_buffer[idx].info = _op | (_info); \ trace_buffer[idx].ptr = _ptr; \ idx++; \ - if (idx >= ZEND_JIT_TRACE_MAX_LENGTH - 2) { \ + if (idx >= JIT_G(max_trace_length) - 2) { \ stop = ZEND_JIT_TRACE_STOP_TOO_LONG; \ break; \ } @@ -372,7 +372,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_trace_helper(ZEND_OPCODE_HAN trace_buffer[idx].op3_type = _op3_type; \ trace_buffer[idx].ptr = _ptr; \ idx++; \ - if (idx >= ZEND_JIT_TRACE_MAX_LENGTH - 2) { \ + if (idx >= JIT_G(max_trace_length) - 2) { \ stop = ZEND_JIT_TRACE_STOP_TOO_LONG; \ break; \ } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index de2fa51526d0c..c340d710cde6a 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -1070,7 +1070,7 @@ static size_t tsrm_tls_offset; || has_concrete_type(src_info & MAY_BE_ANY)) { || if (Z_MODE(dst_addr) == IS_MEM_ZVAL) { || if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) { -|| zend_uchar type = concrete_type(src_info); +|| uint8_t type = concrete_type(src_info); | SET_ZVAL_TYPE_INFO dst_addr, type || } || } @@ -1194,7 +1194,7 @@ static size_t tsrm_tls_offset; || } || if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) && || has_concrete_type(src_info & MAY_BE_ANY)) { -|| zend_uchar type = concrete_type(src_info); +|| uint8_t type = concrete_type(src_info); || if (Z_MODE(dst_addr) == IS_MEM_ZVAL) { || if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF))) { | SET_ZVAL_TYPE_INFO dst_addr, type @@ -1375,7 +1375,7 @@ static size_t tsrm_tls_offset; || do { || if (!((var_info) & MAY_BE_GUARD) || && has_concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { -|| zend_uchar type = concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); +|| uint8_t type = concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); || if (type == IS_STRING && !ZEND_DEBUG) { | EXT_CALL _efree, r0 || break; @@ -3070,6 +3070,12 @@ static int zend_jit_align_func(dasm_State **Dst) return 1; } +static int zend_jit_align_stub(dasm_State **Dst) +{ + |.align 16 + return 1; +} + static int zend_jit_prologue(dasm_State **Dst) { | ENDBR @@ -3969,7 +3975,7 @@ static int zend_jit_load_var(dasm_State **Dst, uint32_t info, int var, zend_reg return zend_jit_load_reg(Dst, src, dst, info); } -static int zend_jit_invalidate_var_if_necessary(dasm_State **Dst, zend_uchar op_type, zend_jit_addr addr, znode_op op) +static int zend_jit_invalidate_var_if_necessary(dasm_State **Dst, uint8_t op_type, zend_jit_addr addr, znode_op op) { if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) { zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var); @@ -4383,7 +4389,7 @@ static int zend_jit_opline_uses_reg(const zend_op *opline, int8_t reg) static int zend_jit_math_long_long(dasm_State **Dst, const zend_op *opline, - zend_uchar opcode, + uint8_t opcode, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, @@ -4593,7 +4599,7 @@ static int zend_jit_math_long_long(dasm_State **Dst, } static int zend_jit_math_long_double(dasm_State **Dst, - zend_uchar opcode, + uint8_t opcode, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, @@ -4638,7 +4644,7 @@ static int zend_jit_math_long_double(dasm_State **Dst, } static int zend_jit_math_double_long(dasm_State **Dst, - zend_uchar opcode, + uint8_t opcode, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, @@ -4731,7 +4737,7 @@ static int zend_jit_math_double_long(dasm_State **Dst, } static int zend_jit_math_double_double(dasm_State **Dst, - zend_uchar opcode, + uint8_t opcode, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, @@ -4811,12 +4817,12 @@ static int zend_jit_math_double_double(dasm_State **Dst, static int zend_jit_math_helper(dasm_State **Dst, const zend_op *opline, - zend_uchar opcode, - zend_uchar op1_type, + uint8_t opcode, + uint8_t op1_type, znode_op op1, zend_jit_addr op1_addr, uint32_t op1_info, - zend_uchar op2_type, + uint8_t op2_type, znode_op op2, zend_jit_addr op2_addr, uint32_t op2_info, @@ -5098,13 +5104,13 @@ static int zend_jit_add_arrays(dasm_State **Dst, const zend_op *opline, uint32_t static int zend_jit_long_math_helper(dasm_State **Dst, const zend_op *opline, - zend_uchar opcode, - zend_uchar op1_type, + uint8_t opcode, + uint8_t op1_type, znode_op op1, zend_jit_addr op1_addr, uint32_t op1_info, zend_ssa_range *op1_range, - zend_uchar op2_type, + uint8_t op2_type, znode_op op2, zend_jit_addr op2_addr, uint32_t op2_info, @@ -5286,7 +5292,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst, } } } else { - if (!op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) { + if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) { if (Z_MODE(op2_addr) == IS_MEM_ZVAL) { | cmp aword [Ra(Z_REG(op2_addr))+Z_OFFSET(op2_addr)], 0 } else if (Z_MODE(op2_addr) == IS_REG) { @@ -5494,11 +5500,11 @@ static int zend_jit_long_math(dasm_State **Dst, const zend_op *opline, uint32_t static int zend_jit_concat_helper(dasm_State **Dst, const zend_op *opline, - zend_uchar op1_type, + uint8_t op1_type, znode_op op1, zend_jit_addr op1_addr, uint32_t op1_info, - zend_uchar op2_type, + uint8_t op2_type, znode_op op2, zend_jit_addr op2_addr, uint32_t op2_info, @@ -6105,7 +6111,7 @@ static int zend_jit_simple_assign(dasm_State **Dst, zend_jit_addr var_addr, uint32_t var_info, uint32_t var_def_info, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, uint32_t val_info, zend_jit_addr res_addr, @@ -6269,7 +6275,7 @@ static int zend_jit_simple_assign(dasm_State **Dst, static int zend_jit_assign_to_typed_ref(dasm_State **Dst, const zend_op *opline, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, zend_jit_addr res_addr, bool check_exception) @@ -6285,22 +6291,39 @@ static int zend_jit_assign_to_typed_ref(dasm_State **Dst, if (opline) { | SET_EX_OPLINE opline, r0 } - if (val_type == IS_CONST) { - | EXT_CALL zend_jit_assign_const_to_typed_ref, r0 - } else if (val_type == IS_TMP_VAR) { - | EXT_CALL zend_jit_assign_tmp_to_typed_ref, r0 - } else if (val_type == IS_VAR) { - | EXT_CALL zend_jit_assign_var_to_typed_ref, r0 - } else if (val_type == IS_CV) { - | EXT_CALL zend_jit_assign_cv_to_typed_ref, r0 + if (!res_addr) { + if (val_type == IS_CONST) { + | EXT_CALL zend_jit_assign_const_to_typed_ref, r0 + } else if (val_type == IS_TMP_VAR) { + | EXT_CALL zend_jit_assign_tmp_to_typed_ref, r0 + } else if (val_type == IS_VAR) { + | EXT_CALL zend_jit_assign_var_to_typed_ref, r0 + } else if (val_type == IS_CV) { + | EXT_CALL zend_jit_assign_cv_to_typed_ref, r0 + } else { + ZEND_UNREACHABLE(); + } } else { - ZEND_UNREACHABLE(); - } - if (res_addr) { - zend_jit_addr ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0); - - | ZVAL_COPY_VALUE res_addr, -1, ret_addr, -1, ZREG_R1, ZREG_R2 - | TRY_ADDREF -1, ch, r2 + |.if X64 + | LOAD_ZVAL_ADDR CARG3, res_addr + |.else + | sub r4, 12 + | PUSH_ZVAL_ADDR res_addr, r0 + |.endif + if (val_type == IS_CONST) { + | EXT_CALL zend_jit_assign_const_to_typed_ref2, r0 + } else if (val_type == IS_TMP_VAR) { + | EXT_CALL zend_jit_assign_tmp_to_typed_ref2, r0 + } else if (val_type == IS_VAR) { + | EXT_CALL zend_jit_assign_var_to_typed_ref2, r0 + } else if (val_type == IS_CV) { + | EXT_CALL zend_jit_assign_cv_to_typed_ref2, r0 + } else { + ZEND_UNREACHABLE(); + } + |.if not(X64) + | add r4, 12 + |.endif } if (check_exception) { | // if (UNEXPECTED(EG(exception) != NULL)) { @@ -6321,7 +6344,7 @@ static int zend_jit_assign_to_variable_call(dasm_State **Dst, zend_jit_addr var_addr, uint32_t __var_info, uint32_t __var_def_info, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, uint32_t val_info, zend_jit_addr __res_addr, @@ -6403,7 +6426,7 @@ static int zend_jit_assign_to_variable(dasm_State **Dst, zend_jit_addr var_addr, uint32_t var_info, uint32_t var_def_info, - zend_uchar val_type, + uint8_t val_type, zend_jit_addr val_addr, uint32_t val_info, zend_jit_addr res_addr, @@ -7117,7 +7140,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, zend_ssa_range *op2_range, zend_jit_addr op2_addr, zend_jit_addr res_addr, - zend_uchar smart_branch_opcode, + uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr, @@ -7379,7 +7402,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, return 1; } -static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, bool swap, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, bool swap, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { if (smart_branch_opcode) { if (smart_branch_opcode == ZEND_JMPZ) { @@ -7682,7 +7705,7 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z return 1; } -static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { zend_reg tmp_reg = ZREG_XMM0; @@ -7692,7 +7715,7 @@ static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zen return zend_jit_cmp_double_common(Dst, opline, res_addr, 0, smart_branch_opcode, target_label, target_label2, exit_addr); } -static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { zend_reg tmp_reg = ZREG_XMM0; @@ -7702,7 +7725,7 @@ static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zen return zend_jit_cmp_double_common(Dst, opline, res_addr, /* swap */ 1, smart_branch_opcode, target_label, target_label2, exit_addr); } -static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { bool swap = 0; @@ -7721,7 +7744,7 @@ static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, z return zend_jit_cmp_double_common(Dst, opline, res_addr, swap, smart_branch_opcode, target_label, target_label2, exit_addr); } -static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { | test, eax, eax if (smart_branch_opcode) { @@ -7857,7 +7880,7 @@ static int zend_jit_cmp(dasm_State **Dst, zend_jit_addr op2_addr, zend_jit_addr res_addr, int may_throw, - zend_uchar smart_branch_opcode, + uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr, @@ -8101,7 +8124,7 @@ static int zend_jit_identical(dasm_State **Dst, zend_jit_addr op2_addr, zend_jit_addr res_addr, int may_throw, - zend_uchar smart_branch_opcode, + uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr, @@ -8228,7 +8251,6 @@ static int zend_jit_identical(dasm_State **Dst, } op1_addr = real_addr; } - | LOAD_ZVAL_ADDR FCARG1a, op1_addr } if (opline->op2_type != IS_CONST) { if (Z_MODE(op2_addr) == IS_REG) { @@ -8240,6 +8262,9 @@ static int zend_jit_identical(dasm_State **Dst, } | LOAD_ZVAL_ADDR FCARG2a, op2_addr } + if (opline->op1_type != IS_CONST) { + | LOAD_ZVAL_ADDR FCARG1a, op1_addr + } } if ((op1_info & op2_info & MAY_BE_ANY) == 0) { @@ -8483,7 +8508,7 @@ static int zend_jit_identical(dasm_State **Dst, return 1; } -static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, zend_uchar branch_opcode, const void *exit_addr) +static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, uint8_t branch_opcode, const void *exit_addr) { uint32_t true_label = -1; uint32_t false_label = -1; @@ -9367,8 +9392,28 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t | // if (CACHED_PTR(opline->result.num)) | mov r2, EX->run_time_cache | mov r0, aword [r2 + opline->result.num] - | test r0, r0 - | jz >1 + if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE + && func + && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) + && opline->opcode != ZEND_INIT_FCALL) { + /* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */ + | .if X64 + || if (!IS_SIGNED_32BIT(func)) { + | mov64 r1, ((ptrdiff_t)func) + | cmp r0, r1 + || } else { + | cmp r0, func + || } + | .else + | cmp r0, func + | .endif + | jnz >1 + |.cold_code + |1: + } else { + | test r0, r0 + | jz >1 + } |.cold_code |1: if (opline->opcode == ZEND_INIT_FCALL @@ -10292,12 +10337,23 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend zend_jit_reset_last_valid_opline(); - | // fbc->internal_function.handler(call, ret); - | mov FCARG1a, RX - if (func) { - | EXT_CALL func->internal_function.handler, r0 + | // (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret); + if (zend_execute_internal) { + |.if X64 + | // CARG2 and FCARG2a are identical + | mov CARG1, RX + |.else + | mov aword A2, FCARG2a + | mov aword A1, RX + |.endif + | EXT_CALL zend_execute_internal, r0 } else { - | call aword [r0 + offsetof(zend_internal_function, handler)] + | mov FCARG1a, RX + if (func) { + | EXT_CALL func->internal_function.handler, r0 + } else { + | call aword [r0 + offsetof(zend_internal_function, handler)] + } } if (ZEND_OBSERVER_ENABLED) { @@ -10864,7 +10920,7 @@ static int zend_jit_check_func_arg(dasm_State **Dst, const zend_op *opline) return 1; } -static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2) +static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2) { if (smart_branch_opcode) { if (smart_branch_opcode == ZEND_JMPZ) { @@ -10888,7 +10944,7 @@ static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, return 1; } -static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label) +static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp, uint8_t smart_branch_opcode, uint32_t target_label) { if (smart_branch_opcode) { if (smart_branch_opcode == ZEND_JMPZ) { @@ -10912,7 +10968,7 @@ static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp return 1; } -static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { uint32_t defined_label = (uint32_t)-1; uint32_t undefined_label = (uint32_t)-1; @@ -11005,7 +11061,7 @@ static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, zend_uchar return 1; } -static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { uint32_t mask; zend_jit_addr op1_addr = OP1_ADDR(); @@ -11071,7 +11127,7 @@ static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t } } else { bool invert = 0; - zend_uchar type; + uint8_t type; switch (mask) { case MAY_BE_NULL: type = IS_NULL; break; @@ -12015,7 +12071,7 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, |8: if (res_exit_addr) { - zend_uchar type = concrete_type(res_info); + uint8_t type = concrete_type(res_info); if ((op1_info & MAY_BE_ARRAY_OF_REF) && dim_type != IS_UNKNOWN @@ -12347,7 +12403,7 @@ static int zend_jit_isset_isempty_dim(dasm_State **Dst, uint32_t op2_info, uint8_t dim_type, int may_throw, - zend_uchar smart_branch_opcode, + uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) @@ -12959,7 +13015,7 @@ static int zend_jit_fetch_obj(dasm_State **Dst, type_loaded = 1; prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); if (opline->opcode == ZEND_FETCH_OBJ_W - && (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS))) { + && (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) { uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS; | mov r0, EX->run_time_cache @@ -12981,6 +13037,17 @@ static int zend_jit_fetch_obj(dasm_State **Dst, | SET_ZVAL_TYPE_INFO res_addr, IS_OBJECT_EX | jmp >9 |2: + | mov eax, dword [FCARG1a + offsetof(zval, u2.extra)] + | test eax, IS_PROP_REINITABLE + | jz >6 + | and eax, ~IS_PROP_REINITABLE + | mov dword [FCARG1a + offsetof(zval, u2.extra)], eax + if (flags) { + | jmp >3 + } else { + | jmp >4 + } + |6: | mov FCARG1a, FCARG2a | SET_EX_OPLINE opline, r0 | EXT_CALL zend_readonly_property_modification_error, r0 @@ -13032,7 +13099,7 @@ static int zend_jit_fetch_obj(dasm_State **Dst, if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) { if (!type_loaded) { type_loaded = 1; - | mov edx, dword [FCARG1a + prop_info->offset + 8] + | mov edx, dword [FCARG1a + prop_info->offset + offsetof(zval, u1.type_info)] } | IF_NOT_TYPE dl, IS_OBJECT, >4 | GET_ZVAL_PTR r0, prop_addr @@ -13042,12 +13109,20 @@ static int zend_jit_fetch_obj(dasm_State **Dst, | jmp >9 |.cold_code |4: + | mov eax, dword [FCARG1a + prop_info->offset + offsetof(zval, u2.extra)] + | test eax, IS_PROP_REINITABLE + | jz >6 + | and eax, ~IS_PROP_REINITABLE + | mov dword [FCARG1a + prop_info->offset + offsetof(zval, u2.extra)], eax + | jmp >4 + |6: | LOAD_ADDR FCARG1a, prop_info | SET_EX_OPLINE opline, r0 | EXT_CALL zend_readonly_property_modification_error, r0 | SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR | jmp >9 |.code + |4: } if (opline->opcode == ZEND_FETCH_OBJ_W && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS) @@ -13127,7 +13202,7 @@ static int zend_jit_fetch_obj(dasm_State **Dst, zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; int32_t exit_point; const void *exit_addr; - zend_uchar type; + uint8_t type; zend_jit_addr val_addr = prop_addr; if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) @@ -13455,7 +13530,7 @@ static int zend_jit_incdec_obj(dasm_State **Dst, | mov r2, aword [r0 + opline->extended_value] | cmp r2, aword [FCARG1a + offsetof(zend_object, ce)] | jne >7 - if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { | cmp aword [r0 + opline->extended_value + sizeof(void*) * 2], 0 | jnz >7 } @@ -13928,7 +14003,7 @@ static int zend_jit_assign_obj_op(dasm_State **Dst, | mov r2, aword [r0 + (opline+1)->extended_value] | cmp r2, aword [FCARG1a + offsetof(zend_object, ce)] | jne >7 - if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { | cmp aword [r0 + (opline+1)->extended_value + sizeof(void*) * 2], 0 | jnz >7 } @@ -14347,7 +14422,7 @@ static int zend_jit_assign_obj(dasm_State **Dst, | mov r2, aword [r0 + opline->extended_value] | cmp r2, aword [FCARG1a + offsetof(zend_object, ce)] | jne >5 - if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { | mov FCARG2a, aword [r0 + opline->extended_value + sizeof(void*) * 2] } | mov r0, aword [r0 + opline->extended_value + sizeof(void*)] @@ -14356,7 +14431,7 @@ static int zend_jit_assign_obj(dasm_State **Dst, | IF_TYPE byte [FCARG1a + r0 + 8], IS_UNDEF, >5 | add FCARG1a, r0 prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { | test FCARG2a, FCARG2a | jnz >1 |.cold_code @@ -15230,7 +15305,7 @@ static bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *opline, return 1; } -static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); @@ -15320,10 +15395,24 @@ static int zend_jit_fe_reset(dasm_State **Dst, const zend_op *opline, uint32_t o return 1; } -static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, zend_uchar exit_opcode, const void *exit_addr) +static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, uint8_t exit_opcode, const void *exit_addr) { zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); + if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) { + /* empty array */ + if (exit_addr) { + if (exit_opcode == ZEND_JMP) { + | jmp &exit_addr + } else { + | jmp >3 + } + } else { + | jmp =>target_label + } + return 1; + } + | // array = EX_VAR(opline->op1.var); | // fe_ht = Z_ARRVAL_P(array); | GET_ZVAL_PTR FCARG1a, op1_addr @@ -15559,7 +15648,7 @@ static int zend_jit_fetch_constant(dasm_State **Dst, res_info &= ~MAY_BE_GUARD; ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD; - zend_uchar type = concrete_type(res_info); + uint8_t type = concrete_type(res_info); if (type < IS_STRING) { | IF_NOT_ZVAL_TYPE const_addr, type, &exit_addr @@ -15601,7 +15690,7 @@ static int zend_jit_fetch_constant(dasm_State **Dst, return 1; } -static int zend_jit_in_array(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) +static int zend_jit_in_array(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) { HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2)); zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); @@ -16007,7 +16096,7 @@ static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, return 1; } -static bool zend_needs_extra_reg_for_const(const zend_op *opline, zend_uchar op_type, znode_op op) +static bool zend_needs_extra_reg_for_const(const zend_op *opline, uint8_t op_type, znode_op op) { |.if X64 || if (op_type == IS_CONST) { @@ -16174,11 +16263,17 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend } } if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) { + if (opline->op1_type == IS_CONST) { + ZEND_REGSET_INCL(regset, ZREG_R0); + } if (ssa_op->result_def != current_var) { ZEND_REGSET_INCL(regset, ZREG_XMM0); } } if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) { + if (opline->op2_type == IS_CONST) { + ZEND_REGSET_INCL(regset, ZREG_R0); + } if (zend_is_commutative(opline->opcode)) { if (ssa_op->result_def != current_var) { ZEND_REGSET_INCL(regset, ZREG_XMM0); diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index e180607efa186..1414ef96149d0 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -154,7 +154,7 @@ static void *find_prefered_mmap_base(size_t requested_size) } #endif -static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in) +static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, const char **error_in) { zend_shared_segment *shared_segment; int flags = PROT_READ | PROT_WRITE, fd = -1; @@ -276,7 +276,7 @@ static size_t segment_type_size(void) return sizeof(zend_shared_segment); } -zend_shared_memory_handlers zend_alloc_mmap_handlers = { +const zend_shared_memory_handlers zend_alloc_mmap_handlers = { create_segments, detach_segment, segment_type_size diff --git a/ext/opcache/shared_alloc_posix.c b/ext/opcache/shared_alloc_posix.c index bab4c4544ef91..70391473dd9ea 100644 --- a/ext/opcache/shared_alloc_posix.c +++ b/ext/opcache/shared_alloc_posix.c @@ -36,7 +36,7 @@ typedef struct { int shm_fd; } zend_shared_segment_posix; -static int create_segments(size_t requested_size, zend_shared_segment_posix ***shared_segments_p, int *shared_segments_count, char **error_in) +static int create_segments(size_t requested_size, zend_shared_segment_posix ***shared_segments_p, int *shared_segments_count, const char **error_in) { zend_shared_segment_posix *shared_segment; char shared_segment_name[sizeof("/ZendAccelerator.") + 20]; @@ -89,7 +89,7 @@ static size_t segment_type_size(void) return sizeof(zend_shared_segment_posix); } -zend_shared_memory_handlers zend_alloc_posix_handlers = { +const zend_shared_memory_handlers zend_alloc_posix_handlers = { (create_segments_t)create_segments, (detach_segment_t)detach_segment, segment_type_size diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c index c55e74e1f7db5..09a357d189ed4 100644 --- a/ext/opcache/shared_alloc_shm.c +++ b/ext/opcache/shared_alloc_shm.c @@ -50,7 +50,7 @@ typedef struct { int shm_id; } zend_shared_segment_shm; -static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, char **error_in) +static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, const char **error_in) { int i; size_t allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size; @@ -135,7 +135,7 @@ static size_t segment_type_size(void) return sizeof(zend_shared_segment_shm); } -zend_shared_memory_handlers zend_alloc_shm_handlers = { +const zend_shared_memory_handlers zend_alloc_shm_handlers = { (create_segments_t)create_segments, (detach_segment_t)detach_segment, segment_type_size diff --git a/ext/opcache/shared_alloc_win32.c b/ext/opcache/shared_alloc_win32.c index c64816c053def..893fe98ec189c 100644 --- a/ext/opcache/shared_alloc_win32.c +++ b/ext/opcache/shared_alloc_win32.c @@ -112,7 +112,7 @@ void zend_shared_alloc_unlock_win32(void) ReleaseMutex(memory_mutex); } -static int zend_shared_alloc_reattach(size_t requested_size, char **error_in) +static int zend_shared_alloc_reattach(size_t requested_size, const char **error_in) { int err; void *wanted_mapping_base; @@ -199,7 +199,7 @@ static int zend_shared_alloc_reattach(size_t requested_size, char **error_in) return SUCCESSFULLY_REATTACHED; } -static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in) +static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, const char **error_in) { int err = 0, ret; zend_shared_segment *shared_segment; @@ -352,7 +352,7 @@ static size_t segment_type_size(void) return sizeof(zend_shared_segment); } -zend_shared_memory_handlers zend_alloc_win32_handlers = { +const zend_shared_memory_handlers zend_alloc_win32_handlers = { create_segments, detach_segment, segment_type_size diff --git a/ext/opcache/tests/bug78175_2.phpt b/ext/opcache/tests/bug78175_2.phpt index 0030962c4fb71..a994c3568617d 100644 --- a/ext/opcache/tests/bug78175_2.phpt +++ b/ext/opcache/tests/bug78175_2.phpt @@ -10,7 +10,6 @@ opcache --SKIPIF-- --FILE-- --FILE-- +--FILE-- + +OK +--EXPECTF-- +bool(false) +included +OK diff --git a/ext/opcache/tests/gh8065.phpt b/ext/opcache/tests/gh8065.phpt new file mode 100644 index 0000000000000..db951a7b0917b --- /dev/null +++ b/ext/opcache/tests/gh8065.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-8065: opcache.consistency_checks > 0 causes segfaults in PHP >= 8.1.5 in fpm context +--EXTENSIONS-- +opcache +--INI-- +opcache.enable_cli=1 +opcache.consistency_checks=1 +opcache.log_verbosity_level=2 +--FILE-- + +--EXPECTF-- +%sWarning opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624). + +string(1) "0" +%sWarning opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624). + +bool(false) +%sWarning opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624). + +bool(false) +string(1) "0" diff --git a/ext/opcache/tests/gh9259_003.phpt b/ext/opcache/tests/gh9259_003.phpt index 1666f93257ecf..04dc46b1906bb 100644 --- a/ext/opcache/tests/gh9259_003.phpt +++ b/ext/opcache/tests/gh9259_003.phpt @@ -4,7 +4,7 @@ Bug GH-9259 003 (Setting opcache.interned_strings_buffer to a very high value le opcache --SKIPIF-- --INI-- opcache.interned_strings_buffer=500 diff --git a/ext/opcache/tests/gh9968-1.inc b/ext/opcache/tests/gh9968-1.inc index 468178c78483f..0f2b14673513c 100644 --- a/ext/opcache/tests/gh9968-1.inc +++ b/ext/opcache/tests/gh9968-1.inc @@ -1,3 +1,3 @@ +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/ext/opcache/tests/jit/assign_dim_002.phpt b/ext/opcache/tests/jit/assign_dim_002.phpt index 3f713a6c6a6a9..83b4bfdec7873 100644 --- a/ext/opcache/tests/jit/assign_dim_002.phpt +++ b/ext/opcache/tests/jit/assign_dim_002.phpt @@ -161,7 +161,7 @@ array(1) { int(1) } } -Illegal offset type +Cannot access offset of type object on array array(1) { [0]=> array(2) { @@ -198,7 +198,7 @@ array(1) { } Deprecated: Automatic conversion of false to array is deprecated in %s on line %d -Illegal offset type +Cannot access offset of type array on array Deprecated: Automatic conversion of false to array is deprecated in %s on line %d int(1) @@ -221,7 +221,7 @@ array(1) { } Deprecated: Automatic conversion of false to array is deprecated in %s on line %d -Illegal offset type +Cannot access offset of type array on array Warning: Undefined variable $undef in %s on line %d NULL diff --git a/ext/opcache/tests/jit/assign_dim_op_001.phpt b/ext/opcache/tests/jit/assign_dim_op_001.phpt index a533cbe9c283b..731a2e96420a7 100644 --- a/ext/opcache/tests/jit/assign_dim_op_001.phpt +++ b/ext/opcache/tests/jit/assign_dim_op_001.phpt @@ -79,7 +79,7 @@ Warning: Undefined array key 2 in %s on line %d Deprecated: Automatic conversion of false to array is deprecated in %s on line %d Deprecated: Automatic conversion of false to array is deprecated in %s on line %d -Illegal offset type +Cannot access offset of type array on array Deprecated: Automatic conversion of false to array is deprecated in %s on line %d @@ -104,5 +104,5 @@ array(1) { } Deprecated: Automatic conversion of false to array is deprecated in %s on line %d -Illegal offset type +Cannot access offset of type array on array Unsupported operand types: null % string diff --git a/ext/opcache/tests/jit/assign_obj_op_003.phpt b/ext/opcache/tests/jit/assign_obj_op_003.phpt new file mode 100644 index 0000000000000..325583e84d912 --- /dev/null +++ b/ext/opcache/tests/jit/assign_obj_op_003.phpt @@ -0,0 +1,26 @@ +--TEST-- +JIT ASSIGN_OBJ_OP: invalid type inference +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- +bar += 1.3; + } catch(y) { + } + } +} +var_dump(new Foo); +?> +--EXPECTF-- +Deprecated: Implicit conversion from float 1.3 to int loses precision in %sassign_obj_op_003.php on line 6 +object(Foo)#1 (1) { + ["bar"]=> + int(1) +} diff --git a/ext/opcache/tests/jit/bug80861.phpt b/ext/opcache/tests/jit/bug80861.phpt index 387f6725eef7f..cb98a3d78f5c3 100644 --- a/ext/opcache/tests/jit/bug80861.phpt +++ b/ext/opcache/tests/jit/bug80861.phpt @@ -1,6 +1,7 @@ --TEST-- Bug #80839: PHP problem with JIT --INI-- +error_log= opcache.enable=1 opcache.enable_cli=1 opcache.jit_buffer_size=1M diff --git a/ext/opcache/tests/jit/bw_not_002.phpt b/ext/opcache/tests/jit/bw_not_002.phpt index 034c6bc90cbdf..e58b06b69f947 100644 --- a/ext/opcache/tests/jit/bw_not_002.phpt +++ b/ext/opcache/tests/jit/bw_not_002.phpt @@ -17,7 +17,7 @@ function test() { test(); ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Cannot perform bitwise not on bool in %sbw_not_002.php:5 +Fatal error: Uncaught TypeError: Cannot perform bitwise not on true in %sbw_not_002.php:5 Stack trace: #0 %sbw_not_002.php(8): test() #1 {main} diff --git a/ext/opcache/tests/jit/fetch_dim_func_arg_002.phpt b/ext/opcache/tests/jit/fetch_dim_func_arg_002.phpt index 3699eba2045f0..b0b2ee2a1ab99 100644 --- a/ext/opcache/tests/jit/fetch_dim_func_arg_002.phpt +++ b/ext/opcache/tests/jit/fetch_dim_func_arg_002.phpt @@ -14,5 +14,5 @@ new class(true[""]) { ?> DONE --EXPECTF-- -Warning: Trying to access array offset on value of type bool in %sfetch_dim_func_arg_002.php on line 2 +Warning: Trying to access array offset on true in %sfetch_dim_func_arg_002.php on line 2 DONE diff --git a/ext/opcache/tests/jit/fetch_dim_r_008.phpt b/ext/opcache/tests/jit/fetch_dim_r_008.phpt index c40d54eefb5f8..42731025fd98e 100644 --- a/ext/opcache/tests/jit/fetch_dim_r_008.phpt +++ b/ext/opcache/tests/jit/fetch_dim_r_008.phpt @@ -12,5 +12,5 @@ test()[1]; ?> DONE --EXPECTF-- -Warning: Trying to access array offset on value of type null in %sfetch_dim_r_008.php on line 3 +Warning: Trying to access array offset on null in %sfetch_dim_r_008.php on line 3 DONE diff --git a/ext/opcache/tests/jit/fetch_dim_rw_004.phpt b/ext/opcache/tests/jit/fetch_dim_rw_004.phpt index ea3fff88f1e45..d9302b8fd04ce 100644 --- a/ext/opcache/tests/jit/fetch_dim_rw_004.phpt +++ b/ext/opcache/tests/jit/fetch_dim_rw_004.phpt @@ -18,7 +18,7 @@ Stack trace: #0 %sfetch_dim_rw_004.php(5): {closure}(2, 'Undefined varia...', '%s', 5) #1 {main} -Next TypeError: Illegal offset type in %sfetch_dim_rw_004.php:5 +Next TypeError: Cannot access offset of type array on array in %sfetch_dim_rw_004.php:5 Stack trace: #0 {main} thrown in %sfetch_dim_rw_004.php on line 5 diff --git a/ext/opcache/tests/jit/fetch_static_prop_001.phpt b/ext/opcache/tests/jit/fetch_static_prop_001.phpt new file mode 100644 index 0000000000000..db781ac993cea --- /dev/null +++ b/ext/opcache/tests/jit/fetch_static_prop_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +FETCH_STATIC_PROP_W should not return UNDEF +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + int(2) +} diff --git a/ext/opcache/tests/jit/gh10271.phpt b/ext/opcache/tests/jit/gh10271.phpt new file mode 100644 index 0000000000000..77c43e3d50a0d --- /dev/null +++ b/ext/opcache/tests/jit/gh10271.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-10271: Incorrect arithmetic calculations when using JIT +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.jit_hot_loop=1 +--FILE-- +$x,'y'=>$y]; +} +?> +--EXPECT-- +0: In;-0.000516528926;-0.000912408759;968.000000000000;548.000000000000;Out;967.500000000004;547.500000000009 +1: In;-0.000516528926;-0.000912408759;968.000000000000;548.000000000000;Out;967.500000000004;547.500000000009 +2: In;-0.000516528926;-0.000912408759;968.000000000000;548.000000000000;Out;967.500000000004;547.500000000009 diff --git a/ext/opcache/tests/jit/gh10635.phpt b/ext/opcache/tests/jit/gh10635.phpt new file mode 100644 index 0000000000000..0f4b43c033b40 --- /dev/null +++ b/ext/opcache/tests/jit/gh10635.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-10635: Function JIT causes impossible assertion +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- +a); + } +} +class C { + use T; + private array $a = [1]; +} +$o = new C; +$o->foo(); +unset($o); +$o = new C; +$o->foo(); +unset($o); +?> +DONE +--EXPECT-- +DONE diff --git a/ext/opcache/tests/jit/identical_003.phpt b/ext/opcache/tests/jit/identical_003.phpt new file mode 100644 index 0000000000000..389fc366c24ad --- /dev/null +++ b/ext/opcache/tests/jit/identical_003.phpt @@ -0,0 +1,19 @@ +--TEST-- +JIT IDENTICAL: 003 register allocation +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.protect_memory=1 +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECT-- +bool(true) diff --git a/ext/opcache/tests/jit/init_fcall_003.inc b/ext/opcache/tests/jit/init_fcall_003.inc new file mode 100644 index 0000000000000..b35315778f42a --- /dev/null +++ b/ext/opcache/tests/jit/init_fcall_003.inc @@ -0,0 +1,6 @@ + diff --git a/ext/opcache/tests/jit/init_fcall_003.phpt b/ext/opcache/tests/jit/init_fcall_003.phpt new file mode 100644 index 0000000000000..f37344cbce4a9 --- /dev/null +++ b/ext/opcache/tests/jit/init_fcall_003.phpt @@ -0,0 +1,27 @@ +--TEST-- +JIT INIT_FCALL: 003 incorrect init fcall guard (fail with tracing JIT and --repeat 3) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.jit_max_polymorphic_calls=0 +opcache.jit=tracing +opcache.jit_hot_loop=64 +opcache.jit_hot_func=127 +opcache.jit_hot_return=8 +opcache.jit_hot_side_exit=8 +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/ext/opcache/tests/jit/mod_007.phpt b/ext/opcache/tests/jit/mod_007.phpt new file mode 100644 index 0000000000000..c83bd0e5a058b --- /dev/null +++ b/ext/opcache/tests/jit/mod_007.phpt @@ -0,0 +1,23 @@ +--TEST-- +JIT MOD: 007 +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.protect_memory=1 +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %smod_007.php:4 +Stack trace: +#0 %smod_007.php(7): test(NULL) +#1 {main} + thrown in %smod_007.php on line 4 \ No newline at end of file diff --git a/ext/opcache/tests/jit/readonly_001.phpt b/ext/opcache/tests/jit/readonly_001.phpt new file mode 100644 index 0000000000000..db56f9a25b045 --- /dev/null +++ b/ext/opcache/tests/jit/readonly_001.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT readonly modification post-inc +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=1M +--FILE-- +bar = 1; + $this->bar++; + } +} + +new Foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): Foo->__construct() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/readonly_002.phpt b/ext/opcache/tests/jit/readonly_002.phpt new file mode 100644 index 0000000000000..aee1902700717 --- /dev/null +++ b/ext/opcache/tests/jit/readonly_002.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT readonly modification pre-inc +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=1M +--FILE-- +bar = 1; + ++$this->bar; + } +} + +new Foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): Foo->__construct() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/readonly_003.phpt b/ext/opcache/tests/jit/readonly_003.phpt new file mode 100644 index 0000000000000..73784919ef944 --- /dev/null +++ b/ext/opcache/tests/jit/readonly_003.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT readonly modification post-inc with result +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=1M +--FILE-- +bar = 1; + var_dump($this->bar++); + } +} + +new Foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): Foo->__construct() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/readonly_004.phpt b/ext/opcache/tests/jit/readonly_004.phpt new file mode 100644 index 0000000000000..50054d2e83ef8 --- /dev/null +++ b/ext/opcache/tests/jit/readonly_004.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT readonly modification pre-inc with result +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=1M +--FILE-- +bar = 1; + var_dump(++$this->bar); + } +} + +new Foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): Foo->__construct() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/readonly_005.phpt b/ext/opcache/tests/jit/readonly_005.phpt new file mode 100644 index 0000000000000..208fee03dbd7d --- /dev/null +++ b/ext/opcache/tests/jit/readonly_005.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT readonly modification post-dec +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=1M +--FILE-- +bar = 1; + $this->bar--; + } +} + +new Foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): Foo->__construct() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/readonly_006.phpt b/ext/opcache/tests/jit/readonly_006.phpt new file mode 100644 index 0000000000000..aceb16399b409 --- /dev/null +++ b/ext/opcache/tests/jit/readonly_006.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT readonly modification pre-dec +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=1M +--FILE-- +bar = 1; + --$this->bar; + } +} + +new Foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): Foo->__construct() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/readonly_007.phpt b/ext/opcache/tests/jit/readonly_007.phpt new file mode 100644 index 0000000000000..9bee61c9a626a --- /dev/null +++ b/ext/opcache/tests/jit/readonly_007.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT readonly modification dec-inc with result +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=1M +--FILE-- +bar = 1; + var_dump($this->bar--); + } +} + +new Foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): Foo->__construct() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/readonly_008.phpt b/ext/opcache/tests/jit/readonly_008.phpt new file mode 100644 index 0000000000000..c38f2cba56e90 --- /dev/null +++ b/ext/opcache/tests/jit/readonly_008.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT readonly modification pre-dec with result +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=1M +--FILE-- +bar = 1; + var_dump(--$this->bar); + } +} + +new Foo(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Cannot modify readonly property Foo::$bar in %s:%d +Stack trace: +#0 %s(%d): Foo->__construct() +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/log_verbosity_bug.phpt b/ext/opcache/tests/log_verbosity_bug.phpt index 6b7e04e2b8c87..8467e4b3b8e67 100644 --- a/ext/opcache/tests/log_verbosity_bug.phpt +++ b/ext/opcache/tests/log_verbosity_bug.phpt @@ -14,7 +14,7 @@ opcache.log_verbosity_level=-1 opcache --SKIPIF-- --FILE-- pre dec conversion for null values) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + +--EXPECT-- +int(1) +int(-1) diff --git a/ext/opcache/tests/opt/gh10801.phpt b/ext/opcache/tests/opt/gh10801.phpt new file mode 100644 index 0000000000000..7260c1c40c11e --- /dev/null +++ b/ext/opcache/tests/opt/gh10801.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10801 (Named arguments in CTE functions cause a segfault) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=0xe0 +--EXTENSIONS-- +opcache +--FILE-- + 1], strict: true, filter_value: 0)); +// Will not use named arguments and do CTE as expected +print_r(array_keys(array: [1 => 1], filter_value: 0, strict: true)); +?> +--EXPECT-- +Array +( +) +Array +( +) diff --git a/ext/opcache/tests/opt/gh11170.phpt b/ext/opcache/tests/opt/gh11170.phpt new file mode 100644 index 0000000000000..ca00c5e852966 --- /dev/null +++ b/ext/opcache/tests/opt/gh11170.phpt @@ -0,0 +1,145 @@ +--TEST-- +GH-11170 (Too wide OR and AND range inferred) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x400000 +opcache.preload= +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=5, args=0, vars=0, tmps=2, ssa_vars=0, no_loops) + ; (after dfa pass) + ; %s + ; return [long] RANGE[1..1] +BB0: + ; start exit lines=[0-4] + ; level=0 +0000 INIT_FCALL 0 %d string("test_or") +0001 DO_UCALL +0002 INIT_FCALL 0 %d string("test_and") +0003 DO_UCALL +0004 RETURN int(1) + +test_or: + ; (lines=11, args=0, vars=2, tmps=7, ssa_vars=11, no_loops) + ; (after dfa pass) + ; %s + ; return [long] RANGE[-20..-1] + ; #0.CV0($a) NOVAL [undef] + ; #1.CV1($b) NOVAL [undef] +BB0: + ; start lines=[0-3] + ; to=(BB2, BB1) + ; level=0 + ; children=(BB1, BB2, BB3) +0000 INIT_FCALL 0 %d string("rand") +0001 #2.V2 [long] = DO_ICALL +0002 #3.T3 [long] RANGE[MIN..MAX] = MOD #2.V2 [long] int(10) +0003 JMPZ #3.T3 [long] RANGE[MIN..MAX] BB2 + +BB1: + ; follow lines=[4-6] + ; from=(BB0) + ; to=(BB3) + ; idom=BB0 + ; level=1 +0004 #4.CV0($a) [long] RANGE[-27..-27] = QM_ASSIGN int(-27) +0005 #5.CV1($b) [long] RANGE[-20..-20] = QM_ASSIGN int(-20) +0006 JMP BB3 + +BB2: + ; target lines=[7-8] + ; from=(BB0) + ; to=(BB3) + ; idom=BB0 + ; level=1 +0007 #6.CV0($a) [long] RANGE[-7..-7] = QM_ASSIGN int(-7) +0008 #7.CV1($b) [long] RANGE[-10..-10] = QM_ASSIGN int(-10) + +BB3: + ; follow target exit lines=[9-10] + ; from=(BB1, BB2) + ; idom=BB0 + ; level=1 + #8.CV0($a) [long] RANGE[-27..-7] = Phi(#4.CV0($a) [long] RANGE[-27..-27], #6.CV0($a) [long] RANGE[-7..-7]) + #9.CV1($b) [long] RANGE[-20..-10] = Phi(#5.CV1($b) [long] RANGE[-20..-20], #7.CV1($b) [long] RANGE[-10..-10]) +0009 #10.T8 [long] RANGE[-20..-1] = BW_OR #8.CV0($a) [long] RANGE[-27..-7] #9.CV1($b) [long] RANGE[-20..-10] +0010 RETURN #10.T8 [long] RANGE[-20..-1] + +test_and: + ; (lines=11, args=0, vars=2, tmps=7, ssa_vars=11, no_loops) + ; (after dfa pass) + ; %s + ; return [long] RANGE[-28..-25] + ; #0.CV0($a) NOVAL [undef] + ; #1.CV1($b) NOVAL [undef] +BB0: + ; start lines=[0-3] + ; to=(BB2, BB1) + ; level=0 + ; children=(BB1, BB2, BB3) +0000 INIT_FCALL 0 %d string("rand") +0001 #2.V2 [long] = DO_ICALL +0002 #3.T3 [long] RANGE[MIN..MAX] = MOD #2.V2 [long] int(10) +0003 JMPZ #3.T3 [long] RANGE[MIN..MAX] BB2 + +BB1: + ; follow lines=[4-6] + ; from=(BB0) + ; to=(BB3) + ; idom=BB0 + ; level=1 +0004 #4.CV0($a) [long] RANGE[-12..-12] = QM_ASSIGN int(-12) +0005 #5.CV1($b) [long] RANGE[-27..-27] = QM_ASSIGN int(-27) +0006 JMP BB3 + +BB2: + ; target lines=[7-8] + ; from=(BB0) + ; to=(BB3) + ; idom=BB0 + ; level=1 +0007 #6.CV0($a) [long] RANGE[-9..-9] = QM_ASSIGN int(-9) +0008 #7.CV1($b) [long] RANGE[-25..-25] = QM_ASSIGN int(-25) + +BB3: + ; follow target exit lines=[9-10] + ; from=(BB1, BB2) + ; idom=BB0 + ; level=1 + #8.CV0($a) [long] RANGE[-12..-9] = Phi(#4.CV0($a) [long] RANGE[-12..-12], #6.CV0($a) [long] RANGE[-9..-9]) + #9.CV1($b) [long] RANGE[-27..-25] = Phi(#5.CV1($b) [long] RANGE[-27..-27], #7.CV1($b) [long] RANGE[-25..-25]) +0009 #10.T8 [long] RANGE[-28..-25] = BW_AND #8.CV0($a) [long] RANGE[-12..-9] #9.CV1($b) [long] RANGE[-27..-25] +0010 RETURN #10.T8 [long] RANGE[-28..-25] diff --git a/ext/opcache/tests/opt/inference_002.phpt b/ext/opcache/tests/opt/inference_002.phpt index 70412426c2fcc..3d8c69d054e5d 100644 --- a/ext/opcache/tests/opt/inference_002.phpt +++ b/ext/opcache/tests/opt/inference_002.phpt @@ -9,7 +9,7 @@ opcache.optimization_level=-1 var_dump([[]=>&$x]); ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Illegal offset type in %sinference_002.php:2 +Fatal error: Uncaught TypeError: Cannot access offset of type array on array in %sinference_002.php:2 Stack trace: #0 {main} - thrown in %sinference_002.php on line 2 \ No newline at end of file + thrown in %sinference_002.php on line 2 diff --git a/ext/opcache/tests/opt/match_002.phpt b/ext/opcache/tests/opt/match_002.phpt new file mode 100644 index 0000000000000..ecda31ee7c0ec --- /dev/null +++ b/ext/opcache/tests/opt/match_002.phpt @@ -0,0 +1,15 @@ +--TEST-- +Match 002: memory leak because of incorrect optimization +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Undefined constant "y" in %smatch_002.php:2 +Stack trace: +#0 {main} + thrown in %smatch_002.php on line 2 diff --git a/ext/opcache/tests/opt/match_003.phpt b/ext/opcache/tests/opt/match_003.phpt new file mode 100644 index 0000000000000..1d55d01b6213a --- /dev/null +++ b/ext/opcache/tests/opt/match_003.phpt @@ -0,0 +1,15 @@ +--TEST-- +Match 003: SSA integrity verification failed because of incorrect optimization +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Call to undefined function y() in %smatch_003.php:2 +Stack trace: +#0 {main} + thrown in %smatch_003.php on line 2 diff --git a/ext/opcache/tests/opt/type_inference_final_class.phpt b/ext/opcache/tests/opt/type_inference_final_class.phpt new file mode 100644 index 0000000000000..f75fd9a121205 --- /dev/null +++ b/ext/opcache/tests/opt/type_inference_final_class.phpt @@ -0,0 +1,42 @@ +--TEST-- +Type inference test with final class +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x20000 +opcache.preload= +--EXTENSIONS-- +opcache +--FILE-- +getInt(); + } +} + +?> +--EXPECTF-- +$_main: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s +0000 RETURN int(1) + +Test::getInt: + ; (lines=1, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s +0000 RETURN int(42) + +Test::getInt2: + ; (lines=2, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s +0000 V0 = QM_ASSIGN int(42) +0001 RETURN V0 diff --git a/ext/opcache/tests/preload_006.phpt b/ext/opcache/tests/preload_006.phpt index d97a492c68466..c72532f41c7b8 100644 --- a/ext/opcache/tests/preload_006.phpt +++ b/ext/opcache/tests/preload_006.phpt @@ -10,7 +10,7 @@ opcache --SKIPIF-- --FILE-- --FILE-- --FILE-- OK diff --git a/ext/opcache/tests/preload_trait_static.phpt b/ext/opcache/tests/preload_trait_static.phpt index 1fed1c11c2aad..cbf09c57a07d0 100644 --- a/ext/opcache/tests/preload_trait_static.phpt +++ b/ext/opcache/tests/preload_trait_static.phpt @@ -10,7 +10,6 @@ opcache --SKIPIF-- --FILE-- +--FILE-- +count_global_server()); +?> +--EXPECTF-- +int(%d) diff --git a/ext/opcache/zend_accelerator_debug.h b/ext/opcache/zend_accelerator_debug.h index f4887a2c3fcab..4a19da57b5e62 100644 --- a/ext/opcache/zend_accelerator_debug.h +++ b/ext/opcache/zend_accelerator_debug.h @@ -28,7 +28,11 @@ #define ACCEL_LOG_INFO 3 #define ACCEL_LOG_DEBUG 4 +BEGIN_EXTERN_C() + void zend_accel_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_NORETURN void zend_accel_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +END_EXTERN_C() + #endif /* _ZEND_ACCELERATOR_DEBUG_H */ diff --git a/ext/opcache/zend_accelerator_hash.c b/ext/opcache/zend_accelerator_hash.c index 676ed32ce8ff3..2fd3dfb5ed56e 100644 --- a/ext/opcache/zend_accelerator_hash.c +++ b/ext/opcache/zend_accelerator_hash.c @@ -25,9 +25,9 @@ #include "zend_shared_alloc.h" /* Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */ -static uint32_t prime_numbers[] = +static const uint32_t prime_numbers[] = {5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }; -static uint32_t num_prime_numbers = sizeof(prime_numbers) / sizeof(uint32_t); +static const uint32_t num_prime_numbers = sizeof(prime_numbers) / sizeof(uint32_t); void zend_accel_hash_clean(zend_accel_hash *accel_hash) { diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 2eb0b38a7a38b..6b1c872fe0520 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -72,8 +72,8 @@ static ZEND_INI_MH(OnUpdateMemoryConsumption) zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption is set below the required 8MB.\n"); return FAILURE; } - if (UNEXPECTED(memsize > ZEND_ULONG_MAX / (1024 * 1024))) { - *p = ZEND_ULONG_MAX; + if (UNEXPECTED(memsize > ZEND_LONG_MAX / (1024 * 1024))) { + *p = ZEND_LONG_MAX; } else { *p = memsize * (1024 * 1024); } @@ -129,6 +129,19 @@ static ZEND_INI_MH(OnUpdateMaxWastedPercentage) return SUCCESS; } +static ZEND_INI_MH(OnUpdateConsistencyChecks) +{ + zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); + zend_long consistency_checks = atoi(ZSTR_VAL(new_value)); + + if (consistency_checks != 0) { + zend_accel_error(ACCEL_LOG_WARNING, "opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624).\n"); + return FAILURE; + } + *p = 0; + return SUCCESS; +} + static ZEND_INI_MH(OnEnable) { if (stage == ZEND_INI_STAGE_STARTUP || @@ -245,6 +258,19 @@ static ZEND_INI_MH(OnUpdateUnrollL) ZEND_JIT_TRACE_MAX_LOOPS_UNROLL); return FAILURE; } + +static ZEND_INI_MH(OnUpdateMaxTraceLength) +{ + zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); + if (val > 3 && val <= ZEND_JIT_TRACE_MAX_LENGTH) { + zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); + *p = val; + return SUCCESS; + } + zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 4 and %d", ZSTR_VAL(entry->name), + ZEND_JIT_TRACE_MAX_LENGTH); + return FAILURE; +} #endif ZEND_INI_BEGIN() @@ -263,7 +289,7 @@ ZEND_INI_BEGIN() STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "8" , PHP_INI_SYSTEM, OnUpdateInternedStringsBuffer, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "10000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals) - STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateLong, accel_directives.consistency_checks, zend_accel_globals, accel_globals) + STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateConsistencyChecks, accel_directives.consistency_checks, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.file_update_protection", "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.file_update_protection, zend_accel_globals, accel_globals) @@ -323,6 +349,7 @@ ZEND_INI_BEGIN() STD_PHP_INI_ENTRY("opcache.jit_max_recursive_calls" , "2", PHP_INI_ALL, OnUpdateUnrollC, max_recursive_calls, zend_jit_globals, jit_globals) STD_PHP_INI_ENTRY("opcache.jit_max_recursive_returns" , "2", PHP_INI_ALL, OnUpdateUnrollR, max_recursive_returns, zend_jit_globals, jit_globals) STD_PHP_INI_ENTRY("opcache.jit_max_polymorphic_calls" , "2", PHP_INI_ALL, OnUpdateLong, max_polymorphic_calls, zend_jit_globals, jit_globals) + STD_PHP_INI_ENTRY("opcache.jit_max_trace_length" , "1024", PHP_INI_ALL, OnUpdateMaxTraceLength, max_trace_length, zend_jit_globals, jit_globals) #endif ZEND_INI_END() @@ -700,15 +727,15 @@ ZEND_FUNCTION(opcache_get_status) } if (zend_hash_num_elements(&ZCSG(preload_script)->script.class_table)) { - zend_class_entry *ce; + zval *zv; zend_string *key; array_init(&scripts); - ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ZCSG(preload_script)->script.class_table, key, ce) { - if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) { + ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(&ZCSG(preload_script)->script.class_table, key, zv) { + if (Z_TYPE_P(zv) == IS_ALIAS_PTR) { add_next_index_str(&scripts, key); } else { - add_next_index_str(&scripts, ce->name); + add_next_index_str(&scripts, Z_CE_P(zv)->name); } } ZEND_HASH_FOREACH_END(); add_assoc_zval(&statistics, "classes", &scripts); @@ -836,6 +863,7 @@ ZEND_FUNCTION(opcache_get_configuration) add_assoc_long(&directives, "opcache.jit_max_root_traces", JIT_G(max_root_traces)); add_assoc_long(&directives, "opcache.jit_max_side_traces", JIT_G(max_side_traces)); add_assoc_long(&directives, "opcache.jit_prof_threshold", JIT_G(prof_threshold)); + add_assoc_long(&directives, "opcache.jit_max_trace_length", JIT_G(max_trace_length)); #endif add_assoc_zval(return_value, "directives", &directives); diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index c5efdc3f33abf..b99a50b212828 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -27,6 +27,11 @@ #include "zend_shared_alloc.h" #include "zend_observer.h" +#ifdef __SSE2__ +/* For SSE2 adler32 */ +#include +#endif + typedef int (*id_function_t)(void *, void *); typedef void (*unique_copy_ctor_func_t)(void *pElement); @@ -451,11 +456,62 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, #define ADLER32_NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ -#define ADLER32_DO1(buf) {s1 += *(buf); s2 += s1;} -#define ADLER32_DO2(buf, i) ADLER32_DO1(buf + i); ADLER32_DO1(buf + i + 1); -#define ADLER32_DO4(buf, i) ADLER32_DO2(buf, i); ADLER32_DO2(buf, i + 2); -#define ADLER32_DO8(buf, i) ADLER32_DO4(buf, i); ADLER32_DO4(buf, i + 4); -#define ADLER32_DO16(buf) ADLER32_DO8(buf, 0); ADLER32_DO8(buf, 8); +#define ADLER32_SCALAR_DO1(buf) {s1 += *(buf); s2 += s1;} +#define ADLER32_SCALAR_DO2(buf, i) ADLER32_SCALAR_DO1(buf + i); ADLER32_SCALAR_DO1(buf + i + 1); +#define ADLER32_SCALAR_DO4(buf, i) ADLER32_SCALAR_DO2(buf, i); ADLER32_SCALAR_DO2(buf, i + 2); +#define ADLER32_SCALAR_DO8(buf, i) ADLER32_SCALAR_DO4(buf, i); ADLER32_SCALAR_DO4(buf, i + 4); +#define ADLER32_SCALAR_DO16(buf) ADLER32_SCALAR_DO8(buf, 0); ADLER32_SCALAR_DO8(buf, 8); + +static zend_always_inline void adler32_do16_loop(unsigned char *buf, unsigned char *end, unsigned int *s1_out, unsigned int *s2_out) +{ + unsigned int s1 = *s1_out; + unsigned int s2 = *s2_out; + +#ifdef __SSE2__ + const __m128i zero = _mm_setzero_si128(); + + __m128i accumulate_s2 = zero; + unsigned int accumulate_s1 = 0; + + do { + __m128i read = _mm_loadu_si128((__m128i *) buf); /* [A:P] */ + + /* Split the 8-bit-element vector into two 16-bit-element vectors where each element gets zero-extended from 8-bits to 16-bits */ + __m128i lower = _mm_unpacklo_epi8(read, zero); /* [A:H] zero-extended to 16-bits */ + __m128i higher = _mm_unpackhi_epi8(read, zero); /* [I:P] zero-extended to 16-bits */ + lower = _mm_madd_epi16(lower, _mm_set_epi16(9, 10, 11, 12, 13, 14, 15, 16)); /* [A * 16:H * 9] */ + higher = _mm_madd_epi16(higher, _mm_set_epi16(1, 2, 3, 4, 5, 6, 7, 8)); /* [I * 8:P * 1] */ + + /* We'll cheat here: it's difficult to add 16-bit elementwise, but we can do 32-bit additions. + * The highest value the sum of two elements of the vectors can take is 0xff * 16 + 0xff * 8 < 0xffff. + * That means there is no carry possible from 16->17 bits so the 32-bit addition is safe. */ + __m128i sum = _mm_add_epi32(lower, higher); /* [A * 16 + I * 8:H * 9 + P * 1] */ + accumulate_s2 = _mm_add_epi32(accumulate_s2, sum); + accumulate_s1 += s1; + + /* Computes 8-bit element-wise abs(buf - zero) and then sums the elements into two 16 bit parts */ + sum = _mm_sad_epu8(read, zero); + s1 += _mm_cvtsi128_si32(sum) + _mm_extract_epi16(sum, 4); + + buf += 16; + } while (buf != end); + + /* For convenience, let's do a rename of variables and let accumulate_s2 = [X, Y, Z, W] */ + __m128i shuffled = _mm_shuffle_epi32(accumulate_s2, _MM_SHUFFLE(1, 0, 0, 2)); /* [Y, X, X, Z] */ + accumulate_s2 = _mm_add_epi32(accumulate_s2, shuffled); /* [X + Y, Y + X, Z + X, W + Z] */ + shuffled = _mm_shuffle_epi32(accumulate_s2, _MM_SHUFFLE(3, 3, 3, 3)); /* [X + Y, X + Y, X + Y, X + Y] */ + accumulate_s2 = _mm_add_epi32(accumulate_s2, shuffled); /* [/, /, /, W + Z + X + Y] */ + s2 += accumulate_s1 * 16 + _mm_cvtsi128_si32(accumulate_s2); +#else + do { + ADLER32_SCALAR_DO16(buf); + buf += 16; + } while (buf != end); +#endif + + *s1_out = s1; + *s2_out = s2; +} unsigned int zend_adler32(unsigned int checksum, unsigned char *buf, uint32_t len) { @@ -466,10 +522,8 @@ unsigned int zend_adler32(unsigned int checksum, unsigned char *buf, uint32_t le while (len >= ADLER32_NMAX) { len -= ADLER32_NMAX; end = buf + ADLER32_NMAX; - do { - ADLER32_DO16(buf); - buf += 16; - } while (buf != end); + adler32_do16_loop(buf, end, &s1, &s2); + buf = end; s1 %= ADLER32_BASE; s2 %= ADLER32_BASE; } @@ -478,15 +532,13 @@ unsigned int zend_adler32(unsigned int checksum, unsigned char *buf, uint32_t le if (len >= 16) { end = buf + (len & 0xfff0); len &= 0xf; - do { - ADLER32_DO16(buf); - buf += 16; - } while (buf != end); + adler32_do16_loop(buf, end, &s1, &s2); + buf = end; } if (len) { end = buf + len; do { - ADLER32_DO1(buf); + ADLER32_SCALAR_DO1(buf); buf++; } while (buf != end); } diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 1cd639403f68b..f4c9a77996b96 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -692,12 +692,12 @@ static void zend_file_cache_serialize_class_constant(zval *z SERIALIZE_PTR(c->ce); zend_file_cache_serialize_zval(&c->value, script, info, buf); - if (c->doc_comment) { SERIALIZE_STR(c->doc_comment); } SERIALIZE_ATTRIBUTES(c->attributes); + zend_file_cache_serialize_type(&c->type, script, info, buf); } } } @@ -1098,7 +1098,7 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm) #if defined(__AVX__) || defined(__SSE2__) /* Align to 64-byte boundary */ mem = emalloc(script->size + 64); - buf = (void*)(((zend_uintptr_t)mem + 63L) & ~63L); + buf = (void*)(((uintptr_t)mem + 63L) & ~63L); #else mem = buf = emalloc(script->size); #endif @@ -1531,6 +1531,7 @@ static void zend_file_cache_unserialize_class_constant(zval * UNSERIALIZE_STR(c->doc_comment); } UNSERIALIZE_ATTRIBUTES(c->attributes); + zend_file_cache_unserialize_type(&c->type, c->ce, script, buf); } } } @@ -1834,7 +1835,7 @@ zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handl #if defined(__AVX__) || defined(__SSE2__) /* Align to 64-byte boundary */ mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size + 64); - mem = (void*)(((zend_uintptr_t)mem + 63L) & ~63L); + mem = (void*)(((uintptr_t)mem + 63L) & ~63L); #else mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size); #endif diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index dcff7a7883289..e21aaa069348a 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -37,11 +37,13 @@ #define zend_set_str_gc_flags(str) do { \ GC_SET_REFCOUNT(str, 2); \ + uint32_t flags = GC_STRING | (ZSTR_IS_VALID_UTF8(str) ? IS_STR_VALID_UTF8 : 0); \ if (file_cache_only) { \ - GC_TYPE_INFO(str) = GC_STRING | (IS_STR_INTERNED << GC_FLAGS_SHIFT); \ + flags |= (IS_STR_INTERNED << GC_FLAGS_SHIFT); \ } else { \ - GC_TYPE_INFO(str) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT); \ + flags |= ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT); \ } \ + GC_TYPE_INFO(str) = flags; \ } while (0) #define zend_accel_store_string(str) do { \ @@ -134,7 +136,7 @@ static void zend_hash_persist(HashTable *ht) hash_size >>= 1; } ht->nTableMask = (uint32_t)(-(int32_t)hash_size); - ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ + ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ HT_SET_DATA_ADDR(ht, ZCG(mem)); ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE((hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket)))); HT_HASH_RESET(ht); @@ -155,7 +157,7 @@ static void zend_hash_persist(HashTable *ht) void *data = ZCG(mem); void *old_data = HT_GET_DATA_ADDR(ht); - ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ + ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ ZCG(mem) = (void*)((char*)data + ZEND_ALIGNED_SIZE(HT_USED_SIZE(ht))); memcpy(data, old_data, HT_USED_SIZE(ht)); if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { @@ -259,6 +261,7 @@ static void zend_persist_zval(zval *z) zend_persist_ast(GC_AST(old_ref)); Z_TYPE_FLAGS_P(z) = 0; GC_SET_REFCOUNT(Z_COUNTED_P(z), 1); + GC_ADD_FLAGS(Z_COUNTED_P(z), GC_IMMUTABLE); efree(old_ref); } break; @@ -837,6 +840,7 @@ static void zend_persist_class_constant(zval *zv) if (c->attributes) { c->attributes = zend_persist_attributes(c->attributes); } + zend_persist_type(&c->type); } zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce) @@ -1079,7 +1083,15 @@ void zend_update_parent_ce(zend_class_entry *ce) end = parent->parent ? parent->parent->default_static_members_count : 0; for (; i >= end; i--) { zval *p = &ce->default_static_members_table[i]; - ZVAL_INDIRECT(p, &parent->default_static_members_table[i]); + /* The static property may have been overridden by a trait + * during inheritance. In that case, the property default + * value is replaced by zend_declare_typed_property() at the + * property index of the parent property. Make sure we only + * point to the parent property value if the child value was + * already indirect. */ + if (Z_TYPE_P(p) == IS_INDIRECT) { + ZVAL_INDIRECT(p, &parent->default_static_members_table[i]); + } } parent = parent->parent; @@ -1306,7 +1318,7 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script script->mem = ZCG(mem); - ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ + ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ script = zend_shared_memdup_free(script, sizeof(zend_persistent_script)); script->corrupted = false; @@ -1321,9 +1333,9 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script #if defined(__AVX__) || defined(__SSE2__) /* Align to 64-byte boundary */ - ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L); + ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 63L) & ~63L); #else - ZEND_ASSERT(((zend_uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ + ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */ #endif #ifdef HAVE_JIT diff --git a/ext/opcache/zend_persist.h b/ext/opcache/zend_persist.h index 4c7d6f2eeee15..930430c9589b7 100644 --- a/ext/opcache/zend_persist.h +++ b/ext/opcache/zend_persist.h @@ -22,6 +22,8 @@ #ifndef ZEND_PERSIST_H #define ZEND_PERSIST_H +BEGIN_EXTERN_C() + uint32_t zend_accel_script_persist_calc(zend_persistent_script *script, int for_shm); zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, int for_shm); @@ -31,4 +33,6 @@ void zend_update_parent_ce(zend_class_entry *ce); void zend_persist_warnings_calc(uint32_t num_warnings, zend_error_info **warnings); zend_error_info **zend_persist_warnings(uint32_t num_warnings, zend_error_info **warnings); +END_EXTERN_C() + #endif /* ZEND_PERSIST_H */ diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 4e3af0d68c653..dfc281eb7f6f7 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -399,6 +399,7 @@ static void zend_persist_class_constant_calc(zval *zv) if (c->attributes) { zend_persist_attributes_calc(c->attributes); } + zend_persist_type_calc(&c->type); } } diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index 3f18a4db6040e..6fbf8ea20ae12 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -19,6 +19,13 @@ +----------------------------------------------------------------------+ */ +#if defined(__linux__) && defined(HAVE_MEMFD_CREATE) +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# include +#endif + #include #include "ZendAccelerator.h" #include "zend_shared_alloc.h" @@ -81,6 +88,18 @@ void zend_shared_alloc_create_lock(char *lockfile_path) zts_lock = tsrm_mutex_alloc(); #endif +#if defined(__linux__) && defined(HAVE_MEMFD_CREATE) + /* on Linux, we can use a memfd instead of a "real" file, so + * we can do this without a writable filesystem and without + * needing to clean up */ + /* note: FreeBSD has memfd_create(), too, but fcntl(F_SETLKW) + * on it fails with EBADF, therefore we use this only on + * Linux */ + lock_file = memfd_create("opcache_lock", MFD_CLOEXEC); + if (lock_file >= 0) + return; +#endif + snprintf(lockfile_name, sizeof(lockfile_name), "%s/%sXXXXXX", lockfile_path, SEM_FILENAME_PREFIX); lock_file = mkstemp(lockfile_name); if (lock_file == -1) { @@ -97,7 +116,7 @@ void zend_shared_alloc_create_lock(char *lockfile_path) } #endif -static void no_memory_bailout(size_t allocate_size, char *error) +static void no_memory_bailout(size_t allocate_size, const char *error) { zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Unable to allocate shared memory segment of %zu bytes: %s: %s (%d)", allocate_size, error?error:"unknown", strerror(errno), errno ); } @@ -117,7 +136,7 @@ static void copy_shared_segments(void *to, void *from, int count, int size) } } -static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in) +static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, const char **error_in) { int res; g_shared_alloc_handler = he->handler; @@ -151,7 +170,7 @@ int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size) zend_shared_segment **tmp_shared_segments; size_t shared_segments_array_size; zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals; - char *error_in = NULL; + const char *error_in = NULL; const zend_shared_memory_handler_entry *he; int res = ALLOC_FAILURE; int i; @@ -169,7 +188,7 @@ int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size) #endif if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) { - char *model = ZCG(accel_directives).memory_model; + const char *model = ZCG(accel_directives).memory_model; /* "cgi" is really "shm"... */ if (strncmp(ZCG(accel_directives).memory_model, "cgi", sizeof("cgi")) == 0) { model = "shm"; @@ -336,6 +355,8 @@ static size_t zend_shared_alloc_get_largest_free_block(void) void *zend_shared_alloc(size_t size) { + ZEND_ASSERT(ZCG(locked)); + int i; unsigned int block_size = ZEND_ALIGNED_SIZE(size); @@ -343,11 +364,6 @@ void *zend_shared_alloc(size_t size) zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Possible integer overflow in shared memory allocation (%zu + %zu)", size, PLATFORM_ALIGNMENT); } -#if 1 - if (!ZCG(locked)) { - zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Shared memory lock not obtained"); - } -#endif if (block_size > ZSMMG(shared_free)) { /* No hope to find a big-enough block */ SHARED_ALLOC_FAILED(); return NULL; @@ -358,7 +374,7 @@ void *zend_shared_alloc(size_t size) ZSMMG(shared_segments)[i]->pos += block_size; ZSMMG(shared_free) -= block_size; - ZEND_ASSERT(((zend_uintptr_t)retval & 0x7) == 0); /* should be 8 byte aligned */ + ZEND_ASSERT(((uintptr_t)retval & 0x7) == 0); /* should be 8 byte aligned */ return retval; } } @@ -416,32 +432,32 @@ static zend_always_inline void *_zend_shared_memdup(void *source, size_t size, b void *zend_shared_memdup_get_put_free(void *source, size_t size) { - return _zend_shared_memdup(source, size, 1, 1, 1); + return _zend_shared_memdup(source, size, true, true, true); } void *zend_shared_memdup_put_free(void *source, size_t size) { - return _zend_shared_memdup(source, size, 0, 1, 1); + return _zend_shared_memdup(source, size, false, true, true); } void *zend_shared_memdup_free(void *source, size_t size) { - return _zend_shared_memdup(source, size, 0, 0, 1); + return _zend_shared_memdup(source, size, false, false, true); } void *zend_shared_memdup_get_put(void *source, size_t size) { - return _zend_shared_memdup(source, size, 1, 1, 0); + return _zend_shared_memdup(source, size, true, true, false); } void *zend_shared_memdup_put(void *source, size_t size) { - return _zend_shared_memdup(source, size, 0, 1, 0); + return _zend_shared_memdup(source, size, false, true, false); } void *zend_shared_memdup(void *source, size_t size) { - return _zend_shared_memdup(source, size, 0, 0, 0); + return _zend_shared_memdup(source, size, false, false, false); } void zend_shared_alloc_safe_unlock(void) @@ -453,6 +469,8 @@ void zend_shared_alloc_safe_unlock(void) void zend_shared_alloc_lock(void) { + ZEND_ASSERT(!ZCG(locked)); + #ifndef ZEND_WIN32 struct flock mem_write_lock; @@ -490,6 +508,8 @@ void zend_shared_alloc_lock(void) void zend_shared_alloc_unlock(void) { + ZEND_ASSERT(ZCG(locked)); + #ifndef ZEND_WIN32 struct flock mem_write_unlock; @@ -540,18 +560,18 @@ void zend_shared_alloc_restore_xlat_table(uint32_t checkpoint) zend_hash_discard(&ZCG(xlat_table), checkpoint); } -void zend_shared_alloc_register_xlat_entry(const void *old, const void *new) +void zend_shared_alloc_register_xlat_entry(const void *key_pointer, const void *value) { - zend_ulong key = (zend_ulong)old; + zend_ulong key = (zend_ulong)key_pointer; key = zend_rotr3(key); - zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, (void*)new); + zend_hash_index_add_new_ptr(&ZCG(xlat_table), key, (void*)value); } -void *zend_shared_alloc_get_xlat_entry(const void *old) +void *zend_shared_alloc_get_xlat_entry(const void *key_pointer) { void *retval; - zend_ulong key = (zend_ulong)old; + zend_ulong key = (zend_ulong)key_pointer; key = zend_rotr3(key); if ((retval = zend_hash_index_find_ptr(&ZCG(xlat_table), key)) == NULL) { @@ -592,7 +612,7 @@ const char *zend_accel_get_shared_model(void) return g_shared_model; } -void zend_accel_shared_protect(int mode) +void zend_accel_shared_protect(bool protected) { #ifdef HAVE_MPROTECT int i; @@ -601,11 +621,7 @@ void zend_accel_shared_protect(int mode) return; } - if (mode) { - mode = PROT_READ; - } else { - mode = PROT_READ|PROT_WRITE; - } + const int mode = protected ? PROT_READ : PROT_READ|PROT_WRITE; for (i = 0; i < ZSMMG(shared_segments_count); i++) { mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, mode); @@ -617,11 +633,7 @@ void zend_accel_shared_protect(int mode) return; } - if (mode) { - mode = PAGE_READONLY; - } else { - mode = PAGE_READWRITE; - } + const int mode = protected ? PAGE_READONLY : PAGE_READWRITE; for (i = 0; i < ZSMMG(shared_segments_count); i++) { DWORD oldProtect; @@ -632,19 +644,19 @@ void zend_accel_shared_protect(int mode) #endif } -int zend_accel_in_shm(void *ptr) +bool zend_accel_in_shm(void *ptr) { int i; if (!smm_shared_globals) { - return 0; + return false; } for (i = 0; i < ZSMMG(shared_segments_count); i++) { if ((char*)ptr >= (char*)ZSMMG(shared_segments)[i]->p && (char*)ptr < (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->end) { - return 1; + return true; } } - return 0; + return false; } diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h index 1caf678e36fe4..ac7ec3e33f34b 100644 --- a/ext/opcache/zend_shared_alloc.h +++ b/ext/opcache/zend_shared_alloc.h @@ -80,7 +80,7 @@ typedef struct _zend_shared_segment { void *p; } zend_shared_segment; -typedef int (*create_segments_t)(size_t requested_size, zend_shared_segment ***shared_segments, int *shared_segment_count, char **error_in); +typedef int (*create_segments_t)(size_t requested_size, zend_shared_segment ***shared_segments, int *shared_segment_count, const char **error_in); typedef int (*detach_segment_t)(zend_shared_segment *shared_segment); typedef struct { @@ -91,7 +91,7 @@ typedef struct { typedef struct _handler_entry { const char *name; - zend_shared_memory_handlers *handler; + const zend_shared_memory_handlers *handler; } zend_shared_memory_handler_entry; typedef struct _zend_shared_memory_state { @@ -141,7 +141,7 @@ static inline void *zend_shared_alloc_aligned(size_t size) { #if defined(__AVX__) || defined(__SSE2__) /* Align to 64-byte boundary */ void *p = zend_shared_alloc(size + 64); - return (void *)(((zend_uintptr_t)p + 63L) & ~63L); + return (void *)(((uintptr_t)p + 63L) & ~63L); #else return zend_shared_alloc(size); #endif @@ -157,7 +157,7 @@ void *zend_shared_memdup(void *source, size_t size); int zend_shared_memdup_size(void *p, size_t size); -int zend_accel_in_shm(void *ptr); +bool zend_accel_in_shm(void *ptr); typedef union _align_test { void *ptr; @@ -185,31 +185,36 @@ void zend_shared_alloc_destroy_xlat_table(void); void zend_shared_alloc_clear_xlat_table(void); uint32_t zend_shared_alloc_checkpoint_xlat_table(void); void zend_shared_alloc_restore_xlat_table(uint32_t checkpoint); -void zend_shared_alloc_register_xlat_entry(const void *old, const void *new); -void *zend_shared_alloc_get_xlat_entry(const void *old); +void zend_shared_alloc_register_xlat_entry(const void *key, const void *value); +void *zend_shared_alloc_get_xlat_entry(const void *key); size_t zend_shared_alloc_get_free_memory(void); void zend_shared_alloc_save_state(void); void zend_shared_alloc_restore_state(void); const char *zend_accel_get_shared_model(void); -/* memory write protection */ -void zend_accel_shared_protect(int mode); +/** + * Memory write protection + * + * @param protected true to protect shared memory (read-only), false + * to unprotect shared memory (writable) + */ +void zend_accel_shared_protect(bool protected); #ifdef USE_MMAP -extern zend_shared_memory_handlers zend_alloc_mmap_handlers; +extern const zend_shared_memory_handlers zend_alloc_mmap_handlers; #endif #ifdef USE_SHM -extern zend_shared_memory_handlers zend_alloc_shm_handlers; +extern const zend_shared_memory_handlers zend_alloc_shm_handlers; #endif #ifdef USE_SHM_OPEN -extern zend_shared_memory_handlers zend_alloc_posix_handlers; +extern const zend_shared_memory_handlers zend_alloc_posix_handlers; #endif #ifdef ZEND_WIN32 -extern zend_shared_memory_handlers zend_alloc_win32_handlers; +extern const zend_shared_memory_handlers zend_alloc_win32_handlers; void zend_shared_alloc_create_lock(void); void zend_shared_alloc_lock_win32(void); void zend_shared_alloc_unlock_win32(void); diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index e377b7a92eed2..f74f25c30403e 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -450,7 +450,7 @@ static int X509_get_signature_nid(const X509 *x) PHP_OPENSSL_CHECK_NUMBER_CONVERSION_NULL_RETURN(ZEND_LONG_EXCEEDS_INT(_var), _name) /* {{{ php_openssl_store_errors */ -void php_openssl_store_errors() +void php_openssl_store_errors(void) { struct php_openssl_errors *errors; int error_code = ERR_get_error(); @@ -1672,7 +1672,7 @@ PHP_FUNCTION(openssl_spki_verify) PHP_FUNCTION(openssl_spki_export) { size_t spkstr_len; - char *spkstr, * spkstr_cleaned = NULL, * s = NULL; + char *spkstr, * spkstr_cleaned = NULL; int spkstr_cleaned_len; EVP_PKEY *pkey = NULL; @@ -1727,9 +1727,6 @@ PHP_FUNCTION(openssl_spki_export) if (spkstr_cleaned != NULL) { efree(spkstr_cleaned); } - if (s != NULL) { - efree(s); - } } /* }}} */ @@ -2600,11 +2597,13 @@ PHP_FUNCTION(openssl_pkcs12_export_to_file) if (p12 != NULL) { bio_out = BIO_new_file(file_path, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY)); if (bio_out != NULL) { - - i2d_PKCS12_bio(bio_out, p12); + if (i2d_PKCS12_bio(bio_out, p12) == 0) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Error writing to file %s", file_path); + } else { + RETVAL_TRUE; + } BIO_free(bio_out); - - RETVAL_TRUE; } else { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Error opening file %s", file_path); @@ -5288,7 +5287,11 @@ PHP_FUNCTION(openssl_pkcs7_verify) } if (p7bout) { - PEM_write_bio_PKCS7(p7bout, p7); + if (PEM_write_bio_PKCS7(p7bout, p7) == 0) { + php_error_docref(NULL, E_WARNING, "Failed to write PKCS7 to file"); + php_openssl_store_errors(); + RETVAL_FALSE; + } } } } else { @@ -5873,7 +5876,11 @@ PHP_FUNCTION(openssl_cms_verify) } if (p7bout) { - PEM_write_bio_CMS(p7bout, cms); + if (PEM_write_bio_CMS(p7bout, cms) == 0) { + php_error_docref(NULL, E_WARNING, "Failed to write CMS to file"); + php_openssl_store_errors(); + RETVAL_FALSE; + } } } } else { diff --git a/ext/openssl/tests/ServerClientTestCase.inc b/ext/openssl/tests/ServerClientTestCase.inc index 753366df6f4be..1b140b63f6b4a 100644 --- a/ext/openssl/tests/ServerClientTestCase.inc +++ b/ext/openssl/tests/ServerClientTestCase.inc @@ -72,8 +72,9 @@ class ServerClientTestCase ); } else { $cmd = sprintf( - '%s "%s" %s %s', + '%s %s "%s" %s %s', PHP_BINARY, + getenv('TEST_PHP_EXTRA_ARGS'), __FILE__, WORKER_ARGV_VALUE, $worker diff --git a/ext/openssl/tests/bug80747.phpt b/ext/openssl/tests/bug80747.phpt index cc7770ea68e5b..b21fc4d9dcda3 100644 --- a/ext/openssl/tests/bug80747.phpt +++ b/ext/openssl/tests/bug80747.phpt @@ -1,6 +1,5 @@ --TEST-- Bug #80747: Providing RSA key size < 512 generates key that crash PHP ---FILE-- --EXTENSIONS-- openssl --SKIPIF-- diff --git a/ext/openssl/tests/openssl_pkey_new_error.phpt b/ext/openssl/tests/openssl_pkey_new_error.phpt index 3db214aa4fbd4..f32292677bac5 100644 --- a/ext/openssl/tests/openssl_pkey_new_error.phpt +++ b/ext/openssl/tests/openssl_pkey_new_error.phpt @@ -28,6 +28,6 @@ try { } ?> --EXPECT-- -openssl_pkey_get_details(): Argument #1 ($key) must be of type OpenSSLAsymmetricKey, bool given -openssl_pkey_get_details(): Argument #1 ($key) must be of type OpenSSLAsymmetricKey, bool given -openssl_pkey_get_details(): Argument #1 ($key) must be of type OpenSSLAsymmetricKey, bool given +openssl_pkey_get_details(): Argument #1 ($key) must be of type OpenSSLAsymmetricKey, false given +openssl_pkey_get_details(): Argument #1 ($key) must be of type OpenSSLAsymmetricKey, false given +openssl_pkey_get_details(): Argument #1 ($key) must be of type OpenSSLAsymmetricKey, false given diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 048076808925d..7b604be043a5c 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -513,7 +513,7 @@ static bool php_openssl_matches_common_name(X509 *peer, const char *subject_name } /* }}} */ -static int php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stream) /* {{{ */ +static zend_result php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stream) /* {{{ */ { zval *val = NULL; zval *peer_fingerprint; @@ -840,7 +840,7 @@ static long php_openssl_load_stream_cafile(X509_STORE *cert_store, const char *c } /* }}} */ -static int php_openssl_enable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */ +static zend_result php_openssl_enable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */ { zval *val = NULL; char *cafile = NULL; @@ -900,7 +900,7 @@ static void php_openssl_disable_peer_verification(SSL_CTX *ctx, php_stream *stre } /* }}} */ -static int php_openssl_set_local_cert(SSL_CTX *ctx, php_stream *stream) /* {{{ */ +static zend_result php_openssl_set_local_cert(SSL_CTX *ctx, php_stream *stream) /* {{{ */ { zval *val = NULL; char *certfile = NULL; @@ -1204,7 +1204,7 @@ static RSA *php_openssl_tmp_rsa_cb(SSL *s, int is_export, int keylength) } #endif -static int php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* {{{ */ +static zend_result php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* {{{ */ { zval *zdhpath = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "dh_param"); if (zdhpath == NULL) { @@ -1237,7 +1237,7 @@ static int php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* return FAILURE; } - if (SSL_CTX_set0_tmp_dh_pkey(ctx, pkey) < 0) { + if (SSL_CTX_set0_tmp_dh_pkey(ctx, pkey) == 0) { php_error_docref(NULL, E_WARNING, "Failed assigning DH params"); EVP_PKEY_free(pkey); return FAILURE; @@ -1251,7 +1251,7 @@ static int php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* return FAILURE; } - if (SSL_CTX_set_tmp_dh(ctx, dh) < 0) { + if (SSL_CTX_set_tmp_dh(ctx, dh) == 0) { php_error_docref(NULL, E_WARNING, "Failed assigning DH params"); DH_free(dh); return FAILURE; @@ -1265,7 +1265,7 @@ static int php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* /* }}} */ #if defined(HAVE_ECDH) && PHP_OPENSSL_API_VERSION < 0x10100 -static int php_openssl_set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx) /* {{{ */ +static zend_result php_openssl_set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx) /* {{{ */ { zval *zvcurve; int curve_nid; @@ -1301,7 +1301,7 @@ static int php_openssl_set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx) / /* }}} */ #endif -static int php_openssl_set_server_specific_opts(php_stream *stream, SSL_CTX *ctx) /* {{{ */ +static zend_result php_openssl_set_server_specific_opts(php_stream *stream, SSL_CTX *ctx) /* {{{ */ { zval *zv; long ssl_ctx_options = SSL_CTX_get_options(ctx); @@ -1320,7 +1320,10 @@ static int php_openssl_set_server_specific_opts(php_stream *stream, SSL_CTX *ctx php_error_docref(NULL, E_WARNING, "rsa_key_size context option has been removed"); } - php_openssl_set_server_dh_param(stream, ctx); + if (php_openssl_set_server_dh_param(stream, ctx) == FAILURE) { + return FAILURE; + } + zv = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "single_dh_use"); if (zv == NULL || zend_is_true(zv)) { ssl_ctx_options |= SSL_OP_SINGLE_DH_USE; @@ -1397,7 +1400,7 @@ static SSL_CTX *php_openssl_create_sni_server_ctx(char *cert_path, char *key_pat } /* }}} */ -static int php_openssl_enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */ +static zend_result php_openssl_enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */ { zval *val; zval *current; @@ -1608,7 +1611,7 @@ static int php_openssl_server_alpn_callback(SSL *ssl_handle, #endif -int php_openssl_setup_crypto(php_stream *stream, +zend_result php_openssl_setup_crypto(php_stream *stream, php_openssl_netstream_data_t *sslsock, php_stream_xport_crypto_param *cparam) /* {{{ */ { @@ -1633,7 +1636,7 @@ int php_openssl_setup_crypto(php_stream *stream, ERR_clear_error(); /* We need to do slightly different things based on client/server method - * so lets remember which method was selected */ + * so let's remember which method was selected */ sslsock->is_client = cparam->inputs.method & STREAM_CRYPTO_IS_CLIENT; method_flags = cparam->inputs.method & ~STREAM_CRYPTO_IS_CLIENT; @@ -2426,8 +2429,15 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val if (sslsock->s.socket == -1) { alive = 0; - } else if ((!sslsock->ssl_active && value == 0 && ((MSG_DONTWAIT != 0) || !sslsock->s.is_blocked)) || - php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) { + } else if ( + ( + !sslsock->ssl_active && + value == 0 && + !(stream->flags & PHP_STREAM_FLAG_NO_IO) && + ((MSG_DONTWAIT != 0) || !sslsock->s.is_blocked) + ) || + php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0 + ) { /* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */ /* additionally, we don't use this optimization if SSL is active because in that case, we're not using MSG_DONTWAIT */ if (sslsock->ssl_active) { diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 9e2ac8e0e6994..bd4c32ca408c2 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -58,6 +58,8 @@ #include "pcntl_arginfo.h" +#include "Zend/zend_max_execution_timer.h" + ZEND_DECLARE_MODULE_GLOBALS(pcntl) static PHP_GINIT_FUNCTION(pcntl); @@ -184,6 +186,8 @@ PHP_FUNCTION(pcntl_fork) if (id == -1) { PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error %d", errno); + } else if (id == 0) { + zend_max_execution_timer_init(); } RETURN_LONG((zend_long) id); @@ -654,7 +658,7 @@ PHP_FUNCTION(pcntl_signal) zend_string *func_name = zend_get_callable_name(handle); PCNTL_G(last_error) = EINVAL; - zend_argument_type_error(2, "must be of type callable|int, %s given", zend_zval_type_name(handle)); + zend_argument_type_error(2, "must be of type callable|int, %s given", zend_zval_value_name(handle)); zend_string_release_ex(func_name, 0); efree(error); RETURN_THROWS(); @@ -1074,7 +1078,7 @@ static void pcntl_signal_handler(int signo) } } -void pcntl_signal_dispatch() +void pcntl_signal_dispatch(void) { zval params[2], *handle, retval; struct php_pcntl_pending_signal *queue, *next; diff --git a/ext/pcntl/tests/bug81577_3.phpt b/ext/pcntl/tests/bug81577_3.phpt index cd77324aebd0f..1a30deaebaaba 100644 --- a/ext/pcntl/tests/bug81577_3.phpt +++ b/ext/pcntl/tests/bug81577_3.phpt @@ -3,7 +3,7 @@ Bug #81577: (Exceptions in interrupt handlers: cleanup_live_vars) --EXTENSIONS-- pcntl posix ---XFAIL-- +--XLEAK-- leaks are not fixed yet --FILE-- preg_options : 0; - } - if (compile_options) { - *compile_options = pce ? pce->compile_options : 0; - } - if (capture_count) { - *capture_count = pce ? pce->capture_count : 0; - } - - return pce ? pce->re : NULL; -} -/* }}} */ - /* XXX For the cases where it's only about match yes/no and no capture required, perhaps just a minimum sized data would suffice. */ PHPAPI pcre2_match_data *php_pcre_create_match_data(uint32_t capture_count, pcre2_code *re) @@ -2457,7 +2438,12 @@ PHP_FUNCTION(preg_replace_callback_array) } if (subject_ht) { - RETURN_ARR(subject_ht); + RETVAL_ARR(subject_ht); + // Unset the type_flags of immutable arrays to prevent the VM from performing refcounting + if (GC_FLAGS(subject_ht) & IS_ARRAY_IMMUTABLE) { + Z_TYPE_FLAGS_P(return_value) = 0; + } + return; } else { RETURN_STR(subject_str); } diff --git a/ext/pcre/php_pcre.h b/ext/pcre/php_pcre.h index 267ad91179d07..a7c4b9cb1c359 100644 --- a/ext/pcre/php_pcre.h +++ b/ext/pcre/php_pcre.h @@ -27,7 +27,6 @@ PHPAPI zend_string *php_pcre_replace(zend_string *regex, zend_string *subject_str, const char *subject, size_t subject_len, zend_string *replace_str, size_t limit, size_t *replace_count); PHPAPI pcre2_code* pcre_get_compiled_regex(zend_string *regex, uint32_t *capture_count); -PHPAPI pcre2_code* pcre_get_compiled_regex_ex(zend_string *regex, uint32_t *capture_count, uint32_t *preg_options, uint32_t *coptions); extern zend_module_entry pcre_module_entry; #define pcre_module_ptr &pcre_module_entry diff --git a/ext/pcre/tests/gh10968.phpt b/ext/pcre/tests/gh10968.phpt new file mode 100644 index 0000000000000..873d17e79da86 --- /dev/null +++ b/ext/pcre/tests/gh10968.phpt @@ -0,0 +1,11 @@ +--TEST-- +GH-10968: preg_replace_callback_array() segmentation fault +--FILE-- + +--EXPECT-- +array(0) { +} +string(0) "" diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 47c9072da56e0..b4664e60fb790 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -461,7 +461,7 @@ static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt zend_string *key; ZVAL_STR(&query_string, stmt->query_string); - key = zend_string_init("queryString", sizeof("queryString") - 1, 0); + key = ZSTR_INIT_LITERAL("queryString", 0); zend_std_write_property(Z_OBJ_P(object), key, &query_string, NULL); zend_string_release_ex(key, 0); @@ -521,7 +521,7 @@ PHP_METHOD(PDO, prepare) if (options && (value = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS)) != NULL) { if (Z_TYPE_P(value) != IS_ARRAY) { zend_type_error("PDO::ATTR_STATEMENT_CLASS value must be of type array, %s given", - zend_zval_type_name(value)); + zend_zval_value_name(value)); RETURN_THROWS(); } if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL) { @@ -545,7 +545,7 @@ PHP_METHOD(PDO, prepare) if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) { if (Z_TYPE_P(item) != IS_ARRAY) { zend_type_error("PDO::ATTR_STATEMENT_CLASS constructor_args must be of type ?array, %s given", - zend_zval_type_name(value)); + zend_zval_value_name(value)); RETURN_THROWS(); } ZVAL_COPY_VALUE(&ctor_args, item); @@ -698,7 +698,7 @@ PDO_API bool pdo_get_long_param(zend_long *lval, zval *value) } ZEND_FALLTHROUGH; default: - zend_type_error("Attribute value must be of type int for selected attribute, %s given", zend_zval_type_name(value)); + zend_type_error("Attribute value must be of type int for selected attribute, %s given", zend_zval_value_name(value)); return false; } } @@ -716,7 +716,7 @@ PDO_API bool pdo_get_bool_param(bool *bval, zval *value) return true; case IS_STRING: /* TODO Should string be allowed? */ default: - zend_type_error("Attribute value must be of type bool for selected attribute, %s given", zend_zval_type_name(value)); + zend_type_error("Attribute value must be of type bool for selected attribute, %s given", zend_zval_value_name(value)); return false; } } @@ -812,7 +812,7 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) / } if (Z_TYPE_P(value) != IS_ARRAY) { zend_type_error("PDO::ATTR_STATEMENT_CLASS value must be of type array, %s given", - zend_zval_type_name(value)); + zend_zval_value_name(value)); return false; } if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL) { @@ -840,7 +840,7 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) / if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) { if (Z_TYPE_P(item) != IS_ARRAY) { zend_type_error("PDO::ATTR_STATEMENT_CLASS constructor_args must be of type ?array, %s given", - zend_zval_type_name(value)); + zend_zval_value_name(value)); return false; } ZVAL_COPY(&dbh->def_stmt_ctor_args, item); @@ -1164,7 +1164,7 @@ PHP_METHOD(PDO, query) PHP_METHOD(PDO, quote) { pdo_dbh_t *dbh = Z_PDO_DBH_P(ZEND_THIS); - zend_string *str; + zend_string *str, *quoted; zend_long paramtype = PDO_PARAM_STR; ZEND_PARSE_PARAMETERS_START(1, 2) @@ -1180,8 +1180,14 @@ PHP_METHOD(PDO, quote) pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support quoting"); RETURN_FALSE; } + quoted = dbh->methods->quoter(dbh, str, paramtype); - RETURN_STR(dbh->methods->quoter(dbh, str, paramtype)); + if (quoted == NULL) { + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; + } + + RETURN_STR(quoted); } /* }}} */ diff --git a/ext/pdo/pdo_sql_parser.re b/ext/pdo/pdo_sql_parser.re index 4c20700379731..6bb0837fb31f9 100644 --- a/ext/pdo/pdo_sql_parser.re +++ b/ext/pdo/pdo_sql_parser.re @@ -242,6 +242,13 @@ safe: if (buf) { zend_string_release_ex(buf, 0); } + if (plc->quoted == NULL) { + /* bork */ + ret = -1; + strncpy(stmt->error_code, stmt->dbh->error_code, 6); + goto clean_up; + } + } else { pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource"); ret = -1; diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 65f0900075af0..2d0010eb747a8 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -1280,7 +1280,7 @@ PHP_METHOD(PDOStatement, fetchAll) /* Figure out correct class */ if (arg2) { if (Z_TYPE_P(arg2) != IS_STRING) { - zend_argument_type_error(2, "must be of type string, %s given", zend_zval_type_name(arg2)); + zend_argument_type_error(2, "must be of type string, %s given", zend_zval_value_name(arg2)); RETURN_THROWS(); } stmt->fetch.cls.ce = zend_fetch_class(Z_STR_P(arg2), ZEND_FETCH_CLASS_AUTO); @@ -1333,7 +1333,7 @@ PHP_METHOD(PDOStatement, fetchAll) if (arg2) { // Reuse convert_to_long(arg2); ? if (Z_TYPE_P(arg2) != IS_LONG) { - zend_argument_type_error(2, "must be of type int, %s given", zend_zval_type_name(arg2)); + zend_argument_type_error(2, "must be of type int, %s given", zend_zval_value_name(arg2)); RETURN_THROWS(); } if (Z_LVAL_P(arg2) < 0) { @@ -1752,7 +1752,7 @@ bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_a return false; } if (Z_TYPE(args[0]) != IS_LONG) { - zend_argument_type_error(arg1_arg_num, "must be of type int, %s given", zend_zval_type_name(&args[0])); + zend_argument_type_error(arg1_arg_num, "must be of type int, %s given", zend_zval_value_name(&args[0])); return false; } if (Z_LVAL(args[0]) < 0) { @@ -1794,7 +1794,7 @@ bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_a return false; } if (Z_TYPE(args[0]) != IS_STRING) { - zend_argument_type_error(arg1_arg_num, "must be of type string, %s given", zend_zval_type_name(&args[0])); + zend_argument_type_error(arg1_arg_num, "must be of type string, %s given", zend_zval_value_name(&args[0])); return false; } cep = zend_lookup_class(Z_STR(args[0])); @@ -1807,7 +1807,7 @@ bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_a if (variadic_num_args == 2) { if (Z_TYPE(args[1]) != IS_NULL && Z_TYPE(args[1]) != IS_ARRAY) { zend_argument_type_error(constructor_arg_num, "must be of type ?array, %s given", - zend_zval_type_name(&args[1])); + zend_zval_value_name(&args[1])); return false; } if (Z_TYPE(args[1]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[1]))) { @@ -1834,7 +1834,7 @@ bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_a return false; } if (Z_TYPE(args[0]) != IS_OBJECT) { - zend_argument_type_error(arg1_arg_num, "must be of type object, %s given", zend_zval_type_name(&args[0])); + zend_argument_type_error(arg1_arg_num, "must be of type object, %s given", zend_zval_value_name(&args[0])); return false; } diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index 2a946c81dc242..c16eb07c59604 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -41,7 +41,7 @@ static char *pdo_dblib_get_field_name(int type) * (example: varchar is reported as char by dbprtype) * * FIX ME: Cache datatypes from server systypes table in pdo_dblib_handle_factory() - * to make this future proof. + * to make this future-proof. */ switch (type) { @@ -243,7 +243,7 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno) len = snprintf(buf, sizeof(buf), "computed%d", S->computed_column_name_count); col->name = zend_string_init(buf, len, 0); } else { - col->name = zend_string_init("computed", strlen("computed"), 0); + col->name = ZSTR_INIT_LITERAL("computed", 0); } S->computed_column_name_count++; diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 7dc40f510d459..cbd7ee7cfd377 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -671,7 +671,7 @@ static zend_string* firebird_handle_quoter(pdo_dbh_t *dbh, const zend_string *un zend_string *quoted_str; if (ZSTR_LEN(unquoted) == 0) { - return zend_string_init("''", 2, 0); + return ZSTR_INIT_LITERAL("''", 0); } /* Firebird only requires single quotes to be doubled if string lengths are used */ diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index 71fee89570cbc..4ad51ab483d96 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -30,6 +30,37 @@ #define RECORD_ERROR(stmt) _firebird_error(NULL, stmt, __FILE__, __LINE__) +#define READ_AND_RETURN_USING_MEMCPY(type, sqldata) do { \ + type ret; \ + memcpy(&ret, sqldata, sizeof(ret)); \ + return ret; \ + } while (0); + +static zend_always_inline ISC_INT64 get_isc_int64_from_sqldata(const ISC_SCHAR *sqldata) +{ + READ_AND_RETURN_USING_MEMCPY(ISC_INT64, sqldata); +} + +static zend_always_inline ISC_LONG get_isc_long_from_sqldata(const ISC_SCHAR *sqldata) +{ + READ_AND_RETURN_USING_MEMCPY(ISC_LONG, sqldata); +} + +static zend_always_inline double get_double_from_sqldata(const ISC_SCHAR *sqldata) +{ + READ_AND_RETURN_USING_MEMCPY(double, sqldata); +} + +static zend_always_inline ISC_TIMESTAMP get_isc_timestamp_from_sqldata(const ISC_SCHAR *sqldata) +{ + READ_AND_RETURN_USING_MEMCPY(ISC_TIMESTAMP, sqldata); +} + +static zend_always_inline ISC_QUAD get_isc_quad_from_sqldata(const ISC_SCHAR *sqldata) +{ + READ_AND_RETURN_USING_MEMCPY(ISC_QUAD, sqldata); +} + /* free the allocated space for passing field values to the db and back */ static void free_sqlda(XSQLDA const *sqlda) /* {{{ */ { @@ -380,10 +411,10 @@ static int firebird_stmt_get_col( n = *(short*)var->sqldata; break; case SQL_LONG: - n = *(ISC_LONG*)var->sqldata; + n = get_isc_long_from_sqldata(var->sqldata); break; case SQL_INT64: - n = *(ISC_INT64*)var->sqldata; + n = get_isc_int64_from_sqldata(var->sqldata); break; case SQL_DOUBLE: break; @@ -391,7 +422,7 @@ static int firebird_stmt_get_col( } if ((var->sqltype & ~1) == SQL_DOUBLE) { - str = zend_strpprintf(0, "%.*F", -var->sqlscale, *(double*)var->sqldata); + str = zend_strpprintf(0, "%.*F", -var->sqlscale, get_double_from_sqldata(var->sqldata)); } else if (n >= 0) { str = zend_strpprintf(0, "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -var->sqlscale, n % f); @@ -417,13 +448,13 @@ static int firebird_stmt_get_col( ZVAL_LONG(result, *(short*)var->sqldata); break; case SQL_LONG: - ZVAL_LONG(result, *(ISC_LONG*)var->sqldata); + ZVAL_LONG(result, get_isc_long_from_sqldata(var->sqldata)); break; case SQL_INT64: #if SIZEOF_ZEND_LONG >= 8 - ZVAL_LONG(result, *(ISC_INT64*)var->sqldata); + ZVAL_LONG(result, get_isc_int64_from_sqldata(var->sqldata)); #else - ZVAL_STR(result, zend_strpprintf(0, "%" LL_MASK "d", *(ISC_INT64*)var->sqldata)); + ZVAL_STR(result, zend_strpprintf(0, "%" LL_MASK "d", get_isc_int64_from_sqldata(var->sqldata))); #endif break; case SQL_FLOAT: @@ -432,7 +463,7 @@ static int firebird_stmt_get_col( break; case SQL_DOUBLE: /* TODO: Why is this not returned as the native type? */ - ZVAL_STR(result, zend_strpprintf(0, "%F", *(double*)var->sqldata)); + ZVAL_STR(result, zend_strpprintf(0, "%F", get_double_from_sqldata(var->sqldata))); break; #ifdef SQL_BOOLEAN case SQL_BOOLEAN: @@ -448,7 +479,10 @@ static int firebird_stmt_get_col( fmt = S->H->time_format ? S->H->time_format : PDO_FB_DEF_TIME_FMT; } else if (0) { case SQL_TIMESTAMP: - isc_decode_timestamp((ISC_TIMESTAMP*)var->sqldata, &t); + { + ISC_TIMESTAMP timestamp = get_isc_timestamp_from_sqldata(var->sqldata); + isc_decode_timestamp(×tamp, &t); + } fmt = S->H->timestamp_format ? S->H->timestamp_format : PDO_FB_DEF_TIMESTAMP_FMT; } /* convert the timestamp into a string */ @@ -456,8 +490,10 @@ static int firebird_stmt_get_col( size_t len = strftime(buf, sizeof(buf), fmt, &t); ZVAL_STRINGL(result, buf, len); break; - case SQL_BLOB: - return firebird_fetch_blob(stmt, colno, result, (ISC_QUAD*)var->sqldata); + case SQL_BLOB: { + ISC_QUAD quad = get_isc_quad_from_sqldata(var->sqldata); + return firebird_fetch_blob(stmt, colno, result, &quad); + } } } } @@ -610,7 +646,12 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat *var->sqlind = -1; return 1; } - return firebird_bind_blob(stmt, (ISC_QUAD*)var->sqldata, parameter); + ISC_QUAD quad = get_isc_quad_from_sqldata(var->sqldata); + if (firebird_bind_blob(stmt, &quad, parameter) != 0) { + memcpy(var->sqldata, &quad, sizeof(quad)); + return 1; + } + return 0; } } diff --git a/ext/pdo_firebird/tests/gh10908.phpt b/ext/pdo_firebird/tests/gh10908.phpt new file mode 100644 index 0000000000000..a1e8271ffd19b --- /dev/null +++ b/ext/pdo_firebird/tests/gh10908.phpt @@ -0,0 +1,146 @@ +--TEST-- +GH-10908 (Bus error with PDO Firebird on RPI with 64 bit kernel and 32 bit userland) +--EXTENSIONS-- +pdo_firebird +--SKIPIF-- + +--ENV-- +LSAN_OPTIONS=detect_leaks=0 +--FILE-- +exec($sql); +$dbh->exec("INSERT INTO gh10908 VALUES(1, 'ABC', 12.34, 1.0, 2.0, '2023-03-24 17:39', '2023-03-24', '17:39', 'abcdefg', 32767, 200000, 'azertyuiop', false);"); + +function query_and_dump($dbh, $sql) { + foreach ($dbh->query($sql) as $row) { + print_r($row); + print("\n"); + } +} + +query_and_dump($dbh, "SELECT CODE FROM gh10908"); // works fine +query_and_dump($dbh, "SELECT ID FROM gh10908"); // Used to "bus error" +query_and_dump($dbh, "SELECT NUM FROM gh10908"); // Used to "bus error" +query_and_dump($dbh, "SELECT DBL FROM gh10908"); // Used to "bus error" +query_and_dump($dbh, "SELECT TS FROM gh10908"); // Used to "bus error" +query_and_dump($dbh, "SELECT MYBLOB FROM gh10908"); // Used to "bus error" +query_and_dump($dbh, "SELECT * FROM gh10908"); // Used to "bus error" + +query_and_dump($dbh, "SELECT CAST(NUM AS NUMERIC(9, 3)) FROM gh10908"); // works fine +query_and_dump($dbh, "SELECT CAST(ID AS INTEGER) FROM gh10908"); // works fine +query_and_dump($dbh, "SELECT CAST(ID AS BIGINT) FROM gh10908"); // Used to "bus error" + +echo "Did not crash\n"; + +?> +--CLEAN-- +exec("DROP TABLE gh10908"); +?> +--EXPECT-- +Array +( + [CODE] => ABC + [0] => ABC +) + +Array +( + [ID] => 1 + [0] => 1 +) + +Array +( + [NUM] => 12.340 + [0] => 12.340 +) + +Array +( + [DBL] => 1.000000 + [0] => 1.000000 +) + +Array +( + [TS] => 2023-03-24 17:39:00 + [0] => 2023-03-24 17:39:00 +) + +Array +( + [MYBLOB] => abcdefg + [0] => abcdefg +) + +Array +( + [ID] => 1 + [0] => 1 + [CODE] => ABC + [1] => ABC + [NUM] => 12.340 + [2] => 12.340 + [DBL] => 1.000000 + [3] => 1.000000 + [FLT] => 2.000000 + [4] => 2.000000 + [TS] => 2023-03-24 17:39:00 + [5] => 2023-03-24 17:39:00 + [MYDATE] => 2023-03-24 + [6] => 2023-03-24 + [MYTIME] => 17:39:00 + [7] => 17:39:00 + [MYBLOB] => abcdefg + [8] => abcdefg + [MYSMALLINT] => 32767 + [9] => 32767 + [MYINT] => 200000 + [10] => 200000 + [MYCHAR] => azertyuiop + [11] => azertyuiop + [MYBOOL] => + [12] => +) + +Array +( + [CAST] => 12.340 + [0] => 12.340 +) + +Array +( + [CAST] => 1 + [0] => 1 +) + +Array +( + [CAST] => 1 + [0] => 1 +) + +Did not crash diff --git a/ext/pdo_mysql/get_error_codes.php b/ext/pdo_mysql/get_error_codes.php deleted file mode 100755 index 27910f8dadd10..0000000000000 --- a/ext/pdo_mysql/get_error_codes.php +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env php - $state) { - echo "#ifdef $code\n"; - printf(" case %-{$maxlen}s: return \"%s\";\n", $code, $state); - echo "#endif\n"; - } - - -?> diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c index 6497b6bc81cfa..a0ccfd68015d7 100644 --- a/ext/pdo_mysql/mysql_driver.c +++ b/ext/pdo_mysql/mysql_driver.c @@ -154,9 +154,11 @@ static void mysql_handle_closer(pdo_dbh_t *dbh) if (H) { if (H->server) { mysql_close(H->server); + H->server = NULL; } if (H->einfo.errmsg) { pefree(H->einfo.errmsg, dbh->is_persistent); + H->einfo.errmsg = NULL; } pefree(H, dbh->is_persistent); dbh->driver_data = NULL; @@ -356,7 +358,7 @@ static bool mysql_handle_begin(pdo_dbh_t *dbh) PDO_DBG_ENTER("mysql_handle_begin"); PDO_DBG_INF_FMT("dbh=%p", dbh); - command = zend_string_init("START TRANSACTION", strlen("START TRANSACTION"), 0); + command = ZSTR_INIT_LITERAL("START TRANSACTION", 0); return_value = mysql_handle_doer(dbh, command); zend_string_release_ex(command, 0); PDO_DBG_RETURN(0 <= return_value); @@ -526,7 +528,7 @@ static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_ break; case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY: - ZVAL_LONG(return_value, H->buffered); + ZVAL_BOOL(return_value, H->buffered); break; case PDO_ATTR_EMULATE_PREPARES: diff --git a/ext/pdo_mysql/php_pdo_mysql_sqlstate.h b/ext/pdo_mysql/php_pdo_mysql_sqlstate.h deleted file mode 100644 index 8f8ccc0116526..0000000000000 --- a/ext/pdo_mysql/php_pdo_mysql_sqlstate.h +++ /dev/null @@ -1,646 +0,0 @@ -/* DO NOT EDIT THIS FILE!!! It is auto generated by get_error_codes.php */ -#ifdef ER_DUP_KEY - case ER_DUP_KEY : return "23000"; -#endif -#ifdef ER_OUTOFMEMORY - case ER_OUTOFMEMORY : return "HY001"; -#endif -#ifdef ER_OUT_OF_SORTMEMORY - case ER_OUT_OF_SORTMEMORY : return "HY001"; -#endif -#ifdef ER_CON_COUNT_ERROR - case ER_CON_COUNT_ERROR : return "08004"; -#endif -#ifdef ER_BAD_HOST_ERROR - case ER_BAD_HOST_ERROR : return "08S01"; -#endif -#ifdef ER_HANDSHAKE_ERROR - case ER_HANDSHAKE_ERROR : return "08S01"; -#endif -#ifdef ER_DBACCESS_DENIED_ERROR - case ER_DBACCESS_DENIED_ERROR : return "42000"; -#endif -#ifdef ER_ACCESS_DENIED_ERROR - case ER_ACCESS_DENIED_ERROR : return "28000"; -#endif -#ifdef ER_NO_DB_ERROR - case ER_NO_DB_ERROR : return "3D000"; -#endif -#ifdef ER_UNKNOWN_COM_ERROR - case ER_UNKNOWN_COM_ERROR : return "08S01"; -#endif -#ifdef ER_BAD_NULL_ERROR - case ER_BAD_NULL_ERROR : return "23000"; -#endif -#ifdef ER_BAD_DB_ERROR - case ER_BAD_DB_ERROR : return "42000"; -#endif -#ifdef ER_TABLE_EXISTS_ERROR - case ER_TABLE_EXISTS_ERROR : return "42S01"; -#endif -#ifdef ER_BAD_TABLE_ERROR - case ER_BAD_TABLE_ERROR : return "42S02"; -#endif -#ifdef ER_NON_UNIQ_ERROR - case ER_NON_UNIQ_ERROR : return "23000"; -#endif -#ifdef ER_SERVER_SHUTDOWN - case ER_SERVER_SHUTDOWN : return "08S01"; -#endif -#ifdef ER_BAD_FIELD_ERROR - case ER_BAD_FIELD_ERROR : return "42S22"; -#endif -#ifdef ER_WRONG_FIELD_WITH_GROUP - case ER_WRONG_FIELD_WITH_GROUP : return "42000"; -#endif -#ifdef ER_WRONG_GROUP_FIELD - case ER_WRONG_GROUP_FIELD : return "42000"; -#endif -#ifdef ER_WRONG_SUM_SELECT - case ER_WRONG_SUM_SELECT : return "42000"; -#endif -#ifdef ER_WRONG_VALUE_COUNT - case ER_WRONG_VALUE_COUNT : return "21S01"; -#endif -#ifdef ER_TOO_LONG_IDENT - case ER_TOO_LONG_IDENT : return "42000"; -#endif -#ifdef ER_DUP_FIELDNAME - case ER_DUP_FIELDNAME : return "42S21"; -#endif -#ifdef ER_DUP_KEYNAME - case ER_DUP_KEYNAME : return "42000"; -#endif -#ifdef ER_DUP_ENTRY - case ER_DUP_ENTRY : return "23000"; -#endif -#ifdef ER_WRONG_FIELD_SPEC - case ER_WRONG_FIELD_SPEC : return "42000"; -#endif -#ifdef ER_PARSE_ERROR - case ER_PARSE_ERROR : return "42000"; -#endif -#ifdef ER_EMPTY_QUERY - case ER_EMPTY_QUERY : return "42000"; -#endif -#ifdef ER_NONUNIQ_TABLE - case ER_NONUNIQ_TABLE : return "42000"; -#endif -#ifdef ER_INVALID_DEFAULT - case ER_INVALID_DEFAULT : return "42000"; -#endif -#ifdef ER_MULTIPLE_PRI_KEY - case ER_MULTIPLE_PRI_KEY : return "42000"; -#endif -#ifdef ER_TOO_MANY_KEYS - case ER_TOO_MANY_KEYS : return "42000"; -#endif -#ifdef ER_TOO_MANY_KEY_PARTS - case ER_TOO_MANY_KEY_PARTS : return "42000"; -#endif -#ifdef ER_TOO_LONG_KEY - case ER_TOO_LONG_KEY : return "42000"; -#endif -#ifdef ER_KEY_COLUMN_DOES_NOT_EXITS - case ER_KEY_COLUMN_DOES_NOT_EXITS : return "42000"; -#endif -#ifdef ER_BLOB_USED_AS_KEY - case ER_BLOB_USED_AS_KEY : return "42000"; -#endif -#ifdef ER_TOO_BIG_FIELDLENGTH - case ER_TOO_BIG_FIELDLENGTH : return "42000"; -#endif -#ifdef ER_WRONG_AUTO_KEY - case ER_WRONG_AUTO_KEY : return "42000"; -#endif -#ifdef ER_FORCING_CLOSE - case ER_FORCING_CLOSE : return "08S01"; -#endif -#ifdef ER_IPSOCK_ERROR - case ER_IPSOCK_ERROR : return "08S01"; -#endif -#ifdef ER_NO_SUCH_INDEX - case ER_NO_SUCH_INDEX : return "42S12"; -#endif -#ifdef ER_WRONG_FIELD_TERMINATORS - case ER_WRONG_FIELD_TERMINATORS : return "42000"; -#endif -#ifdef ER_BLOBS_AND_NO_TERMINATED - case ER_BLOBS_AND_NO_TERMINATED : return "42000"; -#endif -#ifdef ER_CANT_REMOVE_ALL_FIELDS - case ER_CANT_REMOVE_ALL_FIELDS : return "42000"; -#endif -#ifdef ER_CANT_DROP_FIELD_OR_KEY - case ER_CANT_DROP_FIELD_OR_KEY : return "42000"; -#endif -#ifdef ER_BLOB_CANT_HAVE_DEFAULT - case ER_BLOB_CANT_HAVE_DEFAULT : return "42000"; -#endif -#ifdef ER_WRONG_DB_NAME - case ER_WRONG_DB_NAME : return "42000"; -#endif -#ifdef ER_WRONG_TABLE_NAME - case ER_WRONG_TABLE_NAME : return "42000"; -#endif -#ifdef ER_TOO_BIG_SELECT - case ER_TOO_BIG_SELECT : return "42000"; -#endif -#ifdef ER_UNKNOWN_PROCEDURE - case ER_UNKNOWN_PROCEDURE : return "42000"; -#endif -#ifdef ER_WRONG_PARAMCOUNT_TO_PROCEDURE - case ER_WRONG_PARAMCOUNT_TO_PROCEDURE : return "42000"; -#endif -#ifdef ER_UNKNOWN_TABLE - case ER_UNKNOWN_TABLE : return "42S02"; -#endif -#ifdef ER_FIELD_SPECIFIED_TWICE - case ER_FIELD_SPECIFIED_TWICE : return "42000"; -#endif -#ifdef ER_UNSUPPORTED_EXTENSION - case ER_UNSUPPORTED_EXTENSION : return "42000"; -#endif -#ifdef ER_TABLE_MUST_HAVE_COLUMNS - case ER_TABLE_MUST_HAVE_COLUMNS : return "42000"; -#endif -#ifdef ER_UNKNOWN_CHARACTER_SET - case ER_UNKNOWN_CHARACTER_SET : return "42000"; -#endif -#ifdef ER_TOO_BIG_ROWSIZE - case ER_TOO_BIG_ROWSIZE : return "42000"; -#endif -#ifdef ER_WRONG_OUTER_JOIN - case ER_WRONG_OUTER_JOIN : return "42000"; -#endif -#ifdef ER_NULL_COLUMN_IN_INDEX - case ER_NULL_COLUMN_IN_INDEX : return "42000"; -#endif -#ifdef ER_PASSWORD_ANONYMOUS_USER - case ER_PASSWORD_ANONYMOUS_USER : return "42000"; -#endif -#ifdef ER_PASSWORD_NOT_ALLOWED - case ER_PASSWORD_NOT_ALLOWED : return "42000"; -#endif -#ifdef ER_PASSWORD_NO_MATCH - case ER_PASSWORD_NO_MATCH : return "42000"; -#endif -#ifdef ER_WRONG_VALUE_COUNT_ON_ROW - case ER_WRONG_VALUE_COUNT_ON_ROW : return "21S01"; -#endif -#ifdef ER_INVALID_USE_OF_NULL - case ER_INVALID_USE_OF_NULL : return "22004"; -#endif -#ifdef ER_REGEXP_ERROR - case ER_REGEXP_ERROR : return "42000"; -#endif -#ifdef ER_MIX_OF_GROUP_FUNC_AND_FIELDS - case ER_MIX_OF_GROUP_FUNC_AND_FIELDS : return "42000"; -#endif -#ifdef ER_NONEXISTING_GRANT - case ER_NONEXISTING_GRANT : return "42000"; -#endif -#ifdef ER_TABLEACCESS_DENIED_ERROR - case ER_TABLEACCESS_DENIED_ERROR : return "42000"; -#endif -#ifdef ER_COLUMNACCESS_DENIED_ERROR - case ER_COLUMNACCESS_DENIED_ERROR : return "42000"; -#endif -#ifdef ER_ILLEGAL_GRANT_FOR_TABLE - case ER_ILLEGAL_GRANT_FOR_TABLE : return "42000"; -#endif -#ifdef ER_GRANT_WRONG_HOST_OR_USER - case ER_GRANT_WRONG_HOST_OR_USER : return "42000"; -#endif -#ifdef ER_NO_SUCH_TABLE - case ER_NO_SUCH_TABLE : return "42S02"; -#endif -#ifdef ER_NONEXISTING_TABLE_GRANT - case ER_NONEXISTING_TABLE_GRANT : return "42000"; -#endif -#ifdef ER_NOT_ALLOWED_COMMAND - case ER_NOT_ALLOWED_COMMAND : return "42000"; -#endif -#ifdef ER_SYNTAX_ERROR - case ER_SYNTAX_ERROR : return "42000"; -#endif -#ifdef ER_ABORTING_CONNECTION - case ER_ABORTING_CONNECTION : return "08S01"; -#endif -#ifdef ER_NET_PACKET_TOO_LARGE - case ER_NET_PACKET_TOO_LARGE : return "08S01"; -#endif -#ifdef ER_NET_READ_ERROR_FROM_PIPE - case ER_NET_READ_ERROR_FROM_PIPE : return "08S01"; -#endif -#ifdef ER_NET_FCNTL_ERROR - case ER_NET_FCNTL_ERROR : return "08S01"; -#endif -#ifdef ER_NET_PACKETS_OUT_OF_ORDER - case ER_NET_PACKETS_OUT_OF_ORDER : return "08S01"; -#endif -#ifdef ER_NET_UNCOMPRESS_ERROR - case ER_NET_UNCOMPRESS_ERROR : return "08S01"; -#endif -#ifdef ER_NET_READ_ERROR - case ER_NET_READ_ERROR : return "08S01"; -#endif -#ifdef ER_NET_READ_INTERRUPTED - case ER_NET_READ_INTERRUPTED : return "08S01"; -#endif -#ifdef ER_NET_ERROR_ON_WRITE - case ER_NET_ERROR_ON_WRITE : return "08S01"; -#endif -#ifdef ER_NET_WRITE_INTERRUPTED - case ER_NET_WRITE_INTERRUPTED : return "08S01"; -#endif -#ifdef ER_TOO_LONG_STRING - case ER_TOO_LONG_STRING : return "42000"; -#endif -#ifdef ER_TABLE_CANT_HANDLE_BLOB - case ER_TABLE_CANT_HANDLE_BLOB : return "42000"; -#endif -#ifdef ER_TABLE_CANT_HANDLE_AUTO_INCREMENT - case ER_TABLE_CANT_HANDLE_AUTO_INCREMENT : return "42000"; -#endif -#ifdef ER_WRONG_COLUMN_NAME - case ER_WRONG_COLUMN_NAME : return "42000"; -#endif -#ifdef ER_WRONG_KEY_COLUMN - case ER_WRONG_KEY_COLUMN : return "42000"; -#endif -#ifdef ER_DUP_UNIQUE - case ER_DUP_UNIQUE : return "23000"; -#endif -#ifdef ER_BLOB_KEY_WITHOUT_LENGTH - case ER_BLOB_KEY_WITHOUT_LENGTH : return "42000"; -#endif -#ifdef ER_PRIMARY_CANT_HAVE_NULL - case ER_PRIMARY_CANT_HAVE_NULL : return "42000"; -#endif -#ifdef ER_TOO_MANY_ROWS - case ER_TOO_MANY_ROWS : return "42000"; -#endif -#ifdef ER_REQUIRES_PRIMARY_KEY - case ER_REQUIRES_PRIMARY_KEY : return "42000"; -#endif -#ifdef ER_KEY_DOES_NOT_EXITS - case ER_KEY_DOES_NOT_EXITS : return "42000"; -#endif -#ifdef ER_CHECK_NO_SUCH_TABLE - case ER_CHECK_NO_SUCH_TABLE : return "42000"; -#endif -#ifdef ER_CHECK_NOT_IMPLEMENTED - case ER_CHECK_NOT_IMPLEMENTED : return "42000"; -#endif -#ifdef ER_CANT_DO_THIS_DURING_AN_TRANSACTION - case ER_CANT_DO_THIS_DURING_AN_TRANSACTION : return "25000"; -#endif -#ifdef ER_NEW_ABORTING_CONNECTION - case ER_NEW_ABORTING_CONNECTION : return "08S01"; -#endif -#ifdef ER_MASTER_NET_READ - case ER_MASTER_NET_READ : return "08S01"; -#endif -#ifdef ER_MASTER_NET_WRITE - case ER_MASTER_NET_WRITE : return "08S01"; -#endif -#ifdef ER_TOO_MANY_USER_CONNECTIONS - case ER_TOO_MANY_USER_CONNECTIONS : return "42000"; -#endif -#ifdef ER_READ_ONLY_TRANSACTION - case ER_READ_ONLY_TRANSACTION : return "25000"; -#endif -#ifdef ER_NO_PERMISSION_TO_CREATE_USER - case ER_NO_PERMISSION_TO_CREATE_USER : return "42000"; -#endif -#ifdef ER_LOCK_DEADLOCK - case ER_LOCK_DEADLOCK : return "40001"; -#endif -#ifdef ER_NO_REFERENCED_ROW - case ER_NO_REFERENCED_ROW : return "23000"; -#endif -#ifdef ER_ROW_IS_REFERENCED - case ER_ROW_IS_REFERENCED : return "23000"; -#endif -#ifdef ER_CONNECT_TO_MASTER - case ER_CONNECT_TO_MASTER : return "08S01"; -#endif -#ifdef ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT - case ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT : return "21000"; -#endif -#ifdef ER_USER_LIMIT_REACHED - case ER_USER_LIMIT_REACHED : return "42000"; -#endif -#ifdef ER_SPECIFIC_ACCESS_DENIED_ERROR - case ER_SPECIFIC_ACCESS_DENIED_ERROR : return "42000"; -#endif -#ifdef ER_NO_DEFAULT - case ER_NO_DEFAULT : return "42000"; -#endif -#ifdef ER_WRONG_VALUE_FOR_VAR - case ER_WRONG_VALUE_FOR_VAR : return "42000"; -#endif -#ifdef ER_WRONG_TYPE_FOR_VAR - case ER_WRONG_TYPE_FOR_VAR : return "42000"; -#endif -#ifdef ER_CANT_USE_OPTION_HERE - case ER_CANT_USE_OPTION_HERE : return "42000"; -#endif -#ifdef ER_NOT_SUPPORTED_YET - case ER_NOT_SUPPORTED_YET : return "42000"; -#endif -#ifdef ER_WRONG_FK_DEF - case ER_WRONG_FK_DEF : return "42000"; -#endif -#ifdef ER_OPERAND_COLUMNS - case ER_OPERAND_COLUMNS : return "21000"; -#endif -#ifdef ER_SUBQUERY_NO_1_ROW - case ER_SUBQUERY_NO_1_ROW : return "21000"; -#endif -#ifdef ER_ILLEGAL_REFERENCE - case ER_ILLEGAL_REFERENCE : return "42S22"; -#endif -#ifdef ER_DERIVED_MUST_HAVE_ALIAS - case ER_DERIVED_MUST_HAVE_ALIAS : return "42000"; -#endif -#ifdef ER_SELECT_REDUCED - case ER_SELECT_REDUCED : return "01000"; -#endif -#ifdef ER_TABLENAME_NOT_ALLOWED_HERE - case ER_TABLENAME_NOT_ALLOWED_HERE : return "42000"; -#endif -#ifdef ER_NOT_SUPPORTED_AUTH_MODE - case ER_NOT_SUPPORTED_AUTH_MODE : return "08004"; -#endif -#ifdef ER_SPATIAL_CANT_HAVE_NULL - case ER_SPATIAL_CANT_HAVE_NULL : return "42000"; -#endif -#ifdef ER_COLLATION_CHARSET_MISMATCH - case ER_COLLATION_CHARSET_MISMATCH : return "42000"; -#endif -#ifdef ER_WARN_TOO_FEW_RECORDS - case ER_WARN_TOO_FEW_RECORDS : return "01000"; -#endif -#ifdef ER_WARN_TOO_MANY_RECORDS - case ER_WARN_TOO_MANY_RECORDS : return "01000"; -#endif -#ifdef ER_WARN_NULL_TO_NOTNULL - case ER_WARN_NULL_TO_NOTNULL : return "22004"; -#endif -#ifdef ER_WARN_DATA_OUT_OF_RANGE - case ER_WARN_DATA_OUT_OF_RANGE : return "22003"; -#endif -#ifdef ER_WRONG_NAME_FOR_INDEX - case ER_WRONG_NAME_FOR_INDEX : return "42000"; -#endif -#ifdef ER_WRONG_NAME_FOR_CATALOG - case ER_WRONG_NAME_FOR_CATALOG : return "42000"; -#endif -#ifdef ER_UNKNOWN_STORAGE_ENGINE - case ER_UNKNOWN_STORAGE_ENGINE : return "42000"; -#endif -#ifdef ER_TRUNCATED_WRONG_VALUE - case ER_TRUNCATED_WRONG_VALUE : return "22007"; -#endif -#ifdef ER_SP_NO_RECURSIVE_CREATE - case ER_SP_NO_RECURSIVE_CREATE : return "2F003"; -#endif -#ifdef ER_SP_ALREADY_EXISTS - case ER_SP_ALREADY_EXISTS : return "42000"; -#endif -#ifdef ER_SP_DOES_NOT_EXIST - case ER_SP_DOES_NOT_EXIST : return "42000"; -#endif -#ifdef ER_SP_LILABEL_MISMATCH - case ER_SP_LILABEL_MISMATCH : return "42000"; -#endif -#ifdef ER_SP_LABEL_REDEFINE - case ER_SP_LABEL_REDEFINE : return "42000"; -#endif -#ifdef ER_SP_LABEL_MISMATCH - case ER_SP_LABEL_MISMATCH : return "42000"; -#endif -#ifdef ER_SP_UNINIT_VAR - case ER_SP_UNINIT_VAR : return "01000"; -#endif -#ifdef ER_SP_BADSELECT - case ER_SP_BADSELECT : return "0A000"; -#endif -#ifdef ER_SP_BADRETURN - case ER_SP_BADRETURN : return "42000"; -#endif -#ifdef ER_SP_BADSTATEMENT - case ER_SP_BADSTATEMENT : return "0A000"; -#endif -#ifdef ER_UPDATE_LOG_DEPRECATED_IGNORED - case ER_UPDATE_LOG_DEPRECATED_IGNORED : return "42000"; -#endif -#ifdef ER_UPDATE_LOG_DEPRECATED_TRANSLATED - case ER_UPDATE_LOG_DEPRECATED_TRANSLATED : return "42000"; -#endif -#ifdef ER_QUERY_INTERRUPTED - case ER_QUERY_INTERRUPTED : return "70100"; -#endif -#ifdef ER_SP_WRONG_NO_OF_ARGS - case ER_SP_WRONG_NO_OF_ARGS : return "42000"; -#endif -#ifdef ER_SP_COND_MISMATCH - case ER_SP_COND_MISMATCH : return "42000"; -#endif -#ifdef ER_SP_NORETURN - case ER_SP_NORETURN : return "42000"; -#endif -#ifdef ER_SP_NORETURNEND - case ER_SP_NORETURNEND : return "2F005"; -#endif -#ifdef ER_SP_BAD_CURSOR_QUERY - case ER_SP_BAD_CURSOR_QUERY : return "42000"; -#endif -#ifdef ER_SP_BAD_CURSOR_SELECT - case ER_SP_BAD_CURSOR_SELECT : return "42000"; -#endif -#ifdef ER_SP_CURSOR_MISMATCH - case ER_SP_CURSOR_MISMATCH : return "42000"; -#endif -#ifdef ER_SP_CURSOR_ALREADY_OPEN - case ER_SP_CURSOR_ALREADY_OPEN : return "24000"; -#endif -#ifdef ER_SP_CURSOR_NOT_OPEN - case ER_SP_CURSOR_NOT_OPEN : return "24000"; -#endif -#ifdef ER_SP_UNDECLARED_VAR - case ER_SP_UNDECLARED_VAR : return "42000"; -#endif -#ifdef ER_SP_FETCH_NO_DATA - case ER_SP_FETCH_NO_DATA : return "02000"; -#endif -#ifdef ER_SP_DUP_PARAM - case ER_SP_DUP_PARAM : return "42000"; -#endif -#ifdef ER_SP_DUP_VAR - case ER_SP_DUP_VAR : return "42000"; -#endif -#ifdef ER_SP_DUP_COND - case ER_SP_DUP_COND : return "42000"; -#endif -#ifdef ER_SP_DUP_CURS - case ER_SP_DUP_CURS : return "42000"; -#endif -#ifdef ER_SP_SUBSELECT_NYI - case ER_SP_SUBSELECT_NYI : return "0A000"; -#endif -#ifdef ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG - case ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG : return "0A000"; -#endif -#ifdef ER_SP_VARCOND_AFTER_CURSHNDLR - case ER_SP_VARCOND_AFTER_CURSHNDLR : return "42000"; -#endif -#ifdef ER_SP_CURSOR_AFTER_HANDLER - case ER_SP_CURSOR_AFTER_HANDLER : return "42000"; -#endif -#ifdef ER_SP_CASE_NOT_FOUND - case ER_SP_CASE_NOT_FOUND : return "20000"; -#endif -#ifdef ER_DIVISION_BY_ZERO - case ER_DIVISION_BY_ZERO : return "22012"; -#endif -#ifdef ER_ILLEGAL_VALUE_FOR_TYPE - case ER_ILLEGAL_VALUE_FOR_TYPE : return "22007"; -#endif -#ifdef ER_PROCACCESS_DENIED_ERROR - case ER_PROCACCESS_DENIED_ERROR : return "42000"; -#endif -#ifdef ER_XAER_NOTA - case ER_XAER_NOTA : return "XAE04"; -#endif -#ifdef ER_XAER_INVAL - case ER_XAER_INVAL : return "XAE05"; -#endif -#ifdef ER_XAER_RMFAIL - case ER_XAER_RMFAIL : return "XAE07"; -#endif -#ifdef ER_XAER_OUTSIDE - case ER_XAER_OUTSIDE : return "XAE09"; -#endif -#ifdef ER_XAER_RMERR - case ER_XAER_RMERR : return "XAE03"; -#endif -#ifdef ER_XA_RBROLLBACK - case ER_XA_RBROLLBACK : return "XA100"; -#endif -#ifdef ER_NONEXISTING_PROC_GRANT - case ER_NONEXISTING_PROC_GRANT : return "42000"; -#endif -#ifdef ER_DATA_TOO_LONG - case ER_DATA_TOO_LONG : return "22001"; -#endif -#ifdef ER_SP_BAD_SQLSTATE - case ER_SP_BAD_SQLSTATE : return "42000"; -#endif -#ifdef ER_CANT_CREATE_USER_WITH_GRANT - case ER_CANT_CREATE_USER_WITH_GRANT : return "42000"; -#endif -#ifdef ER_SP_DUP_HANDLER - case ER_SP_DUP_HANDLER : return "42000"; -#endif -#ifdef ER_SP_NOT_VAR_ARG - case ER_SP_NOT_VAR_ARG : return "42000"; -#endif -#ifdef ER_SP_NO_RETSET - case ER_SP_NO_RETSET : return "0A000"; -#endif -#ifdef ER_CANT_CREATE_GEOMETRY_OBJECT - case ER_CANT_CREATE_GEOMETRY_OBJECT : return "22003"; -#endif -#ifdef ER_TOO_BIG_SCALE - case ER_TOO_BIG_SCALE : return "42000"; -#endif -#ifdef ER_TOO_BIG_PRECISION - case ER_TOO_BIG_PRECISION : return "42000"; -#endif -#ifdef ER_M_BIGGER_THAN_D - case ER_M_BIGGER_THAN_D : return "42000"; -#endif -#ifdef ER_TOO_LONG_BODY - case ER_TOO_LONG_BODY : return "42000"; -#endif -#ifdef ER_TOO_BIG_DISPLAYWIDTH - case ER_TOO_BIG_DISPLAYWIDTH : return "42000"; -#endif -#ifdef ER_XAER_DUPID - case ER_XAER_DUPID : return "XAE08"; -#endif -#ifdef ER_DATETIME_FUNCTION_OVERFLOW - case ER_DATETIME_FUNCTION_OVERFLOW : return "22008"; -#endif -#ifdef ER_ROW_IS_REFERENCED_2 - case ER_ROW_IS_REFERENCED_2 : return "23000"; -#endif -#ifdef ER_NO_REFERENCED_ROW_2 - case ER_NO_REFERENCED_ROW_2 : return "23000"; -#endif -#ifdef ER_SP_BAD_VAR_SHADOW - case ER_SP_BAD_VAR_SHADOW : return "42000"; -#endif -#ifdef ER_SP_WRONG_NAME - case ER_SP_WRONG_NAME : return "42000"; -#endif -#ifdef ER_SP_NO_AGGREGATE - case ER_SP_NO_AGGREGATE : return "42000"; -#endif -#ifdef ER_MAX_PREPARED_STMT_COUNT_REACHED - case ER_MAX_PREPARED_STMT_COUNT_REACHED : return "42000"; -#endif -#ifdef ER_NON_GROUPING_FIELD_USED - case ER_NON_GROUPING_FIELD_USED : return "42000"; -#endif -#ifdef ER_FOREIGN_DUPLICATE_KEY - case ER_FOREIGN_DUPLICATE_KEY : return "23000"; -#endif -#ifdef ER_CANT_CHANGE_TX_ISOLATION - case ER_CANT_CHANGE_TX_ISOLATION : return "25001"; -#endif -#ifdef ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT - case ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT : return "42000"; -#endif -#ifdef ER_WRONG_PARAMETERS_TO_NATIVE_FCT - case ER_WRONG_PARAMETERS_TO_NATIVE_FCT : return "42000"; -#endif -#ifdef ER_WRONG_PARAMETERS_TO_STORED_FCT - case ER_WRONG_PARAMETERS_TO_STORED_FCT : return "42000"; -#endif -#ifdef ER_DUP_ENTRY_WITH_KEY_NAME - case ER_DUP_ENTRY_WITH_KEY_NAME : return "23000"; -#endif -#ifdef ER_XA_RBTIMEOUT - case ER_XA_RBTIMEOUT : return "XA106"; -#endif -#ifdef ER_XA_RBDEADLOCK - case ER_XA_RBDEADLOCK : return "XA102"; -#endif -#ifdef ER_FUNC_INEXISTENT_NAME_COLLISION - case ER_FUNC_INEXISTENT_NAME_COLLISION : return "42000"; -#endif -#ifdef ER_DUP_SIGNAL_SET - case ER_DUP_SIGNAL_SET : return "42000"; -#endif -#ifdef ER_SIGNAL_WARN - case ER_SIGNAL_WARN : return "01000"; -#endif -#ifdef ER_SIGNAL_NOT_FOUND - case ER_SIGNAL_NOT_FOUND : return "02000"; -#endif -#ifdef ER_SIGNAL_EXCEPTION - case ER_SIGNAL_EXCEPTION : return "HY000"; -#endif -#ifdef ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER - case ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER : return "0K000"; -#endif -#ifdef ER_SPATIAL_MUST_HAVE_GEOM_COL - case ER_SPATIAL_MUST_HAVE_GEOM_COL : return "42000"; -#endif -#ifdef ER_DATA_OUT_OF_RANGE - case ER_DATA_OUT_OF_RANGE : return "22003"; -#endif diff --git a/ext/pdo_mysql/tests/bug44327.phpt b/ext/pdo_mysql/tests/bug44327.phpt index 1b99d47937949..40be22e592ffa 100644 --- a/ext/pdo_mysql/tests/bug44327.phpt +++ b/ext/pdo_mysql/tests/bug44327.phpt @@ -62,5 +62,5 @@ object(PDORow)#5 (2) { string(19) "SELECT id FROM test" ---------------------------------- -Warning: Attempt to read property "queryString" on bool in %s on line %d +Warning: Attempt to read property "queryString" on false in %s on line %d NULL diff --git a/ext/pdo_mysql/tests/bug68371.phpt b/ext/pdo_mysql/tests/bug68371.phpt index bc96ce8eda8e6..375011af33ea7 100644 --- a/ext/pdo_mysql/tests/bug68371.phpt +++ b/ext/pdo_mysql/tests/bug68371.phpt @@ -17,7 +17,7 @@ $attrs = array( // Extensive test: default value and set+get values PDO::ATTR_EMULATE_PREPARES => array(null, 1, 0), PDO::MYSQL_ATTR_DIRECT_QUERY => array(null, 0, 1), - PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => array(null, 0, 1), + PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => array(null, false, true), // Just test the default PDO::ATTR_AUTOCOMMIT => array(null), @@ -73,7 +73,7 @@ OK int(0) OK OK -int(1) +bool(true) OK OK int(1) diff --git a/ext/pdo_mysql/tests/pdo_mysql___construct.phpt b/ext/pdo_mysql/tests/pdo_mysql___construct.phpt index bf70cad4fce7d..1f009185267c5 100644 --- a/ext/pdo_mysql/tests/pdo_mysql___construct.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql___construct.phpt @@ -6,6 +6,7 @@ pdo_mysql --FILE-- false, PDO::ATTR_EMULATE_PREPARES => 1, - PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => 1, + PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, /* TODO getAttribute() does not handle it */ PDO::MYSQL_ATTR_LOCAL_INFILE => false, /* TODO getAttribute() does not handle it */ @@ -144,8 +144,8 @@ MySQLPDOTest::skip(); if ($db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY)) printf("[018] PDO::MYSQL_ATTR_DIRECT_QUERY should be off\n"); - set_option_and_check(19, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1, 'PDO::MYSQL_ATTR_USE_BUFFERED_QUERY'); - set_option_and_check(20, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 0, 'PDO::MYSQL_ATTR_USE_BUFFERED_QUERY'); + set_option_and_check(19, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true, 'PDO::MYSQL_ATTR_USE_BUFFERED_QUERY'); + set_option_and_check(20, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false, 'PDO::MYSQL_ATTR_USE_BUFFERED_QUERY'); set_option_and_check(21, PDO::MYSQL_ATTR_LOCAL_INFILE, true, 'PDO::MYSQL_ATTR_LOCAL_INFILE'); set_option_and_check(22, PDO::MYSQL_ATTR_LOCAL_INFILE, false, 'PDO::MYSQL_ATTR_LOCAL_INFILE'); diff --git a/ext/pdo_mysql/tests/pdo_mysql_prepare_native_clear_error.phpt b/ext/pdo_mysql/tests/pdo_mysql_prepare_native_clear_error.phpt index 7318caa185893..8dfafbb37f977 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_prepare_native_clear_error.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_prepare_native_clear_error.phpt @@ -95,7 +95,7 @@ array(1) { Warning: PDO::prepare(): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'unknown_column' in 'field list' in %s on line %d -Fatal error: Uncaught Error: Call to a member function execute() on bool in %s:%d +Fatal error: Uncaught Error: Call to a member function execute() on false in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/ext/pdo_mysql/tests/pdo_mysql_prepare_native_mixed_style.phpt b/ext/pdo_mysql/tests/pdo_mysql_prepare_native_mixed_style.phpt index f5ec8a9307d35..d1e4cc8d30134 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_prepare_native_mixed_style.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_prepare_native_mixed_style.phpt @@ -37,7 +37,7 @@ Warning: PDO::prepare(): SQLSTATE[HY093]: Invalid parameter number: mixed named Warning: PDO::prepare(): SQLSTATE[HY093]: Invalid parameter number in %s on line %d -Fatal error: Uncaught Error: Call to a member function execute() on bool in %s:%d +Fatal error: Uncaught Error: Call to a member function execute() on false in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/ext/pdo_mysql/tests/pdo_mysql_stmt_errorcode.phpt b/ext/pdo_mysql/tests/pdo_mysql_stmt_errorcode.phpt index 6d00353a7d8b6..c3c4c68a70dd7 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_stmt_errorcode.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_stmt_errorcode.phpt @@ -57,7 +57,7 @@ Testing native PS... Warning: PDO::prepare(): SQLSTATE[42S02]: Base table or view not found: 1146 Table '%s.ihopeitdoesnotexist' doesn't exist in %s on line %d -Fatal error: Uncaught Error: Call to a member function execute() on bool in %s:%d +Fatal error: Uncaught Error: Call to a member function execute() on false in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/ext/pdo_mysql/tests/pdo_mysql_stmt_multiquery.phpt b/ext/pdo_mysql/tests/pdo_mysql_stmt_multiquery.phpt index 010ef31f463b4..b2cbe43561b04 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_stmt_multiquery.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_stmt_multiquery.phpt @@ -100,7 +100,7 @@ Native Prepared Statements... Warning: PDO::query(): SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near '%SSELECT label FROM test ORDER BY id ASC LIMIT 1' at line %d in %s on line %d -Fatal error: Uncaught Error: Call to a member function errorInfo() on bool in %s:%d +Fatal error: Uncaught Error: Call to a member function errorInfo() on false in %s:%d Stack trace: #0 %s(%d): mysql_stmt_multiquery_wrong_usage(Object(PDO)) #1 {main} diff --git a/ext/pdo_oci/config.m4 b/ext/pdo_oci/config.m4 index 1f5f436c3214e..05ecebf272c62 100644 --- a/ext/pdo_oci/config.m4 +++ b/ext/pdo_oci/config.m4 @@ -182,6 +182,14 @@ if test "$PHP_PDO_OCI" != "no"; then -L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD ]) + dnl Can handle bytes vs. characters? + PHP_CHECK_LIBRARY(clntsh, OCILobRead2, + [ + AC_DEFINE(HAVE_OCILOBREAD2,1,[ ]) + ], [], [ + -L$PDO_OCI_LIB_DIR $PDO_OCI_SHARED_LIBADD + ]) + PHP_CHECK_PDO_INCLUDES PHP_NEW_EXTENSION(pdo_oci, pdo_oci.c oci_driver.c oci_statement.c, $ext_shared,,-I$pdo_cv_inc_path) diff --git a/ext/pdo_oci/oci_driver.c b/ext/pdo_oci/oci_driver.c index f74c67ff4ed39..6a16420b95760 100644 --- a/ext/pdo_oci/oci_driver.c +++ b/ext/pdo_oci/oci_driver.c @@ -363,7 +363,7 @@ static zend_string* oci_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquote zend_string *quoted_str; if (ZSTR_LEN(unquoted) == 0) { - return zend_string_init("''", 2, 0); + return ZSTR_INIT_LITERAL("''", 0); } /* count single quotes */ diff --git a/ext/pdo_oci/oci_statement.c b/ext/pdo_oci/oci_statement.c index e77c78eef2d03..f3be69f9c32c2 100644 --- a/ext/pdo_oci/oci_statement.c +++ b/ext/pdo_oci/oci_statement.c @@ -616,6 +616,7 @@ struct oci_lob_self { OCILobLocator *lob; oci_lob_env *E; ub4 offset; + ub1 csfrm; }; static ssize_t oci_blob_write(php_stream *stream, const char *buf, size_t count) @@ -641,23 +642,34 @@ static ssize_t oci_blob_write(php_stream *stream, const char *buf, size_t count) static ssize_t oci_blob_read(php_stream *stream, char *buf, size_t count) { struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract; - ub4 amt; - sword r; +#if HAVE_OCILOBREAD2 + oraub8 byte_amt = (oraub8) count; + oraub8 char_amt = 0; - amt = (ub4) count; - r = OCILobRead(self->E->svc, self->E->err, self->lob, - &amt, self->offset, buf, (ub4) count, + sword r = OCILobRead2(self->E->svc, self->E->err, self->lob, + &byte_amt, &char_amt, (oraub8) self->offset, buf, (oraub8) count, + OCI_ONE_PIECE, NULL, NULL, 0, self->csfrm); +#else + ub4 byte_amt = (ub4) count; + + sword r = OCILobRead(self->E->svc, self->E->err, self->lob, + &byte_amt, self->offset, buf, (ub4) count, NULL, NULL, 0, SQLCS_IMPLICIT); +#endif if (r != OCI_SUCCESS && r != OCI_NEED_DATA) { - return (size_t)-1; + return (ssize_t)-1; } - self->offset += amt; - if (amt < count) { +#if HAVE_OCILOBREAD2 + self->offset += self->csfrm == 0 ? byte_amt : char_amt; +#else + self->offset += byte_amt; +#endif + if (byte_amt < count) { stream->eof = 1; } - return amt; + return byte_amt; } static int oci_blob_close(php_stream *stream, int close_handle) @@ -724,6 +736,8 @@ static php_stream *oci_create_lob_stream(zval *dbh, pdo_stmt_t *stmt, OCILobLoca self->E->svc = self->S->H->svc; self->E->err = self->S->err; + OCILobCharSetForm(self->S->H->env, self->S->err, self->lob, &self->csfrm); + stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b"); if (stm) { diff --git a/ext/pdo_oci/php_pdo_oci_int.h b/ext/pdo_oci/php_pdo_oci_int.h index dbffb22d092f8..9f335fdcc8448 100644 --- a/ext/pdo_oci/php_pdo_oci_int.h +++ b/ext/pdo_oci/php_pdo_oci_int.h @@ -14,7 +14,14 @@ +----------------------------------------------------------------------+ */ +#ifndef PHP_PDO_OCI_INT_H +#define PHP_PDO_OCI_INT_H + +#include "zend_portability.h" + +ZEND_CGG_DIAGNOSTIC_IGNORED_START("-Wstrict-prototypes") #include +ZEND_CGG_DIAGNOSTIC_IGNORED_END typedef struct { const char *file; @@ -105,3 +112,5 @@ enum { PDO_OCI_ATTR_MODULE, PDO_OCI_ATTR_CALL_TIMEOUT }; + +#endif /* PHP_PDO_OCI_INT_H */ diff --git a/ext/pdo_oci/tests/CONFLICTS b/ext/pdo_oci/tests/CONFLICTS index 176b41ab8bb6f..ff6afc6fb0838 100644 --- a/ext/pdo_oci/tests/CONFLICTS +++ b/ext/pdo_oci/tests/CONFLICTS @@ -1 +1,2 @@ -oci8 +# OCI tests are network intensive and may cause timeouts in other tests +all diff --git a/ext/pdo_oci/tests/bug60994.phpt b/ext/pdo_oci/tests/bug60994.phpt index 15ec56c3e0283..6f5c9161dc8e5 100644 --- a/ext/pdo_oci/tests/bug60994.phpt +++ b/ext/pdo_oci/tests/bug60994.phpt @@ -21,18 +21,19 @@ $dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL); $dbh->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); @$dbh->exec('DROP TABLE pdo_oci_bug60994'); -$dbh->exec('CREATE TABLE pdo_oci_bug60994 (id NUMBER, data CLOB)'); +$dbh->exec('CREATE TABLE pdo_oci_bug60994 (id NUMBER, data CLOB, data2 NCLOB)'); $id = null; -$insert = $dbh->prepare('INSERT INTO pdo_oci_bug60994 (id, data) VALUES (:id, :data)'); +$insert = $dbh->prepare('INSERT INTO pdo_oci_bug60994 (id, data, data2) VALUES (:id, :data, :data2)'); $insert->bindParam(':id', $id, \PDO::PARAM_STR); -$select = $dbh->prepare("SELECT data FROM pdo_oci_bug60994 WHERE id = :id"); +$select = $dbh->prepare("SELECT data, data2 FROM pdo_oci_bug60994 WHERE id = :id"); echo PHP_EOL, 'Test 1: j', PHP_EOL; $string1 = 'abc' . str_repeat('j', 8187) . 'xyz'; // 8193 chars total works fine here (even 1 million works fine, subject to memory_limit) $id = 1; $insert->bindParam(':data', $string1, \PDO::PARAM_STR, strlen($string1)); // length in bytes +$insert->bindParam(':data2', $string1, \PDO::PARAM_STR, strlen($string1)); $insert->execute(); $select->bindParam(':id', $id, \PDO::PARAM_STR); $select->execute(); @@ -44,12 +45,15 @@ echo 'size of string1 is ', strlen($string1), ' bytes, ', mb_strlen($string1), ' echo 'size of stream1 is ', strlen($stream1), ' bytes, ', mb_strlen($stream1), ' chars.', PHP_EOL; echo 'beg of stream1 is ', $start1, PHP_EOL; echo 'end of stream1 is ', $ending1, PHP_EOL; - +if ($string1 != $stream1 || $stream1 != stream_get_contents($row['DATA2'])) { + echo 'Expected nclob value to match clob value for stream1', PHP_EOL; +} echo PHP_EOL, 'Test 2: £', PHP_EOL; $string2 = 'abc' . str_repeat('£', 8187) . 'xyz'; // 8193 chars total is when it breaks $id = 2; $insert->bindParam(':data', $string2, \PDO::PARAM_STR, strlen($string2)); // length in bytes +$insert->bindParam(':data2', $string2, \PDO::PARAM_STR, strlen($string2)); $insert->execute(); $select->bindParam(':id', $id, \PDO::PARAM_STR); $select->execute(); @@ -61,12 +65,15 @@ echo 'size of string2 is ', strlen($string2), ' bytes, ', mb_strlen($string2), ' echo 'size of stream2 is ', strlen($stream2), ' bytes, ', mb_strlen($stream2), ' chars.', PHP_EOL; echo 'beg of stream2 is ', $start2, PHP_EOL; echo 'end of stream2 is ', $ending2, PHP_EOL; - +if ($string2 != $stream2 || $stream2 != stream_get_contents($row['DATA2'])) { + echo 'Expected nclob value to match clob value for stream2', PHP_EOL; +} echo PHP_EOL, 'Test 3: Җ', PHP_EOL; $string3 = 'abc' . str_repeat('Җ', 8187) . 'xyz'; // 8193 chars total is when it breaks $id = 3; $insert->bindParam(':data', $string3, \PDO::PARAM_STR, strlen($string3)); // length in bytes +$insert->bindParam(':data2', $string3, \PDO::PARAM_STR, strlen($string3)); $insert->execute(); $select->bindParam(':id', $id, \PDO::PARAM_STR); $select->execute(); @@ -78,12 +85,15 @@ echo 'size of string3 is ', strlen($string3), ' bytes, ', mb_strlen($string3), ' echo 'size of stream3 is ', strlen($stream3), ' bytes, ', mb_strlen($stream3), ' chars.', PHP_EOL; echo 'beg of stream3 is ', $start3, PHP_EOL; echo 'end of stream3 is ', $ending3, PHP_EOL; - +if ($string3 != $stream3 || $stream3 != stream_get_contents($row['DATA2'])) { + echo 'Expected nclob value to match clob value for stream3', PHP_EOL; +} echo PHP_EOL, 'Test 4: の', PHP_EOL; $string4 = 'abc' . str_repeat('の', 8187) . 'xyz'; // 8193 chars total is when it breaks $id = 4; $insert->bindParam(':data', $string4, \PDO::PARAM_STR, strlen($string4)); // length in bytes +$insert->bindParam(':data2', $string4, \PDO::PARAM_STR, strlen($string4)); $insert->execute(); $select->bindParam(':id', $id, \PDO::PARAM_STR); $select->execute(); @@ -95,13 +105,14 @@ echo 'size of string4 is ', strlen($string4), ' bytes, ', mb_strlen($string4), ' echo 'size of stream4 is ', strlen($stream4), ' bytes, ', mb_strlen($stream4), ' chars.', PHP_EOL; echo 'beg of stream4 is ', $start4, PHP_EOL; echo 'end of stream4 is ', $ending4, PHP_EOL; +if ($string4 != $stream4 || $stream4 != stream_get_contents($row['DATA2'])) { + echo 'Expected nclob value to match clob value for stream4', PHP_EOL; +} ?> ---XFAIL-- -Fails due to Bug 60994 --EXPECT-- Test 1: j -size of string1 is 1000006 bytes, 1000006 chars. -size of stream1 is 1000006 bytes, 1000006 chars. +size of string1 is 8193 bytes, 8193 chars. +size of stream1 is 8193 bytes, 8193 chars. beg of stream1 is abcjjjjjjj end of stream1 is jjjjjjjxyz diff --git a/ext/pdo_oci/tests/pecl_bug_6364.phpt b/ext/pdo_oci/tests/pecl_bug_6364.phpt index 9a97496fd0fb2..afd3685a5b613 100644 --- a/ext/pdo_oci/tests/pecl_bug_6364.phpt +++ b/ext/pdo_oci/tests/pecl_bug_6364.phpt @@ -5,7 +5,7 @@ pdo pdo_oci --SKIPIF-- diff --git a/ext/pdo_odbc/odbc_driver.c b/ext/pdo_odbc/odbc_driver.c index 661cab3c04f8c..a9d5befdac8f2 100644 --- a/ext/pdo_odbc/odbc_driver.c +++ b/ext/pdo_odbc/odbc_driver.c @@ -222,7 +222,7 @@ static zend_long odbc_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) PDO_ODBC_HSTMT stmt; rc = SQLAllocHandle(SQL_HANDLE_STMT, H->dbc, &stmt); - if (rc != SQL_SUCCESS) { + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { pdo_odbc_drv_error("SQLAllocHandle: STMT"); return -1; } @@ -449,7 +449,12 @@ static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ dbh->driver_data = H; - SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &H->env); + rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &H->env); + if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { + pdo_odbc_drv_error("SQLAllocHandle: ENV"); + goto fail; + } + rc = SQLSetEnvAttr(H->env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { @@ -469,7 +474,7 @@ static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ rc = SQLAllocHandle(SQL_HANDLE_DBC, H->env, &H->dbc); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - pdo_odbc_drv_error("SQLAllocHandle (DBC)"); + pdo_odbc_drv_error("SQLAllocHandle: DBC"); goto fail; } diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 6a41e2162a934..f83ce43a3ce8b 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -203,13 +203,9 @@ static bool sqlite_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t static zend_long sqlite_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) { pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; - char *errmsg = NULL; - if (sqlite3_exec(H->db, ZSTR_VAL(sql), NULL, NULL, &errmsg) != SQLITE_OK) { + if (sqlite3_exec(H->db, ZSTR_VAL(sql), NULL, NULL, NULL) != SQLITE_OK) { pdo_sqlite_error(dbh); - if (errmsg) - sqlite3_free(errmsg); - return -1; } else { return sqlite3_changes(H->db); @@ -226,7 +222,11 @@ static zend_string *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const zend_string /* NB: doesn't handle binary strings... use prepared stmts for that */ static zend_string* sqlite_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype) { - char *quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3); + char *quoted; + if (ZSTR_LEN(unquoted) > (INT_MAX - 3) / 2) { + return NULL; + } + quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3); /* TODO use %Q format? */ sqlite3_snprintf(2*ZSTR_LEN(unquoted) + 3, quoted, "'%q'", ZSTR_VAL(unquoted)); zend_string *quoted_str = zend_string_init(quoted, strlen(quoted), 0); @@ -237,12 +237,9 @@ static zend_string* sqlite_handle_quoter(pdo_dbh_t *dbh, const zend_string *unqu static bool sqlite_handle_begin(pdo_dbh_t *dbh) { pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; - char *errmsg = NULL; - if (sqlite3_exec(H->db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) { + if (sqlite3_exec(H->db, "BEGIN", NULL, NULL, NULL) != SQLITE_OK) { pdo_sqlite_error(dbh); - if (errmsg) - sqlite3_free(errmsg); return false; } return true; @@ -251,12 +248,9 @@ static bool sqlite_handle_begin(pdo_dbh_t *dbh) static bool sqlite_handle_commit(pdo_dbh_t *dbh) { pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; - char *errmsg = NULL; - if (sqlite3_exec(H->db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) { + if (sqlite3_exec(H->db, "COMMIT", NULL, NULL, NULL) != SQLITE_OK) { pdo_sqlite_error(dbh); - if (errmsg) - sqlite3_free(errmsg); return false; } return true; @@ -265,12 +259,9 @@ static bool sqlite_handle_commit(pdo_dbh_t *dbh) static bool sqlite_handle_rollback(pdo_dbh_t *dbh) { pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; - char *errmsg = NULL; - if (sqlite3_exec(H->db, "ROLLBACK", NULL, NULL, &errmsg) != SQLITE_OK) { + if (sqlite3_exec(H->db, "ROLLBACK", NULL, NULL, NULL) != SQLITE_OK) { pdo_sqlite_error(dbh); - if (errmsg) - sqlite3_free(errmsg); return false; } return true; diff --git a/ext/pdo_sqlite/tests/bug81740.phpt b/ext/pdo_sqlite/tests/bug81740.phpt new file mode 100644 index 0000000000000..2b8b9447f0fed --- /dev/null +++ b/ext/pdo_sqlite/tests/bug81740.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #81740 (PDO::quote() may return unquoted string) +--EXTENSIONS-- +pdo +pdo_sqlite +--SKIPIF-- + +--INI-- +memory_limit=-1 +--FILE-- +quote($string)); +?> +--EXPECT-- +bool(false) diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_open_basedir_uri.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_open_basedir_uri.phpt index 7525ae34a8e86..7ec111dcf7f80 100644 --- a/ext/pdo_sqlite/tests/pdo_sqlite_open_basedir_uri.phpt +++ b/ext/pdo_sqlite/tests/pdo_sqlite_open_basedir_uri.phpt @@ -3,7 +3,7 @@ PDO_sqlite: Testing URIs with open_basedir --EXTENSIONS-- pdo_sqlite --INI-- -open_basedir={TMP} +open_basedir="{TMP}" --FILE-- constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), /* retval */ NULL, /* argc */ 0, /* params */ NULL, ctor_params); } else if (ctor_params && zend_hash_num_elements(ctor_params) > 0) { - /* TODO Convert this to a ValueError */ - zend_argument_error(zend_ce_exception, 3, + zend_argument_value_error(3, "must be empty when the specified class (%s) does not have a constructor", ZSTR_VAL(ce->name) ); @@ -2116,13 +2115,14 @@ PHP_FUNCTION(pg_trace) { char *z_filename, *mode = "w"; size_t z_filename_len, mode_len; + zend_long trace_mode = 0; zval *pgsql_link = NULL; PGconn *pgsql; FILE *fp = NULL; php_stream *stream; pgsql_link_handle *link; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|sO!", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link, pgsql_link_ce) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|sO!l", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link, pgsql_link_ce, &trace_mode) == FAILURE) { RETURN_THROWS(); } @@ -2148,6 +2148,19 @@ PHP_FUNCTION(pg_trace) } php_stream_auto_cleanup(stream); PQtrace(pgsql, fp); + if (trace_mode > 0) { +#ifdef PQTRACE_REGRESS_MODE + if (!(trace_mode & (PQTRACE_SUPPRESS_TIMESTAMPS|PQTRACE_REGRESS_MODE))) { + zend_argument_value_error(4, "must be PGSQL_TRACE_SUPPRESS_TIMESTAMPS and/or PGSQL_TRACE_REGRESS_MODE"); + RETURN_THROWS(); + } else { + PQsetTraceFlags(pgsql, trace_mode); + } +#else + zend_argument_value_error(4, "cannot set as trace is unsupported"); + RETURN_THROWS(); +#endif + } RETURN_TRUE; } /* }}} */ @@ -2228,7 +2241,7 @@ PHP_FUNCTION(pg_lo_create) wanted_oid = (Oid)Z_LVAL_P(oid); break; default: - zend_type_error("OID value must be of type string|int, %s given", zend_zval_type_name(oid)); + zend_type_error("OID value must be of type string|int, %s given", zend_zval_value_name(oid)); RETURN_THROWS(); } if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) { @@ -2338,7 +2351,7 @@ PHP_FUNCTION(pg_lo_open) CHECK_PGSQL_LINK(link); } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), - "Ols", &pgsql_link, pgsql_link_ce, &oid_long, &mode) == SUCCESS) { + "OlS", &pgsql_link, pgsql_link_ce, &oid_long, &mode) == SUCCESS) { if (oid_long <= (zend_long)InvalidOid) { zend_value_error("Invalid OID value passed"); RETURN_THROWS(); @@ -2477,9 +2490,8 @@ PHP_FUNCTION(pg_lo_read) RETURN_FALSE; } - /* TODO Use truncate API? */ - ZSTR_LEN(buf) = nbytes; - ZSTR_VAL(buf)[ZSTR_LEN(buf)] = '\0'; + ZSTR_VAL(buf)[nbytes] = '\0'; + buf = zend_string_truncate(buf, nbytes, 0); RETURN_NEW_STR(buf); } /* }}} */ @@ -2599,7 +2611,7 @@ PHP_FUNCTION(pg_lo_import) wanted_oid = (Oid)Z_LVAL_P(oid); break; default: - zend_type_error("OID value must be of type string|int, %s given", zend_zval_type_name(oid)); + zend_type_error("OID value must be of type string|int, %s given", zend_zval_value_name(oid)); RETURN_THROWS(); } @@ -2634,7 +2646,7 @@ PHP_FUNCTION(pg_lo_export) /* allow string to handle large OID value correctly */ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), - "rlP", &pgsql_link, pgsql_link_ce, &oid_long, &file_out) == SUCCESS) { + "OlP", &pgsql_link, pgsql_link_ce, &oid_long, &file_out) == SUCCESS) { if (oid_long <= (zend_long)InvalidOid) { zend_value_error("Invalid OID value passed"); RETURN_THROWS(); @@ -3471,12 +3483,22 @@ static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) PQconsumeInput(pgsql); RETVAL_LONG(PQisBusy(pgsql)); break; - case PHP_PG_ASYNC_REQUEST_CANCEL: - RETVAL_LONG(PQrequestCancel(pgsql)); + case PHP_PG_ASYNC_REQUEST_CANCEL: { + PGcancel *c; + char err[256]; + int rc; + + c = PQgetCancel(pgsql); + RETVAL_LONG((rc = PQcancel(c, err, sizeof(err)))); + if (rc < 0) { + zend_error(E_WARNING, "cannot cancel the query: %s", err); + } while ((pgsql_result = PQgetResult(pgsql))) { PQclear(pgsql_result); } + PQfreeCancel(c); break; + } EMPTY_SWITCH_DEFAULT_CASE() } if (PQsetnonblocking(pgsql, 0)) { @@ -4138,9 +4160,8 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string src = estrdup(ZSTR_VAL(table_name)); tmp_name = php_strtok_r(src, ".", &tmp_name2); if (!tmp_name) { - // TODO ValueError (empty table name)? efree(src); - php_error_docref(NULL, E_WARNING, "The table name must be specified"); + zend_argument_value_error(2, "must be specified (%s)", ZSTR_VAL(table_name)); return FAILURE; } if (!tmp_name2 || !*tmp_name2) { @@ -4217,7 +4238,7 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string /* pg_type.typtype */ add_assoc_bool_ex(&elem, "is base", sizeof("is base") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "b")); add_assoc_bool_ex(&elem, "is composite", sizeof("is composite") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "c")); - add_assoc_bool_ex(&elem, "is pesudo", sizeof("is pesudo") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "p")); + add_assoc_bool_ex(&elem, "is pseudo", sizeof("is pseudo") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "p")); /* pg_description.description */ add_assoc_string_ex(&elem, "description", sizeof("description") - 1, PQgetvalue(pg_result, i, 8)); } @@ -4489,7 +4510,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string * err = 1; } if (!err && (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT || Z_TYPE_P(val) == IS_RESOURCE)) { - zend_type_error("Values must be of type string|int|float|bool|null, %s given", zend_zval_type_name(val)); + zend_type_error("Values must be of type string|int|float|bool|null, %s given", zend_zval_value_name(val)); err = 1; } if (err) { @@ -5253,7 +5274,7 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t smart_str_appendl(&querystr, "NULL", sizeof("NULL")-1); break; default: - zend_type_error("Value must be of type string|int|float|null, %s given", zend_zval_type_name(val)); + zend_type_error("Value must be of type string|int|float|null, %s given", zend_zval_value_name(val)); goto cleanup; } smart_str_appendc(&querystr, ','); @@ -5427,7 +5448,7 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr, smart_str_appendl(querystr, "NULL", sizeof("NULL")-1); break; default: - zend_type_error("Value must be of type string|int|float|null, %s given", zend_zval_type_name(val)); + zend_type_error("Value must be of type string|int|float|null, %s given", zend_zval_value_name(val)); return -1; } smart_str_appendl(querystr, pad, pad_len); @@ -5800,4 +5821,66 @@ PHP_FUNCTION(pg_select) } /* }}} */ +#ifdef LIBPQ_HAS_PIPELINING +PHP_FUNCTION(pg_enter_pipeline_mode) +{ + zval *pgsql_link; + pgsql_link_handle *pgsql_handle; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) { + RETURN_THROWS(); + } + + pgsql_handle = Z_PGSQL_LINK_P(pgsql_link); + CHECK_PGSQL_LINK(pgsql_handle); + + RETURN_BOOL(PQenterPipelineMode(pgsql_handle->conn)); +} + +PHP_FUNCTION(pg_exit_pipeline_mode) +{ + zval *pgsql_link; + pgsql_link_handle *pgsql_handle; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) { + RETURN_THROWS(); + } + + pgsql_handle = Z_PGSQL_LINK_P(pgsql_link); + CHECK_PGSQL_LINK(pgsql_handle); + + RETURN_BOOL(PQexitPipelineMode(pgsql_handle->conn)); +} + +PHP_FUNCTION(pg_pipeline_sync) +{ + zval *pgsql_link; + pgsql_link_handle *pgsql_handle; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) { + RETURN_THROWS(); + } + + pgsql_handle = Z_PGSQL_LINK_P(pgsql_link); + CHECK_PGSQL_LINK(pgsql_handle); + + RETURN_BOOL(PQpipelineSync(pgsql_handle->conn)); +} + +PHP_FUNCTION(pg_pipeline_status) +{ + zval *pgsql_link; + pgsql_link_handle *pgsql_handle; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pgsql_link, pgsql_link_ce) == FAILURE) { + RETURN_THROWS(); + } + + pgsql_handle = Z_PGSQL_LINK_P(pgsql_link); + CHECK_PGSQL_LINK(pgsql_handle); + + RETURN_LONG(PQpipelineStatus(pgsql_handle->conn)); +} +#endif + #endif diff --git a/ext/pgsql/pgsql.stub.php b/ext/pgsql/pgsql.stub.php index 3eea65f586d16..e095350543c79 100644 --- a/ext/pgsql/pgsql.stub.php +++ b/ext/pgsql/pgsql.stub.php @@ -2,7 +2,7 @@ /** @generate-class-entries */ -namespace PgSql { +namespace { /* libpq version */ /** @@ -412,34 +412,43 @@ * @cvalue PGSQL_DML_STRING */ const PGSQL_DML_STRING = UNKNOWN; - +#ifdef PQTRACE_SUPPPRESS_TIMESTAMPS /** - * @strict-properties - * @not-serializable + * @var int + * @cvalue PQTRACE_SUPPRESS_TIMESTAMPS */ - final class Connection - { - } - + const PGSQL_TRACE_SUPPRESS_TIMESTAMPS = UNKNOWN; +#endif +#ifdef PQTRACE_REGRESS_MODE /** - * @strict-properties - * @not-serializable + * @var int + * @cvalue PQTRACE_REGRESS_MODE */ - final class Result - { - } + const PGSQL_TRACE_REGRESS_MODE = UNKNOWN; +#endif +#ifdef LIBPQ_HAS_PIPELINING /** - * @strict-properties - * @not-serializable + * @var int + * @cvalue PGRES_PIPELINE_SYNC */ - final class Lob - { - } - -} - -namespace { + const PGSQL_PIPELINE_SYNC = UNKNOWN; + /** + * @var int + * @cvalue PQ_PIPELINE_ON + */ + const PGSQL_PIPELINE_ON = UNKNOWN; + /** + * @var int + * @cvalue PQ_PIPELINE_OFF + */ + const PGSQL_PIPELINE_OFF = UNKNOWN; + /** + * @var int + * @cvalue PQ_PIPELINE_ABORTED + */ + const PGSQL_PIPELINE_ABORTED = UNKNOWN; +#endif function pg_connect(string $connection_string, int $flags = 0): PgSql\Connection|false {} @@ -667,7 +676,7 @@ function pg_last_oid(PgSql\Result $result): string|int|false {} */ function pg_getlastoid(PgSql\Result $result): string|int|false {} - function pg_trace(string $filename, string $mode = "w", ?PgSql\Connection $connection = null): bool {} + function pg_trace(string $filename, string $mode = "w", ?PgSql\Connection $connection = null, int $trace_mode = 0): bool {} function pg_untrace(?PgSql\Connection $connection = null): bool {} @@ -922,4 +931,38 @@ function pg_delete(PgSql\Connection $connection, string $table_name, array $cond * @refcount 1 */ function pg_select(PgSql\Connection $connection, string $table_name, array $conditions, int $flags = PGSQL_DML_EXEC, int $mode = PGSQL_ASSOC): array|string|false {} + +#ifdef LIBPQ_HAS_PIPELINING + function pg_enter_pipeline_mode(PgSql\Connection $connection): bool {} + function pg_exit_pipeline_mode(PgSql\Connection $connection): bool {} + function pg_pipeline_sync(PgSql\Connection $connection): bool {} + function pg_pipeline_status(PgSql\Connection $connection): int {} +#endif +} + +namespace PgSql { + /** + * @strict-properties + * @not-serializable + */ + final class Connection + { + } + + /** + * @strict-properties + * @not-serializable + */ + final class Result + { + } + + /** + * @strict-properties + * @not-serializable + */ + final class Lob + { + } + } diff --git a/ext/pgsql/pgsql_arginfo.h b/ext/pgsql/pgsql_arginfo.h index e6ade23529e50..2b8e7cd17ae6a 100644 --- a/ext/pgsql/pgsql_arginfo.h +++ b/ext/pgsql/pgsql_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 16b910c38da087e1b4b55e38031b593334c698ec */ + * Stub hash: f18a73443942daa2b3695e8750c8daaea6b96194 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_connect, 0, 1, PgSql\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, connection_string, IS_STRING, 0) @@ -198,6 +198,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_trace, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_STRING, 0, "\"w\"") ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, connection, PgSql\\Connection, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, trace_mode, IS_LONG, 0, "0") ZEND_END_ARG_INFO() #define arginfo_pg_untrace arginfo_pg_close @@ -449,6 +450,26 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_pg_select, 0, 3, MAY_BE_ARRAY|MA ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "PGSQL_ASSOC") ZEND_END_ARG_INFO() +#if defined(LIBPQ_HAS_PIPELINING) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_enter_pipeline_mode, 0, 1, _IS_BOOL, 0) + ZEND_ARG_OBJ_INFO(0, connection, PgSql\\Connection, 0) +ZEND_END_ARG_INFO() +#endif + +#if defined(LIBPQ_HAS_PIPELINING) +#define arginfo_pg_exit_pipeline_mode arginfo_pg_enter_pipeline_mode +#endif + +#if defined(LIBPQ_HAS_PIPELINING) +#define arginfo_pg_pipeline_sync arginfo_pg_enter_pipeline_mode +#endif + +#if defined(LIBPQ_HAS_PIPELINING) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pg_pipeline_status, 0, 1, IS_LONG, 0) + ZEND_ARG_OBJ_INFO(0, connection, PgSql\\Connection, 0) +ZEND_END_ARG_INFO() +#endif + ZEND_FUNCTION(pg_connect); ZEND_FUNCTION(pg_pconnect); @@ -539,6 +560,18 @@ ZEND_FUNCTION(pg_insert); ZEND_FUNCTION(pg_update); ZEND_FUNCTION(pg_delete); ZEND_FUNCTION(pg_select); +#if defined(LIBPQ_HAS_PIPELINING) +ZEND_FUNCTION(pg_enter_pipeline_mode); +#endif +#if defined(LIBPQ_HAS_PIPELINING) +ZEND_FUNCTION(pg_exit_pipeline_mode); +#endif +#if defined(LIBPQ_HAS_PIPELINING) +ZEND_FUNCTION(pg_pipeline_sync); +#endif +#if defined(LIBPQ_HAS_PIPELINING) +ZEND_FUNCTION(pg_pipeline_status); +#endif static const zend_function_entry ext_functions[] = { @@ -656,6 +689,18 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(pg_update, arginfo_pg_update) ZEND_FE(pg_delete, arginfo_pg_delete) ZEND_FE(pg_select, arginfo_pg_select) +#if defined(LIBPQ_HAS_PIPELINING) + ZEND_FE(pg_enter_pipeline_mode, arginfo_pg_enter_pipeline_mode) +#endif +#if defined(LIBPQ_HAS_PIPELINING) + ZEND_FE(pg_exit_pipeline_mode, arginfo_pg_exit_pipeline_mode) +#endif +#if defined(LIBPQ_HAS_PIPELINING) + ZEND_FE(pg_pipeline_sync, arginfo_pg_pipeline_sync) +#endif +#if defined(LIBPQ_HAS_PIPELINING) + ZEND_FE(pg_pipeline_status, arginfo_pg_pipeline_status) +#endif ZEND_FE_END }; @@ -764,6 +809,24 @@ static void register_pgsql_symbols(int module_number) REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_PERSISTENT); +#if defined(PQTRACE_SUPPPRESS_TIMESTAMPS) + REGISTER_LONG_CONSTANT("PGSQL_TRACE_SUPPRESS_TIMESTAMPS", PQTRACE_SUPPRESS_TIMESTAMPS, CONST_PERSISTENT); +#endif +#if defined(PQTRACE_REGRESS_MODE) + REGISTER_LONG_CONSTANT("PGSQL_TRACE_REGRESS_MODE", PQTRACE_REGRESS_MODE, CONST_PERSISTENT); +#endif +#if defined(LIBPQ_HAS_PIPELINING) + REGISTER_LONG_CONSTANT("PGSQL_PIPELINE_SYNC", PGRES_PIPELINE_SYNC, CONST_PERSISTENT); +#endif +#if defined(LIBPQ_HAS_PIPELINING) + REGISTER_LONG_CONSTANT("PGSQL_PIPELINE_ON", PQ_PIPELINE_ON, CONST_PERSISTENT); +#endif +#if defined(LIBPQ_HAS_PIPELINING) + REGISTER_LONG_CONSTANT("PGSQL_PIPELINE_OFF", PQ_PIPELINE_OFF, CONST_PERSISTENT); +#endif +#if defined(LIBPQ_HAS_PIPELINING) + REGISTER_LONG_CONSTANT("PGSQL_PIPELINE_ABORTED", PQ_PIPELINE_ABORTED, CONST_PERSISTENT); +#endif } static zend_class_entry *register_class_PgSql_Connection(void) diff --git a/ext/pgsql/tests/28large_object_import_oid.phpt b/ext/pgsql/tests/28large_object_import_oid.phpt index 3af7529333989..13a0918d84879 100644 --- a/ext/pgsql/tests/28large_object_import_oid.phpt +++ b/ext/pgsql/tests/28large_object_import_oid.phpt @@ -104,7 +104,7 @@ Invalid OID value passed Invalid OID value passed Deprecated: pg_lo_import(): Automatic fetching of PostgreSQL connection is deprecated in %s on line %d -OID value must be of type string|int, bool given +OID value must be of type string|int, true given OID value must be of type string|int, array given OID value must be of type string|int, stdClass given OID value must be of type string|int, PgSql\Connection given diff --git a/ext/pgsql/tests/gh10672.phpt b/ext/pgsql/tests/gh10672.phpt new file mode 100644 index 0000000000000..2f334e573dac9 --- /dev/null +++ b/ext/pgsql/tests/gh10672.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-10672 (pg_lo_open segfaults in the strict_types mode) +--EXTENSIONS-- +pgsql +--SKIPIF-- + +--FILE-- + +--EXPECT-- +The large object has been opened successfully. diff --git a/ext/pgsql/tests/pg_insert_002.phpt b/ext/pgsql/tests/pg_insert_002.phpt index e3e593999f680..19537e8a5d5d1 100644 --- a/ext/pgsql/tests/pg_insert_002.phpt +++ b/ext/pgsql/tests/pg_insert_002.phpt @@ -22,10 +22,6 @@ foreach (array('', '.', '..') as $table) { Done --EXPECTF-- pg_insert(): Argument #2 ($table_name) cannot be empty - -Warning: pg_insert(): The table name must be specified in %s on line %d -bool(false) - -Warning: pg_insert(): The table name must be specified in %s on line %d -bool(false) +pg_insert(): Argument #2 ($table_name) must be specified (.) +pg_insert(): Argument #2 ($table_name) must be specified (..) Done diff --git a/ext/pgsql/tests/pg_meta_data_001.phpt b/ext/pgsql/tests/pg_meta_data_001.phpt index 72f2f4fa5ad48..a69fcb2ef63eb 100644 --- a/ext/pgsql/tests/pg_meta_data_001.phpt +++ b/ext/pgsql/tests/pg_meta_data_001.phpt @@ -122,7 +122,7 @@ array(2) { bool(true) ["is composite"]=> bool(false) - ["is pesudo"]=> + ["is pseudo"]=> bool(false) ["description"]=> string(0) "" @@ -147,7 +147,7 @@ array(2) { bool(true) ["is composite"]=> bool(false) - ["is pesudo"]=> + ["is pseudo"]=> bool(false) ["description"]=> string(0) "" diff --git a/ext/pgsql/tests/pg_pipeline_sync.phpt b/ext/pgsql/tests/pg_pipeline_sync.phpt new file mode 100644 index 0000000000000..38366a025483b --- /dev/null +++ b/ext/pgsql/tests/pg_pipeline_sync.phpt @@ -0,0 +1,99 @@ +--TEST-- +PostgreSQL pipeline mode +--EXTENSIONS-- +pgsql +--SKIPIF-- + +--FILE-- + +--EXPECT-- +OK diff --git a/ext/pgsql/tests/pg_trace.phpt b/ext/pgsql/tests/pg_trace.phpt new file mode 100644 index 0000000000000..0917959bbef77 --- /dev/null +++ b/ext/pgsql/tests/pg_trace.phpt @@ -0,0 +1,26 @@ +--TEST-- +pg_trace +--EXTENSIONS-- +pgsql +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; +} +var_dump(pg_trace($tracefile, 'w', $db, 0)); +$res = pg_query($db, 'select 1'); + +?> +--EXPECT-- +pg_trace(): Argument #4 ($trace_mode) cannot set as trace is unsupported +bool(true) diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c index 6e545a1ff4398..c52ee805b2b12 100644 --- a/ext/phar/func_interceptors.c +++ b/ext/phar/func_interceptors.c @@ -41,18 +41,17 @@ PHAR_FUNC(phar_opendir) /* {{{ */ } if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { - char *arch, *entry, *fname; - size_t arch_len, entry_len, fname_len; - fname = (char*)zend_get_executed_filename(); + char *arch, *entry; + size_t arch_len, entry_len; + zend_string *fname = zend_get_executed_filename_ex(); /* we are checking for existence of a file within the relative path. Chances are good that this is retrieving something from within the phar archive */ - - if (strncasecmp(fname, "phar://", 7)) { + if (!fname || !zend_string_starts_with_literal_ci(fname, "phar://")) { goto skip_phar; } - fname_len = strlen(fname); - if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + + if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, &entry, &entry_len, 2, 0)) { php_stream_context *context = NULL; php_stream *stream; char *name; @@ -89,13 +88,79 @@ PHAR_FUNC(phar_opendir) /* {{{ */ } /* }}} */ +static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool using_include_path) +{ + char *arch, *entry; + size_t arch_len, entry_len; + zend_string *fname = zend_get_executed_filename_ex(); + + /* we are checking for existence of a file within the relative path. Chances are good that this is + retrieving something from within the phar archive */ + if (!fname || !zend_string_starts_with_literal_ci(fname, "phar://")) { + return NULL; + } + + if (FAILURE == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, &entry, &entry_len, 2, 0)) { + return NULL; + } + + efree(entry); + entry = NULL; + entry_len = 0; + /* fopen within phar, if :// is not in the url, then prepend phar:/// */ + /* retrieving a file defaults to within the current directory, so use this if possible */ + phar_archive_data *phar; + if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { + efree(arch); + return NULL; + } + + zend_string *name = NULL; + if (using_include_path) { + if (!(name = phar_find_in_include_path(filename, NULL))) { + /* this file is not in the phar, use the original path */ + efree(arch); + return NULL; + } + } else { + entry_len = ZSTR_LEN(filename); + entry = phar_fix_filepath(estrndup(ZSTR_VAL(filename), ZSTR_LEN(filename)), &entry_len, 1); + if (entry[0] == '/') { + if (!zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1)) { + /* this file is not in the phar, use the original path */ +notfound: + efree(entry); + efree(arch); + return NULL; + } + } else { + if (!zend_hash_str_exists(&(phar->manifest), entry, entry_len)) { + goto notfound; + } + } + /* auto-convert to phar:// */ + if (entry[0] == '/') { + ZEND_ASSERT(strlen("phar://") + arch_len + entry_len < 4096); + name = zend_string_concat3( + "phar://", strlen("phar://"), + arch, arch_len, + entry, entry_len + ); + } else { + name = strpprintf(4096, "phar://%s/%s", arch, entry); + } + efree(entry); + } + + efree(arch); + return name; +} + PHAR_FUNC(phar_file_get_contents) /* {{{ */ { - char *filename; - size_t filename_len; + zend_string *filename; zend_string *contents; bool use_include_path = 0; - php_stream *stream; zend_long offset = -1; zend_long maxlen; bool maxlen_is_null = 1; @@ -111,117 +176,56 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */ } /* Parse arguments */ - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "p|br!ll!", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen, &maxlen_is_null) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "P|br!ll!", &filename, &use_include_path, &zcontext, &offset, &maxlen, &maxlen_is_null) == FAILURE) { goto skip_phar; } if (maxlen_is_null) { maxlen = (ssize_t) PHP_STREAM_COPY_ALL; + } else if (maxlen < 0) { + zend_argument_value_error(5, "must be greater than or equal to 0"); + RETURN_THROWS(); } - if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { - char *arch, *entry, *fname; - zend_string *entry_str = NULL; - size_t arch_len, entry_len, fname_len; - php_stream_context *context = NULL; - - fname = (char*)zend_get_executed_filename(); - - if (strncasecmp(fname, "phar://", 7)) { + if (use_include_path || (!IS_ABSOLUTE_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename)) && !strstr(ZSTR_VAL(filename), "://"))) { + zend_string *name = phar_get_name_for_relative_paths(filename, use_include_path); + if (!name) { goto skip_phar; } - fname_len = strlen(fname); - if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { - char *name; - phar_archive_data *phar; - - efree(entry); - entry = filename; - /* fopen within phar, if :// is not in the url, then prepend phar:/// */ - entry_len = filename_len; - - if (!maxlen_is_null && maxlen < 0) { - efree(arch); - zend_argument_value_error(5, "must be greater than or equal to 0"); - RETURN_THROWS(); - } - /* retrieving a file defaults to within the current directory, so use this if possible */ - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { - efree(arch); - goto skip_phar; - } - if (use_include_path) { - if ((entry_str = phar_find_in_include_path(entry, entry_len, NULL))) { - name = ZSTR_VAL(entry_str); - goto phar_it; - } else { - /* this file is not in the phar, use the original path */ - efree(arch); - goto skip_phar; - } - } else { - entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1); - if (entry[0] == '/') { - if (!zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1)) { - /* this file is not in the phar, use the original path */ -notfound: - efree(arch); - efree(entry); - goto skip_phar; - } - } else { - if (!zend_hash_str_exists(&(phar->manifest), entry, entry_len)) { - goto notfound; - } - } - /* auto-convert to phar:// */ - if (entry[0] == '/') { - spprintf(&name, 4096, "phar://%s%s", arch, entry); - } else { - spprintf(&name, 4096, "phar://%s/%s", arch, entry); - } - if (entry != filename) { - efree(entry); - } - } - -phar_it: - efree(arch); - if (zcontext) { - context = php_stream_context_from_zval(zcontext, 0); - } - stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context); - if (entry_str) { - zend_string_release_ex(entry_str, 0); - } else { - efree(name); - } + php_stream_context *context = NULL; + php_stream *stream; - if (!stream) { - RETURN_FALSE; - } + if (zcontext) { + context = php_stream_context_from_zval(zcontext, 0); + } + stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), "rb", 0 | REPORT_ERRORS, NULL, context); - if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) { - php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", offset); - php_stream_close(stream); - RETURN_FALSE; - } + zend_string_release_ex(name, false); - /* uses mmap if possible */ - contents = php_stream_copy_to_mem(stream, maxlen, 0); - if (contents && ZSTR_LEN(contents) > 0) { - RETVAL_STR(contents); - } else if (contents) { - zend_string_release_ex(contents, 0); - RETVAL_EMPTY_STRING(); - } else { - RETVAL_FALSE; - } + if (!stream) { + RETURN_FALSE; + } + if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) { + php_error_docref(NULL, E_WARNING, "Failed to seek to position " ZEND_LONG_FMT " in the stream", offset); php_stream_close(stream); - return; + RETURN_FALSE; + } + + /* uses mmap if possible */ + contents = php_stream_copy_to_mem(stream, maxlen, 0); + if (contents && ZSTR_LEN(contents) > 0) { + RETVAL_STR(contents); + } else if (contents) { + zend_string_release_ex(contents, 0); + RETVAL_EMPTY_STRING(); + } else { + RETVAL_FALSE; } + + php_stream_close(stream); + return; } skip_phar: PHAR_G(orig_file_get_contents)(INTERNAL_FUNCTION_PARAM_PASSTHRU); @@ -231,12 +235,9 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */ PHAR_FUNC(phar_readfile) /* {{{ */ { - char *filename; - size_t filename_len; - int size = 0; + zend_string *filename; bool use_include_path = 0; zval *zcontext = NULL; - php_stream *stream; if (!PHAR_G(intercepted)) { goto skip_phar; @@ -246,79 +247,25 @@ PHAR_FUNC(phar_readfile) /* {{{ */ && !HT_IS_INITIALIZED(&cached_phars)) { goto skip_phar; } - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "p|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "P|br!", &filename, &use_include_path, &zcontext) == FAILURE) { goto skip_phar; } - if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { - char *arch, *entry, *fname; - zend_string *entry_str = NULL; - size_t arch_len, entry_len, fname_len; - php_stream_context *context = NULL; - char *name; - phar_archive_data *phar; - fname = (char*)zend_get_executed_filename(); - - if (strncasecmp(fname, "phar://", 7)) { - goto skip_phar; - } - fname_len = strlen(fname); - if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + if (use_include_path || (!IS_ABSOLUTE_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename)) && !strstr(ZSTR_VAL(filename), "://"))) { + zend_string *name = phar_get_name_for_relative_paths(filename, use_include_path); + if (!name) { goto skip_phar; } - efree(entry); - entry = filename; - /* fopen within phar, if :// is not in the url, then prepend phar:/// */ - entry_len = filename_len; - /* retrieving a file defaults to within the current directory, so use this if possible */ - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { - efree(arch); - goto skip_phar; - } - if (use_include_path) { - if (!(entry_str = phar_find_in_include_path(entry, entry_len, NULL))) { - /* this file is not in the phar, use the original path */ - efree(arch); - goto skip_phar; - } else { - name = ZSTR_VAL(entry_str); - } - } else { - entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1); - if (entry[0] == '/') { - if (!zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1)) { - /* this file is not in the phar, use the original path */ -notfound: - efree(entry); - efree(arch); - goto skip_phar; - } - } else { - if (!zend_hash_str_exists(&(phar->manifest), entry, entry_len)) { - goto notfound; - } - } - /* auto-convert to phar:// */ - if (entry[0] == '/') { - spprintf(&name, 4096, "phar://%s%s", arch, entry); - } else { - spprintf(&name, 4096, "phar://%s/%s", arch, entry); - } - efree(entry); - } + php_stream *stream; + php_stream_context *context = php_stream_context_from_zval(zcontext, 0); - efree(arch); - context = php_stream_context_from_zval(zcontext, 0); - stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context); - if (entry_str) { - zend_string_release_ex(entry_str, 0); - } else { - efree(name); - } + stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), "rb", 0 | REPORT_ERRORS, NULL, context); + + zend_string_release_ex(name, false); if (stream == NULL) { RETURN_FALSE; } - size = php_stream_passthru(stream); + ssize_t size = php_stream_passthru(stream); php_stream_close(stream); RETURN_LONG(size); } @@ -332,11 +279,11 @@ PHAR_FUNC(phar_readfile) /* {{{ */ PHAR_FUNC(phar_fopen) /* {{{ */ { - char *filename, *mode; - size_t filename_len, mode_len; + zend_string *filename; + char *mode; + size_t mode_len; bool use_include_path = 0; zval *zcontext = NULL; - php_stream *stream; if (!PHAR_G(intercepted)) { goto skip_phar; @@ -347,76 +294,21 @@ PHAR_FUNC(phar_fopen) /* {{{ */ /* no need to check, include_path not even specified in fopen/ no active phars */ goto skip_phar; } - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "ps|br!", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "Ps|br!", &filename, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) { goto skip_phar; } - if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) { - char *arch, *entry, *fname; - zend_string *entry_str = NULL; - size_t arch_len, entry_len, fname_len; - php_stream_context *context = NULL; - char *name; - phar_archive_data *phar; - fname = (char*)zend_get_executed_filename(); - - if (strncasecmp(fname, "phar://", 7)) { - goto skip_phar; - } - fname_len = strlen(fname); - if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + if (use_include_path || (!IS_ABSOLUTE_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename)) && !strstr(ZSTR_VAL(filename), "://"))) { + zend_string *name = phar_get_name_for_relative_paths(filename, use_include_path); + if (!name) { goto skip_phar; } - efree(entry); - entry = filename; - /* fopen within phar, if :// is not in the url, then prepend phar:/// */ - entry_len = filename_len; - /* retrieving a file defaults to within the current directory, so use this if possible */ - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { - efree(arch); - goto skip_phar; - } - if (use_include_path) { - if (!(entry_str = phar_find_in_include_path(entry, entry_len, NULL))) { - /* this file is not in the phar, use the original path */ - efree(arch); - goto skip_phar; - } else { - name = ZSTR_VAL(entry_str); - } - } else { - entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1); - if (entry[0] == '/') { - if (!zend_hash_str_exists(&(phar->manifest), entry + 1, entry_len - 1)) { - /* this file is not in the phar, use the original path */ -notfound: - efree(entry); - efree(arch); - goto skip_phar; - } - } else { - if (!zend_hash_str_exists(&(phar->manifest), entry, entry_len)) { - /* this file is not in the phar, use the original path */ - goto notfound; - } - } - /* auto-convert to phar:// */ - if (entry[0] == '/') { - spprintf(&name, 4096, "phar://%s%s", arch, entry); - } else { - spprintf(&name, 4096, "phar://%s/%s", arch, entry); - } - efree(entry); - } + php_stream *stream; + php_stream_context *context = php_stream_context_from_zval(zcontext, 0); - efree(arch); - context = php_stream_context_from_zval(zcontext, 0); - stream = php_stream_open_wrapper_ex(name, mode, 0 | REPORT_ERRORS, NULL, context); - if (entry_str) { - zend_string_release_ex(entry_str, 0); - } else { - efree(name); - } + stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), mode, 0 | REPORT_ERRORS, NULL, context); + + zend_string_release_ex(name, false); if (stream == NULL) { RETURN_FALSE; } @@ -594,22 +486,22 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ } if (!IS_ABSOLUTE_PATH(filename, filename_length) && !strstr(filename, "://")) { - char *arch, *entry, *fname; - size_t arch_len, entry_len, fname_len; + char *arch, *entry; + size_t arch_len, entry_len; + zend_string *fname; zend_stat_t sb = {0}; phar_entry_info *data = NULL; phar_archive_data *phar; - fname = (char*)zend_get_executed_filename(); + fname = zend_get_executed_filename_ex(); /* we are checking for existence of a file within the relative path. Chances are good that this is retrieving something from within the phar archive */ - - if (strncasecmp(fname, "phar://", 7)) { + if (!fname || !zend_string_starts_with_literal_ci(fname, "phar://")) { goto skip_phar; } - fname_len = strlen(fname); - if (PHAR_G(last_phar) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) { + + if (PHAR_G(last_phar) && ZSTR_LEN(fname) - 7 >= PHAR_G(last_phar_name_len) && !memcmp(ZSTR_VAL(fname) + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) { arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len)); arch_len = PHAR_G(last_phar_name_len); entry = estrndup(filename, filename_length); @@ -618,7 +510,7 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ phar = PHAR_G(last_phar); goto splitted; } - if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, &entry, &entry_len, 2, 0)) { efree(entry); entry = estrndup(filename, filename_length); @@ -850,18 +742,17 @@ PHAR_FUNC(phar_is_file) /* {{{ */ goto skip_phar; } if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { - char *arch, *entry, *fname; - size_t arch_len, entry_len, fname_len; - fname = (char*)zend_get_executed_filename(); + char *arch, *entry; + size_t arch_len, entry_len; + zend_string *fname = zend_get_executed_filename_ex(); /* we are checking for existence of a file within the relative path. Chances are good that this is retrieving something from within the phar archive */ - - if (strncasecmp(fname, "phar://", 7)) { + if (!fname || !zend_string_starts_with_literal_ci(fname, "phar://")) { goto skip_phar; } - fname_len = strlen(fname); - if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + + if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, &entry, &entry_len, 2, 0)) { phar_archive_data *phar; efree(entry); @@ -917,18 +808,17 @@ PHAR_FUNC(phar_is_link) /* {{{ */ goto skip_phar; } if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { - char *arch, *entry, *fname; - size_t arch_len, entry_len, fname_len; - fname = (char*)zend_get_executed_filename(); + char *arch, *entry; + size_t arch_len, entry_len; + zend_string *fname = zend_get_executed_filename_ex(); /* we are checking for existence of a file within the relative path. Chances are good that this is retrieving something from within the phar archive */ - - if (strncasecmp(fname, "phar://", 7)) { + if (!fname || !zend_string_starts_with_literal_ci(fname, "phar://")) { goto skip_phar; } - fname_len = strlen(fname); - if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + + if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, &entry, &entry_len, 2, 0)) { phar_archive_data *phar; efree(entry); diff --git a/ext/phar/phar.1.in b/ext/phar/phar.1.in index ac314fe9d5807..bf4fd964d6386 100644 --- a/ext/phar/phar.1.in +++ b/ext/phar/phar.1.in @@ -1,4 +1,4 @@ -.TH PHAR 1 "2022" "The PHP Group" "User Commands" +.TH PHAR 1 "2023" "The PHP Group" "User Commands" .SH NAME phar, phar.phar \- PHAR (PHP archive) command line tool .SH SYNOPSIS diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 3c0f3eb50b70f..d2713c2a6f652 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1622,10 +1622,10 @@ static inline char *phar_strnstr(const char *buf, int buf_len, const char *searc */ static int phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, int is_data, char **error) /* {{{ */ { - const char token[] = "__HALT_COMPILER();"; - const char zip_magic[] = "PK\x03\x04"; - const char gz_magic[] = "\x1f\x8b\x08"; - const char bz_magic[] = "BZh"; + static const char token[] = "__HALT_COMPILER();"; + static const char zip_magic[] = "PK\x03\x04"; + static const char gz_magic[] = "\x1f\x8b\x08"; + static const char bz_magic[] = "BZh"; char *pos, test = '\0'; int recursion_count = 3; // arbitrary limit to avoid too deep or even infinite recursion const int window_size = 1024; @@ -1965,7 +1965,7 @@ int phar_detect_phar_fname_ext(const char *filename, size_t filename_len, const *ext_str = NULL; *ext_len = 0; - if (!filename_len || filename_len == 1) { + if (filename_len <= 1) { return FAILURE; } @@ -2318,30 +2318,23 @@ int phar_split_fname(const char *filename, size_t filename_len, char **arch, siz */ int phar_open_executed_filename(char *alias, size_t alias_len, char **error) /* {{{ */ { - char *fname; - php_stream *fp; - size_t fname_len; - zend_string *actual = NULL; - int ret; - if (error) { *error = NULL; } - fname = (char*)zend_get_executed_filename(); - fname_len = strlen(fname); + zend_string *fname = zend_get_executed_filename_ex(); - if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0) == SUCCESS) { - return SUCCESS; - } - - if (!strcmp(fname, "[no active file]")) { + if (!fname) { if (error) { spprintf(error, 0, "cannot initialize a phar outside of PHP execution"); } return FAILURE; } + if (phar_open_parsed_phar(ZSTR_VAL(fname), ZSTR_LEN(fname), alias, alias_len, 0, REPORT_ERRORS, NULL, 0) == SUCCESS) { + return SUCCESS; + } + if (0 == zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) { if (error) { spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar"); @@ -2349,15 +2342,17 @@ int phar_open_executed_filename(char *alias, size_t alias_len, char **error) /* return FAILURE; } - if (php_check_open_basedir(fname)) { + if (php_check_open_basedir(ZSTR_VAL(fname))) { return FAILURE; } - fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual); + zend_string *actual = NULL; + php_stream *fp; + fp = php_stream_open_wrapper(ZSTR_VAL(fname), "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual); if (!fp) { if (error) { - spprintf(error, 0, "unable to open phar for reading \"%s\"", fname); + spprintf(error, 0, "unable to open phar for reading \"%s\"", ZSTR_VAL(fname)); } if (actual) { zend_string_release_ex(actual, 0); @@ -2366,11 +2361,10 @@ int phar_open_executed_filename(char *alias, size_t alias_len, char **error) /* } if (actual) { - fname = ZSTR_VAL(actual); - fname_len = ZSTR_LEN(actual); + fname = actual; } - ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0, error); + int ret = phar_open_from_fp(fp, ZSTR_VAL(fname), ZSTR_LEN(fname), alias, alias_len, REPORT_ERRORS, NULL, 0, error); if (actual) { zend_string_release_ex(actual, 0); @@ -3288,7 +3282,7 @@ zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type static zend_string *phar_resolve_path(zend_string *filename) { - zend_string *ret = phar_find_in_include_path(ZSTR_VAL(filename), ZSTR_LEN(filename), NULL); + zend_string *ret = phar_find_in_include_path(filename, NULL); if (!ret) { ret = phar_save_resolve_path(filename); } diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 30b408a8c4462..9f8a46b65ec60 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -547,7 +547,7 @@ char *phar_compress_filter(phar_entry_info * entry, int return_unknown); /* void phar_remove_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len); */ void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len); int phar_mount_entry(phar_archive_data *phar, char *filename, size_t filename_len, char *path, size_t path_len); -zend_string *phar_find_in_include_path(char *file, size_t file_len, phar_archive_data **pphar); +zend_string *phar_find_in_include_path(zend_string *file, phar_archive_data **pphar); char *phar_fix_filepath(char *path, size_t *new_len, int use_cwd); phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error); void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker, uint32_t zip_metadata_len, int persistent); diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 5421b12198e8b..47a4ca541d12e 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -392,21 +392,27 @@ static void phar_postprocess_ru_web(char *fname, size_t fname_len, char **entry, */ PHP_METHOD(Phar, running) { - char *fname, *arch, *entry; - size_t fname_len, arch_len, entry_len; + zend_string *fname; + char *arch, *entry; + size_t arch_len, entry_len; bool retphar = 1; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &retphar) == FAILURE) { RETURN_THROWS(); } - fname = (char*)zend_get_executed_filename(); - fname_len = strlen(fname); + fname = zend_get_executed_filename_ex(); + if (!fname) { + RETURN_EMPTY_STRING(); + } - if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { + if ( + zend_string_starts_with_literal_ci(fname, "phar://") + && SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, &entry, &entry_len, 2, 0) + ) { efree(entry); if (retphar) { - RETVAL_STRINGL(fname, arch_len + 7); + RETVAL_STRINGL(ZSTR_VAL(fname), arch_len + 7); efree(arch); return; } else { @@ -441,8 +447,14 @@ PHP_METHOD(Phar, mount) RETURN_THROWS(); } - fname = (char*)zend_get_executed_filename(); - fname_len = strlen(fname); + zend_string *zend_file_name = zend_get_executed_filename_ex(); + if (UNEXPECTED(!zend_file_name)) { + fname = ""; + fname_len = 0; + } else { + fname = ZSTR_VAL(zend_file_name); + fname_len = ZSTR_LEN(zend_file_name); + } #ifdef PHP_WIN32 save_fname = fname; @@ -482,18 +494,9 @@ PHP_METHOD(Phar, mount) carry_on: if (SUCCESS != phar_mount_entry(pphar, actual, actual_len, path, path_len)) { zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s within phar %s failed", path, actual, arch); - if (path && path == entry) { - efree(entry); - } - - if (arch) { - efree(arch); - } - - goto finish; } - if (entry && path && path == entry) { + if (entry && path == entry) { efree(entry); } @@ -556,8 +559,6 @@ PHP_METHOD(Phar, webPhar) } phar_request_initialize(); - fname = (char*)zend_get_executed_filename(); - fname_len = strlen(fname); if (phar_open_executed_filename(alias, alias_len, &error) != SUCCESS) { if (error) { @@ -583,6 +584,14 @@ PHP_METHOD(Phar, webPhar) return; } + zend_string *zend_file_name = zend_get_executed_filename_ex(); + if (UNEXPECTED(!zend_file_name)) { + return; + } + + fname = ZSTR_VAL(zend_file_name); + fname_len = ZSTR_LEN(zend_file_name); + #ifdef PHP_WIN32 if (memchr(fname, '\\', fname_len)) { fname = estrndup(fname, fname_len); @@ -1274,9 +1283,9 @@ PHP_METHOD(Phar, getSupportedCompression) /* {{{ Completely remove a phar archive from memory and disk */ PHP_METHOD(Phar, unlinkArchive) { - char *fname, *error, *zname, *arch, *entry; + char *fname, *error, *arch, *entry; size_t fname_len; - size_t zname_len, arch_len, entry_len; + size_t arch_len, entry_len; phar_archive_data *phar; if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) { @@ -1298,11 +1307,14 @@ PHP_METHOD(Phar, unlinkArchive) RETURN_THROWS(); } - zname = (char*)zend_get_executed_filename(); - zname_len = strlen(zname); + zend_string *zend_file_name = zend_get_executed_filename_ex(); - if (zname_len > 7 && !memcmp(zname, "phar://", 7) && SUCCESS == phar_split_fname(zname, zname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { - if ((size_t)arch_len == fname_len && !memcmp(arch, fname, arch_len)) { + if ( + zend_file_name + && zend_string_starts_with_literal_ci(zend_file_name, "phar://") + && SUCCESS == phar_split_fname(ZSTR_VAL(zend_file_name), ZSTR_LEN(zend_file_name), &arch, &arch_len, &entry, &entry_len, 2, 0) + ) { + if (arch_len == fname_len && !memcmp(arch, fname, arch_len)) { zend_throw_exception_ex(phar_ce_PharException, 0, "phar archive \"%s\" cannot be unlinked from within itself", fname); efree(arch); efree(entry); @@ -1435,7 +1447,7 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ } close_fp = 0; - opened = zend_string_init("[stream]", sizeof("[stream]") - 1, 0); + opened = ZSTR_INIT_LITERAL("[stream]", 0); goto after_open_fp; case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(value), spl_ce_SplFileInfo)) { @@ -1975,7 +1987,7 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* char *ext_pos = NULL; /* Array of PHAR extensions, Must be in order, starting with longest * ending with the shortest. */ - char *phar_ext_list[] = { + static const char *const phar_ext_list[] = { ".phar.tar.bz2", ".phar.tar.gz", ".phar.php", @@ -2113,10 +2125,12 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* pphar->flags = phar->flags; pphar->fp = phar->fp; phar->fp = NULL; + /* FIX: GH-10755 Double-free issue caught by ASAN check */ + pphar->alias = phar->alias; /* Transfer alias to pphar to */ + phar->alias = NULL; /* avoid being free'd twice */ phar_destroy_phar_data(phar); *sphar = NULL; phar = pphar; - phar->refcount++; newpath = oldpath; goto its_ok; } @@ -2606,16 +2620,14 @@ PHP_METHOD(Phar, delete) zend_throw_exception_ex(phar_ce_PharException, 0, "phar \"%s\" is persistent, unable to copy on write", phar_obj->archive->fname); RETURN_THROWS(); } - if (zend_hash_str_exists(&phar_obj->archive->manifest, fname, (uint32_t) fname_len)) { - if (NULL != (entry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, fname, (uint32_t) fname_len))) { - if (entry->is_deleted) { - /* entry is deleted, but has not been flushed to disk yet */ - RETURN_TRUE; - } else { - entry->is_deleted = 1; - entry->is_modified = 1; - phar_obj->archive->is_modified = 1; - } + if (NULL != (entry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, fname, (uint32_t) fname_len))) { + if (entry->is_deleted) { + /* entry is deleted, but has not been flushed to disk yet */ + RETURN_TRUE; + } else { + entry->is_deleted = 1; + entry->is_modified = 1; + phar_obj->archive->is_modified = 1; } } else { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s does not exist and cannot be deleted", fname); @@ -3314,7 +3326,7 @@ PHP_METHOD(Phar, compressFiles) } if (!pharobj_cancompress(&phar_obj->archive->manifest)) { - if (flags == PHAR_FILE_COMPRESSED_GZ) { + if (flags == PHAR_ENT_COMPRESSED_GZ) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Cannot compress all files as Gzip, some are compressed as bzip2 and cannot be decompressed"); } else { @@ -3420,18 +3432,16 @@ PHP_METHOD(Phar, copy) RETURN_THROWS(); } - if (!zend_hash_str_exists(&phar_obj->archive->manifest, oldfile, (uint32_t) oldfile_len) || NULL == (oldentry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, oldfile, (uint32_t) oldfile_len)) || oldentry->is_deleted) { + if (NULL == (oldentry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, oldfile, (uint32_t) oldfile_len)) || oldentry->is_deleted) { zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "file \"%s\" cannot be copied to file \"%s\", file does not exist in %s", oldfile, newfile, phar_obj->archive->fname); RETURN_THROWS(); } - if (zend_hash_str_exists(&phar_obj->archive->manifest, newfile, (uint32_t) newfile_len)) { - if (NULL != (temp = zend_hash_str_find_ptr(&phar_obj->archive->manifest, newfile, (uint32_t) newfile_len)) || !temp->is_deleted) { - zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, - "file \"%s\" cannot be copied to file \"%s\", file must not already exist in phar %s", oldfile, newfile, phar_obj->archive->fname); - RETURN_THROWS(); - } + if (NULL != (temp = zend_hash_str_find_ptr(&phar_obj->archive->manifest, newfile, (uint32_t) newfile_len)) && !temp->is_deleted) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, + "file \"%s\" cannot be copied to file \"%s\", file must not already exist in phar %s", oldfile, newfile, phar_obj->archive->fname); + RETURN_THROWS(); } tmp_len = newfile_len; diff --git a/ext/phar/stream.c b/ext/phar/stream.c index b45b662398c79..e400699780e1f 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -84,7 +84,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const return NULL; } resource = ecalloc(1, sizeof(php_url)); - resource->scheme = zend_string_init("phar", 4, 0); + resource->scheme = ZSTR_INIT_LITERAL("phar", 0); resource->host = zend_string_init(arch, arch_len, 0); efree(arch); resource->path = zend_string_init(entry, entry_len, 0); diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 3b2e4c2ca76aa..60e248c78df5f 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -478,14 +478,15 @@ int phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, char *alia return FAILURE; } + uint32_t entry_mode = phar_tar_number(hdr->mode, sizeof(hdr->mode)); entry.tar_type = ((old & (hdr->typeflag == '\0')) ? TAR_FILE : hdr->typeflag); entry.offset = entry.offset_abs = pos; /* header_offset unused in tar */ entry.fp_type = PHAR_FP; - entry.flags = phar_tar_number(hdr->mode, sizeof(hdr->mode)) & PHAR_ENT_PERM_MASK; + entry.flags = entry_mode & PHAR_ENT_PERM_MASK; entry.timestamp = phar_tar_number(hdr->mtime, sizeof(hdr->mtime)); entry.is_persistent = myphar->is_persistent; - if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) { + if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry_mode)) { entry.tar_type = TAR_DIR; } @@ -1239,13 +1240,15 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int return EOF; } #ifdef WORDS_BIGENDIAN -# define PHAR_SET_32(var, buffer) \ - *(uint32_t *)(var) = (((((unsigned char*)&(buffer))[3]) << 24) \ - | ((((unsigned char*)&(buffer))[2]) << 16) \ - | ((((unsigned char*)&(buffer))[1]) << 8) \ - | (((unsigned char*)&(buffer))[0])) +# define PHAR_SET_32(destination, source) do { \ + uint32_t swapped = (((((unsigned char*)&(source))[3]) << 24) \ + | ((((unsigned char*)&(source))[2]) << 16) \ + | ((((unsigned char*)&(source))[1]) << 8) \ + | (((unsigned char*)&(source))[0])); \ + memcpy(destination, &swapped, 4); \ + } while (0); #else -# define PHAR_SET_32(var, buffer) *(uint32_t *)(var) = (uint32_t) (buffer) +# define PHAR_SET_32(destination, source) memcpy(destination, &source, 4) #endif PHAR_SET_32(sigbuf, phar->sig_flags); PHAR_SET_32(sigbuf + 4, signature_length); diff --git a/ext/phar/tests/bug69958.phpt b/ext/phar/tests/bug69958.phpt index b53c76a104951..447efce57db7c 100644 --- a/ext/phar/tests/bug69958.phpt +++ b/ext/phar/tests/bug69958.phpt @@ -1,7 +1,5 @@ --TEST-- Phar: bug #69958: Segfault in Phar::convertToData on invalid file ---XFAIL-- -Still has memory leaks, see https://bugs.php.net/bug.php?id=70005 --EXTENSIONS-- phar --FILE-- @@ -10,8 +8,8 @@ $tarphar = new PharData(__DIR__.'/bug69958.tar'); $phar = $tarphar->convertToData(Phar::TAR); ?> --EXPECTF-- -Fatal error: Uncaught BadMethodCallException: phar "%s/bug69958.tar" exists and must be unlinked prior to conversion in %s/bug69958.php:%d +Fatal error: Uncaught BadMethodCallException: phar "%sbug69958.tar" exists and must be unlinked prior to conversion in %sbug69958.php:%d Stack trace: -#0 %s/bug69958.php(%d): PharData->convertToData(%d) +#0 %sbug69958.php(%d): PharData->convertToData(%d) #1 {main} - thrown in %s/bug69958.php on line %d + thrown in %sbug69958.php on line %d diff --git a/ext/phar/tests/zip/gh10766.phpt b/ext/phar/tests/zip/gh10766.phpt new file mode 100644 index 0000000000000..c6b2927d08c05 --- /dev/null +++ b/ext/phar/tests/zip/gh10766.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-10766 (PharData archive created with Phar::Zip format does not keep files metadata (datetime)) +--EXTENSIONS-- +phar +zip +--INI-- +phar.readonly=0 +--FILE-- +addFromString('name', 'contents'); +unset($phar); + +// Re-read from disk, but using the zip extension because the phar bug will not make it possible +// to use their timestamp methods. +$zip = new ZipArchive(); +$zip->open(__DIR__ . '/gh10766.zip'); +var_dump($zip->statName('name')['mtime'] > 315529200 /* earliest possible zip timestamp */); +$zip->close(); +?> +--CLEAN-- + +--EXPECT-- +bool(true) diff --git a/ext/phar/util.c b/ext/phar/util.c index 72e633a5b3324..edd10dc3837af 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -239,11 +239,11 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, size_t filename_le } /* }}} */ -zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar_archive_data **pphar) /* {{{ */ +zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data **pphar) /* {{{ */ { zend_string *ret; - char *path, *fname, *arch, *entry, *test; - size_t arch_len, entry_len, fname_len; + char *path, *arch, *entry, *test; + size_t arch_len, entry_len; phar_archive_data *phar; if (pphar) { @@ -256,23 +256,33 @@ zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar return NULL; } - fname = (char*)zend_get_executed_filename(); - fname_len = strlen(fname); + zend_string *fname = zend_get_executed_filename_ex(); + if (!fname) { + return NULL; + } - if (PHAR_G(last_phar) && !memcmp(fname, "phar://", 7) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) { + bool is_file_a_phar_wrapper = zend_string_starts_with_literal_ci(fname, "phar://"); + size_t length_phar_protocol = strlen("phar://"); + + if ( + PHAR_G(last_phar) + && is_file_a_phar_wrapper + && ZSTR_LEN(fname) - length_phar_protocol >= PHAR_G(last_phar_name_len) + && !memcmp(ZSTR_VAL(fname) + length_phar_protocol, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len)) + ) { arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len)); arch_len = PHAR_G(last_phar_name_len); phar = PHAR_G(last_phar); goto splitted; } - if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0)) { + if (!is_file_a_phar_wrapper || SUCCESS != phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, &entry, &entry_len, 1, 0)) { return NULL; } efree(entry); - if (*filename == '.') { + if (*ZSTR_VAL(filename) == '.') { size_t try_len; if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { @@ -284,8 +294,8 @@ zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar *pphar = phar; } - try_len = filename_len; - test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1); + try_len = ZSTR_LEN(filename); + test = phar_fix_filepath(estrndup(ZSTR_VAL(filename), ZSTR_LEN(filename)), &try_len, 1); if (*test == '/') { if (zend_hash_str_exists(&(phar->manifest), test + 1, try_len - 1)) { @@ -307,10 +317,10 @@ zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar spprintf(&path, MAXPATHLEN + 1 + strlen(PG(include_path)), "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path)); efree(arch); - ret = php_resolve_path(filename, filename_len, path); + ret = php_resolve_path(ZSTR_VAL(filename), ZSTR_LEN(filename), path); efree(path); - if (ret && ZSTR_LEN(ret) > 8 && !strncmp(ZSTR_VAL(ret), "phar://", 7)) { + if (ret && zend_string_starts_with_literal_ci(ret, "phar://")) { /* found phar:// */ if (SUCCESS != phar_split_fname(ZSTR_VAL(ret), ZSTR_LEN(ret), &arch, &arch_len, &entry, &entry_len, 1, 0)) { return ret; @@ -1247,7 +1257,7 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, si } if (is_dir) { - if (!path_len || path_len == 1) { + if (path_len <= 1) { return NULL; } path_len--; @@ -1539,10 +1549,8 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, #ifndef PHAR_HAVE_OPENSSL tempsig = sig_len; - if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey ? ZSTR_VAL(pubkey) : NULL, pubkey ? ZSTR_LEN(pubkey) : 0, &sig, &tempsig, sig_type)) { - if (pubkey) { - zend_string_release_ex(pubkey, 0); - } + if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, ZSTR_VAL(pubkey), ZSTR_LEN(pubkey), &sig, &tempsig, sig_type)) { + zend_string_release_ex(pubkey, 0); if (error) { spprintf(error, 0, "openssl signature could not be verified"); @@ -1551,13 +1559,11 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, return FAILURE; } - if (pubkey) { - zend_string_release_ex(pubkey, 0); - } + zend_string_release_ex(pubkey, 0); sig_len = tempsig; #else - in = BIO_new_mem_buf(pubkey ? ZSTR_VAL(pubkey) : NULL, pubkey ? ZSTR_LEN(pubkey) : 0); + in = BIO_new_mem_buf(ZSTR_VAL(pubkey), ZSTR_LEN(pubkey)); if (NULL == in) { zend_string_release_ex(pubkey, 0); @@ -1579,7 +1585,15 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, } md_ctx = EVP_MD_CTX_create(); - EVP_VerifyInit(md_ctx, mdtype); + if (!md_ctx || !EVP_VerifyInit(md_ctx, mdtype)) { + if (md_ctx) { + EVP_MD_CTX_destroy(md_ctx); + } + if (error) { + spprintf(error, 0, "openssl signature could not be verified"); + } + return FAILURE; + } read_len = end_of_phar; if ((size_t)read_len > sizeof(buf)) { diff --git a/ext/phar/zip.c b/ext/phar/zip.c index bfa23e9768b32..90b36d94e5b8d 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -147,7 +147,8 @@ static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate) /* {{{ */ struct tm *tm, tmbuf; tm = php_localtime_r(&time, &tmbuf); - if (tm->tm_year >= 1980) { + /* Note: tm_year is the year - 1900 */ + if (tm->tm_year >= 80) { cdate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday; ctime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1); } else { @@ -428,7 +429,6 @@ int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alia PHAR_ZIP_FAIL("signatures larger than 64 KiB are not supported"); } - php_stream_tell(fp); sigfile = php_stream_fopen_tmpfile(); if (!sigfile) { PHAR_ZIP_FAIL("couldn't open temporary file"); diff --git a/ext/posix/config.m4 b/ext/posix/config.m4 index e91041188ae73..6b056c43740c9 100644 --- a/ext/posix/config.m4 +++ b/ext/posix/config.m4 @@ -10,7 +10,7 @@ if test "$PHP_POSIX" = "yes"; then AC_CHECK_HEADERS([sys/mkdev.h sys/sysmacros.h]) - AC_CHECK_FUNCS(seteuid setegid setsid getsid getpgid ctermid mkfifo mknod setrlimit getrlimit getgroups makedev initgroups getgrgid_r) + AC_CHECK_FUNCS(seteuid setegid setsid getsid getpgid ctermid mkfifo mknod setrlimit getrlimit getgroups makedev initgroups getgrgid_r posix_pathconf eaccess) AC_MSG_CHECKING([for working ttyname_r() implementation]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ diff --git a/ext/posix/posix.c b/ext/posix/posix.c index 271b11567016b..bfb542bad7539 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -417,7 +417,7 @@ PHP_FUNCTION(posix_ctermid) /* }}} */ /* Checks if the provides resource is a stream and if it provides a file descriptor */ -static int php_posix_stream_get_fd(zval *zfp, int *fd) /* {{{ */ +static int php_posix_stream_get_fd(zval *zfp, zend_long *fd) /* {{{ */ { php_stream *stream; @@ -444,7 +444,7 @@ PHP_FUNCTION(posix_ttyname) { zval *z_fd; char *p; - int fd; + zend_long fd; #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX) zend_long buflen; #endif @@ -453,14 +453,21 @@ PHP_FUNCTION(posix_ttyname) Z_PARAM_ZVAL(z_fd) ZEND_PARSE_PARAMETERS_END(); - switch (Z_TYPE_P(z_fd)) { - case IS_RESOURCE: - if (!php_posix_stream_get_fd(z_fd, &fd)) { - RETURN_FALSE; - } - break; - default: + if (Z_TYPE_P(z_fd) == IS_RESOURCE) { + if (!php_posix_stream_get_fd(z_fd, &fd)) { + RETURN_FALSE; + } + } else { + if (!zend_parse_arg_long(z_fd, &fd, /* is_null */ NULL, /* check_null */ false, /* arg_num */ 1)) { + php_error_docref(NULL, E_WARNING, "Argument #1 ($file_descriptor) must be of type int|resource, %s given", + zend_zval_value_name(z_fd)); fd = zval_get_long(z_fd); + } + /* fd must fit in an int and be positive */ + if (fd < 0 || fd > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Argument #1 ($file_descriptor) must be between 0 and %d", INT_MAX); + RETURN_FALSE; + } } #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX) buflen = sysconf(_SC_TTY_NAME_MAX); @@ -474,15 +481,15 @@ PHP_FUNCTION(posix_ttyname) efree(p); RETURN_FALSE; } - RETURN_STRING(p); + RETVAL_STRING(p); efree(p); #else if (NULL == (p = ttyname(fd))) { POSIX_G(last_error) = errno; RETURN_FALSE; } -#endif RETURN_STRING(p); +#endif } /* }}} */ @@ -490,22 +497,28 @@ PHP_FUNCTION(posix_ttyname) PHP_FUNCTION(posix_isatty) { zval *z_fd; - int fd; + zend_long fd; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(z_fd) ZEND_PARSE_PARAMETERS_END(); - switch (Z_TYPE_P(z_fd)) { - case IS_RESOURCE: - if (!php_posix_stream_get_fd(z_fd, &fd)) { - RETURN_FALSE; - } - break; - default: + if (Z_TYPE_P(z_fd) == IS_RESOURCE) { + if (!php_posix_stream_get_fd(z_fd, &fd)) { + RETURN_FALSE; + } + } else { + if (!zend_parse_arg_long(z_fd, &fd, /* is_null */ NULL, /* check_null */ false, /* arg_num */ 1)) { + php_error_docref(NULL, E_WARNING, "Argument #1 ($file_descriptor) must be of type int|resource, %s given", + zend_zval_value_name(z_fd)); fd = zval_get_long(z_fd); + } } + /* A valid file descriptor must fit in an int and be positive */ + if (fd < 0 || fd > INT_MAX) { + RETURN_FALSE; + } if (isatty(fd)) { RETURN_TRUE; } else { @@ -700,6 +713,44 @@ PHP_FUNCTION(posix_access) RETURN_TRUE; } + +#ifdef HAVE_EACCESS +PHP_FUNCTION(posix_eaccess) +{ + zend_long mode = 0; + size_t filename_len, ret; + char *filename, *path; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_PATH(filename, filename_len) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(mode) + ZEND_PARSE_PARAMETERS_END(); + + path = expand_filepath(filename, NULL); + if (!path) { + zend_argument_value_error(1, "cannot be empty"); + RETURN_THROWS(); + } + + if (php_check_open_basedir_ex(path, 0)) { + efree(path); + POSIX_G(last_error) = EPERM; + RETURN_FALSE; + } + + ret = eaccess(path, mode); + efree(path); + + if (ret) { + POSIX_G(last_error) = errno; + RETURN_FALSE; + } + + RETURN_TRUE; +} +#endif + /* }}} */ /* @@ -1183,3 +1234,66 @@ PHP_FUNCTION(posix_sysconf) RETURN_LONG(sysconf(conf_id)); } + +#ifdef HAVE_POSIX_PATHCONF +PHP_FUNCTION(posix_pathconf) +{ + zend_long name, ret; + char *path; + size_t path_len; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH(path, path_len) + Z_PARAM_LONG(name); + ZEND_PARSE_PARAMETERS_END(); + + if (path_len == 0) { + zend_argument_value_error(1, "cannot be empty"); + RETURN_THROWS(); + } else if (php_check_open_basedir(path)) { + php_error_docref(NULL, E_WARNING, "Invalid path supplied: %s", path); + RETURN_FALSE; + } + + ret = pathconf(path, name); + + if (ret < 0 && errno != 0) { + POSIX_G(last_error) = errno; + RETURN_FALSE; + } + + RETURN_LONG(ret); +} + +PHP_FUNCTION(posix_fpathconf) +{ + zend_long name, ret, fd; + zval *z_fd; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(z_fd) + Z_PARAM_LONG(name); + ZEND_PARSE_PARAMETERS_END(); + + if (Z_TYPE_P(z_fd) == IS_RESOURCE) { + if (!php_posix_stream_get_fd(z_fd, &fd)) { + RETURN_FALSE; + } + } else { + if (!zend_parse_arg_long(z_fd, &fd, /* is_null */ NULL, /* check_null */ false, /* arg_num */ 1)) { + zend_argument_type_error(1, "must be of type int|resource, %s given", + zend_zval_value_name(z_fd)); + RETURN_THROWS(); + } + } + + ret = fpathconf(fd, name); + + if (ret < 0 && errno != 0) { + POSIX_G(last_error) = errno; + RETURN_FALSE; + } + + RETURN_LONG(ret); +} +#endif diff --git a/ext/posix/posix.stub.php b/ext/posix/posix.stub.php index cc73901444fbb..4e5adc2eef92b 100644 --- a/ext/posix/posix.stub.php +++ b/ext/posix/posix.stub.php @@ -219,6 +219,76 @@ */ const POSIX_SC_NPROCESSORS_ONLN = UNKNOWN; #endif +#ifdef _PC_LINK_MAX +/** + * @var int + * @cvalue _PC_LINK_MAX + */ +const POSIX_PC_LINK_MAX = UNKNOWN; +#endif +#ifdef _PC_MAX_CANON +/** + * @var int + * @cvalue _PC_MAX_CANON + */ +const POSIX_PC_MAX_CANON = UNKNOWN; +#endif +#ifdef _PC_MAX_INPUT +/** + * @var int + * @cvalue _PC_MAX_INPUT + */ +const POSIX_PC_MAX_INPUT = UNKNOWN; +#endif +#ifdef _PC_NAME_MAX +/** + * @var int + * @cvalue _PC_NAME_MAX + */ +const POSIX_PC_NAME_MAX = UNKNOWN; +#endif +#ifdef _PC_PATH_MAX +/** + * @var int + * @cvalue _PC_PATH_MAX + */ +const POSIX_PC_PATH_MAX = UNKNOWN; +#endif +#ifdef _PC_PIPE_BUF +/** + * @var int + * @cvalue _PC_PIPE_BUF + */ +const POSIX_PC_PIPE_BUF = UNKNOWN; +#endif +#ifdef _PC_CHOWN_RESTRICTED +/** + * @var int + * @cvalue _PC_CHOWN_RESTRICTED + */ +const POSIX_PC_CHOWN_RESTRICTED = UNKNOWN; +#endif +#ifdef _PC_NO_TRUNC +/** + * @var int + * @cvalue _PC_NO_TRUNC + */ +const POSIX_PC_NO_TRUNC = UNKNOWN; +#endif +#ifdef _PC_ALLOC_SIZE_MIN +/** + * @var int + * @cvalue _PC_ALLOC_SIZE_MIN + */ +const POSIX_PC_ALLOC_SIZE_MIN = UNKNOWN; +#endif +#ifdef _PC_SYMLINK_MAX +/** + * @var int + * @cvalue _PC_SYMLINK_MAX + */ +const POSIX_PC_SYMLINK_MAX = UNKNOWN; +#endif function posix_kill(int $process_id, int $signal): bool {} @@ -309,6 +379,10 @@ function posix_mknod(string $filename, int $flags, int $major = 0, int $minor = function posix_access(string $filename, int $flags = 0): bool {} +#ifdef HAVE_EACCESS +function posix_eaccess(string $filename, int $flags = 0): bool {} +#endif + /** * @return array|false * @refcount 1 @@ -357,3 +431,9 @@ function posix_initgroups(string $username, int $group_id): bool {} #endif function posix_sysconf(int $conf_id): int {} + +#ifdef HAVE_POSIX_PATHCONF +function posix_pathconf(string $path, int $name): int|false {} +/** @param resource|int $file_descriptor */ +function posix_fpathconf($file_descriptor, int $name): int|false {} +#endif diff --git a/ext/posix/posix_arginfo.h b/ext/posix/posix_arginfo.h index bc7f4791ef086..2953e93fcdd4d 100644 --- a/ext/posix/posix_arginfo.h +++ b/ext/posix/posix_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a6ba91179f2a7ca3622aed0c28e8431868076567 */ + * Stub hash: 5a4a863892761475f2d34d9463e0660b0a8ede5d */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_posix_kill, 0, 2, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, process_id, IS_LONG, 0) @@ -115,6 +115,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_posix_access, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") ZEND_END_ARG_INFO() +#if defined(HAVE_EACCESS) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_posix_eaccess, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_posix_getgrnam, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -164,6 +171,20 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_posix_sysconf, 0, 1, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, conf_id, IS_LONG, 0) ZEND_END_ARG_INFO() +#if defined(HAVE_POSIX_PATHCONF) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_posix_pathconf, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_LONG, 0) +ZEND_END_ARG_INFO() +#endif + +#if defined(HAVE_POSIX_PATHCONF) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_posix_fpathconf, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) + ZEND_ARG_INFO(0, file_descriptor) + ZEND_ARG_TYPE_INFO(0, name, IS_LONG, 0) +ZEND_END_ARG_INFO() +#endif + ZEND_FUNCTION(posix_kill); ZEND_FUNCTION(posix_getpid); @@ -212,6 +233,9 @@ ZEND_FUNCTION(posix_mkfifo); ZEND_FUNCTION(posix_mknod); #endif ZEND_FUNCTION(posix_access); +#if defined(HAVE_EACCESS) +ZEND_FUNCTION(posix_eaccess); +#endif ZEND_FUNCTION(posix_getgrnam); ZEND_FUNCTION(posix_getgrgid); ZEND_FUNCTION(posix_getpwnam); @@ -228,6 +252,12 @@ ZEND_FUNCTION(posix_strerror); ZEND_FUNCTION(posix_initgroups); #endif ZEND_FUNCTION(posix_sysconf); +#if defined(HAVE_POSIX_PATHCONF) +ZEND_FUNCTION(posix_pathconf); +#endif +#if defined(HAVE_POSIX_PATHCONF) +ZEND_FUNCTION(posix_fpathconf); +#endif static const zend_function_entry ext_functions[] = { @@ -278,6 +308,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(posix_mknod, arginfo_posix_mknod) #endif ZEND_FE(posix_access, arginfo_posix_access) +#if defined(HAVE_EACCESS) + ZEND_FE(posix_eaccess, arginfo_posix_eaccess) +#endif ZEND_FE(posix_getgrnam, arginfo_posix_getgrnam) ZEND_FE(posix_getgrgid, arginfo_posix_getgrgid) ZEND_FE(posix_getpwnam, arginfo_posix_getpwnam) @@ -295,6 +328,12 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(posix_initgroups, arginfo_posix_initgroups) #endif ZEND_FE(posix_sysconf, arginfo_posix_sysconf) +#if defined(HAVE_POSIX_PATHCONF) + ZEND_FE(posix_pathconf, arginfo_posix_pathconf) +#endif +#if defined(HAVE_POSIX_PATHCONF) + ZEND_FE(posix_fpathconf, arginfo_posix_fpathconf) +#endif ZEND_FE_END }; @@ -388,4 +427,34 @@ static void register_posix_symbols(int module_number) #if defined(_SC_NPROCESSORS_ONLN) REGISTER_LONG_CONSTANT("POSIX_SC_NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN, CONST_PERSISTENT); #endif +#if defined(_PC_LINK_MAX) + REGISTER_LONG_CONSTANT("POSIX_PC_LINK_MAX", _PC_LINK_MAX, CONST_PERSISTENT); +#endif +#if defined(_PC_MAX_CANON) + REGISTER_LONG_CONSTANT("POSIX_PC_MAX_CANON", _PC_MAX_CANON, CONST_PERSISTENT); +#endif +#if defined(_PC_MAX_INPUT) + REGISTER_LONG_CONSTANT("POSIX_PC_MAX_INPUT", _PC_MAX_INPUT, CONST_PERSISTENT); +#endif +#if defined(_PC_NAME_MAX) + REGISTER_LONG_CONSTANT("POSIX_PC_NAME_MAX", _PC_NAME_MAX, CONST_PERSISTENT); +#endif +#if defined(_PC_PATH_MAX) + REGISTER_LONG_CONSTANT("POSIX_PC_PATH_MAX", _PC_PATH_MAX, CONST_PERSISTENT); +#endif +#if defined(_PC_PIPE_BUF) + REGISTER_LONG_CONSTANT("POSIX_PC_PIPE_BUF", _PC_PIPE_BUF, CONST_PERSISTENT); +#endif +#if defined(_PC_CHOWN_RESTRICTED) + REGISTER_LONG_CONSTANT("POSIX_PC_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED, CONST_PERSISTENT); +#endif +#if defined(_PC_NO_TRUNC) + REGISTER_LONG_CONSTANT("POSIX_PC_NO_TRUNC", _PC_NO_TRUNC, CONST_PERSISTENT); +#endif +#if defined(_PC_ALLOC_SIZE_MIN) + REGISTER_LONG_CONSTANT("POSIX_PC_ALLOC_SIZE_MIN", _PC_ALLOC_SIZE_MIN, CONST_PERSISTENT); +#endif +#if defined(_PC_SYMLINK_MAX) + REGISTER_LONG_CONSTANT("POSIX_PC_SYMLINK_MAX", _PC_SYMLINK_MAX, CONST_PERSISTENT); +#endif } diff --git a/ext/posix/tests/posix_eaccess.phpt b/ext/posix/tests/posix_eaccess.phpt new file mode 100644 index 0000000000000..ab47a1a0e8e36 --- /dev/null +++ b/ext/posix/tests/posix_eaccess.phpt @@ -0,0 +1,20 @@ +--TEST-- +posix_eaccess() with bogus paths +--EXTENSIONS-- +posix +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; +} + +?> +--EXPECT-- +posix_eaccess(): Argument #1 ($filename) cannot be empty diff --git a/ext/posix/tests/posix_fpathconf.phpt b/ext/posix/tests/posix_fpathconf.phpt new file mode 100644 index 0000000000000..cc388d5c0971f --- /dev/null +++ b/ext/posix/tests/posix_fpathconf.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test posix_fpathconf +--EXTENSIONS-- +posix +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +$fd = fopen(sys_get_temp_dir(), "r"); +var_dump(posix_fpathconf($fd, POSIX_PC_PATH_MAX)); +fclose($fd); +?> +--EXPECTF-- +bool(false) +bool(true) +posix_fpathconf(): Argument #1 ($file_descriptor) must be of type int|resource, string given +int(%d) diff --git a/ext/posix/tests/posix_getgrgid_basic.phpt b/ext/posix/tests/posix_getgrgid_basic.phpt index 6b0daa5e940fc..392e81d491d61 100644 --- a/ext/posix/tests/posix_getgrgid_basic.phpt +++ b/ext/posix/tests/posix_getgrgid_basic.phpt @@ -17,7 +17,7 @@ Basic test of POSIX getgid and getgrid functions Array ( [name] => %s - [passwd] => %a + [passwd] => %A [members] => Array %a diff --git a/ext/posix/tests/posix_getgrgid_error.phpt b/ext/posix/tests/posix_getgrgid_error.phpt index 952a3894ef8c3..f0d49a7860f8a 100644 --- a/ext/posix/tests/posix_getgrgid_error.phpt +++ b/ext/posix/tests/posix_getgrgid_error.phpt @@ -4,7 +4,7 @@ Test posix_getgrgid() function : error conditions posix --SKIPIF-- --FILE-- string(%d) "%s" ["passwd"]=> - string(1) "%s" + string(%d) "%S" ["members"]=> %a ["gid"]=> diff --git a/ext/posix/tests/posix_getpwuid_error.phpt b/ext/posix/tests/posix_getpwuid_error.phpt index b7bae3039262f..4f2f0ac1e2464 100644 --- a/ext/posix/tests/posix_getpwuid_error.phpt +++ b/ext/posix/tests/posix_getpwuid_error.phpt @@ -4,7 +4,7 @@ Test posix_getpwuid() function : error conditions posix --SKIPIF-- --FILE-- null, + 'false' => false, + 'true' => true, + 'int' => 1, + 'float no decimal' => 1.0, + 'float decimal' => 5.5, + 'string int' => "1", + 'string float no decimal' => "1.0", + 'string float decimal' => "5.5", + 'string' => "Hello", + 'array' => [], + 'class' => new stdClass(), + 'stringable class' => new classWithToString(), + 'int castable class' => gmp_init(1), +]; + +foreach ($types as $description => $type) { + echo $description, ':'; + var_dump(posix_isatty($type)); +} +?> +--EXPECTF-- +null: +Deprecated: posix_isatty(): Passing null to parameter #1 ($file_descriptor) of type int is deprecated in %s on line %d +bool(false) +false:bool(false) +true:bool(false) +int:bool(false) +float no decimal:bool(false) +float decimal: +Deprecated: Implicit conversion from float 5.5 to int loses precision in %s on line %d +bool(false) +string int:bool(false) +string float no decimal:bool(false) +string float decimal: +Deprecated: Implicit conversion from float-string "5.5" to int loses precision in %s on line %d +bool(false) +string: +Warning: posix_isatty(): Argument #1 ($file_descriptor) must be of type int|resource, string given in %s on line %d +bool(false) +array: +Warning: posix_isatty(): Argument #1 ($file_descriptor) must be of type int|resource, array given in %s on line %d +bool(false) +class: +Warning: posix_isatty(): Argument #1 ($file_descriptor) must be of type int|resource, stdClass given in %s on line %d + +Warning: Object of class stdClass could not be converted to int in %s on line %d +bool(false) +stringable class: +Warning: posix_isatty(): Argument #1 ($file_descriptor) must be of type int|resource, classWithToString given in %s on line %d + +Warning: Object of class classWithToString could not be converted to int in %s on line %d +bool(false) +int castable class: +Warning: posix_isatty(): Argument #1 ($file_descriptor) must be of type int|resource, GMP given in %s on line %d +bool(false) diff --git a/ext/posix/tests/posix_isatty_value_errors.phpt b/ext/posix/tests/posix_isatty_value_errors.phpt new file mode 100644 index 0000000000000..19dfe62c93019 --- /dev/null +++ b/ext/posix/tests/posix_isatty_value_errors.phpt @@ -0,0 +1,23 @@ +--TEST-- +posix_isatty(): errors for invalid file descriptors +--EXTENSIONS-- +posix +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/posix/tests/posix_pathconf.phpt b/ext/posix/tests/posix_pathconf.phpt new file mode 100644 index 0000000000000..ffbec521f92c0 --- /dev/null +++ b/ext/posix/tests/posix_pathconf.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test posix_pathconf +--EXTENSIONS-- +posix +--SKIPIF-- + +--FILE-- +getMessage(). "\n"; +} +var_dump(posix_pathconf(str_repeat('non_existent', 4096), POSIX_PC_NAME_MAX)); +var_dump(posix_errno() != 0); +var_dump(posix_pathconf(sys_get_temp_dir(), POSIX_PC_PATH_MAX)); +?> +--EXPECTF-- +posix_pathconf(): Argument #1 ($path) cannot be empty +bool(false) +bool(true) +int(%d) diff --git a/ext/posix/tests/posix_ttyname_manual_zpp.phpt b/ext/posix/tests/posix_ttyname_manual_zpp.phpt new file mode 100644 index 0000000000000..0fd24efd8f81b --- /dev/null +++ b/ext/posix/tests/posix_ttyname_manual_zpp.phpt @@ -0,0 +1,71 @@ +--TEST-- +posix_ttyname(): manually validating int ZPP param +--EXTENSIONS-- +posix +gmp +--FILE-- + null, + 'false' => false, + 'true' => true, + 'int' => 1, + 'float no decimal' => 1.0, + 'float decimal' => 5.5, + 'string int' => "1", + 'string float no decimal' => "1.0", + 'string float decimal' => "5.5", + 'string' => "Hello", + 'array' => [], + 'class' => new stdClass(), + 'stringable class' => new classWithToString(), + 'int castable class' => gmp_init(1), +]; + +foreach ($types as $description => $type) { + echo $description, ':'; + var_dump(posix_ttyname($type)); +} +?> +--EXPECTF-- +null: +Deprecated: posix_ttyname(): Passing null to parameter #1 ($file_descriptor) of type int is deprecated in %s on line %d +bool(false) +false:bool(false) +true:bool(false) +int:bool(false) +float no decimal:bool(false) +float decimal: +Deprecated: Implicit conversion from float 5.5 to int loses precision in %s on line %d +bool(false) +string int:bool(false) +string float no decimal:bool(false) +string float decimal: +Deprecated: Implicit conversion from float-string "5.5" to int loses precision in %s on line %d +bool(false) +string: +Warning: posix_ttyname(): Argument #1 ($file_descriptor) must be of type int|resource, string given in %s on line %d +bool(false) +array: +Warning: posix_ttyname(): Argument #1 ($file_descriptor) must be of type int|resource, array given in %s on line %d +bool(false) +class: +Warning: posix_ttyname(): Argument #1 ($file_descriptor) must be of type int|resource, stdClass given in %s on line %d + +Warning: Object of class stdClass could not be converted to int in %s on line %d +bool(false) +stringable class: +Warning: posix_ttyname(): Argument #1 ($file_descriptor) must be of type int|resource, classWithToString given in %s on line %d + +Warning: Object of class classWithToString could not be converted to int in %s on line %d +bool(false) +int castable class: +Warning: posix_ttyname(): Argument #1 ($file_descriptor) must be of type int|resource, GMP given in %s on line %d +bool(false) diff --git a/ext/posix/tests/posix_ttyname_value_errors.phpt b/ext/posix/tests/posix_ttyname_value_errors.phpt new file mode 100644 index 0000000000000..0f0c853458fbf --- /dev/null +++ b/ext/posix/tests/posix_ttyname_value_errors.phpt @@ -0,0 +1,26 @@ +--TEST-- +posix_ttyname(): errors for invalid file descriptors +--EXTENSIONS-- +posix +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: posix_ttyname(): Argument #1 ($file_descriptor) must be between 0 and %d in %s on line %d +bool(false) + +Warning: posix_ttyname(): Argument #1 ($file_descriptor) must be between 0 and %d in %s on line %d +bool(false) diff --git a/ext/posix/tests/posix_ttyname_variation1.phpt b/ext/posix/tests/posix_ttyname_variation1.phpt deleted file mode 100644 index 60357e4e1779f..0000000000000 --- a/ext/posix/tests/posix_ttyname_variation1.phpt +++ /dev/null @@ -1,37 +0,0 @@ ---TEST-- -Test function posix_ttyname() by substituting argument 1 with array values. ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---EXTENSIONS-- -posix ---FILE-- - 'one', 2 => 'two'); - -$variation_array = array( - 'empty array' => array(), - 'int indexed array' => $index_array, - 'associative array' => $assoc_array, - 'nested arrays' => array('foo', $index_array, $assoc_array), - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_ttyname( $var ) ); -} -?> ---EXPECT-- -*** Test substituting argument 1 with array values *** -bool(false) -bool(false) -bool(false) -bool(false) diff --git a/ext/posix/tests/posix_ttyname_variation2.phpt b/ext/posix/tests/posix_ttyname_variation2.phpt deleted file mode 100644 index 7a51cff3a5df7..0000000000000 --- a/ext/posix/tests/posix_ttyname_variation2.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -Test function posix_ttyname() by substituting argument 1 with boolean values. ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---EXTENSIONS-- -posix ---FILE-- - true, - 'lowercase false' =>false, - 'uppercase TRUE' =>TRUE, - 'uppercase FALSE' =>FALSE, - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_ttyname( $var ) ); -} -?> ---EXPECT-- -*** Test substituting argument 1 with boolean values *** -bool(false) -bool(false) -bool(false) -bool(false) diff --git a/ext/posix/tests/posix_ttyname_variation3.phpt b/ext/posix/tests/posix_ttyname_variation3.phpt deleted file mode 100644 index 4fab6f104b648..0000000000000 --- a/ext/posix/tests/posix_ttyname_variation3.phpt +++ /dev/null @@ -1,41 +0,0 @@ ---TEST-- -Test function posix_ttyname() by substituting argument 1 with emptyUnsetUndefNull values. ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---EXTENSIONS-- -posix ---FILE-- - @$unset_var, - 'undefined var' => @$undefined_var, - 'empty string DQ' => "", - 'empty string SQ' => '', - 'uppercase NULL' => NULL, - 'lowercase null' => null, - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_ttyname( $var ) ); -} -?> ---EXPECT-- -*** Test substituting argument 1 with emptyUnsetUndefNull values *** -bool(false) -bool(false) -bool(false) -bool(false) -bool(false) -bool(false) diff --git a/ext/posix/tests/posix_ttyname_variation5.phpt b/ext/posix/tests/posix_ttyname_variation5.phpt deleted file mode 100644 index b5290ed2c8fc3..0000000000000 --- a/ext/posix/tests/posix_ttyname_variation5.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -Test function posix_ttyname() by substituting argument 1 with int values. ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---EXTENSIONS-- -posix ---FILE-- - 12345, - 'int -12345' => -2345, - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_ttyname( $var ) ); -} -?> ---EXPECT-- -*** Test substituting argument 1 with int values *** -bool(false) -bool(false) diff --git a/ext/posix/tests/posix_ttyname_variation6.phpt b/ext/posix/tests/posix_ttyname_variation6.phpt deleted file mode 100644 index 9ecf5ca41516c..0000000000000 --- a/ext/posix/tests/posix_ttyname_variation6.phpt +++ /dev/null @@ -1,43 +0,0 @@ ---TEST-- -Test function posix_ttyname() by substituting argument 1 with object values. ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---EXTENSIONS-- -posix ---FILE-- - new classWithToString(), - 'instance of classWithoutToString' => new classWithoutToString(), - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_ttyname( $var ) ); -} -?> ---EXPECTF-- -*** Test substituting argument 1 with object values *** - -Warning: Object of class classWithToString could not be converted to int in %s on line %d -bool(false) - -Warning: Object of class classWithoutToString could not be converted to int in %s on line %d -bool(false) diff --git a/ext/posix/tests/posix_ttyname_variation7.phpt b/ext/posix/tests/posix_ttyname_variation7.phpt deleted file mode 100644 index a955bba182f77..0000000000000 --- a/ext/posix/tests/posix_ttyname_variation7.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -Test function posix_ttyname() by substituting argument 1 with string values. ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---EXTENSIONS-- -posix ---FILE-- - "string", - 'string SQ' => 'string', - 'mixed case string' => "sTrInG", - 'heredoc' => $heredoc, - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_ttyname( $var ) ); -} -?> ---EXPECT-- -*** Test substituting argument 1 with string values *** -bool(false) -bool(false) -bool(false) -bool(false) diff --git a/ext/pspell/tests/003.phpt b/ext/pspell/tests/003.phpt index 02d66f6309f16..2629a64ea056c 100644 --- a/ext/pspell/tests/003.phpt +++ b/ext/pspell/tests/003.phpt @@ -35,7 +35,7 @@ var_dump(pspell_config_ignore($cfg, PHP_INT_MAX)); bool(false) Warning: pspell_new_config(): PSPELL couldn't open the dictionary. reason: The encoding "b0rked" is not known. This could also mean that the file "%sb0rked.%s" could not be opened for reading or does not exist. in %s003.php on line 9 -pspell_check(): Argument #1 ($dictionary) must be of type PSpell\Dictionary, bool given +pspell_check(): Argument #1 ($dictionary) must be of type PSpell\Dictionary, false given --- bool(true) bool(true) diff --git a/ext/pspell/tests/005.phpt b/ext/pspell/tests/005.phpt index ac8ee78e95d51..ab577dbe696f7 100644 --- a/ext/pspell/tests/005.phpt +++ b/ext/pspell/tests/005.phpt @@ -5,7 +5,7 @@ pspell --SKIPIF-- --FILE-- | + | Go Kudo | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "php.h" + +#include "Zend/zend_exceptions.h" + +#include "php_random.h" + +#if HAVE_UNISTD_H +# include +#endif + +#ifdef PHP_WIN32 +# include "win32/time.h" +# include "win32/winutil.h" +# include +#endif + +#ifdef __linux__ +# include +#endif + +#if HAVE_SYS_PARAM_H +# include +# if (__FreeBSD__ && __FreeBSD_version > 1200000) || (__DragonFly__ && __DragonFly_version >= 500700) || \ + defined(__sun) || (defined(__NetBSD__) && __NetBSD_Version__ >= 1000000000) +# include +# endif +#endif + +#if HAVE_COMMONCRYPTO_COMMONRANDOM_H +# include +# include +#endif + +#if __has_feature(memory_sanitizer) +# include +#endif + +PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw) +{ +#ifdef PHP_WIN32 + /* Defer to CryptGenRandom on Windows */ + if (php_win32_get_random_bytes(bytes, size) == FAILURE) { + if (should_throw) { + zend_throw_exception(random_ce_Random_RandomException, "Failed to retrieve randomness from the operating system (BCryptGenRandom)", 0); + } + return FAILURE; + } +#elif HAVE_COMMONCRYPTO_COMMONRANDOM_H + /* + * Purposely prioritized upon arc4random_buf for modern macOs releases + * arc4random api on this platform uses `ccrng_generate` which returns + * a status but silented to respect the "no fail" arc4random api interface + * the vast majority of the time, it works fine ; but better make sure we catch failures + */ + if (CCRandomGenerateBytes(bytes, size) != kCCSuccess) { + if (should_throw) { + zend_throw_exception(random_ce_Random_RandomException, "Failed to retrieve randomness from the operating system (CCRandomGenerateBytes)", 0); + } + return FAILURE; + } +#elif HAVE_DECL_ARC4RANDOM_BUF && ((defined(__OpenBSD__) && OpenBSD >= 201405) || (defined(__NetBSD__) && __NetBSD_Version__ >= 700000001 && __NetBSD_Version__ < 1000000000) || \ + defined(__APPLE__)) + /* + * OpenBSD until there is a valid equivalent + * or NetBSD before the 10.x release + * falls back to arc4random_buf + * giving a decent output, the main benefit + * is being (relatively) failsafe. + * Older macOs releases fall also into this + * category for reasons explained above. + */ + arc4random_buf(bytes, size); +#else + size_t read_bytes = 0; +# if (defined(__linux__) && defined(SYS_getrandom)) || (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || (defined(__DragonFly__) && __DragonFly_version >= 500700) || \ + defined(__sun) || (defined(__NetBSD__) && __NetBSD_Version__ >= 1000000000) + /* Linux getrandom(2) syscall or FreeBSD/DragonFlyBSD/NetBSD getrandom(2) function + * Being a syscall, implemented in the kernel, getrandom offers higher quality output + * compared to the arc4random api albeit a fallback to /dev/urandom is considered. + */ + while (read_bytes < size) { + /* Below, (bytes + read_bytes) is pointer arithmetic. + + bytes read_bytes size + | | | + [#######=============] (we're going to write over the = region) + \\\\\\\\\\\\\ + amount_to_read + */ + size_t amount_to_read = size - read_bytes; + ssize_t n; + + errno = 0; +# if defined(__linux__) + n = syscall(SYS_getrandom, bytes + read_bytes, amount_to_read, 0); +# else + n = getrandom(bytes + read_bytes, amount_to_read, 0); +# endif + + if (n == -1) { + if (errno == ENOSYS) { + /* This can happen if PHP was compiled against a newer kernel where getrandom() + * is available, but then runs on an older kernel without getrandom(). If this + * happens we simply fall back to reading from /dev/urandom. */ + ZEND_ASSERT(read_bytes == 0); + break; + } else if (errno == EINTR || errno == EAGAIN) { + /* Try again */ + continue; + } else { + /* If the syscall fails, fall back to reading from /dev/urandom */ + break; + } + } + +# if __has_feature(memory_sanitizer) + /* MSan does not instrument manual syscall invocations. */ + __msan_unpoison(bytes + read_bytes, n); +# endif + read_bytes += (size_t) n; + } +# endif + if (read_bytes < size) { + int fd = RANDOM_G(random_fd); + struct stat st; + + if (fd < 0) { + errno = 0; + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + if (should_throw) { + if (errno != 0) { + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Cannot open /dev/urandom: %s", strerror(errno)); + } else { + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Cannot open /dev/urandom"); + } + } + return FAILURE; + } + + errno = 0; + /* Does the file exist and is it a character device? */ + if (fstat(fd, &st) != 0 || +# ifdef S_ISNAM + !(S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode)) +# else + !S_ISCHR(st.st_mode) +# endif + ) { + close(fd); + if (should_throw) { + if (errno != 0) { + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Error reading from /dev/urandom: %s", strerror(errno)); + } else { + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Error reading from /dev/urandom"); + } + } + return FAILURE; + } + RANDOM_G(random_fd) = fd; + } + + read_bytes = 0; + while (read_bytes < size) { + errno = 0; + ssize_t n = read(fd, bytes + read_bytes, size - read_bytes); + + if (n <= 0) { + if (should_throw) { + if (errno != 0) { + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Could not gather sufficient random data: %s", strerror(errno)); + } else { + zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Could not gather sufficient random data"); + } + } + return FAILURE; + } + + read_bytes += (size_t) n; + } + } +#endif + + return SUCCESS; +} + +PHPAPI zend_result php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw) +{ + zend_ulong umax; + zend_ulong trial; + + if (min == max) { + *result = min; + return SUCCESS; + } + + umax = (zend_ulong) max - (zend_ulong) min; + + if (php_random_bytes(&trial, sizeof(trial), should_throw) == FAILURE) { + return FAILURE; + } + + /* Special case where no modulus is required */ + if (umax == ZEND_ULONG_MAX) { + *result = (zend_long)trial; + return SUCCESS; + } + + /* Increment the max so the range is inclusive of max */ + umax++; + + /* Powers of two are not biased */ + if ((umax & (umax - 1)) != 0) { + /* Ceiling under which ZEND_LONG_MAX % max == 0 */ + zend_ulong limit = ZEND_ULONG_MAX - (ZEND_ULONG_MAX % umax) - 1; + + /* Discard numbers over the limit to avoid modulo bias */ + while (trial > limit) { + if (php_random_bytes(&trial, sizeof(trial), should_throw) == FAILURE) { + return FAILURE; + } + } + } + + *result = (zend_long)((trial % umax) + min); + return SUCCESS; +} diff --git a/ext/random/gammasection.c b/ext/random/gammasection.c new file mode 100644 index 0000000000000..aa4531fba22f7 --- /dev/null +++ b/ext/random/gammasection.c @@ -0,0 +1,135 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Tim Düsterhus | + | | + | Based on code from: Frédéric Goualard | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_random.h" +#include + +/* This file implements the γ-section algorithm as published in: + * + * Drawing Random Floating-Point Numbers from an Interval. Frédéric + * Goualard, ACM Trans. Model. Comput. Simul., 32:3, 2022. + * https://doi.org/10.1145/3503512 + */ + +static double gamma_low(double x) +{ + return x - nextafter(x, -DBL_MAX); +} + +static double gamma_high(double x) +{ + return nextafter(x, DBL_MAX) - x; +} + +static double gamma_max(double x, double y) +{ + return (fabs(x) > fabs(y)) ? gamma_high(x) : gamma_low(y); +} + +static uint64_t ceilint(double a, double b, double g) +{ + double s = b / g - a / g; + double e; + + if (fabs(a) <= fabs(b)) { + e = -a / g - (s - b / g); + } else { + e = b / g - (s + a / g); + } + + double si = ceil(s); + + return (s != si) ? (uint64_t)si : (uint64_t)si + (e > 0); +} + +PHPAPI double php_random_gammasection_closed_open(const php_random_algo *algo, php_random_status *status, double min, double max) +{ + double g = gamma_max(min, max); + uint64_t hi = ceilint(min, max, g); + + if (UNEXPECTED(max <= min || hi < 1)) { + return NAN; + } + + uint64_t k = 1 + php_random_range64(algo, status, hi - 1); /* [1, hi] */ + + if (fabs(min) <= fabs(max)) { + return k == hi ? min : max - k * g; + } else { + return min + (k - 1) * g; + } +} + +PHPAPI double php_random_gammasection_closed_closed(const php_random_algo *algo, php_random_status *status, double min, double max) +{ + double g = gamma_max(min, max); + uint64_t hi = ceilint(min, max, g); + + if (UNEXPECTED(max < min)) { + return NAN; + } + + uint64_t k = php_random_range64(algo, status, hi); /* [0, hi] */ + + if (fabs(min) <= fabs(max)) { + return k == hi ? min : max - k * g; + } else { + return k == hi ? max : min + k * g; + } +} + +PHPAPI double php_random_gammasection_open_closed(const php_random_algo *algo, php_random_status *status, double min, double max) +{ + double g = gamma_max(min, max); + uint64_t hi = ceilint(min, max, g); + + if (UNEXPECTED(max <= min || hi < 1)) { + return NAN; + } + + uint64_t k = php_random_range64(algo, status, hi - 1); /* [0, hi - 1] */ + + if (fabs(min) <= fabs(max)) { + return max - k * g; + } else { + return k == (hi - 1) ? max : min + (k + 1) * g; + } +} + +PHPAPI double php_random_gammasection_open_open(const php_random_algo *algo, php_random_status *status, double min, double max) +{ + double g = gamma_max(min, max); + uint64_t hi = ceilint(min, max, g); + + if (UNEXPECTED(max <= min || hi < 2)) { + return NAN; + } + + uint64_t k = 1 + php_random_range64(algo, status, hi - 2); /* [1, hi - 1] */ + + if (fabs(min) <= fabs(max)) { + return max - k * g; + } else { + return min + k * g; + } +} diff --git a/ext/random/php_random.h b/ext/random/php_random.h index a4665b5d10aca..c970148912586 100644 --- a/ext/random/php_random.h +++ b/ext/random/php_random.h @@ -31,6 +31,8 @@ #ifndef PHP_RANDOM_H # define PHP_RANDOM_H +# include "php.h" + PHPAPI double php_combined_lcg(void); /* @@ -62,9 +64,9 @@ PHPAPI double php_combined_lcg(void); (__n) = (__min) + (zend_long) ((double) ( (double) (__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0))) # ifdef PHP_WIN32 -# define GENERATE_SEED() (((zend_long) (time(0) * GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg()))) +# define GENERATE_SEED() (((zend_long) ((zend_ulong) time(NULL) * (zend_ulong) GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg()))) # else -# define GENERATE_SEED() (((zend_long) (time(0) * getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg()))) +# define GENERATE_SEED() (((zend_long) ((zend_ulong) time(NULL) * (zend_ulong) getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg()))) # endif # define PHP_MT_RAND_MAX ((zend_long) (0x7FFFFFFF)) /* (1<<31) - 1 */ @@ -193,13 +195,28 @@ static inline uint64_t php_random_pcgoneseq128xslrr64_rotr64(php_random_uint128_ } # endif -# define php_random_bytes_throw(b, s) php_random_bytes((b), (s), 1) -# define php_random_bytes_silent(b, s) php_random_bytes((b), (s), 0) -# define php_random_int_throw(min, max, result) php_random_int((min), (max), (result), 1) -# define php_random_int_silent(min, max, result) php_random_int((min), (max), (result), 0) +PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw); +PHPAPI zend_result php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw); + +static inline zend_result php_random_bytes_throw(void *bytes, size_t size) +{ + return php_random_bytes(bytes, size, true); +} -PHPAPI int php_random_bytes(void *bytes, size_t size, bool should_throw); -PHPAPI int php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw); +static inline zend_result php_random_bytes_silent(void *bytes, size_t size) +{ + return php_random_bytes(bytes, size, false); +} + +static inline zend_result php_random_int_throw(zend_long min, zend_long max, zend_long *result) +{ + return php_random_int(min, max, result, true); +} + +static inline zend_result php_random_int_silent(zend_long min, zend_long max, zend_long *result) +{ + return php_random_int(min, max, result, false); +} typedef struct _php_random_status_ { size_t last_generated_size; @@ -270,8 +287,11 @@ extern PHPAPI zend_class_entry *random_ce_Random_Engine_PcgOneseq128XslRr64; extern PHPAPI zend_class_entry *random_ce_Random_Engine_Mt19937; extern PHPAPI zend_class_entry *random_ce_Random_Engine_Xoshiro256StarStar; extern PHPAPI zend_class_entry *random_ce_Random_Engine_Secure; + extern PHPAPI zend_class_entry *random_ce_Random_Randomizer; +extern PHPAPI zend_class_entry *random_ce_Random_IntervalBoundary; + static inline php_random_engine *php_random_engine_from_obj(zend_object *object) { return (php_random_engine *)((char *)(object) - XtOffsetOf(php_random_engine, std)); } @@ -290,6 +310,8 @@ PHPAPI void php_random_status_free(php_random_status *status, const bool persist PHPAPI php_random_engine *php_random_engine_common_init(zend_class_entry *ce, zend_object_handlers *handlers, const php_random_algo *algo); PHPAPI void php_random_engine_common_free_object(zend_object *object); PHPAPI zend_object *php_random_engine_common_clone_object(zend_object *object); +PHPAPI uint32_t php_random_range32(const php_random_algo *algo, php_random_status *status, uint32_t umax); +PHPAPI uint64_t php_random_range64(const php_random_algo *algo, php_random_status *status, uint64_t umax); PHPAPI zend_long php_random_range(const php_random_algo *algo, php_random_status *status, zend_long min, zend_long max); PHPAPI const php_random_algo *php_random_default_algo(void); PHPAPI php_random_status *php_random_default_status(void); @@ -306,6 +328,11 @@ PHPAPI void php_random_pcgoneseq128xslrr64_advance(php_random_status_state_pcgon PHPAPI void php_random_xoshiro256starstar_jump(php_random_status_state_xoshiro256starstar *state); PHPAPI void php_random_xoshiro256starstar_jump_long(php_random_status_state_xoshiro256starstar *state); +PHPAPI double php_random_gammasection_closed_open(const php_random_algo *algo, php_random_status *status, double min, double max); +PHPAPI double php_random_gammasection_closed_closed(const php_random_algo *algo, php_random_status *status, double min, double max); +PHPAPI double php_random_gammasection_open_closed(const php_random_algo *algo, php_random_status *status, double min, double max); +PHPAPI double php_random_gammasection_open_open(const php_random_algo *algo, php_random_status *status, double min, double max); + extern zend_module_entry random_module_entry; # define phpext_random_ptr &random_module_entry diff --git a/ext/random/random.c b/ext/random/random.c index 5f6ae0c720681..d67b82c0713a7 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -26,6 +26,7 @@ #include "php.h" +#include "Zend/zend_enum.h" #include "Zend/zend_exceptions.h" #include "php_random.h" @@ -42,24 +43,8 @@ # include #endif -#ifdef __linux__ -# include -#endif - #if HAVE_SYS_PARAM_H # include -# if (__FreeBSD__ && __FreeBSD_version > 1200000) || (__DragonFly__ && __DragonFly_version >= 500700) || defined(__sun) -# include -# endif -#endif - -#if HAVE_COMMONCRYPTO_COMMONRANDOM_H -# include -# include -#endif - -#if __has_feature(memory_sanitizer) -# include #endif #include "random_arginfo.h" @@ -76,6 +61,8 @@ PHPAPI zend_class_entry *random_ce_Random_Engine_Secure; PHPAPI zend_class_entry *random_ce_Random_Randomizer; +PHPAPI zend_class_entry *random_ce_Random_IntervalBoundary; + PHPAPI zend_class_entry *random_ce_Random_RandomError; PHPAPI zend_class_entry *random_ce_Random_BrokenRandomEngineError; PHPAPI zend_class_entry *random_ce_Random_RandomException; @@ -86,7 +73,7 @@ static zend_object_handlers random_engine_xoshiro256starstar_object_handlers; static zend_object_handlers random_engine_secure_object_handlers; static zend_object_handlers random_randomizer_object_handlers; -static inline uint32_t rand_range32(const php_random_algo *algo, php_random_status *status, uint32_t umax) +PHPAPI uint32_t php_random_range32(const php_random_algo *algo, php_random_status *status, uint32_t umax) { uint32_t result, limit; size_t total_size = 0; @@ -142,7 +129,7 @@ static inline uint32_t rand_range32(const php_random_algo *algo, php_random_stat return result % umax; } -static inline uint64_t rand_range64(const php_random_algo *algo, php_random_status *status, uint64_t umax) +PHPAPI uint64_t php_random_range64(const php_random_algo *algo, php_random_status *status, uint64_t umax) { uint64_t result, limit; size_t total_size = 0; @@ -231,7 +218,7 @@ static zend_object *php_random_randomizer_new(zend_class_entry *ce) static void randomizer_free_obj(zend_object *object) { php_random_randomizer *randomizer = php_random_randomizer_from_obj(object); - if (randomizer->is_userland_algo && randomizer->status) { + if (randomizer->is_userland_algo) { php_random_status_free(randomizer->status, false); } @@ -258,9 +245,10 @@ PHPAPI php_random_status *php_random_status_copy(const php_random_algo *algo, ph PHPAPI void php_random_status_free(php_random_status *status, const bool persistent) { - if (status->state) { + if (status != NULL) { pefree(status->state, persistent); } + pefree(status, persistent); } @@ -282,10 +270,7 @@ PHPAPI void php_random_engine_common_free_object(zend_object *object) { php_random_engine *engine = php_random_engine_from_obj(object); - if (engine->status) { - php_random_status_free(engine->status, false); - } - + php_random_status_free(engine->status, false); zend_object_std_dtor(object); } @@ -310,10 +295,10 @@ PHPAPI zend_long php_random_range(const php_random_algo *algo, php_random_status zend_ulong umax = (zend_ulong) max - (zend_ulong) min; if (umax > UINT32_MAX) { - return (zend_long) (rand_range64(algo, status, umax) + min); + return (zend_long) (php_random_range64(algo, status, umax) + min); } - return (zend_long) (rand_range32(algo, status, umax) + min); + return (zend_long) (php_random_range32(algo, status, umax) + min); } /* }}} */ @@ -477,190 +462,6 @@ PHPAPI zend_long php_rand(void) } /* }}} */ -/* {{{ php_random_bytes */ -PHPAPI int php_random_bytes(void *bytes, size_t size, bool should_throw) -{ -#ifdef PHP_WIN32 - /* Defer to CryptGenRandom on Windows */ - if (php_win32_get_random_bytes(bytes, size) == FAILURE) { - if (should_throw) { - zend_throw_exception(random_ce_Random_RandomException, "Failed to retrieve randomness from the operating system (BCryptGenRandom)", 0); - } - return FAILURE; - } -#elif HAVE_COMMONCRYPTO_COMMONRANDOM_H - /* - * Purposely prioritized upon arc4random_buf for modern macOs releases - * arc4random api on this platform uses `ccrng_generate` which returns - * a status but silented to respect the "no fail" arc4random api interface - * the vast majority of the time, it works fine ; but better make sure we catch failures - */ - if (CCRandomGenerateBytes(bytes, size) != kCCSuccess) { - if (should_throw) { - zend_throw_exception(random_ce_Random_RandomException, "Failed to retrieve randomness from the operating system (CCRandomGenerateBytes)", 0); - } - return FAILURE; - } -#elif HAVE_DECL_ARC4RANDOM_BUF && ((defined(__OpenBSD__) && OpenBSD >= 201405) || (defined(__NetBSD__) && __NetBSD_Version__ >= 700000001) || defined(__APPLE__) || defined(__GLIBC__)) - arc4random_buf(bytes, size); -#else - size_t read_bytes = 0; - ssize_t n; -# if (defined(__linux__) && defined(SYS_getrandom)) || (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || (defined(__DragonFly__) && __DragonFly_version >= 500700) || defined(__sun) - /* Linux getrandom(2) syscall or FreeBSD/DragonFlyBSD getrandom(2) function*/ - /* Keep reading until we get enough entropy */ - while (read_bytes < size) { - errno = 0; - - /* Below, (bytes + read_bytes) is pointer arithmetic. - - bytes read_bytes size - | | | - [#######=============] (we're going to write over the = region) - \\\\\\\\\\\\\ - amount_to_read - */ - size_t amount_to_read = size - read_bytes; -# if defined(__linux__) - n = syscall(SYS_getrandom, bytes + read_bytes, amount_to_read, 0); -# else - n = getrandom(bytes + read_bytes, amount_to_read, 0); -# endif - - if (n == -1) { - if (errno == ENOSYS) { - /* This can happen if PHP was compiled against a newer kernel where getrandom() - * is available, but then runs on an older kernel without getrandom(). If this - * happens we simply fall back to reading from /dev/urandom. */ - ZEND_ASSERT(read_bytes == 0); - break; - } else if (errno == EINTR || errno == EAGAIN) { - /* Try again */ - continue; - } else { - /* If the syscall fails, fall back to reading from /dev/urandom */ - break; - } - } - -# if __has_feature(memory_sanitizer) - /* MSan does not instrument manual syscall invocations. */ - __msan_unpoison(bytes + read_bytes, n); -# endif - read_bytes += (size_t) n; - } -# endif - if (read_bytes < size) { - int fd = RANDOM_G(random_fd); - struct stat st; - - if (fd < 0) { - errno = 0; -# if HAVE_DEV_URANDOM - fd = open("/dev/urandom", O_RDONLY); -# endif - if (fd < 0) { - if (should_throw) { - if (errno != 0) { - zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Cannot open /dev/urandom: %s", strerror(errno)); - } else { - zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Cannot open /dev/urandom"); - } - } - return FAILURE; - } - - errno = 0; - /* Does the file exist and is it a character device? */ - if (fstat(fd, &st) != 0 || -# ifdef S_ISNAM - !(S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode)) -# else - !S_ISCHR(st.st_mode) -# endif - ) { - close(fd); - if (should_throw) { - if (errno != 0) { - zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Error reading from /dev/urandom: %s", strerror(errno)); - } else { - zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Error reading from /dev/urandom"); - } - } - return FAILURE; - } - RANDOM_G(random_fd) = fd; - } - - for (read_bytes = 0; read_bytes < size; read_bytes += (size_t) n) { - errno = 0; - n = read(fd, bytes + read_bytes, size - read_bytes); - if (n <= 0) { - break; - } - } - - if (read_bytes < size) { - if (should_throw) { - if (errno != 0) { - zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Could not gather sufficient random data: %s", strerror(errno)); - } else { - zend_throw_exception_ex(random_ce_Random_RandomException, 0, "Could not gather sufficient random data"); - } - } - return FAILURE; - } - } -#endif - - return SUCCESS; -} -/* }}} */ - -/* {{{ php_random_int */ -PHPAPI int php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw) -{ - zend_ulong umax; - zend_ulong trial; - - if (min == max) { - *result = min; - return SUCCESS; - } - - umax = (zend_ulong) max - (zend_ulong) min; - - if (php_random_bytes(&trial, sizeof(trial), should_throw) == FAILURE) { - return FAILURE; - } - - /* Special case where no modulus is required */ - if (umax == ZEND_ULONG_MAX) { - *result = (zend_long)trial; - return SUCCESS; - } - - /* Increment the max so the range is inclusive of max */ - umax++; - - /* Powers of two are not biased */ - if ((umax & (umax - 1)) != 0) { - /* Ceiling under which ZEND_LONG_MAX % max == 0 */ - zend_ulong limit = ZEND_ULONG_MAX - (ZEND_ULONG_MAX % umax) - 1; - - /* Discard numbers over the limit to avoid modulo bias */ - while (trial > limit) { - if (php_random_bytes(&trial, sizeof(trial), should_throw) == FAILURE) { - return FAILURE; - } - } - } - - *result = (zend_long)((trial % umax) + min); - return SUCCESS; -} -/* }}} */ - /* {{{ Returns a value from the combined linear congruential generator */ PHP_FUNCTION(lcg_value) { @@ -674,19 +475,20 @@ PHP_FUNCTION(lcg_value) PHP_FUNCTION(mt_srand) { zend_long seed = 0; + bool seed_is_null = true; zend_long mode = MT_RAND_MT19937; php_random_status *status = RANDOM_G(mt19937); php_random_status_state_mt19937 *state = status->state; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL - Z_PARAM_LONG(seed) + Z_PARAM_LONG_OR_NULL(seed, seed_is_null) Z_PARAM_LONG(mode) ZEND_PARSE_PARAMETERS_END(); state->mode = mode; - if (ZEND_NUM_ARGS() == 0) { + if (seed_is_null) { php_random_mt19937_seed_default(status->state); } else { php_random_algo_mt19937.seed(status, (uint64_t) seed); @@ -824,7 +626,7 @@ static PHP_GINIT_FUNCTION(random) /* {{{ PHP_GSHUTDOWN_FUNCTION */ static PHP_GSHUTDOWN_FUNCTION(random) { - if (random_globals->random_fd > 0) { + if (random_globals->random_fd >= 0) { close(random_globals->random_fd); random_globals->random_fd = -1; } @@ -896,6 +698,9 @@ PHP_MINIT_FUNCTION(random) random_randomizer_object_handlers.free_obj = randomizer_free_obj; random_randomizer_object_handlers.clone_obj = NULL; + /* Random\IntervalBoundary */ + random_ce_Random_IntervalBoundary = register_class_Random_IntervalBoundary(); + register_random_symbols(module_number); return SUCCESS; diff --git a/ext/random/random.stub.php b/ext/random/random.stub.php index 69049a837b2c2..d03057d7a6a6e 100644 --- a/ext/random/random.stub.php +++ b/ext/random/random.stub.php @@ -16,10 +16,10 @@ function lcg_value(): float {} - function mt_srand(int $seed = 0, int $mode = MT_RAND_MT19937): void {} + function mt_srand(?int $seed = null, int $mode = MT_RAND_MT19937): void {} /** @alias mt_srand */ - function srand(int $seed = 0, int $mode = MT_RAND_MT19937): void {} + function srand(?int $seed = null, int $mode = MT_RAND_MT19937): void {} function rand(int $min = UNKNOWN, int $max = UNKNOWN): int {} @@ -133,6 +133,10 @@ public function __construct(?Engine $engine = null) {} public function nextInt(): int {} + public function nextFloat(): float {} + + public function getFloat(float $min, float $max, IntervalBoundary $boundary = IntervalBoundary::ClosedOpen): float {} + public function getInt(int $min, int $max): int {} public function getBytes(int $length): string {} @@ -150,6 +154,13 @@ public function __serialize(): array {} public function __unserialize(array $data): void {} } + enum IntervalBoundary { + case ClosedOpen; + case ClosedClosed; + case OpenClosed; + case OpenOpen; + } + /** * @strict-properties */ diff --git a/ext/random/random_arginfo.h b/ext/random/random_arginfo.h index 1da1b8576b196..967dd2d2eb290 100644 --- a/ext/random/random_arginfo.h +++ b/ext/random/random_arginfo.h @@ -1,11 +1,11 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a4226bc7838eba98c5a935b279f681a7d083c0b2 */ + * Stub hash: 533dc78162cc1e510f7c87971a6350acd43de1ab */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_lcg_value, 0, 0, IS_DOUBLE, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mt_srand, 0, 0, IS_VOID, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, seed, IS_LONG, 0, "0") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, seed, IS_LONG, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "MT_RAND_MT19937") ZEND_END_ARG_INFO() @@ -90,6 +90,14 @@ ZEND_END_ARG_INFO() #define arginfo_class_Random_Randomizer_nextInt arginfo_mt_getrandmax +#define arginfo_class_Random_Randomizer_nextFloat arginfo_lcg_value + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Random_Randomizer_getFloat, 0, 2, IS_DOUBLE, 0) + ZEND_ARG_TYPE_INFO(0, min, IS_DOUBLE, 0) + ZEND_ARG_TYPE_INFO(0, max, IS_DOUBLE, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, boundary, Random\\IntervalBoundary, 0, "Random\\IntervalBoundary::ClosedOpen") +ZEND_END_ARG_INFO() + #define arginfo_class_Random_Randomizer_getInt arginfo_random_int #define arginfo_class_Random_Randomizer_getBytes arginfo_random_bytes @@ -136,6 +144,8 @@ ZEND_METHOD(Random_Engine_Xoshiro256StarStar, jump); ZEND_METHOD(Random_Engine_Xoshiro256StarStar, jumpLong); ZEND_METHOD(Random_Randomizer, __construct); ZEND_METHOD(Random_Randomizer, nextInt); +ZEND_METHOD(Random_Randomizer, nextFloat); +ZEND_METHOD(Random_Randomizer, getFloat); ZEND_METHOD(Random_Randomizer, getInt); ZEND_METHOD(Random_Randomizer, getBytes); ZEND_METHOD(Random_Randomizer, getBytesFromString); @@ -213,6 +223,8 @@ static const zend_function_entry class_Random_CryptoSafeEngine_methods[] = { static const zend_function_entry class_Random_Randomizer_methods[] = { ZEND_ME(Random_Randomizer, __construct, arginfo_class_Random_Randomizer___construct, ZEND_ACC_PUBLIC) ZEND_ME(Random_Randomizer, nextInt, arginfo_class_Random_Randomizer_nextInt, ZEND_ACC_PUBLIC) + ZEND_ME(Random_Randomizer, nextFloat, arginfo_class_Random_Randomizer_nextFloat, ZEND_ACC_PUBLIC) + ZEND_ME(Random_Randomizer, getFloat, arginfo_class_Random_Randomizer_getFloat, ZEND_ACC_PUBLIC) ZEND_ME(Random_Randomizer, getInt, arginfo_class_Random_Randomizer_getInt, ZEND_ACC_PUBLIC) ZEND_ME(Random_Randomizer, getBytes, arginfo_class_Random_Randomizer_getBytes, ZEND_ACC_PUBLIC) ZEND_ME(Random_Randomizer, getBytesFromString, arginfo_class_Random_Randomizer_getBytesFromString, ZEND_ACC_PUBLIC) @@ -225,6 +237,11 @@ static const zend_function_entry class_Random_Randomizer_methods[] = { }; +static const zend_function_entry class_Random_IntervalBoundary_methods[] = { + ZEND_FE_END +}; + + static const zend_function_entry class_Random_RandomError_methods[] = { ZEND_FE_END }; @@ -332,6 +349,21 @@ static zend_class_entry *register_class_Random_Randomizer(void) return class_entry; } +static zend_class_entry *register_class_Random_IntervalBoundary(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("Random\\IntervalBoundary", IS_UNDEF, class_Random_IntervalBoundary_methods); + + zend_enum_add_case_cstr(class_entry, "ClosedOpen", NULL); + + zend_enum_add_case_cstr(class_entry, "ClosedClosed", NULL); + + zend_enum_add_case_cstr(class_entry, "OpenClosed", NULL); + + zend_enum_add_case_cstr(class_entry, "OpenOpen", NULL); + + return class_entry; +} + static zend_class_entry *register_class_Random_RandomError(zend_class_entry *class_entry_Error) { zend_class_entry ce, *class_entry; diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index a95e6b0fdd8a8..fe9ad5fc35a9c 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -24,6 +24,7 @@ #include "ext/standard/php_array.h" #include "ext/standard/php_string.h" +#include "Zend/zend_enum.h" #include "Zend/zend_exceptions.h" static inline void randomizer_common_init(php_random_randomizer *randomizer, zend_object *engine_object) { @@ -41,7 +42,7 @@ static inline void randomizer_common_init(php_random_randomizer *randomizer, zen zend_string *mname; zend_function *generate_method; - mname = zend_string_init("generate", strlen("generate"), 0); + mname = ZSTR_INIT_LITERAL("generate", 0); generate_method = zend_hash_find_ptr(&engine_object->ce->function_table, mname); zend_string_release(mname); @@ -88,6 +89,121 @@ PHP_METHOD(Random_Randomizer, __construct) } /* }}} */ +/* {{{ Generate a float in [0, 1) */ +PHP_METHOD(Random_Randomizer, nextFloat) +{ + php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS); + uint64_t result; + size_t total_size; + + ZEND_PARSE_PARAMETERS_NONE(); + + result = 0; + total_size = 0; + do { + uint64_t r = randomizer->algo->generate(randomizer->status); + result = result | (r << (total_size * 8)); + total_size += randomizer->status->last_generated_size; + if (EG(exception)) { + RETURN_THROWS(); + } + } while (total_size < sizeof(uint64_t)); + + /* A double has 53 bits of precision, thus we must not + * use the full 64 bits of the uint64_t, because we would + * introduce a bias / rounding error. + */ +#if DBL_MANT_DIG != 53 +# error "Random_Randomizer::nextFloat(): Requires DBL_MANT_DIG == 53 to work." +#endif + const double step_size = 1.0 / (1ULL << 53); + + /* Use the upper 53 bits, because some engine's lower bits + * are of lower quality. + */ + result = (result >> 11); + + RETURN_DOUBLE(step_size * result); +} +/* }}} */ + +/* {{{ Generates a random float within a configurable interval. + * + * This method uses the γ-section algorithm by Frédéric Goualard. + */ +PHP_METHOD(Random_Randomizer, getFloat) +{ + php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS); + double min, max; + zend_object *bounds = NULL; + int bounds_type = 'C' + sizeof("ClosedOpen") - 1; + + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_DOUBLE(min) + Z_PARAM_DOUBLE(max) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS(bounds, random_ce_Random_IntervalBoundary); + ZEND_PARSE_PARAMETERS_END(); + + if (!zend_finite(min)) { + zend_argument_value_error(1, "must be finite"); + RETURN_THROWS(); + } + + if (!zend_finite(max)) { + zend_argument_value_error(2, "must be finite"); + RETURN_THROWS(); + } + + if (bounds) { + zval *case_name = zend_enum_fetch_case_name(bounds); + zend_string *bounds_name = Z_STR_P(case_name); + + bounds_type = ZSTR_VAL(bounds_name)[0] + ZSTR_LEN(bounds_name); + } + + switch (bounds_type) { + case 'C' + sizeof("ClosedOpen") - 1: + if (UNEXPECTED(max <= min)) { + zend_argument_value_error(2, "must be greater than argument #1 ($min)"); + RETURN_THROWS(); + } + + RETURN_DOUBLE(php_random_gammasection_closed_open(randomizer->algo, randomizer->status, min, max)); + case 'C' + sizeof("ClosedClosed") - 1: + if (UNEXPECTED(max < min)) { + zend_argument_value_error(2, "must be greater than or equal to argument #1 ($min)"); + RETURN_THROWS(); + } + + RETURN_DOUBLE(php_random_gammasection_closed_closed(randomizer->algo, randomizer->status, min, max)); + case 'O' + sizeof("OpenClosed") - 1: + if (UNEXPECTED(max <= min)) { + zend_argument_value_error(2, "must be greater than argument #1 ($min)"); + RETURN_THROWS(); + } + + RETURN_DOUBLE(php_random_gammasection_open_closed(randomizer->algo, randomizer->status, min, max)); + case 'O' + sizeof("OpenOpen") - 1: + if (UNEXPECTED(max <= min)) { + zend_argument_value_error(2, "must be greater than argument #1 ($min)"); + RETURN_THROWS(); + } + + RETVAL_DOUBLE(php_random_gammasection_open_open(randomizer->algo, randomizer->status, min, max)); + + if (UNEXPECTED(isnan(Z_DVAL_P(return_value)))) { + zend_value_error("The given interval is empty, there are no floats between argument #1 ($min) and argument #2 ($max)."); + RETURN_THROWS(); + } + + return; + default: + ZEND_UNREACHABLE(); + } +} +/* }}} */ + /* {{{ Generate positive random number */ PHP_METHOD(Random_Randomizer, nextInt) { @@ -272,6 +388,7 @@ PHP_METHOD(Random_Randomizer, getBytesFromString) ZEND_PARSE_PARAMETERS_END(); const size_t source_length = ZSTR_LEN(source); + const size_t max_offset = source_length - 1; if (source_length < 1) { zend_argument_value_error(1, "cannot be empty"); @@ -285,9 +402,9 @@ PHP_METHOD(Random_Randomizer, getBytesFromString) retval = zend_string_alloc(length, 0); - if (source_length > 0xFF) { + if (max_offset > 0xff) { while (total_size < length) { - uint64_t offset = randomizer->algo->range(randomizer->status, 0, source_length - 1); + uint64_t offset = randomizer->algo->range(randomizer->status, 0, max_offset); if (EG(exception)) { zend_string_free(retval); @@ -297,26 +414,14 @@ PHP_METHOD(Random_Randomizer, getBytesFromString) ZSTR_VAL(retval)[total_size++] = ZSTR_VAL(source)[offset]; } } else { - uint64_t mask; - if (source_length <= 0x1) { - mask = 0x0; - } else if (source_length <= 0x2) { - mask = 0x1; - } else if (source_length <= 0x4) { - mask = 0x3; - } else if (source_length <= 0x8) { - mask = 0x7; - } else if (source_length <= 0x10) { - mask = 0xF; - } else if (source_length <= 0x20) { - mask = 0x1F; - } else if (source_length <= 0x40) { - mask = 0x3F; - } else if (source_length <= 0x80) { - mask = 0x7F; - } else { - mask = 0xFF; - } + uint64_t mask = max_offset; + // Copy the top-most bit into all lower bits. + // Shifting by 4 is sufficient, because max_offset + // is guaranteed to fit in an 8-bit integer at this + // point. + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; int failures = 0; while (total_size < length) { @@ -329,7 +434,7 @@ PHP_METHOD(Random_Randomizer, getBytesFromString) for (size_t i = 0; i < randomizer->status->last_generated_size; i++) { uint64_t offset = (result >> (i * 8)) & mask; - if (offset >= source_length) { + if (offset > max_offset) { if (++failures > PHP_RANDOM_RANGE_ATTEMPTS) { zend_string_free(retval); zend_throw_error(random_ce_Random_BrokenRandomEngineError, "Failed to generate an acceptable random number in %d attempts", PHP_RANDOM_RANGE_ATTEMPTS); diff --git a/ext/random/tests/03_randomizer/methods/getBytesFromString_fast_path.phpt b/ext/random/tests/03_randomizer/methods/getBytesFromString_fast_path.phpt new file mode 100644 index 0000000000000..84c8ec611db80 --- /dev/null +++ b/ext/random/tests/03_randomizer/methods/getBytesFromString_fast_path.phpt @@ -0,0 +1,162 @@ +--TEST-- +Random: Randomizer: getBytesFromString(): Fast Path Masking +--FILE-- + chr($byte), + range(0x00, 0xff) +)); + +// Xoshiro256** is the fastest engine available. +$xoshiro = new Xoshiro256StarStar(); + +var_dump(strlen($allBytes)); +echo PHP_EOL; + +// Fast path: Inputs less than or equal to 256. +for ($i = 1; $i <= strlen($allBytes); $i *= 2) { + echo "{$i}:", PHP_EOL; + + $wrapper = new TestWrapperEngine($xoshiro); + $r = new Randomizer($wrapper); + $result = $r->getBytesFromString(substr($allBytes, 0, $i), 20000); + + // Xoshiro256** is a 64 Bit engine and thus generates 8 bytes at once. + // For powers of two we expect no rejections and thus exactly + // 20000/8 = 2500 calls to the engine. + var_dump($wrapper->getCount()); + + $count = []; + for ($j = 0; $j < strlen($result); $j++) { + $b = $result[$j]; + $count[ord($b)] ??= 0; + $count[ord($b)]++; + } + + // We also expect that each possible value appears at least once, if + // not is is very likely that some bits were erroneously masked away. + var_dump(count($count)); + + echo PHP_EOL; +} + +// Test lengths that are one more than the powers of two. For these +// the maximum offset will be a power of two and thus a minimal number +// of bits will be set in the offset. +for ($i = 1; ($i + 1) <= strlen($allBytes); $i *= 2) { + $oneMore = $i + 1; + + echo "{$oneMore}:", PHP_EOL; + + $wrapper = new TestWrapperEngine($xoshiro); + $r = new Randomizer($wrapper); + $result = $r->getBytesFromString(substr($allBytes, 0, $oneMore), 20000); + + $count = []; + for ($j = 0; $j < strlen($result); $j++) { + $b = $result[$j]; + $count[ord($b)] ??= 0; + $count[ord($b)]++; + } + + // We expect that each possible value appears at least once, if + // not is is very likely that some bits were erroneously masked away. + var_dump(count($count)); + + echo PHP_EOL; +} + +echo "Slow Path:", PHP_EOL; + +$wrapper = new TestWrapperEngine($xoshiro); +$r = new Randomizer($wrapper); +$result = $r->getBytesFromString($allBytes . $allBytes, 20000); + +// In the slow path we expect one call per byte, i.e. 20000 +var_dump($wrapper->getCount()); + +$count = []; +for ($j = 0; $j < strlen($result); $j++) { + $b = $result[$j]; + $count[ord($b)] ??= 0; + $count[ord($b)]++; +} + +// We also expect that each possible value appears at least once, if +// not is is very likely that some bits were erroneously masked away. +var_dump(count($count)); + +?> +--EXPECT-- +int(256) + +1: +int(2500) +int(1) + +2: +int(2500) +int(2) + +4: +int(2500) +int(4) + +8: +int(2500) +int(8) + +16: +int(2500) +int(16) + +32: +int(2500) +int(32) + +64: +int(2500) +int(64) + +128: +int(2500) +int(128) + +256: +int(2500) +int(256) + +2: +int(2) + +3: +int(3) + +5: +int(5) + +9: +int(9) + +17: +int(17) + +33: +int(33) + +65: +int(65) + +129: +int(129) + +Slow Path: +int(20000) +int(256) diff --git a/ext/random/tests/03_randomizer/methods/getFloat.phpt b/ext/random/tests/03_randomizer/methods/getFloat.phpt new file mode 100644 index 0000000000000..1fcec7f3e223a --- /dev/null +++ b/ext/random/tests/03_randomizer/methods/getFloat.phpt @@ -0,0 +1,50 @@ +--TEST-- +Random: Randomizer: getFloat(): Basic functionality +--FILE-- +getFloat(-$i, $i, IntervalBoundary::ClosedClosed); + + if ($result > $i || $result < -$i) { + die("failure: out of range at {$i}"); + } + } +} + +die('success'); + +?> +--EXPECT-- +Random\Engine\Mt19937 +Random\Engine\Mt19937 +Random\Engine\PcgOneseq128XslRr64 +Random\Engine\Xoshiro256StarStar +Random\Engine\Secure +Random\Engine\Test\TestShaEngine +success diff --git a/ext/random/tests/03_randomizer/methods/getFloat_error.phpt b/ext/random/tests/03_randomizer/methods/getFloat_error.phpt new file mode 100644 index 0000000000000..286435e1752fb --- /dev/null +++ b/ext/random/tests/03_randomizer/methods/getFloat_error.phpt @@ -0,0 +1,130 @@ +--TEST-- +Random: Randomizer: getFloat(): Parameters are correctly validated +--FILE-- +name, PHP_EOL; + + try { + var_dump(randomizer()->getFloat(NAN, 0.0, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + var_dump(randomizer()->getFloat(INF, 0.0, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + var_dump(randomizer()->getFloat(-INF, 0.0, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + var_dump(randomizer()->getFloat(0.0, NAN, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + var_dump(randomizer()->getFloat(0.0, INF, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + var_dump(randomizer()->getFloat(0.0, -INF, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + var_dump(randomizer()->getFloat(0.0, -0.1, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + var_dump(randomizer()->getFloat(0.0, 0.0, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + // Both values round to the same float. + var_dump(randomizer()->getFloat(100_000_000_000_000_000.0, 100_000_000_000_000_000.1, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } + + try { + // There is no float between the two parameters, thus making the OpenOpen interval empty. + var_dump(randomizer()->getFloat(1.0, 1 + PHP_FLOAT_EPSILON, $boundary)); + } catch (ValueError $e) { + echo $e->getMessage(), PHP_EOL; + } +} + +?> +--EXPECTF-- +ClosedClosed +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than or equal to argument #1 ($min) +float(0) +float(1.0E+17) +float(%f) +ClosedOpen +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +float(1) +OpenClosed +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +float(1.0000000000000002) +OpenOpen +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #1 ($min) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be finite +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +Random\Randomizer::getFloat(): Argument #2 ($max) must be greater than argument #1 ($min) +The given interval is empty, there are no floats between argument #1 ($min) and argument #2 ($max). diff --git a/ext/random/tests/03_randomizer/methods/nextFloat.phpt b/ext/random/tests/03_randomizer/methods/nextFloat.phpt new file mode 100644 index 0000000000000..4a583d00e78d9 --- /dev/null +++ b/ext/random/tests/03_randomizer/methods/nextFloat.phpt @@ -0,0 +1,49 @@ +--TEST-- +Random: Randomizer: nextFloat(): Basic functionality +--FILE-- +nextFloat(); + + if ($result >= 1 || $result < 0) { + die("failure: out of range at {$i}"); + } + } +} + +die('success'); + +?> +--EXPECT-- +Random\Engine\Mt19937 +Random\Engine\Mt19937 +Random\Engine\PcgOneseq128XslRr64 +Random\Engine\Xoshiro256StarStar +Random\Engine\Secure +Random\Engine\Test\TestShaEngine +success diff --git a/ext/random/tests/engines.inc b/ext/random/tests/engines.inc index 909f581d775a1..73b070b0c7f57 100644 --- a/ext/random/tests/engines.inc +++ b/ext/random/tests/engines.inc @@ -27,14 +27,23 @@ final class TestShaEngine implements Engine final class TestWrapperEngine implements Engine { + private int $count = 0; + public function __construct(private readonly Engine $engine) { } public function generate(): string { + $this->count++; + return $this->engine->generate(); } + + public function getCount(): int + { + return $this->count; + } } final class TestXoshiro128PlusPlusEngine implements Engine diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 186a240b4a01e..2f8acbfb00852 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -297,7 +297,7 @@ static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{ static void _const_string(smart_str *str, char *name, zval *value, char *indent); static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent); static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent); -static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char* indent); +static void _class_const_string(smart_str *str, zend_string *name, zend_class_constant *c, char* indent); static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent); static void _extension_string(smart_str *str, zend_module_entry *module, char *indent); static void _zend_extension_string(smart_str *str, zend_extension *extension, char *indent); @@ -384,7 +384,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char zend_class_constant *c; ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, c) { - _class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent)); + _class_const_string(str, key, c, ZSTR_VAL(sub_indent)); if (UNEXPECTED(EG(exception))) { zend_string_release(sub_indent); return; @@ -556,17 +556,18 @@ static void _const_string(smart_str *str, char *name, zval *value, char *indent) /* }}} */ /* {{{ _class_const_string */ -static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char *indent) +static void _class_const_string(smart_str *str, zend_string *name, zend_class_constant *c, char *indent) { - if (zval_update_constant_ex(&c->value, c->ce) == FAILURE) { + if (Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, name, c->ce) == FAILURE) { return; } const char *visibility = zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)); const char *final = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_FINAL ? "final " : ""; - const char *type = zend_zval_type_name(&c->value); + zend_string *type_str = ZEND_TYPE_IS_SET(c->type) ? zend_type_to_string(c->type) : NULL; + const char *type = type_str ? ZSTR_VAL(type_str) : zend_zval_type_name(&c->value); smart_str_append_printf(str, "%sConstant [ %s%s %s %s ] { ", - indent, final, visibility, type, name); + indent, final, visibility, type, ZSTR_VAL(name)); if (Z_TYPE(c->value) == IS_ARRAY) { smart_str_appends(str, "Array"); } else if (Z_TYPE(c->value) == IS_OBJECT) { @@ -578,6 +579,10 @@ static void _class_const_string(smart_str *str, char *name, zend_class_constant zend_tmp_string_release(tmp_value_str); } smart_str_appends(str, " }\n"); + + if (type_str) { + zend_string_release(type_str); + } } /* }}} */ @@ -1040,11 +1045,13 @@ static void _extension_string(smart_str *str, zend_module_entry *module, char *i { smart_str str_constants = {0}; zend_constant *constant; + zend_string *name; int num_constants = 0; - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) { + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(zend_constants), name, constant) { + if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) { - _const_string(&str_constants, ZSTR_VAL(constant->name), &constant->value, indent); + _const_string(&str_constants, ZSTR_VAL(name), &constant->value, indent); num_constants++; } } ZEND_HASH_FOREACH_END(); @@ -1752,6 +1759,9 @@ ZEND_METHOD(ReflectionFunctionAbstract, getClosureUsedVariables) } zend_op *opline = ops->opcodes + ops->num_args; + if (ops->fn_flags & ZEND_ACC_VARIADIC) { + opline++; + } for (; opline->opcode == ZEND_BIND_STATIC; opline++) { if (!(opline->extended_value & (ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))) { @@ -1973,9 +1983,8 @@ ZEND_METHOD(ReflectionFunction, invoke) { zval retval; zval *params; - int result, num_args; + uint32_t num_args; HashTable *named_params; - zend_fcall_info fci; zend_fcall_info_cache fcc; reflection_object *intern; zend_function *fptr; @@ -1986,14 +1995,6 @@ ZEND_METHOD(ReflectionFunction, invoke) GET_REFLECTION_OBJECT_PTR(fptr); - fci.size = sizeof(fci); - ZVAL_UNDEF(&fci.function_name); - fci.object = NULL; - fci.retval = &retval; - fci.param_count = num_args; - fci.params = params; - fci.named_params = named_params; - fcc.function_handler = fptr; fcc.called_scope = NULL; fcc.object = NULL; @@ -2003,20 +2004,18 @@ ZEND_METHOD(ReflectionFunction, invoke) Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object, 0); } - result = zend_call_function(&fci, &fcc); + zend_call_known_fcc(&fcc, &retval, num_args, params, named_params); - if (result == FAILURE) { + if (Z_TYPE(retval) == IS_UNDEF && !EG(exception)) { zend_throw_exception_ex(reflection_exception_ptr, 0, "Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name)); RETURN_THROWS(); } - if (Z_TYPE(retval) != IS_UNDEF) { - if (Z_ISREF(retval)) { - zend_unwrap_reference(&retval); - } - ZVAL_COPY_VALUE(return_value, &retval); + if (Z_ISREF(retval)) { + zend_unwrap_reference(&retval); } + ZVAL_COPY_VALUE(return_value, &retval); } /* }}} */ @@ -2024,8 +2023,6 @@ ZEND_METHOD(ReflectionFunction, invoke) ZEND_METHOD(ReflectionFunction, invokeArgs) { zval retval; - int result; - zend_fcall_info fci; zend_fcall_info_cache fcc; reflection_object *intern; zend_function *fptr; @@ -2037,14 +2034,6 @@ ZEND_METHOD(ReflectionFunction, invokeArgs) GET_REFLECTION_OBJECT_PTR(fptr); - fci.size = sizeof(fci); - ZVAL_UNDEF(&fci.function_name); - fci.object = NULL; - fci.retval = &retval; - fci.param_count = 0; - fci.params = NULL; - fci.named_params = params; - fcc.function_handler = fptr; fcc.called_scope = NULL; fcc.object = NULL; @@ -2054,20 +2043,18 @@ ZEND_METHOD(ReflectionFunction, invokeArgs) Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object, 0); } - result = zend_call_function(&fci, &fcc); + zend_call_known_fcc(&fcc, &retval, /* num_params */ 0, /* params */ NULL, params); - if (result == FAILURE) { + if (Z_TYPE(retval) == IS_UNDEF && !EG(exception)) { zend_throw_exception_ex(reflection_exception_ptr, 0, "Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name)); RETURN_THROWS(); } - if (Z_TYPE(retval) != IS_UNDEF) { - if (Z_ISREF(retval)) { - zend_unwrap_reference(&retval); - } - ZVAL_COPY_VALUE(return_value, &retval); + if (Z_ISREF(retval)) { + zend_unwrap_reference(&retval); } + ZVAL_COPY_VALUE(return_value, &retval); } /* }}} */ @@ -2493,7 +2480,7 @@ ZEND_METHOD(ReflectionParameter, __construct) break; default: - zend_argument_error(reflection_exception_ptr, 1, "must be a string, an array(class, method), or a callable object, %s given", zend_zval_type_name(reference)); + zend_argument_error(reflection_exception_ptr, 1, "must be a string, an array(class, method), or a callable object, %s given", zend_zval_value_name(reference)); RETURN_THROWS(); } @@ -3360,10 +3347,8 @@ static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic) zval *params = NULL, *object; HashTable *named_params = NULL; reflection_object *intern; - zend_function *mptr; - int argc = 0, result; - zend_fcall_info fci; - zend_fcall_info_cache fcc; + zend_function *mptr, *callback; + uint32_t argc = 0; zend_class_entry *obj_ce; GET_REFLECTION_OBJECT_PTR(mptr); @@ -3413,40 +3398,20 @@ static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic) RETURN_THROWS(); } } + /* Copy the zend_function when calling via handler (e.g. Closure::__invoke()) */ + callback = _copy_function(mptr); + zend_call_known_function(callback, (object ? Z_OBJ_P(object) : NULL), intern->ce, &retval, argc, params, named_params); - fci.size = sizeof(fci); - ZVAL_UNDEF(&fci.function_name); - fci.object = object ? Z_OBJ_P(object) : NULL; - fci.retval = &retval; - fci.param_count = argc; - fci.params = params; - fci.named_params = named_params; - - fcc.function_handler = mptr; - fcc.called_scope = intern->ce; - fcc.object = object ? Z_OBJ_P(object) : NULL; - - /* - * Copy the zend_function when calling via handler (e.g. Closure::__invoke()) - */ - if ((mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - fcc.function_handler = _copy_function(mptr); - } - - result = zend_call_function(&fci, &fcc); - - if (result == FAILURE) { + if (Z_TYPE(retval) == IS_UNDEF && !EG(exception)) { zend_throw_exception_ex(reflection_exception_ptr, 0, "Invocation of method %s::%s() failed", ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name)); RETURN_THROWS(); } - if (Z_TYPE(retval) != IS_UNDEF) { - if (Z_ISREF(retval)) { - zend_unwrap_reference(&retval); - } - ZVAL_COPY_VALUE(return_value, &retval); + if (Z_ISREF(retval)) { + zend_unwrap_reference(&retval); } + ZVAL_COPY_VALUE(return_value, &retval); } /* }}} */ @@ -3541,7 +3506,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, inNamespace) zend_string *name = fptr->common.function_name; const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - RETURN_BOOL(backslash && backslash > ZSTR_VAL(name)); + RETURN_BOOL(backslash); } /* }}} */ @@ -3559,7 +3524,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName) zend_string *name = fptr->common.function_name; const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - if (backslash && backslash > ZSTR_VAL(name)) { + if (backslash) { RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name)); } RETURN_EMPTY_STRING(); @@ -3580,7 +3545,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getShortName) zend_string *name = fptr->common.function_name; const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - if (backslash && backslash > ZSTR_VAL(name)) { + if (backslash) { RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1)); } RETURN_STR_COPY(name); @@ -3836,7 +3801,7 @@ ZEND_METHOD(ReflectionClassConstant, __toString) ZVAL_DEREF(name); ZEND_ASSERT(Z_TYPE_P(name) == IS_STRING); - _class_const_string(&str, Z_STRVAL_P(name), ref, ""); + _class_const_string(&str, Z_STR_P(name), ref, ""); RETURN_STR(smart_str_extract(&str)); } /* }}} */ @@ -3860,6 +3825,39 @@ ZEND_METHOD(ReflectionClassConstant, getName) } /* }}} */ +/* Returns the type associated with the class constant */ +ZEND_METHOD(ReflectionClassConstant, getType) +{ + reflection_object *intern; + zend_class_constant *ref; + + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } + + GET_REFLECTION_OBJECT_PTR(ref); + + if (!ZEND_TYPE_IS_SET(ref->type)) { + RETURN_NULL(); + } + + reflection_type_factory(ref->type, return_value, 1); +} + +/* Returns whether class constant has a type */ +ZEND_METHOD(ReflectionClassConstant, hasType) +{ + reflection_object *intern; + zend_class_constant *ref; + + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } + + GET_REFLECTION_OBJECT_PTR(ref); + RETVAL_BOOL(ZEND_TYPE_IS_SET(ref->type)); +} + static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */ { reflection_object *intern; @@ -3927,8 +3925,19 @@ ZEND_METHOD(ReflectionClassConstant, getValue) } GET_REFLECTION_OBJECT_PTR(ref); + zval *name = reflection_prop_name(ZEND_THIS); + if (Z_ISUNDEF_P(name)) { + zend_throw_error(NULL, + "Typed property ReflectionClassConstant::$name " + "must not be accessed before initialization"); + RETURN_THROWS(); + } + if (Z_TYPE(ref->value) == IS_CONSTANT_AST) { - zval_update_constant_ex(&ref->value, ref->ce); + zend_result result = zend_update_class_constant(ref, Z_STR_P(name), ref->ce); + if (result == FAILURE) { + RETURN_THROWS(); + } } ZVAL_COPY_OR_DUP(return_value, &ref->value); } @@ -4684,7 +4693,7 @@ ZEND_METHOD(ReflectionClass, getProperties) if (Z_TYPE(intern->obj) != IS_UNDEF && (filter & ZEND_ACC_PUBLIC) != 0) { HashTable *properties = Z_OBJ_HT(intern->obj)->get_properties(Z_OBJ(intern->obj)); zval *prop; - ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(properties, key, prop) { + ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) { _adddynproperty(prop, key, ce, return_value); } ZEND_HASH_FOREACH_END(); } @@ -4734,7 +4743,7 @@ ZEND_METHOD(ReflectionClass, getConstants) array_init(return_value); ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, constant) { - if (UNEXPECTED(zval_update_constant_ex(&constant->value, constant->ce) != SUCCESS)) { + if (UNEXPECTED(Z_TYPE(constant->value) == IS_CONSTANT_AST && zend_update_class_constant(constant, key, constant->ce) != SUCCESS)) { RETURN_THROWS(); } @@ -4784,7 +4793,7 @@ ZEND_METHOD(ReflectionClass, getConstant) zend_class_entry *ce; HashTable *constants_table; zend_class_constant *c; - zend_string *name; + zend_string *name, *key; if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) { RETURN_THROWS(); @@ -4792,8 +4801,8 @@ ZEND_METHOD(ReflectionClass, getConstant) GET_REFLECTION_OBJECT_PTR(ce); constants_table = CE_CONSTANTS_TABLE(ce); - ZEND_HASH_MAP_FOREACH_PTR(constants_table, c) { - if (UNEXPECTED(zval_update_constant_ex(&c->value, c->ce) != SUCCESS)) { + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(constants_table, key, c) { + if (UNEXPECTED(Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, key, c->ce) != SUCCESS)) { RETURN_THROWS(); } } ZEND_HASH_FOREACH_END(); @@ -5408,7 +5417,7 @@ ZEND_METHOD(ReflectionClass, inNamespace) zend_string *name = ce->name; const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - RETURN_BOOL(backslash && backslash > ZSTR_VAL(name)); + RETURN_BOOL(backslash); } /* }}} */ @@ -5426,7 +5435,7 @@ ZEND_METHOD(ReflectionClass, getNamespaceName) zend_string *name = ce->name; const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - if (backslash && backslash > ZSTR_VAL(name)) { + if (backslash) { RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name)); } RETURN_EMPTY_STRING(); @@ -5447,7 +5456,7 @@ ZEND_METHOD(ReflectionClass, getShortName) zend_string *name = ce->name; const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - if (backslash && backslash > ZSTR_VAL(name)) { + if (backslash) { RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1)); } RETURN_STR_COPY(name); @@ -5712,7 +5721,7 @@ ZEND_METHOD(ReflectionProperty, setValue) } /* }}} */ -/* {{{ Returns this property's value */ +/* {{{ Returns true if property was initialized */ ZEND_METHOD(ReflectionProperty, isInitialized) { reflection_object *intern; @@ -6034,6 +6043,7 @@ ZEND_METHOD(ReflectionExtension, getConstants) reflection_object *intern; zend_module_entry *module; zend_constant *constant; + zend_string *name; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -6041,11 +6051,11 @@ ZEND_METHOD(ReflectionExtension, getConstants) GET_REFLECTION_OBJECT_PTR(module); array_init(return_value); - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) { + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(zend_constants), name, constant) { if (module->module_number == ZEND_CONSTANT_MODULE_NUMBER(constant)) { zval const_val; ZVAL_COPY_OR_DUP(&const_val, &constant->value); - zend_hash_update(Z_ARRVAL_P(return_value), constant->name, &const_val); + zend_hash_update(Z_ARRVAL_P(return_value), name, &const_val); } } ZEND_HASH_FOREACH_END(); } @@ -6544,7 +6554,7 @@ ZEND_METHOD(ReflectionAttribute, __toString) } /* }}} */ -/* {{{ * Returns the name of the attribute */ +/* {{{ Returns the name of the attribute */ ZEND_METHOD(ReflectionAttribute, getName) { reflection_object *intern; @@ -6559,7 +6569,7 @@ ZEND_METHOD(ReflectionAttribute, getName) } /* }}} */ -/* {{{ * Returns the target of the attribute */ +/* {{{ Returns the target of the attribute */ ZEND_METHOD(ReflectionAttribute, getTarget) { reflection_object *intern; @@ -6574,7 +6584,7 @@ ZEND_METHOD(ReflectionAttribute, getTarget) } /* }}} */ -/* {{{ * Returns true if the attribute is repeated */ +/* {{{ Returns true if the attribute is repeated */ ZEND_METHOD(ReflectionAttribute, isRepeated) { reflection_object *intern; @@ -6589,7 +6599,7 @@ ZEND_METHOD(ReflectionAttribute, isRepeated) } /* }}} */ -/* {{{ * Returns the arguments passed to the attribute */ +/* {{{ Returns the arguments passed to the attribute */ ZEND_METHOD(ReflectionAttribute, getArguments) { reflection_object *intern; @@ -6706,7 +6716,7 @@ static void attribute_ctor_cleanup( } /* }}} */ -/* {{{ * Returns the attribute as an object */ +/* {{{ Returns the attribute as an object */ ZEND_METHOD(ReflectionAttribute, newInstance) { reflection_object *intern; @@ -6993,7 +7003,7 @@ ZEND_METHOD(ReflectionEnumBackedCase, getBackingValue) if (Z_TYPE(ref->value) == IS_CONSTANT_AST) { zval_update_constant_ex(&ref->value, ref->ce); if (EG(exception)) { - return; + RETURN_THROWS(); } } @@ -7082,7 +7092,13 @@ ZEND_METHOD(ReflectionFiber, getExecutingLine) prev_execute_data = fiber->execute_data->prev_execute_data; } - RETURN_LONG(prev_execute_data->opline->lineno); + while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) { + prev_execute_data = prev_execute_data->prev_execute_data; + } + if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) { + RETURN_LONG(prev_execute_data->opline->lineno); + } + RETURN_NULL(); } ZEND_METHOD(ReflectionFiber, getExecutingFile) @@ -7100,7 +7116,13 @@ ZEND_METHOD(ReflectionFiber, getExecutingFile) prev_execute_data = fiber->execute_data->prev_execute_data; } - RETURN_STR_COPY(prev_execute_data->func->op_array.filename); + while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) { + prev_execute_data = prev_execute_data->prev_execute_data; + } + if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) { + RETURN_STR_COPY(prev_execute_data->func->op_array.filename); + } + RETURN_NULL(); } ZEND_METHOD(ReflectionFiber, getCallable) diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 22223bb0a1c3f..de0d83d244a85 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -346,7 +346,7 @@ public function getConstants(?int $filter = null): array {} public function getReflectionConstants(?int $filter = null): array {} /** @tentative-return-type */ - public function getConstant(string $name): mixed {} + public function getConstant(string $name): mixed {} // TODO throw exception when the constant doesn't exist /** @tentative-return-type */ public function getReflectionConstant(string $name): ReflectionClassConstant|false {} @@ -404,7 +404,7 @@ public function getParentClass(): ReflectionClass|false {} public function isSubclassOf(ReflectionClass|string $class): bool {} /** @tentative-return-type */ - public function getStaticProperties(): ?array {} + public function getStaticProperties(): array {} /** @tentative-return-type */ public function getStaticPropertyValue(string $name, mixed $default = UNKNOWN): mixed {} @@ -609,6 +609,10 @@ public function getDocComment(): string|false {} public function getAttributes(?string $name = null, int $flags = 0): array {} public function isEnumCase(): bool {} + + public function hasType(): bool {} + + public function getType(): ?ReflectionType {} } /** @not-serializable */ @@ -874,9 +878,9 @@ public function __construct(Fiber $fiber) {} public function getFiber(): Fiber {} - public function getExecutingFile(): string {} + public function getExecutingFile(): ?string {} - public function getExecutingLine(): int {} + public function getExecutingLine(): ?int {} public function getCallable(): callable {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 92f37a67510ef..ddc445f5206d3 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a531c9132b4ac3d3196570ae6dda52b8f6a4f488 */ + * Stub hash: 75d10a475cce503d94bd8471764adf495f0ddd34 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0) @@ -288,8 +288,7 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_ ZEND_ARG_OBJ_TYPE_MASK(0, class, ReflectionClass, MAY_BE_STRING, NULL) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_getStaticProperties, 0, 0, IS_ARRAY, 1) -ZEND_END_ARG_INFO() +#define arginfo_class_ReflectionClass_getStaticProperties arginfo_class_ReflectionFunctionAbstract_getParameters ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionClass_getStaticPropertyValue, 0, 1, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) @@ -415,6 +414,10 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionClassConstant_isEnumCase arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType +#define arginfo_class_ReflectionClassConstant_hasType arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType + +#define arginfo_class_ReflectionClassConstant_getType arginfo_class_ReflectionFunctionAbstract_getTentativeReturnType + #define arginfo_class_ReflectionParameter___clone arginfo_class_ReflectionFunctionAbstract___clone ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionParameter___construct, 0, 0, 2) @@ -593,9 +596,11 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ReflectionFiber_getFiber, 0, 0, Fiber, 0) ZEND_END_ARG_INFO() -#define arginfo_class_ReflectionFiber_getExecutingFile arginfo_class_ReflectionFunction___toString +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFiber_getExecutingFile, 0, 0, IS_STRING, 1) +ZEND_END_ARG_INFO() -#define arginfo_class_ReflectionFiber_getExecutingLine arginfo_class_ReflectionAttribute_getTarget +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFiber_getExecutingLine, 0, 0, IS_LONG, 1) +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFiber_getCallable, 0, 0, IS_CALLABLE, 0) ZEND_END_ARG_INFO() @@ -759,6 +764,8 @@ ZEND_METHOD(ReflectionClassConstant, getDeclaringClass); ZEND_METHOD(ReflectionClassConstant, getDocComment); ZEND_METHOD(ReflectionClassConstant, getAttributes); ZEND_METHOD(ReflectionClassConstant, isEnumCase); +ZEND_METHOD(ReflectionClassConstant, hasType); +ZEND_METHOD(ReflectionClassConstant, getType); ZEND_METHOD(ReflectionParameter, __construct); ZEND_METHOD(ReflectionParameter, __toString); ZEND_METHOD(ReflectionParameter, getName); @@ -1045,6 +1052,8 @@ static const zend_function_entry class_ReflectionClassConstant_methods[] = { ZEND_ME(ReflectionClassConstant, getDocComment, arginfo_class_ReflectionClassConstant_getDocComment, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClassConstant, getAttributes, arginfo_class_ReflectionClassConstant_getAttributes, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClassConstant, isEnumCase, arginfo_class_ReflectionClassConstant_isEnumCase, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClassConstant, hasType, arginfo_class_ReflectionClassConstant_hasType, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClassConstant, getType, arginfo_class_ReflectionClassConstant_getType, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/reflection/tests/ReflectionClassConstant_basic1.phpt b/ext/reflection/tests/ReflectionClassConstant_basic1.phpt index 7d563bdf3bc16..33d923d97130c 100644 --- a/ext/reflection/tests/ReflectionClassConstant_basic1.phpt +++ b/ext/reflection/tests/ReflectionClassConstant_basic1.phpt @@ -28,11 +28,15 @@ function reflectClassConstant($base, $constant) { var_dump($constInfo->getDeclaringClass()); echo "getDocComment():\n"; var_dump($constInfo->getDocComment()); + echo "hasType():\n"; + var_dump($constInfo->hasType()); + echo "getType():\n"; + echo $constInfo->getType() ?? "NULL"; echo "\n**********************************\n"; } class TestClass { - public const /** My Doc comment */ PUB = true; + public const bool /** My Doc comment */ PUB = true; /** Another doc comment */ protected const PROT = 4; private const PRIV = "keepOut"; @@ -76,7 +80,10 @@ object(ReflectionClass)#3 (1) { } getDocComment(): string(21) "/** My Doc comment */" - +hasType(): +bool(true) +getType(): +bool ********************************** ********************************** Reflecting on class constant TestClass::PROT @@ -105,7 +112,10 @@ object(ReflectionClass)#3 (1) { } getDocComment(): string(26) "/** Another doc comment */" - +hasType(): +bool(false) +getType(): +NULL ********************************** ********************************** Reflecting on class constant TestClass::PRIV @@ -134,7 +144,10 @@ object(ReflectionClass)#3 (1) { } getDocComment(): bool(false) - +hasType(): +bool(false) +getType(): +NULL ********************************** ********************************** Reflecting on class constant TestClass::FINAL @@ -163,7 +176,10 @@ object(ReflectionClass)#3 (1) { } getDocComment(): bool(false) - +hasType(): +bool(false) +getType(): +NULL ********************************** ********************************** Reflecting on class constant TestClass::PRIV @@ -192,7 +208,10 @@ object(ReflectionClass)#3 (1) { } getDocComment(): bool(false) - +hasType(): +bool(false) +getType(): +NULL ********************************** Fatal error: Uncaught ReflectionException: Constant TestClass::BAD_CONST does not exist in %s:%d diff --git a/ext/reflection/tests/ReflectionClassConstant_getValue_typed.phpt b/ext/reflection/tests/ReflectionClassConstant_getValue_typed.phpt new file mode 100644 index 0000000000000..f964f4c146fbc --- /dev/null +++ b/ext/reflection/tests/ReflectionClassConstant_getValue_typed.phpt @@ -0,0 +1,39 @@ +--TEST-- +Test variations of getting typed class constant values +--FILE-- +getValue()); +echo $rc; + +$rc = new ReflectionClassConstant(B::class, 'CONST1'); +try { + $rc->getValue(); +} catch (TypeError $e) { + echo $e->getMessage() . "\n"; +} + +try { + echo $rc; +} catch (TypeError $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +object(stdClass)#1 (0) { +} +Constant [ public object CONST1 ] { Object } +Cannot assign stdClass to class constant B::CONST1 of type array +Cannot assign stdClass to class constant B::CONST1 of type array diff --git a/ext/reflection/tests/ReflectionClass_getConstant_typed.phpt b/ext/reflection/tests/ReflectionClass_getConstant_typed.phpt new file mode 100644 index 0000000000000..c63eaab5d9027 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_getConstant_typed.phpt @@ -0,0 +1,29 @@ +--TEST-- +ReflectionClass::getConstant() with typed class constants +--FILE-- +getConstant("CONST1")); + +$rc = new ReflectionClass(D::class); +try { + $rc->getConstant("CONST1"); +} catch (TypeError $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +object(stdClass)#1 (0) { +} +Cannot assign stdClass to class constant D::CONST1 of type array diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index 3b2c276ebc071..15059211ef01d 100644 --- a/ext/reflection/tests/ReflectionClass_toString_001.phpt +++ b/ext/reflection/tests/ReflectionClass_toString_001.phpt @@ -349,7 +349,7 @@ Class [ class ReflectionClass implements Stringable, Refle - Parameters [0] { } - - Tentative return [ ?array ] + - Tentative return [ array ] } Method [ public method getStaticPropertyValue ] { diff --git a/ext/reflection/tests/ReflectionClass_toString_006.phpt b/ext/reflection/tests/ReflectionClass_toString_006.phpt new file mode 100644 index 0000000000000..b94467261f682 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_toString_006.phpt @@ -0,0 +1,32 @@ +--TEST-- +Using ReflectionClass::__toString() with typed class constants +--FILE-- + +--EXPECTF-- +Class [ class Foo ] { + @@ %s 3-5 + + - Constants [1] { + Constant [ public ?int CONST1 ] { 1 } + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} diff --git a/ext/reflection/tests/ReflectionClass_toString_007.phpt b/ext/reflection/tests/ReflectionClass_toString_007.phpt new file mode 100644 index 0000000000000..fd3ed8f32e354 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_toString_007.phpt @@ -0,0 +1,20 @@ +--TEST-- +Using ReflectionClass::__toString() with typed class constants when there is a type mismatch +--FILE-- +getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot assign stdClass to class constant Foo::CONST1 of type array diff --git a/ext/reflection/tests/ReflectionFiber_notrace_1.phpt b/ext/reflection/tests/ReflectionFiber_notrace_1.phpt new file mode 100644 index 0000000000000..28e5da39f59d1 --- /dev/null +++ b/ext/reflection/tests/ReflectionFiber_notrace_1.phpt @@ -0,0 +1,31 @@ +--TEST-- +ReflectionFiber should not segfault when inspecting fibers with no stack frames before suspend +--FILE-- +start(); + +$reflection = new ReflectionFiber($f); + +var_dump($reflection->getExecutingFile()); +var_dump($reflection->getExecutingLine()); +var_dump($reflection->getTrace()); + +?> +--EXPECTF-- +NULL +NULL +array(1) { + [0]=> + array(4) { + ["function"]=> + string(7) "suspend" + ["class"]=> + string(5) "Fiber" + ["type"]=> + string(2) "::" + ["args"]=> + array(0) { + } + } +} diff --git a/ext/reflection/tests/ReflectionFiber_notrace_2.phpt b/ext/reflection/tests/ReflectionFiber_notrace_2.phpt new file mode 100644 index 0000000000000..85cb4ebd20a71 --- /dev/null +++ b/ext/reflection/tests/ReflectionFiber_notrace_2.phpt @@ -0,0 +1,61 @@ +--TEST-- +ReflectionFiber should not segfault when inspecting fibers where the previous stack frame is a native function +--FILE-- + call_user_func(["Fiber", "suspend"])); +$f->start(); + +$reflection = new \ReflectionFiber($f); + +var_dump($reflection->getExecutingFile()); +var_dump($reflection->getExecutingLine()); +var_dump($reflection->getTrace()); + +?> +--EXPECTF-- +string(%d) "%sReflectionFiber_notrace_2.php" +int(5) +array(3) { + [0]=> + array(4) { + ["function"]=> + string(7) "suspend" + ["class"]=> + string(5) "Fiber" + ["type"]=> + string(2) "::" + ["args"]=> + array(0) { + } + } + [1]=> + array(4) { + ["file"]=> + string(%d) "%sReflectionFiber_notrace_2.php" + ["line"]=> + int(5) + ["function"]=> + string(14) "call_user_func" + ["args"]=> + array(1) { + [0]=> + array(2) { + [0]=> + string(5) "Fiber" + [1]=> + string(7) "suspend" + } + } + } + [2]=> + array(2) { + ["function"]=> + string(14) "test\{closure}" + ["args"]=> + array(0) { + } + } +} diff --git a/ext/reflection/tests/ReflectionMethod_invokeArgs_error2.phpt b/ext/reflection/tests/ReflectionMethod_invokeArgs_error2.phpt index 869682ccdd451..791bfe3f43587 100644 --- a/ext/reflection/tests/ReflectionMethod_invokeArgs_error2.phpt +++ b/ext/reflection/tests/ReflectionMethod_invokeArgs_error2.phpt @@ -24,4 +24,4 @@ try { ?> --EXPECT-- -string(85) "ReflectionMethod::invokeArgs(): Argument #2 ($args) must be of type array, bool given" +string(85) "ReflectionMethod::invokeArgs(): Argument #2 ($args) must be of type array, true given" diff --git a/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt b/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt index 92bd0543388b0..67b37411b4216 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_basic.phpt @@ -103,7 +103,7 @@ NULL Static method: ReflectionMethod::invoke() expects at least 1 argument, 0 given -ReflectionMethod::invoke(): Argument #1 ($object) must be of type ?object, bool given +ReflectionMethod::invoke(): Argument #1 ($object) must be of type ?object, true given Called staticMethod() Exception: Using $this when not in object context NULL diff --git a/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt b/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt index 620f993325e06..e9575c4d0cdc3 100644 --- a/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt +++ b/ext/reflection/tests/ReflectionMethod_invoke_error1.phpt @@ -55,7 +55,7 @@ try { ?> --EXPECT-- invoke() on a non-object: -string(85) "ReflectionMethod::invoke(): Argument #1 ($object) must be of type ?object, bool given" +string(85) "ReflectionMethod::invoke(): Argument #1 ($object) must be of type ?object, true given" invoke() on a non-instance: string(72) "Given object is not an instance of the class this method was declared in" diff --git a/ext/reflection/tests/gh10623.phpt b/ext/reflection/tests/gh10623.phpt new file mode 100644 index 0000000000000..6e564fb5186d8 --- /dev/null +++ b/ext/reflection/tests/gh10623.phpt @@ -0,0 +1,64 @@ +--TEST-- +GH-10623 (ReflectionFunction::getClosureUsedVariables() returns empty array in presence of variadic arguments) +--FILE-- +getClosureUsedVariables()); + +$closure = function($var, ...$variadic) {}; +var_dump((new ReflectionFunction($closure))->getClosureUsedVariables()); + +$closure = function($var, ...$variadic) use($data1) {}; +var_dump((new ReflectionFunction($closure))->getClosureUsedVariables()); + +$closure = function($var, ...$variadic) use($data1, $data2, $data3) {}; +var_dump((new ReflectionFunction($closure))->getClosureUsedVariables()); + +$closure = function(...$variadic) use($data1) {}; +var_dump((new ReflectionFunction($closure))->getClosureUsedVariables()); + +$closure = function($var, $var2, ...$variadic) {}; +var_dump((new ReflectionFunction($closure))->getClosureUsedVariables()); + +$closure = function($var, $var2, $var3, ...$variadic) use($data1, $data2, $data3) {}; +var_dump((new ReflectionFunction($closure))->getClosureUsedVariables()); + +?> +--EXPECT-- +array(1) { + ["data1"]=> + int(1) +} +array(0) { +} +array(1) { + ["data1"]=> + int(1) +} +array(3) { + ["data1"]=> + int(1) + ["data2"]=> + int(2) + ["data3"]=> + int(3) +} +array(1) { + ["data1"]=> + int(1) +} +array(0) { +} +array(3) { + ["data1"]=> + int(1) + ["data2"]=> + int(2) + ["data3"]=> + int(3) +} diff --git a/ext/reflection/tests/static_properties_with_typed_class_constants1.phpt b/ext/reflection/tests/static_properties_with_typed_class_constants1.phpt new file mode 100644 index 0000000000000..cebfa1dddd3e0 --- /dev/null +++ b/ext/reflection/tests/static_properties_with_typed_class_constants1.phpt @@ -0,0 +1,24 @@ +--TEST-- +Typed class constant reflection +--FILE-- +getStaticProperties(); +} catch (TypeError $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot assign string to class constant Foo::CONST1 of type int diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c index a3207569616eb..ba68dfde9ec6d 100644 --- a/ext/session/mod_files.c +++ b/ext/session/mod_files.c @@ -288,7 +288,7 @@ static int ps_files_cleanup_dir(const zend_string *dirname, zend_long maxlifetim dir = opendir(ZSTR_VAL(dirname)); if (!dir) { php_error_docref(NULL, E_NOTICE, "ps_files_cleanup_dir: opendir(%s) failed: %s (%d)", ZSTR_VAL(dirname), strerror(errno), errno); - return (0); + return -1; } time(&now); @@ -296,7 +296,7 @@ static int ps_files_cleanup_dir(const zend_string *dirname, zend_long maxlifetim if (ZSTR_LEN(dirname) >= MAXPATHLEN) { php_error_docref(NULL, E_NOTICE, "ps_files_cleanup_dir: dirname(%s) is too long", ZSTR_VAL(dirname)); closedir(dir); - return (0); + return -1; } /* Prepare buffer (dirname never changes) */ @@ -674,10 +674,8 @@ PS_CREATE_SID_FUNC(files) /* Check collision */ /* FIXME: mod_data(data) should not be NULL (User handler could be NULL) */ if (data && ps_files_key_exists(data, sid) == SUCCESS) { - if (sid) { - zend_string_release_ex(sid, 0); - sid = NULL; - } + zend_string_release_ex(sid, 0); + sid = NULL; if (--maxfail < 0) { return NULL; } diff --git a/ext/session/mod_user.c b/ext/session/mod_user.c index fe50f2a8e8f70..168c5c7f1d44a 100644 --- a/ext/session/mod_user.c +++ b/ext/session/mod_user.c @@ -62,19 +62,19 @@ static zend_result verify_bool_return_type_userland_calls(const zval* value) if ((Z_TYPE_P(value) == IS_LONG) && (Z_LVAL_P(value) == -1)) { /* TODO Why are exception cheked? */ if (!EG(exception)) { - php_error_docref(NULL, E_DEPRECATED, "Session callback must have a return value of type bool, %s returned", zend_zval_type_name(value)); + php_error_docref(NULL, E_DEPRECATED, "Session callback must have a return value of type bool, %s returned", zend_zval_value_name(value)); } return FAILURE; } if ((Z_TYPE_P(value) == IS_LONG) && (Z_LVAL_P(value) == 0)) { /* TODO Why are exception cheked? */ if (!EG(exception)) { - php_error_docref(NULL, E_DEPRECATED, "Session callback must have a return value of type bool, %s returned", zend_zval_type_name(value)); + php_error_docref(NULL, E_DEPRECATED, "Session callback must have a return value of type bool, %s returned", zend_zval_value_name(value)); } return SUCCESS; } if (!EG(exception)) { - zend_type_error("Session callback must have a return value of type bool, %s returned", zend_zval_type_name(value)); \ + zend_type_error("Session callback must have a return value of type bool, %s returned", zend_zval_value_name(value)); \ } return FAILURE; } diff --git a/ext/session/php_session.h b/ext/session/php_session.h index 8a52e61564eba..341aac5716ac2 100644 --- a/ext/session/php_session.h +++ b/ext/session/php_session.h @@ -154,6 +154,8 @@ typedef struct _php_ps_globals { const ps_module *default_mod; void *mod_data; php_session_status session_status; + zend_string *session_started_filename; + uint32_t session_started_lineno; zend_long gc_probability; zend_long gc_divisor; zend_long gc_maxlifetime; diff --git a/ext/session/session.c b/ext/session/session.c index 4bfc973ed537b..c3ee25313fbbe 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -56,8 +56,8 @@ PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps) -static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra); -static int (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); +static zend_result php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra); +static zend_result (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); static void php_session_track_init(void); /* SessionHandler class */ @@ -97,8 +97,8 @@ zend_class_entry *php_session_update_timestamp_iface_entry; #define APPLY_TRANS_SID (PS(use_trans_sid) && !PS(use_only_cookies)) -static int php_session_send_cookie(void); -static int php_session_abort(void); +static zend_result php_session_send_cookie(void); +static zend_result php_session_abort(void); /* Initialized in MINIT, readonly otherwise. */ static int my_module_number = 0; @@ -121,6 +121,16 @@ static inline void php_rinit_session_globals(void) /* {{{ */ } /* }}} */ +static inline void php_session_cleanup_filename(void) /* {{{ */ +{ + if (PS(session_started_filename)) { + zend_string_release(PS(session_started_filename)); + PS(session_started_filename) = NULL; + PS(session_started_lineno) = 0; + } +} +/* }}} */ + /* Dispatched by RSHUTDOWN and by php_session_destroy */ static inline void php_rshutdown_session_globals(void) /* {{{ */ { @@ -149,6 +159,8 @@ static inline void php_rshutdown_session_globals(void) /* {{{ */ PS(mod_user_class_name) = NULL; } + php_session_cleanup_filename(); + /* User save handlers may end up directly here by misuse, bugs in user script, etc. */ /* Set session status to prevent error while restoring save handler INI value. */ PS(session_status) = php_session_none; @@ -215,7 +227,7 @@ PHPAPI zval* php_get_session_var(zend_string *name) /* {{{ */ static void php_session_track_init(void) /* {{{ */ { zval session_vars; - zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0); + zend_string *var_name = ZSTR_INIT_LITERAL("_SESSION", 0); /* Unconditionally destroy existing array -- possible dirty data */ zend_delete_global_variable(var_name); @@ -306,17 +318,14 @@ static void bin_to_readable(unsigned char *in, size_t inlen, char *out, size_t o } /* }}} */ -#define PS_EXTRA_RAND_BYTES 60 - PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */ { - unsigned char rbuf[PS_MAX_SID_LENGTH + PS_EXTRA_RAND_BYTES]; + unsigned char rbuf[PS_MAX_SID_LENGTH]; zend_string *outid; /* It would be enough to read ceil(sid_length * sid_bits_per_character / 8) bytes here. * We read sid_length bytes instead for simplicity. */ - /* Read additional PS_EXTRA_RAND_BYTES just in case CSPRNG is not safe enough */ - if (php_random_bytes_throw(rbuf, PS(sid_length) + PS_EXTRA_RAND_BYTES) == FAILURE) { + if (php_random_bytes_throw(rbuf, PS(sid_length)) == FAILURE) { return NULL; } @@ -468,6 +477,13 @@ static zend_result php_session_initialize(void) /* {{{ */ php_session_decode(val); zend_string_release_ex(val, 0); } + + php_session_cleanup_filename(); + zend_string *session_started_filename = zend_get_executed_filename_ex(); + if (session_started_filename != NULL) { + PS(session_started_filename) = zend_string_copy(session_started_filename); + PS(session_started_lineno) = zend_get_executed_lineno(); + } return SUCCESS; } /* }}} */ @@ -844,7 +860,7 @@ PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */ zval session_vars; php_unserialize_data_t var_hash; bool result; - zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0); + zend_string *var_name = ZSTR_INIT_LITERAL("_SESSION", 0); ZVAL_NULL(&session_vars); PHP_VAR_UNSERIALIZE_INIT(var_hash); @@ -907,10 +923,9 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ PHP_VAR_UNSERIALIZE_INIT(var_hash); for (p = val; p < endptr; ) { - // Can this be changed to size_t? - int namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF); + size_t namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF); - if (namelen < 0 || namelen > PS_BIN_MAX || (p + namelen) >= endptr) { + if (namelen > PS_BIN_MAX || (p + namelen) >= endptr) { PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return FAILURE; } @@ -1494,7 +1509,14 @@ PHPAPI zend_result php_session_start(void) /* {{{ */ switch (PS(session_status)) { case php_session_active: - php_error(E_NOTICE, "Ignoring session_start() because a session has already been started"); + if (PS(session_started_filename)) { + php_error(E_NOTICE, "Ignoring session_start() because a session has already been started (started from %s on line %"PRIu32")", ZSTR_VAL(PS(session_started_filename)), PS(session_started_lineno)); + } else if (PS(auto_start)) { + /* This option can't be changed at runtime, so we can assume it's because of this */ + php_error(E_NOTICE, "Ignoring session_start() because a session has already been started automatically"); + } else { + php_error(E_NOTICE, "Ignoring session_start() because a session has already been started"); + } return FAILURE; break; @@ -1604,6 +1626,7 @@ PHPAPI zend_result php_session_start(void) /* {{{ */ } return FAILURE; } + return SUCCESS; } /* }}} */ @@ -1762,7 +1785,7 @@ PHP_FUNCTION(session_set_cookie_params) } if (lifetime) { - ini_name = zend_string_init("session.cookie_lifetime", sizeof("session.cookie_lifetime") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.cookie_lifetime", 0); result = zend_alter_ini_entry(ini_name, lifetime, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { @@ -1771,7 +1794,7 @@ PHP_FUNCTION(session_set_cookie_params) } } if (path) { - ini_name = zend_string_init("session.cookie_path", sizeof("session.cookie_path") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.cookie_path", 0); result = zend_alter_ini_entry(ini_name, path, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { @@ -1780,7 +1803,7 @@ PHP_FUNCTION(session_set_cookie_params) } } if (domain) { - ini_name = zend_string_init("session.cookie_domain", sizeof("session.cookie_domain") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.cookie_domain", 0); result = zend_alter_ini_entry(ini_name, domain, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { @@ -1789,7 +1812,7 @@ PHP_FUNCTION(session_set_cookie_params) } } if (!secure_null) { - ini_name = zend_string_init("session.cookie_secure", sizeof("session.cookie_secure") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.cookie_secure", 0); result = zend_alter_ini_entry_chars(ini_name, secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { @@ -1798,7 +1821,7 @@ PHP_FUNCTION(session_set_cookie_params) } } if (!httponly_null) { - ini_name = zend_string_init("session.cookie_httponly", sizeof("session.cookie_httponly") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.cookie_httponly", 0); result = zend_alter_ini_entry_chars(ini_name, httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { @@ -1807,7 +1830,7 @@ PHP_FUNCTION(session_set_cookie_params) } } if (samesite) { - ini_name = zend_string_init("session.cookie_samesite", sizeof("session.cookie_samesite") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.cookie_samesite", 0); result = zend_alter_ini_entry(ini_name, samesite, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); if (result == FAILURE) { @@ -1869,7 +1892,7 @@ PHP_FUNCTION(session_name) RETVAL_STRING(PS(session_name)); if (name) { - ini_name = zend_string_init("session.name", sizeof("session.name") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.name", 0); zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); } @@ -1919,7 +1942,7 @@ PHP_FUNCTION(session_module_name) } PS(mod_data) = NULL; - ini_name = zend_string_init("session.save_handler", sizeof("session.save_handler") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.save_handler", 0); zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); } @@ -1943,8 +1966,8 @@ static bool can_session_handler_be_changed(void) { static inline void set_user_save_handler_ini(void) { zend_string *ini_name, *ini_val; - ini_name = zend_string_init("session.save_handler", sizeof("session.save_handler") - 1, 0); - ini_val = zend_string_init("user", sizeof("user") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.save_handler", 0); + ini_val = ZSTR_INIT_LITERAL("user", 0); PS(set_handler) = 1; zend_alter_ini_entry(ini_name, ini_val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); PS(set_handler) = 0; @@ -2019,7 +2042,7 @@ PHP_FUNCTION(session_set_save_handler) /* Find implemented methods - SessionIdInterface (optional) */ /* First release old handlers */ SESSION_RELEASE_USER_HANDLER_OO(ps_create_sid); - zend_string *create_sid_name = zend_string_init("create_sid", strlen("create_sid"), false); + zend_string *create_sid_name = ZSTR_INIT_LITERAL("create_sid", false); if (instanceof_function(Z_OBJCE_P(obj), php_session_id_iface_entry)) { SESSION_SET_USER_HANDLER_OO(ps_create_sid, zend_string_copy(create_sid_name)); } else if (zend_hash_find_ptr(object_methods, create_sid_name)) { @@ -2033,8 +2056,8 @@ PHP_FUNCTION(session_set_save_handler) SESSION_RELEASE_USER_HANDLER_OO(ps_validate_sid); SESSION_RELEASE_USER_HANDLER_OO(ps_update_timestamp); /* Method names need to be lowercase */ - zend_string *validate_sid_name = zend_string_init("validateid", strlen("validateid"), false); - zend_string *update_timestamp_name = zend_string_init("updatetimestamp", strlen("updatetimestamp"), false); + zend_string *validate_sid_name = ZSTR_INIT_LITERAL("validateid", false); + zend_string *update_timestamp_name = ZSTR_INIT_LITERAL("updatetimestamp", false); if (instanceof_function(Z_OBJCE_P(obj), php_session_update_timestamp_iface_entry)) { /* Validate ID handler */ SESSION_SET_USER_HANDLER_OO(ps_validate_sid, zend_string_copy(validate_sid_name)); @@ -2175,7 +2198,7 @@ PHP_FUNCTION(session_save_path) RETVAL_STRING(PS(save_path)); if (name) { - ini_name = zend_string_init("session.save_path", sizeof("session.save_path") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.save_path", 0); zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); } @@ -2413,7 +2436,7 @@ PHP_FUNCTION(session_cache_limiter) RETVAL_STRING(PS(cache_limiter)); if (limiter) { - ini_name = zend_string_init("session.cache_limiter", sizeof("session.cache_limiter") - 1, 0); + ini_name = ZSTR_INIT_LITERAL("session.cache_limiter", 0); zend_alter_ini_entry(ini_name, limiter, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); } @@ -2443,7 +2466,7 @@ PHP_FUNCTION(session_cache_expire) RETVAL_LONG(PS(cache_expire)); if (!expires_is_null) { - zend_string *ini_name = zend_string_init("session.cache_expire", sizeof("session.cache_expire") - 1, 0); + zend_string *ini_name = ZSTR_INIT_LITERAL("session.cache_expire", 0); zend_string *ini_value = zend_long_to_str(expires); zend_alter_ini_entry(ini_name, ini_value, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); zend_string_release_ex(ini_name, 0); @@ -2517,7 +2540,14 @@ PHP_FUNCTION(session_start) } if (PS(session_status) == php_session_active) { - php_error_docref(NULL, E_NOTICE, "Ignoring session_start() because a session is already active"); + if (PS(session_started_filename)) { + php_error_docref(NULL, E_NOTICE, "Ignoring session_start() because a session is already active (started from %s on line %"PRIu32")", ZSTR_VAL(PS(session_started_filename)), PS(session_started_lineno)); + } else if (PS(auto_start)) { + /* This option can't be changed at runtime, so we can assume it's because of this */ + php_error_docref(NULL, E_NOTICE, "Ignoring session_start() because a session is already automatically active"); + } else { + php_error_docref(NULL, E_NOTICE, "Ignoring session_start() because a session is already active"); + } RETURN_TRUE; } @@ -2553,7 +2583,7 @@ PHP_FUNCTION(session_start) break; default: zend_type_error("%s(): Option \"%s\" must be of type string|int|bool, %s given", - get_active_function_name(), ZSTR_VAL(str_idx), zend_zval_type_name(value) + get_active_function_name(), ZSTR_VAL(str_idx), zend_zval_value_name(value) ); RETURN_THROWS(); } @@ -2850,6 +2880,8 @@ static PHP_MINIT_FUNCTION(session) /* {{{ */ PS(module_number) = module_number; PS(session_status) = php_session_none; + PS(session_started_filename) = NULL; + PS(session_started_lineno) = 0; REGISTER_INI_ENTRIES(); #ifdef HAVE_LIBMM @@ -2913,7 +2945,7 @@ static PHP_MINFO_FUNCTION(session) /* {{{ */ /* Get serializer handlers */ for (i = 0, ser = ps_serializers; i < MAX_SERIALIZERS; i++, ser++) { - if (ser && ser->name) { + if (ser->name) { smart_str_appends(&ser_handlers, ser->name); smart_str_appendc(&ser_handlers, ' '); } diff --git a/ext/session/tests/session_start_variation1.phpt b/ext/session/tests/session_start_variation1.phpt index 66520639de09e..0d6a866bf08f9 100644 --- a/ext/session/tests/session_start_variation1.phpt +++ b/ext/session/tests/session_start_variation1.phpt @@ -25,15 +25,15 @@ ob_end_flush(); *** Testing session_start() : variation *** bool(true) -Notice: session_start(): Ignoring session_start() because a session is already active in %s on line %d +Notice: session_start(): Ignoring session_start() because a session is already active (started from %s on line %d) in %s on line %d bool(true) -Notice: session_start(): Ignoring session_start() because a session is already active in %s on line %d +Notice: session_start(): Ignoring session_start() because a session is already active (started from %s on line %d) in %s on line %d bool(true) -Notice: session_start(): Ignoring session_start() because a session is already active in %s on line %d +Notice: session_start(): Ignoring session_start() because a session is already active (started from %s on line %d) in %s on line %d bool(true) -Notice: session_start(): Ignoring session_start() because a session is already active in %s on line %d +Notice: session_start(): Ignoring session_start() because a session is already active (started from %s on line %d) in %s on line %d bool(true) Done diff --git a/ext/session/tests/session_start_variation9.phpt b/ext/session/tests/session_start_variation9.phpt index e4c6e573810ed..3fdcdcffbb9ff 100644 --- a/ext/session/tests/session_start_variation9.phpt +++ b/ext/session/tests/session_start_variation9.phpt @@ -26,7 +26,7 @@ ob_end_flush(); *** Testing session_start() : variation *** string(%d) "%s" -Notice: session_start(): Ignoring session_start() because a session is already active in %s on line %d +Notice: session_start(): Ignoring session_start() because a session is already automatically active in %s on line %d bool(true) string(%d) "%s" bool(true) diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 20537989d0711..d3f2865e12036 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -496,7 +496,7 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value, if (member == &tmp_zv) { zval_ptr_dtor_str(&tmp_zv); } - zend_type_error("It's not possible to assign a complex type to %s, %s given", attribs ? "attributes" : "properties", zend_zval_type_name(value)); + zend_type_error("It's not possible to assign a complex type to %s, %s given", attribs ? "attributes" : "properties", zend_zval_value_name(value)); return &EG(error_zval); } } @@ -2605,7 +2605,7 @@ PHP_FUNCTION(simplexml_import_dom) nodep = php_libxml_import_node(node); if (!nodep) { - zend_argument_type_error(1, "must be of type SimpleXMLElement|DOMNode, %s given", zend_zval_type_name(node)); + zend_argument_type_error(1, "must be of type SimpleXMLElement|DOMNode, %s given", zend_zval_value_name(node)); RETURN_THROWS(); } diff --git a/ext/simplexml/tests/bug79971_1.phpt b/ext/simplexml/tests/bug79971_1.phpt index 1097d74bb29d2..2ee07c81822ff 100644 --- a/ext/simplexml/tests/bug79971_1.phpt +++ b/ext/simplexml/tests/bug79971_1.phpt @@ -1,8 +1,10 @@ --TEST-- Bug #79971 (special character is breaking the path in xml function) +--EXTENSIONS-- +simplexml --SKIPIF-- --FILE-- u.flags & (1<<2)) != 0)' failed.) +--EXTENSIONS-- +simplexml +--FILE-- + +https://github.com/php/php-src/issues/10200 not encountered +EOF; + +$xml = simplexml_load_string($xmlData); +$output = get_object_vars($xml); +var_dump($output); + +?> +--EXPECT-- +array(1) { + [0]=> + string(59) "https://github.com/php/php-src/issues/10200 not encountered" +} diff --git a/ext/simplexml/tests/gh10983.phpt b/ext/simplexml/tests/gh10983.phpt new file mode 100644 index 0000000000000..ae6da92d7de2f --- /dev/null +++ b/ext/simplexml/tests/gh10983.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-10983 (State-dependant segfault in ReflectionObject::getProperties) +--EXTENSIONS-- +simplexml +--FILE-- + +XML; + +$simplexml = simplexml_load_string($xml); + +var_dump($simplexml['name']); +$reflector = new ReflectionObject($simplexml['name']); +$rprops = $reflector->getProperties(); + +?> +--EXPECT-- +object(SimpleXMLElement)#2 (1) { + [0]=> + string(4) "test" +} diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 6c7a6f42e968c..617d07ab7822a 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -91,7 +91,7 @@ ZEND_DECLARE_MODULE_GLOBALS(snmp) static PHP_GINIT_FUNCTION(snmp); /* constant - can be shared among threads */ -static oid objid_mib[] = {1, 3, 6, 1, 2, 1}; +static const oid objid_mib[] = {1, 3, 6, 1, 2, 1}; /* Handlers */ static zend_object_handlers php_snmp_object_handlers; @@ -397,7 +397,7 @@ static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st, php_snmp_error(getThis(), PHP_SNMP_ERRNO_NOERROR, ""); if (st & SNMP_CMD_WALK) { /* remember root OID */ - memmove((char *)root, (char *)(objid_query->vars[0].name), (objid_query->vars[0].name_length) * sizeof(oid)); + memcpy((char *)root, (char *)(objid_query->vars[0].name), (objid_query->vars[0].name_length) * sizeof(oid)); rootlen = objid_query->vars[0].name_length; objid_query->offset = objid_query->count; } @@ -551,7 +551,7 @@ static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st, php_snmp_error(getThis(), PHP_SNMP_ERRNO_OID_NOT_INCREASING, "Error: OID not increasing: %s", buf2); keepwalking = false; } else { - memmove((char *)(objid_query->vars[0].name), (char *)vars->name, vars->name_length * sizeof(oid)); + memcpy((char *)(objid_query->vars[0].name), (char *)vars->name, vars->name_length * sizeof(oid)); objid_query->vars[0].name_length = vars->name_length; keepwalking = true; } @@ -765,7 +765,7 @@ static bool php_snmp_parse_oid( return false; } } else { - memmove((char *)objid_query->vars[0].name, (char *)objid_mib, sizeof(objid_mib)); + memmove((char *)objid_query->vars[0].name, (const char *)objid_mib, sizeof(objid_mib)); objid_query->vars[0].name_length = sizeof(objid_mib) / sizeof(oid); } } else { diff --git a/ext/snmp/snmp.stub.php b/ext/snmp/snmp.stub.php index 175c3cdc6461e..84fc738354aeb 100644 --- a/ext/snmp/snmp.stub.php +++ b/ext/snmp/snmp.stub.php @@ -186,62 +186,74 @@ class SNMP /** * @var int * @cvalue SNMP_VERSION_1 + * @link snmp.class.constants.version-1 */ public const VERSION_1 = UNKNOWN; /** * @var int * @cvalue SNMP_VERSION_2c + * @link snmp.class.constants.version-2c */ public const VERSION_2c = UNKNOWN; /** * @var int * @cvalue SNMP_VERSION_2c + * @link snmp.class.constants.version-2c */ public const VERSION_2C = UNKNOWN; /** * @var int * @cvalue SNMP_VERSION_3 + * @link snmp.class.constants.version-3 */ public const VERSION_3 = UNKNOWN; /** * @var int * @cvalue PHP_SNMP_ERRNO_NOERROR + * @link snmp.class.constants.errno-noerror */ public const ERRNO_NOERROR = UNKNOWN; /** * @var int * @cvalue PHP_SNMP_ERRNO_ANY + * @link snmp.class.constants.errno-any */ public const ERRNO_ANY = UNKNOWN; /** * @var int * @cvalue PHP_SNMP_ERRNO_GENERIC + * @link snmp.class.constants.errno-generic */ public const ERRNO_GENERIC = UNKNOWN; /** * @var int * @cvalue PHP_SNMP_ERRNO_TIMEOUT + * @link snmp.class.constants.errno-timeout */ public const ERRNO_TIMEOUT = UNKNOWN; /** * @var int * @cvalue PHP_SNMP_ERRNO_ERROR_IN_REPLY + * @link snmp.class.constants.errno-error-in-reply */ public const ERRNO_ERROR_IN_REPLY = UNKNOWN; /** * @var int * @cvalue PHP_SNMP_ERRNO_OID_NOT_INCREASING + * @link snmp.class.constants.errno-oid-not-increasing */ public const ERRNO_OID_NOT_INCREASING = UNKNOWN; /** * @var int * @cvalue PHP_SNMP_ERRNO_OID_PARSING_ERROR + * @link snmp.class.constants.errno-oid-parsing-error */ public const ERRNO_OID_PARSING_ERROR = UNKNOWN; /** * @var int * @cvalue PHP_SNMP_ERRNO_MULTIPLE_SET_QUERIES + * @link snmp.class.constants.errno-multiple-set-queries */ public const ERRNO_MULTIPLE_SET_QUERIES = UNKNOWN; diff --git a/ext/snmp/snmp_arginfo.h b/ext/snmp/snmp_arginfo.h index 19974c85753e3..bbe95f1dd2cfb 100644 --- a/ext/snmp/snmp_arginfo.h +++ b/ext/snmp/snmp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: feff81a6d260b4c1c1d3f3acd11c564a5800e1c5 */ + * Stub hash: a79a697fa8c1ab2513bde03e0c2367d0caaec7d8 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_snmpget, 0, 3, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, hostname, IS_STRING, 0) diff --git a/ext/snmp/tests/snmp-object-errno-errstr.phpt b/ext/snmp/tests/snmp-object-errno-errstr.phpt index 8304c6cb9f921..2f00507104542 100644 --- a/ext/snmp/tests/snmp-object-errno-errstr.phpt +++ b/ext/snmp/tests/snmp-object-errno-errstr.phpt @@ -7,6 +7,7 @@ snmp --SKIPIF-- --FILE-- --FILE-- --FILE-- --ENV-- MIBS= diff --git a/ext/snmp/tests/snmp2_walk.phpt b/ext/snmp/tests/snmp2_walk.phpt index 4cd9b3a85b6fd..6baae774e84ec 100644 --- a/ext/snmp/tests/snmp2_walk.phpt +++ b/ext/snmp/tests/snmp2_walk.phpt @@ -7,6 +7,7 @@ snmp --SKIPIF-- --FILE-- --FILE-- --FILE-- --FILE-- --ENV-- MIBS= diff --git a/ext/snmp/tests/snmpwalk.phpt b/ext/snmp/tests/snmpwalk.phpt index b0e8a8a8afd18..e8f4586e8ed5e 100644 --- a/ext/snmp/tests/snmpwalk.phpt +++ b/ext/snmp/tests/snmpwalk.phpt @@ -7,6 +7,7 @@ snmp --SKIPIF-- --FILE-- = 11 + ZEND_CGG_DIAGNOSTIC_IGNORED_START("-Wstringop-overread") +#endif + bool is_xsd_any_type = strcmp(ZSTR_VAL(array_type.s),"xsd:anyType") == 0; +#if defined(__GNUC__) && __GNUC__ >= 11 + ZEND_CGG_DIAGNOSTIC_IGNORED_END +#endif + if (is_xsd_any_type) { smart_str_free(&array_type); smart_str_appendl(&array_type,"xsd:ur-type",sizeof("xsd:ur-type")-1); } @@ -3414,7 +3421,7 @@ static void set_xsi_type(xmlNodePtr node, char *type) set_ns_prop(node, XSI_NAMESPACE, "type", type); } -void encode_reset_ns() +void encode_reset_ns(void) { SOAP_GLOBAL(cur_uniq_ns) = 0; SOAP_GLOBAL(cur_uniq_ref) = 0; @@ -3426,7 +3433,7 @@ void encode_reset_ns() zend_hash_init(SOAP_GLOBAL(ref_map), 0, NULL, NULL, 0); } -void encode_finish() +void encode_finish(void) { SOAP_GLOBAL(cur_uniq_ns) = 0; SOAP_GLOBAL(cur_uniq_ref) = 0; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index e2e69f64ca620..fea43f2f82146 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -667,7 +667,7 @@ static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht) /* {{{ */ zend_string *name; if (Z_TYPE_P(tmp) != IS_ARRAY) { - zend_type_error("SoapHeader::__construct(): \"typemap\" option must be of type array, %s given", zend_zval_type_name(tmp)); + zend_type_error("SoapHeader::__construct(): \"typemap\" option must be of type array, %s given", zend_zval_value_name(tmp)); return NULL; } ht2 = Z_ARRVAL_P(tmp); @@ -1089,7 +1089,7 @@ PHP_METHOD(SoapServer, addFunction) RETURN_THROWS(); } } else { - zend_argument_type_error(1, "must be of type array|string|int, %s given", zend_zval_type_name(function_name)); + zend_argument_type_error(1, "must be of type array|string|int, %s given", zend_zval_value_name(function_name)); RETURN_THROWS(); } @@ -1753,7 +1753,7 @@ static zend_never_inline ZEND_COLD void soap_real_error_handler(int error_num, z instanceof_function(Z_OBJCE_P(error_object), soap_server_class_entry) && (service = soap_server_object_fetch(Z_OBJ_P(error_object))->service) && !service->send_errors) { - buffer = zend_string_init("Internal Error", sizeof("Internal Error")-1, 0); + buffer = ZSTR_INIT_LITERAL("Internal Error", 0); } else { buffer = zend_string_copy(message); @@ -2414,7 +2414,7 @@ void soap_client_call_impl(INTERNAL_FUNCTION_PARAMETERS, bool is_soap_call) Z_ADDREF_P(headers); free_soap_headers = 1; } else { - zend_argument_type_error(4, "must be of type SoapHeader|array|null, %s given", zend_zval_type_name(headers)); + zend_argument_type_error(4, "must be of type SoapHeader|array|null, %s given", zend_zval_value_name(headers)); RETURN_THROWS(); } @@ -2678,7 +2678,7 @@ PHP_METHOD(SoapClient, __setSoapHeaders) zval_ptr_dtor(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr)); ZVAL_COPY_VALUE(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr), &default_headers); } else { - zend_argument_type_error(1, "must be of type SoapHeader|array|null, %s given", zend_zval_type_name(headers)); + zend_argument_type_error(1, "must be of type SoapHeader|array|null, %s given", zend_zval_value_name(headers)); RETURN_THROWS(); } RETURN_TRUE; diff --git a/ext/sockets/conversions.c b/ext/sockets/conversions.c index ae90cbe59d2a7..4059758f44719 100644 --- a/ext/sockets/conversions.c +++ b/ext/sockets/conversions.c @@ -726,8 +726,13 @@ static void from_zval_write_sockaddr_aux(const zval *container, && Z_TYPE_P(elem) != IS_NULL) { const char *node = "family"; zend_llist_add_element(&ctx->keys, &node); + family = 0; /* Silence compiler warning */ from_zval_write_int(elem, (char*)&family, ctx); zend_llist_remove_tail(&ctx->keys); + + if (UNEXPECTED(ctx->err.has_error)) { + return; + } } else { family = ctx->sock->type; } @@ -1117,13 +1122,16 @@ static void from_zval_write_iov_array(const zval *arr, char *msghdr_c, ser_conte static void from_zval_write_controllen(const zval *elem, char *msghdr_c, ser_context *ctx) { struct msghdr *msghdr = (struct msghdr *)msghdr_c; - uint32_t len; + uint32_t len = 0; /* Silence compiler warning */ /* controllen should be an unsigned with at least 32-bit. Let's assume * this least common denominator */ from_zval_write_uint32(elem, (char*)&len, ctx); - if (!ctx->err.has_error && len == 0) { + if (ctx->err.has_error) { + return; + } + if (len == 0) { do_from_zval_err(ctx, "controllen cannot be 0"); return; } diff --git a/ext/sockets/multicast.c b/ext/sockets/multicast.c index ef32661be09ff..82672e68f2bab 100644 --- a/ext/sockets/multicast.c +++ b/ext/sockets/multicast.c @@ -59,7 +59,7 @@ static const char *_php_source_op_to_string(enum source_op sop); static int _php_source_op_to_ipv4_op(enum source_op sop); #endif -int php_string_to_if_index(const char *val, unsigned *out) +zend_result php_string_to_if_index(const char *val, unsigned *out) { #if HAVE_IF_NAMETOINDEX unsigned int ind; @@ -81,7 +81,7 @@ int php_string_to_if_index(const char *val, unsigned *out) #endif } -static int php_get_if_index_from_zval(zval *val, unsigned *out) +static zend_result php_get_if_index_from_zval(zval *val, unsigned *out) { int ret; @@ -104,7 +104,7 @@ static int php_get_if_index_from_zval(zval *val, unsigned *out) -static int php_get_if_index_from_array(const HashTable *ht, const char *key, +static zend_result php_get_if_index_from_array(const HashTable *ht, const char *key, php_socket *sock, unsigned int *if_index) { zval *val; @@ -117,7 +117,7 @@ static int php_get_if_index_from_array(const HashTable *ht, const char *key, return php_get_if_index_from_zval(val, if_index); } -static int php_get_address_from_array(const HashTable *ht, const char *key, +static zend_result php_get_address_from_array(const HashTable *ht, const char *key, php_socket *sock, php_sockaddr_storage *ss, socklen_t *ss_len) { zval *val; @@ -136,7 +136,7 @@ static int php_get_address_from_array(const HashTable *ht, const char *key, return SUCCESS; } -static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval *arg4) +static zend_result php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval *arg4) { HashTable *opt_ht; unsigned int if_index; @@ -616,7 +616,7 @@ static int _php_source_op_to_ipv4_op(enum source_op sop) #endif /* HAS_MCAST_EXT */ #ifdef PHP_WIN32 -int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr) +zend_result php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr) { MIB_IPADDRTABLE *addr_table; ULONG size; @@ -659,7 +659,7 @@ int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_add return FAILURE; } -int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index) +zend_result php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index) { MIB_IPADDRTABLE *addr_table; ULONG size; @@ -709,7 +709,7 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *i #else -int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr) +zend_result php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr) { struct ifreq if_req; @@ -746,7 +746,7 @@ int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_add return SUCCESS; } -int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index) +zend_result php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index) { struct ifconf if_conf = {0}; char *buf = NULL, diff --git a/ext/sockets/multicast.h b/ext/sockets/multicast.h index 1e7a0daeb2f20..0362b269728f1 100644 --- a/ext/sockets/multicast.h +++ b/ext/sockets/multicast.h @@ -51,17 +51,17 @@ int php_do_setsockopt_ipv6_mcast(php_socket *php_sock, int optname, zval *arg4); -int php_if_index_to_addr4( +zend_result php_if_index_to_addr4( unsigned if_index, php_socket *php_sock, struct in_addr *out_addr); -int php_add4_to_if_index( +zend_result php_add4_to_if_index( struct in_addr *addr, php_socket *php_sock, unsigned *if_index); -int php_string_to_if_index(const char *val, unsigned *out); +zend_result php_string_to_if_index(const char *val, unsigned *out); int php_mcast_join( php_socket *sock, diff --git a/ext/sockets/php_sockets.h b/ext/sockets/php_sockets.h index fdbc636538cf7..93eba9da0731a 100644 --- a/ext/sockets/php_sockets.h +++ b/ext/sockets/php_sockets.h @@ -126,7 +126,7 @@ enum sockopt_return { }; PHP_SOCKETS_API char *sockets_strerror(int error); -PHP_SOCKETS_API int socket_import_file_descriptor(PHP_SOCKET socket, php_socket *retsock); +PHP_SOCKETS_API bool socket_import_file_descriptor(PHP_SOCKET socket, php_socket *retsock); #else #define phpext_sockets_ptr NULL diff --git a/ext/sockets/sockaddr_conv.c b/ext/sockets/sockaddr_conv.c index 6ec540931f725..e4a7347cafab3 100644 --- a/ext/sockets/sockaddr_conv.c +++ b/ext/sockets/sockaddr_conv.c @@ -9,7 +9,7 @@ #include #endif -extern int php_string_to_if_index(const char *val, unsigned *out); +extern zend_result php_string_to_if_index(const char *val, unsigned *out); #if HAVE_IPV6 /* Sets addr by hostname, or by ip in string form (AF_INET6) */ diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index ed6f729dcc909..77e6a2c4c2b01 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -223,7 +223,7 @@ ZEND_GET_MODULE(sockets) int inet_ntoa_lock = 0; #endif -static int php_open_listen_sock(php_socket *sock, int port, int backlog) /* {{{ */ +static bool php_open_listen_sock(php_socket *sock, int port, int backlog) /* {{{ */ { struct sockaddr_in la; struct hostent *hp; @@ -266,7 +266,7 @@ static int php_open_listen_sock(php_socket *sock, int port, int backlog) /* {{{ } /* }}} */ -static int php_accept_connect(php_socket *in_sock, php_socket *out_sock, struct sockaddr *la, socklen_t *la_len) /* {{{ */ +static bool php_accept_connect(php_socket *in_sock, php_socket *out_sock, struct sockaddr *la, socklen_t *la_len) /* {{{ */ { out_sock->bsd_socket = accept(in_sock->bsd_socket, la, la_len); @@ -505,7 +505,7 @@ static int php_sock_array_to_fd_set(uint32_t arg_num, zval *sock_array, fd_set * ZVAL_DEREF(element); if (Z_TYPE_P(element) != IS_OBJECT || Z_OBJCE_P(element) != socket_ce) { - zend_argument_type_error(arg_num, "must only have elements of type Socket, %s given", zend_zval_type_name(element)); + zend_argument_type_error(arg_num, "must only have elements of type Socket, %s given", zend_zval_value_name(element)); return -1; } @@ -526,14 +526,13 @@ static int php_sock_array_to_fd_set(uint32_t arg_num, zval *sock_array, fd_set * } /* }}} */ -static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds) /* {{{ */ +static void php_sock_array_from_fd_set(zval *sock_array, fd_set *fds) /* {{{ */ { zval *element; zval *dest_element; php_socket *php_sock; zval new_hash; - int num = 0; - zend_ulong num_key; + zend_ulong num_key; zend_string *key; ZEND_ASSERT(Z_TYPE_P(sock_array) == IS_ARRAY); @@ -557,15 +556,12 @@ static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds) /* {{{ */ Z_ADDREF_P(dest_element); } } - num++; } ZEND_HASH_FOREACH_END(); /* Destroy old array, add new one */ zval_ptr_dtor(sock_array); ZVAL_COPY_VALUE(sock_array, &new_hash); - - return num ? 1 : 0; } /* }}} */ @@ -2179,7 +2175,7 @@ PHP_FUNCTION(socket_clear_error) } /* }}} */ -int socket_import_file_descriptor(PHP_SOCKET socket, php_socket *retsock) +bool socket_import_file_descriptor(PHP_SOCKET socket, php_socket *retsock) { #ifdef SO_DOMAIN int type; @@ -2301,7 +2297,7 @@ PHP_FUNCTION(socket_export_stream) getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &protoid, &protoidlen); if (protoid == SOCK_STREAM) { - /* SO_PROTOCOL is not (yet?) supported on OS X, so lets assume it's TCP there */ + /* SO_PROTOCOL is not (yet?) supported on OS X, so let's assume it's TCP there */ #ifdef SO_PROTOCOL protoidlen = sizeof(protoid); getsockopt(socket->bsd_socket, SOL_SOCKET, SO_PROTOCOL, (char *) &protoid, &protoidlen); diff --git a/ext/sockets/sockets.stub.php b/ext/sockets/sockets.stub.php index b4457db185198..6860cea3aacf2 100644 --- a/ext/sockets/sockets.stub.php +++ b/ext/sockets/sockets.stub.php @@ -19,6 +19,13 @@ */ const AF_INET6 = UNKNOWN; #endif +#ifdef AF_DIVERT +/** + * @var int + * @cvalue AF_DIVERT + */ +const AF_DIVERT = UNKNOWN; +#endif /** * @var int * @cvalue SOCK_STREAM @@ -166,6 +173,13 @@ */ const SO_REUSEPORT = UNKNOWN; #endif +#ifdef SO_REUSEPORT_LB +/** + * @var int + * @cvalue SO_REUSEPORT_LB + */ +const SO_REUSEPORT_LB = UNKNOWN; +#endif /** * @var int * @cvalue SO_KEEPALIVE @@ -286,6 +300,27 @@ */ const SO_ACCEPTFILTER = UNKNOWN; #endif +#ifdef SO_RERROR +/** + * @var int + * @cvalue SO_RERROR + */ +const SO_RERROR = UNKNOWN; +#endif +#ifdef SO_SOPLICE +/** + * @var int + * @cvalue SO_SPLICE + */ +const SO_SPLICE = UNKNOWN; +#endif +#ifdef SO_ZEROIZE +/** + * @var int + * @cvalue SO_ZEROIZE + */ +const SO_ZEROIZE = UNKNOWN; +#endif #ifdef SOL_FILTER /** * @var int @@ -607,6 +642,13 @@ * @cvalue IP_MULTICAST_LOOP */ const IP_MULTICAST_LOOP = UNKNOWN; +#ifdef IP_BIND_ADDRESS_NO_PORT +/** + * @var int + * @cvalue IP_BIND_ADDRESS_NO_PORT + */ +const IP_BIND_ADDRESS_NO_PORT = UNKNOWN; +#endif #if HAVE_IPV6 /** * @var int @@ -1518,6 +1560,13 @@ * @cvalue IPPROTO_UDP */ const SOL_UDP = UNKNOWN; +#ifdef IPPROTO_UDPLITE +/** + * @var int + * @cvalue IPPROTO_UDPLITE + */ +const SOL_UDPLITE = UNKNOWN; +#endif #if HAVE_IPV6 /** @@ -1699,6 +1748,90 @@ */ const SO_DETACH_BPF = UNKNOWN; #endif +#if defined(TCP_QUICKACK) +/** + * @var int + * @cvalue TCP_QUICKACK + */ +const TCP_QUICKACK = UNKNOWN; +#endif +#if defined(TCP_REPAIR) +/** + * @var int + * @cvalue TCP_REPAIR + */ +const TCP_REPAIR = UNKNOWN; +#endif +#if defined(IP_DONTFRAG) +/** + * @var int + * @cvalue IP_DONTFRAG + */ +const IP_DONTFRAG = UNKNOWN; +#endif +#if defined(IP_MTU_DISCOVER) +/** + * @var int + * @cvalue IP_MTU_DISCOVER + */ +const IP_MTU_DISCOVER = UNKNOWN; +#endif +#if defined(IP_PMTUDISC_DO) +/** + * @var int + * @cvalue IP_PMTUDISC_DO + */ +const IP_PMTUDISC_DO = UNKNOWN; +#endif +#if defined(IP_PMTUDISC_DONT) +/** + * @var int + * @cvalue IP_PMTUDISC_DONT + */ +const IP_PMTUDISC_DONT = UNKNOWN; +#endif +#if defined(IP_PMTUDISC_WANT) +/** + * @var int + * @cvalue IP_PMTUDISC_WANT + */ +const IP_PMTUDISC_WANT = UNKNOWN; +#endif +#if defined(IP_PMTUDISC_PROBE) +/** + * @var int + * @cvalue IP_PMTUDISC_PROBE + */ +const IP_PMTUDISC_PROBE = UNKNOWN; +#endif +#if defined(IP_PMTUDISC_INTERFACE) +/** + * @var int + * @cvalue IP_PMTUDISC_INTERFACE + */ +const IP_PMTUDISC_INTERFACE = UNKNOWN; +#endif +#if defined(IP_PMTUDISC_OMIT) +/** + * @var int + * @cvalue IP_PMTUDISC_OMIT + */ +const IP_PMTUDISC_OMIT = UNKNOWN; +#endif +#if defined(UDPLITE_SEND_CSCOV) +/** + * @var int + * @cvalue UDPLITE_SEND_CSCOV + */ +const UDPLITE_SEND_CSCOV = UNKNOWN; +#endif +#if defined(UDPLITE_RECV_CSCOV) +/** + * @var int + * @cvalue UDPLITE_RECV_CSCOV + */ +const UDPLITE_RECV_CSCOV = UNKNOWN; +#endif /** * @strict-properties diff --git a/ext/sockets/sockets_arginfo.h b/ext/sockets/sockets_arginfo.h index 4171018b188a9..ae9334d6b6743 100644 --- a/ext/sockets/sockets_arginfo.h +++ b/ext/sockets/sockets_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 4fb48cdd2188e8834fd2210027adc1072e885d6e */ + * Stub hash: a64427da8198261f528a38c5bf90c673eb5b8282 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_socket_select, 0, 4, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1) @@ -340,6 +340,9 @@ static void register_sockets_symbols(int module_number) REGISTER_LONG_CONSTANT("AF_INET", AF_INET, CONST_PERSISTENT); #if HAVE_IPV6 REGISTER_LONG_CONSTANT("AF_INET6", AF_INET6, CONST_PERSISTENT); +#endif +#if defined(AF_DIVERT) + REGISTER_LONG_CONSTANT("AF_DIVERT", AF_DIVERT, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SOCK_STREAM", SOCK_STREAM, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOCK_DGRAM", SOCK_DGRAM, CONST_PERSISTENT); @@ -388,6 +391,9 @@ static void register_sockets_symbols(int module_number) REGISTER_LONG_CONSTANT("SO_REUSEADDR", SO_REUSEADDR, CONST_PERSISTENT); #if defined(SO_REUSEPORT) REGISTER_LONG_CONSTANT("SO_REUSEPORT", SO_REUSEPORT, CONST_PERSISTENT); +#endif +#if defined(SO_REUSEPORT_LB) + REGISTER_LONG_CONSTANT("SO_REUSEPORT_LB", SO_REUSEPORT_LB, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SO_KEEPALIVE", SO_KEEPALIVE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_DONTROUTE", SO_DONTROUTE, CONST_PERSISTENT); @@ -429,6 +435,15 @@ static void register_sockets_symbols(int module_number) #if defined(SO_ACCEPTFILTER) REGISTER_LONG_CONSTANT("SO_ACCEPTFILTER", SO_ACCEPTFILTER, CONST_PERSISTENT); #endif +#if defined(SO_RERROR) + REGISTER_LONG_CONSTANT("SO_RERROR", SO_RERROR, CONST_PERSISTENT); +#endif +#if defined(SO_SOPLICE) + REGISTER_LONG_CONSTANT("SO_SPLICE", SO_SPLICE, CONST_PERSISTENT); +#endif +#if defined(SO_ZEROIZE) + REGISTER_LONG_CONSTANT("SO_ZEROIZE", SO_ZEROIZE, CONST_PERSISTENT); +#endif #if defined(SOL_FILTER) REGISTER_LONG_CONSTANT("SOL_FILTER", SOL_FILTER, CONST_PERSISTENT); #endif @@ -561,6 +576,9 @@ static void register_sockets_symbols(int module_number) REGISTER_LONG_CONSTANT("IP_MULTICAST_IF", IP_MULTICAST_IF, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IP_MULTICAST_TTL", IP_MULTICAST_TTL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP, CONST_PERSISTENT); +#if defined(IP_BIND_ADDRESS_NO_PORT) + REGISTER_LONG_CONSTANT("IP_BIND_ADDRESS_NO_PORT", IP_BIND_ADDRESS_NO_PORT, CONST_PERSISTENT); +#endif #if HAVE_IPV6 REGISTER_LONG_CONSTANT("IPV6_MULTICAST_IF", IPV6_MULTICAST_IF, CONST_PERSISTENT); #endif @@ -912,6 +930,9 @@ static void register_sockets_symbols(int module_number) #endif REGISTER_LONG_CONSTANT("SOL_TCP", IPPROTO_TCP, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOL_UDP", IPPROTO_UDP, CONST_PERSISTENT); +#if defined(IPPROTO_UDPLITE) + REGISTER_LONG_CONSTANT("SOL_UDPLITE", IPPROTO_UDPLITE, CONST_PERSISTENT); +#endif #if HAVE_IPV6 REGISTER_LONG_CONSTANT("IPV6_UNICAST_HOPS", IPV6_UNICAST_HOPS, CONST_PERSISTENT); #endif @@ -988,6 +1009,42 @@ static void register_sockets_symbols(int module_number) #if defined(SO_DETACH_BPF) REGISTER_LONG_CONSTANT("SO_DETACH_BPF", SO_DETACH_BPF, CONST_PERSISTENT); #endif +#if defined(TCP_QUICKACK) + REGISTER_LONG_CONSTANT("TCP_QUICKACK", TCP_QUICKACK, CONST_PERSISTENT); +#endif +#if defined(TCP_REPAIR) + REGISTER_LONG_CONSTANT("TCP_REPAIR", TCP_REPAIR, CONST_PERSISTENT); +#endif +#if defined(IP_DONTFRAG) + REGISTER_LONG_CONSTANT("IP_DONTFRAG", IP_DONTFRAG, CONST_PERSISTENT); +#endif +#if defined(IP_MTU_DISCOVER) + REGISTER_LONG_CONSTANT("IP_MTU_DISCOVER", IP_MTU_DISCOVER, CONST_PERSISTENT); +#endif +#if defined(IP_PMTUDISC_DO) + REGISTER_LONG_CONSTANT("IP_PMTUDISC_DO", IP_PMTUDISC_DO, CONST_PERSISTENT); +#endif +#if defined(IP_PMTUDISC_DONT) + REGISTER_LONG_CONSTANT("IP_PMTUDISC_DONT", IP_PMTUDISC_DONT, CONST_PERSISTENT); +#endif +#if defined(IP_PMTUDISC_WANT) + REGISTER_LONG_CONSTANT("IP_PMTUDISC_WANT", IP_PMTUDISC_WANT, CONST_PERSISTENT); +#endif +#if defined(IP_PMTUDISC_PROBE) + REGISTER_LONG_CONSTANT("IP_PMTUDISC_PROBE", IP_PMTUDISC_PROBE, CONST_PERSISTENT); +#endif +#if defined(IP_PMTUDISC_INTERFACE) + REGISTER_LONG_CONSTANT("IP_PMTUDISC_INTERFACE", IP_PMTUDISC_INTERFACE, CONST_PERSISTENT); +#endif +#if defined(IP_PMTUDISC_OMIT) + REGISTER_LONG_CONSTANT("IP_PMTUDISC_OMIT", IP_PMTUDISC_OMIT, CONST_PERSISTENT); +#endif +#if defined(UDPLITE_SEND_CSCOV) + REGISTER_LONG_CONSTANT("UDPLITE_SEND_CSCOV", UDPLITE_SEND_CSCOV, CONST_PERSISTENT); +#endif +#if defined(UDPLITE_RECV_CSCOV) + REGISTER_LONG_CONSTANT("UDPLITE_RECV_CSCOV", UDPLITE_RECV_CSCOV, CONST_PERSISTENT); +#endif } static zend_class_entry *register_class_Socket(void) diff --git a/ext/sockets/tests/socket_dontfragment.phpt b/ext/sockets/tests/socket_dontfragment.phpt new file mode 100644 index 0000000000000..c4c62976bcade --- /dev/null +++ b/ext/sockets/tests/socket_dontfragment.phpt @@ -0,0 +1,19 @@ +--TEST-- +IP_MTU_DISCOVER test +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) diff --git a/ext/sockets/tests/socket_dontfragment_bsd.phpt b/ext/sockets/tests/socket_dontfragment_bsd.phpt new file mode 100644 index 0000000000000..b9c927cb87846 --- /dev/null +++ b/ext/sockets/tests/socket_dontfragment_bsd.phpt @@ -0,0 +1,19 @@ +--TEST-- +IP_DONTFRAG test +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) diff --git a/ext/sodium/sodium_pwhash.c b/ext/sodium/sodium_pwhash.c index 8eaac64207f5f..45e206bcd9435 100644 --- a/ext/sodium/sodium_pwhash.c +++ b/ext/sodium/sodium_pwhash.c @@ -171,7 +171,7 @@ static const php_password_algo sodium_algo_argon2id = { }; PHP_MINIT_FUNCTION(sodium_password_hash) /* {{{ */ { - zend_string *argon2i = zend_string_init("argon2i", strlen("argon2i"), 1); + zend_string *argon2i = ZSTR_INIT_LITERAL("argon2i", 1); if (php_password_algo_find(argon2i)) { /* Nothing to do. Core has registered these algorithms for us. */ diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 4357c9d16b52f..b91af068779d9 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -74,12 +74,13 @@ PHP_FUNCTION(class_parents) zend_class_entry *parent_class, *ce; bool autoload = 1; + /* We do not use Z_PARAM_OBJ_OR_STR here to be able to exclude int, float, and bool which are bogus class names */ if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &obj, &autoload) == FAILURE) { RETURN_THROWS(); } if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) { - zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(obj)); + zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_value_name(obj)); RETURN_THROWS(); } @@ -107,11 +108,12 @@ PHP_FUNCTION(class_implements) bool autoload = 1; zend_class_entry *ce; + /* We do not use Z_PARAM_OBJ_OR_STR here to be able to exclude int, float, and bool which are bogus class names */ if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &obj, &autoload) == FAILURE) { RETURN_THROWS(); } if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) { - zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(obj)); + zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_value_name(obj)); RETURN_THROWS(); } @@ -135,11 +137,12 @@ PHP_FUNCTION(class_uses) bool autoload = 1; zend_class_entry *ce; + /* We do not use Z_PARAM_OBJ_OR_STR here to be able to exclude int, float, and bool which are bogus class names */ if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &obj, &autoload) == FAILURE) { RETURN_THROWS(); } if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) { - zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(obj)); + zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_value_name(obj)); RETURN_THROWS(); } diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 4098382c61c17..1ef0c48d272d6 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -12,7 +12,7 @@ +----------------------------------------------------------------------+ | Authors: Marcus Boerger | +----------------------------------------------------------------------+ - */ +*/ #ifdef HAVE_CONFIG_H # include "config.h" @@ -28,7 +28,6 @@ #include "php_spl.h" #include "spl_functions.h" -#include "spl_engine.h" #include "spl_iterators.h" #include "spl_array.h" #include "spl_array_arginfo.h" @@ -46,6 +45,8 @@ typedef struct _spl_array_object { uint32_t ht_iter; int ar_flags; unsigned char nApplyCount; + bool is_child; + Bucket *bucket; zend_function *fptr_offset_get; zend_function *fptr_offset_set; zend_function *fptr_offset_has; @@ -55,6 +56,11 @@ typedef struct _spl_array_object { zend_object std; } spl_array_object; +typedef struct _spl_array_iterator { + zend_object_iterator it; + bool by_ref; +} spl_array_iterator; + static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ { return (spl_array_object*)((char*)(obj) - XtOffsetOf(spl_array_object, std)); } @@ -89,6 +95,21 @@ static inline HashTable **spl_array_get_hash_table_ptr(spl_array_object* intern) } /* }}} */ +static void spl_array_illegal_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s on ArrayObject", zend_get_type_by_const(Z_TYPE_P(offset))); +} + +static void spl_array_illegal_empty_or_isset_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s in isset or empty", zend_get_type_by_const(Z_TYPE_P(offset))); +} + +static void spl_array_illegal_unset_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s in unset", zend_get_type_by_const(Z_TYPE_P(offset))); +} + static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /* {{{ */ return *spl_array_get_hash_table_ptr(intern); } @@ -150,6 +171,8 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zend_o object_properties_init(&intern->std, class_type); intern->ar_flags = 0; + intern->is_child = false; + intern->bucket = NULL; intern->ce_get_iterator = spl_ce_ArrayIterator; if (orig) { spl_array_object *other = spl_array_from_obj(orig); @@ -286,7 +309,7 @@ static zend_result get_hash_key(spl_hash_key *key, spl_array_object *intern, zva ZVAL_DEREF(offset); goto try_again; default: - zend_type_error("Illegal offset type"); + spl_array_illegal_offset(offset); return FAILURE; } @@ -313,7 +336,7 @@ static zval *spl_array_get_dimension_ptr(int check_inherited, spl_array_object * } if (get_hash_key(&key, intern, offset) == FAILURE) { - zend_type_error("Illegal offset type"); + spl_array_illegal_offset(offset); return (type == BP_VAR_W || type == BP_VAR_RW) ? &EG(error_zval) : &EG(uninitialized_zval); } @@ -436,6 +459,22 @@ static zval *spl_array_read_dimension(zend_object *object, zval *offset, int typ return spl_array_read_dimension_ex(1, object, offset, type, rv); } /* }}} */ +/* + * The assertion(HT_ASSERT_RC1(ht)) failed because the refcount was increased manually when intern->is_child is true. + * We have to set the refcount to 1 to make assertion success and restore the refcount to the original value after + * modifying the array when intern->is_child is true. + */ +static uint32_t spl_array_set_refcount(bool is_child, HashTable *ht, uint32_t refcount) /* {{{ */ +{ + uint32_t old_refcount = 0; + if (is_child) { + old_refcount = GC_REFCOUNT(ht); + GC_SET_REFCOUNT(ht, refcount); + } + + return old_refcount; +} /* }}} */ + static void spl_array_write_dimension_ex(int check_inherited, zend_object *object, zval *offset, zval *value) /* {{{ */ { spl_array_object *intern = spl_array_from_obj(object); @@ -459,25 +498,37 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec } Z_TRY_ADDREF_P(value); + + uint32_t refcount = 0; if (!offset || Z_TYPE_P(offset) == IS_NULL) { ht = spl_array_get_hash_table(intern); + refcount = spl_array_set_refcount(intern->is_child, ht, 1); zend_hash_next_index_insert(ht, value); + + if (refcount) { + spl_array_set_refcount(intern->is_child, ht, refcount); + } return; } if (get_hash_key(&key, intern, offset) == FAILURE) { - zend_type_error("Illegal offset type"); + spl_array_illegal_offset(offset); zval_ptr_dtor(value); return; } ht = spl_array_get_hash_table(intern); + refcount = spl_array_set_refcount(intern->is_child, ht, 1); if (key.key) { zend_hash_update_ind(ht, key.key, value); spl_hash_key_release(&key); } else { zend_hash_index_update(ht, key.h, value); } + + if (refcount) { + spl_array_set_refcount(intern->is_child, ht, refcount); + } } /* }}} */ static void spl_array_write_dimension(zend_object *object, zval *offset, zval *value) /* {{{ */ @@ -502,11 +553,13 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec } if (get_hash_key(&key, intern, offset) == FAILURE) { - zend_type_error("Illegal offset type in unset"); + spl_array_illegal_unset_offset(offset); return; } ht = spl_array_get_hash_table(intern); + uint32_t refcount = spl_array_set_refcount(intern->is_child, ht, 1); + if (key.key) { zval *data = zend_hash_find(ht, key.key); if (data) { @@ -529,6 +582,10 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec } else { zend_hash_index_del(ht, key.h); } + + if (refcount) { + spl_array_set_refcount(intern->is_child, ht, refcount); + } } /* }}} */ static void spl_array_unset_dimension(zend_object *object, zval *offset) /* {{{ */ @@ -566,7 +623,7 @@ static bool spl_array_has_dimension_ex(bool check_inherited, zend_object *object spl_hash_key key; if (get_hash_key(&key, intern, offset) == FAILURE) { - zend_type_error("Illegal offset type in isset or empty"); + spl_array_illegal_empty_or_isset_offset(offset); return 0; } @@ -926,12 +983,35 @@ static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */ static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */ { + spl_array_iterator *array_iter = (spl_array_iterator*)iter; spl_array_object *object = Z_SPLARRAY_P(&iter->data); HashTable *aht = spl_array_get_hash_table(object); zval *data = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, object)); if (data && Z_TYPE_P(data) == IS_INDIRECT) { data = Z_INDIRECT_P(data); } + // ZEND_FE_FETCH_RW converts the value to a reference but doesn't know the source is a property. + // Typed properties must add a type source to the reference, and readonly properties must fail. + if (array_iter->by_ref + && Z_TYPE_P(data) != IS_REFERENCE + && Z_TYPE(object->array) == IS_OBJECT + && !(object->ar_flags & (SPL_ARRAY_IS_SELF|SPL_ARRAY_USE_OTHER))) { + zend_string *key; + zend_hash_get_current_key_ex(aht, &key, NULL, spl_array_get_pos_ptr(aht, object)); + zend_class_entry *ce = Z_OBJCE(object->array); + zend_property_info *prop_info = zend_get_property_info(ce, key, true); + ZEND_ASSERT(prop_info != ZEND_WRONG_PROPERTY_INFO); + if (EXPECTED(prop_info != NULL) && ZEND_TYPE_IS_SET(prop_info->type)) { + if (prop_info->flags & ZEND_ACC_READONLY) { + zend_throw_error(NULL, + "Cannot acquire reference to readonly property %s::$%s", + ZSTR_VAL(prop_info->ce->name), ZSTR_VAL(key)); + return NULL; + } + ZVAL_NEW_REF(data, data); + ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), prop_info); + } + } return data; } /* }}} */ @@ -990,6 +1070,16 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar } else { //??? TODO: try to avoid array duplication ZVAL_ARR(&intern->array, zend_array_dup(Z_ARR_P(array))); + + if (intern->is_child) { + Z_TRY_DELREF_P(&intern->bucket->val); + /* + * replace bucket->val with copied array, so the changes between + * parent and child object can affect each other. + */ + intern->bucket->val = intern->array; + Z_TRY_ADDREF_P(&intern->array); + } } } else { if (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator) { @@ -1039,15 +1129,16 @@ static const zend_object_iterator_funcs spl_array_it_funcs = { spl_array_it_get_gc, }; -zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ +static zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ { - zend_object_iterator *iterator = emalloc(sizeof(zend_object_iterator)); - zend_iterator_init(iterator); + spl_array_iterator *iterator = emalloc(sizeof(spl_array_iterator)); + zend_iterator_init(&iterator->it); - ZVAL_OBJ_COPY(&iterator->data, Z_OBJ_P(object)); - iterator->funcs = &spl_array_it_funcs; + ZVAL_OBJ_COPY(&iterator->it.data, Z_OBJ_P(object)); + iterator->it.funcs = &spl_array_it_funcs; + iterator->by_ref = by_ref; - return iterator; + return &iterator->it; } /* }}} */ @@ -1465,6 +1556,22 @@ PHP_METHOD(RecursiveArrayIterator, hasChildren) } /* }}} */ +static void spl_instantiate_child_arg(zend_class_entry *pce, zval *retval, zval *arg1, zval *arg2) /* {{{ */ +{ + object_init_ex(retval, pce); + spl_array_object *new_intern = Z_SPLARRAY_P(retval); + /* + * set new_intern->is_child is true to indicate that the object was created by + * RecursiveArrayIterator::getChildren() method. + */ + new_intern->is_child = true; + + /* find the bucket of parent object. */ + new_intern->bucket = (Bucket *)((char *)(arg1) - XtOffsetOf(Bucket, val));; + zend_call_known_instance_method_with_2_params(pce->constructor, Z_OBJ_P(retval), NULL, arg1, arg2); +} +/* }}} */ + /* {{{ Create a sub iterator for the current element (same class as $this) */ PHP_METHOD(RecursiveArrayIterator, getChildren) { @@ -1495,7 +1602,7 @@ PHP_METHOD(RecursiveArrayIterator, getChildren) } ZVAL_LONG(&flags, intern->ar_flags); - spl_instantiate_arg_ex2(Z_OBJCE_P(ZEND_THIS), return_value, entry, &flags); + spl_instantiate_child_arg(Z_OBJCE_P(ZEND_THIS), return_value, entry, &flags); } /* }}} */ diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 5c32e2f9ee359..029edcdfb21de 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -695,7 +695,7 @@ static inline HashTable *spl_filesystem_object_get_debug_info(zend_object *objec } /* }}} */ -zend_function *spl_filesystem_object_get_method_check(zend_object **object, zend_string *method, const zval *key) /* {{{ */ +static zend_function *spl_filesystem_object_get_method_check(zend_object **object, zend_string *method, const zval *key) /* {{{ */ { spl_filesystem_object *fsobj = spl_filesystem_from_obj(*object); @@ -711,7 +711,7 @@ zend_function *spl_filesystem_object_get_method_check(zend_object **object, zend #define DIT_CTOR_FLAGS 0x00000001 #define DIT_CTOR_GLOB 0x00000002 -void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, zend_long ctor_flags) /* {{{ */ +static void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, zend_long ctor_flags) /* {{{ */ { spl_filesystem_object *intern; zend_string *path; @@ -1637,7 +1637,7 @@ static const zend_object_iterator_funcs spl_filesystem_dir_it_funcs = { /* }}} */ /* {{{ spl_ce_dir_get_iterator */ -zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref) +static zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref) { spl_filesystem_iterator *iterator; spl_filesystem_object *dir_object; @@ -1830,7 +1830,7 @@ static const zend_object_iterator_funcs spl_filesystem_tree_it_funcs = { /* }}} */ /* {{{ spl_ce_dir_get_iterator */ -zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref) +static zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref) { spl_filesystem_iterator *iterator; spl_filesystem_object *dir_object; @@ -1964,7 +1964,7 @@ static zend_result spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesys if (Z_TYPE(retval) != IS_STRING) { zend_type_error("%s::getCurrentLine(): Return value must be of type string, %s returned", - ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), zend_zval_type_name(&retval)); + ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), zend_zval_value_name(&retval)); zval_ptr_dtor(&retval); return FAILURE; } @@ -2074,14 +2074,14 @@ PHP_METHOD(SplTempFileObject, __construct) } if (max_memory < 0) { - file_name = zend_string_init("php://memory", sizeof("php://memory")-1, 0); + file_name = ZSTR_INIT_LITERAL("php://memory", 0); } else if (ZEND_NUM_ARGS()) { file_name = zend_strpprintf(0, "php://temp/maxmemory:" ZEND_LONG_FMT, max_memory); } else { - file_name = zend_string_init("php://temp", sizeof("php://temp")-1, 0); + file_name = ZSTR_INIT_LITERAL("php://temp", 0); } intern->file_name = file_name; - intern->u.file.open_mode = zend_string_init("wb", sizeof("wb")-1, 0); + intern->u.file.open_mode = ZSTR_INIT_LITERAL("wb", 0); /* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling); diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index a3c17d59668c0..176989936ed8f 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -1223,7 +1223,7 @@ static const zend_object_iterator_funcs spl_dllist_it_funcs = { NULL, /* get_gc */ }; /* }}} */ -zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ +static zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ { spl_dllist_object *dllist_object = Z_SPLDLLIST_P(object); diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 465c649e980aa..574b06fc4e93c 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -83,6 +83,11 @@ static bool spl_fixedarray_empty(spl_fixedarray *array) return true; } +static void spl_fixedarray_illegal_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s on FixedArray", zend_get_type_by_const(Z_TYPE_P(offset))); +} + static void spl_fixedarray_default_ctor(spl_fixedarray *array) { array->size = 0; @@ -333,7 +338,7 @@ static zend_long spl_offset_convert_to_long(zval *offset) /* {{{ */ return Z_RES_HANDLE_P(offset); } - zend_type_error("Illegal offset type"); + spl_fixedarray_illegal_offset(offset); return 0; } @@ -581,8 +586,8 @@ PHP_METHOD(SplFixedArray, __serialize) RETURN_THROWS(); } - uint32_t num_properties = - intern->std.properties ? zend_hash_num_elements(intern->std.properties) : 0; + HashTable *ht = zend_std_get_properties(&intern->std); + uint32_t num_properties = zend_hash_num_elements(ht); array_init_size(return_value, intern->array.size + num_properties); /* elements */ @@ -593,12 +598,15 @@ PHP_METHOD(SplFixedArray, __serialize) } /* members */ - if (intern->std.properties) { - ZEND_HASH_FOREACH_STR_KEY_VAL(intern->std.properties, key, current) { - zend_hash_add(Z_ARRVAL_P(return_value), key, current); + ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, key, current) { + /* If the properties table was already rebuild, it will also contain the + * array elements. The array elements are already added in the above loop. + * We can detect array elements by the fact that their key == NULL. */ + if (key != NULL) { + zend_hash_add_new(Z_ARRVAL_P(return_value), key, current); Z_TRY_ADDREF_P(current); - } ZEND_HASH_FOREACH_END(); - } + } + } ZEND_HASH_FOREACH_END(); } PHP_METHOD(SplFixedArray, __unserialize) @@ -922,7 +930,7 @@ static const zend_object_iterator_funcs spl_fixedarray_it_funcs = { NULL, /* get_gc */ }; -zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref) +static zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref) { spl_fixedarray_it *iterator; diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 64fe962ee2de3..d781ff4ca010d 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -121,7 +121,7 @@ static void spl_ptr_heap_pqueue_elem_ctor(void *elem) { /* {{{ */ } /* }}} */ -static int spl_ptr_heap_cmp_cb_helper(zval *object, spl_heap_object *heap_object, zval *a, zval *b, zend_long *result) { /* {{{ */ +static zend_result spl_ptr_heap_cmp_cb_helper(zval *object, spl_heap_object *heap_object, zval *a, zval *b, zend_long *result) { /* {{{ */ zval zresult; zend_call_method_with_2_params(Z_OBJ_P(object), heap_object->std.ce, &heap_object->fptr_cmp, "compare", &zresult, a, b); @@ -247,7 +247,7 @@ static int spl_ptr_pqueue_elem_cmp_long(void *x, void *y, zval *object) { static int spl_ptr_pqueue_elem_cmp_double(void *x, void *y, zval *object) { double a = Z_DVAL(((spl_pqueue_elem*) x)->priority); double b = Z_DVAL(((spl_pqueue_elem*) y)->priority); - return ZEND_NORMALIZE_BOOL(a - b); + return ZEND_THREEWAY_COMPARE(a, b); } static spl_ptr_heap *spl_ptr_heap_init(spl_ptr_heap_cmp_func cmp, spl_ptr_heap_ctor_func ctor, spl_ptr_heap_dtor_func dtor, size_t elem_size) /* {{{ */ @@ -302,7 +302,7 @@ static void *spl_ptr_heap_top(spl_ptr_heap *heap) { /* {{{ */ } /* }}} */ -static int spl_ptr_heap_delete_top(spl_ptr_heap *heap, void *elem, void *cmp_userdata) { /* {{{ */ +static zend_result spl_ptr_heap_delete_top(spl_ptr_heap *heap, void *elem, void *cmp_userdata) { /* {{{ */ int i, j; const int limit = (heap->count-1)/2; void *bottom; @@ -1085,7 +1085,7 @@ static const zend_object_iterator_funcs spl_pqueue_it_funcs = { NULL, /* get_gc */ }; -zend_object_iterator *spl_heap_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ +static zend_object_iterator *spl_heap_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ { if (by_ref) { zend_throw_error(NULL, "An iterator cannot be used with foreach by reference"); @@ -1104,7 +1104,7 @@ zend_object_iterator *spl_heap_get_iterator(zend_class_entry *ce, zval *object, } /* }}} */ -zend_object_iterator *spl_pqueue_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ +static zend_object_iterator *spl_pqueue_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ { if (by_ref) { zend_throw_error(NULL, "An iterator cannot be used with foreach by reference"); diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 39791039b1d83..4fcf2b8872722 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -514,7 +514,7 @@ static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, return (zend_object_iterator*)iterator; } -static int spl_get_iterator_from_aggregate(zval *retval, zend_class_entry *ce, zend_object *obj) { +static zend_result spl_get_iterator_from_aggregate(zval *retval, zend_class_entry *ce, zend_object *obj) { zend_function **getiterator_cache = ce->iterator_funcs_ptr ? &ce->iterator_funcs_ptr->zf_new_iterator : NULL; zend_call_method_with_0_params(obj, ce, getiterator_cache, "getiterator", retval); @@ -1001,10 +1001,10 @@ static zend_object *spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class if (init_prefix) { intern->prefix[0] = ZSTR_EMPTY_ALLOC(); - intern->prefix[1] = zend_string_init("| ", 2, 0); - intern->prefix[2] = zend_string_init(" ", 2, 0); - intern->prefix[3] = zend_string_init("|-", 2, 0); - intern->prefix[4] = zend_string_init("\\-", 2, 0); + intern->prefix[1] = ZSTR_INIT_LITERAL("| ", 0); + intern->prefix[2] = ZSTR_INIT_LITERAL(" ", 0); + intern->prefix[3] = ZSTR_INIT_LITERAL("|-", 0); + intern->prefix[4] = ZSTR_INIT_LITERAL("\\-", 0); intern->prefix[5] = ZSTR_EMPTY_ALLOC(); intern->postfix[0] = ZSTR_EMPTY_ALLOC(); @@ -1301,9 +1301,9 @@ static zend_function *spl_dual_it_get_method(zend_object **object, zend_string * #define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator) -static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more); +static inline zend_result spl_dual_it_fetch(spl_dual_it_object *intern, int check_more); -static inline int spl_cit_check_flags(zend_long flags) +static inline zend_result spl_cit_check_flags(zend_long flags) { zend_long cnt = 0; @@ -1542,7 +1542,7 @@ static inline int spl_dual_it_valid(spl_dual_it_object *intern) return intern->inner.iterator->funcs->valid(intern->inner.iterator); } -static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more) +static inline zend_result spl_dual_it_fetch(spl_dual_it_object *intern, int check_more) { zval *data; @@ -1822,6 +1822,8 @@ PHP_METHOD(CallbackFilterIterator, accept) zend_call_known_fcc(fcc, return_value, 3, params, NULL); if (Z_ISUNDEF_P(return_value)) { RETURN_FALSE; + } else if (Z_ISREF_P(return_value)) { + zend_unwrap_reference(return_value); } } /* }}} */ @@ -2874,7 +2876,7 @@ PHP_METHOD(EmptyIterator, next) } } /* }}} */ -int spl_append_it_next_iterator(spl_dual_it_object *intern) /* {{{*/ +zend_result spl_append_it_next_iterator(spl_dual_it_object *intern) /* {{{*/ { spl_dual_it_free(intern); @@ -2901,7 +2903,7 @@ int spl_append_it_next_iterator(spl_dual_it_object *intern) /* {{{*/ } } /* }}} */ -void spl_append_it_fetch(spl_dual_it_object *intern) /* {{{*/ +static void spl_append_it_fetch(spl_dual_it_object *intern) /* {{{*/ { while (spl_dual_it_valid(intern) != SUCCESS) { intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator); @@ -2912,7 +2914,7 @@ void spl_append_it_fetch(spl_dual_it_object *intern) /* {{{*/ spl_dual_it_fetch(intern, 0); } /* }}} */ -void spl_append_it_next(spl_dual_it_object *intern) /* {{{ */ +static void spl_append_it_next(spl_dual_it_object *intern) /* {{{ */ { if (spl_dual_it_valid(intern) == SUCCESS) { spl_dual_it_next(intern, 1); @@ -3051,7 +3053,7 @@ PHP_METHOD(AppendIterator, getArrayIterator) RETURN_COPY_DEREF(value); } /* }}} */ -PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser) +PHPAPI zend_result spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser) { zend_object_iterator *iter; zend_class_entry *ce = Z_OBJCE_P(obj); diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h index d8d50862a26fc..3c78bb97bf8c0 100644 --- a/ext/spl/spl_iterators.h +++ b/ext/spl/spl_iterators.h @@ -114,6 +114,6 @@ typedef enum { typedef int (*spl_iterator_apply_func_t)(zend_object_iterator *iter, void *puser); -PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser); +PHPAPI zend_result spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser); #endif /* SPL_ITERATORS_H */ diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index ce7852618f875..b996764c1aca1 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -173,7 +173,7 @@ static spl_SplObjectStorageElement *spl_object_storage_attach_handle(spl_SplObje return pelement; } /* }}} */ -spl_SplObjectStorageElement *spl_object_storage_attach(spl_SplObjectStorage *intern, zend_object *obj, zval *inf) /* {{{ */ +static spl_SplObjectStorageElement *spl_object_storage_attach(spl_SplObjectStorage *intern, zend_object *obj, zval *inf) /* {{{ */ { if (EXPECTED(!(intern->flags & SOS_OVERRIDDEN_WRITE_DIMENSION))) { return spl_object_storage_attach_handle(intern, obj, inf); @@ -238,7 +238,7 @@ static zend_result spl_object_storage_detach(spl_SplObjectStorage *intern, zend_ return ret; } /* }}}*/ -void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorage *other) { /* {{{ */ +static void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorage *other) { /* {{{ */ spl_SplObjectStorageElement *element; ZEND_HASH_FOREACH_PTR(&other->storage, element) { @@ -406,7 +406,7 @@ static zend_object *spl_SplObjectStorage_new(zend_class_entry *class_type) /* }}} */ /* Returns true if the SplObjectStorage contains an entry for getHash(obj), even if the corresponding value is null. */ -bool spl_object_storage_contains(spl_SplObjectStorage *intern, zend_object *obj) /* {{{ */ +static bool spl_object_storage_contains(spl_SplObjectStorage *intern, zend_object *obj) /* {{{ */ { if (EXPECTED(!intern->fptr_get_hash)) { return zend_hash_index_find(&intern->storage, obj->handle) != NULL; diff --git a/ext/spl/tests/ArrayObject_illegal_offset.phpt b/ext/spl/tests/ArrayObject_illegal_offset.phpt index df25e4fa5e0fa..08353c704c6f3 100644 --- a/ext/spl/tests/ArrayObject_illegal_offset.phpt +++ b/ext/spl/tests/ArrayObject_illegal_offset.phpt @@ -32,8 +32,8 @@ try { ?> --EXPECT-- -Illegal offset type -Illegal offset type -Illegal offset type -Illegal offset type in isset or empty -Illegal offset type in unset +Cannot access offset of type array on ArrayObject +Cannot access offset of type array on ArrayObject +Cannot access offset of type array on ArrayObject +Cannot access offset of type array in isset or empty +Cannot access offset of type array in unset diff --git a/ext/spl/tests/SplFixedArray_get_properties_for.phpt b/ext/spl/tests/SplFixedArray_get_properties_for.phpt index 24fa4bf1ae058..40130b9d5ec75 100644 --- a/ext/spl/tests/SplFixedArray_get_properties_for.phpt +++ b/ext/spl/tests/SplFixedArray_get_properties_for.phpt @@ -71,16 +71,15 @@ array(3) { } } [{},{}] -O:15:"MySplFixedArray":5:{i:0;O:8:"stdClass":0:{}i:1;O:1:"Y":0:{}s:1:"x";i:0;s:1:"y";i:0;s:1:"0";O:1:"X":0:{}} -object(MySplFixedArray)#6 (4) { +O:15:"MySplFixedArray":4:{i:0;O:8:"stdClass":0:{}i:1;O:1:"Y":0:{}s:1:"x";O:13:"SplFixedArray":0:{}s:1:"0";O:1:"X":0:{}} +object(MySplFixedArray)#6 (3) { [0]=> - object(X)#9 (0) { + object(X)#10 (0) { } [1]=> object(Y)#8 (0) { } ["x"]=> - int(0) - ["y"]=> - int(0) + object(SplFixedArray)#9 (0) { + } } diff --git a/ext/spl/tests/array_026.phpt b/ext/spl/tests/array_026.phpt index 268b39d5e8edd..4ebd0ed925740 100644 --- a/ext/spl/tests/array_026.phpt +++ b/ext/spl/tests/array_026.phpt @@ -10,7 +10,7 @@ var_dump($test, $test3['mmmmm']); --EXPECTF-- Warning: Undefined variable $test3 in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d object(ArrayObject)#1 (1) { ["storage":"ArrayObject":private]=> array(1) { diff --git a/ext/spl/tests/bug42654.phpt b/ext/spl/tests/bug42654.phpt index 20aad74b73423..eb72863e08759 100644 --- a/ext/spl/tests/bug42654.phpt +++ b/ext/spl/tests/bug42654.phpt @@ -110,11 +110,11 @@ object(RecursiveArrayIterator)#%d (1) { [2]=> array(2) { [2]=> - string(4) "val2" + string(5) "alter" [3]=> array(1) { [3]=> - string(4) "val3" + string(5) "alter" } } [4]=> @@ -129,11 +129,11 @@ object(RecursiveArrayIterator)#%d (1) { [2]=> array(2) { [2]=> - string(4) "val2" + string(5) "alter" [3]=> array(1) { [3]=> - string(4) "val3" + string(5) "alter" } } [4]=> @@ -146,11 +146,11 @@ array(3) { [2]=> array(2) { [2]=> - string(4) "val2" + string(5) "alter" [3]=> array(1) { [3]=> - string(4) "val3" + string(5) "alter" } } [4]=> diff --git a/ext/spl/tests/bug42654_2.phpt b/ext/spl/tests/bug42654_2.phpt new file mode 100644 index 0000000000000..bd290247dbdc4 --- /dev/null +++ b/ext/spl/tests/bug42654_2.phpt @@ -0,0 +1,33 @@ +--TEST-- +Bug #42654 (RecursiveIteratorIterator modifies only part of leaves) +--FILE-- + 'val1', array('key2' => 'val2'), 'key3' => 'val3'); + +$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($data)); +foreach($iterator as $foo) { + $key = $iterator->key(); + switch($key) { + case 'key1': // first level + case 'key2': // recursive level + echo "update $key".PHP_EOL; + $iterator->offsetSet($key, 'alter'); + } +} +$copy = $iterator->getArrayCopy(); +var_dump($copy); +?> +--EXPECT-- +update key1 +update key2 +array(3) { + ["key1"]=> + string(5) "alter" + [0]=> + array(1) { + ["key2"]=> + string(5) "alter" + } + ["key3"]=> + string(4) "val3" +} diff --git a/ext/spl/tests/bug62978.phpt b/ext/spl/tests/bug62978.phpt index 073530926a6f1..758649e231692 100644 --- a/ext/spl/tests/bug62978.phpt +++ b/ext/spl/tests/bug62978.phpt @@ -34,7 +34,7 @@ NULL Warning: Undefined variable $c in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d NULL Warning: Undefined array key "epic_magic" in %s on line %d diff --git a/ext/spl/tests/bug73029.phpt b/ext/spl/tests/bug73029.phpt index 5c3cd8420da8d..771e81d5c4d45 100644 --- a/ext/spl/tests/bug73029.phpt +++ b/ext/spl/tests/bug73029.phpt @@ -3,6 +3,13 @@ Bug #73029: Missing type check when unserializing SplArray --FILE-- getMessage() . "\n"; +} +try { $a = 'C:11:"ArrayObject":19:0x:i:0;r:2;;m:a:0:{}}'; $m = unserialize($a); $x = $m[2]; @@ -11,6 +18,10 @@ $x = $m[2]; } ?> DONE ---EXPECT-- +--EXPECTF-- Error at offset 10 of 19 bytes + +Warning: unserialize(): Error at offset 22 of 43 bytes in %s on line %d + +Warning: Trying to access array offset on false in %s on line %d DONE diff --git a/ext/spl/tests/class_implements_variation1.phpt b/ext/spl/tests/class_implements_variation1.phpt index 2843745171bbf..1f7892f128340 100644 --- a/ext/spl/tests/class_implements_variation1.phpt +++ b/ext/spl/tests/class_implements_variation1.phpt @@ -158,16 +158,16 @@ class_implements(): Argument #1 ($object_or_class) must be of type object|string class_implements(): Argument #1 ($object_or_class) must be of type object|string, null given --lowercase true-- -class_implements(): Argument #1 ($object_or_class) must be of type object|string, bool given +class_implements(): Argument #1 ($object_or_class) must be of type object|string, true given --lowercase false-- -class_implements(): Argument #1 ($object_or_class) must be of type object|string, bool given +class_implements(): Argument #1 ($object_or_class) must be of type object|string, false given --uppercase TRUE-- -class_implements(): Argument #1 ($object_or_class) must be of type object|string, bool given +class_implements(): Argument #1 ($object_or_class) must be of type object|string, true given --uppercase FALSE-- -class_implements(): Argument #1 ($object_or_class) must be of type object|string, bool given +class_implements(): Argument #1 ($object_or_class) must be of type object|string, false given --empty string DQ-- Error: 2 - class_implements(): Class does not exist and could not be loaded, %s(%d) diff --git a/ext/spl/tests/class_uses_variation1.phpt b/ext/spl/tests/class_uses_variation1.phpt index da26b2630185a..016a9cc0d2f41 100644 --- a/ext/spl/tests/class_uses_variation1.phpt +++ b/ext/spl/tests/class_uses_variation1.phpt @@ -158,16 +158,16 @@ class_uses(): Argument #1 ($object_or_class) must be of type object|string, null class_uses(): Argument #1 ($object_or_class) must be of type object|string, null given --lowercase true-- -class_uses(): Argument #1 ($object_or_class) must be of type object|string, bool given +class_uses(): Argument #1 ($object_or_class) must be of type object|string, true given --lowercase false-- -class_uses(): Argument #1 ($object_or_class) must be of type object|string, bool given +class_uses(): Argument #1 ($object_or_class) must be of type object|string, false given --uppercase TRUE-- -class_uses(): Argument #1 ($object_or_class) must be of type object|string, bool given +class_uses(): Argument #1 ($object_or_class) must be of type object|string, true given --uppercase FALSE-- -class_uses(): Argument #1 ($object_or_class) must be of type object|string, bool given +class_uses(): Argument #1 ($object_or_class) must be of type object|string, false given --empty string DQ-- Error: 2 - class_uses(): Class does not exist and could not be loaded, %s(%d) diff --git a/ext/spl/tests/fixedarray_001.phpt b/ext/spl/tests/fixedarray_001.phpt index a6ab149c75ca5..35a7a9cf17725 100644 --- a/ext/spl/tests/fixedarray_001.phpt +++ b/ext/spl/tests/fixedarray_001.phpt @@ -46,7 +46,7 @@ var_dump($b[0]); ?> --EXPECT-- RuntimeException: Index invalid or out of range -TypeError: Illegal offset type +TypeError: Cannot access offset of type string on FixedArray RuntimeException: Index invalid or out of range string(6) "value0" string(6) "value2" diff --git a/ext/spl/tests/fixedarray_002.phpt b/ext/spl/tests/fixedarray_002.phpt index 4f6682e6df3a0..940d5996f5dbc 100644 --- a/ext/spl/tests/fixedarray_002.phpt +++ b/ext/spl/tests/fixedarray_002.phpt @@ -71,7 +71,7 @@ var_dump(count($a), $a->getSize(), count($a) == $a->getSize()); A::offsetSet RuntimeException: Index invalid or out of range A::offsetGet -TypeError: Illegal offset type +TypeError: Cannot access offset of type string on FixedArray A::offsetUnset RuntimeException: Index invalid or out of range A::offsetSet diff --git a/ext/spl/tests/fixedarray_003.phpt b/ext/spl/tests/fixedarray_003.phpt index 277088d04f045..d246561c1b7e8 100644 --- a/ext/spl/tests/fixedarray_003.phpt +++ b/ext/spl/tests/fixedarray_003.phpt @@ -168,55 +168,55 @@ try { Write context Deprecated: Implicit conversion from float 2.5 to int loses precision in %s on line %d -Illegal offset type -Illegal offset type +Cannot access offset of type array on FixedArray +Cannot access offset of type object on FixedArray Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d -Illegal offset type -Illegal offset type -Illegal offset type +Cannot access offset of type string on FixedArray +Cannot access offset of type string on FixedArray +Cannot access offset of type string on FixedArray Read context string(1) "a" string(1) "b" Deprecated: Implicit conversion from float 2.5 to int loses precision in %s on line %d string(1) "c" -Illegal offset type -Illegal offset type +Cannot access offset of type array on FixedArray +Cannot access offset of type object on FixedArray Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d string(1) "f" string(1) "g" -Illegal offset type -Illegal offset type -Illegal offset type +Cannot access offset of type string on FixedArray +Cannot access offset of type string on FixedArray +Cannot access offset of type string on FixedArray isset() bool(true) bool(true) Deprecated: Implicit conversion from float 2.5 to int loses precision in %s on line %d bool(true) -Illegal offset type -Illegal offset type +Cannot access offset of type array on FixedArray +Cannot access offset of type object on FixedArray Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d bool(true) bool(true) -Illegal offset type -Illegal offset type -Illegal offset type +Cannot access offset of type string on FixedArray +Cannot access offset of type string on FixedArray +Cannot access offset of type string on FixedArray empty() bool(false) bool(false) Deprecated: Implicit conversion from float 2.5 to int loses precision in %s on line %d bool(false) -Illegal offset type -Illegal offset type +Cannot access offset of type array on FixedArray +Cannot access offset of type object on FixedArray Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d bool(false) bool(false) -Illegal offset type -Illegal offset type -Illegal offset type +Cannot access offset of type string on FixedArray +Cannot access offset of type string on FixedArray +Cannot access offset of type string on FixedArray diff --git a/ext/spl/tests/gh10248.phpt b/ext/spl/tests/gh10248.phpt new file mode 100644 index 0000000000000..d4af9e98d0f69 --- /dev/null +++ b/ext/spl/tests/gh10248.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-10248 (Assertion `!(zval_get_type(&(*(property))) == 10)' failed.) +--FILE-- +property = &$b; +$a->property; + +echo "Done\n"; + +?> +--EXPECT-- +Done diff --git a/ext/spl/tests/gh10519.phpt b/ext/spl/tests/gh10519.phpt new file mode 100644 index 0000000000000..1f7572d6e8ca6 --- /dev/null +++ b/ext/spl/tests/gh10519.phpt @@ -0,0 +1,69 @@ +--TEST-- +Bug GH-10519 (Array Data Address Reference Issue) +--FILE-- +getArrayCopy(), $colname); + } + + public function bugySetMethod($key, $value) + { + $data = &$this; + + while ($data->hasChildren()) { + $data = $data->getChildren(); + } + $data->offsetSet($key, $value); + } + + public function jsonSerialize(): mixed + { + return $this; + } +} + +$a = [ + 'test' => [ + 'a' => (object) [2 => '',3 => '',4 => ''], + ] +]; + +$example = A::init($a); +$example->bugySetMethod(5, 'in here'); +var_dump(json_encode($example)); +var_dump(json_encode($a)); + +$b = [ + 'test' => [ + 'b' => [2 => '',3 => '',4 => ''], + ] +]; +$example = A::init($b); + +$example->bugySetMethod(5, 'must be here'); +var_dump(json_encode($example)); +var_dump(json_encode($b)); +?> +--EXPECT-- +string(51) "{"test":{"a":{"2":"","3":"","4":"","5":"in here"}}}" +string(51) "{"test":{"a":{"2":"","3":"","4":"","5":"in here"}}}" +string(56) "{"test":{"b":{"2":"","3":"","4":"","5":"must be here"}}}" +string(37) "{"test":{"b":{"2":"","3":"","4":""}}}" diff --git a/ext/spl/tests/gh10907.phpt b/ext/spl/tests/gh10907.phpt new file mode 100644 index 0000000000000..f93986cd4b876 --- /dev/null +++ b/ext/spl/tests/gh10907.phpt @@ -0,0 +1,139 @@ +--TEST-- +GH-10907 (Unable to serialize processed SplFixedArrays in PHP 8.2.4) +--FILE-- +my_dynamic_property = "my_dynamic_property_value"; +$array[0] = "test value 1"; +$array[1] = "test value 2"; +var_dump(serialize($array)); +var_dump(unserialize(serialize($array))); +var_dump($array); +?> +--EXPECT-- +Test without rebuilding properties +string(73) "O:13:"SplFixedArray":2:{i:0;s:12:"test value 1";i:1;s:12:"test value 2";}" +object(SplFixedArray)#2 (2) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" +} +object(SplFixedArray)#1 (2) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" +} +================= +Test with rebuilding properties +object(SplFixedArray)#2 (2) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" +} +string(73) "O:13:"SplFixedArray":2:{i:0;s:12:"test value 1";i:1;s:12:"test value 2";}" +object(SplFixedArray)#1 (2) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" +} +object(SplFixedArray)#2 (2) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" +} +================= +Test with partially rebuilding properties +object(SplFixedArray)#1 (3) { + [0]=> + string(12) "test value 1" + [1]=> + NULL + [2]=> + NULL +} +string(79) "O:13:"SplFixedArray":3:{i:0;s:12:"test value 1";i:1;s:12:"test value 2";i:2;N;}" +object(SplFixedArray)#2 (3) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" + [2]=> + NULL +} +object(SplFixedArray)#1 (3) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" + [2]=> + NULL +} +================= +Test with adding members +string(180) "O:15:"MySplFixedArray":5:{i:0;s:12:"test value 1";i:1;s:12:"test value 2";i:2;N;s:9:"my_string";s:15:"my_string_value";s:19:"my_dynamic_property";s:25:"my_dynamic_property_value";}" +object(MySplFixedArray)#1 (5) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" + [2]=> + NULL + ["my_string"]=> + string(15) "my_string_value" + ["my_dynamic_property"]=> + string(25) "my_dynamic_property_value" +} +object(MySplFixedArray)#2 (5) { + [0]=> + string(12) "test value 1" + [1]=> + string(12) "test value 2" + [2]=> + NULL + ["my_string"]=> + string(15) "my_string_value" + ["my_dynamic_property"]=> + string(25) "my_dynamic_property_value" +} diff --git a/ext/spl/tests/gh10925.phpt b/ext/spl/tests/gh10925.phpt new file mode 100644 index 0000000000000..0402a57560f3d --- /dev/null +++ b/ext/spl/tests/gh10925.phpt @@ -0,0 +1,69 @@ +--TEST-- +Properties serialization for SplFixedArray should have updated properties +--FILE-- +y); +$x->y = 2; +var_dump($x->y); +$serialized = serialize($x); +var_dump($serialized); +var_dump(unserialize($serialized)); + +$x->dynamic_property = "dynamic_property_value"; +$serialized = serialize($x); +var_dump($serialized); +var_dump(unserialize($serialized)); + +$x->dynamic_property = "dynamic_property_value2"; +$x->y = 4; +$serialized = serialize($x); +var_dump($serialized); +var_dump(unserialize($serialized)); +?> +--EXPECT-- +int(3) +int(2) +string(61) "O:15:"MySplFixedArray":4:{i:0;N;i:1;N;s:1:"x";N;s:1:"y";i:2;}" +object(MySplFixedArray)#2 (4) { + [0]=> + NULL + [1]=> + NULL + ["x"]=> + NULL + ["y"]=> + int(2) +} +string(115) "O:15:"MySplFixedArray":5:{i:0;N;i:1;N;s:1:"x";N;s:1:"y";i:2;s:16:"dynamic_property";s:22:"dynamic_property_value";}" +object(MySplFixedArray)#2 (5) { + [0]=> + NULL + [1]=> + NULL + ["x"]=> + NULL + ["y"]=> + int(2) + ["dynamic_property"]=> + string(22) "dynamic_property_value" +} +string(116) "O:15:"MySplFixedArray":5:{i:0;N;i:1;N;s:1:"x";N;s:1:"y";i:4;s:16:"dynamic_property";s:23:"dynamic_property_value2";}" +object(MySplFixedArray)#2 (5) { + [0]=> + NULL + [1]=> + NULL + ["x"]=> + NULL + ["y"]=> + int(4) + ["dynamic_property"]=> + string(23) "dynamic_property_value2" +} diff --git a/ext/spl/tests/gh11178.phpt b/ext/spl/tests/gh11178.phpt new file mode 100644 index 0000000000000..3732c57a59d19 --- /dev/null +++ b/ext/spl/tests/gh11178.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-11178 (Segmentation fault in spl_array_it_get_current_data (PHP 8.1.18)) +--FILE-- +{'x'} = 1; + } + + function getIterator(): Traversable { + return new ArrayIterator($this); + } +} + +$obj = new A; + +foreach ($obj as $k => &$v) { + $v = 3; +} + +var_dump($obj); +?> +--EXPECT-- +object(A)#1 (1) { + ["x"]=> + &int(3) +} diff --git a/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt b/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt index f3460bfccca77..44b4e2a0ebcbb 100644 --- a/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt +++ b/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt @@ -21,4 +21,4 @@ try { ?> --EXPECTF-- Deprecated: Implicit conversion from float 2.5 to int loses precision in %s on line %d -Illegal offset type +Cannot access offset of type array on array diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 721503e10ac98..2b8cbe33dd94e 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -39,7 +39,7 @@ static void sqlite3_param_dtor(zval *data); static int php_sqlite3_compare_stmt_zval_free(php_sqlite3_free_list **free_list, zval *statement); /* {{{ Error Handler */ -static void php_sqlite3_error(php_sqlite3_db_object *db_obj, char *format, ...) +static void php_sqlite3_error(php_sqlite3_db_object *db_obj, const char *format, ...) { va_list arg; char *message; @@ -1234,7 +1234,7 @@ PHP_METHOD(SQLite3, openBlob) { php_sqlite3_db_object *db_obj; zval *object = ZEND_THIS; - char *table, *column, *dbname = "main", *mode = "rb"; + const char *table, *column, *dbname = "main", *mode = "rb"; size_t table_len, column_len, dbname_len; zend_long rowid, flags = SQLITE_OPEN_READONLY, sqlite_flags = 0; sqlite3_blob *blob = NULL; @@ -1338,7 +1338,7 @@ PHP_METHOD(SQLite3, backup) { php_sqlite3_db_object *source_obj; php_sqlite3_db_object *destination_obj; - char *source_dbname = "main", *destination_dbname = "main"; + const char *source_dbname = "main", *destination_dbname = "main"; size_t source_dbname_length, destination_dbname_length; zval *source_zval = ZEND_THIS; zval *destination_zval; diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php index 8c8bf7edce5df..639a5fb782fc7 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -74,6 +74,7 @@ class SQLite3 /** * @var int * @cvalue SQLITE_OK + * @link sqlite3.class.constants.ok */ public const OK = UNKNOWN; @@ -82,11 +83,13 @@ class SQLite3 /** * @var int * @cvalue SQLITE_DENY + * @link sqlite3.class.constants.deny */ public const DENY = UNKNOWN; /** * @var int * @cvalue SQLITE_IGNORE + * @link sqlite3.class.constants.ignore */ public const IGNORE = UNKNOWN; @@ -95,172 +98,206 @@ class SQLite3 /** * @var int * @cvalue SQLITE_CREATE_INDEX + * @link sqlite3.class.constants.create-index */ public const CREATE_INDEX = UNKNOWN; /** * @var int * @cvalue SQLITE_CREATE_TABLE + * @link sqlite3.class.constants.create-table */ public const CREATE_TABLE = UNKNOWN; /** * @var int * @cvalue SQLITE_CREATE_TEMP_INDEX + * @link sqlite3.class.constants.create-temp-index */ public const CREATE_TEMP_INDEX = UNKNOWN; /** * @var int * @cvalue SQLITE_CREATE_TEMP_TABLE + * @link sqlite3.class.constants.create-temp-table */ public const CREATE_TEMP_TABLE = UNKNOWN; /** * @var int * @cvalue SQLITE_CREATE_TEMP_TRIGGER + * @link sqlite3.class.constants.create-temp-trigger */ public const CREATE_TEMP_TRIGGER = UNKNOWN; /** * @var int * @cvalue SQLITE_CREATE_TEMP_VIEW + * @link sqlite3.class.constants.create-temp-view */ public const CREATE_TEMP_VIEW = UNKNOWN; /** * @var int * @cvalue SQLITE_CREATE_TRIGGER + * @link sqlite3.class.constants.create-trigger */ public const CREATE_TRIGGER = UNKNOWN; /** * @var int * @cvalue SQLITE_CREATE_VIEW + * @link sqlite3.class.constants.create-view */ public const CREATE_VIEW = UNKNOWN; /** * @var int * @cvalue SQLITE_DELETE + * @link sqlite3.class.constants.delete */ public const DELETE = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_INDEX + * @link sqlite3.class.constants.drop-index */ public const DROP_INDEX = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_TABLE + * @link sqlite3.class.constants.drop-table */ public const DROP_TABLE = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_TEMP_INDEX + * @link sqlite3.class.constants.drop-temp-index */ public const DROP_TEMP_INDEX = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_TEMP_TABLE + * @link sqlite3.class.constants.drop-temp-table */ public const DROP_TEMP_TABLE = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_TEMP_TRIGGER + * @link sqlite3.class.constants.drop-temp-trigger */ public const DROP_TEMP_TRIGGER = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_TEMP_VIEW + * @link sqlite3.class.constants.drop-temp-view */ public const DROP_TEMP_VIEW = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_TRIGGER + * @link sqlite3.class.constants.drop-trigger */ public const DROP_TRIGGER = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_VIEW + * @link sqlite3.class.constants.drop-view */ public const DROP_VIEW = UNKNOWN; /** * @var int * @cvalue SQLITE_INSERT + * @link sqlite3.class.constants.insert */ public const INSERT = UNKNOWN; /** * @var int * @cvalue SQLITE_PRAGMA + * @link sqlite3.class.constants.pragma */ public const PRAGMA = UNKNOWN; /** * @var int * @cvalue SQLITE_READ + * @link sqlite3.class.constants.read */ public const READ = UNKNOWN; /** * @var int * @cvalue SQLITE_SELECT + * @link sqlite3.class.constants.select */ public const SELECT = UNKNOWN; /** * @var int * @cvalue SQLITE_TRANSACTION + * @link sqlite3.class.constants.transaction */ public const TRANSACTION = UNKNOWN; /** * @var int * @cvalue SQLITE_UPDATE + * @link sqlite3.class.constants.update */ public const UPDATE = UNKNOWN; /** * @var int * @cvalue SQLITE_ATTACH + * @link sqlite3.class.constants.attach */ public const ATTACH = UNKNOWN; /** * @var int * @cvalue SQLITE_DETACH + * @link sqlite3.class.constants.detach */ public const DETACH = UNKNOWN; /** * @var int * @cvalue SQLITE_ALTER_TABLE + * @link sqlite3.class.constants.alter-table */ public const ALTER_TABLE = UNKNOWN; /** * @var int * @cvalue SQLITE_REINDEX + * @link sqlite3.class.constants.reindex */ public const REINDEX = UNKNOWN; /** * @var int * @cvalue SQLITE_ANALYZE + * @link sqlite3.class.constants.analyze */ public const ANALYZE = UNKNOWN; /** * @var int * @cvalue SQLITE_CREATE_VTABLE + * @link sqlite3.class.constants.create-vtable */ public const CREATE_VTABLE = UNKNOWN; /** * @var int * @cvalue SQLITE_DROP_VTABLE + * @link sqlite3.class.constants.drop-vtable */ public const DROP_VTABLE = UNKNOWN; /** * @var int * @cvalue SQLITE_FUNCTION + * @link sqlite3.class.constants.function */ public const FUNCTION = UNKNOWN; /** * @var int * @cvalue SQLITE_SAVEPOINT + * @link sqlite3.class.constants.savepoint */ public const SAVEPOINT = UNKNOWN; /** * @var int * @cvalue SQLITE_COPY + * @link sqlite3.class.constants.copy */ public const COPY = UNKNOWN; #ifdef SQLITE_RECURSIVE /** * @var int * @cvalue SQLITE_RECURSIVE + * @link sqlite3.class.constants.recursive */ public const RECURSIVE = UNKNOWN; #endif diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h index 4091374dee78c..b99134ed1f24b 100644 --- a/ext/sqlite3/sqlite3_arginfo.h +++ b/ext/sqlite3/sqlite3_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: bdee592c8babbc221080c6ea2d73f94b2b79274a */ + * Stub hash: 61f4a2611ed8cef37003610991e357b0f227bec9 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) diff --git a/ext/standard/array.c b/ext/standard/array.c index 6252b61d2042a..5399706320d19 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -164,7 +164,7 @@ static zend_always_inline int php_array_key_compare_numeric_unstable_i(Bucket *f } else { d2 = (double)(zend_long)s->h; } - return ZEND_NORMALIZE_BOOL(d1 - d2); + return ZEND_THREEWAY_COMPARE(d1, d2); } } /* }}} */ @@ -290,7 +290,27 @@ static zend_always_inline int php_array_key_compare_string_locale_unstable_i(Buc static zend_always_inline int php_array_data_compare_unstable_i(Bucket *f, Bucket *s) /* {{{ */ { - return zend_compare(&f->val, &s->val); + int result = zend_compare(&f->val, &s->val); + /* Special enums handling for array_unique. We don't want to add this logic to zend_compare as + * that would be observable via comparison operators. */ + zval *rhs = &s->val; + ZVAL_DEREF(rhs); + if (UNEXPECTED(Z_TYPE_P(rhs) == IS_OBJECT) + && result == ZEND_UNCOMPARABLE + && (Z_OBJCE_P(rhs)->ce_flags & ZEND_ACC_ENUM)) { + zval *lhs = &f->val; + ZVAL_DEREF(lhs); + if (Z_TYPE_P(lhs) == IS_OBJECT && (Z_OBJCE_P(lhs)->ce_flags & ZEND_ACC_ENUM)) { + // Order doesn't matter, we just need to group the same enum values + uintptr_t lhs_uintptr = (uintptr_t)Z_OBJ_P(lhs); + uintptr_t rhs_uintptr = (uintptr_t)Z_OBJ_P(rhs); + return lhs_uintptr == rhs_uintptr ? 0 : (lhs_uintptr < rhs_uintptr ? -1 : 1); + } else { + // Shift enums to the end of the array + return -1; + } + } + return result; } /* }}} */ @@ -670,7 +690,7 @@ PHP_FUNCTION(count) } ZEND_FALLTHROUGH; default: - zend_argument_type_error(1, "must be of type Countable|array, %s given", zend_zval_type_name(array)); + zend_argument_type_error(1, "must be of type Countable|array, %s given", zend_zval_value_name(array)); RETURN_THROWS(); } } @@ -881,11 +901,19 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compar RETURN_TRUE; } - /* Copy array, so the in-place modifications will not be visible to the callback function */ - arr = zend_array_dup(arr); + /* Copy array, so the in-place modifications will not be visible to the callback function. + * Unless there are no other references since we know for sure it won't be visible. */ + bool in_place = zend_may_modify_arg_in_place(array); + if (!in_place) { + arr = zend_array_dup(arr); + } zend_hash_sort(arr, compare_func, renumber); + if (in_place) { + GC_ADDREF(arr); + } + zval garbage; ZVAL_COPY_VALUE(&garbage, array); ZVAL_ARR(array, arr); @@ -1020,6 +1048,10 @@ PHP_FUNCTION(end) ZEND_PARSE_PARAMETERS_END(); HashTable *array = get_ht_for_iap(array_zv, /* separate */ true); + if (zend_hash_num_elements(array) == 0) { + /* array->nInternalPointer is already 0 if the array is empty, even after removing elements */ + RETURN_FALSE; + } zend_hash_internal_pointer_end(array); if (USED_RET()) { @@ -1047,6 +1079,10 @@ PHP_FUNCTION(prev) ZEND_PARSE_PARAMETERS_END(); HashTable *array = get_ht_for_iap(array_zv, /* separate */ true); + if (zend_hash_num_elements(array) == 0) { + /* array->nInternalPointer is already 0 if the array is empty, even after removing elements */ + RETURN_FALSE; + } zend_hash_move_backwards(array); if (USED_RET()) { @@ -1074,6 +1110,10 @@ PHP_FUNCTION(next) ZEND_PARSE_PARAMETERS_END(); HashTable *array = get_ht_for_iap(array_zv, /* separate */ true); + if (zend_hash_num_elements(array) == 0) { + /* array->nInternalPointer is already 0 if the array is empty, even after removing elements */ + RETURN_FALSE; + } zend_hash_move_forward(array); if (USED_RET()) { @@ -1101,6 +1141,10 @@ PHP_FUNCTION(reset) ZEND_PARSE_PARAMETERS_END(); HashTable *array = get_ht_for_iap(array_zv, /* separate */ true); + if (zend_hash_num_elements(array) == 0) { + /* array->nInternalPointer is already 0 if the array is empty, even after removing elements */ + RETURN_FALSE; + } zend_hash_internal_pointer_reset(array); if (USED_RET()) { @@ -1176,7 +1220,7 @@ PHP_FUNCTION(min) /* mixed min ( array $values ) */ if (argc == 1) { if (Z_TYPE(args[0]) != IS_ARRAY) { - zend_argument_type_error(1, "must be of type array, %s given", zend_zval_type_name(&args[0])); + zend_argument_type_error(1, "must be of type array, %s given", zend_zval_value_name(&args[0])); RETURN_THROWS(); } else { zval *result = zend_hash_minmax(Z_ARRVAL(args[0]), php_data_compare, 0); @@ -1222,7 +1266,7 @@ PHP_FUNCTION(max) /* mixed max ( array $values ) */ if (argc == 1) { if (Z_TYPE(args[0]) != IS_ARRAY) { - zend_argument_type_error(1, "must be of type array, %s given", zend_zval_type_name(&args[0])); + zend_argument_type_error(1, "must be of type array, %s given", zend_zval_value_name(&args[0])); RETURN_THROWS(); } else { zval *result = zend_hash_minmax(Z_ARRVAL(args[0]), php_data_compare, 1); @@ -2495,7 +2539,7 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu Z_UNPROTECT_RECURSION_P(entry); } } else { - php_error_docref(NULL, E_WARNING, "Argument #%d must be string or array of strings, %s given", pos, zend_zval_type_name(entry)); + php_error_docref(NULL, E_WARNING, "Argument #%d must be string or array of strings, %s given", pos, zend_zval_value_name(entry)); return; } } @@ -3600,11 +3644,7 @@ PHP_FUNCTION(array_slice) break; } n++; - if (preserve_keys) { - entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), idx, zv); - } else { - entry = zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), zv); - } + entry = zend_hash_index_add_new(Z_ARRVAL_P(return_value), idx, zv); zval_add_ref(entry); } } @@ -3829,15 +3869,22 @@ static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM zval *arg = args + i; if (Z_TYPE_P(arg) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(arg)); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(arg)); RETURN_THROWS(); } } - /* copy first array */ + /* copy first array if necessary */ arg = args; - dest = zend_array_dup(Z_ARRVAL_P(arg)); + bool in_place = zend_may_modify_arg_in_place(arg); + if (in_place) { + dest = Z_ARRVAL_P(arg); + } else { + dest = zend_array_dup(Z_ARRVAL_P(arg)); + } + ZVAL_ARR(return_value, dest); + if (recursive) { for (i = 1; i < argc; i++) { arg = args + i; @@ -3849,6 +3896,10 @@ static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1); } } + + if (in_place) { + GC_ADDREF(dest); + } } /* }}} */ @@ -3873,7 +3924,7 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET zval *arg = args + i; if (Z_TYPE_P(arg) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(arg)); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(arg)); RETURN_THROWS(); } count += zend_hash_num_elements(Z_ARRVAL_P(arg)); @@ -3913,22 +3964,34 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET arg = args; src = Z_ARRVAL_P(arg); - /* copy first array */ - array_init_size(return_value, count); - dest = Z_ARRVAL_P(return_value); + /* copy first array if necessary */ + bool in_place = false; if (HT_IS_PACKED(src)) { - zend_hash_real_init_packed(dest); - ZEND_HASH_FILL_PACKED(dest) { - ZEND_HASH_PACKED_FOREACH_VAL(src, src_entry) { - if (UNEXPECTED(Z_ISREF_P(src_entry) && - Z_REFCOUNT_P(src_entry) == 1)) { - src_entry = Z_REFVAL_P(src_entry); - } - Z_TRY_ADDREF_P(src_entry); - ZEND_HASH_FILL_ADD(src_entry); - } ZEND_HASH_FOREACH_END(); - } ZEND_HASH_FILL_END(); + /* Note: If it has holes, it might get sequentialized */ + if (HT_IS_WITHOUT_HOLES(src) && zend_may_modify_arg_in_place(arg)) { + dest = src; + in_place = true; + ZVAL_ARR(return_value, dest); + } else { + array_init_size(return_value, count); + dest = Z_ARRVAL_P(return_value); + + zend_hash_real_init_packed(dest); + ZEND_HASH_FILL_PACKED(dest) { + ZEND_HASH_PACKED_FOREACH_VAL(src, src_entry) { + if (UNEXPECTED(Z_ISREF_P(src_entry) && + Z_REFCOUNT_P(src_entry) == 1)) { + src_entry = Z_REFVAL_P(src_entry); + } + Z_TRY_ADDREF_P(src_entry); + ZEND_HASH_FILL_ADD(src_entry); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FILL_END(); + } } else { + array_init_size(return_value, count); + dest = Z_ARRVAL_P(return_value); + zend_string *string_key; zend_hash_real_init_mixed(dest); ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(src, string_key, src_entry) { @@ -3955,6 +4018,10 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET php_array_merge(dest, Z_ARRVAL_P(arg)); } } + + if (in_place) { + GC_ADDREF(dest); + } } /* }}} */ @@ -4343,13 +4410,14 @@ PHP_FUNCTION(array_pad) Z_PARAM_ZVAL(pad_value) ZEND_PARSE_PARAMETERS_END(); + if (pad_size < Z_L(-HT_MAX_SIZE) || pad_size > Z_L(HT_MAX_SIZE)) { + zend_argument_value_error(2, "must not exceed the maximum allowed array size"); + RETURN_THROWS(); + } + /* Do some initial calculations */ input_size = zend_hash_num_elements(Z_ARRVAL_P(input)); pad_size_abs = ZEND_ABS(pad_size); - if (pad_size_abs < 0 || pad_size_abs - input_size > Z_L(1048576)) { - zend_argument_value_error(2, "must be less than or equal to 1048576"); - RETURN_THROWS(); - } if (input_size >= pad_size_abs) { /* Copy the original array */ @@ -4561,7 +4629,12 @@ PHP_FUNCTION(array_unique) cmp = php_get_data_compare_func_unstable(sort_type, 0); - RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array))); + bool in_place = zend_may_modify_arg_in_place(array); + if (in_place) { + RETVAL_ARR(Z_ARRVAL_P(array)); + } else { + RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(array))); + } /* create and sort array with pointers to the target_hash buckets */ arTmp = pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT); @@ -4607,6 +4680,10 @@ PHP_FUNCTION(array_unique) } } pefree(arTmp, GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT); + + if (in_place) { + Z_ADDREF_P(return_value); + } } /* }}} */ @@ -4671,7 +4748,7 @@ static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compa for (i = 0; i < argc; i++) { if (Z_TYPE(args[i]) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(&args[i])); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i])); RETURN_THROWS(); } } @@ -4731,6 +4808,7 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int zend_fcall_info *fci_key = NULL, *fci_data; zend_fcall_info_cache *fci_key_cache = NULL, *fci_data_cache; PHP_ARRAY_CMP_FUNC_VARS; + bool in_place = false; bucket_compare_func_t intersect_key_compare_func; bucket_compare_func_t intersect_data_compare_func; @@ -4819,7 +4897,7 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int for (i = 0; i < arr_argc; i++) { if (Z_TYPE(args[i]) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(&args[i])); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i])); arr_argc = i; /* only free up to i - 1 */ goto out; } @@ -4857,8 +4935,13 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int } } - /* copy the argument array */ - RETVAL_ARR(zend_array_dup(Z_ARRVAL(args[0]))); + /* copy the argument array if necessary */ + in_place = zend_may_modify_arg_in_place(&args[0]); + if (in_place) { + RETVAL_ARR(Z_ARRVAL_P(&args[0])); + } else { + RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(&args[0]))); + } /* go through the lists and look for common values */ while (Z_TYPE(ptrs[0]->val) != IS_UNDEF) { @@ -4969,6 +5052,10 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int efree(ptrs); efree(lists); + + if (in_place) { + Z_ADDREF_P(return_value); + } } /* }}} */ @@ -5056,7 +5143,7 @@ static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_ty for (i = 0; i < argc; i++) { if (Z_TYPE(args[i]) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(&args[i])); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i])); RETURN_THROWS(); } } @@ -5204,7 +5291,7 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_ for (i = 0; i < arr_argc; i++) { if (Z_TYPE(args[i]) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(&args[i])); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i])); arr_argc = i; /* only free up to i - 1 */ goto out; } @@ -5386,7 +5473,7 @@ PHP_FUNCTION(array_diff) ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE(args[0]) != IS_ARRAY) { - zend_argument_type_error(1, "must be of type array, %s given", zend_zval_type_name(&args[0])); + zend_argument_type_error(1, "must be of type array, %s given", zend_zval_value_name(&args[0])); RETURN_THROWS(); } @@ -5394,7 +5481,7 @@ PHP_FUNCTION(array_diff) if (num == 0) { for (i = 1; i < argc; i++) { if (Z_TYPE(args[i]) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(&args[i])); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i])); RETURN_THROWS(); } } @@ -5411,7 +5498,7 @@ PHP_FUNCTION(array_diff) if (!value) { for (i = 1; i < argc; i++) { if (Z_TYPE(args[i]) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(&args[i])); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i])); RETURN_THROWS(); } } @@ -5422,7 +5509,7 @@ PHP_FUNCTION(array_diff) for (i = 1; i < argc; i++) { if (Z_TYPE(args[i]) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(&args[i])); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i])); RETURN_THROWS(); } if (!found) { @@ -5452,7 +5539,7 @@ PHP_FUNCTION(array_diff) num = 0; for (i = 1; i < argc; i++) { if (Z_TYPE(args[i]) != IS_ARRAY) { - zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_type_name(&args[i])); + zend_argument_type_error(i + 1, "must be of type array, %s given", zend_zval_value_name(&args[i])); RETURN_THROWS(); } num += zend_hash_num_elements(Z_ARRVAL(args[i])); @@ -5902,65 +5989,70 @@ PHP_FUNCTION(array_rand) } /* }}} */ -/* {{{ Returns the sum of the array entries */ -PHP_FUNCTION(array_sum) +/* Wrapper for array_sum and array_product */ +static void php_array_binop(INTERNAL_FUNCTION_PARAMETERS, const char *op_name, binary_op_type op, zend_long initial) { - zval *input, - *entry, - entry_n; + HashTable *input; + zval *entry; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(input) + Z_PARAM_ARRAY_HT(input) ZEND_PARSE_PARAMETERS_END(); - ZVAL_LONG(return_value, 0); + if (zend_hash_num_elements(input) == 0) { + RETURN_LONG(initial); + } + + ZVAL_LONG(return_value, initial); + ZEND_HASH_FOREACH_VAL(input, entry) { + /* For objects we try to cast them to a numeric type */ + if (Z_TYPE_P(entry) == IS_OBJECT) { + zval dst; + zend_result status = Z_OBJ_HT_P(entry)->cast_object(Z_OBJ_P(entry), &dst, _IS_NUMBER); - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) { - if (Z_TYPE_P(entry) == IS_ARRAY || Z_TYPE_P(entry) == IS_OBJECT) { + /* Do not type error for BC */ + if (status == FAILURE || (Z_TYPE(dst) != IS_LONG && Z_TYPE(dst) != IS_DOUBLE)) { + php_error_docref(NULL, E_WARNING, "%s is not supported on type %s", + op_name, zend_zval_type_name(entry)); + continue; + } + op(return_value, return_value, &dst); continue; } - ZVAL_COPY(&entry_n, entry); - convert_scalar_to_number(&entry_n); - fast_add_function(return_value, return_value, &entry_n); + + zend_result status = op(return_value, return_value, entry); + if (status == FAILURE) { + ZEND_ASSERT(EG(exception)); + zend_clear_exception(); + /* BC resources: previously resources were cast to int */ + if (Z_TYPE_P(entry) == IS_RESOURCE) { + zval tmp; + ZVAL_LONG(&tmp, Z_RES_HANDLE_P(entry)); + op(return_value, return_value, &tmp); + } + /* BC non numeric strings: previously were cast to 0 */ + else if (Z_TYPE_P(entry) == IS_STRING) { + zval tmp; + ZVAL_LONG(&tmp, 0); + op(return_value, return_value, &tmp); + } + php_error_docref(NULL, E_WARNING, "%s is not supported on type %s", + op_name, zend_zval_type_name(entry)); + } } ZEND_HASH_FOREACH_END(); } + +/* {{{ Returns the sum of the array entries */ +PHP_FUNCTION(array_sum) +{ + php_array_binop(INTERNAL_FUNCTION_PARAM_PASSTHRU, "Addition", add_function, 0); +} /* }}} */ /* {{{ Returns the product of the array entries */ PHP_FUNCTION(array_product) { - zval *input, - *entry, - entry_n; - double dval; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(input) - ZEND_PARSE_PARAMETERS_END(); - - ZVAL_LONG(return_value, 1); - if (!zend_hash_num_elements(Z_ARRVAL_P(input))) { - return; - } - - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) { - if (Z_TYPE_P(entry) == IS_ARRAY || Z_TYPE_P(entry) == IS_OBJECT) { - continue; - } - ZVAL_COPY(&entry_n, entry); - convert_scalar_to_number(&entry_n); - - if (Z_TYPE(entry_n) == IS_LONG && Z_TYPE_P(return_value) == IS_LONG) { - dval = (double)Z_LVAL_P(return_value) * (double)Z_LVAL(entry_n); - if ( (double)ZEND_LONG_MIN <= dval && dval <= (double)ZEND_LONG_MAX ) { - Z_LVAL_P(return_value) *= Z_LVAL(entry_n); - continue; - } - } - convert_to_double(return_value); - convert_to_double(&entry_n); - Z_DVAL_P(return_value) *= Z_DVAL(entry_n); - } ZEND_HASH_FOREACH_END(); + php_array_binop(INTERNAL_FUNCTION_PARAM_PASSTHRU, "Multiplication", mul_function, 1); } /* }}} */ @@ -6134,7 +6226,7 @@ PHP_FUNCTION(array_map) int ret; if (Z_TYPE(arrays[0]) != IS_ARRAY) { - zend_argument_type_error(2, "must be of type array, %s given", zend_zval_type_name(&arrays[0])); + zend_argument_type_error(2, "must be of type array, %s given", zend_zval_value_name(&arrays[0])); RETURN_THROWS(); } maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[0])); @@ -6171,7 +6263,7 @@ PHP_FUNCTION(array_map) for (i = 0; i < n_arrays; i++) { if (Z_TYPE(arrays[i]) != IS_ARRAY) { - zend_argument_type_error(i + 2, "must be of type array, %s given", zend_zval_type_name(&arrays[i])); + zend_argument_type_error(i + 2, "must be of type array, %s given", zend_zval_value_name(&arrays[i])); efree(array_pos); RETURN_THROWS(); } diff --git a/ext/standard/assert.c b/ext/standard/assert.c index f5f10752fe54c..0b43033dd4d30 100644 --- a/ext/standard/assert.c +++ b/ext/standard/assert.c @@ -213,7 +213,7 @@ PHP_FUNCTION(assert_options) RETURN_THROWS(); } - key = zend_string_init("assert.active", sizeof("assert.active")-1, 0); + key = ZSTR_INIT_LITERAL("assert.active", 0); zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(key, 0); zend_string_release_ex(value_str, 0); @@ -229,7 +229,7 @@ PHP_FUNCTION(assert_options) RETURN_THROWS(); } - key = zend_string_init("assert.bail", sizeof("assert.bail")-1, 0); + key = ZSTR_INIT_LITERAL("assert.bail", 0); zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(key, 0); zend_string_release_ex(value_str, 0); @@ -245,7 +245,7 @@ PHP_FUNCTION(assert_options) RETURN_THROWS(); } - key = zend_string_init("assert.warning", sizeof("assert.warning")-1, 0); + key = ZSTR_INIT_LITERAL("assert.warning", 0); zend_alter_ini_entry_ex(key, value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(key, 0); zend_string_release_ex(value_str, 0); @@ -280,7 +280,7 @@ PHP_FUNCTION(assert_options) RETURN_THROWS(); } - key = zend_string_init("assert.exception", sizeof("assert.exception")-1, 0); + key = ZSTR_INIT_LITERAL("assert.exception", 0); zend_alter_ini_entry_ex(key, val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0); zend_string_release_ex(val, 0); zend_string_release_ex(key, 0); diff --git a/ext/standard/base64.c b/ext/standard/base64.c index 3893438839aee..4257a76ce5b6b 100644 --- a/ext/standard/base64.c +++ b/ext/standard/base64.c @@ -354,6 +354,20 @@ static zend_always_inline int php_base64_decode_impl(const unsigned char *in, si # endif #endif +/* Only enable avx512 resolver if avx2 use resolver also */ +#if ZEND_INTRIN_AVX2_FUNC_PROTO && ZEND_INTRIN_AVX512_FUNC_PROTO +#define BASE64_INTRIN_AVX512_FUNC_PROTO 1 +#endif +#if ZEND_INTRIN_AVX2_FUNC_PTR && ZEND_INTRIN_AVX512_FUNC_PTR +#define BASE64_INTRIN_AVX512_FUNC_PTR 1 +#endif +#if ZEND_INTRIN_AVX2_FUNC_PROTO && ZEND_INTRIN_AVX512_VBMI_FUNC_PROTO +#define BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO 1 +#endif +#if ZEND_INTRIN_AVX2_FUNC_PTR && ZEND_INTRIN_AVX512_VBMI_FUNC_PTR +#define BASE64_INTRIN_AVX512_VBMI_FUNC_PTR 1 +#endif + #if ZEND_INTRIN_AVX2_NATIVE # include #elif ZEND_INTRIN_SSSE3_NATIVE @@ -366,6 +380,15 @@ static zend_always_inline int php_base64_decode_impl(const unsigned char *in, si # endif /* (ZEND_INTRIN_SSSE3_RESOLVER || ZEND_INTRIN_AVX2_RESOLVER) */ # include "Zend/zend_cpuinfo.h" +# if BASE64_INTRIN_AVX512_FUNC_PROTO || BASE64_INTRIN_AVX512_FUNC_PTR +ZEND_INTRIN_AVX512_FUNC_DECL(zend_string *php_base64_encode_avx512(const unsigned char *str, size_t length)); +ZEND_INTRIN_AVX512_FUNC_DECL(zend_string *php_base64_decode_ex_avx512(const unsigned char *str, size_t length, bool strict)); +# endif +# if BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO || BASE64_INTRIN_AVX512_VBMI_FUNC_PTR +ZEND_INTRIN_AVX512_VBMI_FUNC_DECL(zend_string *php_base64_encode_avx512_vbmi(const unsigned char *str, size_t length)); +ZEND_INTRIN_AVX512_VBMI_FUNC_DECL(zend_string *php_base64_decode_ex_avx512_vbmi(const unsigned char *str, size_t length, bool strict)); +# endif + # if ZEND_INTRIN_AVX2_RESOLVER ZEND_INTRIN_AVX2_FUNC_DECL(zend_string *php_base64_encode_avx2(const unsigned char *str, size_t length)); ZEND_INTRIN_AVX2_FUNC_DECL(zend_string *php_base64_decode_ex_avx2(const unsigned char *str, size_t length, bool strict)); @@ -379,7 +402,7 @@ ZEND_INTRIN_SSSE3_FUNC_DECL(zend_string *php_base64_decode_ex_ssse3(const unsign zend_string *php_base64_encode_default(const unsigned char *str, size_t length); zend_string *php_base64_decode_ex_default(const unsigned char *str, size_t length, bool strict); -# if (ZEND_INTRIN_AVX2_FUNC_PROTO || ZEND_INTRIN_SSSE3_FUNC_PROTO) +# if (ZEND_INTRIN_AVX2_FUNC_PROTO || ZEND_INTRIN_SSSE3_FUNC_PROTO || BASE64_INTRIN_AVX512_FUNC_PROTO || BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO) PHPAPI zend_string *php_base64_encode(const unsigned char *str, size_t length) __attribute__((ifunc("resolve_base64_encode"))); PHPAPI zend_string *php_base64_decode_ex(const unsigned char *str, size_t length, bool strict) __attribute__((ifunc("resolve_base64_decode"))); @@ -389,6 +412,16 @@ typedef zend_string *(*base64_decode_func_t)(const unsigned char *, size_t, bool ZEND_NO_SANITIZE_ADDRESS ZEND_ATTRIBUTE_UNUSED /* clang mistakenly warns about this */ static base64_encode_func_t resolve_base64_encode(void) { +# if BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO + if (zend_cpu_supports_avx512_vbmi()) { + return php_base64_encode_avx512_vbmi; + } else +# endif +# if BASE64_INTRIN_AVX512_FUNC_PROTO + if (zend_cpu_supports_avx512()) { + return php_base64_encode_avx512; + } else +# endif # if ZEND_INTRIN_AVX2_FUNC_PROTO if (zend_cpu_supports_avx2()) { return php_base64_encode_avx2; @@ -405,6 +438,16 @@ static base64_encode_func_t resolve_base64_encode(void) { ZEND_NO_SANITIZE_ADDRESS ZEND_ATTRIBUTE_UNUSED /* clang mistakenly warns about this */ static base64_decode_func_t resolve_base64_decode(void) { +# if BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO + if (zend_cpu_supports_avx512_vbmi()) { + return php_base64_decode_ex_avx512_vbmi; + } else +# endif +# if BASE64_INTRIN_AVX512_FUNC_PROTO + if (zend_cpu_supports_avx512()) { + return php_base64_decode_ex_avx512; + } else +# endif # if ZEND_INTRIN_AVX2_FUNC_PROTO if (zend_cpu_supports_avx2()) { return php_base64_decode_ex_avx2; @@ -431,6 +474,18 @@ PHPAPI zend_string *php_base64_decode_ex(const unsigned char *str, size_t length PHP_MINIT_FUNCTION(base64_intrin) { +# if BASE64_INTRIN_AVX512_VBMI_FUNC_PTR + if (zend_cpu_supports_avx512_vbmi()) { + php_base64_encode_ptr = php_base64_encode_avx512_vbmi; + php_base64_decode_ex_ptr = php_base64_decode_ex_avx512_vbmi; + } else +# endif +# if BASE64_INTRIN_AVX512_FUNC_PTR + if (zend_cpu_supports_avx512()) { + php_base64_encode_ptr = php_base64_encode_avx512; + php_base64_decode_ex_ptr = php_base64_decode_ex_avx512; + } else +# endif # if ZEND_INTRIN_AVX2_FUNC_PTR if (zend_cpu_supports_avx2()) { php_base64_encode_ptr = php_base64_encode_avx2; @@ -452,6 +507,249 @@ PHP_MINIT_FUNCTION(base64_intrin) # endif /* (ZEND_INTRIN_AVX2_FUNC_PROTO || ZEND_INTRIN_SSSE3_FUNC_PROTO) */ #endif /* ZEND_INTRIN_AVX2_NATIVE */ +#if BASE64_INTRIN_AVX512_VBMI_FUNC_PROTO || BASE64_INTRIN_AVX512_VBMI_FUNC_PTR +zend_string *php_base64_encode_avx512_vbmi(const unsigned char *str, size_t length) +{ + const unsigned char *c = str; + unsigned char *o; + zend_string *result; + + result = zend_string_safe_alloc(((length + 2) / 3), 4 * sizeof(char), 0, 0); + o = (unsigned char *)ZSTR_VAL(result); + + const __m512i shuffle_splitting = _mm512_setr_epi32( + 0x01020001, 0x04050304, 0x07080607, 0x0a0b090a, 0x0d0e0c0d, 0x10110f10, + 0x13141213, 0x16171516, 0x191a1819, 0x1c1d1b1c, 0x1f201e1f, 0x22232122, + 0x25262425, 0x28292728, 0x2b2c2a2b, 0x2e2f2d2e); + const __m512i multi_shifts = _mm512_set1_epi64(0x3036242a1016040a); + const char *ascii_lookup_tbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const __m512i ascii_lookup = _mm512_loadu_si512((__m512i *)ascii_lookup_tbl); + + while (length > 63) { + /* Step 1: load input data */ + __m512i str = _mm512_loadu_si512((const __m512i *)c); + + /* Step 2: splitting 24-bit words into 32-bit lanes */ + str = _mm512_permutexvar_epi8(shuffle_splitting, str); + + /* Step 3: moving 6-bit word to sperate bytes */ + str = _mm512_multishift_epi64_epi8(multi_shifts, str); + + /* Step 4: conversion to ASCII */ + str = _mm512_permutexvar_epi8(str, ascii_lookup); + + /* Step 5: store the final result */ + _mm512_storeu_si512((__m512i *)o, str); + c += 48; + o += 64; + length -= 48; + } + + o = php_base64_encode_impl(c, length, o); + + ZSTR_LEN(result) = (o - (unsigned char *)ZSTR_VAL(result)); + + return result; +} + +zend_string *php_base64_decode_ex_avx512_vbmi(const unsigned char *str, size_t length, bool strict) +{ + const unsigned char *c = str; + unsigned char *o; + size_t outl = 0; + zend_string *result; + + result = zend_string_alloc(length, 0); + o = (unsigned char *)ZSTR_VAL(result); + + const __m512i lookup_0 = _mm512_setr_epi32( + 0x80808080, 0x80808080, 0x80808080, 0x80808080, 0x80808080, 0x80808080, + 0x80808080, 0x80808080, 0x80808080, 0x80808080, 0x3e808080, 0x3f808080, + 0x37363534, 0x3b3a3938, 0x80803d3c, 0x80808080); + const __m512i lookup_1 = _mm512_setr_epi32( + 0x02010080, 0x06050403, 0x0a090807, 0x0e0d0c0b, 0x1211100f, 0x16151413, + 0x80191817, 0x80808080, 0x1c1b1a80, 0x201f1e1d, 0x24232221, 0x28272625, + 0x2c2b2a29, 0x302f2e2d, 0x80333231, 0x80808080); + + const __m512i merge_mask1 = _mm512_set1_epi32(0x01400140); + const __m512i merge_mask2 = _mm512_set1_epi32(0x00011000); + + const __m512i continuous_mask = _mm512_setr_epi32( + 0x06000102, 0x090a0405, 0x0c0d0e08, 0x16101112, 0x191a1415, 0x1c1d1e18, + 0x26202122, 0x292a2425, 0x2c2d2e28, 0x36303132, 0x393a3435, 0x3c3d3e38, + 0x00000000, 0x00000000, 0x00000000, 0x00000000); + + while (length > 64) { + /* Step 1: load input data */ + const __m512i input = _mm512_loadu_si512((__m512i *)c); + + /* Step 2: translation into 6-bit values(saved on bytes) from ASCII and error detection */ + __m512i str = _mm512_permutex2var_epi8(lookup_0, input, lookup_1); + const uint64_t mask = _mm512_movepi8_mask(_mm512_or_epi64(str, input)); /* convert MSBs to the mask */ + if (mask) { + break; + } + + /* Step 3: pack four fields within 32-bit words into 24-bit words. */ + const __m512i merge_ab_and_bc = _mm512_maddubs_epi16(str, merge_mask1); + str = _mm512_madd_epi16(merge_ab_and_bc, merge_mask2); + + /* Step 4: move 3-byte words into the continuous array. */ + str = _mm512_permutexvar_epi8(continuous_mask, str); + + /* Step 5: store the final result */ + _mm512_storeu_si512((__m512i *)o, str); + + c += 64; + o += 48; + outl += 48; + length -= 64; + } + + if (!php_base64_decode_impl(c, length, (unsigned char*)ZSTR_VAL(result), &outl, strict)) { + zend_string_efree(result); + return NULL; + } + + ZSTR_LEN(result) = outl; + + return result; +} +#endif + +#if BASE64_INTRIN_AVX512_FUNC_PROTO || BASE64_INTRIN_AVX512_FUNC_PTR +zend_string *php_base64_encode_avx512(const unsigned char *str, size_t length) +{ + const unsigned char *c = str; + unsigned char *o; + zend_string *result; + + result = zend_string_safe_alloc(((length + 2) / 3), 4 * sizeof(char), 0, 0); + o = (unsigned char *)ZSTR_VAL(result); + + while (length > 63) { + /* Step 1: load input data */ + /* [????|????|????|????|PPPO|OONN|NMMM|LLLK|KKJJ|JIII|HHHG|GGFF|FEEE|DDDC|CCBB|BAAA] */ + __m512i str = _mm512_loadu_si512((const __m512i *)c); + + /* Step 2: splitting 24-bit words into 32-bit lanes */ + /* [0000|PPPO|OONN|NMMM|0000|LLLK|KKJJ|JIII|0000|HHHG|GGFF|FEEE|0000|DDDC|CCBB|BAAA] */ + str = _mm512_permutexvar_epi32( + _mm512_set_epi32(-1, 11, 10, 9, -1, 8, 7, 6, -1, 5, 4, 3, -1, 2, 1, 0), str); + /* [D1 D2 D0 D1|C1 C2 C0 C1|B1 B2 B0 B1|A1 A2 A0 A1] x 4 */ + str = _mm512_shuffle_epi8(str, _mm512_set4_epi32(0x0a0b090a, 0x07080607, 0x04050304, 0x01020001)); + + /* Step 3: moving 6-bit word to sperate bytes */ + /* in: [bbbbcccc|ccdddddd|aaaaaabb|bbbbcccc] */ + /* t0: [0000cccc|cc000000|aaaaaa00|00000000] */ + const __m512i t0 = _mm512_and_si512(str, _mm512_set1_epi32(0x0fc0fc00)); + /* t1: [00000000|00cccccc|00000000|00aaaaaa] */ + const __m512i t1 = _mm512_srlv_epi16(t0, _mm512_set1_epi32(0x0006000a)); + /* t2: [ccdddddd|00000000|aabbbbbb|cccc0000] */ + const __m512i t2 = _mm512_sllv_epi16(str, _mm512_set1_epi32(0x00080004)); + /* str: [00dddddd|00cccccc|00bbbbbb|00aaaaaa] */ + str = _mm512_ternarylogic_epi32(_mm512_set1_epi32(0x3f003f00), t2, t1, 0xca); + + /* Step 4: conversion to ASCII */ + __m512i result = _mm512_subs_epu8(str, _mm512_set1_epi8(51)); + const __mmask64 less = _mm512_cmpgt_epi8_mask(_mm512_set1_epi8(26), str); + result = _mm512_mask_mov_epi8(result, less, _mm512_set1_epi8(13)); + const __m512i lut = _mm512_set4_epi32(0x000041f0, 0xedfcfcfc, 0xfcfcfcfc, 0xfcfcfc47); + result = _mm512_shuffle_epi8(lut, result); + result = _mm512_add_epi8(result, str); + + /* Step 5: store the final result */ + _mm512_storeu_si512((__m512i *)o, result); + c += 48; + o += 64; + length -= 48; + } + + o = php_base64_encode_impl(c, length, o); + + ZSTR_LEN(result) = (o - (unsigned char *)ZSTR_VAL(result)); + + return result; +} + +#define build_dword(b0, b1, b2, b3) \ + ((uint32_t)(uint8_t)b0 << 0) | ((uint32_t)(uint8_t)b1 << 8) | \ + ((uint32_t)(uint8_t)b2 << 16) | ((uint32_t)(uint8_t)b3 << 24) + +#define _mm512_set4lanes_epi8(b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15) \ + _mm512_setr4_epi32(build_dword(b0, b1, b2, b3), build_dword(b4, b5, b6, b7), \ + build_dword(b8, b9, b10, b11), build_dword(b12, b13, b14, b15)) + +zend_string *php_base64_decode_ex_avx512(const unsigned char *str, size_t length, bool strict) +{ + const unsigned char *c = str; + unsigned char *o; + size_t outl = 0; + zend_string *result; + + result = zend_string_alloc(length, 0); + o = (unsigned char *)ZSTR_VAL(result); + + while (length > 64) { + /* Step 1: load input data */ + __m512i str = _mm512_loadu_si512((__m512i *)c); + + /* Step 2: translation into 6-bit values(saved on bytes) from ASCII and error detection */ + const __m512i higher_nibble = _mm512_and_si512(_mm512_srli_epi32(str, 4), _mm512_set1_epi8(0x0f)); + const __m512i lower_nibble = _mm512_and_si512(str, _mm512_set1_epi8(0x0f)); + const __m512i shiftLUT = _mm512_set4lanes_epi8( + 0, 0, 19, 4, -65, -65, -71, -71, 0, 0, 0, 0, 0, 0, 0, 0); + const __m512i maskLUT = _mm512_set4lanes_epi8( + /* 0 : 0b1010_1000*/ 0xa8, + /* 1 .. 9 : 0b1111_1000*/ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + /* 10 : 0b1111_0000*/ 0xf0, + /* 11 : 0b0101_0100*/ 0x54, + /* 12 .. 14 : 0b0101_0000*/ 0x50, 0x50, 0x50, + /* 15 : 0b0101_0100*/ 0x54); + const __m512i bitposLUT = _mm512_set4lanes_epi8( + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + const __m512i M = _mm512_shuffle_epi8(maskLUT, lower_nibble); + const __m512i bit = _mm512_shuffle_epi8(bitposLUT, higher_nibble); + const uint64_t match = _mm512_test_epi8_mask(M, bit); + if (match != (uint64_t)-1) { + break; + } + const __m512i sh = _mm512_shuffle_epi8(shiftLUT, higher_nibble); + const __mmask64 eq_2f = _mm512_cmpeq_epi8_mask(str, _mm512_set1_epi8(0x2f)); + const __m512i shift = _mm512_mask_mov_epi8(sh, eq_2f, _mm512_set1_epi8(16)); + str = _mm512_add_epi8(str, shift); + + /* Step 3: pack four fields within 32-bit words into 24-bit words. */ + const __m512i merge_ab_and_bc = _mm512_maddubs_epi16(str, _mm512_set1_epi32(0x01400140)); + str = _mm512_madd_epi16(merge_ab_and_bc, _mm512_set1_epi32(0x00011000)); + + /* Step 4: move 3-byte words into the continuous array. */ + const __m512i t1 = _mm512_shuffle_epi8(str, + _mm512_set4lanes_epi8(2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, -1, -1, -1, -1)); + const __m512i s6 = _mm512_setr_epi32(0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0, 0, 0, 0); + const __m512i t2 = _mm512_permutexvar_epi32(s6, t1); + + /* Step 5: store the final result */ + _mm512_storeu_si512((__m512i *)o, t2); + + c += 64; + o += 48; + outl += 48; + length -= 64; + } + + if (!php_base64_decode_impl(c, length, (unsigned char*)ZSTR_VAL(result), &outl, strict)) { + zend_string_efree(result); + return NULL; + } + + ZSTR_LEN(result) = outl; + + return result; +} +#endif + #if ZEND_INTRIN_AVX2_NATIVE || ZEND_INTRIN_AVX2_RESOLVER # if ZEND_INTRIN_AVX2_RESOLVER && defined(HAVE_FUNC_ATTRIBUTE_TARGET) static __m256i php_base64_encode_avx2_reshuffle(__m256i in) __attribute__((target("avx2"))); diff --git a/ext/standard/base64.h b/ext/standard/base64.h index 5c4cfff42b442..5e1c6f195cc24 100644 --- a/ext/standard/base64.h +++ b/ext/standard/base64.h @@ -19,7 +19,7 @@ #define BASE64_H /* - * NEON implementation is based on https://github.com/WojciechMula/base64simd + * NEON and AVX512 implementation are based on https://github.com/WojciechMula/base64simd * which is copyrighted to: * Copyright (c) 2015-2018, Wojciech Mula * All rights reserved. @@ -57,7 +57,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if (ZEND_INTRIN_AVX2_FUNC_PTR || ZEND_INTRIN_SSSE3_FUNC_PTR) && !ZEND_INTRIN_AVX2_NATIVE +#if (ZEND_INTRIN_AVX2_FUNC_PTR || ZEND_INTRIN_SSSE3_FUNC_PTR || ZEND_INTRIN_AVX512_FUNC_PTR || ZEND_INTRIN_AVX512_VBMI_FUNC_PTR) && !ZEND_INTRIN_AVX2_NATIVE PHP_MINIT_FUNCTION(base64_intrin); #endif diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index f65a71a7266dd..1c84ddcc98947 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -2104,7 +2104,7 @@ PHP_FUNCTION(set_include_path) RETVAL_FALSE; } - key = zend_string_init("include_path", sizeof("include_path") - 1, 0); + key = ZSTR_INIT_LITERAL("include_path", 0); if (zend_alter_ini_entry_ex(key, new_value, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) { zend_string_release_ex(key, 0); zval_ptr_dtor_str(return_value); @@ -2185,7 +2185,7 @@ PHP_FUNCTION(ignore_user_abort) old_setting = (unsigned short)PG(ignore_user_abort); if (!arg_is_null) { - zend_string *key = zend_string_init("ignore_user_abort", sizeof("ignore_user_abort") - 1, 0); + zend_string *key = ZSTR_INIT_LITERAL("ignore_user_abort", 0); zend_alter_ini_entry_chars(key, arg ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(key, 0); } diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index ab56a8c0e8fbb..9124626b5c5b5 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1722,14 +1722,14 @@ function array_pad(array $array, int $length, mixed $value): array {} /** * @return array - * @refcount 1 * @compile-time-eval + * @refcount 1 */ function array_flip(array $array): array {} /** - * @refcount 1 * @compile-time-eval + * @refcount 1 */ function array_change_key_case(array $array, int $case = CASE_LOWER): array {} @@ -1738,7 +1738,10 @@ function array_change_key_case(array $array, int $case = CASE_LOWER): array {} */ function array_unique(array $array, int $flags = SORT_STRING): array {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function array_intersect_key(array $array, array ...$arrays): array {} /** @@ -1747,7 +1750,10 @@ function array_intersect_key(array $array, array ...$arrays): array {} */ function array_intersect_ukey(array $array, ...$rest): array {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function array_intersect(array $array, array ...$arrays): array {} /** @@ -1756,7 +1762,10 @@ function array_intersect(array $array, array ...$arrays): array {} */ function array_uintersect(array $array, ...$rest): array {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function array_intersect_assoc(array $array, array ...$arrays): array {} /** @@ -1778,15 +1787,14 @@ function array_intersect_uassoc(array $array, ...$rest): array {} function array_uintersect_uassoc(array $array, ...$rest): array {} /** - * @refcount 1 * @compile-time-eval + * @refcount 1 */ function array_diff_key(array $array, array ...$arrays): array {} /** * @param array|callable $rest * @refcount 1 - * @compile-time-eval */ function array_diff_ukey(array $array, ...$rest): array {} @@ -1802,8 +1810,8 @@ function array_diff(array $array, array ...$arrays): array {} function array_udiff(array $array, ...$rest): array {} /** - * @refcount 1 * @compile-time-eval + * @refcount 1 */ function array_diff_assoc(array $array, array ...$arrays): array {} @@ -1846,7 +1854,10 @@ function array_filter(array $array, ?callable $callback = null, int $mode = 0): function array_map(?callable $callback, array $array, array ...$arrays): array {} -/** @param string|int $key */ +/** + * @param string|int $key + * @compile-time-eval + */ function array_key_exists($key, array $array): bool {} /** @@ -1859,13 +1870,14 @@ function array_chunk(array $array, int $length, bool $preserve_keys = false): ar function array_combine(array $keys, array $values): array {} +/** @compile-time-eval */ function array_is_list(array $array): bool {} /* base64.c */ /** - * @refcount 1 * @compile-time-eval + * @refcount 1 */ function base64_encode(string $string): string {} @@ -2277,8 +2289,8 @@ function wordwrap(string $string, int $width = 75, string $break = "\n", bool $c /** * @return array - * @refcount 1 * @compile-time-eval + * @refcount 1 */ function explode(string $separator, string $string, int $limit = PHP_INT_MAX): array {} @@ -2314,7 +2326,10 @@ function pathinfo(string $path, int $flags = PATHINFO_ALL): array|string {} /** @refcount 1 */ function stristr(string $haystack, string $needle, bool $before_needle = false): string|false {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function strstr(string $haystack, string $needle, bool $before_needle = false): string|false {} /** @alias strstr */ @@ -2952,42 +2967,61 @@ function mail(string $to, string $subject, string $message, array|string $additi /* math.c */ +/** @compile-time-eval */ function abs(int|float $num): int|float {} +/** @compile-time-eval */ function ceil(int|float $num): float {} +/** @compile-time-eval */ function floor(int|float $num): float {} +/** @compile-time-eval */ function round(int|float $num, int $precision = 0, int $mode = PHP_ROUND_HALF_UP): float {} +/** @compile-time-eval */ function sin(float $num): float {} +/** @compile-time-eval */ function cos(float $num): float {} +/** @compile-time-eval */ function tan(float $num): float {} +/** @compile-time-eval */ function asin(float $num): float {} +/** @compile-time-eval */ function acos(float $num): float {} +/** @compile-time-eval */ function atan(float $num): float {} +/** @compile-time-eval */ function atanh(float $num): float {} +/** @compile-time-eval */ function atan2(float $y, float $x): float {} +/** @compile-time-eval */ function sinh(float $num): float {} +/** @compile-time-eval */ function cosh(float $num): float {} +/** @compile-time-eval */ function tanh(float $num): float {} +/** @compile-time-eval */ function asinh(float $num): float {} +/** @compile-time-eval */ function acosh(float $num): float {} +/** @compile-time-eval */ function expm1(float $num): float {} +/** @compile-time-eval */ function log1p(float $num): float {} /** @compile-time-eval */ @@ -3008,18 +3042,25 @@ function is_infinite(float $num): bool {} /** @compile-time-eval */ function pow(mixed $num, mixed $exponent): int|float|object {} +/** @compile-time-eval */ function exp(float $num): float {} +/** @compile-time-eval */ function log(float $num, float $base = M_E): float {} +/** @compile-time-eval */ function log10(float $num): float {} +/** @compile-time-eval */ function sqrt(float $num): float {} +/** @compile-time-eval */ function hypot(float $x, float $y): float {} +/** @compile-time-eval */ function deg2rad(float $num): float {} +/** @compile-time-eval */ function rad2deg(float $num): float {} /** @compile-time-eval */ @@ -3049,14 +3090,26 @@ function decoct(int $num): string {} */ function dechex(int $num): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function base_convert(string $num, int $from_base, int $to_base): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function number_format(float $num, int $decimals = 0, ?string $decimal_separator = ".", ?string $thousands_separator = ","): string {} +/** + * @compile-time-eval + */ function fmod(float $num1, float $num2): float {} +/** + * @compile-time-eval + */ function fdiv(float $num1, float $num2): float {} /* microtime.c */ @@ -3082,11 +3135,15 @@ function getrusage(int $mode = 0): array|false {} /* pack.c */ -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function pack(string $format, mixed ...$values): string {} /** * @return array|false + * @compile-time-eval * @refcount 1 */ function unpack(string $format, string $string, int $offset = 0): array|false {} @@ -3352,29 +3409,59 @@ function socket_set_timeout($stream, int $seconds, int $microseconds = 0): bool /* type.c */ +/** + * @compile-time-eval + */ function gettype(mixed $value): string {} +/** + * @compile-time-eval + */ function get_debug_type(mixed $value): string {} function settype(mixed &$var, string $type): bool {} +/** + * @compile-time-eval + */ function intval(mixed $value, int $base = 10): int {} +/** + * @compile-time-eval + */ function floatval(mixed $value): float {} /** @alias floatval */ function doubleval(mixed $value): float {} +/** + * @compile-time-eval + */ function boolval(mixed $value): bool {} +/** + * @compile-time-eval + */ function strval(mixed $value): string {} +/** + * @compile-time-eval + */ function is_null(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_resource(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_bool(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_int(mixed $value): bool {} /** @alias is_int */ @@ -3383,26 +3470,50 @@ function is_integer(mixed $value): bool {} /** @alias is_int */ function is_long(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_float(mixed $value): bool {} /** @alias is_float */ function is_double(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_numeric(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_string(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_array(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_object(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_scalar(mixed $value): bool {} /** @param string $callable_name */ function is_callable(mixed $value, bool $syntax_only = false, &$callable_name = null): bool {} +/** + * @compile-time-eval + */ function is_iterable(mixed $value): bool {} +/** + * @compile-time-eval + */ function is_countable(mixed $value): bool {} /* uniqid.c */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 077f9876df7c2..bb46fb87090f6 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 39d455982dfdea9d0b9b646bc207b05f7108d1b2 */ + * Stub hash: 73f82e392f5adf146b9b8dfb39496b3ce8465115 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -2897,16 +2897,16 @@ static const zend_function_entry ext_functions[] = { ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_flip, arginfo_array_flip) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_change_key_case, arginfo_array_change_key_case) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_unique, arginfo_array_unique) - ZEND_FE(array_intersect_key, arginfo_array_intersect_key) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_intersect_key, arginfo_array_intersect_key) ZEND_FE(array_intersect_ukey, arginfo_array_intersect_ukey) - ZEND_FE(array_intersect, arginfo_array_intersect) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_intersect, arginfo_array_intersect) ZEND_FE(array_uintersect, arginfo_array_uintersect) - ZEND_FE(array_intersect_assoc, arginfo_array_intersect_assoc) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_intersect_assoc, arginfo_array_intersect_assoc) ZEND_FE(array_uintersect_assoc, arginfo_array_uintersect_assoc) ZEND_FE(array_intersect_uassoc, arginfo_array_intersect_uassoc) ZEND_FE(array_uintersect_uassoc, arginfo_array_uintersect_uassoc) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_diff_key, arginfo_array_diff_key) - ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_diff_ukey, arginfo_array_diff_ukey) + ZEND_FE(array_diff_ukey, arginfo_array_diff_ukey) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_diff, arginfo_array_diff) ZEND_FE(array_udiff, arginfo_array_udiff) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_diff_assoc, arginfo_array_diff_assoc) @@ -2920,11 +2920,11 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(array_reduce, arginfo_array_reduce) ZEND_FE(array_filter, arginfo_array_filter) ZEND_FE(array_map, arginfo_array_map) - ZEND_FE(array_key_exists, arginfo_array_key_exists) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_key_exists, arginfo_array_key_exists) ZEND_FALIAS(key_exists, array_key_exists, arginfo_key_exists) ZEND_FE(array_chunk, arginfo_array_chunk) ZEND_FE(array_combine, arginfo_array_combine) - ZEND_FE(array_is_list, arginfo_array_is_list) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_is_list, arginfo_array_is_list) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(base64_encode, arginfo_base64_encode) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(base64_decode, arginfo_base64_decode) ZEND_FE(constant, arginfo_constant) @@ -3090,7 +3090,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(dirname, arginfo_dirname) ZEND_FE(pathinfo, arginfo_pathinfo) ZEND_FE(stristr, arginfo_stristr) - ZEND_FE(strstr, arginfo_strstr) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strstr, arginfo_strstr) ZEND_FALIAS(strchr, strstr, arginfo_strchr) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strpos, arginfo_strpos) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(stripos, arginfo_stripos) @@ -3277,48 +3277,48 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(link, arginfo_link) #endif ZEND_FE(mail, arginfo_mail) - ZEND_FE(abs, arginfo_abs) - ZEND_FE(ceil, arginfo_ceil) - ZEND_FE(floor, arginfo_floor) - ZEND_FE(round, arginfo_round) - ZEND_FE(sin, arginfo_sin) - ZEND_FE(cos, arginfo_cos) - ZEND_FE(tan, arginfo_tan) - ZEND_FE(asin, arginfo_asin) - ZEND_FE(acos, arginfo_acos) - ZEND_FE(atan, arginfo_atan) - ZEND_FE(atanh, arginfo_atanh) - ZEND_FE(atan2, arginfo_atan2) - ZEND_FE(sinh, arginfo_sinh) - ZEND_FE(cosh, arginfo_cosh) - ZEND_FE(tanh, arginfo_tanh) - ZEND_FE(asinh, arginfo_asinh) - ZEND_FE(acosh, arginfo_acosh) - ZEND_FE(expm1, arginfo_expm1) - ZEND_FE(log1p, arginfo_log1p) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(abs, arginfo_abs) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(ceil, arginfo_ceil) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(floor, arginfo_floor) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(round, arginfo_round) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(sin, arginfo_sin) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(cos, arginfo_cos) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(tan, arginfo_tan) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(asin, arginfo_asin) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(acos, arginfo_acos) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(atan, arginfo_atan) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(atanh, arginfo_atanh) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(atan2, arginfo_atan2) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(sinh, arginfo_sinh) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(cosh, arginfo_cosh) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(tanh, arginfo_tanh) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(asinh, arginfo_asinh) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(acosh, arginfo_acosh) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(expm1, arginfo_expm1) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(log1p, arginfo_log1p) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(pi, arginfo_pi) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_finite, arginfo_is_finite) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_nan, arginfo_is_nan) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(intdiv, arginfo_intdiv) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_infinite, arginfo_is_infinite) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(pow, arginfo_pow) - ZEND_FE(exp, arginfo_exp) - ZEND_FE(log, arginfo_log) - ZEND_FE(log10, arginfo_log10) - ZEND_FE(sqrt, arginfo_sqrt) - ZEND_FE(hypot, arginfo_hypot) - ZEND_FE(deg2rad, arginfo_deg2rad) - ZEND_FE(rad2deg, arginfo_rad2deg) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(exp, arginfo_exp) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(log, arginfo_log) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(log10, arginfo_log10) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(sqrt, arginfo_sqrt) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(hypot, arginfo_hypot) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(deg2rad, arginfo_deg2rad) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(rad2deg, arginfo_rad2deg) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(bindec, arginfo_bindec) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(hexdec, arginfo_hexdec) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(octdec, arginfo_octdec) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(decbin, arginfo_decbin) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(decoct, arginfo_decoct) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(dechex, arginfo_dechex) - ZEND_FE(base_convert, arginfo_base_convert) - ZEND_FE(number_format, arginfo_number_format) - ZEND_FE(fmod, arginfo_fmod) - ZEND_FE(fdiv, arginfo_fdiv) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(base_convert, arginfo_base_convert) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(number_format, arginfo_number_format) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(fmod, arginfo_fmod) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(fdiv, arginfo_fdiv) #if defined(HAVE_GETTIMEOFDAY) ZEND_FE(microtime, arginfo_microtime) #endif @@ -3328,8 +3328,8 @@ static const zend_function_entry ext_functions[] = { #if defined(HAVE_GETRUSAGE) ZEND_FE(getrusage, arginfo_getrusage) #endif - ZEND_FE(pack, arginfo_pack) - ZEND_FE(unpack, arginfo_unpack) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(pack, arginfo_pack) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(unpack, arginfo_unpack) ZEND_FE(password_get_info, arginfo_password_get_info) ZEND_FE(password_hash, arginfo_password_hash) ZEND_FE(password_needs_rehash, arginfo_password_needs_rehash) @@ -3400,30 +3400,30 @@ static const zend_function_entry ext_functions[] = { #if (defined(HAVE_SYS_TIME_H) || defined(PHP_WIN32)) ZEND_FALIAS(socket_set_timeout, stream_set_timeout, arginfo_socket_set_timeout) #endif - ZEND_FE(gettype, arginfo_gettype) - ZEND_FE(get_debug_type, arginfo_get_debug_type) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(gettype, arginfo_gettype) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(get_debug_type, arginfo_get_debug_type) ZEND_FE(settype, arginfo_settype) - ZEND_FE(intval, arginfo_intval) - ZEND_FE(floatval, arginfo_floatval) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(intval, arginfo_intval) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(floatval, arginfo_floatval) ZEND_FALIAS(doubleval, floatval, arginfo_doubleval) - ZEND_FE(boolval, arginfo_boolval) - ZEND_FE(strval, arginfo_strval) - ZEND_FE(is_null, arginfo_is_null) - ZEND_FE(is_resource, arginfo_is_resource) - ZEND_FE(is_bool, arginfo_is_bool) - ZEND_FE(is_int, arginfo_is_int) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(boolval, arginfo_boolval) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strval, arginfo_strval) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_null, arginfo_is_null) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_resource, arginfo_is_resource) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_bool, arginfo_is_bool) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_int, arginfo_is_int) ZEND_FALIAS(is_integer, is_int, arginfo_is_integer) ZEND_FALIAS(is_long, is_int, arginfo_is_long) - ZEND_FE(is_float, arginfo_is_float) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_float, arginfo_is_float) ZEND_FALIAS(is_double, is_float, arginfo_is_double) - ZEND_FE(is_numeric, arginfo_is_numeric) - ZEND_FE(is_string, arginfo_is_string) - ZEND_FE(is_array, arginfo_is_array) - ZEND_FE(is_object, arginfo_is_object) - ZEND_FE(is_scalar, arginfo_is_scalar) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_numeric, arginfo_is_numeric) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_string, arginfo_is_string) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_array, arginfo_is_array) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_object, arginfo_is_object) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_scalar, arginfo_is_scalar) ZEND_FE(is_callable, arginfo_is_callable) - ZEND_FE(is_iterable, arginfo_is_iterable) - ZEND_FE(is_countable, arginfo_is_countable) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_iterable, arginfo_is_iterable) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_countable, arginfo_is_countable) #if defined(HAVE_GETTIMEOFDAY) ZEND_FE(uniqid, arginfo_uniqid) #endif diff --git a/ext/standard/browscap.c b/ext/standard/browscap.c index ab2ae983d76e2..4fa766e3df802 100644 --- a/ext/standard/browscap.c +++ b/ext/standard/browscap.c @@ -432,7 +432,7 @@ static int browscap_read_file(char *filename, browser_data *browdata, int persis ctx.current_section_name = NULL; zend_hash_init(&ctx.str_interned, 8, NULL, str_interned_dtor, persistent); - zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_RAW, + zend_parse_ini_file(&fh, persistent, ZEND_INI_SCANNER_RAW, (zend_ini_parser_cb_t) php_browscap_parser_cb, &ctx); /* Destroy parser context */ @@ -612,7 +612,7 @@ static int browser_reg_compare(browscap_entry *entry, zend_string *agent_name, b } rc = pcre2_match(re, (PCRE2_SPTR)ZSTR_VAL(agent_name), ZSTR_LEN(agent_name), 0, 0, match_data, php_pcre_mctx()); php_pcre_free_match_data(match_data); - if (PCRE2_ERROR_NOMATCH != rc) { + if (rc >= 0) { /* If we've found a possible browser, we need to do a comparison of the number of characters changed in the user agent being checked versus the previous match found and the current match. */ diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 87f41b25eb9d5..984dfcd8a256e 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -81,7 +81,7 @@ if test "$PHP_EXTERNAL_LIBCRYPT" != "no"; then #include #include -int main() { +int main(void) { #if HAVE_CRYPT char *encrypted = crypt("rasmuslerdorf","rl"); return !encrypted || strcmp(encrypted,"rl.3StKT.4T8M"); @@ -111,7 +111,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char *encrypted = crypt("rasmuslerdorf","_J9..rasm"); return !encrypted || strcmp(encrypted,"_J9..rasmBYk8r9AiWNc"); @@ -141,7 +141,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char salt[15], answer[40]; char *encrypted; @@ -181,7 +181,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char salt[30], answer[70]; char *encrypted; @@ -218,7 +218,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char salt[21], answer[21+86]; char *encrypted; @@ -254,7 +254,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char salt[21], answer[21+43]; char *encrypted; diff --git a/ext/standard/crypt.c b/ext/standard/crypt.c index a3e0f00c9bcd5..ee54824ab02f8 100644 --- a/ext/standard/crypt.c +++ b/ext/standard/crypt.c @@ -124,6 +124,7 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch } else if ( salt[0] == '$' && salt[1] == '2' && + salt[2] != 0 && salt[3] == '$') { char output[PHP_MAX_SALT_LEN + 1]; diff --git a/ext/standard/crypt_blowfish.c b/ext/standard/crypt_blowfish.c index 3806a290aee40..351d40308089e 100644 --- a/ext/standard/crypt_blowfish.c +++ b/ext/standard/crypt_blowfish.c @@ -371,7 +371,6 @@ static const unsigned char BF_atoi64[0x60] = { #define BF_safe_atoi64(dst, src) \ { \ tmp = (unsigned char)(src); \ - if (tmp == '$') break; /* PHP hack */ \ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ tmp = BF_atoi64[tmp]; \ if (tmp > 63) return -1; \ @@ -399,13 +398,6 @@ static int BF_decode(BF_word *dst, const char *src, int size) *dptr++ = ((c3 & 0x03) << 6) | c4; } while (dptr < end); - if (end - dptr == size) { - return -1; - } - - while (dptr < end) /* PHP hack */ - *dptr++ = 0; - return 0; } diff --git a/ext/standard/file.c b/ext/standard/file.c index 345536624d8fc..f06b672fb6736 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -675,7 +675,7 @@ PHP_FUNCTION(file) } while ((p = memchr(p, eol_marker, (e-p)))); } - /* handle any left overs of files without new lines */ + /* handle any leftovers of files without new lines */ if (s != e) { p = e; goto parse_eol; @@ -1539,8 +1539,9 @@ PHPAPI int php_copy_file_ctx(const char *src, const char *dest, int src_flg, php php_stream *srcstream = NULL, *deststream = NULL; int ret = FAILURE; php_stream_statbuf src_s, dest_s; + int src_stat_flags = (src_flg & STREAM_DISABLE_OPEN_BASEDIR) ? PHP_STREAM_URL_STAT_IGNORE_OPEN_BASEDIR : 0; - switch (php_stream_stat_path_ex(src, 0, &src_s, ctx)) { + switch (php_stream_stat_path_ex(src, src_stat_flags, &src_s, ctx)) { case -1: /* non-statable stream */ goto safe_to_copy; @@ -1970,7 +1971,7 @@ PHPAPI HashTable *php_fgetcsv(php_stream *stream, char delimiter, char enclosure while ((*tmp != delimiter) && isspace((int)*(unsigned char *)tmp)) { tmp++; } - if (*tmp == enclosure) { + if (*tmp == enclosure && tmp < limit) { bptr = tmp; } } diff --git a/ext/standard/filters.c b/ext/standard/filters.c index b390ac7b0a212..d72c09b7d22b6 100644 --- a/ext/standard/filters.c +++ b/ext/standard/filters.c @@ -939,7 +939,7 @@ static php_conv_err_t php_conv_qprint_decode_convert(php_conv_qprint_decode *ins ps++, icnt--; break; } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\n') { - /* auto-detect line endings, looks like unix-lineendings, not to spec, but it is seem in the wild, a lot */ + /* auto-detect line endings, looks like unix-lineendings, not to spec, but it is seen in the wild, a lot */ lb_cnt = lb_ptr = 0; scan_stat = 0; ps++, icnt--; @@ -1187,7 +1187,7 @@ static php_conv *php_conv_open(int conv_mode, const HashTable *options, int pers } retval = pemalloc(sizeof(php_conv_base64_encode), persistent); if (lbchars != NULL) { - if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, line_len, lbchars, lbchars_len, 1, persistent)) { + if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, line_len, lbchars, lbchars_len, 1, persistent) != PHP_CONV_ERR_SUCCESS) { if (lbchars != NULL) { pefree(lbchars, 0); } @@ -1195,7 +1195,7 @@ static php_conv *php_conv_open(int conv_mode, const HashTable *options, int pers } pefree(lbchars, 0); } else { - if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, 0, NULL, 0, 0, persistent)) { + if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, 0, NULL, 0, 0, persistent) != PHP_CONV_ERR_SUCCESS) { goto out_failure; } } @@ -1239,13 +1239,13 @@ static php_conv *php_conv_open(int conv_mode, const HashTable *options, int pers } retval = pemalloc(sizeof(php_conv_qprint_encode), persistent); if (lbchars != NULL) { - if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, line_len, lbchars, lbchars_len, 1, opts, persistent)) { + if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, line_len, lbchars, lbchars_len, 1, opts, persistent) != PHP_CONV_ERR_SUCCESS) { pefree(lbchars, 0); goto out_failure; } pefree(lbchars, 0); } else { - if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, 0, NULL, 0, 0, opts, persistent)) { + if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, 0, NULL, 0, 0, opts, persistent) != PHP_CONV_ERR_SUCCESS) { goto out_failure; } } @@ -1262,13 +1262,13 @@ static php_conv *php_conv_open(int conv_mode, const HashTable *options, int pers retval = pemalloc(sizeof(php_conv_qprint_decode), persistent); if (lbchars != NULL) { - if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, lbchars, lbchars_len, 1, persistent)) { + if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, lbchars, lbchars_len, 1, persistent) != PHP_CONV_ERR_SUCCESS) { pefree(lbchars, 0); goto out_failure; } pefree(lbchars, 0); } else { - if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, NULL, 0, 0, persistent)) { + if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, NULL, 0, 0, persistent) != PHP_CONV_ERR_SUCCESS) { goto out_failure; } } @@ -1301,20 +1301,13 @@ static int php_convert_filter_ctor(php_convert_filter *inst, inst->stub_len = 0; if ((inst->cd = php_conv_open(conv_mode, conv_opts, persistent)) == NULL) { - goto out_failure; + if (inst->filtername != NULL) { + pefree(inst->filtername, persistent); + } + return FAILURE; } return SUCCESS; - -out_failure: - if (inst->cd != NULL) { - php_conv_dtor(inst->cd); - pefree(inst->cd, persistent); - } - if (inst->filtername != NULL) { - pefree(inst->filtername, persistent); - } - return FAILURE; } static void php_convert_filter_dtor(php_convert_filter *inst) diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 0be729a59fddb..89c89dcc469c8 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -299,9 +299,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char return stream; connect_errexit: - if (resource) { - php_url_free(resource); - } + php_url_free(resource); if (stream) { php_stream_close(stream); @@ -916,7 +914,7 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i } /* Attempt to delete the file */ - php_stream_printf(stream, "DELE %s\r\n", (resource->path != NULL ? ZSTR_VAL(resource->path) : "/")); + php_stream_printf(stream, "DELE %s\r\n", ZSTR_VAL(resource->path)); result = GET_FTP_RESULT(stream); if (result < 200 || result > 299) { @@ -979,7 +977,7 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr } /* Rename FROM */ - php_stream_printf(stream, "RNFR %s\r\n", (resource_from->path != NULL ? ZSTR_VAL(resource_from->path) : "/")); + php_stream_printf(stream, "RNFR %s\r\n", ZSTR_VAL(resource_from->path)); result = GET_FTP_RESULT(stream); if (result < 300 || result > 399) { @@ -990,7 +988,7 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr } /* Rename TO */ - php_stream_printf(stream, "RNTO %s\r\n", (resource_to->path != NULL ? ZSTR_VAL(resource_to->path) : "/")); + php_stream_printf(stream, "RNTO %s\r\n", ZSTR_VAL(resource_to->path)); result = GET_FTP_RESULT(stream); if (result < 200 || result > 299) { diff --git a/ext/standard/html.c b/ext/standard/html.c index 25dad2b7cc5f3..f736ef33d9c76 100644 --- a/ext/standard/html.c +++ b/ext/standard/html.c @@ -477,7 +477,7 @@ static inline int map_from_unicode(unsigned code, enum entity_charset charset, u *res = 0xF0; /* numero sign */ } else if (code == 0xA7) { *res = 0xFD; /* section sign */ - } else if (code >= 0x0401 && code <= 0x044F) { + } else if (code >= 0x0401 && code <= 0x045F) { if (code == 0x040D || code == 0x0450 || code == 0x045D) return FAILURE; *res = code - 0x360; @@ -712,9 +712,9 @@ static inline int process_named_entity_html(const char **buf, const char **start *start = *buf; /* "&" is represented by a 0x26 in all supported encodings. That means - * the byte after represents a character or is the leading byte of an + * the byte after represents a character or is the leading byte of a * sequence of 8-bit code units. If in the ranges below, it represents - * necessarily a alpha character because none of the supported encodings + * necessarily an alpha character because none of the supported encodings * has an overlap with ASCII in the leading byte (only on the second one) */ while ((**buf >= 'a' && **buf <= 'z') || (**buf >= 'A' && **buf <= 'Z') || diff --git a/ext/standard/http.c b/ext/standard/http.c index 95e583343aa1a..92d0af5cd9b6e 100644 --- a/ext/standard/http.c +++ b/ext/standard/http.c @@ -18,19 +18,89 @@ #include "php_ini.h" #include "url.h" -#define URL_DEFAULT_ARG_SEP "&" +static void php_url_encode_scalar(zval *scalar, smart_str *form_str, + int encoding_type, zend_ulong index_int, + const char *index_string, size_t index_string_len, + const char *num_prefix, size_t num_prefix_len, + const zend_string *key_prefix, + const zend_string *arg_sep) +{ + if (form_str->s) { + smart_str_append(form_str, arg_sep); + } + /* Simple key=value */ + if (key_prefix) { + smart_str_append(form_str, key_prefix); + } + if (index_string) { + zend_string *encoded_key; + if (encoding_type == PHP_QUERY_RFC3986) { + encoded_key = php_raw_url_encode(index_string, index_string_len); + } else { + encoded_key = php_url_encode(index_string, index_string_len); + } + smart_str_append(form_str, encoded_key); + zend_string_free(encoded_key); + } else { + /* Numeric key */ + if (num_prefix) { + smart_str_appendl(form_str, num_prefix, num_prefix_len); + } + smart_str_append_long(form_str, index_int); + } + if (key_prefix) { + smart_str_appendl(form_str, "%5D", strlen("%5D")); + } + smart_str_appendc(form_str, '='); + + switch (Z_TYPE_P(scalar)) { + case IS_STRING: { + zend_string *encoded_data; + if (encoding_type == PHP_QUERY_RFC3986) { + encoded_data = php_raw_url_encode(Z_STRVAL_P(scalar), Z_STRLEN_P(scalar)); + } else { + encoded_data = php_url_encode(Z_STRVAL_P(scalar), Z_STRLEN_P(scalar)); + } + smart_str_append(form_str, encoded_data); + zend_string_free(encoded_data); + break; + } + case IS_LONG: + smart_str_append_long(form_str, Z_LVAL_P(scalar)); + break; + case IS_DOUBLE: { + zend_string *encoded_data; + zend_string *tmp = zend_double_to_str(Z_DVAL_P(scalar)); + if (encoding_type == PHP_QUERY_RFC3986) { + encoded_data = php_raw_url_encode(ZSTR_VAL(tmp), ZSTR_LEN(tmp)); + } else { + encoded_data = php_url_encode(ZSTR_VAL(tmp), ZSTR_LEN(tmp)); + } + smart_str_append(form_str, encoded_data); + zend_string_free(tmp); + zend_string_free(encoded_data); + break; + } + case IS_FALSE: + smart_str_appendc(form_str, '0'); + break; + case IS_TRUE: + smart_str_appendc(form_str, '1'); + break; + /* All possible types are either handled here or previously */ + EMPTY_SWITCH_DEFAULT_CASE(); + } +} /* {{{ php_url_encode_hash */ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, const char *num_prefix, size_t num_prefix_len, - const char *key_prefix, size_t key_prefix_len, - const char *key_suffix, size_t key_suffix_len, - zval *type, const char *arg_sep, int enc_type) + const zend_string *key_prefix, + zval *type, const zend_string *arg_sep, int enc_type) { zend_string *key = NULL; - char *newprefix, *p; const char *prop_name; - size_t arg_sep_len, newprefix_len, prop_len; + size_t prop_len; zend_ulong idx; zval *zdata = NULL; ZEND_ASSERT(ht); @@ -41,12 +111,11 @@ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, } if (!arg_sep) { - arg_sep = INI_STR("arg_separator.output"); - if (!arg_sep || !strlen(arg_sep)) { - arg_sep = URL_DEFAULT_ARG_SEP; + arg_sep = zend_ini_str("arg_separator.output", strlen("arg_separator.output"), false); + if (ZSTR_LEN(arg_sep) == 0) { + arg_sep = ZSTR_CHAR('&'); } } - arg_sep_len = strlen(arg_sep); ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, zdata) { bool is_dynamic = 1; @@ -83,148 +152,73 @@ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, ZVAL_DEREF(zdata); if (Z_TYPE_P(zdata) == IS_ARRAY || Z_TYPE_P(zdata) == IS_OBJECT) { + zend_string *new_prefix; if (key) { - zend_string *ekey; + zend_string *encoded_key; if (enc_type == PHP_QUERY_RFC3986) { - ekey = php_raw_url_encode(prop_name, prop_len); + encoded_key = php_raw_url_encode(prop_name, prop_len); } else { - ekey = php_url_encode(prop_name, prop_len); + encoded_key = php_url_encode(prop_name, prop_len); } - newprefix_len = key_suffix_len + ZSTR_LEN(ekey) + key_prefix_len + 3 /* %5B */; - newprefix = emalloc(newprefix_len + 1); - p = newprefix; if (key_prefix) { - memcpy(p, key_prefix, key_prefix_len); - p += key_prefix_len; - } - - memcpy(p, ZSTR_VAL(ekey), ZSTR_LEN(ekey)); - p += ZSTR_LEN(ekey); - zend_string_free(ekey); - - if (key_suffix) { - memcpy(p, key_suffix, key_suffix_len); - p += key_suffix_len; - } - *(p++) = '%'; - *(p++) = '5'; - *(p++) = 'B'; - *p = '\0'; - } else { - char *ekey; - size_t ekey_len; - /* Is an integer key */ - ekey_len = spprintf(&ekey, 0, ZEND_LONG_FMT, idx); - newprefix_len = key_prefix_len + num_prefix_len + ekey_len + key_suffix_len + 3 /* %5B */; - newprefix = emalloc(newprefix_len + 1); - p = newprefix; - - if (key_prefix) { - memcpy(p, key_prefix, key_prefix_len); - p += key_prefix_len; - } - - if (num_prefix) { - memcpy(p, num_prefix, num_prefix_len); - p += num_prefix_len; + new_prefix = zend_string_concat3(ZSTR_VAL(key_prefix), ZSTR_LEN(key_prefix), ZSTR_VAL(encoded_key), ZSTR_LEN(encoded_key), "%5D%5B", strlen("%5D%5B")); + } else { + new_prefix = zend_string_concat2(ZSTR_VAL(encoded_key), ZSTR_LEN(encoded_key), "%5B", strlen("%5B")); } - - memcpy(p, ekey, ekey_len); - p += ekey_len; - efree(ekey); - - if (key_suffix) { - memcpy(p, key_suffix, key_suffix_len); - p += key_suffix_len; + zend_string_release_ex(encoded_key, false); + } else { /* is integer index */ + char *index_int_as_str; + size_t index_int_as_str_len; + + index_int_as_str_len = spprintf(&index_int_as_str, 0, ZEND_LONG_FMT, idx); + + if (key_prefix && num_prefix) { + /* zend_string_concat4() */ + size_t len = ZSTR_LEN(key_prefix) + num_prefix_len + index_int_as_str_len + strlen("%5D%5B"); + new_prefix = zend_string_alloc(len, 0); + + memcpy(ZSTR_VAL(new_prefix), ZSTR_VAL(key_prefix), ZSTR_LEN(key_prefix)); + memcpy(ZSTR_VAL(new_prefix) + ZSTR_LEN(key_prefix), num_prefix, num_prefix_len); + memcpy(ZSTR_VAL(new_prefix) + ZSTR_LEN(key_prefix) + num_prefix_len, index_int_as_str, index_int_as_str_len); + memcpy(ZSTR_VAL(new_prefix) + ZSTR_LEN(key_prefix) + num_prefix_len +index_int_as_str_len, "%5D%5B", strlen("%5D%5B")); + ZSTR_VAL(new_prefix)[len] = '\0'; + } else if (key_prefix) { + new_prefix = zend_string_concat3(ZSTR_VAL(key_prefix), ZSTR_LEN(key_prefix), index_int_as_str, index_int_as_str_len, "%5D%5B", strlen("%5D%5B")); + } else if (num_prefix) { + new_prefix = zend_string_concat3(num_prefix, num_prefix_len, index_int_as_str, index_int_as_str_len, "%5B", strlen("%5B")); + } else { + new_prefix = zend_string_concat2(index_int_as_str, index_int_as_str_len, "%5B", strlen("%5B")); } - *(p++) = '%'; - *(p++) = '5'; - *(p++) = 'B'; - *p = '\0'; + efree(index_int_as_str); } GC_TRY_PROTECT_RECURSION(ht); - php_url_encode_hash_ex(HASH_OF(zdata), formstr, NULL, 0, newprefix, newprefix_len, "%5D", 3, (Z_TYPE_P(zdata) == IS_OBJECT ? zdata : NULL), arg_sep, enc_type); + php_url_encode_hash_ex(HASH_OF(zdata), formstr, NULL, 0, new_prefix, (Z_TYPE_P(zdata) == IS_OBJECT ? zdata : NULL), arg_sep, enc_type); GC_TRY_UNPROTECT_RECURSION(ht); - efree(newprefix); + zend_string_release_ex(new_prefix, false); } else if (Z_TYPE_P(zdata) == IS_NULL || Z_TYPE_P(zdata) == IS_RESOURCE) { /* Skip these types */ continue; } else { - if (formstr->s) { - smart_str_appendl(formstr, arg_sep, arg_sep_len); - } - /* Simple key=value */ - if (key_prefix) { - smart_str_appendl(formstr, key_prefix, key_prefix_len); - } - if (key) { - zend_string *ekey; - if (enc_type == PHP_QUERY_RFC3986) { - ekey = php_raw_url_encode(prop_name, prop_len); - } else { - ekey = php_url_encode(prop_name, prop_len); - } - smart_str_append(formstr, ekey); - zend_string_free(ekey); - } else { - /* Numeric key */ - if (num_prefix) { - smart_str_appendl(formstr, num_prefix, num_prefix_len); - } - smart_str_append_long(formstr, idx); - } - if (key_suffix) { - smart_str_appendl(formstr, key_suffix, key_suffix_len); - } - smart_str_appendl(formstr, "=", 1); - switch (Z_TYPE_P(zdata)) { - case IS_STRING: { - zend_string *ekey; - if (enc_type == PHP_QUERY_RFC3986) { - ekey = php_raw_url_encode(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)); - } else { - ekey = php_url_encode(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)); - } - smart_str_append(formstr, ekey); - zend_string_free(ekey); - } - break; - case IS_LONG: - smart_str_append_long(formstr, Z_LVAL_P(zdata)); - break; - case IS_FALSE: - smart_str_appendl(formstr, "0", sizeof("0")-1); - break; - case IS_TRUE: - smart_str_appendl(formstr, "1", sizeof("1")-1); - break; - default: - { - zend_string *ekey; - zend_string *tmp; - zend_string *str= zval_get_tmp_string(zdata, &tmp); - if (enc_type == PHP_QUERY_RFC3986) { - ekey = php_raw_url_encode(ZSTR_VAL(str), ZSTR_LEN(str)); - } else { - ekey = php_url_encode(ZSTR_VAL(str), ZSTR_LEN(str)); - } - smart_str_append(formstr, ekey); - zend_tmp_string_release(tmp); - zend_string_free(ekey); - } - } + php_url_encode_scalar(zdata, formstr, + enc_type, idx, + prop_name, prop_len, + num_prefix, num_prefix_len, + key_prefix, + arg_sep); } } ZEND_HASH_FOREACH_END(); } /* }}} */ + /* If there is a prefix we need to close the key with an encoded ] ("%5D") */ /* {{{ Generates a form-encoded query string from an associative array or object. */ PHP_FUNCTION(http_build_query) { zval *formdata; - char *prefix = NULL, *arg_sep=NULL; - size_t arg_sep_len = 0, prefix_len = 0; + char *prefix = NULL; + size_t prefix_len = 0; + zend_string *arg_sep = NULL; smart_str formstr = {0}; zend_long enc_type = PHP_QUERY_RFC1738; @@ -232,11 +226,11 @@ PHP_FUNCTION(http_build_query) Z_PARAM_ARRAY_OR_OBJECT(formdata) Z_PARAM_OPTIONAL Z_PARAM_STRING(prefix, prefix_len) - Z_PARAM_STRING_OR_NULL(arg_sep, arg_sep_len) + Z_PARAM_STR(arg_sep) Z_PARAM_LONG(enc_type) ZEND_PARSE_PARAMETERS_END(); - php_url_encode_hash_ex(HASH_OF(formdata), &formstr, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL), arg_sep, (int)enc_type); + php_url_encode_hash_ex(HASH_OF(formdata), &formstr, prefix, prefix_len, /* key_prefix */ NULL, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL), arg_sep, (int)enc_type); RETURN_STR(smart_str_extract(&formstr)); } diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index be0ee30b7d832..89ea1220177f4 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -567,7 +567,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, * interprets the RFC literally and establishes a keep-alive connection, * unless the user specifically requests something else by specifying a * Connection header in the context options. Send that header even for - * HTTP/1.0 to avoid issues when the server respond with a HTTP/1.1 + * HTTP/1.0 to avoid issues when the server respond with an HTTP/1.1 * keep-alive response, which is the preferred response type. */ if ((have_header & HTTP_HEADER_CONNECTION) == 0) { smart_str_appends(&req_buf, "Connection: close\r\n"); @@ -857,7 +857,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, s = ZSTR_VAL(resource->path); if (!ZSTR_LEN(resource->path)) { zend_string_release_ex(resource->path, 0); - resource->path = zend_string_init("/", 1, 0); + resource->path = ZSTR_INIT_LITERAL("/", 0); s = ZSTR_VAL(resource->path); } else { *s = '/'; diff --git a/ext/standard/info.c b/ext/standard/info.c index 0c4081d2a9151..9d914508e9776 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -898,6 +898,12 @@ PHPAPI ZEND_COLD void php_print_info(int flag) efree(descr); } +#ifdef ZEND_MAX_EXECUTION_TIMERS + php_info_print_table_row(2, "Zend Max Execution Timers", "enabled" ); +#else + php_info_print_table_row(2, "Zend Max Execution Timers", "disabled" ); +#endif + #ifdef HAVE_IPV6 php_info_print_table_row(2, "IPv6 Support", "enabled" ); #else diff --git a/ext/standard/link.c b/ext/standard/link.c index c63f7ff268343..58098d14e8799 100644 --- a/ext/standard/link.c +++ b/ext/standard/link.c @@ -75,7 +75,7 @@ PHP_FUNCTION(readlink) if (ret == -1) { #ifdef PHP_WIN32 - php_error_docref(NULL, E_WARNING, "readlink failed to read the symbolic link (%s), error %d)", link, GetLastError()); + php_error_docref(NULL, E_WARNING, "readlink failed to read the symbolic link (%s), error %d", link, GetLastError()); #else php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); #endif diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 55790e6100fce..b1e0f14b8d5e2 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -121,7 +121,7 @@ static void php_mail_build_headers_elem(smart_str *s, zend_string *key, zval *va php_mail_build_headers_elems(s, key, val); break; default: - zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_type_name(val)); + zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_value_name(val)); } } @@ -136,8 +136,9 @@ static void php_mail_build_headers_elems(smart_str *s, zend_string *key, zval *v zend_type_error("Header \"%s\" must only contain numeric keys, \"%s\" found", ZSTR_VAL(key), ZSTR_VAL(tmp_key)); break; } + ZVAL_DEREF(tmp_val); if (Z_TYPE_P(tmp_val) != IS_STRING) { - zend_type_error("Header \"%s\" must only contain values of type string, %s found", ZSTR_VAL(key), zend_zval_type_name(tmp_val)); + zend_type_error("Header \"%s\" must only contain values of type string, %s found", ZSTR_VAL(key), zend_zval_value_name(tmp_val)); break; } php_mail_build_headers_elem(s, key, tmp_val); @@ -157,6 +158,7 @@ PHPAPI zend_string *php_mail_build_headers(HashTable *headers) zend_type_error("Header name cannot be numeric, " ZEND_LONG_FMT " given", idx); break; } + ZVAL_DEREF(val); /* https://tools.ietf.org/html/rfc2822#section-3.6 */ if (zend_string_equals_literal_ci(key, "orig-date")) { PHP_MAIL_BUILD_HEADER_CHECK("orig-date", s, key, val); @@ -429,6 +431,8 @@ PHPAPI int php_mail(const char *to, const char *subject, const char *message, co MAIL_RET(0); } + char *line_sep = PG(mail_mixed_lf_and_crlf) ? "\n" : "\r\n"; + if (PG(mail_x_header)) { const char *tmp = zend_get_executed_filename(); zend_string *f; @@ -436,7 +440,7 @@ PHPAPI int php_mail(const char *to, const char *subject, const char *message, co f = php_basename(tmp, strlen(tmp), NULL, 0); if (headers != NULL && *headers) { - spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s\r\n%s", php_getuid(), ZSTR_VAL(f), headers); + spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s%s%s", php_getuid(), ZSTR_VAL(f), line_sep, headers); } else { spprintf(&ahdr, 0, "X-PHP-Originating-Script: " ZEND_LONG_FMT ":%s", php_getuid(), ZSTR_VAL(f)); } @@ -510,12 +514,12 @@ PHPAPI int php_mail(const char *to, const char *subject, const char *message, co MAIL_RET(0); } #endif - fprintf(sendmail, "To: %s\r\n", to); - fprintf(sendmail, "Subject: %s\r\n", subject); + fprintf(sendmail, "To: %s%s", to, line_sep); + fprintf(sendmail, "Subject: %s%s", subject, line_sep); if (hdr != NULL) { - fprintf(sendmail, "%s\r\n", hdr); + fprintf(sendmail, "%s%s", hdr, line_sep); } - fprintf(sendmail, "\r\n%s\r\n", message); + fprintf(sendmail, "%s%s%s", line_sep, message, line_sep); ret = pclose(sendmail); #if PHP_SIGCHILD diff --git a/ext/standard/metaphone.c b/ext/standard/metaphone.c index 2ba7a839c88e9..149f95c127c6b 100644 --- a/ext/standard/metaphone.c +++ b/ext/standard/metaphone.c @@ -78,21 +78,29 @@ static const char _codes[26] = }; -#define ENCODE(c) (isalpha(c) ? _codes[((toupper(c)) - 'A')] : 0) +/* Note: these functions require an uppercase letter input! */ +static zend_always_inline char encode(char c) { + if (isalpha(c)) { + ZEND_ASSERT(c >= 'A' && c <= 'Z'); + return _codes[(c - 'A')]; + } else { + return 0; + } +} -#define isvowel(c) (ENCODE(c) & 1) /* AEIOU */ +#define isvowel(c) (encode(c) & 1) /* AEIOU */ /* These letters are passed through unchanged */ -#define NOCHANGE(c) (ENCODE(c) & 2) /* FJMNR */ +#define NOCHANGE(c) (encode(c) & 2) /* FJMNR */ /* These form diphthongs when preceding H */ -#define AFFECTH(c) (ENCODE(c) & 4) /* CGPST */ +#define AFFECTH(c) (encode(c) & 4) /* CGPST */ /* These make C and G soft */ -#define MAKESOFT(c) (ENCODE(c) & 8) /* EIY */ +#define MAKESOFT(c) (encode(c) & 8) /* EIY */ /* These prevent GH from becoming F */ -#define NOGHTOF(c) (ENCODE(c) & 16) /* BDH */ +#define NOGHTOF(c) (encode(c) & 16) /* BDH */ /*----------------------------- */ /* end of "metachar.h" */ @@ -101,16 +109,19 @@ static const char _codes[26] = /* I suppose I could have been using a character pointer instead of * accesssing the array directly... */ +#define Convert_Raw(c) toupper(c) /* Look at the next letter in the word */ -#define Next_Letter (toupper(word[w_idx+1])) +#define Read_Raw_Next_Letter (word[w_idx+1]) +#define Read_Next_Letter (Convert_Raw(Read_Raw_Next_Letter)) /* Look at the current letter in the word */ -#define Curr_Letter (toupper(word[w_idx])) +#define Read_Raw_Curr_Letter (word[w_idx]) +#define Read_Curr_Letter (Convert_Raw(Read_Raw_Curr_Letter)) /* Go N letters back. */ -#define Look_Back_Letter(n) (w_idx >= n ? toupper(word[w_idx-n]) : '\0') +#define Look_Back_Letter(n) (w_idx >= n ? Convert_Raw(word[w_idx-n]) : '\0') /* Previous letter. I dunno, should this return null on failure? */ -#define Prev_Letter (Look_Back_Letter(1)) +#define Read_Prev_Letter (Look_Back_Letter(1)) /* Look two letters down. It makes sure you don't walk off the string. */ -#define After_Next_Letter (Next_Letter != '\0' ? toupper(word[w_idx+2]) \ +#define Read_After_Next_Letter (Read_Raw_Next_Letter != '\0' ? Convert_Raw(word[w_idx+2]) \ : '\0') #define Look_Ahead_Letter(n) (toupper(Lookahead((char *) word+w_idx, n))) @@ -119,15 +130,13 @@ static const char _codes[26] = /* I probably could have just used strlen... */ static char Lookahead(char *word, int how_far) { - char letter_ahead = '\0'; /* null by default */ int idx; for (idx = 0; word[idx] != '\0' && idx < how_far; idx++); /* Edge forward in the string... */ - letter_ahead = word[idx]; /* idx will be either == to how_far or - * at the end of the string + return word[idx]; /* idx will be either == to how_far or + * at the end of the string where it will be null */ - return letter_ahead; } @@ -164,6 +173,7 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem int w_idx = 0; /* point in the phonization we're at. */ size_t p_idx = 0; /* end of the phoned phrase */ size_t max_buffer_len = 0; /* maximum length of the destination buffer */ + char curr_letter; ZEND_ASSERT(word != NULL); ZEND_ASSERT(max_phonemes >= 0); @@ -179,18 +189,20 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem /*-- The first phoneme has to be processed specially. --*/ /* Find our first letter */ - for (; !isalpha(Curr_Letter); w_idx++) { + for (; !isalpha(curr_letter = Read_Raw_Curr_Letter); w_idx++) { /* On the off chance we were given nothing but crap... */ - if (Curr_Letter == '\0') { + if (curr_letter == '\0') { End_Phoned_Word(); return; } } - switch (Curr_Letter) { + curr_letter = Convert_Raw(curr_letter); + + switch (curr_letter) { /* AE becomes E */ case 'A': - if (Next_Letter == 'E') { + if (Read_Next_Letter == 'E') { Phonize('E'); w_idx += 2; } @@ -204,7 +216,7 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem case 'G': case 'K': case 'P': - if (Next_Letter == 'N') { + if (Read_Next_Letter == 'N') { Phonize('N'); w_idx += 2; } @@ -212,16 +224,18 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem /* WH becomes W, WR becomes R W if followed by a vowel */ - case 'W': - if (Next_Letter == 'R') { - Phonize(Next_Letter); + case 'W': { + char next_letter = Read_Next_Letter; + if (next_letter == 'R') { + Phonize('R'); w_idx += 2; - } else if (Next_Letter == 'H' || isvowel(Next_Letter)) { + } else if (next_letter == 'H' || isvowel(next_letter)) { Phonize('W'); w_idx += 2; } /* else ignore */ break; + } /* X becomes S */ case 'X': Phonize('S'); @@ -236,7 +250,7 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem case 'I': case 'O': case 'U': - Phonize(Curr_Letter); + Phonize(curr_letter); w_idx++; break; default: @@ -247,7 +261,7 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem /* On to the metaphoning */ - for (; Curr_Letter != '\0' && + for (; (curr_letter = Read_Raw_Curr_Letter) != '\0' && (max_phonemes == 0 || Phone_Len < (size_t)max_phonemes); w_idx++) { /* How many letters to skip because an eariler encoding handled @@ -263,18 +277,23 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem */ /* Ignore non-alphas */ - if (!isalpha(Curr_Letter)) + if (!isalpha(curr_letter)) continue; + curr_letter = Convert_Raw(curr_letter); + /* Note: we can't cache curr_letter from the previous loop + * because of the skip_letter variable. */ + char prev_letter = Read_Prev_Letter; + /* Drop duplicates, except CC */ - if (Curr_Letter == Prev_Letter && - Curr_Letter != 'C') + if (curr_letter == prev_letter && + curr_letter != 'C') continue; - switch (Curr_Letter) { + switch (curr_letter) { /* B -> B unless in MB */ case 'B': - if (Prev_Letter != 'M') + if (prev_letter != 'M') Phonize('B'); break; /* 'sh' if -CIA- or -CH, but not SCH, except SCHW. @@ -283,20 +302,20 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem * dropped if -SCI-, SCE-, -SCY- (handed in S) * else K */ - case 'C': - if (MAKESOFT(Next_Letter)) { /* C[IEY] */ - if (After_Next_Letter == 'A' && - Next_Letter == 'I') { /* CIA */ + case 'C': { + char next_letter = Read_Next_Letter; + if (MAKESOFT(next_letter)) { /* C[IEY] */ + if (next_letter == 'I' && Read_After_Next_Letter == 'A') { /* CIA */ Phonize(SH); } /* SC[IEY] */ - else if (Prev_Letter == 'S') { + else if (prev_letter == 'S') { /* Dropped */ } else { Phonize('S'); } - } else if (Next_Letter == 'H') { - if ((!traditional) && (After_Next_Letter == 'R' || Prev_Letter == 'S')) { /* Christ, School */ + } else if (next_letter == 'H') { + if ((!traditional) && (prev_letter == 'S' || Read_After_Next_Letter == 'R')) { /* Christ, School */ Phonize('K'); } else { Phonize(SH); @@ -306,12 +325,13 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem Phonize('K'); } break; + } /* J if in -DGE-, -DGI- or -DGY- * else T */ case 'D': - if (Next_Letter == 'G' && - MAKESOFT(After_Next_Letter)) { + if (Read_Next_Letter == 'G' && + MAKESOFT(Read_After_Next_Letter)) { Phonize('J'); skip_letter++; } else @@ -323,8 +343,9 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem * else J if in -GE-, -GI, -GY and not GG * else K */ - case 'G': - if (Next_Letter == 'H') { + case 'G': { + char next_letter = Read_Next_Letter; + if (next_letter == 'H') { if (!(NOGHTOF(Look_Back_Letter(3)) || Look_Back_Letter(4) == 'H')) { Phonize('F'); @@ -332,38 +353,40 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem } else { /* silent */ } - } else if (Next_Letter == 'N') { - if (Isbreak(After_Next_Letter) || - (After_Next_Letter == 'E' && + } else if (next_letter == 'N') { + char after_next_letter = Read_After_Next_Letter; + if (Isbreak(after_next_letter) || + (after_next_letter == 'E' && Look_Ahead_Letter(3) == 'D')) { /* dropped */ } else Phonize('K'); - } else if (MAKESOFT(Next_Letter) && - Prev_Letter != 'G') { + } else if (MAKESOFT(next_letter) && + prev_letter != 'G') { Phonize('J'); } else { Phonize('K'); } break; + } /* H if before a vowel and not after C,G,P,S,T */ case 'H': - if (isvowel(Next_Letter) && - !AFFECTH(Prev_Letter)) + if (isvowel(Read_Next_Letter) && + !AFFECTH(prev_letter)) Phonize('H'); break; /* dropped if after C * else K */ case 'K': - if (Prev_Letter != 'C') + if (prev_letter != 'C') Phonize('K'); break; /* F if before H * else P */ case 'P': - if (Next_Letter == 'H') { + if (Read_Next_Letter == 'H') { Phonize('F'); } else { Phonize('P'); @@ -377,44 +400,50 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem /* 'sh' in -SH-, -SIO- or -SIA- or -SCHW- * else S */ - case 'S': - if (Next_Letter == 'I' && - (After_Next_Letter == 'O' || - After_Next_Letter == 'A')) { + case 'S': { + char next_letter = Read_Next_Letter; + char after_next_letter; + if (next_letter == 'I' && + ((after_next_letter = Read_After_Next_Letter) == 'O' || + after_next_letter == 'A')) { Phonize(SH); - } else if (Next_Letter == 'H') { + } else if (next_letter == 'H') { Phonize(SH); skip_letter++; - } else if ((!traditional) && (Next_Letter == 'C' && Look_Ahead_Letter(2) == 'H' && Look_Ahead_Letter(3) == 'W')) { + } else if ((!traditional) && (next_letter == 'C' && Look_Ahead_Letter(2) == 'H' && Look_Ahead_Letter(3) == 'W')) { Phonize(SH); skip_letter += 2; } else { Phonize('S'); } break; + } /* 'sh' in -TIA- or -TIO- * else 'th' before H * else T */ - case 'T': - if (Next_Letter == 'I' && - (After_Next_Letter == 'O' || - After_Next_Letter == 'A')) { + case 'T': { + char next_letter = Read_Next_Letter; + char after_next_letter; + if (next_letter == 'I' && + ((after_next_letter = Read_After_Next_Letter) == 'O' || + after_next_letter == 'A')) { Phonize(SH); - } else if (Next_Letter == 'H') { + } else if (next_letter == 'H') { Phonize(TH); skip_letter++; - } else if (!(Next_Letter == 'C' && After_Next_Letter == 'H')) { + } else if (!(next_letter == 'C' && Read_After_Next_Letter == 'H')) { Phonize('T'); } break; + } /* F */ case 'V': Phonize('F'); break; /* W before a vowel, else dropped */ case 'W': - if (isvowel(Next_Letter)) + if (isvowel(Read_Next_Letter)) Phonize('W'); break; /* KS */ @@ -424,7 +453,7 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem break; /* Y if followed by a vowel */ case 'Y': - if (isvowel(Next_Letter)) + if (isvowel(Read_Next_Letter)) Phonize('Y'); break; /* S */ @@ -438,7 +467,7 @@ static void metaphone(unsigned char *word, size_t word_len, zend_long max_phonem case 'M': case 'N': case 'R': - Phonize(Curr_Letter); + Phonize(curr_letter); break; default: /* nothing */ diff --git a/ext/standard/pack.c b/ext/standard/pack.c index f61214ca7e5d6..6abdc98bd6dca 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -750,7 +750,16 @@ PHP_FUNCTION(unpack) c = *format; if (c >= '0' && c <= '9') { - repetitions = atoi(format); + errno = 0; + long tmp = strtol(format, NULL, 10); + /* There is not strtoi. We have to check the range ourselves. + * With 32-bit long the INT_{MIN,MAX} are useless because long == int, but with 64-bit they do limit us to 32-bit. */ + if (errno || tmp < INT_MIN || tmp > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Type %c: integer overflow", type); + zend_array_destroy(Z_ARR_P(return_value)); + RETURN_FALSE; + } + repetitions = tmp; while (formatlen > 0 && *format >= '0' && *format <= '9') { format++; @@ -800,7 +809,7 @@ PHP_FUNCTION(unpack) case 'h': case 'H': - size = (repetitions > 0) ? (repetitions + (repetitions % 2)) / 2 : repetitions; + size = (repetitions > 0) ? ((unsigned int) repetitions + 1) / 2 : repetitions; repetitions = 1; break; @@ -865,12 +874,6 @@ PHP_FUNCTION(unpack) RETURN_THROWS(); } - if (size != 0 && size != -1 && size < 0) { - php_error_docref(NULL, E_WARNING, "Type %c: integer overflow", type); - zend_array_destroy(Z_ARR_P(return_value)); - RETURN_FALSE; - } - /* Do actual unpacking */ for (i = 0; i != repetitions; i++ ) { @@ -1178,7 +1181,7 @@ PHP_FUNCTION(unpack) /* Reached end of input for '*' repeater */ break; } else { - php_error_docref(NULL, E_WARNING, "Type %c: not enough input, need %d, have " ZEND_LONG_FMT, type, size, inputlen - inputpos); + php_error_docref(NULL, E_WARNING, "Type %c: not enough input values, need %d values but only " ZEND_LONG_FMT " %s provided", type, size, inputlen - inputpos, inputlen - inputpos == 1 ? "was" : "were"); zend_array_destroy(Z_ARR_P(return_value)); RETURN_FALSE; } diff --git a/ext/standard/password.c b/ext/standard/password.c index 503e72fbbf366..af1b68af1082d 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -83,7 +83,7 @@ static zend_string* php_password_make_salt(size_t length) /* {{{ */ } buffer = zend_string_alloc(length * 3 / 4 + 1, 0); - if (FAILURE == php_random_bytes_silent(ZSTR_VAL(buffer), ZSTR_LEN(buffer))) { + if (FAILURE == php_random_bytes_throw(ZSTR_VAL(buffer), ZSTR_LEN(buffer))) { zend_value_error("Unable to generate salt"); zend_string_release_ex(buffer, 0); return NULL; @@ -497,14 +497,14 @@ static const php_password_algo* php_password_algo_find_zval(zend_string *arg_str #else case 2: { - zend_string *n = zend_string_init("argon2i", sizeof("argon2i")-1, 0); + zend_string *n = ZSTR_INIT_LITERAL("argon2i", 0); const php_password_algo* ret = php_password_algo_find(n); zend_string_release(n); return ret; } case 3: { - zend_string *n = zend_string_init("argon2id", sizeof("argon2id")-1, 0); + zend_string *n = ZSTR_INIT_LITERAL("argon2id", 0); const php_password_algo* ret = php_password_algo_find(n); zend_string_release(n); return ret; diff --git a/ext/standard/php_http.h b/ext/standard/php_http.h index 1f98d8aa28437..9350be597ea1c 100644 --- a/ext/standard/php_http.h +++ b/ext/standard/php_http.h @@ -18,12 +18,12 @@ #define PHP_HTTP_H #include "php.h" +#include "zend_types.h" /* for zend_string */ #include "zend_smart_str.h" PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, const char *num_prefix, size_t num_prefix_len, - const char *key_prefix, size_t key_prefix_len, - const char *key_suffix, size_t key_suffix_len, - zval *type, const char *arg_sep, int enc_type); + const zend_string *key_prefix, + zval *type, const zend_string *arg_sep, int enc_type); #endif diff --git a/ext/standard/php_mail.h b/ext/standard/php_mail.h index 4e2f57749dd90..9536d1f62616d 100644 --- a/ext/standard/php_mail.h +++ b/ext/standard/php_mail.h @@ -33,7 +33,7 @@ do { \ } \ php_mail_build_headers_elems(&s, key, val); \ } else { \ - zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_type_name(val)); \ + zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_value_name(val)); \ } \ } while(0) @@ -45,7 +45,7 @@ do { \ } else if (Z_TYPE_P(val) == IS_ARRAY) { \ php_mail_build_headers_elems(&s, key, val); \ } else { \ - zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_type_name(val)); \ + zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_value_name(val)); \ } \ } while(0) diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 53ec6faa1019e..03fd0716bacf3 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -226,6 +226,28 @@ static void _php_free_envp(php_process_env env) } /* }}} */ +#if HAVE_SYS_WAIT_H +static pid_t waitpid_cached(php_process_handle *proc, int *wait_status, int options) +{ + if (proc->has_cached_exit_wait_status) { + *wait_status = proc->cached_exit_wait_status_value; + return proc->child; + } + + pid_t wait_pid = waitpid(proc->child, wait_status, options); + + /* The "exit" status is the final status of the process. + * If we were to cache the status unconditionally, + * we would return stale statuses in the future after the process continues. */ + if (wait_pid > 0 && WIFEXITED(*wait_status)) { + proc->has_cached_exit_wait_status = true; + proc->cached_exit_wait_status_value = *wait_status; + } + + return wait_pid; +} +#endif + /* {{{ proc_open_rsrc_dtor * Free `proc` resource, either because all references to it were dropped or because `pclose` or * `proc_close` were called */ @@ -270,7 +292,7 @@ static void proc_open_rsrc_dtor(zend_resource *rsrc) waitpid_options = WNOHANG; } do { - wait_pid = waitpid(proc->child, &wstatus, waitpid_options); + wait_pid = waitpid_cached(proc, &wstatus, waitpid_options); } while (wait_pid == -1 && errno == EINTR); if (wait_pid <= 0) { @@ -382,8 +404,12 @@ PHP_FUNCTION(proc_get_status) running = wstatus == STILL_ACTIVE; exitcode = running ? -1 : wstatus; + /* The status is always available on Windows and will always read the same, + * even if the child has already exited. This is because the result stays available + * until the child handle is closed. Hence no caching is used on Windows. */ + add_assoc_bool(return_value, "cached", false); #elif HAVE_SYS_WAIT_H - wait_pid = waitpid(proc->child, &wstatus, WNOHANG|WUNTRACED); + wait_pid = waitpid_cached(proc, &wstatus, WNOHANG|WUNTRACED); if (wait_pid == proc->child) { if (WIFEXITED(wstatus)) { @@ -404,6 +430,8 @@ PHP_FUNCTION(proc_get_status) * looking for either does not exist or is not a child of this process */ running = 0; } + + add_assoc_bool(return_value, "cached", proc->has_cached_exit_wait_status); #endif add_assoc_bool(return_value, "running", running); @@ -475,6 +503,12 @@ static zend_string *get_valid_arg_string(zval *zv, int elem_num) { return NULL; } + if (elem_num == 1 && ZSTR_LEN(str) == 0) { + zend_value_error("First element must contain a non-empty program name"); + zend_string_release(str); + return NULL; + } + if (strlen(ZSTR_VAL(str)) != ZSTR_LEN(str)) { zend_value_error("Command array element %d contains a null byte", elem_num); zend_string_release(str); @@ -900,7 +934,7 @@ static zend_result set_proc_descriptor_from_array(zval *descitem, descriptorspec goto finish; } if (Z_TYPE_P(ztarget) != IS_LONG) { - zend_value_error("Redirection target must be of type int, %s given", zend_zval_type_name(ztarget)); + zend_value_error("Redirection target must be of type int, %s given", zend_zval_value_name(ztarget)); goto finish; } @@ -1244,6 +1278,9 @@ PHP_FUNCTION(proc_open) proc->childHandle = childHandle; #endif proc->env = env; +#if HAVE_SYS_WAIT_H + proc->has_cached_exit_wait_status = false; +#endif /* Clean up all the child ends and then open streams on the parent * ends, where appropriate */ @@ -1276,7 +1313,7 @@ PHP_FUNCTION(proc_open) } #ifdef PHP_WIN32 - stream = php_stream_fopen_from_fd(_open_osfhandle((zend_intptr_t)descriptors[i].parentend, + stream = php_stream_fopen_from_fd(_open_osfhandle((intptr_t)descriptors[i].parentend, descriptors[i].mode_flags), mode_string, NULL); php_stream_set_option(stream, PHP_STREAM_OPTION_PIPE_BLOCKING, blocking_pipes, NULL); #else diff --git a/ext/standard/proc_open.h b/ext/standard/proc_open.h index d2e75ca1f3a58..411e7e3da8c74 100644 --- a/ext/standard/proc_open.h +++ b/ext/standard/proc_open.h @@ -43,4 +43,10 @@ typedef struct _php_process_handle { zend_resource **pipes; zend_string *command; php_process_env env; +#if HAVE_SYS_WAIT_H + /* We can only request the status once before it becomes unavailable. + * Cache the result so we can request it multiple times. */ + int cached_exit_wait_status_value; + bool has_cached_exit_wait_status; +#endif } php_process_handle; diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index ac2c777eea52b..53fa8d33dad6b 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -33,11 +33,13 @@ #ifndef PHP_WIN32 #define php_select(m, r, w, e, t) select(m, r, w, e, t) typedef unsigned long long php_timeout_ull; +#define PHP_TIMEOUT_ULL_MAX ULLONG_MAX #else #include "win32/select.h" #include "win32/sockets.h" #include "win32/console.h" typedef unsigned __int64 php_timeout_ull; +#define PHP_TIMEOUT_ULL_MAX UINT64_MAX #endif #define GET_CTX_OPT(stream, wrapper, name, val) (PHP_STREAM_CONTEXT(stream) && NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), wrapper, name))) @@ -134,14 +136,21 @@ PHP_FUNCTION(stream_socket_client) } /* prepare the timeout value for use */ - conv = (php_timeout_ull) (timeout * 1000000.0); + struct timeval *tv_pointer; + if (timeout < 0.0 || timeout >= (double) PHP_TIMEOUT_ULL_MAX / 1000000.0) { + tv_pointer = NULL; + } else { + conv = (php_timeout_ull) (timeout * 1000000.0); #ifdef PHP_WIN32 - tv.tv_sec = (long)(conv / 1000000); - tv.tv_usec =(long)(conv % 1000000); + tv.tv_sec = (long)(conv / 1000000); + tv.tv_usec = (long)(conv % 1000000); #else - tv.tv_sec = conv / 1000000; - tv.tv_usec = conv % 1000000; + tv.tv_sec = conv / 1000000; + tv.tv_usec = conv % 1000000; #endif + tv_pointer = &tv; + } + if (zerrno) { ZEND_TRY_ASSIGN_REF_LONG(zerrno, 0); } @@ -152,7 +161,7 @@ PHP_FUNCTION(stream_socket_client) stream = php_stream_xport_create(ZSTR_VAL(host), ZSTR_LEN(host), REPORT_ERRORS, STREAM_XPORT_CLIENT | (flags & PHP_STREAM_CLIENT_CONNECT ? STREAM_XPORT_CONNECT : 0) | (flags & PHP_STREAM_CLIENT_ASYNC_CONNECT ? STREAM_XPORT_CONNECT_ASYNC : 0), - hashkey, &tv, context, &errstr, &err); + hashkey, tv_pointer, context, &errstr, &err); if (stream == NULL) { @@ -213,10 +222,6 @@ PHP_FUNCTION(stream_socket_server) context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT); - if (context) { - GC_ADDREF(context->res); - } - if (zerrno) { ZEND_TRY_ASSIGN_REF_LONG(zerrno, 0); } @@ -279,19 +284,25 @@ PHP_FUNCTION(stream_socket_accept) php_stream_from_zval(stream, zstream); /* prepare the timeout value for use */ - conv = (php_timeout_ull) (timeout * 1000000.0); + struct timeval *tv_pointer; + if (timeout < 0.0 || timeout >= (double) PHP_TIMEOUT_ULL_MAX / 1000000.0) { + tv_pointer = NULL; + } else { + conv = (php_timeout_ull) (timeout * 1000000.0); #ifdef PHP_WIN32 - tv.tv_sec = (long)(conv / 1000000); - tv.tv_usec = (long)(conv % 1000000); + tv.tv_sec = (long)(conv / 1000000); + tv.tv_usec = (long)(conv % 1000000); #else - tv.tv_sec = conv / 1000000; - tv.tv_usec = conv % 1000000; + tv.tv_sec = conv / 1000000; + tv.tv_usec = conv % 1000000; #endif + tv_pointer = &tv; + } if (0 == php_stream_xport_accept(stream, &clistream, zpeername ? &peername : NULL, NULL, NULL, - &tv, &errstr + tv_pointer, &errstr ) && clistream) { if (peername) { diff --git a/ext/standard/string.c b/ext/standard/string.c index daed5b59cb339..335e6fd897128 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -48,6 +48,7 @@ #ifdef __SSE2__ #include +#include "Zend/zend_bitset.h" #endif /* this is read-only, so it's ok */ @@ -927,9 +928,6 @@ PHP_FUNCTION(explode) } /* }}} */ -/* {{{ An alias for implode */ -/* }}} */ - /* {{{ php_implode */ PHPAPI void php_implode(const zend_string *glue, HashTable *pieces, zval *return_value) { @@ -957,11 +955,14 @@ PHPAPI void php_implode(const zend_string *glue, HashTable *pieces, zval *return ptr = strings = do_alloca((sizeof(*strings)) * numelems, use_heap); + uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(glue); + ZEND_HASH_FOREACH_VAL(pieces, tmp) { if (EXPECTED(Z_TYPE_P(tmp) == IS_STRING)) { ptr->str = Z_STR_P(tmp); len += ZSTR_LEN(ptr->str); ptr->lval = 0; + flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(ptr->str); ptr++; } else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_LONG)) { zend_long val = Z_LVAL_P(tmp); @@ -980,12 +981,14 @@ PHPAPI void php_implode(const zend_string *glue, HashTable *pieces, zval *return ptr->str = zval_get_string_func(tmp); len += ZSTR_LEN(ptr->str); ptr->lval = 1; + flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(ptr->str); ptr++; } } ZEND_HASH_FOREACH_END(); /* numelems cannot be 0, we checked above */ str = zend_string_safe_alloc(numelems - 1, ZSTR_LEN(glue), len, 0); + GC_ADD_FLAGS(str, flags); cptr = ZSTR_VAL(str) + ZSTR_LEN(str); *cptr = 0; @@ -1080,7 +1083,7 @@ PHP_FUNCTION(strtok) if (!BG(strtok_string)) { /* String to tokenize not set. */ - // TODO: Should this warn? + php_error_docref(NULL, E_WARNING, "Both arguments must be provided when starting tokenization"); RETURN_FALSE; } @@ -1621,9 +1624,6 @@ PHP_FUNCTION(str_ends_with) } /* }}} */ -/* {{{ An alias for strstr */ -/* }}} */ - /* {{{ Finds position of first occurrence of a string within another */ PHP_FUNCTION(strpos) { @@ -2196,7 +2196,7 @@ PHP_FUNCTION(substr_replace) if (HT_IS_PACKED(repl_ht)) { while (repl_idx < repl_ht->nNumUsed) { tmp_repl = &repl_ht->arPacked[repl_idx]; - if (repl_ht != IS_UNDEF) { + if (Z_TYPE_P(tmp_repl) != IS_UNDEF) { break; } repl_idx++; @@ -2204,7 +2204,7 @@ PHP_FUNCTION(substr_replace) } else { while (repl_idx < repl_ht->nNumUsed) { tmp_repl = &repl_ht->arData[repl_idx].val; - if (repl_ht != IS_UNDEF) { + if (Z_TYPE_P(tmp_repl) != IS_UNDEF) { break; } repl_idx++; @@ -3472,15 +3472,10 @@ PHPAPI zend_string *php_addcslashes(zend_string *str, const char *what, size_t w ZEND_INTRIN_SSE4_2_FUNC_DECL(zend_string *php_addslashes_sse42(zend_string *str)); zend_string *php_addslashes_default(zend_string *str); -ZEND_INTRIN_SSE4_2_FUNC_DECL(void php_stripslashes_sse42(zend_string *str)); -void php_stripslashes_default(zend_string *str); - # ifdef ZEND_INTRIN_SSE4_2_FUNC_PROTO PHPAPI zend_string *php_addslashes(zend_string *str) __attribute__((ifunc("resolve_addslashes"))); -PHPAPI void php_stripslashes(zend_string *str) __attribute__((ifunc("resolve_stripslashes"))); typedef zend_string *(*php_addslashes_func_t)(zend_string *); -typedef void (*php_stripslashes_func_t)(zend_string *); ZEND_NO_SANITIZE_ADDRESS ZEND_ATTRIBUTE_UNUSED /* clang mistakenly warns about this */ @@ -3490,36 +3485,21 @@ static php_addslashes_func_t resolve_addslashes(void) { } return php_addslashes_default; } - -ZEND_NO_SANITIZE_ADDRESS -ZEND_ATTRIBUTE_UNUSED /* clang mistakenly warns about this */ -static php_stripslashes_func_t resolve_stripslashes(void) { - if (zend_cpu_supports_sse42()) { - return php_stripslashes_sse42; - } - return php_stripslashes_default; -} # else /* ZEND_INTRIN_SSE4_2_FUNC_PTR */ static zend_string *(*php_addslashes_ptr)(zend_string *str) = NULL; -static void (*php_stripslashes_ptr)(zend_string *str) = NULL; PHPAPI zend_string *php_addslashes(zend_string *str) { return php_addslashes_ptr(str); } -PHPAPI void php_stripslashes(zend_string *str) { - php_stripslashes_ptr(str); -} /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(string_intrin) { if (zend_cpu_supports_sse42()) { php_addslashes_ptr = php_addslashes_sse42; - php_stripslashes_ptr = php_stripslashes_sse42; } else { php_addslashes_ptr = php_addslashes_default; - php_stripslashes_ptr = php_stripslashes_default; } return SUCCESS; } @@ -3821,19 +3801,23 @@ static zend_always_inline char *php_stripslashes_impl(const char *str, char *out quad_word q; vst1q_u8(q.mem, vceqq_u8(x, vdupq_n_u8('\\'))); if (q.dw[0] | q.dw[1]) { - int i = 0; - for (; i < 16; i++) { + unsigned int i = 0; + while (i < 16) { if (q.mem[i] == 0) { *out++ = str[i]; + i++; continue; } i++; /* skip the slash */ - char s = str[i]; - if (s == '0') - *out++ = '\0'; - else - *out++ = s; /* preserve the next character */ + if (i < len) { + char s = str[i]; + if (s == '0') + *out++ = '\0'; + else + *out++ = s; /* preserve the next character */ + i++; + } } str += i; len -= i; @@ -3868,12 +3852,8 @@ static zend_always_inline char *php_stripslashes_impl(const char *str, char *out return out; } -#if defined(ZEND_INTRIN_SSE4_2_NATIVE) || defined(ZEND_INTRIN_SSE4_2_RESOLVER) -# ifdef ZEND_INTRIN_SSE4_2_NATIVE +#ifdef __SSE2__ PHPAPI void php_stripslashes(zend_string *str) -# elif defined(ZEND_INTRIN_SSE4_2_RESOLVER) -void php_stripslashes_sse42(zend_string *str) -# endif { const char *s = ZSTR_VAL(str); char *t = ZSTR_VAL(str); @@ -3924,14 +3904,8 @@ void php_stripslashes_sse42(zend_string *str) ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0'; } } -#endif - -#ifndef ZEND_INTRIN_SSE4_2_NATIVE -# ifdef ZEND_INTRIN_SSE4_2_RESOLVER -void php_stripslashes_default(zend_string *str) /* {{{ */ -# else +#else PHPAPI void php_stripslashes(zend_string *str) -# endif { const char *t = php_stripslashes_impl(ZSTR_VAL(str), ZSTR_VAL(str), ZSTR_LEN(str)); if (t != (ZSTR_VAL(str) + ZSTR_LEN(str))) { @@ -3939,7 +3913,6 @@ PHPAPI void php_stripslashes(zend_string *str) ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0'; } } -/* }}} */ #endif /* }}} */ @@ -4137,9 +4110,7 @@ static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, bool case_sensi /* Make sure we're dealing with strings and do the replacement. */ if (search_str && replace_ht) { - zend_argument_type_error(2, "must be of type %s when argument #1 ($search) is %s", - search_str ? "string" : "array", search_str ? "a string" : "an array" - ); + zend_argument_type_error(2, "must be of type string when argument #1 ($search) is a string"); RETURN_THROWS(); } @@ -5087,6 +5058,7 @@ PHP_FUNCTION(str_repeat) /* Initialize the result string */ result = zend_string_safe_alloc(ZSTR_LEN(input_str), mult, 0, 0); result_len = ZSTR_LEN(input_str) * mult; + ZSTR_COPY_CONCAT_PROPERTIES(result, input_str); /* Heavy optimization for situations where input string is 1 byte long */ if (ZSTR_LEN(input_str) == 1) { @@ -5132,7 +5104,7 @@ PHP_FUNCTION(count_chars) ZEND_PARSE_PARAMETERS_END(); if (mymode < 0 || mymode > 4) { - zend_argument_value_error(2, "must be between 1 and 4 (inclusive)"); + zend_argument_value_error(2, "must be between 0 and 4 (inclusive)"); RETURN_THROWS(); } @@ -5785,7 +5757,7 @@ PHP_FUNCTION(substr_compare) } if ((size_t)offset > ZSTR_LEN(s1)) { - zend_argument_value_error(3, "must be contained in argument #1 ($main_str)"); + zend_argument_value_error(3, "must be contained in argument #1 ($haystack)"); RETURN_THROWS(); } diff --git a/ext/standard/tests/array/003.phpt b/ext/standard/tests/array/003.phpt index 2cea8034bb10c..27d9cad4eb3b7 100644 --- a/ext/standard/tests/array/003.phpt +++ b/ext/standard/tests/array/003.phpt @@ -8,27 +8,27 @@ require(__DIR__ . '/data.inc'); function cmp ($a, $b) { is_array ($a) - and $a = array_sum ($a); + and $a = count($a); is_array ($b) - and $b = array_sum ($b); + and $b = count($b); return strcmp ($a, $b); } -echo " -- Testing uasort() -- \n"; +echo "-- Testing uasort() --\n"; uasort ($data, 'cmp'); var_dump ($data); -echo "\n -- Testing uksort() -- \n"; +echo "\n-- Testing uksort() --\n"; uksort ($data, 'cmp'); var_dump ($data); -echo "\n -- Testing usort() -- \n"; +echo "\n-- Testing usort() --\n"; usort ($data, 'cmp'); var_dump ($data); ?> --EXPECT-- --- Testing uasort() -- +-- Testing uasort() -- array(8) { [16777216]=> float(-0.3333333333333333) @@ -53,7 +53,7 @@ array(8) { string(4) "test" } - -- Testing uksort() -- +-- Testing uksort() -- array(8) { [-1000]=> array(2) { @@ -78,7 +78,7 @@ array(8) { int(27) } - -- Testing usort() -- +-- Testing usort() -- array(8) { [0]=> float(-0.3333333333333333) diff --git a/ext/standard/tests/array/array_column_scalar_index_strict_types.phpt b/ext/standard/tests/array/array_column_scalar_index_strict_types.phpt index ca5ff20197c67..322cd1f0ab0bf 100644 --- a/ext/standard/tests/array/array_column_scalar_index_strict_types.phpt +++ b/ext/standard/tests/array/array_column_scalar_index_strict_types.phpt @@ -47,15 +47,15 @@ try { DONE --EXPECT-- -- Testing array_column() column key parameter should be a string or an integer (testing bool) -- -array_column(): Argument #2 ($column_key) must be of type string|int|null, bool given -array_column(): Argument #2 ($column_key) must be of type string|int|null, bool given +array_column(): Argument #2 ($column_key) must be of type string|int|null, false given +array_column(): Argument #2 ($column_key) must be of type string|int|null, true given -- Testing array_column() column key parameter should be a string or integer (testing array) -- array_column(): Argument #2 ($column_key) must be of type string|int|null, array given -- Testing array_column() index key parameter should be a string or an integer (testing bool) -- -array_column(): Argument #3 ($index_key) must be of type string|int|null, bool given -array_column(): Argument #3 ($index_key) must be of type string|int|null, bool given +array_column(): Argument #3 ($index_key) must be of type string|int|null, false given +array_column(): Argument #3 ($index_key) must be of type string|int|null, true given -- Testing array_column() index key parameter should be a string or integer (testing array) -- array_column(): Argument #3 ($index_key) must be of type string|int|null, array given diff --git a/ext/standard/tests/array/array_diff_assoc_variation1.phpt b/ext/standard/tests/array/array_diff_assoc_variation1.phpt index 0909348620f5b..b16baa300f575 100644 --- a/ext/standard/tests/array/array_diff_assoc_variation1.phpt +++ b/ext/standard/tests/array/array_diff_assoc_variation1.phpt @@ -133,16 +133,16 @@ array_diff_assoc(): Argument #1 ($array) must be of type array, null given array_diff_assoc(): Argument #1 ($array) must be of type array, null given -- Iteration 12 -- -array_diff_assoc(): Argument #1 ($array) must be of type array, bool given +array_diff_assoc(): Argument #1 ($array) must be of type array, true given -- Iteration 13 -- -array_diff_assoc(): Argument #1 ($array) must be of type array, bool given +array_diff_assoc(): Argument #1 ($array) must be of type array, false given -- Iteration 14 -- -array_diff_assoc(): Argument #1 ($array) must be of type array, bool given +array_diff_assoc(): Argument #1 ($array) must be of type array, true given -- Iteration 15 -- -array_diff_assoc(): Argument #1 ($array) must be of type array, bool given +array_diff_assoc(): Argument #1 ($array) must be of type array, false given -- Iteration 16 -- array_diff_assoc(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_assoc_variation2.phpt b/ext/standard/tests/array/array_diff_assoc_variation2.phpt index 76967f2ce77be..a0b1bac329d9a 100644 --- a/ext/standard/tests/array/array_diff_assoc_variation2.phpt +++ b/ext/standard/tests/array/array_diff_assoc_variation2.phpt @@ -133,16 +133,16 @@ array_diff_assoc(): Argument #2 must be of type array, null given array_diff_assoc(): Argument #2 must be of type array, null given -- Iteration 12 -- -array_diff_assoc(): Argument #2 must be of type array, bool given +array_diff_assoc(): Argument #2 must be of type array, true given -- Iteration 13 -- -array_diff_assoc(): Argument #2 must be of type array, bool given +array_diff_assoc(): Argument #2 must be of type array, false given -- Iteration 14 -- -array_diff_assoc(): Argument #2 must be of type array, bool given +array_diff_assoc(): Argument #2 must be of type array, true given -- Iteration 15 -- -array_diff_assoc(): Argument #2 must be of type array, bool given +array_diff_assoc(): Argument #2 must be of type array, false given -- Iteration 16 -- array_diff_assoc(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_key_variation1.phpt b/ext/standard/tests/array/array_diff_key_variation1.phpt index 525df63819b33..7b422153a0a0f 100644 --- a/ext/standard/tests/array/array_diff_key_variation1.phpt +++ b/ext/standard/tests/array/array_diff_key_variation1.phpt @@ -147,20 +147,20 @@ array_diff_key(): Argument #1 ($array) must be of type array, null given array_diff_key(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_diff_key(): Argument #1 ($array) must be of type array, bool given -array_diff_key(): Argument #1 ($array) must be of type array, bool given +array_diff_key(): Argument #1 ($array) must be of type array, true given +array_diff_key(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_diff_key(): Argument #1 ($array) must be of type array, bool given -array_diff_key(): Argument #1 ($array) must be of type array, bool given +array_diff_key(): Argument #1 ($array) must be of type array, false given +array_diff_key(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_diff_key(): Argument #1 ($array) must be of type array, bool given -array_diff_key(): Argument #1 ($array) must be of type array, bool given +array_diff_key(): Argument #1 ($array) must be of type array, true given +array_diff_key(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_diff_key(): Argument #1 ($array) must be of type array, bool given -array_diff_key(): Argument #1 ($array) must be of type array, bool given +array_diff_key(): Argument #1 ($array) must be of type array, false given +array_diff_key(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_diff_key(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_key_variation2.phpt b/ext/standard/tests/array/array_diff_key_variation2.phpt index a6e7201cb7a49..b7093606c60ae 100644 --- a/ext/standard/tests/array/array_diff_key_variation2.phpt +++ b/ext/standard/tests/array/array_diff_key_variation2.phpt @@ -148,20 +148,20 @@ array_diff_key(): Argument #2 must be of type array, null given array_diff_key(): Argument #2 must be of type array, null given --lowercase true-- -array_diff_key(): Argument #2 must be of type array, bool given -array_diff_key(): Argument #2 must be of type array, bool given +array_diff_key(): Argument #2 must be of type array, true given +array_diff_key(): Argument #2 must be of type array, true given --lowercase false-- -array_diff_key(): Argument #2 must be of type array, bool given -array_diff_key(): Argument #2 must be of type array, bool given +array_diff_key(): Argument #2 must be of type array, false given +array_diff_key(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_diff_key(): Argument #2 must be of type array, bool given -array_diff_key(): Argument #2 must be of type array, bool given +array_diff_key(): Argument #2 must be of type array, true given +array_diff_key(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_diff_key(): Argument #2 must be of type array, bool given -array_diff_key(): Argument #2 must be of type array, bool given +array_diff_key(): Argument #2 must be of type array, false given +array_diff_key(): Argument #2 must be of type array, false given --empty string DQ-- array_diff_key(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_uassoc_variation1.phpt b/ext/standard/tests/array/array_diff_uassoc_variation1.phpt index 7c02e5d142759..49d6903a90eab 100644 --- a/ext/standard/tests/array/array_diff_uassoc_variation1.phpt +++ b/ext/standard/tests/array/array_diff_uassoc_variation1.phpt @@ -143,16 +143,16 @@ array_diff_uassoc(): Argument #1 ($array) must be of type array, null given array_diff_uassoc(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_diff_uassoc(): Argument #1 ($array) must be of type array, bool given +array_diff_uassoc(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_diff_uassoc(): Argument #1 ($array) must be of type array, bool given +array_diff_uassoc(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_diff_uassoc(): Argument #1 ($array) must be of type array, bool given +array_diff_uassoc(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_diff_uassoc(): Argument #1 ($array) must be of type array, bool given +array_diff_uassoc(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_diff_uassoc(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_uassoc_variation2.phpt b/ext/standard/tests/array/array_diff_uassoc_variation2.phpt index 36fd109bb6c8b..7466da23d4260 100644 --- a/ext/standard/tests/array/array_diff_uassoc_variation2.phpt +++ b/ext/standard/tests/array/array_diff_uassoc_variation2.phpt @@ -143,16 +143,16 @@ array_diff_uassoc(): Argument #2 must be of type array, null given array_diff_uassoc(): Argument #2 must be of type array, null given --lowercase true-- -array_diff_uassoc(): Argument #2 must be of type array, bool given +array_diff_uassoc(): Argument #2 must be of type array, true given --lowercase false-- -array_diff_uassoc(): Argument #2 must be of type array, bool given +array_diff_uassoc(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_diff_uassoc(): Argument #2 must be of type array, bool given +array_diff_uassoc(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_diff_uassoc(): Argument #2 must be of type array, bool given +array_diff_uassoc(): Argument #2 must be of type array, false given --empty string DQ-- array_diff_uassoc(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_ukey_variation1.phpt b/ext/standard/tests/array/array_diff_ukey_variation1.phpt index 9e15307f23331..125406497eda8 100644 --- a/ext/standard/tests/array/array_diff_ukey_variation1.phpt +++ b/ext/standard/tests/array/array_diff_ukey_variation1.phpt @@ -155,20 +155,20 @@ array_diff_ukey(): Argument #1 ($array) must be of type array, null given array_diff_ukey(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_diff_ukey(): Argument #1 ($array) must be of type array, bool given -array_diff_ukey(): Argument #1 ($array) must be of type array, bool given +array_diff_ukey(): Argument #1 ($array) must be of type array, true given +array_diff_ukey(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_diff_ukey(): Argument #1 ($array) must be of type array, bool given -array_diff_ukey(): Argument #1 ($array) must be of type array, bool given +array_diff_ukey(): Argument #1 ($array) must be of type array, false given +array_diff_ukey(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_diff_ukey(): Argument #1 ($array) must be of type array, bool given -array_diff_ukey(): Argument #1 ($array) must be of type array, bool given +array_diff_ukey(): Argument #1 ($array) must be of type array, true given +array_diff_ukey(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_diff_ukey(): Argument #1 ($array) must be of type array, bool given -array_diff_ukey(): Argument #1 ($array) must be of type array, bool given +array_diff_ukey(): Argument #1 ($array) must be of type array, false given +array_diff_ukey(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_diff_ukey(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_ukey_variation2.phpt b/ext/standard/tests/array/array_diff_ukey_variation2.phpt index dd79e53b5e220..cf71a26d22be1 100644 --- a/ext/standard/tests/array/array_diff_ukey_variation2.phpt +++ b/ext/standard/tests/array/array_diff_ukey_variation2.phpt @@ -159,20 +159,20 @@ array_diff_ukey(): Argument #2 must be of type array, null given array_diff_ukey(): Argument #2 must be of type array, null given --lowercase true-- -array_diff_ukey(): Argument #2 must be of type array, bool given -array_diff_ukey(): Argument #2 must be of type array, bool given +array_diff_ukey(): Argument #2 must be of type array, true given +array_diff_ukey(): Argument #2 must be of type array, true given --lowercase false-- -array_diff_ukey(): Argument #2 must be of type array, bool given -array_diff_ukey(): Argument #2 must be of type array, bool given +array_diff_ukey(): Argument #2 must be of type array, false given +array_diff_ukey(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_diff_ukey(): Argument #2 must be of type array, bool given -array_diff_ukey(): Argument #2 must be of type array, bool given +array_diff_ukey(): Argument #2 must be of type array, true given +array_diff_ukey(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_diff_ukey(): Argument #2 must be of type array, bool given -array_diff_ukey(): Argument #2 must be of type array, bool given +array_diff_ukey(): Argument #2 must be of type array, false given +array_diff_ukey(): Argument #2 must be of type array, false given --empty string DQ-- array_diff_ukey(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_variation1.phpt b/ext/standard/tests/array/array_diff_variation1.phpt index 075cf66f7bd41..1031b6f947e0c 100644 --- a/ext/standard/tests/array/array_diff_variation1.phpt +++ b/ext/standard/tests/array/array_diff_variation1.phpt @@ -122,13 +122,13 @@ echo "Done"; -- Iteration 11 --array_diff(): Argument #1 ($array) must be of type array, null given --- Iteration 12 --array_diff(): Argument #1 ($array) must be of type array, bool given +-- Iteration 12 --array_diff(): Argument #1 ($array) must be of type array, true given --- Iteration 13 --array_diff(): Argument #1 ($array) must be of type array, bool given +-- Iteration 13 --array_diff(): Argument #1 ($array) must be of type array, false given --- Iteration 14 --array_diff(): Argument #1 ($array) must be of type array, bool given +-- Iteration 14 --array_diff(): Argument #1 ($array) must be of type array, true given --- Iteration 15 --array_diff(): Argument #1 ($array) must be of type array, bool given +-- Iteration 15 --array_diff(): Argument #1 ($array) must be of type array, false given -- Iteration 16 --array_diff(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_diff_variation2.phpt b/ext/standard/tests/array/array_diff_variation2.phpt index 68e933e29924b..2b03f22513695 100644 --- a/ext/standard/tests/array/array_diff_variation2.phpt +++ b/ext/standard/tests/array/array_diff_variation2.phpt @@ -121,13 +121,13 @@ echo "Done"; -- Iteration 11 --array_diff(): Argument #2 must be of type array, null given --- Iteration 12 --array_diff(): Argument #2 must be of type array, bool given +-- Iteration 12 --array_diff(): Argument #2 must be of type array, true given --- Iteration 13 --array_diff(): Argument #2 must be of type array, bool given +-- Iteration 13 --array_diff(): Argument #2 must be of type array, false given --- Iteration 14 --array_diff(): Argument #2 must be of type array, bool given +-- Iteration 14 --array_diff(): Argument #2 must be of type array, true given --- Iteration 15 --array_diff(): Argument #2 must be of type array, bool given +-- Iteration 15 --array_diff(): Argument #2 must be of type array, false given -- Iteration 16 --array_diff(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_fill_error2.phpt b/ext/standard/tests/array/array_fill_error2.phpt new file mode 100644 index 0000000000000..1f8b841c8421f --- /dev/null +++ b/ext/standard/tests/array/array_fill_error2.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test array_fill() function : error conditions - count is too large +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} + +// calling array_fill() with 'count' equals to INT_MAX +$array = array_fill(0, $intMax, 1); + +?> +--EXPECTF-- +array_fill(): Argument #2 ($count) is too large + +Fatal error: Possible integer overflow in memory allocation (%d * %d + %d) in %s on line %d diff --git a/ext/standard/tests/array/array_intersect_assoc_variation1.phpt b/ext/standard/tests/array/array_intersect_assoc_variation1.phpt index 72d862958b5cb..9c9cef73dd1fb 100644 --- a/ext/standard/tests/array/array_intersect_assoc_variation1.phpt +++ b/ext/standard/tests/array/array_intersect_assoc_variation1.phpt @@ -146,17 +146,17 @@ array_intersect_assoc(): Argument #1 ($array) must be of type array, null given -- Iteration 11 --array_intersect_assoc(): Argument #1 ($array) must be of type array, null given array_intersect_assoc(): Argument #1 ($array) must be of type array, null given --- Iteration 12 --array_intersect_assoc(): Argument #1 ($array) must be of type array, bool given -array_intersect_assoc(): Argument #1 ($array) must be of type array, bool given +-- Iteration 12 --array_intersect_assoc(): Argument #1 ($array) must be of type array, true given +array_intersect_assoc(): Argument #1 ($array) must be of type array, true given --- Iteration 13 --array_intersect_assoc(): Argument #1 ($array) must be of type array, bool given -array_intersect_assoc(): Argument #1 ($array) must be of type array, bool given +-- Iteration 13 --array_intersect_assoc(): Argument #1 ($array) must be of type array, false given +array_intersect_assoc(): Argument #1 ($array) must be of type array, false given --- Iteration 14 --array_intersect_assoc(): Argument #1 ($array) must be of type array, bool given -array_intersect_assoc(): Argument #1 ($array) must be of type array, bool given +-- Iteration 14 --array_intersect_assoc(): Argument #1 ($array) must be of type array, true given +array_intersect_assoc(): Argument #1 ($array) must be of type array, true given --- Iteration 15 --array_intersect_assoc(): Argument #1 ($array) must be of type array, bool given -array_intersect_assoc(): Argument #1 ($array) must be of type array, bool given +-- Iteration 15 --array_intersect_assoc(): Argument #1 ($array) must be of type array, false given +array_intersect_assoc(): Argument #1 ($array) must be of type array, false given -- Iteration 16 --array_intersect_assoc(): Argument #1 ($array) must be of type array, string given array_intersect_assoc(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_assoc_variation2.phpt b/ext/standard/tests/array/array_intersect_assoc_variation2.phpt index 78ed38f153b46..31b54469863af 100644 --- a/ext/standard/tests/array/array_intersect_assoc_variation2.phpt +++ b/ext/standard/tests/array/array_intersect_assoc_variation2.phpt @@ -147,17 +147,17 @@ array_intersect_assoc(): Argument #2 must be of type array, null given -- Iteration 11 --array_intersect_assoc(): Argument #2 must be of type array, null given array_intersect_assoc(): Argument #2 must be of type array, null given --- Iteration 12 --array_intersect_assoc(): Argument #2 must be of type array, bool given -array_intersect_assoc(): Argument #2 must be of type array, bool given +-- Iteration 12 --array_intersect_assoc(): Argument #2 must be of type array, true given +array_intersect_assoc(): Argument #2 must be of type array, true given --- Iteration 13 --array_intersect_assoc(): Argument #2 must be of type array, bool given -array_intersect_assoc(): Argument #2 must be of type array, bool given +-- Iteration 13 --array_intersect_assoc(): Argument #2 must be of type array, false given +array_intersect_assoc(): Argument #2 must be of type array, false given --- Iteration 14 --array_intersect_assoc(): Argument #2 must be of type array, bool given -array_intersect_assoc(): Argument #2 must be of type array, bool given +-- Iteration 14 --array_intersect_assoc(): Argument #2 must be of type array, true given +array_intersect_assoc(): Argument #2 must be of type array, true given --- Iteration 15 --array_intersect_assoc(): Argument #2 must be of type array, bool given -array_intersect_assoc(): Argument #2 must be of type array, bool given +-- Iteration 15 --array_intersect_assoc(): Argument #2 must be of type array, false given +array_intersect_assoc(): Argument #2 must be of type array, false given -- Iteration 16 --array_intersect_assoc(): Argument #2 must be of type array, string given array_intersect_assoc(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_key_variation1.phpt b/ext/standard/tests/array/array_intersect_key_variation1.phpt index 9256234597d00..ae11e0a2ec931 100644 --- a/ext/standard/tests/array/array_intersect_key_variation1.phpt +++ b/ext/standard/tests/array/array_intersect_key_variation1.phpt @@ -151,20 +151,20 @@ array_intersect_key(): Argument #1 ($array) must be of type array, null given array_intersect_key(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_intersect_key(): Argument #1 ($array) must be of type array, bool given -array_intersect_key(): Argument #1 ($array) must be of type array, bool given +array_intersect_key(): Argument #1 ($array) must be of type array, true given +array_intersect_key(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_intersect_key(): Argument #1 ($array) must be of type array, bool given -array_intersect_key(): Argument #1 ($array) must be of type array, bool given +array_intersect_key(): Argument #1 ($array) must be of type array, false given +array_intersect_key(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_intersect_key(): Argument #1 ($array) must be of type array, bool given -array_intersect_key(): Argument #1 ($array) must be of type array, bool given +array_intersect_key(): Argument #1 ($array) must be of type array, true given +array_intersect_key(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_intersect_key(): Argument #1 ($array) must be of type array, bool given -array_intersect_key(): Argument #1 ($array) must be of type array, bool given +array_intersect_key(): Argument #1 ($array) must be of type array, false given +array_intersect_key(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_intersect_key(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_key_variation2.phpt b/ext/standard/tests/array/array_intersect_key_variation2.phpt index 70401e8469269..d2a8672e284c1 100644 --- a/ext/standard/tests/array/array_intersect_key_variation2.phpt +++ b/ext/standard/tests/array/array_intersect_key_variation2.phpt @@ -152,20 +152,20 @@ array_intersect_key(): Argument #2 must be of type array, null given array_intersect_key(): Argument #2 must be of type array, null given --lowercase true-- -array_intersect_key(): Argument #2 must be of type array, bool given -array_intersect_key(): Argument #2 must be of type array, bool given +array_intersect_key(): Argument #2 must be of type array, true given +array_intersect_key(): Argument #2 must be of type array, true given --lowercase false-- -array_intersect_key(): Argument #2 must be of type array, bool given -array_intersect_key(): Argument #2 must be of type array, bool given +array_intersect_key(): Argument #2 must be of type array, false given +array_intersect_key(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_intersect_key(): Argument #2 must be of type array, bool given -array_intersect_key(): Argument #2 must be of type array, bool given +array_intersect_key(): Argument #2 must be of type array, true given +array_intersect_key(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_intersect_key(): Argument #2 must be of type array, bool given -array_intersect_key(): Argument #2 must be of type array, bool given +array_intersect_key(): Argument #2 must be of type array, false given +array_intersect_key(): Argument #2 must be of type array, false given --empty string DQ-- array_intersect_key(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_uassoc_variation1.phpt b/ext/standard/tests/array/array_intersect_uassoc_variation1.phpt index 268d169c886e3..ea6ce6a1a5a16 100644 --- a/ext/standard/tests/array/array_intersect_uassoc_variation1.phpt +++ b/ext/standard/tests/array/array_intersect_uassoc_variation1.phpt @@ -159,20 +159,20 @@ array_intersect_uassoc(): Argument #1 ($array) must be of type array, null given array_intersect_uassoc(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_intersect_uassoc(): Argument #1 ($array) must be of type array, bool given -array_intersect_uassoc(): Argument #1 ($array) must be of type array, bool given +array_intersect_uassoc(): Argument #1 ($array) must be of type array, true given +array_intersect_uassoc(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_intersect_uassoc(): Argument #1 ($array) must be of type array, bool given -array_intersect_uassoc(): Argument #1 ($array) must be of type array, bool given +array_intersect_uassoc(): Argument #1 ($array) must be of type array, false given +array_intersect_uassoc(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_intersect_uassoc(): Argument #1 ($array) must be of type array, bool given -array_intersect_uassoc(): Argument #1 ($array) must be of type array, bool given +array_intersect_uassoc(): Argument #1 ($array) must be of type array, true given +array_intersect_uassoc(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_intersect_uassoc(): Argument #1 ($array) must be of type array, bool given -array_intersect_uassoc(): Argument #1 ($array) must be of type array, bool given +array_intersect_uassoc(): Argument #1 ($array) must be of type array, false given +array_intersect_uassoc(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_intersect_uassoc(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_uassoc_variation2.phpt b/ext/standard/tests/array/array_intersect_uassoc_variation2.phpt index 9377a09518d2f..03a7dc8d07e5c 100644 --- a/ext/standard/tests/array/array_intersect_uassoc_variation2.phpt +++ b/ext/standard/tests/array/array_intersect_uassoc_variation2.phpt @@ -159,20 +159,20 @@ array_intersect_uassoc(): Argument #2 must be of type array, null given array_intersect_uassoc(): Argument #2 must be of type array, null given --lowercase true-- -array_intersect_uassoc(): Argument #2 must be of type array, bool given -array_intersect_uassoc(): Argument #2 must be of type array, bool given +array_intersect_uassoc(): Argument #2 must be of type array, true given +array_intersect_uassoc(): Argument #2 must be of type array, true given --lowercase false-- -array_intersect_uassoc(): Argument #2 must be of type array, bool given -array_intersect_uassoc(): Argument #2 must be of type array, bool given +array_intersect_uassoc(): Argument #2 must be of type array, false given +array_intersect_uassoc(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_intersect_uassoc(): Argument #2 must be of type array, bool given -array_intersect_uassoc(): Argument #2 must be of type array, bool given +array_intersect_uassoc(): Argument #2 must be of type array, true given +array_intersect_uassoc(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_intersect_uassoc(): Argument #2 must be of type array, bool given -array_intersect_uassoc(): Argument #2 must be of type array, bool given +array_intersect_uassoc(): Argument #2 must be of type array, false given +array_intersect_uassoc(): Argument #2 must be of type array, false given --empty string DQ-- array_intersect_uassoc(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_ukey_variation1.phpt b/ext/standard/tests/array/array_intersect_ukey_variation1.phpt index 993994fc0792a..8195d45c294ea 100644 --- a/ext/standard/tests/array/array_intersect_ukey_variation1.phpt +++ b/ext/standard/tests/array/array_intersect_ukey_variation1.phpt @@ -157,20 +157,20 @@ array_intersect_ukey(): Argument #1 ($array) must be of type array, null given array_intersect_ukey(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_intersect_ukey(): Argument #1 ($array) must be of type array, bool given -array_intersect_ukey(): Argument #1 ($array) must be of type array, bool given +array_intersect_ukey(): Argument #1 ($array) must be of type array, true given +array_intersect_ukey(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_intersect_ukey(): Argument #1 ($array) must be of type array, bool given -array_intersect_ukey(): Argument #1 ($array) must be of type array, bool given +array_intersect_ukey(): Argument #1 ($array) must be of type array, false given +array_intersect_ukey(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_intersect_ukey(): Argument #1 ($array) must be of type array, bool given -array_intersect_ukey(): Argument #1 ($array) must be of type array, bool given +array_intersect_ukey(): Argument #1 ($array) must be of type array, true given +array_intersect_ukey(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_intersect_ukey(): Argument #1 ($array) must be of type array, bool given -array_intersect_ukey(): Argument #1 ($array) must be of type array, bool given +array_intersect_ukey(): Argument #1 ($array) must be of type array, false given +array_intersect_ukey(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_intersect_ukey(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_ukey_variation2.phpt b/ext/standard/tests/array/array_intersect_ukey_variation2.phpt index bdc0686774cdd..d32c0632ca5e5 100644 --- a/ext/standard/tests/array/array_intersect_ukey_variation2.phpt +++ b/ext/standard/tests/array/array_intersect_ukey_variation2.phpt @@ -157,20 +157,20 @@ array_intersect_ukey(): Argument #2 must be of type array, null given array_intersect_ukey(): Argument #2 must be of type array, null given --lowercase true-- -array_intersect_ukey(): Argument #2 must be of type array, bool given -array_intersect_ukey(): Argument #2 must be of type array, bool given +array_intersect_ukey(): Argument #2 must be of type array, true given +array_intersect_ukey(): Argument #2 must be of type array, true given --lowercase false-- -array_intersect_ukey(): Argument #2 must be of type array, bool given -array_intersect_ukey(): Argument #2 must be of type array, bool given +array_intersect_ukey(): Argument #2 must be of type array, false given +array_intersect_ukey(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_intersect_ukey(): Argument #2 must be of type array, bool given -array_intersect_ukey(): Argument #2 must be of type array, bool given +array_intersect_ukey(): Argument #2 must be of type array, true given +array_intersect_ukey(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_intersect_ukey(): Argument #2 must be of type array, bool given -array_intersect_ukey(): Argument #2 must be of type array, bool given +array_intersect_ukey(): Argument #2 must be of type array, false given +array_intersect_ukey(): Argument #2 must be of type array, false given --empty string DQ-- array_intersect_ukey(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_variation1.phpt b/ext/standard/tests/array/array_intersect_variation1.phpt index 81b77bd4aa308..733250b69f70b 100644 --- a/ext/standard/tests/array/array_intersect_variation1.phpt +++ b/ext/standard/tests/array/array_intersect_variation1.phpt @@ -146,17 +146,17 @@ array_intersect(): Argument #1 ($array) must be of type array, null given -- Iterator 11 --array_intersect(): Argument #1 ($array) must be of type array, null given array_intersect(): Argument #1 ($array) must be of type array, null given --- Iterator 12 --array_intersect(): Argument #1 ($array) must be of type array, bool given -array_intersect(): Argument #1 ($array) must be of type array, bool given +-- Iterator 12 --array_intersect(): Argument #1 ($array) must be of type array, true given +array_intersect(): Argument #1 ($array) must be of type array, true given --- Iterator 13 --array_intersect(): Argument #1 ($array) must be of type array, bool given -array_intersect(): Argument #1 ($array) must be of type array, bool given +-- Iterator 13 --array_intersect(): Argument #1 ($array) must be of type array, false given +array_intersect(): Argument #1 ($array) must be of type array, false given --- Iterator 14 --array_intersect(): Argument #1 ($array) must be of type array, bool given -array_intersect(): Argument #1 ($array) must be of type array, bool given +-- Iterator 14 --array_intersect(): Argument #1 ($array) must be of type array, true given +array_intersect(): Argument #1 ($array) must be of type array, true given --- Iterator 15 --array_intersect(): Argument #1 ($array) must be of type array, bool given -array_intersect(): Argument #1 ($array) must be of type array, bool given +-- Iterator 15 --array_intersect(): Argument #1 ($array) must be of type array, false given +array_intersect(): Argument #1 ($array) must be of type array, false given -- Iterator 16 --array_intersect(): Argument #1 ($array) must be of type array, string given array_intersect(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_intersect_variation2.phpt b/ext/standard/tests/array/array_intersect_variation2.phpt index d98e1162960ee..b09683446b87a 100644 --- a/ext/standard/tests/array/array_intersect_variation2.phpt +++ b/ext/standard/tests/array/array_intersect_variation2.phpt @@ -147,17 +147,17 @@ array_intersect(): Argument #2 must be of type array, null given -- Iterator 11 --array_intersect(): Argument #2 must be of type array, null given array_intersect(): Argument #2 must be of type array, null given --- Iterator 12 --array_intersect(): Argument #2 must be of type array, bool given -array_intersect(): Argument #2 must be of type array, bool given +-- Iterator 12 --array_intersect(): Argument #2 must be of type array, true given +array_intersect(): Argument #2 must be of type array, true given --- Iterator 13 --array_intersect(): Argument #2 must be of type array, bool given -array_intersect(): Argument #2 must be of type array, bool given +-- Iterator 13 --array_intersect(): Argument #2 must be of type array, false given +array_intersect(): Argument #2 must be of type array, false given --- Iterator 14 --array_intersect(): Argument #2 must be of type array, bool given -array_intersect(): Argument #2 must be of type array, bool given +-- Iterator 14 --array_intersect(): Argument #2 must be of type array, true given +array_intersect(): Argument #2 must be of type array, true given --- Iterator 15 --array_intersect(): Argument #2 must be of type array, bool given -array_intersect(): Argument #2 must be of type array, bool given +-- Iterator 15 --array_intersect(): Argument #2 must be of type array, false given +array_intersect(): Argument #2 must be of type array, false given -- Iterator 16 --array_intersect(): Argument #2 must be of type array, string given array_intersect(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_key_exists.phpt b/ext/standard/tests/array/array_key_exists.phpt index d6f9ca13de718..8cc2f9c5207c2 100644 --- a/ext/standard/tests/array/array_key_exists.phpt +++ b/ext/standard/tests/array/array_key_exists.phpt @@ -202,7 +202,7 @@ bool(false) bool(true) *** Testing error conditions *** -Illegal offset type +Cannot access offset of type array on array *** Testing operation on objects *** array_key_exists(): Argument #2 ($array) must be of type array, key_check given diff --git a/ext/standard/tests/array/array_key_exists_variation1.phpt b/ext/standard/tests/array/array_key_exists_variation1.phpt index 3a410258bb999..eb35d1bfae0c1 100644 --- a/ext/standard/tests/array/array_key_exists_variation1.phpt +++ b/ext/standard/tests/array/array_key_exists_variation1.phpt @@ -129,7 +129,7 @@ bool(false) bool(false) -- Iteration 13 -- -Illegal offset type +Cannot access offset of type array on array -- Iteration 14 -- bool(true) @@ -141,7 +141,7 @@ bool(true) bool(true) -- Iteration 17 -- -Illegal offset type +Cannot access offset of type object on array -- Iteration 18 -- bool(false) diff --git a/ext/standard/tests/array/array_merge_recursive_variation1.phpt b/ext/standard/tests/array/array_merge_recursive_variation1.phpt index 0a72aeeccd17e..121f7969d43c4 100644 --- a/ext/standard/tests/array/array_merge_recursive_variation1.phpt +++ b/ext/standard/tests/array/array_merge_recursive_variation1.phpt @@ -157,20 +157,20 @@ echo "Done"; -- With more arguments --array_merge_recursive(): Argument #1 must be of type array, null given -- Iteration 12 -- --- With default argument --array_merge_recursive(): Argument #1 must be of type array, bool given --- With more arguments --array_merge_recursive(): Argument #1 must be of type array, bool given +-- With default argument --array_merge_recursive(): Argument #1 must be of type array, true given +-- With more arguments --array_merge_recursive(): Argument #1 must be of type array, true given -- Iteration 13 -- --- With default argument --array_merge_recursive(): Argument #1 must be of type array, bool given --- With more arguments --array_merge_recursive(): Argument #1 must be of type array, bool given +-- With default argument --array_merge_recursive(): Argument #1 must be of type array, false given +-- With more arguments --array_merge_recursive(): Argument #1 must be of type array, false given -- Iteration 14 -- --- With default argument --array_merge_recursive(): Argument #1 must be of type array, bool given --- With more arguments --array_merge_recursive(): Argument #1 must be of type array, bool given +-- With default argument --array_merge_recursive(): Argument #1 must be of type array, true given +-- With more arguments --array_merge_recursive(): Argument #1 must be of type array, true given -- Iteration 15 -- --- With default argument --array_merge_recursive(): Argument #1 must be of type array, bool given --- With more arguments --array_merge_recursive(): Argument #1 must be of type array, bool given +-- With default argument --array_merge_recursive(): Argument #1 must be of type array, false given +-- With more arguments --array_merge_recursive(): Argument #1 must be of type array, false given -- Iteration 16 -- -- With default argument --array_merge_recursive(): Argument #1 must be of type array, string given diff --git a/ext/standard/tests/array/array_merge_recursive_variation2.phpt b/ext/standard/tests/array/array_merge_recursive_variation2.phpt index 981e7426c1d53..4588d8d160aaa 100644 --- a/ext/standard/tests/array/array_merge_recursive_variation2.phpt +++ b/ext/standard/tests/array/array_merge_recursive_variation2.phpt @@ -122,13 +122,13 @@ echo "Done"; -- Iteration 11 --array_merge_recursive(): Argument #2 must be of type array, null given --- Iteration 12 --array_merge_recursive(): Argument #2 must be of type array, bool given +-- Iteration 12 --array_merge_recursive(): Argument #2 must be of type array, true given --- Iteration 13 --array_merge_recursive(): Argument #2 must be of type array, bool given +-- Iteration 13 --array_merge_recursive(): Argument #2 must be of type array, false given --- Iteration 14 --array_merge_recursive(): Argument #2 must be of type array, bool given +-- Iteration 14 --array_merge_recursive(): Argument #2 must be of type array, true given --- Iteration 15 --array_merge_recursive(): Argument #2 must be of type array, bool given +-- Iteration 15 --array_merge_recursive(): Argument #2 must be of type array, false given -- Iteration 16 --array_merge_recursive(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_merge_variation2.phpt b/ext/standard/tests/array/array_merge_variation2.phpt index 9e7a8cab17895..2ef55565742fc 100644 --- a/ext/standard/tests/array/array_merge_variation2.phpt +++ b/ext/standard/tests/array/array_merge_variation2.phpt @@ -133,16 +133,16 @@ array_merge(): Argument #2 must be of type array, null given array_merge(): Argument #2 must be of type array, null given -- Iteration 12 -- -array_merge(): Argument #2 must be of type array, bool given +array_merge(): Argument #2 must be of type array, true given -- Iteration 13 -- -array_merge(): Argument #2 must be of type array, bool given +array_merge(): Argument #2 must be of type array, false given -- Iteration 14 -- -array_merge(): Argument #2 must be of type array, bool given +array_merge(): Argument #2 must be of type array, true given -- Iteration 15 -- -array_merge(): Argument #2 must be of type array, bool given +array_merge(): Argument #2 must be of type array, false given -- Iteration 16 -- array_merge(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_pad.phpt b/ext/standard/tests/array/array_pad.phpt index 5abcbac87ef7d..67cb423497ffb 100644 --- a/ext/standard/tests/array/array_pad.phpt +++ b/ext/standard/tests/array/array_pad.phpt @@ -13,12 +13,6 @@ var_dump(array_pad(array("", -1, 2.0), 2, array())); var_dump(array_pad(array("", -1, 2.0), -3, array())); var_dump(array_pad(array("", -1, 2.0), -4, array())); -try { - var_dump(array_pad(array("", -1, 2.0), 2000000, 0)); -} catch (\ValueError $e) { - echo $e->getMessage() . "\n"; -} - ?> --EXPECT-- array(1) { @@ -84,4 +78,3 @@ array(4) { [3]=> float(2) } -array_pad(): Argument #2 ($length) must be less than or equal to 1048576 diff --git a/ext/standard/tests/array/array_pad_too_large_padding.phpt b/ext/standard/tests/array/array_pad_too_large_padding.phpt new file mode 100644 index 0000000000000..3a45e834f9a01 --- /dev/null +++ b/ext/standard/tests/array/array_pad_too_large_padding.phpt @@ -0,0 +1,20 @@ +--TEST-- +array_pad() with too large padding should fail +--FILE-- +getMessage() . "\n"; + } +} + +test(PHP_INT_MIN); +test(PHP_INT_MAX); + +?> +--EXPECT-- +array_pad(): Argument #2 ($length) must not exceed the maximum allowed array size +array_pad(): Argument #2 ($length) must not exceed the maximum allowed array size diff --git a/ext/standard/tests/array/array_product_empty_array.phpt b/ext/standard/tests/array/array_product_empty_array.phpt new file mode 100644 index 0000000000000..714030d15103a --- /dev/null +++ b/ext/standard/tests/array/array_product_empty_array.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test array_product() function with empty array +--FILE-- + $carry * $value, 1)); +?> +--EXPECT-- +array_product() version: +int(1) +array_reduce() version: +int(1) diff --git a/ext/standard/tests/array/array_product_objects_operation_no_cast.phpt b/ext/standard/tests/array/array_product_objects_operation_no_cast.phpt new file mode 100644 index 0000000000000..7f4af3759f03e --- /dev/null +++ b/ext/standard/tests/array/array_product_objects_operation_no_cast.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test array_product() function with objects that implement addition but not castable to numeric type +--EXTENSIONS-- +zend_test +--FILE-- + $carry * $value, 1)); +?> +--EXPECTF-- +array_product() version: + +Warning: array_product(): Multiplication is not supported on type DoOperationNoCast in %s on line %d + +Warning: array_product(): Multiplication is not supported on type DoOperationNoCast in %s on line %d + +Warning: array_product(): Multiplication is not supported on type DoOperationNoCast in %s on line %d +int(1) +array_reduce() version: +object(DoOperationNoCast)#5 (1) { + ["val":"DoOperationNoCast":private]=> + int(1500) +} diff --git a/ext/standard/tests/array/array_product_variation1.phpt b/ext/standard/tests/array/array_product_variation1.phpt index c27d872a85f36..330479f4ef8bf 100644 --- a/ext/standard/tests/array/array_product_variation1.phpt +++ b/ext/standard/tests/array/array_product_variation1.phpt @@ -7,20 +7,18 @@ echo "*** Testing array_product() : variation - using non numeric values ***\n"; class A { static function help() { echo "hello\n"; } } -$fp = fopen(__FILE__, "r"); $types = array("boolean (true)" => true, "boolean (false)" => false, "string" => "hello", "numeric string" => "12", - "resource" => $fp, "object" => new A(), "null" => null, + "resource" => STDERR, "object" => new A(), "null" => null, "array" => array(3,2)); foreach ($types as $desc => $type) { - echo $desc . "\n"; - var_dump(array_product(array($type))); + echo $desc, "\n"; + var_dump(array_product([1, $type])); echo "\n"; } -fclose($fp); ?> --EXPECTF-- *** Testing array_product() : variation - using non numeric values *** @@ -31,20 +29,28 @@ boolean (false) int(0) string + +Warning: array_product(): Multiplication is not supported on type string in %s on line %d int(0) numeric string int(12) resource -int(%d) + +Warning: array_product(): Multiplication is not supported on type resource in %s on line %d +int(3) object + +Warning: array_product(): Multiplication is not supported on type A in %s on line %d int(1) null int(0) array + +Warning: array_product(): Multiplication is not supported on type array in %s on line %d int(1) diff --git a/ext/standard/tests/array/array_product_variation5.phpt b/ext/standard/tests/array/array_product_variation5.phpt new file mode 100644 index 0000000000000..525b6a52bd14a --- /dev/null +++ b/ext/standard/tests/array/array_product_variation5.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test array_product() function: resources in array +--FILE-- + $carry * $value, 1)); +} catch (TypeError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +array_product() version: + +Warning: array_product(): Multiplication is not supported on type resource in %s on line %d +int(30) +array_reduce() version: +Unsupported operand types: int * resource diff --git a/ext/standard/tests/array/array_product_variation6.phpt b/ext/standard/tests/array/array_product_variation6.phpt new file mode 100644 index 0000000000000..6526197ce52ec --- /dev/null +++ b/ext/standard/tests/array/array_product_variation6.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test array_product() function with objects castable to numeric type +--EXTENSIONS-- +gmp +--FILE-- + $carry * $value, 1)); +?> +--EXPECT-- +array_product() version: +int(150) +array_reduce() version: +object(GMP)#5 (1) { + ["num"]=> + string(3) "150" +} diff --git a/ext/standard/tests/array/array_sum_empty_array.phpt b/ext/standard/tests/array/array_sum_empty_array.phpt new file mode 100644 index 0000000000000..17c80ce43472d --- /dev/null +++ b/ext/standard/tests/array/array_sum_empty_array.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test array_sum() function with empty array +--FILE-- + $carry + $value, 0)); +?> +--EXPECT-- +array_sum() version: +int(0) +array_reduce() version: +int(0) diff --git a/ext/standard/tests/array/array_sum_objects_operation_no_cast.phpt b/ext/standard/tests/array/array_sum_objects_operation_no_cast.phpt new file mode 100644 index 0000000000000..d89b44ae0b6b7 --- /dev/null +++ b/ext/standard/tests/array/array_sum_objects_operation_no_cast.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test array_sum() function with objects that implement addition but not castable to numeric type +--EXTENSIONS-- +zend_test +--FILE-- + $carry + $value, 0)); +?> +--EXPECTF-- +array_sum() version: + +Warning: array_sum(): Addition is not supported on type DoOperationNoCast in %s on line %d + +Warning: array_sum(): Addition is not supported on type DoOperationNoCast in %s on line %d +int(0) +array_reduce() version: +object(DoOperationNoCast)#5 (1) { + ["val":"DoOperationNoCast":private]=> + int(31) +} diff --git a/ext/standard/tests/array/array_sum_objects_operation_no_cast_FFI.phpt b/ext/standard/tests/array/array_sum_objects_operation_no_cast_FFI.phpt new file mode 100644 index 0000000000000..a19e34f0b170a --- /dev/null +++ b/ext/standard/tests/array/array_sum_objects_operation_no_cast_FFI.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test array_sum() function with objects that implement addition but not castable to numeric type +--EXTENSIONS-- +ffi +--FILE-- + $carry + $value, 0)); +?> +--EXPECTF-- +array_sum() version: + +Warning: array_sum(): Addition is not supported on type FFI\CData in %s on line %d +int(1) +array_reduce() version: +object(FFI\CData:int32_t*)#4 (1) { + [0]=> + int(25) +} diff --git a/ext/standard/tests/array/array_sum_variation7.phpt b/ext/standard/tests/array/array_sum_variation7.phpt index 9e716485f4e91..181a172e3087a 100644 --- a/ext/standard/tests/array/array_sum_variation7.phpt +++ b/ext/standard/tests/array/array_sum_variation7.phpt @@ -9,11 +9,6 @@ Test array_sum() function : usage variations - 'input' array with unexpected val echo "*** Testing array_sum() : array with unexpected entries ***\n"; -// empty array -$input = array(); -echo "-- empty array --\n"; -var_dump( array_sum($input) ); - // string array $input = array('Apple', 'Banana', 'Carrot', 'Mango', 'Orange'); echo "-- array with string values --\n"; @@ -62,20 +57,48 @@ echo "-- array with mixed values --\n"; var_dump( array_sum($input) ); echo "Done" ?> ---EXPECT-- +--EXPECTF-- *** Testing array_sum() : array with unexpected entries *** --- empty array -- -int(0) -- array with string values -- + +Warning: array_sum(): Addition is not supported on type string in %s on line %d + +Warning: array_sum(): Addition is not supported on type string in %s on line %d + +Warning: array_sum(): Addition is not supported on type string in %s on line %d + +Warning: array_sum(): Addition is not supported on type string in %s on line %d + +Warning: array_sum(): Addition is not supported on type string in %s on line %d int(0) -- array with bool values -- int(3) -- array with null values -- int(0) -- array with subarrays -- + +Warning: array_sum(): Addition is not supported on type array in %s on line %d + +Warning: array_sum(): Addition is not supported on type array in %s on line %d + +Warning: array_sum(): Addition is not supported on type array in %s on line %d int(0) -- array with object values -- + +Warning: array_sum(): Addition is not supported on type MyClass in %s on line %d + +Warning: array_sum(): Addition is not supported on type MyClass in %s on line %d + +Warning: array_sum(): Addition is not supported on type MyClass in %s on line %d + +Warning: array_sum(): Addition is not supported on type MyClass in %s on line %d int(0) -- array with mixed values -- + +Warning: array_sum(): Addition is not supported on type string in %s on line %d + +Warning: array_sum(): Addition is not supported on type string in %s on line %d + +Warning: array_sum(): Addition is not supported on type array in %s on line %d float(14) Done diff --git a/ext/standard/tests/array/array_sum_variation8.phpt b/ext/standard/tests/array/array_sum_variation8.phpt new file mode 100644 index 0000000000000..017b1b8b44b1d --- /dev/null +++ b/ext/standard/tests/array/array_sum_variation8.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test array_sum() function: resources in array +--FILE-- + $carry + $value, 0)); +} catch (TypeError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +array_sum() version: + +Warning: array_sum(): Addition is not supported on type resource in %s on line %d +int(13) +array_reduce() version: +Unsupported operand types: int + resource diff --git a/ext/standard/tests/array/array_sum_variation9.phpt b/ext/standard/tests/array/array_sum_variation9.phpt new file mode 100644 index 0000000000000..61af56b2a5f81 --- /dev/null +++ b/ext/standard/tests/array/array_sum_variation9.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test array_sum() function with objects castable to numeric type +--EXTENSIONS-- +gmp +--FILE-- + $carry + $value, 0)); +?> +--EXPECT-- +array_sum() version: +int(31) +array_reduce() version: +object(GMP)#5 (1) { + ["num"]=> + string(2) "31" +} diff --git a/ext/standard/tests/array/array_udiff_assoc_variation1.phpt b/ext/standard/tests/array/array_udiff_assoc_variation1.phpt index 21239f3ee0476..3cc54bdc4e787 100644 --- a/ext/standard/tests/array/array_udiff_assoc_variation1.phpt +++ b/ext/standard/tests/array/array_udiff_assoc_variation1.phpt @@ -131,16 +131,16 @@ array_udiff_assoc(): Argument #1 ($array) must be of type array, null given array_udiff_assoc(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_udiff_assoc(): Argument #1 ($array) must be of type array, bool given +array_udiff_assoc(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_udiff_assoc(): Argument #1 ($array) must be of type array, bool given +array_udiff_assoc(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_udiff_assoc(): Argument #1 ($array) must be of type array, bool given +array_udiff_assoc(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_udiff_assoc(): Argument #1 ($array) must be of type array, bool given +array_udiff_assoc(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_udiff_assoc(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_udiff_assoc_variation2.phpt b/ext/standard/tests/array/array_udiff_assoc_variation2.phpt index 02bf34f0ecd4a..9e5c796484ae9 100644 --- a/ext/standard/tests/array/array_udiff_assoc_variation2.phpt +++ b/ext/standard/tests/array/array_udiff_assoc_variation2.phpt @@ -131,16 +131,16 @@ array_udiff_assoc(): Argument #2 must be of type array, null given array_udiff_assoc(): Argument #2 must be of type array, null given --lowercase true-- -array_udiff_assoc(): Argument #2 must be of type array, bool given +array_udiff_assoc(): Argument #2 must be of type array, true given --lowercase false-- -array_udiff_assoc(): Argument #2 must be of type array, bool given +array_udiff_assoc(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_udiff_assoc(): Argument #2 must be of type array, bool given +array_udiff_assoc(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_udiff_assoc(): Argument #2 must be of type array, bool given +array_udiff_assoc(): Argument #2 must be of type array, false given --empty string DQ-- array_udiff_assoc(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_udiff_uassoc_variation1.phpt b/ext/standard/tests/array/array_udiff_uassoc_variation1.phpt index 6ededf9b10cee..4bf85a3c20983 100644 --- a/ext/standard/tests/array/array_udiff_uassoc_variation1.phpt +++ b/ext/standard/tests/array/array_udiff_uassoc_variation1.phpt @@ -132,16 +132,16 @@ array_udiff_uassoc(): Argument #1 ($array) must be of type array, null given array_udiff_uassoc(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_udiff_uassoc(): Argument #1 ($array) must be of type array, bool given +array_udiff_uassoc(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_udiff_uassoc(): Argument #1 ($array) must be of type array, bool given +array_udiff_uassoc(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_udiff_uassoc(): Argument #1 ($array) must be of type array, bool given +array_udiff_uassoc(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_udiff_uassoc(): Argument #1 ($array) must be of type array, bool given +array_udiff_uassoc(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_udiff_uassoc(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_udiff_uassoc_variation2.phpt b/ext/standard/tests/array/array_udiff_uassoc_variation2.phpt index bc6068b5b0f1c..765e159bab543 100644 --- a/ext/standard/tests/array/array_udiff_uassoc_variation2.phpt +++ b/ext/standard/tests/array/array_udiff_uassoc_variation2.phpt @@ -132,16 +132,16 @@ array_udiff_uassoc(): Argument #2 must be of type array, null given array_udiff_uassoc(): Argument #2 must be of type array, null given --lowercase true-- -array_udiff_uassoc(): Argument #2 must be of type array, bool given +array_udiff_uassoc(): Argument #2 must be of type array, true given --lowercase false-- -array_udiff_uassoc(): Argument #2 must be of type array, bool given +array_udiff_uassoc(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_udiff_uassoc(): Argument #2 must be of type array, bool given +array_udiff_uassoc(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_udiff_uassoc(): Argument #2 must be of type array, bool given +array_udiff_uassoc(): Argument #2 must be of type array, false given --empty string DQ-- array_udiff_uassoc(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_udiff_variation1.phpt b/ext/standard/tests/array/array_udiff_variation1.phpt index c2cb3074b495c..59cfca5968644 100644 --- a/ext/standard/tests/array/array_udiff_variation1.phpt +++ b/ext/standard/tests/array/array_udiff_variation1.phpt @@ -131,16 +131,16 @@ array_udiff(): Argument #1 ($array) must be of type array, null given array_udiff(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_udiff(): Argument #1 ($array) must be of type array, bool given +array_udiff(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_udiff(): Argument #1 ($array) must be of type array, bool given +array_udiff(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_udiff(): Argument #1 ($array) must be of type array, bool given +array_udiff(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_udiff(): Argument #1 ($array) must be of type array, bool given +array_udiff(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_udiff(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_udiff_variation2.phpt b/ext/standard/tests/array/array_udiff_variation2.phpt index 72e814f75b000..6637692e0b25c 100644 --- a/ext/standard/tests/array/array_udiff_variation2.phpt +++ b/ext/standard/tests/array/array_udiff_variation2.phpt @@ -131,16 +131,16 @@ array_udiff(): Argument #2 must be of type array, null given array_udiff(): Argument #2 must be of type array, null given --lowercase true-- -array_udiff(): Argument #2 must be of type array, bool given +array_udiff(): Argument #2 must be of type array, true given --lowercase false-- -array_udiff(): Argument #2 must be of type array, bool given +array_udiff(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_udiff(): Argument #2 must be of type array, bool given +array_udiff(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_udiff(): Argument #2 must be of type array, bool given +array_udiff(): Argument #2 must be of type array, false given --empty string DQ-- array_udiff(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_uintersect_assoc_variation1.phpt b/ext/standard/tests/array/array_uintersect_assoc_variation1.phpt index abfa224b20ea4..64e21a30d1ae9 100644 --- a/ext/standard/tests/array/array_uintersect_assoc_variation1.phpt +++ b/ext/standard/tests/array/array_uintersect_assoc_variation1.phpt @@ -131,16 +131,16 @@ array_uintersect_assoc(): Argument #1 ($array) must be of type array, null given array_uintersect_assoc(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_uintersect_assoc(): Argument #1 ($array) must be of type array, bool given +array_uintersect_assoc(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_uintersect_assoc(): Argument #1 ($array) must be of type array, bool given +array_uintersect_assoc(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_uintersect_assoc(): Argument #1 ($array) must be of type array, bool given +array_uintersect_assoc(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_uintersect_assoc(): Argument #1 ($array) must be of type array, bool given +array_uintersect_assoc(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_uintersect_assoc(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_uintersect_assoc_variation2.phpt b/ext/standard/tests/array/array_uintersect_assoc_variation2.phpt index 080d81ceee41b..4078bec27dcc0 100644 --- a/ext/standard/tests/array/array_uintersect_assoc_variation2.phpt +++ b/ext/standard/tests/array/array_uintersect_assoc_variation2.phpt @@ -131,16 +131,16 @@ array_uintersect_assoc(): Argument #2 must be of type array, null given array_uintersect_assoc(): Argument #2 must be of type array, null given --lowercase true-- -array_uintersect_assoc(): Argument #2 must be of type array, bool given +array_uintersect_assoc(): Argument #2 must be of type array, true given --lowercase false-- -array_uintersect_assoc(): Argument #2 must be of type array, bool given +array_uintersect_assoc(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_uintersect_assoc(): Argument #2 must be of type array, bool given +array_uintersect_assoc(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_uintersect_assoc(): Argument #2 must be of type array, bool given +array_uintersect_assoc(): Argument #2 must be of type array, false given --empty string DQ-- array_uintersect_assoc(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_uintersect_uassoc_variation1.phpt b/ext/standard/tests/array/array_uintersect_uassoc_variation1.phpt index cc92118bc2a2a..651e78e62855e 100644 --- a/ext/standard/tests/array/array_uintersect_uassoc_variation1.phpt +++ b/ext/standard/tests/array/array_uintersect_uassoc_variation1.phpt @@ -132,16 +132,16 @@ array_uintersect_uassoc(): Argument #1 ($array) must be of type array, null give array_uintersect_uassoc(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_uintersect_uassoc(): Argument #1 ($array) must be of type array, bool given +array_uintersect_uassoc(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_uintersect_uassoc(): Argument #1 ($array) must be of type array, bool given +array_uintersect_uassoc(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_uintersect_uassoc(): Argument #1 ($array) must be of type array, bool given +array_uintersect_uassoc(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_uintersect_uassoc(): Argument #1 ($array) must be of type array, bool given +array_uintersect_uassoc(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_uintersect_uassoc(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_uintersect_uassoc_variation2.phpt b/ext/standard/tests/array/array_uintersect_uassoc_variation2.phpt index cfa7300b27414..e01d3b4e95720 100644 --- a/ext/standard/tests/array/array_uintersect_uassoc_variation2.phpt +++ b/ext/standard/tests/array/array_uintersect_uassoc_variation2.phpt @@ -132,16 +132,16 @@ array_uintersect_uassoc(): Argument #2 must be of type array, null given array_uintersect_uassoc(): Argument #2 must be of type array, null given --lowercase true-- -array_uintersect_uassoc(): Argument #2 must be of type array, bool given +array_uintersect_uassoc(): Argument #2 must be of type array, true given --lowercase false-- -array_uintersect_uassoc(): Argument #2 must be of type array, bool given +array_uintersect_uassoc(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_uintersect_uassoc(): Argument #2 must be of type array, bool given +array_uintersect_uassoc(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_uintersect_uassoc(): Argument #2 must be of type array, bool given +array_uintersect_uassoc(): Argument #2 must be of type array, false given --empty string DQ-- array_uintersect_uassoc(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/array_uintersect_variation1.phpt b/ext/standard/tests/array/array_uintersect_variation1.phpt index b5442ed392419..390fc6137401b 100644 --- a/ext/standard/tests/array/array_uintersect_variation1.phpt +++ b/ext/standard/tests/array/array_uintersect_variation1.phpt @@ -131,16 +131,16 @@ array_uintersect(): Argument #1 ($array) must be of type array, null given array_uintersect(): Argument #1 ($array) must be of type array, null given --lowercase true-- -array_uintersect(): Argument #1 ($array) must be of type array, bool given +array_uintersect(): Argument #1 ($array) must be of type array, true given --lowercase false-- -array_uintersect(): Argument #1 ($array) must be of type array, bool given +array_uintersect(): Argument #1 ($array) must be of type array, false given --uppercase TRUE-- -array_uintersect(): Argument #1 ($array) must be of type array, bool given +array_uintersect(): Argument #1 ($array) must be of type array, true given --uppercase FALSE-- -array_uintersect(): Argument #1 ($array) must be of type array, bool given +array_uintersect(): Argument #1 ($array) must be of type array, false given --empty string DQ-- array_uintersect(): Argument #1 ($array) must be of type array, string given diff --git a/ext/standard/tests/array/array_uintersect_variation2.phpt b/ext/standard/tests/array/array_uintersect_variation2.phpt index 2f6b9d3e99fef..ca3a4bff3a904 100644 --- a/ext/standard/tests/array/array_uintersect_variation2.phpt +++ b/ext/standard/tests/array/array_uintersect_variation2.phpt @@ -131,16 +131,16 @@ array_uintersect(): Argument #2 must be of type array, null given array_uintersect(): Argument #2 must be of type array, null given --lowercase true-- -array_uintersect(): Argument #2 must be of type array, bool given +array_uintersect(): Argument #2 must be of type array, true given --lowercase false-- -array_uintersect(): Argument #2 must be of type array, bool given +array_uintersect(): Argument #2 must be of type array, false given --uppercase TRUE-- -array_uintersect(): Argument #2 must be of type array, bool given +array_uintersect(): Argument #2 must be of type array, true given --uppercase FALSE-- -array_uintersect(): Argument #2 must be of type array, bool given +array_uintersect(): Argument #2 must be of type array, false given --empty string DQ-- array_uintersect(): Argument #2 must be of type array, string given diff --git a/ext/standard/tests/array/bug35014.phpt b/ext/standard/tests/array/bug35014.phpt index f1f407081f52d..3935657f7a796 100644 --- a/ext/standard/tests/array/bug35014.phpt +++ b/ext/standard/tests/array/bug35014.phpt @@ -5,7 +5,6 @@ Bug #35014 (array_product() always returns 0) (32bit) --FILE-- --EXPECT-- -int(1) int(0) int(3) int(9) diff --git a/ext/standard/tests/array/bug35014_64bit.phpt b/ext/standard/tests/array/bug35014_64bit.phpt index 40d656d83509e..29fa9e187ac73 100644 --- a/ext/standard/tests/array/bug35014_64bit.phpt +++ b/ext/standard/tests/array/bug35014_64bit.phpt @@ -7,7 +7,6 @@ precision=14 --FILE-- --EXPECT-- -int(1) int(0) int(3) int(9) diff --git a/ext/standard/tests/array/bug48484.phpt b/ext/standard/tests/array/bug48484.phpt deleted file mode 100644 index 5688c0cad8beb..0000000000000 --- a/ext/standard/tests/array/bug48484.phpt +++ /dev/null @@ -1,8 +0,0 @@ ---TEST-- -Bug 48484 (array_product() always returns 0 for an empty array) ---FILE-- - ---EXPECT-- -int(1) diff --git a/ext/standard/tests/array/bug68553.phpt b/ext/standard/tests/array/bug68553.phpt index dbb74c7994bb3..7325a68da5413 100644 --- a/ext/standard/tests/array/bug68553.phpt +++ b/ext/standard/tests/array/bug68553.phpt @@ -79,5 +79,5 @@ array(8) { NULL } } -Illegal offset type -Illegal offset type +Cannot access offset of type object on array +Cannot access offset of type array on array diff --git a/ext/standard/tests/array/bug77931.phpt b/ext/standard/tests/array/bug77931.phpt index 4f73daeb07e82..d876d4b01c6af 100644 --- a/ext/standard/tests/array/bug77931.phpt +++ b/ext/standard/tests/array/bug77931.phpt @@ -22,5 +22,5 @@ try { ?> --EXPECT-- array_map(): Argument #3 must be of type array, int given -array_map(): Argument #4 must be of type array, bool given +array_map(): Argument #4 must be of type array, true given array_map(): Argument #5 must be of type array, null given diff --git a/ext/standard/tests/array/compact.phpt b/ext/standard/tests/array/compact.phpt index d4c6236c03e47..7d139cf2f0365 100644 --- a/ext/standard/tests/array/compact.phpt +++ b/ext/standard/tests/array/compact.phpt @@ -28,10 +28,10 @@ array(2) { string(2) "CA" } -Warning: compact(): Argument #1 must be string or array of strings, bool given in %s on line %d +Warning: compact(): Argument #1 must be string or array of strings, true given in %s on line %d Warning: compact(): Argument #2 must be string or array of strings, int given in %s on line %d array(1) { ["bar"]=> string(3) "baz" -} \ No newline at end of file +} diff --git a/ext/standard/tests/array/count_invalid.phpt b/ext/standard/tests/array/count_invalid.phpt index fd7e3356eaefa..d05c6a1961eeb 100644 --- a/ext/standard/tests/array/count_invalid.phpt +++ b/ext/standard/tests/array/count_invalid.phpt @@ -50,6 +50,6 @@ try { count(): Argument #1 ($value) must be of type Countable|array, null given count(): Argument #1 ($value) must be of type Countable|array, string given count(): Argument #1 ($value) must be of type Countable|array, int given -count(): Argument #1 ($value) must be of type Countable|array, bool given -count(): Argument #1 ($value) must be of type Countable|array, bool given +count(): Argument #1 ($value) must be of type Countable|array, true given +count(): Argument #1 ($value) must be of type Countable|array, false given count(): Argument #1 ($value) must be of type Countable|array, stdClass given diff --git a/ext/standard/tests/array/negative_index_empty_array.phpt b/ext/standard/tests/array/negative_index_empty_array.phpt new file mode 100644 index 0000000000000..322ac6e820ce6 --- /dev/null +++ b/ext/standard/tests/array/negative_index_empty_array.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test empty arrays with first added index being negative +--FILE-- + +--EXPECT-- +array(2) { + [-5]=> + string(2) "-5" + [-4]=> + string(8) "after -5" +} diff --git a/ext/standard/tests/class_object/get_class_methods_variation_001.phpt b/ext/standard/tests/class_object/get_class_methods_variation_001.phpt index 3fc707c15ec38..f7b86a2977acf 100644 --- a/ext/standard/tests/class_object/get_class_methods_variation_001.phpt +++ b/ext/standard/tests/class_object/get_class_methods_variation_001.phpt @@ -137,16 +137,16 @@ Arg value get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, null given Arg value 1 -get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, bool given +get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, true given Arg value -get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, bool given +get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, false given Arg value 1 -get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, bool given +get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, true given Arg value -get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, bool given +get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, false given Arg value get_class_methods(): Argument #1 ($object_or_class) must be an object or a valid class name, string given diff --git a/ext/standard/tests/class_object/get_class_variation_001.phpt b/ext/standard/tests/class_object/get_class_variation_001.phpt index 67c468cace7c4..09f995c21fb6d 100644 --- a/ext/standard/tests/class_object/get_class_variation_001.phpt +++ b/ext/standard/tests/class_object/get_class_variation_001.phpt @@ -127,16 +127,16 @@ Arg value: (type: NULL) get_class(): Argument #1 ($object) must be of type object, null given Arg value: 1 (type: boolean) -get_class(): Argument #1 ($object) must be of type object, bool given +get_class(): Argument #1 ($object) must be of type object, true given Arg value: (type: boolean) -get_class(): Argument #1 ($object) must be of type object, bool given +get_class(): Argument #1 ($object) must be of type object, false given Arg value: 1 (type: boolean) -get_class(): Argument #1 ($object) must be of type object, bool given +get_class(): Argument #1 ($object) must be of type object, true given Arg value: (type: boolean) -get_class(): Argument #1 ($object) must be of type object, bool given +get_class(): Argument #1 ($object) must be of type object, false given Arg value: (type: string) get_class(): Argument #1 ($object) must be of type object, string given diff --git a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt index 529f13ce7119c..8faeff9dd8dcf 100644 --- a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt +++ b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt @@ -140,16 +140,16 @@ Arg value get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, null given Arg value 1 -get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, bool given +get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, true given Arg value -get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, bool given +get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, false given Arg value 1 -get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, bool given +get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, true given Arg value -get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, bool given +get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, false given Arg value get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, string given diff --git a/ext/standard/tests/class_object/method_exists_variation_001.phpt b/ext/standard/tests/class_object/method_exists_variation_001.phpt index 5e6d34f550eea..d45d2652d11c9 100644 --- a/ext/standard/tests/class_object/method_exists_variation_001.phpt +++ b/ext/standard/tests/class_object/method_exists_variation_001.phpt @@ -140,16 +140,16 @@ Arg value method_exists(): Argument #1 ($object_or_class) must be of type object|string, null given Arg value 1 -method_exists(): Argument #1 ($object_or_class) must be of type object|string, bool given +method_exists(): Argument #1 ($object_or_class) must be of type object|string, true given Arg value -method_exists(): Argument #1 ($object_or_class) must be of type object|string, bool given +method_exists(): Argument #1 ($object_or_class) must be of type object|string, false given Arg value 1 -method_exists(): Argument #1 ($object_or_class) must be of type object|string, bool given +method_exists(): Argument #1 ($object_or_class) must be of type object|string, true given Arg value -method_exists(): Argument #1 ($object_or_class) must be of type object|string, bool given +method_exists(): Argument #1 ($object_or_class) must be of type object|string, false given Arg value bool(false) diff --git a/ext/standard/tests/constant_with_typed_class_constant.phpt b/ext/standard/tests/constant_with_typed_class_constant.phpt new file mode 100644 index 0000000000000..87a1c006426da --- /dev/null +++ b/ext/standard/tests/constant_with_typed_class_constant.phpt @@ -0,0 +1,25 @@ +--TEST-- +Calling constant() with a typed class constant +--FILE-- +getMessage() . "\n"; +} + +?> +--EXPECT-- +object(stdClass)#1 (0) { +} +Cannot assign stdClass to class constant Foo::CONST2 of type array diff --git a/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt b/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt new file mode 100644 index 0000000000000..32e335f4b087e --- /dev/null +++ b/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt @@ -0,0 +1,82 @@ +--TEST-- +bcrypt correctly rejects salts containing $ +--FILE-- + +--EXPECT-- +string(8) "$2y$04$$" +string(2) "*0" +bool(false) +string(9) "$2y$04$0$" +string(2) "*0" +bool(false) +string(10) "$2y$04$00$" +string(2) "*0" +bool(false) +string(11) "$2y$04$000$" +string(2) "*0" +bool(false) +string(12) "$2y$04$0000$" +string(2) "*0" +bool(false) +string(13) "$2y$04$00000$" +string(2) "*0" +bool(false) +string(14) "$2y$04$000000$" +string(2) "*0" +bool(false) +string(15) "$2y$04$0000000$" +string(2) "*0" +bool(false) +string(16) "$2y$04$00000000$" +string(2) "*0" +bool(false) +string(17) "$2y$04$000000000$" +string(2) "*0" +bool(false) +string(18) "$2y$04$0000000000$" +string(2) "*0" +bool(false) +string(19) "$2y$04$00000000000$" +string(2) "*0" +bool(false) +string(20) "$2y$04$000000000000$" +string(2) "*0" +bool(false) +string(21) "$2y$04$0000000000000$" +string(2) "*0" +bool(false) +string(22) "$2y$04$00000000000000$" +string(2) "*0" +bool(false) +string(23) "$2y$04$000000000000000$" +string(2) "*0" +bool(false) +string(24) "$2y$04$0000000000000000$" +string(2) "*0" +bool(false) +string(25) "$2y$04$00000000000000000$" +string(2) "*0" +bool(false) +string(26) "$2y$04$000000000000000000$" +string(2) "*0" +bool(false) +string(27) "$2y$04$0000000000000000000$" +string(2) "*0" +bool(false) +string(28) "$2y$04$00000000000000000000$" +string(2) "*0" +bool(false) +string(29) "$2y$04$000000000000000000000$" +string(2) "*0" +bool(false) +string(30) "$2y$04$0000000000000000000000$" +string(60) "$2y$04$000000000000000000000u2a2UpVexIt9k3FMJeAVr3c04F5tcI8K" +bool(false) diff --git a/ext/standard/tests/directory/bug74589_utf8.phpt b/ext/standard/tests/directory/bug74589_utf8.phpt index 7a13b57f046ea..e493dd84245de 100644 --- a/ext/standard/tests/directory/bug74589_utf8.phpt +++ b/ext/standard/tests/directory/bug74589_utf8.phpt @@ -18,6 +18,7 @@ internal_encoding=utf-8 $item = "bug74589_新建文件夹"; // utf-8 string $dir = __DIR__ . DIRECTORY_SEPARATOR . $item; $test_file = $dir . DIRECTORY_SEPARATOR . "test.php"; +$test_file_escaped = escapeshellarg($test_file); mkdir($dir); @@ -27,9 +28,9 @@ file_put_contents($test_file, var_dump(__FILE__); var_dump(__DIR__ === __DIR__);"); -$php = getenv('TEST_PHP_EXECUTABLE'); +$php = getenv('TEST_PHP_EXECUTABLE_ESCAPED'); -echo shell_exec("$php -n $test_file"); +echo shell_exec("$php -n $test_file_escaped"); ?> --EXPECTF-- diff --git a/ext/standard/tests/file/bug22414.phpt b/ext/standard/tests/file/bug22414.phpt index 55078568152c4..49ac237f1ab6e 100644 --- a/ext/standard/tests/file/bug22414.phpt +++ b/ext/standard/tests/file/bug22414.phpt @@ -6,22 +6,21 @@ output_handler= '.$tmpfile ; + $cmd = $php_escaped . $args . ' -r ' . escapeshellarg('passthru("'.$cmd.'");') . ' > '.escapeshellarg($tmpfile); } else { - $cmd = $php . $args . ' -r \"readfile(@getenv(\\\\\\"TEST_PHP_EXECUTABLE\\\\\\")); \"'; - $cmd = $php . $args . ' -r " passthru(\''.$cmd.'\');" > '.$tmpfile ; + $cmd = $php_escaped . $args . ' -r ' . "\"passthru('".addslashes($cmd)."');\"" . ' > '.escapeshellarg($tmpfile); } exec($cmd); diff --git a/ext/standard/tests/file/bug26615.phpt b/ext/standard/tests/file/bug26615.phpt index 8a5df91ec1834..2e652fa34390a 100644 --- a/ext/standard/tests/file/bug26615.phpt +++ b/ext/standard/tests/file/bug26615.phpt @@ -7,9 +7,9 @@ variables_order=E $out = array(); $status = -1; if (substr(PHP_OS, 0, 3) != 'WIN') { - exec($_ENV['TEST_PHP_EXECUTABLE'].' -n -r \'for($i=1;$i<=5000;$i++) print "$i\n";\' | tr \'\n\' \' \'', $out, $status); + exec($_ENV['TEST_PHP_EXECUTABLE_ESCAPED'].' -n -r \'for($i=1;$i<=5000;$i++) print "$i\n";\' | tr \'\n\' \' \'', $out, $status); } else { - exec($_ENV['TEST_PHP_EXECUTABLE'].' -n -r "for($i=1;$i<=5000;$i++) echo $i,\' \';"', $out, $status); + exec($_ENV['TEST_PHP_EXECUTABLE_ESCAPED'].' -n -r "for($i=1;$i<=5000;$i++) echo $i,\' \';"', $out, $status); } print_r($out); ?> diff --git a/ext/standard/tests/file/bug26938.phpt b/ext/standard/tests/file/bug26938.phpt index 13732c03f6303..eec537d2d970b 100644 --- a/ext/standard/tests/file/bug26938.phpt +++ b/ext/standard/tests/file/bug26938.phpt @@ -4,7 +4,7 @@ Bug #26938 (exec does not read consecutive long lines correctly) --FILE-- --FILE-- = $stdinLen) { fclose($writePipes[0]); @@ -58,12 +59,21 @@ while ($pipes || $writePipes) { foreach ($r as $pipe) { $type = array_search($pipe, $pipes); $data = fread($pipe, 8192); - if (false === $data || feof($pipe)) { + if (feof($pipe)) { fclose($pipe); unset($pipes[$type]); + } elseif (false === $data) { + die('Failed to read from pipe'); + } else { + $procOutput[$type] = ($procOutput[$type] ?? '') . $data; } } } +foreach ($procOutput as $output) { + if ($output !== $stdin) { + die('Output does not match input: ' . $output); + } +} echo "OK."; ?> --EXPECT-- diff --git a/ext/standard/tests/file/bug81145.phpt b/ext/standard/tests/file/bug81145.phpt index ea498b493ee7d..f3258ff6019e9 100644 --- a/ext/standard/tests/file/bug81145.phpt +++ b/ext/standard/tests/file/bug81145.phpt @@ -13,6 +13,8 @@ if (PHP_OS_FAMILY !== "Windows") { @unlink(__DIR__ . "/bug81145_src.bin"); } ?> +--CONFLICTS-- +all --FILE-- --INI-- memory_limit=32M diff --git a/ext/standard/tests/file/file_variation5-win32-mb.phpt b/ext/standard/tests/file/file_variation5-win32-mb.phpt index 18dd399e5b7a9..0e6bbd69e33d0 100644 --- a/ext/standard/tests/file/file_variation5-win32-mb.phpt +++ b/ext/standard/tests/file/file_variation5-win32-mb.phpt @@ -14,7 +14,7 @@ chdir($script_directory); $test_dirname = basename(__FILE__, ".php") . "私はガラスを食べられますtestdir"; mkdir($test_dirname); -$filepath = __DIR__ . '/file_variation_5.tmp'; +$filepath = __DIR__ . '/file_variation_5_mb.tmp'; $filename = basename($filepath); $fd = fopen($filepath, "w+"); fwrite($fd, "Line 1\nLine 2\nLine 3"); @@ -35,8 +35,8 @@ chdir($script_directory); --CLEAN-- --EXPECT-- diff --git a/ext/standard/tests/file/file_variation5-win32.phpt b/ext/standard/tests/file/file_variation5-win32.phpt index cde34d83c53f3..948f56e034720 100644 --- a/ext/standard/tests/file/file_variation5-win32.phpt +++ b/ext/standard/tests/file/file_variation5-win32.phpt @@ -36,7 +36,7 @@ chdir($script_directory); --EXPECT-- diff --git a/ext/standard/tests/file/mkdir-002.phpt b/ext/standard/tests/file/mkdir-002.phpt index 2953af88874ef..f4a42a7d61982 100644 --- a/ext/standard/tests/file/mkdir-002.phpt +++ b/ext/standard/tests/file/mkdir-002.phpt @@ -24,7 +24,8 @@ var_dump(rmdir("./mkdir-002")); var_dump(mkdir(__DIR__."/mkdir-002", 0777)); var_dump(mkdir(__DIR__."/mkdir-002/subdir", 0777)); $dirname = __DIR__."/mkdir-002"; -var_dump(`ls -l $dirname`); +$dirname_escaped = escapeshellarg($dirname); +var_dump(`ls -l $dirname_escaped`); var_dump(rmdir(__DIR__."/mkdir-002/subdir")); var_dump(rmdir(__DIR__."/mkdir-002")); diff --git a/ext/standard/tests/file/popen_pclose_basic.phpt b/ext/standard/tests/file/popen_pclose_basic.phpt index 4964a4fa85b36..51c54ab50ce28 100644 --- a/ext/standard/tests/file/popen_pclose_basic.phpt +++ b/ext/standard/tests/file/popen_pclose_basic.phpt @@ -16,7 +16,7 @@ echo "-- Testing popen(): reading from the pipe --\n"; $dirpath = $file_path."/popen_basic"; mkdir($dirpath); touch($dirpath."/popen_basic.tmp"); -define('CMD', "ls $dirpath"); +define('CMD', "ls " . escapeshellarg($dirpath)); $file_handle = popen(CMD, 'r'); fpassthru($file_handle); pclose($file_handle); @@ -24,7 +24,8 @@ pclose($file_handle); echo "-- Testing popen(): reading from a file using 'cat' command --\n"; create_files($dirpath, 1, "text_with_new_line", 0755, 100, "w", "popen_basic", 1, "bytes"); $filename = $dirpath."/popen_basic1.tmp"; -$command = "cat $filename"; +$filename_escaped = escapeshellarg($filename); +$command = "cat $filename_escaped"; $file_handle = popen($command, "r"); $return_value = fpassthru($file_handle); echo "\n"; diff --git a/ext/standard/tests/file/proc_open01.phpt b/ext/standard/tests/file/proc_open01.phpt index 2f74a17464f17..5ebfc72351b6d 100644 --- a/ext/standard/tests/file/proc_open01.phpt +++ b/ext/standard/tests/file/proc_open01.phpt @@ -4,7 +4,7 @@ proc_open() regression test 1 (proc_open() leak) --EXPECTF-- -array(8) { +array(9) { ["command"]=> string(14) "/bin/sleep 120" ["pid"]=> int(%d) + ["cached"]=> + bool(false) ["running"]=> bool(false) ["signaled"]=> diff --git a/ext/standard/tests/general_functions/bug69646.phpt b/ext/standard/tests/general_functions/bug69646.phpt index 97e60bfff08d6..70fd06dd8c37b 100644 --- a/ext/standard/tests/general_functions/bug69646.phpt +++ b/ext/standard/tests/general_functions/bug69646.phpt @@ -24,7 +24,7 @@ SCRIPT; $script = __DIR__ . DIRECTORY_SEPARATOR . "arginfo.php"; file_put_contents($script, $helper_script); -$cmd = PHP_BINARY . " " . $script . " " . escapeshellarg($a) . " " . escapeshellarg($b); +$cmd = getenv('TEST_PHP_EXECUTABLE_ESCAPED') . " " . escapeshellarg($script) . " " . escapeshellarg($a) . " " . escapeshellarg($b); system($cmd); diff --git a/ext/standard/tests/general_functions/bug70018.phpt b/ext/standard/tests/general_functions/bug70018.phpt index 77df0417a6098..a8dcced5ba0d1 100644 --- a/ext/standard/tests/general_functions/bug70018.phpt +++ b/ext/standard/tests/general_functions/bug70018.phpt @@ -5,9 +5,10 @@ Bug #70018 (exec does not strip all whitespace) $output = array(); $test_fl = __DIR__ . DIRECTORY_SEPARATOR . md5(uniqid()); +$test_fl_escaped = escapeshellarg($test_fl); file_put_contents($test_fl, ' array(%d) { [123]=> - string(%d) "24575" + int(24575) [456]=> int(123) } diff --git a/ext/standard/tests/general_functions/bug77844.phpt b/ext/standard/tests/general_functions/bug77844.phpt index a8b6bf3d0dd02..608ea865b82e5 100644 --- a/ext/standard/tests/general_functions/bug77844.phpt +++ b/ext/standard/tests/general_functions/bug77844.phpt @@ -13,7 +13,7 @@ var_dump(parse_ini_string($ini, true, INI_SCANNER_TYPED)); --EXPECT-- array(2) { ["val1"]=> - string(1) "2" + int(2) ["val2"]=> - string(1) "2" + int(2) } diff --git a/ext/standard/tests/general_functions/get_cfg_var_variation8.phpt b/ext/standard/tests/general_functions/get_cfg_var_variation8.phpt index 6b975cd4963f8..ddfb3b388724f 100644 --- a/ext/standard/tests/general_functions/get_cfg_var_variation8.phpt +++ b/ext/standard/tests/general_functions/get_cfg_var_variation8.phpt @@ -6,7 +6,7 @@ Francesco Fullone ff@ideato.it --INI-- magic_quotes_gpc=1 --SKIPIF-- - + --FILE-- +--FILE-- + +--EXPECT-- +0 diff --git a/ext/standard/tests/general_functions/gh10239_2.phpt b/ext/standard/tests/general_functions/gh10239_2.phpt new file mode 100644 index 0000000000000..f4df2d3688c56 --- /dev/null +++ b/ext/standard/tests/general_functions/gh10239_2.phpt @@ -0,0 +1,55 @@ +--TEST-- +GH-10239 (proc_close after proc_get_status always returns -1) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +array(9) { + ["command"]=> + string(5) "false" + ["pid"]=> + int(%d) + ["cached"]=> + bool(true) + ["running"]=> + bool(false) + ["signaled"]=> + bool(false) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(1) + ["termsig"]=> + int(0) + ["stopsig"]=> + int(0) +} +array(9) { + ["command"]=> + string(5) "false" + ["pid"]=> + int(%d) + ["cached"]=> + bool(true) + ["running"]=> + bool(false) + ["signaled"]=> + bool(false) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(1) + ["termsig"]=> + int(0) + ["stopsig"]=> + int(0) +} diff --git a/ext/standard/tests/general_functions/parse_ini_string_bug76068.phpt b/ext/standard/tests/general_functions/parse_ini_string_bug76068.phpt index 359e9c34466a3..74d28718a038f 100644 --- a/ext/standard/tests/general_functions/parse_ini_string_bug76068.phpt +++ b/ext/standard/tests/general_functions/parse_ini_string_bug76068.phpt @@ -21,7 +21,7 @@ array(1) { ["foo"]=> array(1) { ["bar"]=> - string(1) "1" + int(1) } } array(1) { @@ -42,6 +42,6 @@ array(1) { ["foo"]=> array(1) { ["bar"]=> - string(2) "42" + int(42) } } diff --git a/ext/standard/tests/general_functions/phpinfo.phpt b/ext/standard/tests/general_functions/phpinfo.phpt index 5f4d99ffbaf2e..57ba13bb7bf7c 100644 --- a/ext/standard/tests/general_functions/phpinfo.phpt +++ b/ext/standard/tests/general_functions/phpinfo.phpt @@ -34,6 +34,7 @@ Thread Safety => %s%A Zend Signal Handling => %s Zend Memory Manager => %s Zend Multibyte Support => %s +Zend Max Execution Timers => %s IPv6 Support => %s DTrace Support => %s diff --git a/ext/standard/tests/general_functions/proc_open-mb0.phpt b/ext/standard/tests/general_functions/proc_open-mb0.phpt index c97ebda9702dc..545f087574edb 100644 --- a/ext/standard/tests/general_functions/proc_open-mb0.phpt +++ b/ext/standard/tests/general_functions/proc_open-mb0.phpt @@ -7,9 +7,10 @@ if (!function_exists("proc_open")) echo "skip proc_open() is not available"; --FILE-- '); $ds = array( @@ -19,7 +20,7 @@ $ds = array( ); $p = proc_open( - "$php -n $f テストマルチバイト・パス füße карамба", + "$php -n $f_escaped テストマルチバイト・パス füße карамба", $ds, $pipes, NULL, diff --git a/ext/standard/tests/general_functions/proc_open-mb1.phpt b/ext/standard/tests/general_functions/proc_open-mb1.phpt index 8a735cf306ed6..057979e604c76 100644 --- a/ext/standard/tests/general_functions/proc_open-mb1.phpt +++ b/ext/standard/tests/general_functions/proc_open-mb1.phpt @@ -7,9 +7,10 @@ if (!function_exists("proc_open")) echo "skip proc_open() is not available"; --FILE-- '); $ds = array( @@ -19,7 +20,7 @@ $ds = array( ); $p = proc_open( - "$php -n $f テストマルチバイト・パス füße карамба", + "$php -n $f_escaped テストマルチバイト・パス füße карамба", $ds, $pipes ); diff --git a/ext/standard/tests/general_functions/proc_open02.phpt b/ext/standard/tests/general_functions/proc_open02.phpt index 96ee7b94e7284..dd2e6902a4114 100644 --- a/ext/standard/tests/general_functions/proc_open02.phpt +++ b/ext/standard/tests/general_functions/proc_open02.phpt @@ -32,11 +32,13 @@ echo "Done!\n"; ?> --EXPECTF-- bool(true) -array(8) { +array(9) { ["command"]=> string(10) "/bin/sleep" ["pid"]=> int(%d) + ["cached"]=> + bool(false) ["running"]=> bool(true) ["signaled"]=> @@ -51,11 +53,13 @@ array(8) { int(0) } bool(true) -array(8) { +array(9) { ["command"]=> string(10) "/bin/sleep" ["pid"]=> int(%d) + ["cached"]=> + bool(false) ["running"]=> bool(false) ["signaled"]=> diff --git a/ext/standard/tests/general_functions/proc_open_array.phpt b/ext/standard/tests/general_functions/proc_open_array.phpt index 9f969a1c32f24..239dc116cd601 100644 --- a/ext/standard/tests/general_functions/proc_open_array.phpt +++ b/ext/standard/tests/general_functions/proc_open_array.phpt @@ -31,6 +31,13 @@ try { echo $exception->getMessage() . "\n"; } +echo "\nEmpty program name:\n"; +try { + proc_open([""], $ds, $pipes); +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} + echo "\nBasic usage:\n"; $proc = proc_open([$php, '-r', 'echo "Hello World!\n";'], $ds, $pipes); fpassthru($pipes[1]); @@ -76,6 +83,9 @@ Command array element 1 contains a null byte Nul byte in argument: Command array element 2 contains a null byte +Empty program name: +First element must contain a non-empty program name + Basic usage: Hello World! diff --git a/ext/standard/tests/general_functions/proc_open_pipes1.phpt b/ext/standard/tests/general_functions/proc_open_pipes1.phpt index 076b8c941e2c8..9822607c6f7ef 100644 --- a/ext/standard/tests/general_functions/proc_open_pipes1.phpt +++ b/ext/standard/tests/general_functions/proc_open_pipes1.phpt @@ -7,8 +7,8 @@ for ($i = 3; $i<= 30; $i++) { $spec[$i] = array('pipe', 'w'); } -$php = getenv("TEST_PHP_EXECUTABLE"); -$callee = __DIR__ . "/proc_open_pipes_sleep.inc"; +$php = getenv("TEST_PHP_EXECUTABLE_ESCAPED"); +$callee = escapeshellarg(__DIR__ . "/proc_open_pipes_sleep.inc"); proc_open("$php -n $callee", $spec, $pipes); var_dump(count($spec)); diff --git a/ext/standard/tests/general_functions/proc_open_pipes2.phpt b/ext/standard/tests/general_functions/proc_open_pipes2.phpt index 3c1cf9695592f..c147a2f376464 100644 --- a/ext/standard/tests/general_functions/proc_open_pipes2.phpt +++ b/ext/standard/tests/general_functions/proc_open_pipes2.phpt @@ -5,8 +5,8 @@ proc_open() with no pipes $spec = array(); -$php = getenv("TEST_PHP_EXECUTABLE"); -$callee = __DIR__ . "/proc_open_pipes_sleep.inc"; +$php = getenv("TEST_PHP_EXECUTABLE_ESCAPED"); +$callee = escapeshellarg(__DIR__ . "/proc_open_pipes_sleep.inc"); proc_open("$php -n $callee", $spec, $pipes); var_dump(count($spec)); diff --git a/ext/standard/tests/general_functions/proc_open_pipes3.phpt b/ext/standard/tests/general_functions/proc_open_pipes3.phpt index f5801ad63e435..1ee42904a0588 100644 --- a/ext/standard/tests/general_functions/proc_open_pipes3.phpt +++ b/ext/standard/tests/general_functions/proc_open_pipes3.phpt @@ -7,25 +7,26 @@ for ($i = 3; $i<= 5; $i++) { $spec[$i] = array('pipe', 'w'); } -$php = getenv("TEST_PHP_EXECUTABLE"); +$php = getenv("TEST_PHP_EXECUTABLE_ESCAPED"); $callee = __DIR__ . "/proc_open_pipes_sleep.inc"; +$callee_escaped = escapeshellarg($callee); $spec[$i] = array('pi'); -proc_open("$php -n $callee", $spec, $pipes); +proc_open("$php -n $callee_escaped", $spec, $pipes); $spec[$i] = 1; try { - proc_open("$php -n $callee", $spec, $pipes); + proc_open("$php -n $callee_escaped", $spec, $pipes); } catch (ValueError $exception) { echo $exception->getMessage() . "\n"; } $spec[$i] = array('pipe', "test"); -proc_open("$php -n $callee", $spec, $pipes); +proc_open("$php -n $callee_escaped", $spec, $pipes); var_dump($pipes); $spec[$i] = array('file', "test", "z"); -proc_open("$php -n $callee", $spec, $pipes); +proc_open("$php -n $callee_escaped", $spec, $pipes); var_dump($pipes); echo "END\n"; diff --git a/ext/standard/tests/gh10885.phpt b/ext/standard/tests/gh10885.phpt new file mode 100644 index 0000000000000..167b832aa25ad --- /dev/null +++ b/ext/standard/tests/gh10885.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10885: stream_socket_server context leaks +--FILE-- + +--EXPECTF-- +resource(%d) of type (stream-context) refcount(2) +resource(%d) of type (stream-context) refcount(3) +resource(%d) of type (stream-context) refcount(2) diff --git a/ext/standard/tests/gh11010.phpt b/ext/standard/tests/gh11010.phpt new file mode 100644 index 0000000000000..cde4be52a66b5 --- /dev/null +++ b/ext/standard/tests/gh11010.phpt @@ -0,0 +1,9 @@ +--TEST-- +GH-11010: Preserve ini formatting of concatenated numbers +--FILE-- + +--EXPECT-- +string(9) "-00 20 30" diff --git a/ext/standard/tests/strings/bug26817.phpt b/ext/standard/tests/http/http_build_query/bug26817.phpt similarity index 100% rename from ext/standard/tests/strings/bug26817.phpt rename to ext/standard/tests/http/http_build_query/bug26817.phpt diff --git a/ext/standard/tests/strings/bug26819.phpt b/ext/standard/tests/http/http_build_query/bug26819.phpt similarity index 100% rename from ext/standard/tests/strings/bug26819.phpt rename to ext/standard/tests/http/http_build_query/bug26819.phpt diff --git a/ext/standard/tests/strings/bug77608.phpt b/ext/standard/tests/http/http_build_query/bug77608.phpt similarity index 100% rename from ext/standard/tests/strings/bug77608.phpt rename to ext/standard/tests/http/http_build_query/bug77608.phpt diff --git a/ext/standard/tests/strings/http_build_query.phpt b/ext/standard/tests/http/http_build_query/http_build_query.phpt similarity index 100% rename from ext/standard/tests/strings/http_build_query.phpt rename to ext/standard/tests/http/http_build_query/http_build_query.phpt diff --git a/ext/standard/tests/http/http_build_query/http_build_query_object_basic.phpt b/ext/standard/tests/http/http_build_query/http_build_query_object_basic.phpt new file mode 100644 index 0000000000000..91bb8fc622957 --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_object_basic.phpt @@ -0,0 +1,17 @@ +--TEST-- +http_build_query() function with object +--FILE-- + +--EXPECT-- +string(12) "public=input" diff --git a/ext/standard/tests/http/http_build_query/http_build_query_object_empty.phpt b/ext/standard/tests/http/http_build_query/http_build_query_object_empty.phpt new file mode 100644 index 0000000000000..7aca03df4a66a --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_object_empty.phpt @@ -0,0 +1,11 @@ +--TEST-- +http_build_query() function with empty object +--FILE-- + +--EXPECT-- +string(0) "" diff --git a/ext/standard/tests/http/http_build_query/http_build_query_object_just_stringable.phpt b/ext/standard/tests/http/http_build_query/http_build_query_object_just_stringable.phpt new file mode 100644 index 0000000000000..4c65547b81c8b --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_object_just_stringable.phpt @@ -0,0 +1,22 @@ +--TEST-- +http_build_query() function with object that is just stringable (GH-10229) +--FILE-- + +--EXPECT-- +string(7) "0=hello" +string(0) "" +string(14) "prefix_0=hello" +string(0) "" diff --git a/ext/standard/tests/http/http_build_query/http_build_query_object_key_val_stringable.phpt b/ext/standard/tests/http/http_build_query/http_build_query_object_key_val_stringable.phpt new file mode 100644 index 0000000000000..2a738df362ae3 --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_object_key_val_stringable.phpt @@ -0,0 +1,20 @@ +--TEST-- +http_build_query() function with recursif object +--FILE-- + +--EXPECT-- +string(12) "public=input" diff --git a/ext/standard/tests/http/http_build_query/http_build_query_object_nested.phpt b/ext/standard/tests/http/http_build_query/http_build_query_object_nested.phpt new file mode 100644 index 0000000000000..125327f0af002 --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_object_nested.phpt @@ -0,0 +1,20 @@ +--TEST-- +http_build_query() function with nested object +--FILE-- +public = $nested; + +// Percent encoded "public[public]=input" +var_dump(http_build_query($o)); +?> +--EXPECT-- +string(24) "public%5Bpublic%5D=input" diff --git a/ext/standard/tests/http/http_build_query/http_build_query_object_recursif.phpt b/ext/standard/tests/http/http_build_query/http_build_query_object_recursif.phpt new file mode 100644 index 0000000000000..ec415fc115b42 --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_object_recursif.phpt @@ -0,0 +1,17 @@ +--TEST-- +http_build_query() function with recursif object +--FILE-- +public = $o; + +var_dump(http_build_query($o)); +?> +--EXPECT-- +string(0) "" diff --git a/ext/standard/tests/strings/http_build_query_variation1.phpt b/ext/standard/tests/http/http_build_query/http_build_query_variation1.phpt similarity index 100% rename from ext/standard/tests/strings/http_build_query_variation1.phpt rename to ext/standard/tests/http/http_build_query/http_build_query_variation1.phpt diff --git a/ext/standard/tests/strings/http_build_query_variation2.phpt b/ext/standard/tests/http/http_build_query/http_build_query_variation2.phpt similarity index 100% rename from ext/standard/tests/strings/http_build_query_variation2.phpt rename to ext/standard/tests/http/http_build_query/http_build_query_variation2.phpt diff --git a/ext/standard/tests/strings/http_build_query_variation3.phpt b/ext/standard/tests/http/http_build_query/http_build_query_variation3.phpt similarity index 100% rename from ext/standard/tests/strings/http_build_query_variation3.phpt rename to ext/standard/tests/http/http_build_query/http_build_query_variation3.phpt diff --git a/ext/standard/tests/http/http_build_query/http_build_query_with_null.phpt b/ext/standard/tests/http/http_build_query/http_build_query_with_null.phpt new file mode 100644 index 0000000000000..3bcd1d0a35658 --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_with_null.phpt @@ -0,0 +1,8 @@ +--TEST-- +http_build_query() function with null in array +--FILE-- + +--EXPECT-- +string(0) "" diff --git a/ext/standard/tests/http/http_build_query/http_build_query_with_references.phpt b/ext/standard/tests/http/http_build_query/http_build_query_with_references.phpt new file mode 100644 index 0000000000000..4638ae4547c63 --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_with_references.phpt @@ -0,0 +1,11 @@ +--TEST-- +http_build_query() function with reference in array +--FILE-- + +--EXPECT-- +string(7) "0=value" diff --git a/ext/standard/tests/http/http_build_query/http_build_query_with_resource.phpt b/ext/standard/tests/http/http_build_query/http_build_query_with_resource.phpt new file mode 100644 index 0000000000000..c8b31064cd247 --- /dev/null +++ b/ext/standard/tests/http/http_build_query/http_build_query_with_resource.phpt @@ -0,0 +1,8 @@ +--TEST-- +http_build_query() function with resource in array +--FILE-- + +--EXPECT-- +string(0) "" diff --git a/ext/standard/tests/ini_info/php_ini_loaded_file.phpt b/ext/standard/tests/ini_info/php_ini_loaded_file.phpt index b4ad617f9fec3..1fce24e67fe4d 100644 --- a/ext/standard/tests/ini_info/php_ini_loaded_file.phpt +++ b/ext/standard/tests/ini_info/php_ini_loaded_file.phpt @@ -3,14 +3,14 @@ php_ini_loaded_file() function --FILE-- --EXPECTREGEX-- bool\(false\) diff --git a/ext/standard/tests/ini_info/php_ini_scanned_files.phpt b/ext/standard/tests/ini_info/php_ini_scanned_files.phpt index 27d2bebadf12a..6f750584fd71c 100644 --- a/ext/standard/tests/ini_info/php_ini_scanned_files.phpt +++ b/ext/standard/tests/ini_info/php_ini_scanned_files.phpt @@ -3,7 +3,7 @@ php_ini_scanned_files() function --FILE-- /dev/null +--SKIPIF-- + +--FILE-- + &$from]; +var_dump(mail('test@example.com', 'Test', 'Test', $headers)); +?> +--EXPECT-- +bool(false) diff --git a/ext/standard/tests/mail/gh8086.phpt b/ext/standard/tests/mail/gh8086.phpt new file mode 100644 index 0000000000000..fba5cc56bb450 --- /dev/null +++ b/ext/standard/tests/mail/gh8086.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-8086 (Mail() function not working correctly in PHP 8.x) +--INI-- +sendmail_path={MAIL:gh8086.out} +mail.mixed_lf_and_crlf=on +--FILE-- + +--CLEAN-- + +--EXPECT-- +bool(true) +int(5) diff --git a/ext/standard/tests/mail/mail_basic7.phpt b/ext/standard/tests/mail/mail_basic7.phpt index 47614c011eb76..a43617befc981 100644 --- a/ext/standard/tests/mail/mail_basic7.phpt +++ b/ext/standard/tests/mail/mail_basic7.phpt @@ -207,7 +207,7 @@ try { } ?> ---EXPECTF-- +--EXPECT-- *** Testing mail() : basic functionality *** @@ -242,7 +242,7 @@ TypeError: Header "foo1" must only contain numeric keys, "foo2" found TypeError: Header "foo2" must only contain values of type string, array found TypeError: Header "foo3" must only contain values of type string, int found TypeError: Header "foo4" must only contain values of type string, float found -TypeError: Header "foo5" must only contain values of type string, bool found +TypeError: Header "foo5" must only contain values of type string, false found TypeError: Header "foo6" must only contain values of type string, null found TypeError: Header "foo7" must only contain values of type string, stdClass found diff --git a/ext/standard/tests/misc/bug79410.phpt b/ext/standard/tests/misc/bug79410.phpt index d14d12c4064ad..8a674c0b6aa08 100644 --- a/ext/standard/tests/misc/bug79410.phpt +++ b/ext/standard/tests/misc/bug79410.phpt @@ -3,7 +3,7 @@ Bug #79410 (system() swallows last chunk if it is exactly 4095 bytes without new --FILE-- --EXPECT-- diff --git a/ext/standard/tests/oss_fuzz_57392.phpt b/ext/standard/tests/oss_fuzz_57392.phpt new file mode 100644 index 0000000000000..5a7e5b28d1caa --- /dev/null +++ b/ext/standard/tests/oss_fuzz_57392.phpt @@ -0,0 +1,17 @@ +--TEST-- +oss-fuzz #57392: Buffer-overflow in php_fgetcsv() with \0 delimiter and enclosure +--FILE-- + +--EXPECT-- +array(2) { + [0]=> + string(12) "aaaaaaaaaaaa" + [1]=> + string(2) " " +} diff --git a/ext/standard/tests/password/password_bcrypt_short.phpt b/ext/standard/tests/password/password_bcrypt_short.phpt new file mode 100644 index 0000000000000..085bc8a239045 --- /dev/null +++ b/ext/standard/tests/password/password_bcrypt_short.phpt @@ -0,0 +1,8 @@ +--TEST-- +Test that password_hash() does not overread buffers when a short hash is passed +--FILE-- + +--EXPECT-- +bool(false) diff --git a/ext/standard/tests/serialize/bug73341.phpt b/ext/standard/tests/serialize/bug73341.phpt index fc1d0271bbc06..460575c0a0652 100644 --- a/ext/standard/tests/serialize/bug73341.phpt +++ b/ext/standard/tests/serialize/bug73341.phpt @@ -2,6 +2,13 @@ Bug #73144 (Use-afte-free in ArrayObject Deserialization) --FILE-- getMessage()."\n"; +} + try { $token = 'a:2:{i:0;O:1:"0":2:0s:1:"0";i:0;s:1:"0";a:1:{i:0;C:11:"ArrayObject":7:{x:i:0;r}'; $obj = unserialize($token); @@ -20,5 +27,7 @@ unserialize($exploit); --EXPECTF-- Error at offset 6 of 7 bytes +Warning: unserialize(): Error at offset 19 of 79 bytes in %s on line %d + Warning: ArrayObject::unserialize(): Unexpected end of serialized data in %sbug73341.php on line %d Error at offset 24 of 34 bytes diff --git a/ext/standard/tests/serialize/bug74111.phpt b/ext/standard/tests/serialize/bug74111.phpt index 87c94423a2a27..2850f0725a939 100644 --- a/ext/standard/tests/serialize/bug74111.phpt +++ b/ext/standard/tests/serialize/bug74111.phpt @@ -6,5 +6,5 @@ $s = 'O:8:"stdClass":00000000'; var_dump(unserialize($s)); ?> --EXPECTF-- -Warning: unserialize(): Error at offset 25 of 23 bytes in %s on line %d +Warning: unserialize(): Error at offset 23 of 23 bytes in %s on line %d bool(false) diff --git a/ext/standard/tests/serialize/serialization_objects_017.phpt b/ext/standard/tests/serialize/serialization_objects_017.phpt new file mode 100644 index 0000000000000..875728f0c9d4d --- /dev/null +++ b/ext/standard/tests/serialize/serialization_objects_017.phpt @@ -0,0 +1,17 @@ +--TEST-- +Object serialization / unserialization: Strict format +--FILE-- + +--EXPECTF-- +Warning: unserialize(): Error at offset 9 of 22 bytes in %s on line %d +bool(false) + +Warning: unserialize(): Error at offset 10 of 22 bytes in %s on line %d +bool(false) diff --git a/ext/standard/tests/serialize/serialization_objects_018.phpt b/ext/standard/tests/serialize/serialization_objects_018.phpt new file mode 100644 index 0000000000000..b1c9ddb0b66cb --- /dev/null +++ b/ext/standard/tests/serialize/serialization_objects_018.phpt @@ -0,0 +1,33 @@ +--TEST-- +Object serialization / unserialization: Strict format (2) +--FILE-- + +--EXPECTF-- +Warning: unserialize(): Error at offset 9 of 15 bytes in %s on line %d +bool(false) + +Warning: unserialize(): Error at offset 10 of 15 bytes in %s on line %d +bool(false) + +Warning: unserialize(): Error at offset 14 of 15 bytes in %s on line %d +bool(false) + +Warning: unserialize(): Error at offset 8 of 8 bytes in %s on line %d +bool(false) diff --git a/ext/standard/tests/serialize/typed_property_ref_overwrite.phpt b/ext/standard/tests/serialize/typed_property_ref_overwrite.phpt index 148c66b76c741..9b68e50783795 100644 --- a/ext/standard/tests/serialize/typed_property_ref_overwrite.phpt +++ b/ext/standard/tests/serialize/typed_property_ref_overwrite.phpt @@ -7,7 +7,7 @@ class Test { public ?object $prop; } $s = <<<'STR' -O:4:"Test":2:{s:4:"prop";R:1;s:4:"prop";N;}} +O:4:"Test":2:{s:4:"prop";R:1;s:4:"prop";N;} STR; var_dump(unserialize($s)); diff --git a/ext/standard/tests/serialize/unserialize_extra_data_001.phpt b/ext/standard/tests/serialize/unserialize_extra_data_001.phpt new file mode 100644 index 0000000000000..421fb3428b3a7 --- /dev/null +++ b/ext/standard/tests/serialize/unserialize_extra_data_001.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test unserialize() with extra data at the end of a valid value +--FILE-- + +--EXPECTF-- +Warning: unserialize(): Extra data starting at offset 4 of 8 bytes in %s on line %d +int(5) + +Warning: unserialize(): Extra data starting at offset 2 of 6 bytes in %s on line %d +NULL + +Warning: unserialize(): Extra data starting at offset 4 of 8 bytes in %s on line %d +bool(true) + +Warning: unserialize(): Extra data starting at offset 20 of 24 bytes in %s on line %d +array(1) { + ["foo"]=> + bool(true) +} diff --git a/ext/standard/tests/serialize/unserialize_extra_data_002.phpt b/ext/standard/tests/serialize/unserialize_extra_data_002.phpt new file mode 100644 index 0000000000000..31e6a227f7112 --- /dev/null +++ b/ext/standard/tests/serialize/unserialize_extra_data_002.phpt @@ -0,0 +1,42 @@ +--TEST-- +Test unserialize() with extra data at the end of a valid value with nested unserialize +--FILE-- +foo = unserialize($foo['bar']); + } + + public function __serialize(): array + { + return [ + 'bar' => serialize($this->foo) . 'garbage', + ]; + } +} + +$f = new Foo; +$f->foo = ['a', 'b', 'c']; + +var_dump(unserialize(serialize($f) . 'garbage')); + +?> +--EXPECTF-- +Warning: unserialize(): Extra data starting at offset 81 of 88 bytes in %s on line %d + +Warning: unserialize(): Extra data starting at offset 42 of 49 bytes in %s on line %d +object(Foo)#2 (1) { + ["foo"]=> + array(3) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + [2]=> + string(1) "c" + } +} diff --git a/ext/standard/tests/serialize/unserialize_extra_data_003.phpt b/ext/standard/tests/serialize/unserialize_extra_data_003.phpt new file mode 100644 index 0000000000000..93f2c49a56a0c --- /dev/null +++ b/ext/standard/tests/serialize/unserialize_extra_data_003.phpt @@ -0,0 +1,42 @@ +--TEST-- +Test unserialize() with extra data at the end of a valid value with Serializable +--FILE-- +foo = unserialize($foo); + } + + public function serialize(): string + { + return serialize($this->foo) . 'garbage'; + } +} + +$f = new Foo; +$f->foo = ['a', 'b', 'c']; + +var_dump(unserialize(serialize($f) . 'garbage')); + +?> +--EXPECTF-- +Deprecated: Foo implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s on line %d + +Warning: unserialize(): Extra data starting at offset 42 of 49 bytes in %s on line %d + +Warning: unserialize(): Extra data starting at offset 64 of 71 bytes in %s on line %d +object(Foo)#2 (1) { + ["foo"]=> + array(3) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + [2]=> + string(1) "c" + } +} diff --git a/ext/standard/tests/streams/bug46024.phpt b/ext/standard/tests/streams/bug46024.phpt index 5a712dcb6b92d..2785c979e006d 100644 --- a/ext/standard/tests/streams/bug46024.phpt +++ b/ext/standard/tests/streams/bug46024.phpt @@ -2,17 +2,16 @@ Bug #46024 stream_select() doesn't return the correct number --SKIPIF-- --FILE-- array('pipe', 'r'), 1 => array('pipe', 'w')) ,$pipes, __DIR__, array(), array() ); diff --git a/ext/standard/tests/streams/bug70198.phpt b/ext/standard/tests/streams/bug70198.phpt index fc9c30f6fe348..0e122b66e8e7d 100644 --- a/ext/standard/tests/streams/bug70198.phpt +++ b/ext/standard/tests/streams/bug70198.phpt @@ -17,6 +17,7 @@ server $srv_addr = "tcp://127.0.0.1:8964"; $srv_fl = __DIR__ . "/bug70198_svr_" . md5(uniqid()) . ".php"; +$srv_fl_escaped = escapeshellarg($srv_fl); $srv_fl_cont = << array("file", "stderr.txt", "ab") ); $pipes = []; -$cmd = 'cmd.exe "/c START ^"^" /WAIT ' . PHP_BINARY . ' -r ^"var_dump(fgets(STDIN));"'; +$cmd = 'cmd.exe "/c START ^"^" /WAIT ' . getenv('TEST_PHP_EXECUTABLE_ESCAPED') . ' -r ^"var_dump(fgets(STDIN));"'; $proc = proc_open($cmd, $descriptorspec, $pipes); var_dump(is_resource($proc)); $pid = proc_get_status($proc)['pid']; diff --git a/ext/standard/tests/streams/gh10406.phpt b/ext/standard/tests/streams/gh10406.phpt new file mode 100644 index 0000000000000..0721dfbe9ed01 --- /dev/null +++ b/ext/standard/tests/streams/gh10406.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10406: feof() behavior change for UNIX based socket resources +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(false) diff --git a/ext/standard/tests/streams/proc_open_bug51800_right.phpt b/ext/standard/tests/streams/proc_open_bug51800_right.phpt index 1c889f6e9877c..ba68fa2a208ff 100644 --- a/ext/standard/tests/streams/proc_open_bug51800_right.phpt +++ b/ext/standard/tests/streams/proc_open_bug51800_right.phpt @@ -9,8 +9,8 @@ if (strpos(PHP_OS, 'FreeBSD') !== false) { --FILE-- array("pipe", "r"),1 => array("pipe", "w")); $pipes = array(); -$process = proc_open(PHP_BINARY.' -n -f ' . $fl, $descriptorspec, $pipes, NULL, NULL, array("blocking_pipes" => true)); +$process = proc_open(getenv('TEST_PHP_EXECUTABLE_ESCAPED').' -n -f ' . escapeshellarg($fl), $descriptorspec, $pipes, NULL, NULL, array("blocking_pipes" => true)); $moreThanLimit = 0; for($i = 0; $i < 10; $i++){ diff --git a/ext/standard/tests/strings/bug40754.phpt b/ext/standard/tests/strings/bug40754.phpt index c5bdeec2d0c73..41032a9405f13 100644 --- a/ext/standard/tests/strings/bug40754.phpt +++ b/ext/standard/tests/strings/bug40754.phpt @@ -81,7 +81,7 @@ string(6) "abcdex" int(0) int(0) substr_count(): Argument #3 ($offset) must be contained in argument #1 ($haystack) -substr_compare(): Argument #3 ($offset) must be contained in argument #1 ($main_str) +substr_compare(): Argument #3 ($offset) must be contained in argument #1 ($haystack) stripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack) substr_count(): Argument #3 ($offset) must be contained in argument #1 ($haystack) substr_count(): Argument #4 ($length) must be contained in argument #1 ($haystack) diff --git a/ext/standard/tests/strings/bug61038.phpt b/ext/standard/tests/strings/bug61038.phpt index 3c0831a0cbc14..d33be766346f8 100644 --- a/ext/standard/tests/strings/bug61038.phpt +++ b/ext/standard/tests/strings/bug61038.phpt @@ -17,7 +17,7 @@ array(1) { string(5) "str%c%c" } -Warning: unpack(): Type a: not enough input, need 6, have 5 in %s on line %d +Warning: unpack(): Type a: not enough input values, need 6 values but only 5 were provided in %s on line %d bool(false) array(1) { [1]=> diff --git a/ext/standard/tests/strings/count_chars_basic.phpt b/ext/standard/tests/strings/count_chars_basic.phpt index 50f5aecd6be75..ccf8cd47ac04a 100644 --- a/ext/standard/tests/strings/count_chars_basic.phpt +++ b/ext/standard/tests/strings/count_chars_basic.phpt @@ -1569,4 +1569,4 @@ array(238) { } string(18) " Rabcdefghimnorstu" string(476) "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051535455565758595a5b5c5d5e5f606a6b6c7071767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" -count_chars(): Argument #2 ($mode) must be between 1 and 4 (inclusive) +count_chars(): Argument #2 ($mode) must be between 0 and 4 (inclusive) diff --git a/ext/standard/tests/strings/gh10187.phpt b/ext/standard/tests/strings/gh10187.phpt new file mode 100644 index 0000000000000..b42c95e591ed0 --- /dev/null +++ b/ext/standard/tests/strings/gh10187.phpt @@ -0,0 +1,8 @@ +--TEST-- +GH-10187 (Segfault in stripslashes() with arm64) +--FILE-- + +--EXPECT-- +string(15) "1234567890abcde" diff --git a/ext/standard/tests/strings/gh10940.phpt b/ext/standard/tests/strings/gh10940.phpt new file mode 100644 index 0000000000000..518726c3a3992 --- /dev/null +++ b/ext/standard/tests/strings/gh10940.phpt @@ -0,0 +1,9 @@ +--TEST-- +Test unpacking at the 32-bit integer limit +--FILE-- + +--EXPECTF-- +Warning: unpack(): Type h: not enough input values, need 1073741824 values but only 12 were provided in %s on line %d diff --git a/ext/standard/tests/strings/html_entity_decode_iso8859-5.phpt b/ext/standard/tests/strings/html_entity_decode_iso8859-5.phpt index 46e6dc4dfe3c8..0616827c54853 100644 --- a/ext/standard/tests/strings/html_entity_decode_iso8859-5.phpt +++ b/ext/standard/tests/strings/html_entity_decode_iso8859-5.phpt @@ -358,47 +358,47 @@ CYRILLIC SMALL LETTER YA: я => ef NUMERO SIGN: № => f0 ð => ð -CYRILLIC SMALL LETTER IO: ё => 2623783435313b +CYRILLIC SMALL LETTER IO: ё => f1 ñ => ñ -CYRILLIC SMALL LETTER DJE: ђ => 2623783435323b +CYRILLIC SMALL LETTER DJE: ђ => f2 ò => ò -CYRILLIC SMALL LETTER GJE: ѓ => 2623783435333b +CYRILLIC SMALL LETTER GJE: ѓ => f3 ó => ó -CYRILLIC SMALL LETTER UKRAINIAN IE: є => 2623783435343b +CYRILLIC SMALL LETTER UKRAINIAN IE: є => f4 ô => ô -CYRILLIC SMALL LETTER DZE: ѕ => 2623783435353b +CYRILLIC SMALL LETTER DZE: ѕ => f5 õ => õ -CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I: і => 2623783435363b +CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I: і => f6 ö => ö -CYRILLIC SMALL LETTER YI: ї => 2623783435373b +CYRILLIC SMALL LETTER YI: ї => f7 ÷ => ÷ -CYRILLIC SMALL LETTER JE: ј => 2623783435383b +CYRILLIC SMALL LETTER JE: ј => f8 ø => ø -CYRILLIC SMALL LETTER LJE: љ => 2623783435393b +CYRILLIC SMALL LETTER LJE: љ => f9 ù => ù -CYRILLIC SMALL LETTER NJE: њ => 2623783435413b +CYRILLIC SMALL LETTER NJE: њ => fa ú => ú -CYRILLIC SMALL LETTER TSHE: ћ => 2623783435423b +CYRILLIC SMALL LETTER TSHE: ћ => fb û => û -CYRILLIC SMALL LETTER KJE: ќ => 2623783435433b +CYRILLIC SMALL LETTER KJE: ќ => fc ü => ü SECTION SIGN: § => fd ý => ý -CYRILLIC SMALL LETTER SHORT U: ў => 2623783435453b +CYRILLIC SMALL LETTER SHORT U: ў => fe þ => þ -CYRILLIC SMALL LETTER DZHE: џ => 2623783435463b +CYRILLIC SMALL LETTER DZHE: џ => ff ÿ => ÿ diff --git a/ext/standard/tests/strings/join_variation2.phpt b/ext/standard/tests/strings/join_variation2.phpt index 57f570b258703..d3e9807b76055 100644 --- a/ext/standard/tests/strings/join_variation2.phpt +++ b/ext/standard/tests/strings/join_variation2.phpt @@ -120,13 +120,13 @@ join(): Argument #2 ($array) must be of type ?array, float given -- Iteration 9 -- join(): Argument #2 ($array) must be of type ?array, float given -- Iteration 10 -- -join(): Argument #2 ($array) must be of type ?array, bool given +join(): Argument #2 ($array) must be of type ?array, true given -- Iteration 11 -- -join(): Argument #2 ($array) must be of type ?array, bool given +join(): Argument #2 ($array) must be of type ?array, false given -- Iteration 12 -- -join(): Argument #2 ($array) must be of type ?array, bool given +join(): Argument #2 ($array) must be of type ?array, true given -- Iteration 13 -- -join(): Argument #2 ($array) must be of type ?array, bool given +join(): Argument #2 ($array) must be of type ?array, false given -- Iteration 14 -- join(): Argument #2 ($array) must be of type ?array, string given -- Iteration 15 -- diff --git a/ext/standard/tests/strings/pack_Z.phpt b/ext/standard/tests/strings/pack_Z.phpt index 672077bd89a28..ac0608a9bd084 100644 --- a/ext/standard/tests/strings/pack_Z.phpt +++ b/ext/standard/tests/strings/pack_Z.phpt @@ -18,7 +18,7 @@ var_dump( ); ?> --EXPECTF-- -Warning: unpack(): Type Z: not enough input, need 2, have 1 in %s on line %d +Warning: unpack(): Type Z: not enough input values, need 2 values but only 1 was provided in %s on line %d string(0) "" string(5) "foo%c%c" string(4) "foo%c" diff --git a/ext/standard/tests/strings/strtok_variation3.phpt b/ext/standard/tests/strings/strtok_variation3.phpt index 8ae1e03e7dba8..d5cf1ad91dba4 100644 --- a/ext/standard/tests/strings/strtok_variation3.phpt +++ b/ext/standard/tests/strings/strtok_variation3.phpt @@ -62,7 +62,7 @@ foreach($heredoc_strings as $string) { echo "Done\n"; ?> ---EXPECT-- +--EXPECTF-- *** Testing strtok() : with heredoc strings *** --- Iteration 1 --- @@ -80,15 +80,35 @@ bool(false) --- Iteration 2 --- bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) --- Iteration 3 --- @@ -137,9 +157,19 @@ string(3) "rld" string(4) "hell" string(4) "hell" bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) Done diff --git a/ext/standard/tests/strings/strtok_variation4.phpt b/ext/standard/tests/strings/strtok_variation4.phpt index 63090497097f9..671cf74b03138 100644 --- a/ext/standard/tests/strings/strtok_variation4.phpt +++ b/ext/standard/tests/strings/strtok_variation4.phpt @@ -36,15 +36,25 @@ foreach( $strings_with_nulls as $string ) { echo "Done\n"; ?> ---EXPECT-- +--EXPECTF-- *** Testing strtok() : with embedded nulls in the strings *** --- Iteration 1 --- bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) --- Iteration 2 --- @@ -82,9 +92,17 @@ bool(false) --- Iteration 6 --- string(11) "hello world" bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) --- Iteration 7 --- diff --git a/ext/standard/tests/strings/strtok_variation5.phpt b/ext/standard/tests/strings/strtok_variation5.phpt index 006cf7a9f9607..bc33315b960f1 100644 --- a/ext/standard/tests/strings/strtok_variation5.phpt +++ b/ext/standard/tests/strings/strtok_variation5.phpt @@ -52,7 +52,7 @@ foreach( $string_array as $string ) { echo "Done\n"; ?> ---EXPECT-- +--EXPECTF-- *** Testing strtok() : with miscellaneous inputs *** --- Iteration 1 --- @@ -65,10 +65,20 @@ bool(false) --- Iteration 2 --- bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) --- Iteration 3 --- @@ -113,18 +123,38 @@ bool(false) --- Iteration 8 --- bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) --- Iteration 9 --- bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) --- Iteration 10 --- diff --git a/ext/standard/tests/strings/strtok_variation6.phpt b/ext/standard/tests/strings/strtok_variation6.phpt index 9b3f1d244d81f..255c100a0b194 100644 --- a/ext/standard/tests/strings/strtok_variation6.phpt +++ b/ext/standard/tests/strings/strtok_variation6.phpt @@ -42,7 +42,7 @@ foreach( $string_array as $string ) { echo "Done\n"; ?> ---EXPECT-- +--EXPECTF-- *** Testing strtok() : with invalid escape sequences in token *** --- Iteration 1 --- @@ -69,6 +69,8 @@ bool(false) string(1) " " string(1) "r" bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) @@ -91,11 +93,15 @@ bool(false) string(5) "hello" string(6) " world" bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) string(1) " " string(1) "r" bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) @@ -113,6 +119,8 @@ bool(false) string(6) "hello\" string(6) " world" bool(false) + +Warning: strtok(): Both arguments must be provided when starting tokenization in %s on line %d bool(false) string(1) "/" diff --git a/ext/standard/tests/strings/strtolower.phpt b/ext/standard/tests/strings/strtolower.phpt index 6052ccd840d50..1abe45a8a0524 100644 --- a/ext/standard/tests/strings/strtolower.phpt +++ b/ext/standard/tests/strings/strtolower.phpt @@ -30,6 +30,7 @@ $strings = array ( "ZZZZZZZZZZZZZZZZZZZZ", "@@@@@@@@@@@@@@@@@@@@", "[[[[[[[[[[[[[[[[[[[[", + "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ); $count = 0; @@ -347,6 +348,9 @@ string(20) "@@@@@@@@@@@@@@@@@@@@" -- Iteration 11 -- string(20) "[[[[[[[[[[[[[[[[[[[[" +-- Iteration 12 -- +string(62) "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz" + *** Testing strtolower() with two different case strings *** strings are same, with Case Insensitive *** Done *** diff --git a/ext/standard/tests/strings/strtoupper1.phpt b/ext/standard/tests/strings/strtoupper1.phpt index abda0b9d38b28..220906a5ba535 100644 --- a/ext/standard/tests/strings/strtoupper1.phpt +++ b/ext/standard/tests/strings/strtoupper1.phpt @@ -28,6 +28,12 @@ $strings = array ( "zzzzzzzzzzzzzzzzzzzz", "````````````````````", "{{{{{{{{{{{{{{{{{{{{", + /* And the AVX2 implementation also */ + "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{", + "abcdefghijklmnopqrstuvwxyz01234", + "abcdefghijklmnopqrstuvwxyz012345", + "abcdefghijklmnopqrstuvwxyz0123456", + "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ); $count = 0; @@ -346,6 +352,21 @@ string(20) "````````````````````" -- Iteration 11 -- string(20) "{{{{{{{{{{{{{{{{{{{{" +-- Iteration 12 -- +string(40) "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{" + +-- Iteration 13 -- +string(31) "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234" + +-- Iteration 14 -- +string(32) "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345" + +-- Iteration 15 -- +string(33) "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456" + +-- Iteration 16 -- +string(62) "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + *** Testing strtoupper() with two different case strings *** strings are same, with Case Insensitive *** Done *** diff --git a/ext/standard/tests/strings/substr_replace_array_unset.phpt b/ext/standard/tests/strings/substr_replace_array_unset.phpt new file mode 100644 index 0000000000000..ff253d3984476 --- /dev/null +++ b/ext/standard/tests/strings/substr_replace_array_unset.phpt @@ -0,0 +1,27 @@ +--TEST-- +substr_replace() function - array with unset +--FILE-- + 'bar', 'baz']; +unset($replacement[42]); +$newarr = substr_replace(['1 string', '2 string'], $replacement, 0); +print_r($newarr); + +?> +--EXPECT-- +Array +( + [0] => A + [1] => B +) +Array +( + [0] => foo + [1] => baz +) diff --git a/ext/standard/tests/strings/vprintf_variation2.phpt b/ext/standard/tests/strings/vprintf_variation2.phpt index 22f2f152d85a2..f6d92e577402c 100644 --- a/ext/standard/tests/strings/vprintf_variation2.phpt +++ b/ext/standard/tests/strings/vprintf_variation2.phpt @@ -132,16 +132,16 @@ vprintf(): Argument #2 ($values) must be of type array, null given vprintf(): Argument #2 ($values) must be of type array, null given -- Iteration 12 -- -vprintf(): Argument #2 ($values) must be of type array, bool given +vprintf(): Argument #2 ($values) must be of type array, true given -- Iteration 13 -- -vprintf(): Argument #2 ($values) must be of type array, bool given +vprintf(): Argument #2 ($values) must be of type array, false given -- Iteration 14 -- -vprintf(): Argument #2 ($values) must be of type array, bool given +vprintf(): Argument #2 ($values) must be of type array, true given -- Iteration 15 -- -vprintf(): Argument #2 ($values) must be of type array, bool given +vprintf(): Argument #2 ($values) must be of type array, false given -- Iteration 16 -- vprintf(): Argument #2 ($values) must be of type array, string given diff --git a/ext/standard/tests/url/base64_decode_basic_002.phpt b/ext/standard/tests/url/base64_decode_basic_002.phpt index 7d19e9cb9c65f..0b4b4f9e23cd7 100644 --- a/ext/standard/tests/url/base64_decode_basic_002.phpt +++ b/ext/standard/tests/url/base64_decode_basic_002.phpt @@ -21,6 +21,21 @@ var_dump(base64_decode($badChars)); var_dump(base64_decode($badChars, false)); var_dump(base64_decode($badChars, true)); +echo "\nTests on long string for SIMD\n"; +$noWhiteSpace = "UEhQIGlzIGEgcG9wdWxhciBnZW5lcmFsLXB1cnBvc2Ugc2NyaXB0aW5nIGxhbmd1YWdlIHRoYXQgaXMgZXNwZWNpYWxseSBzdWl0ZWQgdG8gd2ViIGRldmVsb3BtZW50"; +var_dump(base64_decode($noWhiteSpace)); +var_dump(base64_decode($noWhiteSpace, false)); +var_dump(base64_decode($noWhiteSpace, true)); +$withWhiteSpace = "UEhQIGlzIGE gcG9wdWxhciBnZW5lcmFsLXB1cnBvc2Ugc2NyaXB0aW5nIGxhbmd1YWdl IHRoYXQga + XMgZXNwZWNpYWxseSBzdWl0ZWQgdG8gd2ViIGRldmVsb3BtZW50"; +var_dump(base64_decode($withWhiteSpace)); +var_dump(base64_decode($withWhiteSpace, false)); +var_dump(base64_decode($withWhiteSpace, true)); +$badChars = $noWhiteSpace . '*'; +var_dump(base64_decode($badChars)); +var_dump(base64_decode($badChars, false)); +var_dump(base64_decode($badChars, true)); + echo "Done"; ?> --EXPECT-- @@ -38,4 +53,15 @@ Other chars outside the base64 alphabet are ignored when $strict===false, but ca string(12) "hello world!" string(12) "hello world!" bool(false) + +Tests on long string for SIMD +string(96) "PHP is a popular general-purpose scripting language that is especially suited to web development" +string(96) "PHP is a popular general-purpose scripting language that is especially suited to web development" +string(96) "PHP is a popular general-purpose scripting language that is especially suited to web development" +string(96) "PHP is a popular general-purpose scripting language that is especially suited to web development" +string(96) "PHP is a popular general-purpose scripting language that is especially suited to web development" +string(96) "PHP is a popular general-purpose scripting language that is especially suited to web development" +string(96) "PHP is a popular general-purpose scripting language that is especially suited to web development" +string(96) "PHP is a popular general-purpose scripting language that is especially suited to web development" +bool(false) Done diff --git a/ext/standard/tests/url/base64_encode_basic_001.phpt b/ext/standard/tests/url/base64_encode_basic_001.phpt index a85c1b0a0f8da..7d74696eb80da 100644 --- a/ext/standard/tests/url/base64_encode_basic_001.phpt +++ b/ext/standard/tests/url/base64_encode_basic_001.phpt @@ -14,7 +14,24 @@ for ($i=0; $i<256; $i++) { printf("0x%X: %s\n", $i, $enc); } -echo "Done"; +$values = array( + "Hello World", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!%^&*(){}[]", + "\n\t Line with control characters\r\n", + "\xC1\xC2\xC3\xC4\xC5\xC6", + "\75\76\77\78\79\80", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!\75\76\77\78\79\80", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!\75\76\77\78\79\80" +); + +foreach($values as $str) { + $enc = base64_encode($str); + printf("%s\n", $enc); +} + +echo "Done\n"; ?> --EXPECT-- *** Testing base64_encode() : basic functionality *** @@ -274,4 +291,13 @@ echo "Done"; 0xFD: /Q== 0xFE: /g== 0xFF: /w== +SGVsbG8gV29ybGQ= +QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoxMjM0NTY3ODkwISVeJiooKXt9W10= +CgkgTGluZSB3aXRoIGNvbnRyb2wgY2hhcmFjdGVycw0K +wcLDxMXG +PT4/BzgHOVw4MA== +QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODklIQ== +QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODklIT0+Pwc4BzlcODA= +QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODklIUFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5JSE= +QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODklIUFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5JSE9Pj8HOAc5XDgw Done diff --git a/ext/standard/tests/url/base64_encode_basic_002.phpt b/ext/standard/tests/url/base64_encode_basic_002.phpt index 697afc09160d5..fff9b05c67b21 100644 --- a/ext/standard/tests/url/base64_encode_basic_002.phpt +++ b/ext/standard/tests/url/base64_encode_basic_002.phpt @@ -13,7 +13,11 @@ $values = array( "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!%^&*(){}[]", "\n\t Line with control characters\r\n", "\xC1\xC2\xC3\xC4\xC5\xC6", - "\75\76\77\78\79\80" + "\75\76\77\78\79\80", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!\75\76\77\78\79\80", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%!\75\76\77\78\79\80" ); echo "\n--- Testing base64_encode() with binary string input ---\n"; @@ -49,3 +53,11 @@ TEST PASSED TEST PASSED -- Iteration 5 -- TEST PASSED +-- Iteration 6 -- +TEST PASSED +-- Iteration 7 -- +TEST PASSED +-- Iteration 8 -- +TEST PASSED +-- Iteration 9 -- +TEST PASSED diff --git a/ext/standard/tests/url/base64_loop_001.phpt b/ext/standard/tests/url/base64_loop_001.phpt new file mode 100644 index 0000000000000..e6b9b7adedb68 --- /dev/null +++ b/ext/standard/tests/url/base64_loop_001.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test base64_encode() and base64_decode() function : loop mode +--FILE-- + +--EXPECT-- +*** Testing base64_encode() and base64_decode(): loop mode *** +TEST PASSED +Done diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index 2c4d5d3d263fb..adfec58e8dbee 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -112,7 +112,7 @@ static void userfilter_dtor(php_stream_filter *thisfilter) return; } - zend_string *func_name = zend_string_init("onclose", sizeof("onclose")-1, 0); + zend_string *func_name = ZSTR_INIT_LITERAL("onclose", 0); zend_call_method_if_exists(Z_OBJ_P(obj), func_name, &retval, 0, NULL); zend_string_release(func_name); @@ -313,7 +313,7 @@ static php_stream_filter *user_filter_factory_create(const char *filtername, } /* invoke the constructor */ - zend_string *func_name = zend_string_init("oncreate", sizeof("oncreate")-1, 0); + zend_string *func_name = ZSTR_INIT_LITERAL("oncreate", 0); zend_call_method_if_exists(Z_OBJ(obj), func_name, &retval, 0, NULL); zend_string_release(func_name); diff --git a/ext/standard/var.c b/ext/standard/var.c index 7c6f79aba75ff..cbd59e22c5230 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -680,7 +680,7 @@ static inline zend_long php_add_var_hash(php_serialize_data_t data, zval *var) / /* Index for the variable is stored using the numeric value of the pointer to * the zend_refcounted struct */ - key = (zend_ulong) (zend_uintptr_t) Z_COUNTED_P(var); + key = (zend_ulong) (uintptr_t) Z_COUNTED_P(var); zv = zend_hash_index_find(&data->ht, key); if (zv) { @@ -764,28 +764,13 @@ static inline bool php_var_serialize_class_name(smart_str *buf, zval *struc) /* static HashTable* php_var_serialize_call_sleep(zend_object *obj, zend_function *fn) /* {{{ */ { - zend_result res; - zend_fcall_info fci; - zend_fcall_info_cache fci_cache; zval retval; - fci.size = sizeof(fci); - fci.object = obj; - fci.retval = &retval; - fci.param_count = 0; - fci.params = NULL; - fci.named_params = NULL; - ZVAL_UNDEF(&fci.function_name); - - fci_cache.function_handler = fn; - fci_cache.object = obj; - fci_cache.called_scope = obj->ce; - BG(serialize_lock)++; - res = zend_call_function(&fci, &fci_cache); + zend_call_known_instance_method(fn, obj, &retval, /* param_count */ 0, /* params */ NULL); BG(serialize_lock)--; - if (res == FAILURE || Z_ISUNDEF(retval)) { + if (Z_ISUNDEF(retval) || EG(exception)) { zval_ptr_dtor(&retval); return NULL; } @@ -1148,7 +1133,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_ } else { /* Mark this value in the var_hash, to avoid creating references to it. */ zval *var_idx = zend_hash_index_find(&var_hash->ht, - (zend_ulong) (zend_uintptr_t) Z_COUNTED_P(struc)); + (zend_ulong) (uintptr_t) Z_COUNTED_P(struc)); if (var_idx) { ZVAL_LONG(var_idx, -1); } @@ -1348,7 +1333,7 @@ PHPAPI void php_unserialize_with_options(zval *return_value, const char *buf, co classes = zend_hash_str_find_deref(options, "allowed_classes", sizeof("allowed_classes")-1); if (classes && Z_TYPE_P(classes) != IS_ARRAY && Z_TYPE_P(classes) != IS_TRUE && Z_TYPE_P(classes) != IS_FALSE) { - zend_type_error("%s(): Option \"allowed_classes\" must be of type array|bool, %s given", function_name, zend_zval_type_name(classes)); + zend_type_error("%s(): Option \"allowed_classes\" must be of type array|bool, %s given", function_name, zend_zval_value_name(classes)); goto cleanup; } @@ -1377,7 +1362,7 @@ PHPAPI void php_unserialize_with_options(zval *return_value, const char *buf, co max_depth = zend_hash_str_find_deref(options, "max_depth", sizeof("max_depth") - 1); if (max_depth) { if (Z_TYPE_P(max_depth) != IS_LONG) { - zend_type_error("%s(): Option \"max_depth\" must be of type int, %s given", function_name, zend_zval_type_name(max_depth)); + zend_type_error("%s(): Option \"max_depth\" must be of type int, %s given", function_name, zend_zval_value_name(max_depth)); goto cleanup; } if (Z_LVAL_P(max_depth) < 0) { @@ -1406,11 +1391,19 @@ PHPAPI void php_unserialize_with_options(zval *return_value, const char *buf, co zval_ptr_dtor(return_value); } RETVAL_FALSE; - } else if (BG(unserialize).level > 1) { - ZVAL_COPY(return_value, retval); - } else if (Z_REFCOUNTED_P(return_value)) { - zend_refcounted *ref = Z_COUNTED_P(return_value); - gc_check_possible_root(ref); + } else { + if ((char*)p < buf + buf_len) { + if (!EG(exception)) { + php_error_docref(NULL, E_WARNING, "Extra data starting at offset " ZEND_LONG_FMT " of %zd bytes", + (zend_long)((char*)p - buf), buf_len); + } + } + if (BG(unserialize).level > 1) { + ZVAL_COPY(return_value, retval); + } else if (Z_REFCOUNTED_P(return_value)) { + zend_refcounted *ref = Z_COUNTED_P(return_value); + gc_check_possible_root(ref); + } } cleanup: diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 12b0ff47c803e..a050fb5f74a70 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -616,7 +616,7 @@ declared_property: if ((*var_hash)->ref_props) { /* Remove old entry from ref_props table, if it exists. */ zend_hash_index_del( - (*var_hash)->ref_props, (zend_uintptr_t) data); + (*var_hash)->ref_props, (uintptr_t) data); } } /* We may override default property value, but they are usually immutable */ @@ -705,7 +705,7 @@ second_try: zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0); } zend_hash_index_update_ptr( - (*var_hash)->ref_props, (zend_uintptr_t) data, info); + (*var_hash)->ref_props, (uintptr_t) data, info); } } @@ -743,6 +743,19 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) datalen = parse_iv2((*p) + 2, p); + if (max - (*p) < 2) { + return 0; + } + + if ((*p)[0] != ':') { + return 0; + } + + if ((*p)[1] != '{') { + (*p) += 1; + return 0; + } + (*p) += 2; if (datalen < 0 || (max - (*p)) <= datalen) { @@ -754,6 +767,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) * with unserialize reading past the end of the passed buffer if the string is not * appropriately terminated (usually NUL terminated, but '}' is also sufficient.) */ if ((*p)[datalen] != '}') { + (*p) += datalen; return 0; } @@ -901,7 +915,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) if (!Z_ISREF_P(rval_ref)) { zend_property_info *info = NULL; if ((*var_hash)->ref_props) { - info = zend_hash_index_find_ptr((*var_hash)->ref_props, (zend_uintptr_t) rval_ref); + info = zend_hash_index_find_ptr((*var_hash)->ref_props, (uintptr_t) rval_ref); } ZVAL_NEW_REF(rval_ref, rval_ref); if (info) { @@ -1293,6 +1307,16 @@ object ":" uiv ":" ["] { return 0; } + YYCURSOR = *p; + + if (*(YYCURSOR) != ':') { + return 0; + } + if (*(YYCURSOR+1) != '{') { + *p = YYCURSOR+1; + return 0; + } + *p += 2; has_unserialize = !incomplete_class && ce->__unserialize; diff --git a/ext/sysvmsg/sysvmsg.c b/ext/sysvmsg/sysvmsg.c index debb8b675b0c2..20bdecedb50c3 100644 --- a/ext/sysvmsg/sysvmsg.c +++ b/ext/sysvmsg/sysvmsg.c @@ -398,7 +398,7 @@ PHP_FUNCTION(msg_send) break; default: - zend_argument_type_error(3, "must be of type string|int|float|bool, %s given", zend_zval_type_name(message)); + zend_argument_type_error(3, "must be of type string|int|float|bool, %s given", zend_zval_value_name(message)); RETURN_THROWS(); } diff --git a/ext/sysvshm/tests/bug72858.phpt b/ext/sysvshm/tests/bug72858.phpt index 3a12027440048..846f309678b4c 100644 --- a/ext/sysvshm/tests/bug72858.phpt +++ b/ext/sysvshm/tests/bug72858.phpt @@ -7,6 +7,7 @@ sysvshm if (4 < PHP_INT_SIZE) { print "skip 32-bit only"; } if (substr(PHP_OS, 0, 3) != "WIN") { print "skip windows only"; } +if (getenv('GITHUB_ACTIONS')) die('skip on GitHub actions'); ?> --FILE-- ---EXPECT-- +--EXPECTF-- line 1 column 1 - Warning: missing declaration -line 1 column 7 - Error: is not recognized! +line 1 column 7 - Error: is not recogni%ced! line 1 column 7 - Warning: discarding unexpected line 1 column 17 - Warning: discarding unexpected line 1 column 7 - Warning: inserting missing 'title' element diff --git a/ext/tidy/tests/008.phpt b/ext/tidy/tests/008.phpt index b6cf26a521abc..bb3b779b67b59 100644 --- a/ext/tidy/tests/008.phpt +++ b/ext/tidy/tests/008.phpt @@ -7,9 +7,9 @@ tidy $a = tidy_parse_string(""); echo $a->errorBuffer; ?> ---EXPECT-- +--EXPECTF-- line 1 column 1 - Warning: missing declaration -line 1 column 7 - Error: is not recognized! +line 1 column 7 - Error: is not recogni%ced! line 1 column 7 - Warning: discarding unexpected line 1 column 17 - Warning: discarding unexpected line 1 column 7 - Warning: inserting missing 'title' element diff --git a/ext/tidy/tests/019.phpt b/ext/tidy/tests/019.phpt index 20a15c7018ce2..444ecc155a45c 100644 --- a/ext/tidy/tests/019.phpt +++ b/ext/tidy/tests/019.phpt @@ -28,13 +28,13 @@ tidy_repair_file($l, $l, $l ,$l); // This doesn't emit any warning, TODO look in echo "Done\n"; ?> --EXPECTF-- -Warning: tidy_repair_string(): Could not load configuration file "1" in %s on line %d +Warning: tidy_repair_string(): Could not load the Tidy configuration file "1" in %s on line %d Warning: tidy_repair_string(): Could not set encoding "1" in %s on line %d -Warning: tidy_repair_string(): Could not load configuration file "" in %s on line %d +Warning: tidy_repair_string(): Could not load the Tidy configuration file "" in %s on line %d -Warning: tidy_repair_string(): Could not load configuration file "1" in %s on line %d +Warning: tidy_repair_string(): Could not load the Tidy configuration file "1" in %s on line %d Warning: tidy_repair_string(): Could not set encoding "1" in %s on line %d Path cannot be empty diff --git a/ext/tidy/tests/gh10636.phpt b/ext/tidy/tests/gh10636.phpt new file mode 100644 index 0000000000000..ce0aa3c08d1b2 --- /dev/null +++ b/ext/tidy/tests/gh10636.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-10636 (Tidy does not output notice when it encountered parse errors in the default configuration file) +--EXTENSIONS-- +tidy +--INI-- +tidy.default_config={PWD}/gh10636_config +--FILE-- + +--EXPECTF-- +Notice: main(): There were errors while parsing the Tidy configuration file "%sgh10636_config" in %s on line %d diff --git a/ext/tidy/tests/gh10636_config b/ext/tidy/tests/gh10636_config new file mode 100644 index 0000000000000..d9c4755a2d744 --- /dev/null +++ b/ext/tidy/tests/gh10636_config @@ -0,0 +1 @@ +indent:@ diff --git a/ext/tidy/tests/parsing_file_too_large.phpt b/ext/tidy/tests/parsing_file_too_large.phpt new file mode 100644 index 0000000000000..25829bf4e9595 --- /dev/null +++ b/ext/tidy/tests/parsing_file_too_large.phpt @@ -0,0 +1,59 @@ +--TEST-- +Trying to parse a file that is too large (over 4GB) +--EXTENSIONS-- +tidy +--SKIPIF-- + +--CONFLICTS-- +all +--INI-- +memory_limit="5G" +--FILE-- +parseFile($path)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +try { + var_dump(tidy_parse_file($path)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +try { + $tidy = new tidy($path); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +?> +--CLEAN-- + +--EXPECT-- +int(0) +ValueError: Input string is too long +ValueError: Input string is too long +ValueError: Input string is too long diff --git a/ext/tidy/tests/parsing_inexistent_file.phpt b/ext/tidy/tests/parsing_inexistent_file.phpt new file mode 100644 index 0000000000000..26dfea798574e --- /dev/null +++ b/ext/tidy/tests/parsing_inexistent_file.phpt @@ -0,0 +1,22 @@ +--TEST-- +Trying to parse a non existent file +--EXTENSIONS-- +tidy +--FILE-- +parseFile("does_not_exist.html")); + +var_dump(tidy_parse_file("does_not_exist.html")); + +$tidy = new tidy("does_not_exist.html"); +?> +--EXPECTF-- +Warning: tidy::parseFile(): Cannot load "does_not_exist.html" into memory in %s on line %d +bool(false) + +Warning: tidy_parse_file(): Cannot load "does_not_exist.html" into memory in %s on line %d +bool(false) + +Warning: tidy::__construct(): Cannot load "does_not_exist.html" into memory in %s on line %d diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index 535ac785cacac..e7b345dd25e34 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -79,14 +79,7 @@ _php_tidy_apply_config_array(_doc, _val_ht); \ } else if (_val_str) { \ TIDY_OPEN_BASE_DIR_CHECK(ZSTR_VAL(_val_str)); \ - switch (tidyLoadConfig(_doc, ZSTR_VAL(_val_str))) { \ - case -1: \ - php_error_docref(NULL, E_WARNING, "Could not load configuration file \"%s\"", ZSTR_VAL(_val_str)); \ - break; \ - case 1: \ - php_error_docref(NULL, E_NOTICE, "There were errors while parsing the configuration file \"%s\"", ZSTR_VAL(_val_str)); \ - break; \ - } \ + php_tidy_load_config(_doc, ZSTR_VAL(_val_str)); \ } #define TIDY_OPEN_BASE_DIR_CHECK(filename) \ @@ -96,9 +89,7 @@ if (php_check_open_basedir(filename)) { \ #define TIDY_SET_DEFAULT_CONFIG(_doc) \ if (TG(default_config) && TG(default_config)[0]) { \ - if (tidyLoadConfig(_doc, TG(default_config)) < 0) { \ - php_error_docref(NULL, E_WARNING, "Unable to load Tidy configuration file at \"%s\"", TG(default_config)); \ - } \ + php_tidy_load_config(_doc, TG(default_config)); \ } /* }}} */ @@ -220,6 +211,16 @@ static void TIDY_CALL php_tidy_panic(ctmbstr msg) php_error_docref(NULL, E_ERROR, "Could not allocate memory for tidy! (Reason: %s)", (char *)msg); } +static void php_tidy_load_config(TidyDoc doc, const char *path) +{ + int ret = tidyLoadConfig(doc, path); + if (ret < 0) { + php_error_docref(NULL, E_WARNING, "Could not load the Tidy configuration file \"%s\"", path); + } else if (ret > 0) { + php_error_docref(NULL, E_NOTICE, "There were errors while parsing the Tidy configuration file \"%s\"", path); + } +} + static int _php_tidy_set_tidy_opt(TidyDoc doc, char *optname, zval *value) { TidyOption opt = tidyGetOptionByName(doc, optname); @@ -1069,19 +1070,20 @@ PHP_FUNCTION(tidy_parse_file) Z_PARAM_BOOL(use_include_path) ZEND_PARSE_PARAMETERS_END(); - tidy_instantiate(tidy_ce_doc, return_value); - obj = Z_TIDY_P(return_value); - if (!(contents = php_tidy_file_to_mem(ZSTR_VAL(inputfile), use_include_path))) { php_error_docref(NULL, E_WARNING, "Cannot load \"%s\" into memory%s", ZSTR_VAL(inputfile), (use_include_path) ? " (using include path)" : ""); RETURN_FALSE; } if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) { + zend_string_release_ex(contents, 0); zend_value_error("Input string is too long"); RETURN_THROWS(); } + tidy_instantiate(tidy_ce_doc, return_value); + obj = Z_TIDY_P(return_value); + TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { @@ -1372,6 +1374,7 @@ PHP_METHOD(tidy, __construct) } if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) { + zend_string_release_ex(contents, 0); zend_value_error("Input string is too long"); RETURN_THROWS(); } @@ -1410,6 +1413,7 @@ PHP_METHOD(tidy, parseFile) } if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) { + zend_string_release_ex(contents, 0); zend_value_error("Input string is too long"); RETURN_THROWS(); } diff --git a/ext/tokenizer/tokenizer.c b/ext/tokenizer/tokenizer.c index 20124dbf9110b..75cc99d7b84c6 100644 --- a/ext/tokenizer/tokenizer.c +++ b/ext/tokenizer/tokenizer.c @@ -187,13 +187,13 @@ PHP_METHOD(PhpToken, is) RETURN_TRUE; } } else { - zend_argument_type_error(1, "must only have elements of type string|int, %s given", zend_zval_type_name(entry)); + zend_argument_type_error(1, "must only have elements of type string|int, %s given", zend_zval_value_name(entry)); RETURN_THROWS(); } } ZEND_HASH_FOREACH_END(); RETURN_FALSE; } else { - zend_argument_type_error(1, "must be of type string|int|array, %s given", zend_zval_type_name(kind)); + zend_argument_type_error(1, "must be of type string|int|array, %s given", zend_zval_value_name(kind)); RETURN_THROWS(); } } diff --git a/ext/xml/tests/bug72714.phpt b/ext/xml/tests/bug72714.phpt index 6c35ce3a879e4..e3436ba0eb55e 100644 --- a/ext/xml/tests/bug72714.phpt +++ b/ext/xml/tests/bug72714.phpt @@ -2,6 +2,10 @@ Bug #72714 (_xml_startElementHandler() segmentation fault) --EXTENSIONS-- xml +--SKIPIF-- + --FILE-- --EXPECTF-- -Warning: xml_parser_set_option(): tagstart ignored, because it is out of range in %s on line %d +Warning: xml_parser_set_option(): Argument #3 ($value) must be between 0 and 2147483647 for option XML_OPTION_SKIP_TAGSTART in %s on line %d string(9) "NS1:TOTAL" string(0) "" diff --git a/ext/xml/tests/xml_parser_get_option_variation3.phpt b/ext/xml/tests/xml_parser_get_option_variation3.phpt index 5412ed899f0a3..83720b6a01fc9 100644 --- a/ext/xml/tests/xml_parser_get_option_variation3.phpt +++ b/ext/xml/tests/xml_parser_get_option_variation3.phpt @@ -8,20 +8,26 @@ $parser = xml_parser_create(); echo "defaults:\n"; var_dump(xml_parser_get_option($parser, XML_OPTION_SKIP_TAGSTART)); var_dump(xml_parser_get_option($parser, XML_OPTION_SKIP_WHITE)); +var_dump(xml_parser_get_option($parser, XML_OPTION_CASE_FOLDING)); echo "setting:\n"; var_dump(xml_parser_set_option($parser, XML_OPTION_SKIP_TAGSTART, 7)); var_dump(xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1)); +var_dump(xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false)); echo "getting:\n"; var_dump(xml_parser_get_option($parser, XML_OPTION_SKIP_TAGSTART)); var_dump(xml_parser_get_option($parser, XML_OPTION_SKIP_WHITE)); +var_dump(xml_parser_get_option($parser, XML_OPTION_CASE_FOLDING)); ?> --EXPECT-- defaults: int(0) -int(0) +bool(false) +bool(true) setting: bool(true) bool(true) +bool(true) getting: int(7) -int(1) +bool(true) +bool(false) diff --git a/ext/xml/tests/xml_parser_get_option_variation4.phpt b/ext/xml/tests/xml_parser_get_option_variation4.phpt index 9c12f57544b66..f6d858a7e9c01 100644 --- a/ext/xml/tests/xml_parser_get_option_variation4.phpt +++ b/ext/xml/tests/xml_parser_get_option_variation4.phpt @@ -15,4 +15,4 @@ try { ?> --EXPECT-- -xml_parser_get_option(): Argument #2 ($option) must be a PHP_XML_OPTION_* constant +xml_parser_get_option(): Argument #2 ($option) must be a XML_OPTION_* constant diff --git a/ext/xml/tests/xml_parser_set_option_basic.phpt b/ext/xml/tests/xml_parser_set_option_basic.phpt index 0315ccbb29e74..2256775c93b9c 100644 --- a/ext/xml/tests/xml_parser_set_option_basic.phpt +++ b/ext/xml/tests/xml_parser_set_option_basic.phpt @@ -32,15 +32,15 @@ echo "Done\n"; ?> --EXPECT-- Simple testcase for xml_parser_get_option() function -int(1) +bool(true) string(5) "UTF-8" bool(true) bool(true) -int(1) +bool(true) string(10) "ISO-8859-1" bool(true) bool(true) -int(0) +bool(false) string(5) "UTF-8" bool(true) string(8) "US-ASCII" diff --git a/ext/xml/tests/xml_parser_set_option_errors.phpt b/ext/xml/tests/xml_parser_set_option_errors.phpt new file mode 100644 index 0000000000000..fbb733423d772 --- /dev/null +++ b/ext/xml/tests/xml_parser_set_option_errors.phpt @@ -0,0 +1,88 @@ +--TEST-- +xml_parser_set_option(): Setting options to invalid values +--EXTENSIONS-- +xml +--FILE-- +getMessage() . "\n"; +} +try { + xml_parser_set_option($xmlParser, XML_OPTION_CASE_FOLDING, new stdClass()); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +echo "Skip Whitespace\n"; +try { + xml_parser_set_option($xmlParser, XML_OPTION_SKIP_WHITE, []); +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} +try { + xml_parser_set_option($xmlParser, XML_OPTION_SKIP_WHITE, new stdClass()); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +echo "Tag Start\n"; +xml_parser_set_option($xmlParser, XML_OPTION_SKIP_TAGSTART, -5); + +xml_parser_set_option($xmlParser, XML_OPTION_SKIP_TAGSTART, []); + +xml_parser_set_option($xmlParser, XML_OPTION_SKIP_TAGSTART, new stdClass()); + +echo "Encodings\n"; +try { + xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, 'Invalid Encoding'); +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} +try { + xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, []); +} catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; +} +try { + xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, new stdClass()); +} catch (Error $exception) { + echo $exception::class, ': ', $exception->getMessage() . "\n"; +} + +?> +--EXPECTF-- +Case folding + +Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, array given in %s on line %d + +Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, stdClass given in %s on line %d +Skip Whitespace + +Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, array given in %s on line %d + +Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, stdClass given in %s on line %d +Tag Start + +Warning: xml_parser_set_option(): Argument #3 ($value) must be between 0 and 2147483647 for option XML_OPTION_SKIP_TAGSTART in %s on line %d + +Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, array given in %s on line %d + +Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, stdClass given in %s on line %d + +Warning: Object of class stdClass could not be converted to int in %s on line %d +Encodings +xml_parser_set_option(): Argument #3 ($value) is not a supported target encoding + +Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, array given in %s on line %d + +Warning: Array to string conversion in %s on line %d +xml_parser_set_option(): Argument #3 ($value) is not a supported target encoding + +Warning: xml_parser_set_option(): Argument #3 ($value) must be of type string|int|bool, stdClass given in %s on line %d +Error: Object of class stdClass could not be converted to string diff --git a/ext/xml/tests/xml_parser_set_option_variation5.phpt b/ext/xml/tests/xml_parser_set_option_nonexistent_option.phpt similarity index 62% rename from ext/xml/tests/xml_parser_set_option_variation5.phpt rename to ext/xml/tests/xml_parser_set_option_nonexistent_option.phpt index 382803ca1c74d..d19dc9e69d5c5 100644 --- a/ext/xml/tests/xml_parser_set_option_variation5.phpt +++ b/ext/xml/tests/xml_parser_set_option_nonexistent_option.phpt @@ -1,5 +1,5 @@ --TEST-- -xml_parser_set_option() - Test invalid parameter +xml_parser_set_option(): Non-existent option --EXTENSIONS-- xml --FILE-- @@ -15,4 +15,4 @@ try { ?> --EXPECT-- -xml_parser_set_option(): Argument #2 ($option) must be a PHP_XML_OPTION_* constant +xml_parser_set_option(): Argument #2 ($option) must be a XML_OPTION_* constant diff --git a/ext/xml/tests/xml_parser_set_option_variation4.phpt b/ext/xml/tests/xml_parser_set_option_variation4.phpt deleted file mode 100644 index 7db563d3760a3..0000000000000 --- a/ext/xml/tests/xml_parser_set_option_variation4.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -xml_parser_free - Test setting skip whitespace and invalid encoding type ---CREDITS-- -Mark Niebergall -PHP TestFest 2017 - UPHPU ---EXTENSIONS-- -xml ---FILE-- -getMessage() . "\n"; -} - -?> ---EXPECT-- -bool(true) -xml_parser_set_option(): Argument #3 ($value) is not a supported target encoding diff --git a/ext/xml/xml.c b/ext/xml/xml.c index d8985ed6e78bd..ef68c70af50f1 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -132,7 +132,7 @@ ZEND_GET_MODULE(xml) #define XML_MAXLEVEL 255 /* XXX this should be dynamic */ -#define SKIP_TAGSTART(str) ((str) + (parser->toffset > (int)strlen(str) ? strlen(str) : parser->toffset)) +#define SKIP_TAGSTART(str) ((str) + (parser->toffset > strlen(str) ? strlen(str) : parser->toffset)) static zend_class_entry *xml_parser_ce; static zend_object_handlers xml_parser_object_handlers; @@ -1392,37 +1392,51 @@ PHP_FUNCTION(xml_parser_free) PHP_FUNCTION(xml_parser_set_option) { xml_parser *parser; - zval *pind, *val; + zval *pind; zend_long opt; + zval *value; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olz", &pind, xml_parser_ce, &opt, &val) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olz", &pind, xml_parser_ce, &opt, &value) == FAILURE) { RETURN_THROWS(); } + if (Z_TYPE_P(value) != IS_FALSE && Z_TYPE_P(value) != IS_TRUE && + Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING) { + php_error_docref(NULL, E_WARNING, + "Argument #3 ($value) must be of type string|int|bool, %s given", zend_zval_type_name(value)); + } + parser = Z_XMLPARSER_P(pind); switch (opt) { + /* Boolean option */ case PHP_XML_OPTION_CASE_FOLDING: - parser->case_folding = zval_get_long(val); + parser->case_folding = zend_is_true(value); + break; + /* Boolean option */ + case PHP_XML_OPTION_SKIP_WHITE: + parser->skipwhite = zend_is_true(value); break; + /* Integer option */ case PHP_XML_OPTION_SKIP_TAGSTART: - parser->toffset = zval_get_long(val); + /* The tag start offset is stored in an int */ + /* TODO Improve handling of values? */ + parser->toffset = zval_get_long(value); if (parser->toffset < 0) { - php_error_docref(NULL, E_WARNING, "tagstart ignored, because it is out of range"); - parser->toffset = 0; /* TODO Promote to ValueError in PHP 9.0 */ + php_error_docref(NULL, E_WARNING, "Argument #3 ($value) must be between 0 and %d" + " for option XML_OPTION_SKIP_TAGSTART", INT_MAX); + parser->toffset = 0; RETURN_FALSE; } break; - case PHP_XML_OPTION_SKIP_WHITE: - parser->skipwhite = zval_get_long(val); - break; + /* String option */ case PHP_XML_OPTION_TARGET_ENCODING: { const xml_encoding *enc; - if (!try_convert_to_string(val)) { + if (!try_convert_to_string(value)) { RETURN_THROWS(); } - enc = xml_get_encoding((XML_Char*)Z_STRVAL_P(val)); + enc = xml_get_encoding((XML_Char*)Z_STRVAL_P(value)); if (enc == NULL) { zend_argument_value_error(3, "is not a supported target encoding"); RETURN_THROWS(); @@ -1432,7 +1446,7 @@ PHP_FUNCTION(xml_parser_set_option) break; } default: - zend_argument_value_error(2, "must be a PHP_XML_OPTION_* constant"); + zend_argument_value_error(2, "must be a XML_OPTION_* constant"); RETURN_THROWS(); break; } @@ -1455,19 +1469,19 @@ PHP_FUNCTION(xml_parser_get_option) parser = Z_XMLPARSER_P(pind); switch (opt) { case PHP_XML_OPTION_CASE_FOLDING: - RETURN_LONG(parser->case_folding); + RETURN_BOOL(parser->case_folding); break; case PHP_XML_OPTION_SKIP_TAGSTART: RETURN_LONG(parser->toffset); break; case PHP_XML_OPTION_SKIP_WHITE: - RETURN_LONG(parser->skipwhite); + RETURN_BOOL(parser->skipwhite); break; case PHP_XML_OPTION_TARGET_ENCODING: RETURN_STRING((char *)parser->target_encoding); break; default: - zend_argument_value_error(2, "must be a PHP_XML_OPTION_* constant"); + zend_argument_value_error(2, "must be a XML_OPTION_* constant"); RETURN_THROWS(); } } diff --git a/ext/xml/xml.stub.php b/ext/xml/xml.stub.php index e0b6386bf7705..89385675f4b25 100644 --- a/ext/xml/xml.stub.php +++ b/ext/xml/xml.stub.php @@ -197,11 +197,11 @@ function xml_get_current_byte_index(XMLParser $parser): int {} function xml_parser_free(XMLParser $parser): bool {} -/** @param string|int $value */ +/** @param string|int|bool $value */ function xml_parser_set_option(XMLParser $parser, int $option, $value): bool {} /** @refcount 1 */ -function xml_parser_get_option(XMLParser $parser, int $option): string|int {} +function xml_parser_get_option(XMLParser $parser, int $option): string|int|bool {} /** * @strict-properties diff --git a/ext/xml/xml_arginfo.h b/ext/xml/xml_arginfo.h index 53f7e6026cde4..abf34ac250180 100644 --- a/ext/xml/xml_arginfo.h +++ b/ext/xml/xml_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: fa0ee6afa65408c431e89e542dc8292737c4ff80 */ + * Stub hash: cd199a8733c51c8bb5970f86b7797ca91e6e59c6 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_xml_parser_create, 0, 0, XMLParser, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 1, "null") @@ -77,7 +77,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_xml_parser_set_option, 0, 3, _IS ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_xml_parser_get_option, 0, 2, MAY_BE_STRING|MAY_BE_LONG) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_xml_parser_get_option, 0, 2, MAY_BE_STRING|MAY_BE_LONG|MAY_BE_BOOL) ZEND_ARG_OBJ_INFO(0, parser, XMLParser, 0) ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) ZEND_END_ARG_INFO() diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index 76ca54d686359..8aeff33e4cea5 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -1016,7 +1016,7 @@ PHP_METHOD(XMLReader, XML) xmlreader_object *intern = NULL; char *source, *uri = NULL, *encoding = NULL; int resolved_path_len, ret = 0; - char *directory=NULL, resolved_path[MAXPATHLEN]; + char *directory=NULL, resolved_path[MAXPATHLEN + 1]; xmlParserInputBufferPtr inputbfr; xmlTextReaderPtr reader; diff --git a/ext/xmlwriter/php_xmlwriter.c b/ext/xmlwriter/php_xmlwriter.c index 5944abf30a98b..8fd5f1223d43d 100644 --- a/ext/xmlwriter/php_xmlwriter.c +++ b/ext/xmlwriter/php_xmlwriter.c @@ -215,14 +215,9 @@ static void php_xmlwriter_string_arg(INTERNAL_FUNCTION_PARAMETERS, xmlwriter_rea XMLW_NAME_CHK(2, subject_name); } - if (ptr) { - retval = internal_function(ptr, (xmlChar *) name); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = internal_function(ptr, (xmlChar *) name); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } static void php_xmlwriter_end(INTERNAL_FUNCTION_PARAMETERS, xmlwriter_read_int_t internal_function) @@ -236,14 +231,9 @@ static void php_xmlwriter_end(INTERNAL_FUNCTION_PARAMETERS, xmlwriter_read_int_t } XMLWRITER_FROM_OBJECT(ptr, self); - if (ptr) { - retval = internal_function(ptr); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = internal_function(ptr); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* {{{ Toggle indentation on/off - returns FALSE on error */ @@ -259,14 +249,9 @@ PHP_FUNCTION(xmlwriter_set_indent) } XMLWRITER_FROM_OBJECT(ptr, self); - if (ptr) { - retval = xmlTextWriterSetIndent(ptr, indent); - if (retval == 0) { - RETURN_TRUE; - } - } + retval = xmlTextWriterSetIndent(ptr, indent); - RETURN_FALSE; + RETURN_BOOL(retval == 0); } /* }}} */ @@ -308,14 +293,9 @@ PHP_FUNCTION(xmlwriter_start_attribute_ns) XMLW_NAME_CHK(3, "attribute name"); - if (ptr) { - retval = xmlTextWriterStartAttributeNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterStartAttributeNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -336,14 +316,9 @@ PHP_FUNCTION(xmlwriter_write_attribute) XMLW_NAME_CHK(2, "attribute name"); - if (ptr) { - retval = xmlTextWriterWriteAttribute(ptr, (xmlChar *)name, (xmlChar *)content); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterWriteAttribute(ptr, (xmlChar *)name, (xmlChar *)content); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -364,14 +339,9 @@ PHP_FUNCTION(xmlwriter_write_attribute_ns) XMLW_NAME_CHK(3, "attribute name"); - if (ptr) { - retval = xmlTextWriterWriteAttributeNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri, (xmlChar *)content); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterWriteAttributeNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri, (xmlChar *)content); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -399,15 +369,9 @@ PHP_FUNCTION(xmlwriter_start_element_ns) XMLW_NAME_CHK(3, "element name"); - if (ptr) { - retval = xmlTextWriterStartElementNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri); - if (retval != -1) { - RETURN_TRUE; - } - - } + retval = xmlTextWriterStartElementNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -442,25 +406,17 @@ PHP_FUNCTION(xmlwriter_write_element) XMLW_NAME_CHK(2, "element name"); - if (ptr) { - if (!content) { - retval = xmlTextWriterStartElement(ptr, (xmlChar *)name); - if (retval == -1) { - RETURN_FALSE; - } - xmlTextWriterEndElement(ptr); - if (retval == -1) { - RETURN_FALSE; - } - } else { - retval = xmlTextWriterWriteElement(ptr, (xmlChar *)name, (xmlChar *)content); - } - if (retval != -1) { - RETURN_TRUE; + if (!content) { + retval = xmlTextWriterStartElement(ptr, (xmlChar *)name); + if (retval == -1) { + RETURN_FALSE; } + retval = xmlTextWriterEndElement(ptr); + } else { + retval = xmlTextWriterWriteElement(ptr, (xmlChar *)name, (xmlChar *)content); } - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -481,25 +437,17 @@ PHP_FUNCTION(xmlwriter_write_element_ns) XMLW_NAME_CHK(3, "element name"); - if (ptr) { - if (!content) { - retval = xmlTextWriterStartElementNS(ptr,(xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri); - if (retval == -1) { - RETURN_FALSE; - } - retval = xmlTextWriterEndElement(ptr); - if (retval == -1) { - RETURN_FALSE; - } - } else { - retval = xmlTextWriterWriteElementNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri, (xmlChar *)content); - } - if (retval != -1) { - RETURN_TRUE; + if (!content) { + retval = xmlTextWriterStartElementNS(ptr,(xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri); + if (retval == -1) { + RETURN_FALSE; } + retval = xmlTextWriterEndElement(ptr); + } else { + retval = xmlTextWriterWriteElementNS(ptr, (xmlChar *)prefix, (xmlChar *)name, (xmlChar *)uri, (xmlChar *)content); } - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -534,14 +482,9 @@ PHP_FUNCTION(xmlwriter_write_pi) XMLW_NAME_CHK(2, "PI target"); - if (ptr) { - retval = xmlTextWriterWritePI(ptr, (xmlChar *)name, (xmlChar *)content); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterWritePI(ptr, (xmlChar *)name, (xmlChar *)content); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -557,14 +500,9 @@ PHP_FUNCTION(xmlwriter_start_cdata) } XMLWRITER_FROM_OBJECT(ptr, self); - if (ptr) { - retval = xmlTextWriterStartCDATA(ptr); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterStartCDATA(ptr); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -608,14 +546,9 @@ PHP_FUNCTION(xmlwriter_start_comment) } XMLWRITER_FROM_OBJECT(ptr, self); - if (ptr) { - retval = xmlTextWriterStartComment(ptr); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterStartComment(ptr); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -647,14 +580,9 @@ PHP_FUNCTION(xmlwriter_start_document) } XMLWRITER_FROM_OBJECT(ptr, self); - if (ptr) { - retval = xmlTextWriterStartDocument(ptr, version, enc, alone); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterStartDocument(ptr, version, enc, alone); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -679,14 +607,9 @@ PHP_FUNCTION(xmlwriter_start_dtd) } XMLWRITER_FROM_OBJECT(ptr, self); - if (ptr) { - retval = xmlTextWriterStartDTD(ptr, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterStartDTD(ptr, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -711,14 +634,9 @@ PHP_FUNCTION(xmlwriter_write_dtd) } XMLWRITER_FROM_OBJECT(ptr, self); - if (ptr) { - retval = xmlTextWriterWriteDTD(ptr, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid, (xmlChar *)subset); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterWriteDTD(ptr, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid, (xmlChar *)subset); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -753,14 +671,9 @@ PHP_FUNCTION(xmlwriter_write_dtd_element) XMLW_NAME_CHK(2, "element name"); - if (ptr) { - retval = xmlTextWriterWriteDTDElement(ptr, (xmlChar *)name, (xmlChar *)content); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterWriteDTDElement(ptr, (xmlChar *)name, (xmlChar *)content); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -795,14 +708,9 @@ PHP_FUNCTION(xmlwriter_write_dtd_attlist) XMLW_NAME_CHK(2, "element name"); - if (ptr) { - retval = xmlTextWriterWriteDTDAttlist(ptr, (xmlChar *)name, (xmlChar *)content); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterWriteDTDAttlist(ptr, (xmlChar *)name, (xmlChar *)content); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -823,14 +731,9 @@ PHP_FUNCTION(xmlwriter_start_dtd_entity) XMLW_NAME_CHK(2, "attribute name"); - if (ptr) { - retval = xmlTextWriterStartDTDEntity(ptr, isparm, (xmlChar *)name); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterStartDTDEntity(ptr, isparm, (xmlChar *)name); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -863,14 +766,9 @@ PHP_FUNCTION(xmlwriter_write_dtd_entity) XMLW_NAME_CHK(2, "element name"); - if (ptr) { - retval = xmlTextWriterWriteDTDEntity(ptr, pe, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid, (xmlChar *)ndataid, (xmlChar *)content); - if (retval != -1) { - RETURN_TRUE; - } - } + retval = xmlTextWriterWriteDTDEntity(ptr, pe, (xmlChar *)name, (xmlChar *)pubid, (xmlChar *)sysid, (xmlChar *)ndataid, (xmlChar *)content); - RETURN_FALSE; + RETURN_BOOL(retval != -1); } /* }}} */ @@ -993,24 +891,19 @@ static void php_xmlwriter_flush(INTERNAL_FUNCTION_PARAMETERS, int force_string) } XMLWRITER_FROM_OBJECT(ptr, self); - if (ptr) { - buffer = Z_XMLWRITER_P(self)->output; - if (force_string == 1 && buffer == NULL) { - RETURN_EMPTY_STRING(); - } - output_bytes = xmlTextWriterFlush(ptr); - if (buffer) { - RETVAL_STRING((char *) buffer->content); - if (empty) { - xmlBufferEmpty(buffer); - } - } else { - RETVAL_LONG(output_bytes); + buffer = Z_XMLWRITER_P(self)->output; + if (force_string == 1 && buffer == NULL) { + RETURN_EMPTY_STRING(); + } + output_bytes = xmlTextWriterFlush(ptr); + if (buffer) { + RETVAL_STRING((char *) buffer->content); + if (empty) { + xmlBufferEmpty(buffer); } - return; + } else { + RETVAL_LONG(output_bytes); } - - RETURN_EMPTY_STRING(); } /* }}} */ diff --git a/ext/xsl/tests/bug69168.phpt b/ext/xsl/tests/bug69168.phpt new file mode 100644 index 0000000000000..41fc3aafd8209 --- /dev/null +++ b/ext/xsl/tests/bug69168.phpt @@ -0,0 +1,43 @@ +--TEST-- +bug #69168 (DomNode::getNodePath() returns invalid path) +--EXTENSIONS-- +xsl +--FILE-- +bobjoe +EOB; +$xsl = << + + + +
+
+
+
+EOB; + +function getPath($input){ + $input[0]->nodeValue .= 'a'; + return $input[0]->getNodePath() . ' = ' . $input[0]->nodeValue; +} + +$proc = new XSLTProcessor(); +$proc->registerPHPFunctions(); +$xslDoc = new DOMDocument(); +$xslDoc->loadXML($xsl); +@$proc->importStyleSheet($xslDoc); +$xmlDoc = new DOMDocument(); +$xmlDoc->loadXML($xml); +echo @$proc->transformToXML($xmlDoc); + +// Tests modification of the nodes +var_dump($xmlDoc->firstChild->firstChild->firstChild->getNodePath()); +var_dump($xmlDoc->firstChild->firstChild->firstChild->nodeValue); +?> +--EXPECT-- + +/allusers/user[1]/uid = boba
/allusers/user[2]/uid = joea
+string(21) "/allusers/user[1]/uid" +string(4) "boba" diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index c62c0a13ceaec..7f3d1e0e42170 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -194,7 +194,19 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t node->parent = nsparent; node->ns = curns; } else { - node = xmlDocCopyNode(node, domintern->document->ptr, 1); + /** + * Upon freeing libxslt's context, every document which is not the *main* document will be freed by libxslt. + * If a node of a document which is *not the main* document gets returned to userland, we'd free the node twice: + * first by the cleanup of the xslt context, and then by our own refcounting mechanism. + * To prevent this, we'll take a copy if the node is not from the main document. + * It is important that we do not copy the node unconditionally, because that means that: + * - modifications to the node will only modify the copy, and not the original + * - accesses to the parent, path, ... will not work + */ + xsltTransformContextPtr transform_ctxt = (xsltTransformContextPtr) ctxt->context->extra; + if (node->doc != transform_ctxt->document->doc) { + node = xmlDocCopyNode(node, domintern->document->ptr, 1); + } } php_dom_create_object(node, &child, domintern); @@ -347,7 +359,7 @@ PHP_METHOD(XSLTProcessor, importStylesheet) intern = Z_XSL_P(id); - member = zend_string_init("cloneDocument", sizeof("cloneDocument")-1, 0); + member = ZSTR_INIT_LITERAL("cloneDocument", 0); cloneDocu = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_IS, NULL, &rv); if (Z_TYPE_P(cloneDocu) != IS_NULL) { convert_to_long(cloneDocu); @@ -448,7 +460,7 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl ctxt = xsltNewTransformContext(style, doc); ctxt->_private = (void *) intern; - member = zend_string_init("doXInclude", sizeof("doXInclude")-1, 0); + member = ZSTR_INIT_LITERAL("doXInclude", 0); doXInclude = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_IS, NULL, &rv); if (Z_TYPE_P(doXInclude) != IS_NULL) { convert_to_long(doXInclude); diff --git a/ext/zend_test/fiber.c b/ext/zend_test/fiber.c index f67c0217d050f..428ecc0682dac 100644 --- a/ext/zend_test/fiber.c +++ b/ext/zend_test/fiber.c @@ -95,6 +95,10 @@ static ZEND_STACK_ALIGNED void zend_test_fiber_execute(zend_fiber_transfer *tran EG(current_execute_data) = execute_data; EG(jit_trace_num) = 0; +#ifdef ZEND_CHECK_STACK_LIMIT + EG(stack_base) = zend_fiber_stack_base(fiber->context.stack); + EG(stack_limit) = zend_fiber_stack_limit(fiber->context.stack); +#endif fiber->fci.retval = &retval; zend_call_function(&fiber->fci, &fiber->fci_cache); diff --git a/ext/zend_test/observer.c b/ext/zend_test/observer.c index e6be124b44458..3e870de450a5a 100644 --- a/ext/zend_test/observer.c +++ b/ext/zend_test/observer.c @@ -39,7 +39,7 @@ static void observer_set_user_opcode_handler(const char *opcode_names, user_opco while (1) { if (*e == ' ' || *e == ',' || *e == '\0') { if (s) { - zend_uchar opcode = zend_get_opcode_id(s, e - s); + uint8_t opcode = zend_get_opcode_id(s, e - s); if (opcode <= ZEND_VM_LAST_OPCODE) { zend_set_user_opcode_handler(opcode, handler); } else { @@ -268,6 +268,27 @@ void declared_class_observer(zend_class_entry *ce, zend_string *name) { } } +static void (*zend_test_prev_execute_internal)(zend_execute_data *execute_data, zval *return_value); +static void zend_test_execute_internal(zend_execute_data *execute_data, zval *return_value) { + zend_function *fbc = execute_data->func; + + if (fbc->common.function_name) { + if (fbc->common.scope) { + php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); + } else { + php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->common.function_name)); + } + } else { + php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->op_array.filename)); + } + + if (zend_test_prev_execute_internal) { + zend_test_prev_execute_internal(execute_data, return_value); + } else { + fbc->internal_function.handler(execute_data, return_value); + } +} + static ZEND_INI_MH(zend_test_observer_OnUpdateCommaList) { zend_array **p = (zend_array **) ZEND_INI_GET_ADDR(); @@ -323,6 +344,7 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_init", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_init, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_switch", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_switch, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_destroy", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_destroy, zend_zend_test_globals, zend_test_globals) + STD_PHP_INI_BOOLEAN("zend_test.observer.execute_internal", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_execute_internal, zend_zend_test_globals, zend_test_globals) PHP_INI_END() void zend_test_observer_init(INIT_FUNC_ARGS) @@ -351,6 +373,11 @@ void zend_test_observer_init(INIT_FUNC_ARGS) zend_observer_function_declared_register(declared_function_observer); zend_observer_class_linked_register(declared_class_observer); } + + if (ZT_G(observer_execute_internal)) { + zend_test_prev_execute_internal = zend_execute_internal; + zend_execute_internal = zend_test_execute_internal; + } } void zend_test_observer_shutdown(SHUTDOWN_FUNC_ARGS) diff --git a/ext/zend_test/php_test.h b/ext/zend_test/php_test.h index a5b11a6041dd6..24895f11df4b3 100644 --- a/ext/zend_test/php_test.h +++ b/ext/zend_test/php_test.h @@ -49,10 +49,12 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test) int observer_fiber_init; int observer_fiber_switch; int observer_fiber_destroy; + int observer_execute_internal; HashTable global_weakmap; int replace_zend_execute_ex; int register_passes; bool print_stderr_mshutdown; + zend_long limit_copy_file_range; zend_test_fiber *active_fiber; zend_long quantity_value; zend_string *str_test; diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index afba5a3614efd..55ff614a51ace 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -30,6 +30,7 @@ #include "zend_weakrefs.h" #include "Zend/Optimizer/zend_optimizer.h" #include "test_arginfo.h" +#include "zend_call_stack.h" ZEND_DECLARE_MODULE_GLOBALS(zend_test) @@ -367,7 +368,7 @@ static ZEND_FUNCTION(zend_call_method) return; } } else { - zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(class_or_object)); + zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_value_name(class_or_object)); return; } @@ -423,6 +424,17 @@ static ZEND_FUNCTION(zend_test_zend_ini_str) RETURN_STR(ZT_G(str_test)); } +static ZEND_FUNCTION(zend_test_is_string_marked_as_valid_utf8) +{ + zend_string *str; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + RETURN_BOOL(ZSTR_IS_VALID_UTF8(str)); +} + static ZEND_FUNCTION(ZendTestNS2_namespaced_func) { ZEND_PARSE_PARAMETERS_NONE(); @@ -456,6 +468,111 @@ static ZEND_FUNCTION(zend_test_parameter_with_attribute) RETURN_LONG(1); } +#ifdef ZEND_CHECK_STACK_LIMIT +static ZEND_FUNCTION(zend_test_zend_call_stack_get) +{ + zend_call_stack stack; + + ZEND_PARSE_PARAMETERS_NONE(); + + if (zend_call_stack_get(&stack)) { + zend_string *str; + + array_init(return_value); + + str = strpprintf(0, "%p", stack.base); + add_assoc_str(return_value, "base", str); + + str = strpprintf(0, "0x%zx", stack.max_size); + add_assoc_str(return_value, "max_size", str); + + str = strpprintf(0, "%p", zend_call_stack_position()); + add_assoc_str(return_value, "position", str); + + str = strpprintf(0, "%p", EG(stack_limit)); + add_assoc_str(return_value, "EG(stack_limit)", str); + + return; + } + + RETURN_NULL(); +} + +zend_long (*volatile zend_call_stack_use_all_fun)(void *limit); + +static zend_long zend_call_stack_use_all(void *limit) +{ + if (zend_call_stack_overflowed(limit)) { + return 1; + } + + return 1 + zend_call_stack_use_all_fun(limit); +} + +static ZEND_FUNCTION(zend_test_zend_call_stack_use_all) +{ + zend_call_stack stack; + + ZEND_PARSE_PARAMETERS_NONE(); + + if (!zend_call_stack_get(&stack)) { + return; + } + + zend_call_stack_use_all_fun = zend_call_stack_use_all; + + void *limit = zend_call_stack_limit(stack.base, stack.max_size, 4096); + + RETURN_LONG(zend_call_stack_use_all(limit)); +} +#endif /* ZEND_CHECK_STACK_LIMIT */ + +static ZEND_FUNCTION(zend_get_map_ptr_last) +{ + ZEND_PARSE_PARAMETERS_NONE(); + RETURN_LONG(CG(map_ptr_last)); +} + +static ZEND_FUNCTION(zend_test_crash) +{ + zend_string *message = NULL; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_NULL(message) + ZEND_PARSE_PARAMETERS_END(); + + if (message) { + php_printf("%s", ZSTR_VAL(message)); + } + + char *invalid = (char *) 1; + php_printf("%s", invalid); +} + +static ZEND_FUNCTION(zend_test_fill_packed_array) +{ + HashTable *parameter; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT_EX(parameter, 0, 1) + ZEND_PARSE_PARAMETERS_END(); + + if (!HT_IS_PACKED(parameter)) { + zend_argument_value_error(1, "must be a packed array"); + RETURN_THROWS(); + } + + zend_hash_extend(parameter, parameter->nNumUsed + 10, true); + ZEND_HASH_FILL_PACKED(parameter) { + for (int i = 0; i < 10; i++) { + zval value; + ZVAL_LONG(&value, i); + ZEND_HASH_FILL_ADD(&value); + } + } ZEND_HASH_FILL_END(); +} + static zend_object *zend_test_class_new(zend_class_entry *class_type) { zend_object *obj = zend_objects_new(class_type); @@ -541,6 +658,31 @@ static ZEND_METHOD(_ZendTestClass, returnsThrowable) zend_throw_error(NULL, "Dummy"); } +static ZEND_METHOD(_ZendTestClass, variadicTest) { + int argc, i; + zval *args = NULL; + + ZEND_PARSE_PARAMETERS_START(0, -1) + Z_PARAM_VARIADIC('*', args, argc) + ZEND_PARSE_PARAMETERS_END(); + + for (i = 0; i < argc; i++) { + zval *arg = args + i; + + if (Z_TYPE_P(arg) == IS_STRING) { + continue; + } + if (Z_TYPE_P(arg) == IS_OBJECT && instanceof_function(Z_OBJ_P(arg)->ce, zend_ce_iterator)) { + continue; + } + + zend_argument_type_error(i + 1, "must be of class Iterator or a string, %s given", zend_zval_type_name(arg)); + RETURN_THROWS(); + } + + object_init_ex(return_value, zend_get_called_scope(execute_data)); +} + static ZEND_METHOD(_ZendTestChildClass, returnsThrowable) { ZEND_PARSE_PARAMETERS_NONE(); @@ -646,10 +788,117 @@ static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic) zend_forbid_dynamic_call(); } +/* donc refers to DoOperationNoCast */ +static zend_class_entry *donc_ce; +static zend_object_handlers donc_object_handlers; + +static zend_object* donc_object_create_ex(zend_class_entry* ce, zend_long l) { + zend_object *obj = zend_objects_new(ce); + object_properties_init(obj, ce); + obj->handlers = &donc_object_handlers; + ZVAL_LONG(OBJ_PROP_NUM(obj, 0), l); + return obj; +} +static zend_object *donc_object_create(zend_class_entry *ce) /* {{{ */ +{ + return donc_object_create_ex(ce, 0); +} +/* }}} */ + +static inline void donc_create(zval *target, zend_long l) /* {{{ */ +{ + ZVAL_OBJ(target, donc_object_create_ex(donc_ce, l)); +} + +#define IS_DONC(zval) \ + (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), donc_ce)) + +static void donc_add(zval *result, zval *op1, zval *op2) +{ + zend_long val_1; + zend_long val_2; + if (IS_DONC(op1)) { + val_1 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op1), 0)); + } else { + val_1 = zval_get_long(op1); + } + if (IS_DONC(op2)) { + val_2 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op2), 0)); + } else { + val_2 = zval_get_long(op2); + } + + donc_create(result, val_1 + val_2); +} +static void donc_mul(zval *result, zval *op1, zval *op2) +{ + zend_long val_1; + zend_long val_2; + if (IS_DONC(op1)) { + val_1 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op1), 0)); + } else { + val_1 = zval_get_long(op1); + } + if (IS_DONC(op2)) { + val_2 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op2), 0)); + } else { + val_2 = zval_get_long(op2); + } + + donc_create(result, val_1 * val_2); +} + +static zend_result donc_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2) +{ + zval op1_copy; + zend_result status; + + if (result == op1) { + ZVAL_COPY_VALUE(&op1_copy, op1); + op1 = &op1_copy; + } + + switch (opcode) { + case ZEND_ADD: + donc_add(result, op1, op2); + if (UNEXPECTED(EG(exception))) { status = FAILURE; } + status = SUCCESS; + break; + case ZEND_MUL: + donc_mul(result, op1, op2); + if (UNEXPECTED(EG(exception))) { status = FAILURE; } + status = SUCCESS; + break; + default: + status = FAILURE; + break; + } + + if (status == SUCCESS && op1 == &op1_copy) { + zval_ptr_dtor(op1); + } + + return status; +} + +PHP_METHOD(DoOperationNoCast, __construct) +{ + zend_long l; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(l) + ZEND_PARSE_PARAMETERS_END(); + + ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), l); +} + PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.print_stderr_mshutdown", "0", PHP_INI_SYSTEM, OnUpdateBool, print_stderr_mshutdown, zend_zend_test_globals, zend_test_globals) +#ifdef HAVE_COPY_FILE_RANGE + STD_PHP_INI_ENTRY("zend_test.limit_copy_file_range", "-1", PHP_INI_ALL, OnUpdateLong, limit_copy_file_range, zend_zend_test_globals, zend_test_globals) +#endif STD_PHP_INI_ENTRY("zend_test.quantity_value", "0", PHP_INI_ALL, OnUpdateLong, quantity_value, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_ENTRY("zend_test.str_test", "", PHP_INI_ALL, OnUpdateStr, str_test, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_ENTRY("zend_test.not_empty_str_test", "val", PHP_INI_ALL, OnUpdateStrNotEmpty, not_empty_str_test, zend_zend_test_globals, zend_test_globals) @@ -687,61 +936,12 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_parameter_attribute = register_class_ZendTestParameterAttribute(); zend_mark_internal_attribute(zend_test_parameter_attribute); - { - zend_attribute *attr; - - attr = zend_add_parameter_attribute( - zend_hash_str_find_ptr(CG(function_table), "zend_test_parameter_with_attribute", sizeof("zend_test_parameter_with_attribute") - 1), - 0, - zend_test_parameter_attribute->name, - 1 - ); - - ZVAL_PSTRING(&attr->args[0].value, "value1"); - } - zend_test_property_attribute = register_class_ZendTestPropertyAttribute(); zend_mark_internal_attribute(zend_test_property_attribute); zend_test_class_with_method_with_parameter_attribute = register_class_ZendTestClassWithMethodWithParameterAttribute(); - - { - zend_attribute *attr; - - attr = zend_add_parameter_attribute( - zend_hash_str_find_ptr(&zend_test_class_with_method_with_parameter_attribute->function_table, "no_override", sizeof("no_override") - 1), - 0, - zend_test_parameter_attribute->name, - 1 - ); - - ZVAL_PSTRING(&attr->args[0].value, "value2"); - - attr = zend_add_parameter_attribute( - zend_hash_str_find_ptr(&zend_test_class_with_method_with_parameter_attribute->function_table, "override", sizeof("override") - 1), - 0, - zend_test_parameter_attribute->name, - 1 - ); - - ZVAL_PSTRING(&attr->args[0].value, "value3"); - } - zend_test_child_class_with_method_with_parameter_attribute = register_class_ZendTestChildClassWithMethodWithParameterAttribute(zend_test_class_with_method_with_parameter_attribute); - { - zend_attribute *attr; - - attr = zend_add_parameter_attribute( - zend_hash_str_find_ptr(&zend_test_child_class_with_method_with_parameter_attribute->function_table, "override", sizeof("override") - 1), - 0, - zend_test_parameter_attribute->name, - 1 - ); - - ZVAL_PSTRING(&attr->args[0].value, "value4"); - } - zend_test_forbid_dynamic_call = register_class_ZendTestForbidDynamicCall(); zend_test_ns_foo_class = register_class_ZendTestNS_Foo(); @@ -753,6 +953,12 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_string_enum = register_class_ZendTestStringEnum(); zend_test_int_enum = register_class_ZendTestIntEnum(); + /* DoOperationNoCast class */ + donc_ce = register_class_DoOperationNoCast(); + donc_ce->create_object = donc_object_create; + memcpy(&donc_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + donc_object_handlers.do_operation = donc_do_operation; + zend_register_functions(NULL, ext_function_legacy, NULL, EG(current_module)->type); // Loading via dl() not supported with the observer API @@ -930,3 +1136,17 @@ PHP_ZEND_TEST_API void bug_gh9090_void_int_char_var(int i, char *fmt, ...) { va_end(args); } + +#ifdef HAVE_COPY_FILE_RANGE +/** + * This function allows us to simulate early return of copy_file_range by setting the limit_copy_file_range ini setting. + */ +PHP_ZEND_TEST_API ssize_t copy_file_range(int fd_in, off64_t *off_in, int fd_out, off64_t *off_out, size_t len, unsigned int flags) +{ + ssize_t (*original_copy_file_range)(int, off64_t *, int, off64_t *, size_t, unsigned int) = dlsym(RTLD_NEXT, "copy_file_range"); + if (ZT_G(limit_copy_file_range) >= Z_L(0)) { + len = ZT_G(limit_copy_file_range); + } + return original_copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); +} +#endif diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index a0a042a8297df..30980cf7045f1 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -6,13 +6,16 @@ * @undocumentable */ namespace { + require "Zend/zend_attributes.stub.php"; + /** * @var int * @deprecated */ const ZEND_TEST_DEPRECATED = 42; - require "Zend/zend_attributes.stub.php"; + /** @var string */ + const ZEND_CONSTANT_A = "global"; interface _ZendTestInterface { @@ -40,6 +43,8 @@ public function __toString(): string {} public function returnsStatic(): static {} public function returnsThrowable(): Throwable {} + + static public function variadicTest(string|Iterator ...$elements) : static {} } class _ZendTestChildClass extends _ZendTestClass @@ -74,12 +79,21 @@ public function __construct(string $parameter) {} } class ZendTestClassWithMethodWithParameterAttribute { - final public function no_override(string $parameter): int {} - public function override(string $parameter): int {} + final public function no_override( + #[ZendTestParameterAttribute("value2")] + string $parameter + ): int {} + public function override( + #[ZendTestParameterAttribute("value3")] + string $parameter + ): int {} } class ZendTestChildClassWithMethodWithParameterAttribute extends ZendTestClassWithMethodWithParameterAttribute { - public function override(string $parameter): int {} + public function override( + #[ZendTestParameterAttribute("value4")] + string $parameter + ): int {} } final class ZendTestForbidDynamicCall { @@ -105,9 +119,14 @@ enum ZendTestIntEnum: int { case Baz = -1; } + final class DoOperationNoCast { + private int $val; + public function __construct(int $val) {} + } + function zend_test_array_return(): array {} - function zend_test_nullable_array_return(): ?array {} + function zend_test_nullable_array_return(): null|array {} function zend_test_void_return(): void {} @@ -151,7 +170,10 @@ function zend_weakmap_dump(): array {} function zend_get_unit_enum(): ZendTestUnitEnum {} - function zend_test_parameter_with_attribute(string $parameter): int {} + function zend_test_parameter_with_attribute( + #[ZendTestParameterAttribute("value1")] + string $parameter + ): int {} function zend_get_current_func_name(): string {} @@ -161,6 +183,19 @@ function zend_test_zend_ini_parse_quantity(string $str): int {} function zend_test_zend_ini_parse_uquantity(string $str): int {} function zend_test_zend_ini_str(): string {} + +#ifdef ZEND_CHECK_STACK_LIMIT + function zend_test_zend_call_stack_get(): ?array {} + function zend_test_zend_call_stack_use_all(): int {} +#endif + + function zend_test_is_string_marked_as_valid_utf8(string $string): bool {} + + function zend_get_map_ptr_last(): int {} + + function zend_test_crash(?string $message = null): void {} + + function zend_test_fill_packed_array(array &$array): void {} } namespace ZendTestNS { @@ -180,6 +215,9 @@ public function method(): ?UnlikelyCompileError {} namespace ZendTestNS2 { + /** @var string */ + const ZEND_CONSTANT_A = "namespaced"; + class Foo { public ZendSubNS\Foo $foo; @@ -203,6 +241,9 @@ function namespaced_deprecated_aliased_func(): void {} namespace ZendTestNS2\ZendSubNS { + /** @var string */ + const ZEND_CONSTANT_A = \ZendTestNS2\ZEND_CONSTANT_A; + class Foo { public function method(): void {} } diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 14e9c29bd103d..6a01f6cd0169e 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 786b35a1fbff38215431d5ae46a5816c70defce5 */ + * Stub hash: eb6dd9bae381ca8163307e8a0f54bf3983b79cb5 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -97,6 +97,31 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_zend_ini_str arginfo_zend_get_current_func_name +#if defined(ZEND_CHECK_STACK_LIMIT) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_zend_call_stack_get, 0, 0, IS_ARRAY, 1) +ZEND_END_ARG_INFO() +#endif + +#if defined(ZEND_CHECK_STACK_LIMIT) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_zend_call_stack_use_all, 0, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() +#endif + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_is_string_marked_as_valid_utf8, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_get_map_ptr_last, 0, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_crash, 0, 0, IS_VOID, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_fill_packed_array, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(1, array, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_namespaced_func, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -114,8 +139,7 @@ ZEND_END_ARG_INFO() #define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_aliased_func arginfo_zend_test_void_return -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_is_object, 0, 0, IS_LONG, 0) -ZEND_END_ARG_INFO() +#define arginfo_class__ZendTestClass_is_object arginfo_zend_get_map_ptr_last #define arginfo_class__ZendTestClass___toString arginfo_zend_get_current_func_name @@ -125,6 +149,10 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestClass_returnsThrowable, 0, 0, Throwable, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_variadicTest, 0, 0, IS_STATIC, 0) + ZEND_ARG_VARIADIC_OBJ_TYPE_MASK(0, elements, Iterator, MAY_BE_STRING) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestChildClass_returnsThrowable, 0, 0, Exception, 0) ZEND_END_ARG_INFO() @@ -146,6 +174,10 @@ ZEND_END_ARG_INFO() #define arginfo_class_ZendTestForbidDynamicCall_callStatic arginfo_zend_test_void_return +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DoOperationNoCast___construct, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, val, IS_LONG, 0) +ZEND_END_ARG_INFO() + #if (PHP_VERSION_ID >= 80100) ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ZendTestNS_Foo_method, 0, 0, IS_LONG, 0) #else @@ -185,6 +217,16 @@ static ZEND_FUNCTION(zend_call_method); static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity); static ZEND_FUNCTION(zend_test_zend_ini_parse_uquantity); static ZEND_FUNCTION(zend_test_zend_ini_str); +#if defined(ZEND_CHECK_STACK_LIMIT) +static ZEND_FUNCTION(zend_test_zend_call_stack_get); +#endif +#if defined(ZEND_CHECK_STACK_LIMIT) +static ZEND_FUNCTION(zend_test_zend_call_stack_use_all); +#endif +static ZEND_FUNCTION(zend_test_is_string_marked_as_valid_utf8); +static ZEND_FUNCTION(zend_get_map_ptr_last); +static ZEND_FUNCTION(zend_test_crash); +static ZEND_FUNCTION(zend_test_fill_packed_array); static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -193,6 +235,7 @@ static ZEND_METHOD(_ZendTestClass, is_object); static ZEND_METHOD(_ZendTestClass, __toString); static ZEND_METHOD(_ZendTestClass, returnsStatic); static ZEND_METHOD(_ZendTestClass, returnsThrowable); +static ZEND_METHOD(_ZendTestClass, variadicTest); static ZEND_METHOD(_ZendTestChildClass, returnsThrowable); static ZEND_METHOD(_ZendTestTrait, testMethod); static ZEND_METHOD(ZendTestParameterAttribute, __construct); @@ -202,6 +245,7 @@ static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, override); static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override); static ZEND_METHOD(ZendTestForbidDynamicCall, call); static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic); +static ZEND_METHOD(DoOperationNoCast, __construct); static ZEND_METHOD(ZendTestNS_Foo, method); static ZEND_METHOD(ZendTestNS_UnlikelyCompileError, method); static ZEND_METHOD(ZendTestNS2_Foo, method); @@ -235,6 +279,16 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_zend_ini_parse_quantity, arginfo_zend_test_zend_ini_parse_quantity) ZEND_FE(zend_test_zend_ini_parse_uquantity, arginfo_zend_test_zend_ini_parse_uquantity) ZEND_FE(zend_test_zend_ini_str, arginfo_zend_test_zend_ini_str) +#if defined(ZEND_CHECK_STACK_LIMIT) + ZEND_FE(zend_test_zend_call_stack_get, arginfo_zend_test_zend_call_stack_get) +#endif +#if defined(ZEND_CHECK_STACK_LIMIT) + ZEND_FE(zend_test_zend_call_stack_use_all, arginfo_zend_test_zend_call_stack_use_all) +#endif + ZEND_FE(zend_test_is_string_marked_as_valid_utf8, arginfo_zend_test_is_string_marked_as_valid_utf8) + ZEND_FE(zend_get_map_ptr_last, arginfo_zend_get_map_ptr_last) + ZEND_FE(zend_test_crash, arginfo_zend_test_crash) + ZEND_FE(zend_test_fill_packed_array, arginfo_zend_test_fill_packed_array) ZEND_NS_FALIAS("ZendTestNS2", namespaced_func, ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func) ZEND_NS_DEP_FALIAS("ZendTestNS2", namespaced_deprecated_func, ZendTestNS2_namespaced_deprecated_func, arginfo_ZendTestNS2_namespaced_deprecated_func) ZEND_NS_FALIAS("ZendTestNS2", namespaced_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_namespaced_aliased_func) @@ -257,6 +311,7 @@ static const zend_function_entry class__ZendTestClass_methods[] = { ZEND_ME(_ZendTestClass, __toString, arginfo_class__ZendTestClass___toString, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) ZEND_ME(_ZendTestClass, returnsStatic, arginfo_class__ZendTestClass_returnsStatic, ZEND_ACC_PUBLIC) ZEND_ME(_ZendTestClass, returnsThrowable, arginfo_class__ZendTestClass_returnsThrowable, ZEND_ACC_PUBLIC) + ZEND_ME(_ZendTestClass, variadicTest, arginfo_class__ZendTestClass_variadicTest, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_FE_END }; @@ -325,6 +380,12 @@ static const zend_function_entry class_ZendTestIntEnum_methods[] = { }; +static const zend_function_entry class_DoOperationNoCast_methods[] = { + ZEND_ME(DoOperationNoCast, __construct, arginfo_class_DoOperationNoCast___construct, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + + static const zend_function_entry class_ZendTestNS_Foo_methods[] = { ZEND_ME(ZendTestNS_Foo, method, arginfo_class_ZendTestNS_Foo_method, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -351,6 +412,18 @@ static const zend_function_entry class_ZendTestNS2_ZendSubNS_Foo_methods[] = { static void register_test_symbols(int module_number) { REGISTER_LONG_CONSTANT("ZEND_TEST_DEPRECATED", 42, CONST_PERSISTENT | CONST_DEPRECATED); + REGISTER_STRING_CONSTANT("ZEND_CONSTANT_A", "global", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("ZendTestNS2\\ZEND_CONSTANT_A", "namespaced", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("ZendTestNS2\\ZendSubNS\\ZEND_CONSTANT_A", "namespaced", CONST_PERSISTENT); + + + zend_string *attribute_name_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0 = zend_string_init_interned("ZendTestParameterAttribute", sizeof("ZendTestParameterAttribute") - 1, 1); + zend_attribute *attribute_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0 = zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_parameter_with_attribute", sizeof("zend_test_parameter_with_attribute") - 1), 0, attribute_name_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0, 1); + zend_string_release(attribute_name_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0); + zval attribute_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0_arg0; + zend_string *attribute_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0_arg0_str = zend_string_init("value1", strlen("value1"), 1); + ZVAL_STR(&attribute_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0_arg0, attribute_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0_arg0_str); + ZVAL_COPY_VALUE(&attribute_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0->args[0].value, &attribute_ZendTestParameterAttribute_zend_test_parameter_with_attribute_arg0_arg0); } static zend_class_entry *register_class__ZendTestInterface(void) @@ -477,14 +550,12 @@ static zend_class_entry *register_class_ZendTestAttribute(void) class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; -#if (PHP_VERSION_ID >= 80200) zend_string *attribute_name_Attribute_class_ZendTestAttribute = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1); zend_attribute *attribute_Attribute_class_ZendTestAttribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ZendTestAttribute, 1); zend_string_release(attribute_name_Attribute_class_ZendTestAttribute); zval attribute_Attribute_class_ZendTestAttribute_arg0; ZVAL_LONG(&attribute_Attribute_class_ZendTestAttribute_arg0, ZEND_ATTRIBUTE_TARGET_ALL); ZVAL_COPY_VALUE(&attribute_Attribute_class_ZendTestAttribute->args[0].value, &attribute_Attribute_class_ZendTestAttribute_arg0); -#endif return class_entry; } @@ -503,14 +574,12 @@ static zend_class_entry *register_class_ZendTestParameterAttribute(void) zend_declare_typed_property(class_entry, property_parameter_name, &property_parameter_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_parameter_name); -#if (PHP_VERSION_ID >= 80200) zend_string *attribute_name_Attribute_class_ZendTestParameterAttribute = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1); zend_attribute *attribute_Attribute_class_ZendTestParameterAttribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ZendTestParameterAttribute, 1); zend_string_release(attribute_name_Attribute_class_ZendTestParameterAttribute); zval attribute_Attribute_class_ZendTestParameterAttribute_arg0; ZVAL_LONG(&attribute_Attribute_class_ZendTestParameterAttribute_arg0, ZEND_ATTRIBUTE_TARGET_PARAMETER); ZVAL_COPY_VALUE(&attribute_Attribute_class_ZendTestParameterAttribute->args[0].value, &attribute_Attribute_class_ZendTestParameterAttribute_arg0); -#endif return class_entry; } @@ -529,14 +598,12 @@ static zend_class_entry *register_class_ZendTestPropertyAttribute(void) zend_declare_typed_property(class_entry, property_parameter_name, &property_parameter_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_parameter_name); -#if (PHP_VERSION_ID >= 80200) zend_string *attribute_name_Attribute_class_ZendTestPropertyAttribute = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1); zend_attribute *attribute_Attribute_class_ZendTestPropertyAttribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ZendTestPropertyAttribute, 1); zend_string_release(attribute_name_Attribute_class_ZendTestPropertyAttribute); zval attribute_Attribute_class_ZendTestPropertyAttribute_arg0; ZVAL_LONG(&attribute_Attribute_class_ZendTestPropertyAttribute_arg0, ZEND_ATTRIBUTE_TARGET_PROPERTY); ZVAL_COPY_VALUE(&attribute_Attribute_class_ZendTestPropertyAttribute->args[0].value, &attribute_Attribute_class_ZendTestPropertyAttribute_arg0); -#endif return class_entry; } @@ -548,6 +615,23 @@ static zend_class_entry *register_class_ZendTestClassWithMethodWithParameterAttr INIT_CLASS_ENTRY(ce, "ZendTestClassWithMethodWithParameterAttribute", class_ZendTestClassWithMethodWithParameterAttribute_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); + + zend_string *attribute_name_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0 = zend_string_init_interned("ZendTestParameterAttribute", sizeof("ZendTestParameterAttribute") - 1, 1); + zend_attribute *attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0 = zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "no_override", sizeof("no_override") - 1), 0, attribute_name_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0, 1); + zend_string_release(attribute_name_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0); + zval attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0_arg0; + zend_string *attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0_arg0_str = zend_string_init("value2", strlen("value2"), 1); + ZVAL_STR(&attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0_arg0, attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0_arg0_str); + ZVAL_COPY_VALUE(&attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0->args[0].value, &attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_no_override_arg0_arg0); + + zend_string *attribute_name_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0 = zend_string_init_interned("ZendTestParameterAttribute", sizeof("ZendTestParameterAttribute") - 1, 1); + zend_attribute *attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0 = zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "override", sizeof("override") - 1), 0, attribute_name_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0, 1); + zend_string_release(attribute_name_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0); + zval attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0_arg0; + zend_string *attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0_arg0_str = zend_string_init("value3", strlen("value3"), 1); + ZVAL_STR(&attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0_arg0, attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0_arg0_str); + ZVAL_COPY_VALUE(&attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0->args[0].value, &attribute_ZendTestParameterAttribute_ZendTestClassWithMethodWithParameterAttribute_override_arg0_arg0); + return class_entry; } @@ -558,6 +642,15 @@ static zend_class_entry *register_class_ZendTestChildClassWithMethodWithParamete INIT_CLASS_ENTRY(ce, "ZendTestChildClassWithMethodWithParameterAttribute", class_ZendTestChildClassWithMethodWithParameterAttribute_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_ZendTestClassWithMethodWithParameterAttribute); + + zend_string *attribute_name_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0 = zend_string_init_interned("ZendTestParameterAttribute", sizeof("ZendTestParameterAttribute") - 1, 1); + zend_attribute *attribute_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0 = zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "override", sizeof("override") - 1), 0, attribute_name_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0, 1); + zend_string_release(attribute_name_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0); + zval attribute_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0_arg0; + zend_string *attribute_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0_arg0_str = zend_string_init("value4", strlen("value4"), 1); + ZVAL_STR(&attribute_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0_arg0, attribute_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0_arg0_str); + ZVAL_COPY_VALUE(&attribute_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0->args[0].value, &attribute_ZendTestParameterAttribute_ZendTestChildClassWithMethodWithParameterAttribute_override_arg0_arg0); + return class_entry; } @@ -635,6 +728,23 @@ static zend_class_entry *register_class_ZendTestIntEnum(void) } #endif +static zend_class_entry *register_class_DoOperationNoCast(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "DoOperationNoCast", class_DoOperationNoCast_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_FINAL; + + zval property_val_default_value; + ZVAL_UNDEF(&property_val_default_value); + zend_string *property_val_name = zend_string_init("val", sizeof("val") - 1, 1); + zend_declare_typed_property(class_entry, property_val_name, &property_val_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_val_name); + + return class_entry; +} + static zend_class_entry *register_class_ZendTestNS_Foo(void) { zend_class_entry ce, *class_entry; diff --git a/ext/zend_test/tests/do_operation_not_cast.phpt b/ext/zend_test/tests/do_operation_not_cast.phpt new file mode 100644 index 0000000000000..fbab03c01a841 --- /dev/null +++ b/ext/zend_test/tests/do_operation_not_cast.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test DoOperationNotCast dummy class +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +object(DoOperationNoCast)#3 (1) { + ["val":"DoOperationNoCast":private]=> + int(31) +} +object(DoOperationNoCast)#3 (1) { + ["val":"DoOperationNoCast":private]=> + int(150) +} diff --git a/ext/zend_test/tests/execute_internal.phpt b/ext/zend_test/tests/execute_internal.phpt new file mode 100644 index 0000000000000..ce6cb851aed60 --- /dev/null +++ b/ext/zend_test/tests/execute_internal.phpt @@ -0,0 +1,21 @@ +--TEST-- +Test zend_execute_internal being called +--EXTENSIONS-- +zend_test +--INI-- +zend_test.observer.execute_internal=1 +--FILE-- + 0 ? [1, 2, 3] : []); + +?> +--EXPECT-- + + + +int(6) diff --git a/ext/zend_test/tests/gen_stub_test_02.phpt b/ext/zend_test/tests/gen_stub_test_02.phpt new file mode 100644 index 0000000000000..a3b6f397c89d2 --- /dev/null +++ b/ext/zend_test/tests/gen_stub_test_02.phpt @@ -0,0 +1,16 @@ +--TEST-- +gen_stub.php: constants +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +string(6) "global" +string(10) "namespaced" +string(10) "namespaced" diff --git a/ext/zend_test/tests/gh10370.tar b/ext/zend_test/tests/gh10370.tar new file mode 100644 index 0000000000000..4dbb754430d5d Binary files /dev/null and b/ext/zend_test/tests/gh10370.tar differ diff --git a/ext/zend_test/tests/gh10370_1.phpt b/ext/zend_test/tests/gh10370_1.phpt new file mode 100644 index 0000000000000..99a2da7547bfe --- /dev/null +++ b/ext/zend_test/tests/gh10370_1.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-10370: File corruption in _php_stream_copy_to_stream_ex when using copy_file_range - partial copy +--EXTENSIONS-- +zend_test +phar +--SKIPIF-- + +--INI-- +zend_test.limit_copy_file_range=3584 +--FILE-- +extractTo(__DIR__ . DIRECTORY_SEPARATOR . 'gh10370_001', ['testfile'])); +var_dump(sha1_file(__DIR__ . DIRECTORY_SEPARATOR . 'gh10370_001' . DIRECTORY_SEPARATOR . 'testfile')); +?> +--EXPECT-- +bool(true) +string(40) "a723ae4ec7eababff73ca961a771b794be6388d2" +--CLEAN-- + diff --git a/ext/zend_test/tests/gh10370_2.phpt b/ext/zend_test/tests/gh10370_2.phpt new file mode 100644 index 0000000000000..d78a3c395b6aa --- /dev/null +++ b/ext/zend_test/tests/gh10370_2.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-10370: File corruption in _php_stream_copy_to_stream_ex when using copy_file_range - unlimited copy +--EXTENSIONS-- +zend_test +--SKIPIF-- + +--INI-- +zend_test.limit_copy_file_range=4096 +--FILE-- + +--EXPECT-- +string(40) "edcad8cd6c276f5e318c826ad77a5604d6a6e93d" +string(40) "edcad8cd6c276f5e318c826ad77a5604d6a6e93d" +--CLEAN-- + diff --git a/ext/zend_test/tests/gh10370_3.phpt b/ext/zend_test/tests/gh10370_3.phpt new file mode 100644 index 0000000000000..5701c18d50cb4 --- /dev/null +++ b/ext/zend_test/tests/gh10370_3.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-10370: File corruption in _php_stream_copy_to_stream_ex when using copy_file_range - partial copy using stream_copy_to_stream +--EXTENSIONS-- +zend_test +--SKIPIF-- + +--INI-- +zend_test.limit_copy_file_range=3584 +--FILE-- + +--EXPECT-- +int(10240) +string(40) "a723ae4ec7eababff73ca961a771b794be6388d2" +--CLEAN-- + diff --git a/ext/zend_test/tests/gh10370_4.phpt b/ext/zend_test/tests/gh10370_4.phpt new file mode 100644 index 0000000000000..8cdb26356f02d --- /dev/null +++ b/ext/zend_test/tests/gh10370_4.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-10370: File corruption in _php_stream_copy_to_stream_ex when using copy_file_range - unlimited copy using stream_copy_to_stream +--EXTENSIONS-- +zend_test +--SKIPIF-- + +--INI-- +zend_test.limit_copy_file_range=4096 +--FILE-- + +--EXPECT-- +int(11776) +string(40) "edcad8cd6c276f5e318c826ad77a5604d6a6e93d" +string(40) "edcad8cd6c276f5e318c826ad77a5604d6a6e93d" +--CLEAN-- + diff --git a/ext/zend_test/tests/hash_fill_packed_nr_elements.phpt b/ext/zend_test/tests/hash_fill_packed_nr_elements.phpt new file mode 100644 index 0000000000000..77f22b2d9cd15 --- /dev/null +++ b/ext/zend_test/tests/hash_fill_packed_nr_elements.phpt @@ -0,0 +1,44 @@ +--TEST-- +Test hash packed fill number of elements +--EXTENSIONS-- +zend_test +--FILE-- + 0]; +zend_test_fill_packed_array($my_array); + +var_dump($my_array); +var_dump(count($my_array)); + +?> +--EXPECT-- +array(11) { + [6]=> + int(0) + [7]=> + int(0) + [8]=> + int(1) + [9]=> + int(2) + [10]=> + int(3) + [11]=> + int(4) + [12]=> + int(5) + [13]=> + int(6) + [14]=> + int(7) + [15]=> + int(8) + [16]=> + int(9) +} +int(11) diff --git a/ext/zend_test/tests/observer_declarations_file_cache.phpt b/ext/zend_test/tests/observer_declarations_file_cache.phpt index df20e359c0e58..1cff51650aed5 100644 --- a/ext/zend_test/tests/observer_declarations_file_cache.phpt +++ b/ext/zend_test/tests/observer_declarations_file_cache.phpt @@ -6,7 +6,7 @@ zend_test zend_test.observer.enabled=1 zend_test.observer.observe_declaring=1 opcache.enable_cli=1 -opcache.file_cache={TMP} +opcache.file_cache="{TMP}" opcache.file_cache_only=1 --FILE-- +--EXPECT-- +Empty strings: +bool(true) +Known strings: +bool(true) +Integer cast to string: +string(4) "2563" +bool(true) +Float cast to string: +string(4) "26.7" +bool(true) +string(8) "2.0E+100" +bool(true) +Concatenation known valid UTF-8 strings in variables: +string(2) "fo" +bool(true) +Multiple concatenation known valid UTF-8 strings in variables: +string(3) "foo" +bool(true) +Concatenation known valid UTF-8 in assignment: +string(2) "fo" +bool(true) +Multiple concatenation known valid UTF-8 in assignment: +string(3) "foo" +bool(false) +string(3) "fxo" +bool(true) +Concatenation known valid UTF-8 string with empty string in variables: +bool(true) +bool(true) +Concatenation known valid UTF-8 string with empty string in assignment: +bool(true) +bool(true) +Concatenation in loop: +bool(true) +Concatenation in loop (compound assignment): +bool(true) +Concatenation of objects: +string(2) "zz" +bool(true) +Rope concat: +bool(true) +str_repeat: +bool(true) +bool(false) +implode: +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/zend_test/tests/strings_not_marked_as_utf8.phpt b/ext/zend_test/tests/strings_not_marked_as_utf8.phpt new file mode 100644 index 0000000000000..d9115e8bd987e --- /dev/null +++ b/ext/zend_test/tests/strings_not_marked_as_utf8.phpt @@ -0,0 +1,139 @@ +--TEST-- +Check that invalid UTF-8 strings are NOT marked as valid UTF-8 +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +Integer cast to string concatenated to invalid UTF-8: +bool(false) +Float cast to string concatenated to invalid UTF-8: +bool(false) +bool(false) +Concatenation known valid UTF-8 strings in variables, followed by concatenation of invalid UTF-8: +bool(false) +Multiple concatenation known valid UTF-8 strings in variables, followed by concatenation of invalid UTF-8: +bool(false) +Concatenation known valid UTF-8 with invalid UTF-8 in assignment: +bool(false) +Multiple concatenation known valid UTF-8 and invalid UTF-8 in assignment: +bool(false) +Concatenation known valid UTF-8 string with empty string in variables, followed by concatenation of invalid UTF-8: +bool(false) +bool(false) +Concatenation known valid UTF-8 string with empty string in assignment, followed by concatenation of invalid UTF-8: +bool(false) +bool(false) +Concatenation in loop: +bool(false) +Concatenation in loop (compound assignment): +bool(false) +Concatenation of objects: +bool(false) +Rope concat: +bool(false) diff --git a/ext/zend_test/tests/variadic_arguments.phpt b/ext/zend_test/tests/variadic_arguments.phpt new file mode 100644 index 0000000000000..9261429038395 --- /dev/null +++ b/ext/zend_test/tests/variadic_arguments.phpt @@ -0,0 +1,44 @@ +--TEST-- +Verify that variadic arguments create proper stub +--EXTENSIONS-- +zend_test +--FILE-- +getParameters(); + +echo (string) $arguments[0], "\n"; +var_dump($arguments[0]->isVariadic()); + +$type = $arguments[0]->getType(); + +var_dump($type instanceof ReflectionUnionType); + +echo "\n"; + +$types = $type->getTypes(); + +var_dump($types[0]->getName()); +var_dump($types[0] instanceof ReflectionNamedType); +var_dump($types[0]->allowsNull()); + +echo "\n"; + +var_dump($types[1]->getName()); +var_dump($types[1] instanceof ReflectionNamedType); +var_dump($types[1]->allowsNull()); + +?> +--EXPECTF-- +Parameter #0 [ Iterator|string ...$elements ] +bool(true) +bool(true) + +string(8) "Iterator" +bool(true) +bool(false) + +string(6) "string" +bool(true) +bool(false) diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 10abf4447b083..14523a595af6e 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -354,7 +354,7 @@ static int php_zip_parse_options(HashTable *options, zip_options *opts) if ((option = zend_hash_str_find(options, "remove_all_path", sizeof("remove_all_path") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_FALSE && Z_TYPE_P(option) != IS_TRUE) { php_error_docref(NULL, E_WARNING, "Option \"remove_all_path\" must be of type bool, %s given", - zend_zval_type_name(option)); + zend_zval_value_name(option)); } opts->remove_all_path = zval_get_long(option); } @@ -362,14 +362,14 @@ static int php_zip_parse_options(HashTable *options, zip_options *opts) if ((option = zend_hash_str_find(options, "comp_method", sizeof("comp_method") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_LONG) { php_error_docref(NULL, E_WARNING, "Option \"comp_method\" must be of type int, %s given", - zend_zval_type_name(option)); + zend_zval_value_name(option)); } opts->comp_method = zval_get_long(option); if ((option = zend_hash_str_find(options, "comp_flags", sizeof("comp_flags") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_LONG) { php_error_docref(NULL, E_WARNING, "Option \"comp_flags\" must be of type int, %s given", - zend_zval_type_name(option)); + zend_zval_value_name(option)); } opts->comp_flags = zval_get_long(option); } @@ -379,14 +379,14 @@ static int php_zip_parse_options(HashTable *options, zip_options *opts) if ((option = zend_hash_str_find(options, "enc_method", sizeof("enc_method") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_LONG) { php_error_docref(NULL, E_WARNING, "Option \"enc_method\" must be of type int, %s given", - zend_zval_type_name(option)); + zend_zval_value_name(option)); } opts->enc_method = zval_get_long(option); if ((option = zend_hash_str_find(options, "enc_password", sizeof("enc_password") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_STRING) { zend_type_error("Option \"enc_password\" must be of type string, %s given", - zend_zval_type_name(option)); + zend_zval_value_name(option)); return -1; } opts->enc_password = Z_STRVAL_P(option); @@ -397,7 +397,7 @@ static int php_zip_parse_options(HashTable *options, zip_options *opts) if ((option = zend_hash_str_find(options, "remove_path", sizeof("remove_path") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_STRING) { zend_type_error("Option \"remove_path\" must be of type string, %s given", - zend_zval_type_name(option)); + zend_zval_value_name(option)); return -1; } @@ -417,7 +417,7 @@ static int php_zip_parse_options(HashTable *options, zip_options *opts) if ((option = zend_hash_str_find(options, "add_path", sizeof("add_path") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_STRING) { zend_type_error("Option \"add_path\" must be of type string, %s given", - zend_zval_type_name(option)); + zend_zval_value_name(option)); return -1; } @@ -437,7 +437,7 @@ static int php_zip_parse_options(HashTable *options, zip_options *opts) if ((option = zend_hash_str_find(options, "flags", sizeof("flags") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_LONG) { zend_type_error("Option \"flags\" must be of type int, %s given", - zend_zval_type_name(option)); + zend_zval_value_name(option)); return -1; } opts->flags = Z_LVAL_P(option); diff --git a/ext/zip/php_zip.stub.php b/ext/zip/php_zip.stub.php index c225d493cb3d4..51309cc066a1b 100644 --- a/ext/zip/php_zip.stub.php +++ b/ext/zip/php_zip.stub.php @@ -496,106 +496,127 @@ class ZipArchive implements Countable /** * @var int * @cvalue ZIP_OPSYS_DOS + * @link ziparchive.constants.opsys */ public const OPSYS_DOS = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_AMIGA + * @link ziparchive.constants.opsys */ public const OPSYS_AMIGA = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_OPENVMS + * @link ziparchive.constants.opsys */ public const OPSYS_OPENVMS = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_UNIX + * @link ziparchive.constants.opsys */ public const OPSYS_UNIX = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_VM_CMS + * @link ziparchive.constants.opsys */ public const OPSYS_VM_CMS = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_ATARI_ST + * @link ziparchive.constants.opsys */ public const OPSYS_ATARI_ST = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_OS_2 + * @link ziparchive.constants.opsys */ public const OPSYS_OS_2 = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_MACINTOSH + * @link ziparchive.constants.opsys */ public const OPSYS_MACINTOSH = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_Z_SYSTEM + * @link ziparchive.constants.opsys */ public const OPSYS_Z_SYSTEM = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_CPM + * @link ziparchive.constants.opsys */ public const OPSYS_CPM = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_WINDOWS_NTFS + * @link ziparchive.constants.opsys */ public const OPSYS_WINDOWS_NTFS = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_MVS + * @link ziparchive.constants.opsys */ public const OPSYS_MVS = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_VSE + * @link ziparchive.constants.opsys */ public const OPSYS_VSE = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_ACORN_RISC + * @link ziparchive.constants.opsys */ public const OPSYS_ACORN_RISC = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_VFAT + * @link ziparchive.constants.opsys */ public const OPSYS_VFAT = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_ALTERNATE_MVS + * @link ziparchive.constants.opsys */ public const OPSYS_ALTERNATE_MVS = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_BEOS + * @link ziparchive.constants.opsys */ public const OPSYS_BEOS = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_TANDEM + * @link ziparchive.constants.opsys */ public const OPSYS_TANDEM = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_OS_400 + * @link ziparchive.constants.opsys */ public const OPSYS_OS_400 = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_OS_X + * @link ziparchive.constants.opsys */ public const OPSYS_OS_X = UNKNOWN; /** * @var int * @cvalue ZIP_OPSYS_DEFAULT + * @link ziparchive.constants.opsys */ public const OPSYS_DEFAULT = UNKNOWN; #endif diff --git a/ext/zip/php_zip_arginfo.h b/ext/zip/php_zip_arginfo.h index 287fe25322032..41acc83b034d7 100644 --- a/ext/zip/php_zip_arginfo.h +++ b/ext/zip/php_zip_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: d8c14dfe45c7eff2c18fd3c562488a827f658e12 */ + * Stub hash: 69d4e8a343f237a7192728c805fb3a98bb04ca38 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_open, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) diff --git a/ext/zip/tests/oo_cancel.phpt b/ext/zip/tests/oo_cancel.phpt index fe9f9868c75b1..fa5fe92dadaad 100644 --- a/ext/zip/tests/oo_cancel.phpt +++ b/ext/zip/tests/oo_cancel.phpt @@ -12,7 +12,7 @@ date.timezone=UTC --FILE-- --FILE-- --FILE-- --FILE-- name); } - ini_value = zend_ini_string("output_handler", sizeof("output_handler"), 0); + ini_value = zend_ini_string("output_handler", sizeof("output_handler") - 1, 0); if (ini_value && *ini_value && int_value) { php_error_docref("ref.outcontrol", E_CORE_ERROR, "Cannot use both zlib.output_compression and output_handler together!!"); diff --git a/main/SAPI.c b/main/SAPI.c index 019de09782dec..2e697f9779669 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -683,7 +683,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg) switch (op) { case SAPI_HEADER_SET_STATUS: - sapi_update_response_code((int)(zend_intptr_t) arg); + sapi_update_response_code((int)(intptr_t) arg); return SUCCESS; case SAPI_HEADER_ADD: @@ -801,7 +801,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg) * to disable compression altogether. This contributes to making scripts * portable between setups that have and don't have zlib compression * enabled globally. See req #44164 */ - zend_string *key = zend_string_init("zlib.output_compression", sizeof("zlib.output_compression")-1, 0); + zend_string *key = ZSTR_INIT_LITERAL("zlib.output_compression", 0); zend_alter_ini_entry_chars(key, "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); zend_string_release_ex(key, 0); diff --git a/main/SAPI.h b/main/SAPI.h index 098b7c8c94c30..33c0e280d7390 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -262,7 +262,7 @@ struct _sapi_module_struct { void (*ini_defaults)(HashTable *configuration_hash); int phpinfo_as_text; - char *ini_entries; + const char *ini_entries; const zend_function_entry *additional_functions; unsigned int (*input_filter_init)(void); }; diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c index f6ce26e104bee..ead11a958b32a 100644 --- a/main/fopen_wrappers.c +++ b/main/fopen_wrappers.c @@ -101,11 +101,29 @@ PHPAPI ZEND_INI_MH(OnUpdateBaseDir) *end = '\0'; end++; } - if (ptr[0] == '.' && ptr[1] == '.' && (ptr[2] == '\0' || IS_SLASH(ptr[2]))) { - /* Don't allow paths with a leading .. path component to be set at runtime */ - efree(pathbuf); - return FAILURE; + /* Don't allow paths with a parent dir component (..) to be set at runtime */ + char *substr_pos = ptr; + while (*substr_pos) { + // Check if we have a .. path component + if (substr_pos[0] == '.' + && substr_pos[1] == '.' + && (substr_pos[2] == '\0' || IS_SLASH(substr_pos[2]))) { + efree(pathbuf); + return FAILURE; + } + // Skip to the next path component + while (true) { + substr_pos++; + if (*substr_pos == '\0' || *substr_pos == DEFAULT_DIR_SEPARATOR) { + goto no_parent_dir_component; + } else if (IS_SLASH(*substr_pos)) { + // Also skip the slash + substr_pos++; + break; + } + } } +no_parent_dir_component: if (php_check_open_basedir_ex(ptr, 0) != 0) { /* At least one portion of this open_basedir is less restrictive than the prior one, FAIL */ efree(pathbuf); @@ -129,10 +147,10 @@ PHPAPI ZEND_INI_MH(OnUpdateBaseDir) */ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path) { - char resolved_name[MAXPATHLEN]; - char resolved_basedir[MAXPATHLEN]; + char resolved_name[MAXPATHLEN + 1]; + char resolved_basedir[MAXPATHLEN + 1]; char local_open_basedir[MAXPATHLEN]; - char path_tmp[MAXPATHLEN]; + char path_tmp[MAXPATHLEN + 1]; char *path_file; size_t resolved_basedir_len; size_t resolved_name_len; @@ -353,6 +371,8 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) size_t length; bool orig_display_errors; + memset(file_handle, 0, sizeof(zend_file_handle)); + path_info = SG(request_info).request_uri; #if HAVE_PWD_H if (PG(user_dir) && *PG(user_dir) && path_info && '/' == path_info[0] && '~' == path_info[1]) { @@ -570,7 +590,7 @@ PHPAPI zend_string *php_resolve_path(const char *filename, size_t filename_lengt } } /* end provided path */ - /* check in calling scripts' current working directory as a fall back case + /* check in calling scripts' current working directory as a fallback case */ if (zend_is_executing() && (exec_filename = zend_get_executed_filename_ex()) != NULL) { @@ -650,7 +670,7 @@ PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const c /* check in provided path */ /* append the calling scripts' current working directory - * as a fall back case + * as a fallback case */ if (zend_is_executing() && (exec_filename = zend_get_executed_filename_ex()) != NULL) { @@ -786,7 +806,7 @@ PHPAPI char *expand_filepath_with_mode(const char *filepath, char *real_path, co fdtest = VCWD_OPEN(filepath, O_RDONLY); if (fdtest != -1) { /* return a relative file path if for any reason - * we cannot cannot getcwd() and the requested, + * we cannot getcwd() and the requested, * relatively referenced file is accessible */ copy_len = path_len > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : path_len; if (real_path) { diff --git a/main/main.c b/main/main.c index 2605e554c7ce6..2e0802d3b3b00 100644 --- a/main/main.c +++ b/main/main.c @@ -407,7 +407,7 @@ static PHP_INI_MH(OnUpdateTimeout) /* * If we're restoring INI values, we shouldn't reset the timer. * Otherwise, the timer is active when PHP is idle, such as the - * the CLI web server or CGI. Running a script will re-activate + * CLI web server or CGI. Running a script will re-activate * the timeout, so it's not needed to do so at script end. */ zend_set_timeout(EG(timeout_seconds), 0); @@ -417,7 +417,7 @@ static PHP_INI_MH(OnUpdateTimeout) /* }}} */ /* {{{ php_get_display_errors_mode() helper function */ -static zend_uchar php_get_display_errors_mode(zend_string *value) +static uint8_t php_get_display_errors_mode(zend_string *value) { if (!value) { return PHP_DISPLAY_ERRORS_STDOUT; @@ -440,7 +440,7 @@ static zend_uchar php_get_display_errors_mode(zend_string *value) return PHP_DISPLAY_ERRORS_STDOUT; } - zend_uchar mode = ZEND_ATOL(ZSTR_VAL(value)); + uint8_t mode = ZEND_ATOL(ZSTR_VAL(value)); if (mode && mode != PHP_DISPLAY_ERRORS_STDOUT && mode != PHP_DISPLAY_ERRORS_STDERR) { return PHP_DISPLAY_ERRORS_STDOUT; } @@ -461,7 +461,7 @@ static PHP_INI_MH(OnUpdateDisplayErrors) /* {{{ PHP_INI_DISP */ static PHP_INI_DISP(display_errors_mode) { - zend_uchar mode; + uint8_t mode; bool cgi_or_cli; zend_string *temporary_value; @@ -738,6 +738,7 @@ PHP_INI_BEGIN() PHP_INI_ENTRY("SMTP", "localhost",PHP_INI_ALL, NULL) PHP_INI_ENTRY("smtp_port", "25", PHP_INI_ALL, NULL) STD_PHP_INI_BOOLEAN("mail.add_x_header", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_x_header, php_core_globals, core_globals) + STD_PHP_INI_BOOLEAN("mail.mixed_lf_and_crlf", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_mixed_lf_and_crlf, php_core_globals, core_globals) STD_PHP_INI_ENTRY("mail.log", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateMailLog, mail_log, php_core_globals, core_globals) PHP_INI_ENTRY("browscap", NULL, PHP_INI_SYSTEM, OnChangeBrowscap) PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit) @@ -748,6 +749,7 @@ PHP_INI_BEGIN() PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) + PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL) STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) @@ -1020,7 +1022,7 @@ PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int typ origin = ZSTR_VAL(replace_origin); } - /* origin and buffer available, so lets come up with the error message */ + /* origin and buffer available, so let's come up with the error message */ if (docref && docref[0] == '#') { docref_target = strchr(docref, '#'); docref = NULL; @@ -1489,7 +1491,7 @@ PHP_FUNCTION(set_time_limit) new_timeout_strlen = zend_spprintf(&new_timeout_str, 0, ZEND_LONG_FMT, new_timeout); - key = zend_string_init("max_execution_time", sizeof("max_execution_time")-1, 0); + key = ZSTR_INIT_LITERAL("max_execution_time", 0); if (zend_alter_ini_entry_chars_ex(key, new_timeout_str, new_timeout_strlen, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == SUCCESS) { RETVAL_TRUE; } else { @@ -1625,7 +1627,7 @@ static ZEND_COLD void php_message_handler_for_zend(zend_long message, const void strlcat(memory_leak_buf, relay_buf, sizeof(memory_leak_buf)); } } else { - unsigned long leak_count = (zend_uintptr_t) data; + unsigned long leak_count = (uintptr_t) data; snprintf(memory_leak_buf, 512, "Last leak repeated %lu time%s\n", leak_count, (leak_count>1?"s":"")); } @@ -1950,7 +1952,7 @@ static void core_globals_dtor(php_core_globals *core_globals) free(core_globals->php_binary); } - php_shutdown_ticks(); + php_shutdown_ticks(core_globals); } /* }}} */ @@ -2644,13 +2646,18 @@ PHPAPI void php_reserve_tsrm_memory(void) } /* }}} */ -/* {{{ php_tsrm_startup */ -PHPAPI bool php_tsrm_startup(void) +PHPAPI bool php_tsrm_startup_ex(int expected_threads) { - bool ret = tsrm_startup(1, 1, 0, NULL); + bool ret = tsrm_startup(expected_threads, 1, 0, NULL); php_reserve_tsrm_memory(); (void)ts_resource(0); return ret; } + +/* {{{ php_tsrm_startup */ +PHPAPI bool php_tsrm_startup(void) +{ + return php_tsrm_startup_ex(1); +} /* }}} */ #endif diff --git a/main/network.c b/main/network.c index a189714aafbf9..ea3d17614f565 100644 --- a/main/network.c +++ b/main/network.c @@ -969,7 +969,7 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short /* }}} */ /* {{{ php_any_addr - * Fills the any (wildcard) address into php_sockaddr_storage + * Fills any (wildcard) address into php_sockaddr_storage */ PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port) { diff --git a/main/output.c b/main/output.c index 0567ca97570c5..57a61e4b93651 100644 --- a/main/output.c +++ b/main/output.c @@ -156,7 +156,7 @@ PHPAPI void php_output_shutdown(void) /* }}} */ /* {{{ SUCCESS|FAILURE php_output_activate(void) - * Reset output globals and setup the output handler stack */ + * Reset output globals and set up the output handler stack */ PHPAPI int php_output_activate(void) { #ifdef ZTS @@ -348,7 +348,7 @@ PHPAPI void php_output_discard_all(void) /* }}} */ /* {{{ int php_output_get_level(void) - * Get output buffering level, ie. how many output handlers the stack contains */ + * Get output buffering level, i.e. how many output handlers the stack contains */ PHPAPI int php_output_get_level(void) { return OG(active) ? zend_stack_count(&OG(handlers)) : 0; diff --git a/main/php.h b/main/php.h index b7101ed22f0a6..3385fb799927e 100644 --- a/main/php.h +++ b/main/php.h @@ -434,4 +434,10 @@ END_EXTERN_C() #include "php_reentrancy.h" +/* the following typedefs are deprecated and will be removed in PHP + * 9.0; use the standard C99 types instead */ +typedef bool zend_bool; +typedef intptr_t zend_intptr_t; +typedef uintptr_t zend_uintptr_t; + #endif diff --git a/main/php_globals.h b/main/php_globals.h index cbf0271c7b763..d62516f9d6833 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -19,6 +19,8 @@ #include "zend_globals.h" +#include + typedef struct _php_core_globals php_core_globals; #ifdef ZTS @@ -51,12 +53,19 @@ typedef struct _arg_separators { } arg_separators; struct _php_core_globals { - bool implicit_flush; - zend_long output_buffering; + bool implicit_flush; + bool enable_dl; + uint8_t display_errors; + bool display_startup_errors; + bool log_errors; + bool ignore_repeated_errors; + bool ignore_repeated_source; + bool report_memleaks; + char *output_handler; char *unserialize_callback_func; @@ -65,12 +74,6 @@ struct _php_core_globals { zend_long memory_limit; zend_long max_input_time; - zend_uchar display_errors; - bool display_startup_errors; - bool log_errors; - bool ignore_repeated_errors; - bool ignore_repeated_source; - bool report_memleaks; char *error_log; char *doc_root; @@ -114,12 +117,12 @@ struct _php_core_globals { bool register_argc_argv; bool auto_globals_jit; - char *docref_root; - char *docref_ext; - bool html_errors; bool xmlrpc_errors; + char *docref_root; + char *docref_ext; + zend_long xmlrpc_error_number; bool activated_auto_globals[8]; @@ -132,38 +135,40 @@ struct _php_core_globals { bool report_zend_debug; int last_error_type; + int last_error_lineno; zend_string *last_error_message; zend_string *last_error_file; - int last_error_lineno; char *php_sys_temp_dir; char *disable_classes; - bool allow_url_include; -#ifdef PHP_WIN32 - bool com_initialized; -#endif zend_long max_input_nesting_level; zend_long max_input_vars; - bool in_user_include; char *user_ini_filename; zend_long user_ini_cache_ttl; char *request_order; - bool mail_x_header; char *mail_log; + bool mail_x_header; + bool mail_mixed_lf_and_crlf; bool in_error_log; + bool allow_url_include; +#ifdef PHP_WIN32 + bool com_initialized; +#endif + bool in_user_include; + #ifdef PHP_WIN32 bool windows_show_crt_warning; #endif + bool have_called_openlog; zend_long syslog_facility; char *syslog_ident; - bool have_called_openlog; zend_long syslog_filter; zend_long error_log_mode; }; diff --git a/main/php_main.h b/main/php_main.h index 561635faea6c3..40c1b773fd2f0 100644 --- a/main/php_main.h +++ b/main/php_main.h @@ -47,6 +47,7 @@ extern int php_shutdown_environ(void); #ifdef ZTS PHPAPI void php_reserve_tsrm_memory(void); +PHPAPI bool php_tsrm_startup_ex(int expected_threads); PHPAPI bool php_tsrm_startup(void); #define PHP_ZTS 1 diff --git a/main/php_network.h b/main/php_network.h index a3b7ba7ab3180..7cc3609c44089 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -49,7 +49,7 @@ # define EWOULDBLOCK EAGAIN #endif -/* This is a work around for GCC bug 69602: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69602 */ +/* This is a workaround for GCC bug 69602: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69602 */ #if EAGAIN != EWOULDBLOCK # define PHP_IS_TRANSIENT_ERROR(err) (err == EAGAIN || err == EWOULDBLOCK) #else diff --git a/main/php_streams.h b/main/php_streams.h index 0661491db98fe..13f8fe827b08a 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -90,7 +90,7 @@ END_EXTERN_C() * The only exceptions to this rule are that stream implementations can use * the php_stream->abstract pointer to hold their context, and streams * opened via stream_open_wrappers can use the zval ptr in - * php_stream->wrapperdata to hold meta data for php scripts to + * php_stream->wrapperdata to hold metadata for php scripts to * retrieve using file_get_wrapper_data(). */ typedef struct _php_stream php_stream; @@ -188,6 +188,8 @@ struct _php_stream_wrapper { /* Do not close handle except it is explicitly closed by user (e.g. fclose) */ #define PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE 0x200 +#define PHP_STREAM_FLAG_NO_IO 0x400 + #define PHP_STREAM_FLAG_WAS_WRITTEN 0x80000000 struct _php_stream { @@ -197,7 +199,7 @@ struct _php_stream { php_stream_filter_chain readfilters, writefilters; php_stream_wrapper *wrapper; /* which wrapper was used to open the stream */ - void *wrapperthis; /* convenience pointer for a instance of a wrapper */ + void *wrapperthis; /* convenience pointer for an instance of a wrapper */ zval wrapperdata; /* fgetwrapperdata retrieves this */ uint8_t is_persistent:1; @@ -288,7 +290,7 @@ PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream * #define PHP_STREAM_FREE_CALL_DTOR 1 /* call ops->close */ #define PHP_STREAM_FREE_RELEASE_STREAM 2 /* pefree(stream) */ -#define PHP_STREAM_FREE_PRESERVE_HANDLE 4 /* tell ops->close to not close it's underlying handle */ +#define PHP_STREAM_FREE_PRESERVE_HANDLE 4 /* tell ops->close to not close its underlying handle */ #define PHP_STREAM_FREE_RSRC_DTOR 8 /* called from the resource list dtor */ #define PHP_STREAM_FREE_PERSISTENT 16 /* manually freeing a persistent connection */ #define PHP_STREAM_FREE_IGNORE_ENCLOSING 32 /* don't close the enclosing stream instead */ @@ -439,7 +441,7 @@ PHPAPI int _php_stream_truncate_set_size(php_stream *stream, size_t newsize); #define php_stream_truncate_set_size(stream, size) _php_stream_truncate_set_size((stream), (size)) END_EXTERN_C() -#define PHP_STREAM_OPTION_META_DATA_API 11 /* ptrparam is a zval* to which to add meta data information */ +#define PHP_STREAM_OPTION_META_DATA_API 11 /* ptrparam is a zval* to which to add metadata information */ #define php_stream_populate_meta_data(stream, zv) (_php_stream_set_option((stream), PHP_STREAM_OPTION_META_DATA_API, 0, zv) == PHP_STREAM_OPTION_RETURN_OK ? 1 : 0) /* Check if the stream is still "live"; for sockets/pipes this means the socket diff --git a/main/php_syslog.c b/main/php_syslog.c index fa71a86313466..975a0423df175 100644 --- a/main/php_syslog.c +++ b/main/php_syslog.c @@ -58,7 +58,7 @@ PHPAPI void php_syslog_str(int priority, const zend_string* message) } else if ((c < 0x20) && (PG(syslog_filter) == PHP_SYSLOG_FILTER_ALL)) { smart_string_appendc(&sbuf, c); } else { - const char xdigits[] = "0123456789abcdef"; + static const char xdigits[] = "0123456789abcdef"; smart_string_appendl(&sbuf, "\\x", 2); smart_string_appendc(&sbuf, xdigits[c >> 4]); diff --git a/main/php_ticks.c b/main/php_ticks.c index 004314583bdb0..70201ddecd08d 100644 --- a/main/php_ticks.c +++ b/main/php_ticks.c @@ -34,9 +34,9 @@ void php_deactivate_ticks(void) zend_llist_clean(&PG(tick_functions)); } -void php_shutdown_ticks(void) +void php_shutdown_ticks(php_core_globals *core_globals) { - zend_llist_destroy(&PG(tick_functions)); + zend_llist_destroy(&core_globals->tick_functions); } static int php_compare_tick_functions(void *elem1, void *elem2) diff --git a/main/php_ticks.h b/main/php_ticks.h index 5edf7a483bbac..270ea5348fd2a 100644 --- a/main/php_ticks.h +++ b/main/php_ticks.h @@ -19,7 +19,7 @@ int php_startup_ticks(void); void php_deactivate_ticks(void); -void php_shutdown_ticks(void); +void php_shutdown_ticks(php_core_globals *core_globals); void php_run_ticks(int count); BEGIN_EXTERN_C() diff --git a/main/php_variables.c b/main/php_variables.c index 3d7d904a47d7f..15314869180aa 100644 --- a/main/php_variables.c +++ b/main/php_variables.c @@ -207,7 +207,7 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac zval_ptr_dtor_nogc(val); /* do not output the error message to the screen, - this helps us to to avoid "information disclosure" */ + this helps us to avoid "information disclosure" */ if (!PG(display_errors)) { php_error_docref(NULL, E_WARNING, "Input variable nesting level exceeded " ZEND_LONG_FMT ". To increase the limit change max_input_nesting_level in php.ini.", PG(max_input_nesting_level)); } diff --git a/main/rfc1867.c b/main/rfc1867.c index fb2d785fbee5e..f16af170b6aa8 100644 --- a/main/rfc1867.c +++ b/main/rfc1867.c @@ -49,7 +49,7 @@ static php_rfc1867_getword_t php_rfc1867_getword = php_ap_getword; static php_rfc1867_getword_conf_t php_rfc1867_getword_conf = php_ap_getword_conf; static php_rfc1867_basename_t php_rfc1867_basename = NULL; -PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra) = NULL; +PHPAPI zend_result (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra) = NULL; static void safe_php_register_variable(char *var, char *strval, size_t val_len, zval *track_vars_array, bool override_protection); @@ -663,6 +663,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ void *event_extra_data = NULL; unsigned int llen = 0; int upload_cnt = INI_INT("max_file_uploads"); + int body_parts_cnt = INI_INT("max_multipart_body_parts"); const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(); php_rfc1867_getword_t getword; php_rfc1867_getword_conf_t getword_conf; @@ -684,6 +685,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ return; } + if (body_parts_cnt < 0) { + body_parts_cnt = PG(max_input_vars) + upload_cnt; + } + int body_parts_limit = body_parts_cnt; + /* Get the boundary */ boundary = strstr(content_type_dup, "boundary"); if (!boundary) { @@ -768,6 +774,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ char *pair = NULL; int end = 0; + if (--body_parts_cnt < 0) { + php_error_docref(NULL, E_WARNING, "Multipart body parts limit exceeded %d. To increase the limit change max_multipart_body_parts in php.ini.", body_parts_limit); + goto fileupload_done; + } + while (isspace(*cd)) { ++cd; } @@ -887,7 +898,10 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ skip_upload = 1; } else if (upload_cnt <= 0) { skip_upload = 1; - sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded"); + if (upload_cnt == 0) { + --upload_cnt; + sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded"); + } } /* Return with an error if the posted data is garbled */ diff --git a/main/rfc1867.h b/main/rfc1867.h index e1ec2af87c422..bb690f15aa3e7 100644 --- a/main/rfc1867.h +++ b/main/rfc1867.h @@ -83,7 +83,7 @@ typedef char* (*php_rfc1867_basename_t)(const zend_encoding *encoding, char *str SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler); PHPAPI void destroy_uploaded_files_hash(void); -extern PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra); +extern PHPAPI zend_result (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra); SAPI_API void php_rfc1867_set_multibyte_callbacks( php_rfc1867_encoding_translation_t encoding_translation, diff --git a/main/safe_bcmp.c b/main/safe_bcmp.c index 27a1756d79b46..3e806de4ab6e3 100644 --- a/main/safe_bcmp.c +++ b/main/safe_bcmp.c @@ -19,7 +19,7 @@ #include /* - * Returns 0 if both inputs match, 1 if they don't. + * Returns 0 if both inputs match, non-zero if they don't. * Returns -1 early if inputs do not have the same lengths. * */ @@ -34,6 +34,7 @@ PHPAPI int php_safe_bcmp(const zend_string *a, const zend_string *b) return -1; } + /* This is security sensitive code. Do not optimize this for speed. */ while (i < ZSTR_LEN(a)) { r |= ua[i] ^ ub[i]; ++i; diff --git a/main/snprintf.c b/main/snprintf.c index 3c379c5c2ce18..de69200304a43 100644 --- a/main/snprintf.c +++ b/main/snprintf.c @@ -421,7 +421,7 @@ typedef struct buf_area buffy; * bep points to the end-of-buffer+1 * While using this macro, note that the nextb pointer is NOT updated. * - * NOTE: Evaluation of the c argument should not have any side-effects + * NOTE: Evaluation of the c argument should not have any side effects */ #define INS_CHAR(c, sp, bep, cc) \ { \ @@ -580,8 +580,8 @@ static size_t format_converter(buffy * odp, const char *fmt, va_list ap) /* {{{ } else if (*fmt == '*') { precision = va_arg(ap, int); fmt++; - if (precision < 0) - precision = 0; + if (precision < -1) + precision = -1; } else precision = 0; } else diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index e9a30f3334016..128c3410aa835 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -258,9 +258,9 @@ static void detect_is_seekable(php_stdio_stream_data *self) { self->is_pipe = S_ISFIFO(self->sb.st_mode); } #elif defined(PHP_WIN32) - zend_uintptr_t handle = _get_osfhandle(self->fd); + uintptr_t handle = _get_osfhandle(self->fd); - if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) { + if (handle != (uintptr_t)INVALID_HANDLE_VALUE) { DWORD file_type = GetFileType((HANDLE)handle); self->is_seekable = !(file_type == FILE_TYPE_PIPE || file_type == FILE_TYPE_CHAR); @@ -539,7 +539,7 @@ static int php_stdiop_flush(php_stream *stream) /* * stdio buffers data in user land. By calling fflush(3), this - * data is send to the kernel using write(2). fsync'ing is + * data is sent to the kernel using write(2). fsync'ing is * something completely different. */ if (data->file) { @@ -733,7 +733,7 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void return -1; } - if ((zend_uintptr_t) ptrparam == PHP_STREAM_LOCK_SUPPORTED) { + if ((uintptr_t) ptrparam == PHP_STREAM_LOCK_SUPPORTED) { return 0; } @@ -1671,7 +1671,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(const char *filename, const char /* check in provided path */ /* append the calling scripts' current working directory - * as a fall back case + * as a fallback case */ if (zend_is_executing() && (exec_filename = zend_get_executed_filename_ex()) != NULL) { diff --git a/main/streams/streams.c b/main/streams/streams.c index 1231dbebd63ae..f655faef10cbf 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -469,7 +469,7 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov the cookie_closer unsets the fclose_stdiocast flags, so we can be sure that we only reach here when PHP code calls php_stream_free. - Lets let the cookie code clean it all up. + Let's let the cookie code clean it all up. */ stream->in_free = 0; return fclose(stream->stdiocast); @@ -839,7 +839,7 @@ PHPAPI int _php_stream_stat(php_stream *stream, php_stream_statbuf *ssb) } /* if the stream doesn't directly support stat-ing, return with failure. - * We could try and emulate this by casting to a FD and fstat-ing it, + * We could try and emulate this by casting to an FD and fstat-ing it, * but since the fd might not represent the actual underlying content * this would give bogus results. */ if (stream->ops->stat == NULL) { @@ -1503,7 +1503,7 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int return result; } - /* avoid many reallocs by allocating a good sized chunk to begin with, if + /* avoid many reallocs by allocating a good-sized chunk to begin with, if * we can. Note that the stream may be filtered, in which case the stat * result may be inaccurate, as the filter may inflate or deflate the * number of bytes that we can read. In order to avoid an upsize followed @@ -1615,6 +1615,13 @@ PHPAPI zend_result _php_stream_copy_to_stream_ex(php_stream *src, php_stream *de /* not implemented by this Linux kernel */ break; + case EIO: + /* Some filesystems will cause failures if the max length is greater than the file length + * in certain circumstances and configuration. In those cases the errno is EIO and we will + * fall back to other methods. We cannot use stat to determine the file length upfront because + * that is prone to races and outdated caching. */ + break; + default: /* unexpected I/O error - give up, no fallback */ *len = haveread; @@ -1635,8 +1642,21 @@ PHPAPI zend_result _php_stream_copy_to_stream_ex(php_stream *src, php_stream *de char *p; do { - size_t chunk_size = (maxlen == 0 || maxlen > PHP_STREAM_MMAP_MAX) ? PHP_STREAM_MMAP_MAX : maxlen; - size_t mapped; + /* We must not modify maxlen here, because otherwise the file copy fallback below can fail */ + size_t chunk_size, must_read, mapped; + if (maxlen == 0) { + /* Unlimited read */ + must_read = chunk_size = PHP_STREAM_MMAP_MAX; + } else { + must_read = maxlen - haveread; + if (must_read >= PHP_STREAM_MMAP_MAX) { + chunk_size = PHP_STREAM_MMAP_MAX; + } else { + /* In case the length we still have to read from the file could be smaller than the file size, + * chunk_size must not get bigger the size we're trying to read. */ + chunk_size = must_read; + } + } p = php_stream_mmap_range(src, php_stream_tell(src), chunk_size, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped); @@ -1651,6 +1671,7 @@ PHPAPI zend_result _php_stream_copy_to_stream_ex(php_stream *src, php_stream *de didwrite = php_stream_write(dest, p, mapped); if (didwrite < 0) { *len = haveread; + php_stream_mmap_unmap(src); return FAILURE; } @@ -1667,9 +1688,10 @@ PHPAPI zend_result _php_stream_copy_to_stream_ex(php_stream *src, php_stream *de if (mapped < chunk_size) { return SUCCESS; } + /* If we're not reading as much as possible, so a bounded read */ if (maxlen != 0) { - maxlen -= mapped; - if (maxlen == 0) { + must_read -= mapped; + if (must_read == 0) { return SUCCESS; } } diff --git a/main/streams/transports.c b/main/streams/transports.c index 35ac4ae27ade5..1c9a83be2c882 100644 --- a/main/streams/transports.c +++ b/main/streams/transports.c @@ -76,7 +76,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in if (persistent_id) { switch(php_stream_from_persistent_id(persistent_id, &stream)) { case PHP_STREAM_PERSISTENT_SUCCESS: - /* use a 0 second timeout when checking if the socket + /* use a 0-second timeout when checking if the socket * has already died */ if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS, 0, NULL)) { return stream; @@ -169,6 +169,9 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in failed = true; } } + if (!failed) { + stream->flags |= PHP_STREAM_FLAG_NO_IO; + } } } } zend_catch { diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index 3a4beca9f077b..4ea0dc8e880bf 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -359,7 +359,14 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void if (sock->socket == -1) { alive = 0; - } else if ((value == 0 && ((MSG_DONTWAIT != 0) || !sock->is_blocked)) || php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) { + } else if ( + ( + value == 0 && + !(stream->flags & PHP_STREAM_FLAG_NO_IO) && + ((MSG_DONTWAIT != 0) || !sock->is_blocked) + ) || + php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0 + ) { /* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */ #ifdef PHP_WIN32 int ret; diff --git a/php.ini-development b/php.ini-development index 8a0db63e36bf5..d6bc11ae17e41 100644 --- a/php.ini-development +++ b/php.ini-development @@ -433,6 +433,11 @@ max_input_time = 60 ; How many GET/POST/COOKIE input variables may be accepted ;max_input_vars = 1000 +; How many multipart body parts (combined input variable and file uploads) may +; be accepted. +; Default Value: -1 (Sum of max_input_vars and max_file_uploads) +;max_multipart_body_parts = 1500 + ; Maximum amount of memory a script may consume ; https://php.net/memory-limit memory_limit = 128M @@ -1105,6 +1110,10 @@ smtp_port = 25 ; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename mail.add_x_header = Off +; Use mixed LF and CRLF line separators to keep compatibility with some +; RFC 2822 non conformant MTA. +mail.mixed_lf_and_crlf = Off + ; The path to a log file that will log all mail() calls. Log entries include ; the full path of the script, line number, To address and headers. ;mail.log = @@ -1906,7 +1915,12 @@ ldap.max_links = -1 ;opcache.file_cache_fallback=1 ; Enables or disables copying of PHP code (text segment) into HUGE PAGES. -; This should improve performance, but requires appropriate OS configuration. +; Under certain circumstances (if only a single global PHP process is +; started from which all others fork), this can increase performance +; by a tiny amount because TLB misses are reduced. On the other hand, this +; delays PHP startup, increases memory usage and degrades performance +; under memory pressure - use with care. +; Requires appropriate OS configuration. ;opcache.huge_code_pages=0 ; Validate cached file permissions. diff --git a/php.ini-production b/php.ini-production index f447242cc5cca..0d6ca0f144482 100644 --- a/php.ini-production +++ b/php.ini-production @@ -435,6 +435,11 @@ max_input_time = 60 ; How many GET/POST/COOKIE input variables may be accepted ;max_input_vars = 1000 +; How many multipart body parts (combined input variable and file uploads) may +; be accepted. +; Default Value: -1 (Sum of max_input_vars and max_file_uploads) +;max_multipart_body_parts = 1500 + ; Maximum amount of memory a script may consume ; https://php.net/memory-limit memory_limit = 128M @@ -1107,6 +1112,10 @@ smtp_port = 25 ; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename mail.add_x_header = Off +; Use mixed LF and CRLF line separators to keep compatibility with some +; RFC 2822 non conformant MTA. +mail.mixed_lf_and_crlf = Off + ; The path to a log file that will log all mail() calls. Log entries include ; the full path of the script, line number, To address and headers. ;mail.log = @@ -1908,8 +1917,13 @@ ldap.max_links = -1 ;opcache.file_cache_fallback=1 ; Enables or disables copying of PHP code (text segment) into HUGE PAGES. -; This should improve performance, but requires appropriate OS configuration. -;opcache.huge_code_pages=1 +; Under certain circumstances (if only a single global PHP process is +; started from which all others fork), this can increase performance +; by a tiny amount because TLB misses are reduced. On the other hand, this +; delays PHP startup, increases memory usage and degrades performance +; under memory pressure - use with care. +; Requires appropriate OS configuration. +;opcache.huge_code_pages=0 ; Validate cached file permissions. ;opcache.validate_permission=0 diff --git a/run-tests.php b/run-tests.php index 0d72a2bc9fed9..0d0b683becd79 100755 --- a/run-tests.php +++ b/run-tests.php @@ -580,6 +580,7 @@ function main(): void $environment['SKIP_PERF_SENSITIVE'] = 1; if ($switch === '--msan') { $environment['SKIP_MSAN'] = 1; + $environment['MSAN_OPTIONS'] = 'intercept_tls_get_addr=0'; } $lsanSuppressions = __DIR__ . '/.github/lsan-suppressions.txt'; @@ -678,10 +679,16 @@ function main(): void putenv("TEST_PHP_EXECUTABLE=$php"); $environment['TEST_PHP_EXECUTABLE'] = $php; + putenv("TEST_PHP_EXECUTABLE_ESCAPED=" . escapeshellarg($php)); + $environment['TEST_PHP_EXECUTABLE_ESCAPED'] = escapeshellarg($php); putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); $environment['TEST_PHP_CGI_EXECUTABLE'] = $php_cgi; + putenv("TEST_PHP_CGI_EXECUTABLE_ESCAPED=" . escapeshellarg($php_cgi)); + $environment['TEST_PHP_CGI_EXECUTABLE_ESCAPED'] = escapeshellarg($php_cgi); putenv("TEST_PHPDBG_EXECUTABLE=$phpdbg"); $environment['TEST_PHPDBG_EXECUTABLE'] = $phpdbg; + putenv("TEST_PHPDBG_EXECUTABLE_ESCAPED=" . escapeshellarg($phpdbg ?? '')); + $environment['TEST_PHPDBG_EXECUTABLE_ESCAPED'] = escapeshellarg($phpdbg ?? ''); if ($conf_passed !== null) { if (IS_WINDOWS) { @@ -831,6 +838,7 @@ function verify_config(): void function write_information(): void { global $php, $php_cgi, $phpdbg, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $valgrind, $no_file_cache; + $php_escaped = escapeshellarg($php); // Get info from php $info_file = __DIR__ . '/run-test-info.php'; @@ -846,11 +854,12 @@ function write_information(): void $info_params = []; settings2array($ini_overwrites, $info_params); $info_params = settings2params($info_params); - $php_info = shell_exec("$php $pass_options $info_params $no_file_cache \"$info_file\""); - define('TESTED_PHP_VERSION', shell_exec("$php -n -r \"echo PHP_VERSION;\"")); + $php_info = shell_exec("$php_escaped $pass_options $info_params $no_file_cache \"$info_file\""); + define('TESTED_PHP_VERSION', shell_exec("$php_escaped -n -r \"echo PHP_VERSION;\"")); if ($php_cgi && $php != $php_cgi) { - $php_info_cgi = shell_exec("$php_cgi $pass_options $info_params $no_file_cache -q \"$info_file\""); + $php_cgi_escaped = escapeshellarg($php_cgi); + $php_info_cgi = shell_exec("$php_cgi_escaped $pass_options $info_params $no_file_cache -q \"$info_file\""); $php_info_sep = "\n---------------------------------------------------------------------"; $php_cgi_info = "$php_info_sep\nPHP : $php_cgi $php_info_cgi$php_info_sep"; } else { @@ -858,7 +867,8 @@ function write_information(): void } if ($phpdbg) { - $phpdbg_info = shell_exec("$phpdbg $pass_options $info_params $no_file_cache -qrr \"$info_file\""); + $phpdbg_escaped = escapeshellarg($phpdbg); + $phpdbg_info = shell_exec("$phpdbg_escaped $pass_options $info_params $no_file_cache -qrr \"$info_file\""); $php_info_sep = "\n---------------------------------------------------------------------"; $phpdbg_info = "$php_info_sep\nPHP : $phpdbg $phpdbg_info$php_info_sep"; } else { @@ -884,7 +894,7 @@ function write_information(): void } echo implode(',', $exts); PHP); - $extensionsNames = explode(',', shell_exec("$php $pass_options $info_params $no_file_cache \"$info_file\"")); + $extensionsNames = explode(',', shell_exec("$php_escaped $pass_options $info_params $no_file_cache \"$info_file\"")); $exts_to_test = array_unique(remap_loaded_extensions_names($extensionsNames)); // check for extensions that need special handling and regenerate $info_params_ex = [ @@ -1163,6 +1173,13 @@ function system_with_timeout( ) { global $valgrind; + // when proc_open cmd is passed as a string (without bypass_shell=true option) the cmd goes thru shell + // and on Windows quotes are discarded, this is a fix to honor the quotes and allow values containing + // spaces like '"C:\Program Files\PHP\php.exe"' to be passed as 1 argument correctly + if (IS_WINDOWS) { + $commandline = 'start "" /b /wait ' . $commandline; + } + $data = ''; $bin_env = []; @@ -1496,6 +1513,10 @@ function run_all_tests_parallel(array $test_files, array $env, $redir_tested): v kill_children($workerProcs); error("Could not find worker stdout in array of worker stdouts, THIS SHOULD NOT HAPPEN."); } + if (feof($workerSock)) { + kill_children($workerProcs); + error("Worker $i died unexpectedly"); + } while (false !== ($rawMessage = fgets($workerSock))) { // work around fgets truncating things if (($rawMessageBuffers[$i] ?? '') !== '') { @@ -1830,9 +1851,15 @@ function run_test(string $php, $file, array $env): string $skipCache = new SkipCache($enableSkipCache, $cfg['keep']['skip']); } + $orig_php = $php; + $php = escapeshellarg($php); + + $retriable = true; + $retried = false; +retry: + $temp_filenames = null; $org_file = $file; - $orig_php = $php; $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE'] ?? null; $phpdbg = $env['TEST_PHPDBG_EXECUTABLE'] ?? null; @@ -1869,8 +1896,11 @@ function run_test(string $php, $file, array $env): string $tested = $test->getName(); - if ($num_repeats > 1 && $test->hasSection('FILE_EXTERNAL')) { - return skip_test($tested, $tested_file, $shortname, 'Test with FILE_EXTERNAL might not be repeatable'); + if ($test->hasSection('FILE_EXTERNAL')) { + $retriable = false; + if ($num_repeats > 1) { + return skip_test($tested, $tested_file, $shortname, 'Test with FILE_EXTERNAL might not be repeatable'); + } } if ($test->hasSection('CAPTURE_STDIO')) { @@ -1894,8 +1924,9 @@ function run_test(string $php, $file, array $env): string if (!$php_cgi) { return skip_test($tested, $tested_file, $shortname, 'CGI not available'); } - $php = $php_cgi . ' -C '; + $php = escapeshellarg($php_cgi) . ' -C '; $uses_cgi = true; + $retriable = false; if ($num_repeats > 1) { return skip_test($tested, $tested_file, $shortname, 'CGI does not support --repeat'); } @@ -1905,7 +1936,7 @@ function run_test(string $php, $file, array $env): string $extra_options = ''; if ($test->hasSection('PHPDBG')) { if (isset($phpdbg)) { - $php = $phpdbg . ' -qIb'; + $php = escapeshellarg($phpdbg) . ' -qIb'; // Additional phpdbg command line options for sections that need to // be run straight away. For example, EXTENSIONS, SKIPIF, CLEAN. @@ -1913,20 +1944,18 @@ function run_test(string $php, $file, array $env): string } else { return skip_test($tested, $tested_file, $shortname, 'phpdbg not available'); } + $retriable = false; if ($num_repeats > 1) { return skip_test($tested, $tested_file, $shortname, 'phpdbg does not support --repeat'); } } - if ($num_repeats > 1) { - if ($test->hasSection('CLEAN')) { - return skip_test($tested, $tested_file, $shortname, 'Test with CLEAN might not be repeatable'); - } - if ($test->hasSection('STDIN')) { - return skip_test($tested, $tested_file, $shortname, 'Test with STDIN might not be repeatable'); - } - if ($test->hasSection('CAPTURE_STDIO')) { - return skip_test($tested, $tested_file, $shortname, 'Test with CAPTURE_STDIO might not be repeatable'); + foreach (['CLEAN', 'STDIN', 'CAPTURE_STDIO'] as $section) { + if ($test->hasSection($section)) { + $retriable = false; + if ($num_repeats > 1) { + return skip_test($tested, $tested_file, $shortname, "Test with $section might not be repeatable"); + } } } @@ -2118,8 +2147,11 @@ function run_test(string $php, $file, array $env): string } settings2array(preg_split("/[\n\r]+/", $ini), $ini_settings); - if ($num_repeats > 1 && isset($ini_settings['opcache.opt_debug_level'])) { - return skip_test($tested, $tested_file, $shortname, 'opt_debug_level tests are not repeatable'); + if (isset($ini_settings['opcache.opt_debug_level'])) { + $retriable = false; + if ($num_repeats > 1) { + return skip_test($tested, $tested_file, $shortname, 'opt_debug_level tests are not repeatable'); + } } } @@ -2185,6 +2217,9 @@ function run_test(string $php, $file, array $env): string } elseif (!strncasecmp('xfail', $output, 5)) { // Pretend we have an XFAIL section $test->setSection('XFAIL', ltrim(substr($output, 5))); + } elseif (!strncasecmp('xleak', $output, 5)) { + // Pretend we have an XLEAK section + $test->setSection('XLEAK', ltrim(substr($output, 5))); } elseif ($output !== '') { show_result("BORK", $output, $tested_file, 'reason: invalid output from SKIPIF', $temp_filenames); $PHP_FAILED_TESTS['BORKED'][] = [ @@ -2439,6 +2474,13 @@ function run_test(string $php, $file, array $env): string $cmd = $valgrind->wrapCommand($cmd, $memcheck_filename, strpos($test_file, "pcre") !== false); } + if ($test->hasSection('XLEAK')) { + $env['ZEND_ALLOC_PRINT_LEAKS'] = '0'; + if (isset($env['SKIP_ASAN'])) { + $env['LSAN_OPTIONS'] = 'detect_leaks=0'; + } + } + if ($DETAILED) { echo " CONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . " @@ -2590,49 +2632,7 @@ function run_test(string $php, $file, array $env): string $wanted_re = preg_replace('/\r\n/', "\n", $wanted); if ($test->hasSection('EXPECTF')) { - // do preg_quote, but miss out any %r delimited sections - $temp = ""; - $r = "%r"; - $startOffset = 0; - $length = strlen($wanted_re); - while ($startOffset < $length) { - $start = strpos($wanted_re, $r, $startOffset); - if ($start !== false) { - // we have found a start tag - $end = strpos($wanted_re, $r, $start + 2); - if ($end === false) { - // unbalanced tag, ignore it. - $end = $start = $length; - } - } else { - // no more %r sections - $start = $end = $length; - } - // quote a non re portion of the string - $temp .= preg_quote(substr($wanted_re, $startOffset, $start - $startOffset), '/'); - // add the re unquoted. - if ($end > $start) { - $temp .= '(' . substr($wanted_re, $start + 2, $end - $start - 2) . ')'; - } - $startOffset = $end + 2; - } - $wanted_re = $temp; - - // Stick to basics - $wanted_re = strtr($wanted_re, [ - '%e' => preg_quote(DIRECTORY_SEPARATOR, '/'), - '%s' => '[^\r\n]+', - '%S' => '[^\r\n]*', - '%a' => '.+', - '%A' => '.*', - '%w' => '\s*', - '%i' => '[+-]?\d+', - '%d' => '\d+', - '%x' => '[0-9a-fA-F]+', - '%f' => '[+-]?(?:\d+|(?=\.\d))(?:\.\d+)?(?:[Ee][+-]?\d+)?', - '%c' => '.', - '%0' => '\x00', - ]); + $wanted_re = expectf_to_regex($wanted_re); } if (preg_match('/^' . $wanted_re . '$/s', $output)) { @@ -2650,6 +2650,10 @@ function run_test(string $php, $file, array $env): string $wanted_re = null; } + if (!$passed && !$retried && $retriable && error_may_be_retried($output)) { + $retried = true; + goto retry; + } if ($passed) { if (!$cfg['keep']['php'] && !$leaked) { @@ -2677,9 +2681,13 @@ function run_test(string $php, $file, array $env): string if ($test->hasSection('XFAIL')) { $warn = true; $info = " (warn: XFAIL section but test passes)"; - } elseif ($test->hasSection('XLEAK')) { + } elseif ($test->hasSection('XLEAK') && $valgrind) { + // XLEAK with ASAN completely disables LSAN so the test is expected to pass $warn = true; $info = " (warn: XLEAK section but test passes)"; + } elseif ($retried) { + $warn = true; + $info = " (warn: Test passed on retry attempt)"; } else { show_result("PASS", $tested, $tested_file, '', $temp_filenames); $junit->markTestAs('PASS', $shortname, $tested); @@ -2714,7 +2722,8 @@ function run_test(string $php, $file, array $env): string if ($test->hasSection('XFAIL')) { $restype[] = 'XFAIL'; $info = ' XFAIL REASON: ' . rtrim($test->getSection('XFAIL')); - } elseif ($test->hasSection('XLEAK')) { + } elseif ($test->hasSection('XLEAK') && $valgrind) { + // XLEAK with ASAN completely disables LSAN so the test is expected to pass $restype[] = 'XLEAK'; $info = ' XLEAK REASON: ' . rtrim($test->getSection('XLEAK')); } else { @@ -2823,20 +2832,59 @@ function run_test(string $php, $file, array $env): string return $restype[0] . 'ED'; } -/** - * Map "Zend OPcache" to "opcache" and convert all ext names to lowercase. - */ -function remap_loaded_extensions_names(array $names): array +function error_may_be_retried(string $output): bool { - $exts = []; - foreach ($names as $name) { - if ($name === 'Core') { - continue; - } - $exts[] = ['Zend OPcache' => 'opcache'][$name] ?? strtolower($name); - } + return preg_match('((timed out)|(connection refused))i', $output) === 1; +} - return $exts; +function expectf_to_regex(?string $wanted): string +{ + $wanted_re = $wanted ?? ''; + + $wanted_re = preg_replace('/\r\n/', "\n", $wanted_re); + + // do preg_quote, but miss out any %r delimited sections + $temp = ""; + $r = "%r"; + $startOffset = 0; + $length = strlen($wanted_re); + while ($startOffset < $length) { + $start = strpos($wanted_re, $r, $startOffset); + if ($start !== false) { + // we have found a start tag + $end = strpos($wanted_re, $r, $start + 2); + if ($end === false) { + // unbalanced tag, ignore it. + $end = $start = $length; + } + } else { + // no more %r sections + $start = $end = $length; + } + // quote a non re portion of the string + $temp .= preg_quote(substr($wanted_re, $startOffset, $start - $startOffset), '/'); + // add the re unquoted. + if ($end > $start) { + $temp .= '(' . substr($wanted_re, $start + 2, $end - $start - 2) . ')'; + } + $startOffset = $end + 2; + } + $wanted_re = $temp; + + return strtr($wanted_re, [ + '%e' => preg_quote(DIRECTORY_SEPARATOR, '/'), + '%s' => '[^\r\n]+', + '%S' => '[^\r\n]*', + '%a' => '.+', + '%A' => '.*', + '%w' => '\s*', + '%i' => '[+-]?\d+', + '%d' => '\d+', + '%x' => '[0-9a-fA-F]+', + '%f' => '[+-]?(?:\d+|(?=\.\d))(?:\.\d+)?(?:[Ee][+-]?\d+)?', + '%c' => '.', + '%0' => '\x00', + ]); } /** @@ -2851,188 +2899,44 @@ function comp_line(string $l1, string $l2, bool $is_reg) return !strcmp($l1, $l2); } -function count_array_diff( - array $ar1, - array $ar2, - bool $is_reg, - array $w, - int $idx1, - int $idx2, - int $cnt1, - int $cnt2, - int $steps -): int { - $equal = 0; - - while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { - $idx1++; - $idx2++; - $equal++; - $steps--; - } - if (--$steps > 0) { - $eq1 = 0; - $st = $steps / 2; - - for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) { - $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st); - - if ($eq > $eq1) { - $eq1 = $eq; - } - } - - $eq2 = 0; - $st = $steps; - - for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) { - $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st); - if ($eq > $eq2) { - $eq2 = $eq; - } - } - - if ($eq1 > $eq2) { - $equal += $eq1; - } elseif ($eq2 > 0) { - $equal += $eq2; - } - } - - return $equal; -} - -function generate_array_diff(array $ar1, array $ar2, bool $is_reg, array $w): array +/** + * Map "Zend OPcache" to "opcache" and convert all ext names to lowercase. + */ +function remap_loaded_extensions_names(array $names): array { - global $context_line_count; - $idx1 = 0; - $cnt1 = @count($ar1); - $idx2 = 0; - $cnt2 = @count($ar2); - $diff = []; - $old1 = []; - $old2 = []; - $number_len = max(3, strlen((string)max($cnt1 + 1, $cnt2 + 1))); - $line_number_spec = '%0' . $number_len . 'd'; - - /** Mapping from $idx2 to $idx1, including indexes of idx2 that are identical to idx1 as well as entries that don't have matches */ - $mapping = []; - - while ($idx1 < $cnt1 && $idx2 < $cnt2) { - $mapping[$idx2] = $idx1; - if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { - $idx1++; - $idx2++; + $exts = []; + foreach ($names as $name) { + if ($name === 'Core') { continue; } - - $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1 + 1, $idx2, $cnt1, $cnt2, 10); - $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2 + 1, $cnt1, $cnt2, 10); - - if ($c1 > $c2) { - $old1[$idx1] = sprintf("{$line_number_spec}- ", $idx1 + 1) . $w[$idx1++]; - } elseif ($c2 > 0) { - $old2[$idx2] = sprintf("{$line_number_spec}+ ", $idx2 + 1) . $ar2[$idx2++]; - } else { - $old1[$idx1] = sprintf("{$line_number_spec}- ", $idx1 + 1) . $w[$idx1++]; - $old2[$idx2] = sprintf("{$line_number_spec}+ ", $idx2 + 1) . $ar2[$idx2++]; - } - $last_printed_context_line = $idx1; - } - $mapping[$idx2] = $idx1; - - reset($old1); - $k1 = key($old1); - $l1 = -2; - reset($old2); - $k2 = key($old2); - $l2 = -2; - $old_k1 = -1; - $add_context_lines = function (int $new_k1) use (&$old_k1, &$diff, $w, $context_line_count, $number_len) { - if ($old_k1 >= $new_k1 || !$context_line_count) { - return; - } - $end = $new_k1 - 1; - $range_end = min($end, $old_k1 + $context_line_count); - if ($old_k1 >= 0) { - while ($old_k1 < $range_end) { - $diff[] = str_repeat(' ', $number_len + 2) . $w[$old_k1++]; - } - } - if ($end - $context_line_count > $old_k1) { - $old_k1 = $end - $context_line_count; - if ($old_k1 > 0) { - // Add a '--' to mark sections where the common areas were truncated - $diff[] = '--'; - } - } - $old_k1 = max($old_k1, 0); - while ($old_k1 < $end) { - $diff[] = str_repeat(' ', $number_len + 2) . $w[$old_k1++]; - } - $old_k1 = $new_k1; - }; - - while ($k1 !== null || $k2 !== null) { - if ($k1 == $l1 + 1 || $k2 === null) { - $add_context_lines($k1); - $l1 = $k1; - $diff[] = current($old1); - $old_k1 = $k1; - $k1 = next($old1) ? key($old1) : null; - } elseif ($k2 == $l2 + 1 || $k1 === null) { - $add_context_lines($mapping[$k2]); - $l2 = $k2; - $diff[] = current($old2); - $k2 = next($old2) ? key($old2) : null; - } elseif ($k1 < $mapping[$k2]) { - $add_context_lines($k1); - $l1 = $k1; - $diff[] = current($old1); - $k1 = next($old1) ? key($old1) : null; - } else { - $add_context_lines($mapping[$k2]); - $l2 = $k2; - $diff[] = current($old2); - $k2 = next($old2) ? key($old2) : null; - } - } - - while ($idx1 < $cnt1) { - $add_context_lines($idx1 + 1); - $diff[] = sprintf("{$line_number_spec}- ", $idx1 + 1) . $w[$idx1++]; - } - - while ($idx2 < $cnt2) { - if (isset($mapping[$idx2])) { - $add_context_lines($mapping[$idx2] + 1); - } - $diff[] = sprintf("{$line_number_spec}+ ", $idx2 + 1) . $ar2[$idx2++]; - } - $add_context_lines(min($old_k1 + $context_line_count + 1, $cnt1 + 1)); - if ($context_line_count && $old_k1 < $cnt1 + 1) { - // Add a '--' to mark sections where the common areas were truncated - $diff[] = '--'; + $exts[] = ['Zend OPcache' => 'opcache'][$name] ?? strtolower($name); } - return $diff; + return $exts; } function generate_diff_external(string $diff_cmd, string $exp_file, string $output_file): string { $retval = shell_exec("{$diff_cmd} {$exp_file} {$output_file}"); - return is_string($retval) ? $retval : 'Could not run external diff tool set through PHP_TEST_DIFF_CMD environment variable'; + return is_string($retval) ? $retval : 'Could not run external diff tool set through TEST_PHP_DIFF_CMD environment variable'; } function generate_diff(string $wanted, ?string $wanted_re, string $output): string { $w = explode("\n", $wanted); $o = explode("\n", $output); - $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re); - $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w); + $is_regex = $wanted_re !== null; - return implode(PHP_EOL, $diff); + $differ = new Differ(function ($expected, $new) use ($is_regex) { + if (!$is_regex) { + return $expected === $new; + } + $regex = '/^' . expectf_to_regex($expected). '$/s'; + return preg_match($regex, $new); + }); + $result = $differ->diff($w, $o); + return $result; } function error(string $message): void @@ -4061,4 +3965,265 @@ function bless_failed_tests(array $failedTests): void proc_open($args, [], $pipes); } +/* + * BSD 3-Clause License + * + * Copyright (c) 2002-2023, Sebastian Bergmann + * All rights reserved. + * + * This file is part of sebastian/diff. + * https://github.com/sebastianbergmann/diff + */ + +final class Differ +{ + public const OLD = 0; + public const ADDED = 1; + public const REMOVED = 2; + private $outputBuilder; + private $isEqual; + + public function __construct(callable $isEqual) + { + $this->outputBuilder = new DiffOutputBuilder; + $this->isEqual = $isEqual; + } + + public function diff(array $from, array $to): string + { + $diff = $this->diffToArray($from, $to); + + return $this->outputBuilder->getDiff($diff); + } + + public function diffToArray(array $from, array $to): array + { + $fromLine = 1; + $toLine = 1; + + [$from, $to, $start, $end] = $this->getArrayDiffParted($from, $to); + + $common = $this->calculateCommonSubsequence(array_values($from), array_values($to)); + $diff = []; + + foreach ($start as $token) { + $diff[] = [$token, self::OLD]; + $fromLine++; + $toLine++; + } + + reset($from); + reset($to); + + foreach ($common as $token) { + while (!empty($from) && !($this->isEqual)(reset($from), $token)) { + $diff[] = [array_shift($from), self::REMOVED, $fromLine++]; + } + + while (!empty($to) && !($this->isEqual)($token, reset($to))) { + $diff[] = [array_shift($to), self::ADDED, $toLine++]; + } + + $diff[] = [$token, self::OLD]; + $fromLine++; + $toLine++; + + array_shift($from); + array_shift($to); + } + + while (($token = array_shift($from)) !== null) { + $diff[] = [$token, self::REMOVED, $fromLine++]; + } + + while (($token = array_shift($to)) !== null) { + $diff[] = [$token, self::ADDED, $toLine++]; + } + + foreach ($end as $token) { + $diff[] = [$token, self::OLD]; + $fromLine++; + $toLine++; + } + + return $diff; + } + + private function getArrayDiffParted(array &$from, array &$to): array + { + $start = []; + $end = []; + + reset($to); + + foreach ($from as $k => $v) { + $toK = key($to); + + if (($this->isEqual)($toK, $k) && ($this->isEqual)($v, $to[$k])) { + $start[$k] = $v; + + unset($from[$k], $to[$k]); + } else { + break; + } + } + + end($from); + end($to); + + do { + $fromK = key($from); + $toK = key($to); + + if (null === $fromK || null === $toK || !($this->isEqual)(current($from), current($to))) { + break; + } + + prev($from); + prev($to); + + $end = [$fromK => $from[$fromK]] + $end; + unset($from[$fromK], $to[$toK]); + } while (true); + + return [$from, $to, $start, $end]; + } + + public function calculateCommonSubsequence(array $from, array $to): array + { + $cFrom = count($from); + $cTo = count($to); + + if ($cFrom === 0) { + return []; + } + + if ($cFrom === 1) { + foreach ($to as $toV) { + if (($this->isEqual)($from[0], $toV)) { + return [$from[0]]; + } + } + + return []; + } + + $i = (int) ($cFrom / 2); + $fromStart = array_slice($from, 0, $i); + $fromEnd = array_slice($from, $i); + $llB = $this->commonSubsequenceLength($fromStart, $to); + $llE = $this->commonSubsequenceLength(array_reverse($fromEnd), array_reverse($to)); + $jMax = 0; + $max = 0; + + for ($j = 0; $j <= $cTo; $j++) { + $m = $llB[$j] + $llE[$cTo - $j]; + + if ($m >= $max) { + $max = $m; + $jMax = $j; + } + } + + $toStart = array_slice($to, 0, $jMax); + $toEnd = array_slice($to, $jMax); + + return array_merge( + $this->calculateCommonSubsequence($fromStart, $toStart), + $this->calculateCommonSubsequence($fromEnd, $toEnd) + ); + } + + private function commonSubsequenceLength(array $from, array $to): array + { + $current = array_fill(0, count($to) + 1, 0); + $cFrom = count($from); + $cTo = count($to); + + for ($i = 0; $i < $cFrom; $i++) { + $prev = $current; + + for ($j = 0; $j < $cTo; $j++) { + if (($this->isEqual)($from[$i], $to[$j])) { + $current[$j + 1] = $prev[$j] + 1; + } else { + $current[$j + 1] = max($current[$j], $prev[$j + 1]); + } + } + } + + return $current; + } +} + +class DiffOutputBuilder +{ + public function getDiff(array $diffs): string + { + global $context_line_count; + $i = 0; + $string = ''; + $number_len = max(3, strlen((string)count($diffs))); + $line_number_spec = '%0' . $number_len . 'd'; + $buffer = fopen('php://memory', 'r+b'); + while ($i < count($diffs)) { + // Find next difference + $next = $i; + while ($next < count($diffs)) { + if ($diffs[$next][1] !== Differ::OLD) { + break; + } + $next++; + } + // Found no more differenciating rows, we're done + if ($next === count($diffs)) { + if (($i - 1) < count($diffs)) { + fwrite($buffer, "--\n"); + } + break; + } + // Print separator if necessary + if ($i < ($next - $context_line_count)) { + fwrite($buffer, "--\n"); + $i = $next - $context_line_count; + } + // Print leading context + while ($i < $next) { + fwrite($buffer, str_repeat(' ', $number_len + 2)); + fwrite($buffer, $diffs[$i][0]); + fwrite($buffer, "\n"); + $i++; + } + // Print differences + while ($i < count($diffs) && $diffs[$i][1] !== Differ::OLD) { + fwrite($buffer, sprintf($line_number_spec, $diffs[$i][2])); + switch ($diffs[$i][1]) { + case Differ::ADDED: + fwrite($buffer, '+ '); + break; + case Differ::REMOVED: + fwrite($buffer, '- '); + break; + } + fwrite($buffer, $diffs[$i][0]); + fwrite($buffer, "\n"); + $i++; + } + // Print trailing context + $afterContext = min($i + $context_line_count, count($diffs)); + while ($i < $afterContext && $diffs[$i][1] === Differ::OLD) { + fwrite($buffer, str_repeat(' ', $number_len + 2)); + fwrite($buffer, $diffs[$i][0]); + fwrite($buffer, "\n"); + $i++; + } + } + + $diff = stream_get_contents($buffer, -1, 0); + fclose($buffer); + + return $diff; + } +} + main(); diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c index 30e05aec79ef8..a5d4e8984a5a8 100644 --- a/sapi/apache2handler/sapi_apache2.c +++ b/sapi/apache2handler/sapi_apache2.c @@ -485,7 +485,16 @@ php_apache_server_startup(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp apache2_sapi_module.php_ini_path_override = apache2_php_ini_path_override; } #ifdef ZTS - php_tsrm_startup(); + int expected_threads; +#ifdef AP_MPMQ_MAX_THREADS + if (ap_mpm_query(AP_MPMQ_MAX_THREADS, &expected_threads) != APR_SUCCESS) { + expected_threads = 1; + } +#else + expected_threads = 1; +#endif + + php_tsrm_startup_ex(expected_threads); # ifdef PHP_WIN32 ZEND_TSRMLS_CACHE_UPDATE(); # endif diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index b45468031fcd0..bf0f233118b10 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -2219,6 +2219,8 @@ consult the installation file that came with this distribution, or visit \n\ #ifdef HAVE_VALGRIND if (warmup_repeats > 0) { CALLGRIND_STOP_INSTRUMENTATION; + /* We're not interested in measuring startup */ + CALLGRIND_ZERO_STATS; } #endif } else { @@ -2427,6 +2429,12 @@ consult the installation file that came with this distribution, or visit \n\ } } /* end !cgi && !fastcgi */ +#ifdef HAVE_VALGRIND + if (warmup_repeats == 0) { + CALLGRIND_START_INSTRUMENTATION; + } +#endif + /* request startup only after we've done all we can to * get path_translated */ if (php_request_startup() == FAILURE) { @@ -2546,6 +2554,11 @@ consult the installation file that came with this distribution, or visit \n\ SG(request_info).query_string = NULL; } +#ifdef HAVE_VALGRIND + /* We're not interested in measuring shutdown */ + CALLGRIND_STOP_INSTRUMENTATION; +#endif + if (!fastcgi) { if (benchmark) { if (warmup_repeats) { @@ -2555,9 +2568,6 @@ consult the installation file that came with this distribution, or visit \n\ gettimeofday(&start, NULL); #else time(&start); -#endif -#ifdef HAVE_VALGRIND - CALLGRIND_START_INSTRUMENTATION; #endif } continue; diff --git a/sapi/cgi/tests/bug75574_utf8.phpt b/sapi/cgi/tests/bug75574_utf8.phpt index 9cbd51abfbd99..76d2d8c1f4cda 100644 --- a/sapi/cgi/tests/bug75574_utf8.phpt +++ b/sapi/cgi/tests/bug75574_utf8.phpt @@ -13,7 +13,7 @@ include "skipif.inc"; include "include.inc"; -$php = get_cgi_path(); +$php = escapeshellarg(get_cgi_path()); reset_env_vars(); $fn = __DIR__ . DIRECTORY_SEPARATOR . md5(uniqid()); diff --git a/sapi/cgi/tests/include.inc b/sapi/cgi/tests/include.inc index de526723df0f5..d155edf4ba208 100644 --- a/sapi/cgi/tests/include.inc +++ b/sapi/cgi/tests/include.inc @@ -3,12 +3,13 @@ function get_cgi_path() /* {{{ */ { $php = getenv("TEST_PHP_EXECUTABLE"); + $php_escaped = getenv("TEST_PHP_EXECUTABLE_ESCAPED"); $cli = false; $cgi = false; if (file_exists($php) && is_executable($php)) { - $version = `$php -n -v`; + $version = `$php_escaped -n -v`; if (strstr($version, "(cli)")) { /* that's cli */ $cli = true; diff --git a/sapi/cli/php.1.in b/sapi/cli/php.1.in index abf053769a815..8c41ea8656d95 100644 --- a/sapi/cli/php.1.in +++ b/sapi/cli/php.1.in @@ -1,4 +1,4 @@ -.TH @program_prefix@php 1 "2022" "The PHP Group" "Scripting Language" +.TH @program_prefix@php 1 "2023" "The PHP Group" "Scripting Language" .SH NAME @program_prefix@php \- PHP Command Line Interface 'CLI' .P diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index cc9a26c41389d..5e84ae7379cfb 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -558,16 +558,13 @@ static void cli_register_file_handles(void) php_stream_to_zval(s_err, &ec.value); Z_CONSTANT_FLAGS(ic.value) = 0; - ic.name = zend_string_init_interned("STDIN", sizeof("STDIN")-1, 0); - zend_register_constant(&ic); + zend_register_internal_constant("STDIN", sizeof("STDIN")-1, &ic); Z_CONSTANT_FLAGS(oc.value) = 0; - oc.name = zend_string_init_interned("STDOUT", sizeof("STDOUT")-1, 0); - zend_register_constant(&oc); + zend_register_internal_constant("STDOUT", sizeof("STDOUT")-1, &oc); Z_CONSTANT_FLAGS(ec.value) = 0; - ec.name = zend_string_init_interned("STDERR", sizeof("STDERR")-1, 0); - zend_register_constant(&ec); + zend_register_internal_constant("STDERR", sizeof("STDERR")-1, &ec); } static const char *param_mode_conflict = "Either execute direct code, process stdin or use a file.\n"; @@ -632,7 +629,7 @@ static int do_cli(int argc, char **argv) /* {{{ */ request_started = 1; php_print_info(PHP_INFO_ALL & ~PHP_INFO_CREDITS); php_output_end_all(); - EG(exit_status) = (c == '?' && argc > 1 && !strchr(argv[1], c)); + EG(exit_status) = 0; goto out; case 'v': /* show php version & quit */ @@ -954,9 +951,7 @@ static int do_cli(int argc, char **argv) /* {{{ */ PG(during_request_startup) = 0; switch (behavior) { case PHP_MODE_STANDARD: - if (script_file) { - cli_register_file_handles(); - } + cli_register_file_handles(); if (interactive) { EG(exit_status) = cli_shell_callbacks.cli_shell_run(); diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 4a33ca6a68261..8ea04137d1229 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -208,7 +208,7 @@ typedef struct php_cli_server_http_response_status_code_pair { const char *str; } php_cli_server_http_response_status_code_pair; -static php_cli_server_http_response_status_code_pair template_map[] = { +static const php_cli_server_http_response_status_code_pair template_map[] = { { 400, "

%s

Your browser sent a request that this server could not understand.

" }, { 404, "

%s

The requested resource %s was not found on this server.

" }, { 405, "

%s

Requested method not allowed.

" }, @@ -270,10 +270,10 @@ static bool php_cli_server_get_system_time(char *buf) { gettimeofday(&tv, NULL); - /* TODO: should be checked for NULL tm/return value */ - php_localtime_r(&tv.tv_sec, &tm); - php_asctime_r(&tm, buf); - return true; + if (!php_localtime_r(&tv.tv_sec, &tm)) { + return false; + } + return php_asctime_r(&tm, buf) != NULL; } #endif @@ -696,7 +696,7 @@ static void sapi_cli_server_register_variables(zval *track_vars_array) /* {{{ */ } } { - zend_string *tmp = strpprintf(0, "PHP %s Development Server", PHP_VERSION); + zend_string *tmp = strpprintf(0, "PHP/%s (Development Server)", PHP_VERSION); sapi_cli_server_register_known_var_str(track_vars_array, "SERVER_SOFTWARE", strlen("SERVER_SOFTWARE"), tmp); zend_string_release_ex(tmp, /* persistent */ false); } @@ -865,7 +865,6 @@ static int php_cli_server_poller_poll(php_cli_server_poller *poller, struct time return php_select(poller->max_fd + 1, &poller->active.rfds, &poller->active.wfds, NULL, tv); } /* }}} */ -// TODO Return value is unused, refactor? static zend_result php_cli_server_poller_iter_on_active(php_cli_server_poller *poller, void *opaque, zend_result(*callback)(void *, php_socket_t fd, int events)) /* {{{ */ { zend_result retval = SUCCESS; @@ -1786,8 +1785,10 @@ static int php_cli_server_client_read_request_on_message_complete(php_http_parse php_cli_server_client *client = parser->data; client->request.protocol_version = parser->http_major * 100 + parser->http_minor; php_cli_server_request_translate_vpath(&client->request, client->server->document_root, client->server->document_root_len); - { - const char *vpath = client->request.vpath, *end = vpath + client->request.vpath_len, *p = end; + if (client->request.vpath) { + const char *vpath = client->request.vpath; + const char *end = vpath + client->request.vpath_len; + const char *p = end; client->request.ext = end; client->request.ext_len = 0; while (p > vpath) { @@ -2214,10 +2215,9 @@ static void php_cli_server_request_shutdown(php_cli_server *server, php_cli_serv } /* }}} */ -// TODO Use bool, return value is strange -static int php_cli_server_dispatch_router(php_cli_server *server, php_cli_server_client *client) /* {{{ */ +static bool php_cli_server_dispatch_router(php_cli_server *server, php_cli_server_client *client) /* {{{ */ { - int decline = 0; + bool decline = false; zend_file_handle zfd; char *old_cwd; @@ -2253,7 +2253,6 @@ static int php_cli_server_dispatch_router(php_cli_server *server, php_cli_server } /* }}} */ -// TODO Return FAILURE on error? Or voidify as return value of function not checked static zend_result php_cli_server_dispatch(php_cli_server *server, php_cli_server_client *client) /* {{{ */ { int is_static_file = 0; @@ -2269,7 +2268,7 @@ static zend_result php_cli_server_dispatch(php_cli_server *server, php_cli_serve if (server->router || !is_static_file) { if (FAILURE == php_cli_server_request_startup(server, client)) { php_cli_server_request_shutdown(server, client); - return SUCCESS; + return FAILURE; } } @@ -2610,8 +2609,7 @@ static zend_result php_cli_server_recv_event_read_request(php_cli_server *server return php_cli_server_send_error_page(server, client, 501); } php_cli_server_poller_remove(&server->poller, POLLIN, client->sock); - php_cli_server_dispatch(server, client); - return SUCCESS; + return php_cli_server_dispatch(server, client); case 0: php_cli_server_poller_add(&server->poller, POLLIN, client->sock); return SUCCESS; @@ -2657,7 +2655,6 @@ typedef struct php_cli_server_do_event_for_each_fd_callback_params { zend_result(*whandler)(php_cli_server*, php_cli_server_client*); } php_cli_server_do_event_for_each_fd_callback_params; -// TODO return FAILURE on failure??? static zend_result php_cli_server_do_event_for_each_fd_callback(void *_params, php_socket_t fd, int event) /* {{{ */ { php_cli_server_do_event_for_each_fd_callback_params *params = _params; @@ -2677,12 +2674,12 @@ static zend_result php_cli_server_do_event_for_each_fd_callback(void *_params, p efree(errstr); } pefree(sa, 1); - return SUCCESS; + return FAILURE; } if (SUCCESS != php_set_sock_blocking(client_sock, 0)) { pefree(sa, 1); closesocket(client_sock); - return SUCCESS; + return FAILURE; } client = pemalloc(sizeof(php_cli_server_client), 1); @@ -2717,10 +2714,11 @@ static void php_cli_server_do_event_for_each_fd(php_cli_server *server, whandler }; - php_cli_server_poller_iter_on_active(&server->poller, ¶ms, php_cli_server_do_event_for_each_fd_callback); + if (SUCCESS != php_cli_server_poller_iter_on_active(&server->poller, ¶ms, php_cli_server_do_event_for_each_fd_callback)) { + php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "Failed to poll event"); + } } /* }}} */ -// TODO Return value of function is not used static zend_result php_cli_server_do_event_loop(php_cli_server *server) /* {{{ */ { zend_result retval = SUCCESS; @@ -2763,7 +2761,7 @@ int do_cli_server(int argc, char **argv) /* {{{ */ { char *php_optarg = NULL; int php_optind = 1; - int c; + int c, r; const char *server_bind_address = NULL; extern const opt_struct OPTIONS[]; const char *document_root = NULL; @@ -2841,6 +2839,7 @@ int do_cli_server(int argc, char **argv) /* {{{ */ sapi_module.phpinfo_as_text = 0; { + r = 0; bool ipv6 = strchr(server.host, ':'); php_cli_server_logf( PHP_CLI_SERVER_LOG_PROCESS, @@ -2859,7 +2858,9 @@ int do_cli_server(int argc, char **argv) /* {{{ */ zend_signal_init(); - php_cli_server_do_event_loop(&server); + if (SUCCESS != php_cli_server_do_event_loop(&server)) { + r = 1; + } php_cli_server_dtor(&server); - return 0; + return r; } /* }}} */ diff --git a/sapi/cli/ps_title.c b/sapi/cli/ps_title.c index a5a16f2dea125..8ff7ef719e17f 100644 --- a/sapi/cli/ps_title.c +++ b/sapi/cli/ps_title.c @@ -284,7 +284,7 @@ char** save_ps_args(int argc, char** argv) * and the init function was called. * Otherwise returns NOT_AVAILABLE or NOT_INITIALIZED */ -int is_ps_title_available() +int is_ps_title_available(void) { #ifdef PS_USE_NONE return PS_TITLE_NOT_AVAILABLE; /* disabled functionality */ diff --git a/sapi/cli/tests/001.phpt b/sapi/cli/tests/001.phpt index ede63ffb033ec..aced33623eff4 100644 --- a/sapi/cli/tests/001.phpt +++ b/sapi/cli/tests/001.phpt @@ -5,7 +5,7 @@ version string --FILE-- --EXPECT-- diff --git a/sapi/cli/tests/003.phpt b/sapi/cli/tests/003.phpt index 63e812d4a7cd7..20bf61a247bf9 100644 --- a/sapi/cli/tests/003.phpt +++ b/sapi/cli/tests/003.phpt @@ -10,7 +10,7 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { --FILE-- diff --git a/sapi/cli/tests/006.phpt b/sapi/cli/tests/006.phpt index 1f2af9c6b6358..9d693f65969b4 100644 --- a/sapi/cli/tests/006.phpt +++ b/sapi/cli/tests/006.phpt @@ -15,7 +15,7 @@ date.timezone=UTC --FILE-- --CLEAN-- diff --git a/sapi/cli/tests/011.phpt b/sapi/cli/tests/011.phpt index 24eb9fc2dfff4..bd61b260f5a94 100644 --- a/sapi/cli/tests/011.phpt +++ b/sapi/cli/tests/011.phpt @@ -5,9 +5,10 @@ syntax check --FILE-- diff --git a/sapi/cli/tests/012.phpt b/sapi/cli/tests/012.phpt index 08ec4ecb1c736..be21b3d99e87c 100644 --- a/sapi/cli/tests/012.phpt +++ b/sapi/cli/tests/012.phpt @@ -5,16 +5,16 @@ invalid arguments and error messages --FILE-- diff --git a/sapi/cli/tests/013.phpt b/sapi/cli/tests/013.phpt index 0684b8d0573cf..345a489403acc 100644 --- a/sapi/cli/tests/013.phpt +++ b/sapi/cli/tests/013.phpt @@ -10,14 +10,15 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { --FILE-- &1 | grep Usage:`; +echo `$php -n --version | grep built:`; +echo `echo "&1 | grep Usage:`; echo "Done\n"; ?> diff --git a/sapi/cli/tests/016.phpt b/sapi/cli/tests/016.phpt index c7ce07913f15b..544633f592f6d 100644 --- a/sapi/cli/tests/016.phpt +++ b/sapi/cli/tests/016.phpt @@ -11,7 +11,7 @@ if (readline_info('done') === NULL) { ?> --FILE-- $code) { echo "\n--------------\nSnippet no. $key:\n--------------\n"; $code = escapeshellarg($code); - echo `echo $code | "$php" -a`, "\n"; + echo `echo $code | $php -a`, "\n"; } echo "\nDone\n"; diff --git a/sapi/cli/tests/017.phpt b/sapi/cli/tests/017.phpt index d2d37b18589a0..6adbf195e2ee6 100644 --- a/sapi/cli/tests/017.phpt +++ b/sapi/cli/tests/017.phpt @@ -11,7 +11,7 @@ if (readline_info('done') !== NULL) { ?> --FILE-- diff --git a/sapi/cli/tests/019.phpt b/sapi/cli/tests/019.phpt index e8404d835e5e7..0f5a66c871ef2 100644 --- a/sapi/cli/tests/019.phpt +++ b/sapi/cli/tests/019.phpt @@ -10,10 +10,10 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { --FILE-- diff --git a/sapi/cli/tests/020.phpt b/sapi/cli/tests/020.phpt index fb7bcb4e7b5f6..3ccd6a83d3b37 100644 --- a/sapi/cli/tests/020.phpt +++ b/sapi/cli/tests/020.phpt @@ -10,11 +10,11 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { --FILE-- diff --git a/sapi/cli/tests/021.phpt b/sapi/cli/tests/021.phpt index 837f64109d03d..9a24ec454a989 100644 --- a/sapi/cli/tests/021.phpt +++ b/sapi/cli/tests/021.phpt @@ -7,6 +7,10 @@ if (substr(PHP_OS, 0, 3) == 'WIN') { die ("skip not for Windows"); } +if (str_contains(getenv('TEST_PHP_EXECUTABLE'), " ")) { + die("skip shebang cannot have spaces in its path"); +} + if (strlen("#!".getenv('TEST_PHP_EXECUTABLE')) > 127) { die ("skip shebang is too long, see http://www.in-ulm.de/~mascheck/various/shebang/#results"); } diff --git a/sapi/cli/tests/022.phpt b/sapi/cli/tests/022.phpt index 40c2265351842..1afb5fc371a7a 100644 --- a/sapi/cli/tests/022.phpt +++ b/sapi/cli/tests/022.phpt @@ -7,7 +7,7 @@ if (substr(PHP_OS, 0, 3) == "WIN") die("skip non windows test"); ?> --FILE-- --FILE-- array("pipe", "w"), ); $pipes = array(); -$proc = proc_open("$php -c $ini_file -r 'echo ini_get(\"memory_limit\");'", $desc, $pipes); +$proc = proc_open("$php -c $ini_file_escaped -r 'echo ini_get(\"memory_limit\");'", $desc, $pipes); if (!$proc) { exit(1); } diff --git a/sapi/cli/tests/argv_mb.phpt b/sapi/cli/tests/argv_mb.phpt index 5ed5cef34378b..f7f6dd49081b0 100644 --- a/sapi/cli/tests/argv_mb.phpt +++ b/sapi/cli/tests/argv_mb.phpt @@ -7,12 +7,13 @@ include "skipif.inc"; --FILE-- "); -var_dump(`$php -n $argv_fl 多字节字符串 マルチバイト文字列 многобайтоваястрока flerbytesträng`); +var_dump(`$php -n $argv_fl_escaped 多字节字符串 マルチバイト文字列 многобайтоваястрока flerbytesträng`); @unlink($argv_fl); diff --git a/sapi/cli/tests/bug61546.phpt b/sapi/cli/tests/bug61546.phpt index 071edb7224425..67b531472174a 100644 --- a/sapi/cli/tests/bug61546.phpt +++ b/sapi/cli/tests/bug61546.phpt @@ -11,7 +11,7 @@ Bug #61546 (functions related to current script failed when chdir() in cli sapi) // the ext/standard/tests/file/statpage.phpt test also tests getmyinode() returns an integer and will // pass even if that integer is 0. on Windows, the getmyinode() call in statpage.phpt returns 0 and // passes on Windows. -$php = getenv("TEST_PHP_EXECUTABLE"); +$php = getenv("TEST_PHP_EXECUTABLE_ESCAPED"); $test_code = << diff --git a/sapi/cli/tests/bug64529.phpt b/sapi/cli/tests/bug64529.phpt index dd7b809cfbc58..44df61020e474 100644 --- a/sapi/cli/tests/bug64529.phpt +++ b/sapi/cli/tests/bug64529.phpt @@ -18,7 +18,7 @@ if ($ret) { --FILE-- diff --git a/sapi/cli/tests/bug71624.phpt b/sapi/cli/tests/bug71624.phpt index 8b82ebab58c94..83f48cf921c5a 100644 --- a/sapi/cli/tests/bug71624.phpt +++ b/sapi/cli/tests/bug71624.phpt @@ -7,9 +7,10 @@ include "skipif.inc"; --FILE-- --FILE-- array("pipe", "w"), ); $pipes = array(); -$proc = proc_open("$php -c $ini_file -r 'echo \"okey\";'", $desc, $pipes); +$proc = proc_open("$php -c $ini_file_escaped -r 'echo \"okey\";'", $desc, $pipes); if (!$proc) { exit(1); } diff --git a/sapi/cli/tests/bug78323.phpt b/sapi/cli/tests/bug78323.phpt index 02b18e02a2141..d353281a0e866 100644 --- a/sapi/cli/tests/bug78323.phpt +++ b/sapi/cli/tests/bug78323.phpt @@ -6,7 +6,7 @@ include "skipif.inc"; ?> --FILE-- --EXPECTF-- string(%d) "string(%d) "%sphp_cli_server_002" -string(%d) "PHP %s Development Server" +string(%d) "PHP/%s (Development Server)" string(%d) "localhost" string(%d) "%s" " diff --git a/sapi/cli/tests/sapi_windows_set_ctrl_handler.phpt b/sapi/cli/tests/sapi_windows_set_ctrl_handler.phpt index 69ffb52dd63ce..3d93a82733464 100644 --- a/sapi/cli/tests/sapi_windows_set_ctrl_handler.phpt +++ b/sapi/cli/tests/sapi_windows_set_ctrl_handler.phpt @@ -24,7 +24,7 @@ if ($is_child) { while(1) usleep(100); } else { - $cmd = PHP_BINARY . " -n " . $argv[0] . " 1"; + $cmd = getenv('TEST_PHP_EXECUTABLE_ESCAPED') . " -n " . $argv[0] . " 1"; $spec = [0 => ["pipe", "r"], 1 => ["pipe", "w"]]; $proc = proc_open($cmd, $spec, $pipes, NULL, NULL, ["bypass_shell" => true, "create_process_group" => true]); diff --git a/sapi/cli/tests/upload_2G.phpt b/sapi/cli/tests/upload_2G.phpt index 6993a6776d197..1cf883cd9d3aa 100644 --- a/sapi/cli/tests/upload_2G.phpt +++ b/sapi/cli/tests/upload_2G.phpt @@ -36,10 +36,14 @@ if (getenv('TRAVIS')) { die("skip Fails intermittently on travis"); } +if (getenv('CIRRUS_CI')) die('skip Fails on Cirrus'); + if (getenv('SKIP_PERF_SENSITIVE')) { die("skip Test may be very slow if PHP is instrumented"); } ?> +--CONFLICTS-- +all --FILE-- #include - int main() + int main(void) { kern_return_t ret; clock_serv_t aClock; mach_timespec_t aTime; ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &aClock); @@ -134,7 +134,7 @@ AC_DEFUN([AC_FPM_TRACE], #define PTRACE_PEEKDATA PT_READ_D #endif - int main() + int main(void) { long v1 = (unsigned int) -1; /* copy will fail if sizeof(long) == 8 and we've got "int ptrace()" */ long v2; @@ -239,7 +239,7 @@ AC_DEFUN([AC_FPM_TRACE], #include #include #include - int main() + int main(void) { long v1 = (unsigned int) -1, v2 = 0; char buf[128]; @@ -578,7 +578,7 @@ if test "$PHP_FPM" != "no"; then AC_CHECK_HEADERS([sys/acl.h]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include - int main() + int main(void) { acl_t acl; acl_entry_t user, group; @@ -597,7 +597,7 @@ if test "$PHP_FPM" != "no"; then AC_MSG_RESULT([yes]) ],[ AC_RUN_IFELSE([AC_LANG_SOURCE([[#include - int main() + int main(void) { acl_t acl; acl_entry_t user, group; diff --git a/sapi/fpm/fpm/fpm.c b/sapi/fpm/fpm/fpm.c index 30cb9da010bf1..cb86f403b89c9 100644 --- a/sapi/fpm/fpm/fpm.c +++ b/sapi/fpm/fpm/fpm.c @@ -41,7 +41,7 @@ struct fpm_globals_s fpm_globals = { .send_config_pipe = {0, 0}, }; -int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon, int force_stderr) /* {{{ */ +enum fpm_init_return_status fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon, int force_stderr) /* {{{ */ { fpm_globals.argc = argc; fpm_globals.argv = argv; @@ -67,22 +67,22 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int t 0 > fpm_event_init_main()) { if (fpm_globals.test_successful) { - exit(FPM_EXIT_OK); + return FPM_INIT_EXIT_OK; } else { zlog(ZLOG_ERROR, "FPM initialization failed"); - return -1; + return FPM_INIT_ERROR; } } if (0 > fpm_conf_write_pid()) { zlog(ZLOG_ERROR, "FPM initialization failed"); - return -1; + return FPM_INIT_ERROR; } fpm_stdio_init_final(); zlog(ZLOG_NOTICE, "fpm is running, pid %d", (int) fpm_globals.parent_pid); - return 0; + return FPM_INIT_CONTINUE; } /* }}} */ diff --git a/sapi/fpm/fpm/fpm.h b/sapi/fpm/fpm/fpm.h index f0610ca46dc62..ec036a2d68198 100644 --- a/sapi/fpm/fpm/fpm.h +++ b/sapi/fpm/fpm/fpm.h @@ -34,8 +34,14 @@ #endif +enum fpm_init_return_status { + FPM_INIT_ERROR, + FPM_INIT_CONTINUE, + FPM_INIT_EXIT_OK, +}; + int fpm_run(int *max_requests); -int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon, int force_stderr); +enum fpm_init_return_status fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root, int force_daemon, int force_stderr); struct fpm_globals_s { pid_t parent_pid; diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c index 6a5787c7ec8d4..2f8e3dc4d0acc 100644 --- a/sapi/fpm/fpm/fpm_children.c +++ b/sapi/fpm/fpm/fpm_children.c @@ -297,8 +297,10 @@ void fpm_children_bury(void) break; } } + } else if (fpm_globals.parent_pid == 1) { + zlog(ZLOG_DEBUG, "unknown child (%d) exited %s - most likely an orphan process (master process is the init process)", pid, buf); } else { - zlog(ZLOG_ALERT, "oops, unknown child (%d) exited %s. Please open a bug report (https://github.com/php/php-src/issues).", pid, buf); + zlog(ZLOG_WARNING, "unknown child (%d) exited %s - potentially a bug or pre exec child (e.g. s6-notifyoncheck)", pid, buf); } } } diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c index a4be6b22161e0..8f7548a402c23 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -34,6 +34,7 @@ #include "fpm_status.h" #include "fpm_log.h" #include "fpm_events.h" +#include "fpm_unix.h" #include "zlog.h" #ifdef HAVE_SYSTEMD #include "fpm_systemd.h" @@ -83,7 +84,7 @@ static char *ini_include = NULL; /* * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in */ -static struct ini_value_parser_s ini_fpm_global_options[] = { +static const struct ini_value_parser_s ini_fpm_global_options[] = { { "pid", &fpm_conf_set_string, GO(pid_file) }, { "error_log", &fpm_conf_set_string, GO(error_log) }, #ifdef HAVE_SYSLOG_H @@ -111,7 +112,7 @@ static struct ini_value_parser_s ini_fpm_global_options[] = { /* * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in */ -static struct ini_value_parser_s ini_fpm_pool_options[] = { +static const struct ini_value_parser_s ini_fpm_pool_options[] = { { "prefix", &fpm_conf_set_string, WPO(prefix) }, { "user", &fpm_conf_set_string, WPO(user) }, { "group", &fpm_conf_set_string, WPO(group) }, @@ -1182,11 +1183,10 @@ static int fpm_conf_process_all_pools(void) /* env[], php_value[], php_admin_values[] */ if (!wp->config->chroot) { struct key_value_s *kv; - char *options[] = FPM_PHP_INI_TO_EXPAND; - char **p; + static const char *const options[] = FPM_PHP_INI_TO_EXPAND; for (kv = wp->config->php_values; kv; kv = kv->next) { - for (p = options; *p; p++) { + for (const char *const*p = options; *p; p++) { if (!strcasecmp(kv->key, *p)) { fpm_evaluate_full_path(&kv->value, wp, NULL, 0); } @@ -1196,7 +1196,7 @@ static int fpm_conf_process_all_pools(void) if (!strcasecmp(kv->key, "error_log") && !strcasecmp(kv->value, "syslog")) { continue; } - for (p = options; *p; p++) { + for (const char *const*p = options; *p; p++) { if (!strcasecmp(kv->key, *p)) { fpm_evaluate_full_path(&kv->value, wp, NULL, 0); } @@ -1463,7 +1463,7 @@ static void fpm_conf_ini_parser_section(zval *section, void *arg) /* {{{ */ static void fpm_conf_ini_parser_entry(zval *name, zval *value, void *arg) /* {{{ */ { - struct ini_value_parser_s *parser; + const struct ini_value_parser_s *parser; void *config = NULL; int *error = (int *)arg; @@ -1868,10 +1868,16 @@ int fpm_conf_init_main(int test_conf, int force_daemon) /* {{{ */ } if (test_conf) { + for (struct fpm_worker_pool_s *wp = fpm_worker_all_pools; wp; wp = wp->next) { + if (!fpm_unix_test_config(wp)) { + return -1; + } + } + if (test_conf > 1) { fpm_conf_dump(); } - zlog(ZLOG_NOTICE, "configuration file %s test is successful\n", fpm_globals.config); + zlog(ZLOG_NOTICE, "configuration file %s test is successful", fpm_globals.config); fpm_globals.test_successful = 1; return -1; } diff --git a/sapi/fpm/fpm/fpm_env.c b/sapi/fpm/fpm/fpm_env.c index 72ed1aa94d383..9771a5747396e 100644 --- a/sapi/fpm/fpm/fpm_env.c +++ b/sapi/fpm/fpm/fpm_env.c @@ -11,6 +11,7 @@ #include "fpm_env.h" #include "fpm.h" +#include "fpm_cleanup.h" #ifndef HAVE_SETPROCTITLE #if defined(__linux__) || defined(__APPLE__) @@ -194,6 +195,26 @@ static int fpm_env_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ } /* }}} */ + +#ifndef HAVE_SETPROCTITLE +#if defined(__linux__) || defined(__APPLE__) +/* Frees our copied environment variables. */ +static void fpm_env_cleanup(int which, void *arg) /* {{{ */ +{ + char** allocated_environ = environ; + if (allocated_environ) { + environ = NULL; + unsigned int i = 0; + while (allocated_environ[i]) { + free(allocated_environ[i]); + i++; + } + free(allocated_environ); + } +} +#endif +#endif + int fpm_env_init_main(void) { struct fpm_worker_pool_s *wp; @@ -254,6 +275,10 @@ int fpm_env_init_main(void) env_nb++; } + if (0 > fpm_cleanup_add(FPM_CLEANUP_PARENT_EXIT_MAIN, fpm_env_cleanup, 0)) { + return -1; + } + if ((new_environ = malloc((1U + env_nb) * sizeof (char *))) == NULL) { return -1; } diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index a8d77ef3bed21..7ef0372c08ef1 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -149,6 +149,7 @@ typedef struct _php_cgi_globals_struct { bool force_redirect; bool discard_path; bool fcgi_logging; + bool fcgi_logging_request_started; char *redirect_status_env; HashTable user_config_cache; char *error_header; @@ -598,11 +599,16 @@ void sapi_cgi_log_fastcgi(int level, char *message, size_t len) * - logging is enabled (fastcgi.logging in php.ini) * - we are currently dealing with a request * - the message is not empty - * - the fcgi_write did not fail */ - if (CGIG(fcgi_logging) && request && message && len > 0 - && fcgi_write(request, FCGI_STDERR, message, len) < 0) { - php_handle_aborted_connection(); + if (CGIG(fcgi_logging) && request && message && len > 0) { + if (CGIG(fcgi_logging_request_started)) { + fcgi_write(request, FCGI_STDERR, "; ", 2); + } else { + CGIG(fcgi_logging_request_started) = true; + } + if (fcgi_write(request, FCGI_STDERR, message, len) < 0) { + php_handle_aborted_connection(); + } } } /* }}} */ @@ -1155,12 +1161,32 @@ static void init_request_info(void) * As we can extract PATH_INFO from PATH_TRANSLATED * it is probably also in SCRIPT_NAME and need to be removed */ - int snlen = strlen(env_script_name); - if (snlen>slen && !strcmp(env_script_name+snlen-slen, path_info)) { + char *decoded_path_info = NULL; + size_t decoded_path_info_len = 0; + if (strchr(path_info, '%')) { + decoded_path_info = estrdup(path_info); + decoded_path_info_len = php_url_decode(decoded_path_info, strlen(path_info)); + } + size_t snlen = strlen(env_script_name); + size_t env_script_file_info_start = 0; + if ( + ( + snlen > slen && + !strcmp(env_script_name + (env_script_file_info_start = snlen - slen), path_info) + ) || + ( + decoded_path_info && + snlen > decoded_path_info_len && + !strcmp(env_script_name + (env_script_file_info_start = snlen - decoded_path_info_len), decoded_path_info) + ) + ) { FCGI_PUTENV(request, "ORIG_SCRIPT_NAME", orig_script_name); - env_script_name[snlen-slen] = 0; + env_script_name[env_script_file_info_start] = 0; SG(request_info).request_uri = FCGI_PUTENV(request, "SCRIPT_NAME", env_script_name); } + if (decoded_path_info) { + efree(decoded_path_info); + } } env_path_info = FCGI_PUTENV(request, "PATH_INFO", path_info); } @@ -1403,6 +1429,7 @@ static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals) php_cgi_globals->fix_pathinfo = 1; php_cgi_globals->discard_path = 0; php_cgi_globals->fcgi_logging = 1; + php_cgi_globals->fcgi_logging_request_started = false; zend_hash_init(&php_cgi_globals->user_config_cache, 0, NULL, user_config_cache_entry_dtor, 1); php_cgi_globals->error_header = NULL; php_cgi_globals->fpm_config = NULL; @@ -1530,7 +1557,6 @@ int main(int argc, char *argv[]) int force_stderr = 0; int php_information = 0; int php_allow_to_run_as_root = 0; - int ret; #if ZEND_RC_DEBUG bool old_rc_debug; #endif @@ -1777,21 +1803,24 @@ consult the installation file that came with this distribution, or visit \n\ zend_rc_debug = 0; #endif - ret = fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr); + enum fpm_init_return_status ret = fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr); #if ZEND_RC_DEBUG zend_rc_debug = old_rc_debug; #endif - if (ret < 0) { - + if (ret == FPM_INIT_ERROR) { if (fpm_globals.send_config_pipe[1]) { int writeval = 0; zlog(ZLOG_DEBUG, "Sending \"0\" (error) to parent via fd=%d", fpm_globals.send_config_pipe[1]); zend_quiet_write(fpm_globals.send_config_pipe[1], &writeval, sizeof(writeval)); close(fpm_globals.send_config_pipe[1]); } - return FPM_EXIT_CONFIG; + exit_status = FPM_EXIT_CONFIG; + goto out; + } else if (ret == FPM_INIT_EXIT_OK) { + exit_status = FPM_EXIT_OK; + goto out; } if (fpm_globals.send_config_pipe[1]) { @@ -1820,6 +1849,7 @@ consult the installation file that came with this distribution, or visit \n\ char *primary_script = NULL; request_body_fd = -1; SG(server_context) = (void *) request; + CGIG(fcgi_logging_request_started) = false; init_request_info(); fpm_request_info(); @@ -1888,8 +1918,18 @@ consult the installation file that came with this distribution, or visit \n\ fpm_request_executing(); + /* Reset exit status from the previous execution */ + EG(exit_status) = 0; + php_execute_script(&file_handle); + /* Without opcache, or the first time with opcache, the file handle will be placed + * in the CG(open_files) list by open_file_for_scanning(). Starting from the second + * request in opcache, the file handle won't be in the list and therefore won't be destroyed for us. */ + if (!file_handle.in_list) { + zend_destroy_file_handle(&file_handle); + } + fastcgi_request_done: if (EXPECTED(primary_script)) { efree(primary_script); diff --git a/sapi/fpm/fpm/fpm_php_trace.c b/sapi/fpm/fpm/fpm_php_trace.c index 0e1d8e3f6cee0..b1535b26e3ef8 100644 --- a/sapi/fpm/fpm/fpm_php_trace.c +++ b/sapi/fpm/fpm/fpm_php_trace.c @@ -39,15 +39,14 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog) /* {{{ * int callers_limit = child->wp->config->request_slowlog_trace_depth; pid_t pid = child->pid; struct timeval tv; - static const int buf_size = 1024; - char buf[buf_size]; + char buf[1024]; long execute_data; long path_translated; long l; gettimeofday(&tv, 0); - zlog_print_time(&tv, buf, buf_size); + zlog_print_time(&tv, buf, sizeof(buf)); fprintf(slowlog, "\n%s [pool %s] pid %d\n", buf, child->wp->config->name, (int) pid); @@ -57,7 +56,7 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog) /* {{{ * path_translated = l; - if (0 > fpm_trace_get_strz(buf, buf_size, path_translated)) { + if (0 > fpm_trace_get_strz(buf, sizeof(buf), path_translated)) { return -1; } @@ -103,7 +102,7 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog) /* {{{ * ZEND_UNREACHABLE(); } } else { - if (0 > fpm_trace_get_strz(buf, buf_size, function_name + offsetof(zend_string, val))) { + if (0 > fpm_trace_get_strz(buf, sizeof(buf), function_name + offsetof(zend_string, val))) { return -1; } @@ -149,7 +148,7 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog) /* {{{ * file_name = l; - if (0 > fpm_trace_get_strz(buf, buf_size, file_name + offsetof(zend_string, val))) { + if (0 > fpm_trace_get_strz(buf, sizeof(buf), file_name + offsetof(zend_string, val))) { return -1; } diff --git a/sapi/fpm/fpm/fpm_signals.c b/sapi/fpm/fpm/fpm_signals.c index 6aad4403768cf..aca7c9ed58cc4 100644 --- a/sapi/fpm/fpm/fpm_signals.c +++ b/sapi/fpm/fpm/fpm_signals.c @@ -267,7 +267,7 @@ int fpm_signals_init_mask(void) /* Subset of signals from fpm_signals_init_main() and fpm_got_signal() blocked to avoid unexpected death during early init or during reload just after execvp() or fork */ - int init_signal_array[] = { SIGUSR1, SIGUSR2, SIGCHLD }; + static const int init_signal_array[] = { SIGUSR1, SIGUSR2, SIGCHLD }; size_t size = sizeof(init_signal_array)/sizeof(init_signal_array[0]); size_t i = 0; if (0 > sigemptyset(&block_sigset) || diff --git a/sapi/fpm/fpm/fpm_sockets.c b/sapi/fpm/fpm/fpm_sockets.c index 66488b9bf000e..b532e68b9d304 100644 --- a/sapi/fpm/fpm/fpm_sockets.c +++ b/sapi/fpm/fpm/fpm_sockets.c @@ -313,7 +313,7 @@ static int fpm_socket_af_inet_socket_by_addr(struct fpm_worker_pool_s *wp, const hints.ai_socktype = SOCK_STREAM; if ((status = getaddrinfo(addr, port, &hints, &servinfo)) != 0) { - zlog(ZLOG_ERROR, "getaddrinfo: %s\n", gai_strerror(status)); + zlog(ZLOG_ERROR, "getaddrinfo: %s", gai_strerror(status)); return -1; } diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c index 514d60d176e39..e78cbeab1105a 100644 --- a/sapi/fpm/fpm/fpm_status.c +++ b/sapi/fpm/fpm/fpm_status.c @@ -171,7 +171,7 @@ int fpm_status_handle_request(void) /* {{{ */ fpm_request_executing(); /* full status ? */ - _GET_str = zend_string_init("_GET", sizeof("_GET")-1, 0); + _GET_str = ZSTR_INIT_LITERAL("_GET", 0); full = (fpm_php_get_string_from_table(_GET_str, "full") != NULL); short_syntax = short_post = NULL; full_separator = full_pre = full_syntax = full_post = NULL; diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c index 46cf4aaa2851d..a6c0793d9347e 100644 --- a/sapi/fpm/fpm/fpm_stdio.c +++ b/sapi/fpm/fpm/fpm_stdio.c @@ -168,9 +168,8 @@ int fpm_stdio_flush_child(void) static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg) /* {{{ */ { - static const int max_buf_size = 1024; int fd = ev->fd; - char buf[max_buf_size]; + char buf[1024]; struct fpm_child_s *child; int is_stdout; struct fpm_event_s *event; @@ -219,7 +218,7 @@ static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg) while (1) { stdio_read: - in_buf = read(fd, buf, max_buf_size - 1); + in_buf = read(fd, buf, sizeof(buf) - 1); if (in_buf <= 0) { /* no data */ if (in_buf == 0 || !PHP_IS_TRANSIENT_ERROR(errno)) { /* pipe is closed or error */ diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c index b1127b35949d3..d10a6f3254b24 100644 --- a/sapi/fpm/fpm/fpm_unix.c +++ b/sapi/fpm/fpm/fpm_unix.c @@ -46,6 +46,55 @@ size_t fpm_pagesize; + +static inline bool fpm_unix_is_id(const char* name) +{ + return strlen(name) == strspn(name, "0123456789"); +} + +static struct passwd *fpm_unix_get_passwd(struct fpm_worker_pool_s *wp, const char *name, int flags) +{ + struct passwd *pwd = getpwnam(name); + if (!pwd) { + zlog(flags, "[pool %s] cannot get uid for user '%s'", wp->config->name, name); + return NULL; + } + + return pwd; +} + +static inline bool fpm_unix_check_passwd(struct fpm_worker_pool_s *wp, const char *name, int flags) +{ + return !name || fpm_unix_is_id(name) || fpm_unix_get_passwd(wp, name, flags); +} + +static struct group *fpm_unix_get_group(struct fpm_worker_pool_s *wp, const char *name, int flags) +{ + struct group *group = getgrnam(name); + if (!group) { + zlog(flags, "[pool %s] cannot get gid for group '%s'", wp->config->name, name); + return NULL; + } + + return group; +} + +static inline bool fpm_unix_check_group(struct fpm_worker_pool_s *wp, const char *name, int flags) +{ + return !name || fpm_unix_is_id(name) || fpm_unix_get_group(wp, name, flags); +} + +bool fpm_unix_test_config(struct fpm_worker_pool_s *wp) +{ + struct fpm_worker_pool_config_s *config = wp->config; + return ( + fpm_unix_check_passwd(wp, config->user, ZLOG_ERROR) && + fpm_unix_check_group(wp, config->group, ZLOG_ERROR) && + fpm_unix_check_passwd(wp, config->listen_owner, ZLOG_SYSERROR) && + fpm_unix_check_group(wp, config->listen_group, ZLOG_SYSERROR) + ); +} + int fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s *wp) /* {{{ */ { struct fpm_worker_pool_config_s *c = wp->config; @@ -105,11 +154,10 @@ int fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s *wp) /* {{{ */ if ((end = strchr(p, ','))) { *end++ = 0; } - pwd = getpwnam(p); + pwd = fpm_unix_get_passwd(wp, p, ZLOG_SYSERROR); if (pwd) { zlog(ZLOG_DEBUG, "[pool %s] user '%s' have uid=%d", wp->config->name, p, pwd->pw_uid); } else { - zlog(ZLOG_SYSERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, p); acl_free(acl); efree(tmp); return -1; @@ -138,11 +186,10 @@ int fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s *wp) /* {{{ */ if ((end = strchr(p, ','))) { *end++ = 0; } - grp = getgrnam(p); + grp = fpm_unix_get_group(wp, p, ZLOG_SYSERROR); if (grp) { zlog(ZLOG_DEBUG, "[pool %s] group '%s' have gid=%d", wp->config->name, p, grp->gr_gid); } else { - zlog(ZLOG_SYSERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, p); acl_free(acl); efree(tmp); return -1; @@ -175,14 +222,13 @@ int fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s *wp) /* {{{ */ #endif if (c->listen_owner && *c->listen_owner) { - if (strlen(c->listen_owner) == strspn(c->listen_owner, "0123456789")) { + if (fpm_unix_is_id(c->listen_owner)) { wp->socket_uid = strtoul(c->listen_owner, 0, 10); } else { struct passwd *pwd; - pwd = getpwnam(c->listen_owner); + pwd = fpm_unix_get_passwd(wp, c->listen_owner, ZLOG_SYSERROR); if (!pwd) { - zlog(ZLOG_SYSERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, c->listen_owner); return -1; } @@ -192,14 +238,13 @@ int fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s *wp) /* {{{ */ } if (c->listen_group && *c->listen_group) { - if (strlen(c->listen_group) == strspn(c->listen_group, "0123456789")) { + if (fpm_unix_is_id(c->listen_group)) { wp->socket_gid = strtoul(c->listen_group, 0, 10); } else { struct group *grp; - grp = getgrnam(c->listen_group); + grp = fpm_unix_get_group(wp, c->listen_group, ZLOG_SYSERROR); if (!grp) { - zlog(ZLOG_SYSERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, c->listen_group); return -1; } wp->socket_gid = grp->gr_gid; @@ -279,7 +324,7 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ if (is_root) { if (wp->config->user && *wp->config->user) { - if (strlen(wp->config->user) == strspn(wp->config->user, "0123456789")) { + if (fpm_unix_is_id(wp->config->user)) { wp->set_uid = strtoul(wp->config->user, 0, 10); pwd = getpwuid(wp->set_uid); if (pwd) { @@ -289,9 +334,8 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ } else { struct passwd *pwd; - pwd = getpwnam(wp->config->user); + pwd = fpm_unix_get_passwd(wp, wp->config->user, ZLOG_ERROR); if (!pwd) { - zlog(ZLOG_ERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, wp->config->user); return -1; } @@ -304,14 +348,13 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ } if (wp->config->group && *wp->config->group) { - if (strlen(wp->config->group) == strspn(wp->config->group, "0123456789")) { + if (fpm_unix_is_id(wp->config->group)) { wp->set_gid = strtoul(wp->config->group, 0, 10); } else { struct group *grp; - grp = getgrnam(wp->config->group); + grp = fpm_unix_get_group(wp, wp->config->group, ZLOG_ERROR); if (!grp) { - zlog(ZLOG_ERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, wp->config->group); return -1; } wp->set_gid = grp->gr_gid; diff --git a/sapi/fpm/fpm/fpm_unix.h b/sapi/fpm/fpm/fpm_unix.h index 0bb22687b02f9..6fc9e5e8450dc 100644 --- a/sapi/fpm/fpm/fpm_unix.h +++ b/sapi/fpm/fpm/fpm_unix.h @@ -5,6 +5,8 @@ #include "fpm_worker_pool.h" +bool fpm_unix_test_config(struct fpm_worker_pool_s *wp); + int fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s *wp); int fpm_unix_set_socket_permissions(struct fpm_worker_pool_s *wp, const char *path); int fpm_unix_free_socket_permissions(struct fpm_worker_pool_s *wp); diff --git a/sapi/fpm/php-fpm.8.in b/sapi/fpm/php-fpm.8.in index b972a2bdd031e..e8bbfa7aafba2 100644 --- a/sapi/fpm/php-fpm.8.in +++ b/sapi/fpm/php-fpm.8.in @@ -1,4 +1,4 @@ -.TH PHP-FPM 8 "2022" "The PHP Group" "Scripting Language" +.TH PHP-FPM 8 "2023" "The PHP Group" "Scripting Language" .SH NAME .TP 15 php-fpm \- PHP FastCGI Process Manager 'PHP-FPM' diff --git a/sapi/fpm/status.html.in b/sapi/fpm/status.html.in index d3b6d5efd3e59..b87a446f59f66 100644 --- a/sapi/fpm/status.html.in +++ b/sapi/fpm/status.html.in @@ -215,7 +215,7 @@ doc_rate.disabled = false; } else { delay = parseInt(doc_rate.value); - if (!delay || delay < 1) { + if (isNaN(delay) || delay < 1) { doc_status.innerHTML = "Not valid 'refresh' value"; return; } diff --git a/sapi/fpm/tests/bug68591-conf-test-group.phpt b/sapi/fpm/tests/bug68591-conf-test-group.phpt new file mode 100644 index 0000000000000..d496d0549e87f --- /dev/null +++ b/sapi/fpm/tests/bug68591-conf-test-group.phpt @@ -0,0 +1,39 @@ +--TEST-- +FPM: bug68591 - config test group existence +--SKIPIF-- + +--FILE-- +testConfig(); + +?> +Done +--EXPECT-- +ERROR: [pool unconfined] cannot get gid for group 'aaaaaa' +ERROR: FPM initialization failed +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/bug68591-conf-test-listen-group.phpt b/sapi/fpm/tests/bug68591-conf-test-listen-group.phpt new file mode 100644 index 0000000000000..71ca71adf8316 --- /dev/null +++ b/sapi/fpm/tests/bug68591-conf-test-listen-group.phpt @@ -0,0 +1,39 @@ +--TEST-- +FPM: bug68591 - config test listen group existence +--SKIPIF-- + +--FILE-- +testConfig(); + +?> +Done +--EXPECTF-- +ERROR: [pool unconfined] cannot get gid for group 'aaaaaa': %s +ERROR: FPM initialization failed +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/bug68591-conf-test-listen-owner.phpt b/sapi/fpm/tests/bug68591-conf-test-listen-owner.phpt new file mode 100644 index 0000000000000..c6108bcddeb68 --- /dev/null +++ b/sapi/fpm/tests/bug68591-conf-test-listen-owner.phpt @@ -0,0 +1,39 @@ +--TEST-- +FPM: bug68591 - config test listen owner existence +--SKIPIF-- + +--FILE-- +testConfig(); + +?> +Done +--EXPECTF-- +ERROR: [pool unconfined] cannot get uid for user 'aaaaaa': %s +ERROR: FPM initialization failed +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/bug68591-conf-test-user.phpt b/sapi/fpm/tests/bug68591-conf-test-user.phpt new file mode 100644 index 0000000000000..5627151f3f13e --- /dev/null +++ b/sapi/fpm/tests/bug68591-conf-test-user.phpt @@ -0,0 +1,38 @@ +--TEST-- +FPM: bug68591 - config test user existence +--SKIPIF-- + +--FILE-- +testConfig(); + +?> +Done +--EXPECT-- +ERROR: [pool unconfined] cannot get uid for user 'aaaaaa' +ERROR: FPM initialization failed +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/bug77106-fcgi-missing-nl.phpt b/sapi/fpm/tests/bug77106-fcgi-missing-nl.phpt new file mode 100644 index 0000000000000..c4c7adf382545 --- /dev/null +++ b/sapi/fpm/tests/bug77106-fcgi-missing-nl.phpt @@ -0,0 +1,46 @@ +--TEST-- +FPM: bug77106 - Missing new lines in FCGI error stream +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +$tester->request()->expectErrorPattern( + '/Undefined variable \$a in .+ on line \d+; PHP message: PHP Warning:/' +); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-nopif-apache-handler-with-pi-with-pt-pd.phpt b/sapi/fpm/tests/fcgi-env-nopif-apache-handler-with-pi-with-pt-pd.phpt new file mode 100644 index 0000000000000..a2aa4164fc3bc --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-nopif-apache-handler-with-pi-with-pt-pd.phpt @@ -0,0 +1,58 @@ +--TEST-- +FPM: FastCGI env var without path info fix for Apache handler with PATH_INFO, PATH_TRANSLATED and path discard +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => '/pinfo', + 'PATH_TRANSLATED' => __DIR__ . '/pinfo', + ], + uri: $scriptName . '/pinfo', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . $sourceFilePath, + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, '/pinfo', '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-with-pt-pd.phpt b/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-with-pt-pd.phpt new file mode 100644 index 0000000000000..40b1edc8a930f --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-with-pt-pd.phpt @@ -0,0 +1,58 @@ +--TEST-- +FPM: FastCGI env var no path info fix for custom setup with PATH_INFO, PATH_TRANSLATED and path discard +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => '/pinfo', + 'PATH_TRANSLATED' => __DIR__, + ], + uri: $scriptName . '/pinfo', + scriptFilename: $sourceFilePath, + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, '/pinfo', '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-with-pt.phpt b/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-with-pt.phpt new file mode 100644 index 0000000000000..d68173920eb4c --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-with-pt.phpt @@ -0,0 +1,58 @@ +--TEST-- +FPM: FastCGI env var no path info fix for custom setup with PATH_INFO and PATH_TRANSLATED +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => '/pinfo', + 'PATH_TRANSLATED' => $sourceFilePath, + ], + uri: $scriptName . '/pinfo', + scriptFilename: $sourceFilePath . '/pinfo', // used just for variable display + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath . '/pinfo', '/pinfo', '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-without-pt.phpt b/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-without-pt.phpt new file mode 100644 index 0000000000000..84255f9737a21 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-nopif-custom-with-pi-without-pt.phpt @@ -0,0 +1,56 @@ +--TEST-- +FPM: FastCGI env var no path info fix for custom setup with PATH_INFO and without PATH_TRANSLATED +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => '/pinfo', + ], + uri: $scriptName . '/pinfo', + scriptFilename: $sourceFilePath, + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, '/pinfo', '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-nopif-custom-without-pi-with-pt.phpt b/sapi/fpm/tests/fcgi-env-nopif-custom-without-pi-with-pt.phpt new file mode 100644 index 0000000000000..f580b25804e4e --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-nopif-custom-without-pi-with-pt.phpt @@ -0,0 +1,56 @@ +--TEST-- +FPM: FastCGI env var no path info fix for custom setup without PATH_INFO and with PATH_TRANSLATED +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_TRANSLATED' => $sourceFilePath, + ], + uri: $scriptName . '/pinfo', + scriptFilename: $sourceFilePath . '/pinfo', // should be ignored as PATH_TRANSLATED is used + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath . '/pinfo', $scriptName]); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-nopif-custom-without-pi-without-pt.phpt b/sapi/fpm/tests/fcgi-env-nopif-custom-without-pi-without-pt.phpt new file mode 100644 index 0000000000000..b0ed4ad750290 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-nopif-custom-without-pi-without-pt.phpt @@ -0,0 +1,52 @@ +--TEST-- +FPM: FastCGI env var no path info fix for custom setup without PATH_INFO and PATH_TRANSLATED +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + uri: $scriptName . '/pinfo', + scriptFilename: $sourceFilePath, + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, $scriptName]); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-nopif-custom-without-sf-with-pt.phpt b/sapi/fpm/tests/fcgi-env-nopif-custom-without-sf-with-pt.phpt new file mode 100644 index 0000000000000..3e602e2f18825 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-nopif-custom-without-sf-with-pt.phpt @@ -0,0 +1,58 @@ +--TEST-- +FPM: FastCGI env var no path info fix for custom setup without SCRIPT_FILENAME and with PATH_TRANSLATED +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => '/pinfo', + 'PATH_TRANSLATED' => $sourceFilePath, + ], + uri: $scriptName . '/pinfo', + scriptFilename: '', + scriptName: $scriptName, + ) + ->expectBody([$scriptName, 'unset', '/pinfo', '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-balancer-legacy.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-balancer-legacy.phpt new file mode 100644 index 0000000000000..a7c4c2e6208b5 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-balancer-legacy.phpt @@ -0,0 +1,57 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache balancer legacy setup +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => '/pinfo', + 'PATH_TRANSLATED' => __DIR__ . '/pinfo', + ], + uri: $scriptName . '/pinfo', + scriptFilename: "proxy:balancer://" . $tester->getAddr() . $sourceFilePath, + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, '/pinfo', $scriptName . '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-balancer-real.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-balancer-real.phpt new file mode 100644 index 0000000000000..df8df4a8fb042 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-balancer-real.phpt @@ -0,0 +1,58 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache balancer real configuration +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$pathTranslatedPart = __DIR__ . $sourceFilePath . '/pinfo'; +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => $sourceFilePath . '/pinfo', + 'PATH_TRANSLATED' => 'proxy:balancer://myappcluster' . $pathTranslatedPart . $pathTranslatedPart, + ], + uri: $scriptName . '/pinfo', + scriptFilename: $sourceFilePath . '/pinfo', + scriptName: '', + ) + ->expectBody([$sourceFilePath, $sourceFilePath, '/pinfo', $sourceFilePath . '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-handler-uds.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-handler-uds.phpt new file mode 100644 index 0000000000000..b80fdef3ffdf6 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-handler-uds.phpt @@ -0,0 +1,53 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache handler using Unix Domain Socket +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + uri: $scriptName, + address: '{{ADDR:UDS}}', + scriptFilename: "proxy:fcgi://localhost" . $sourceFilePath, + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, $scriptName]); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-handler-with-pi.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-handler-with-pi.phpt new file mode 100644 index 0000000000000..2d8433123cb2d --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-handler-with-pi.phpt @@ -0,0 +1,57 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache handler with PATH_INFO set +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => '/pinfo', + 'PATH_TRANSLATED' => __DIR__ . '/pinfo', + ], + uri: $scriptName . '/pinfo', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . $sourceFilePath, + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, '/pinfo', $scriptName . '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-handler-with-query.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-handler-with-query.phpt new file mode 100644 index 0000000000000..1b1ad05fa5693 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-handler-with-query.phpt @@ -0,0 +1,58 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache handler basic +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + query: 'q=1', + headers: [ + 'PATH_INFO' => '/pinfo', + 'PATH_TRANSLATED' => __DIR__ . '/pinfo', + ], + uri: $scriptName . '/pinfo', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . $sourceFilePath . '?q=1', + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, '/pinfo', $scriptName . '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-handler-without-docroot.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-handler-without-docroot.phpt new file mode 100644 index 0000000000000..5d2559adbb530 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-handler-without-docroot.phpt @@ -0,0 +1,63 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache handler basic +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ + 'PATH_INFO' => '/pinfo', + 'PATH_TRANSLATED' => __DIR__ . '/pinfo', + 'DOCUMENT_ROOT' => null, + ], + uri: $scriptName . '/pinfo', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . $sourceFilePath, + scriptName: $scriptName, + ) + ->expectBody([$scriptName, $sourceFilePath, '/pinfo', $scriptName . '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-basic.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-basic.phpt new file mode 100644 index 0000000000000..c0c0fc9360844 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-basic.phpt @@ -0,0 +1,54 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache ProxyPass SCRIPT_NAME stripping with basic path +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + uri: $scriptName . '/pinfo', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . $sourceFilePath . '/pinfo', + scriptName: $scriptName . '/pinfo' + ) + ->expectBody([$scriptName, $scriptName . '/pinfo', $sourceFilePath, '/pinfo', $scriptName . '/pinfo']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-encoded.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-encoded.phpt new file mode 100644 index 0000000000000..22114e1abde47 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-encoded.phpt @@ -0,0 +1,54 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache ProxyPass SCRIPT_NAME stripping with encoded path (bug #74129) +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + uri: $scriptName . '/1%202', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . $sourceFilePath . '/1%202', + scriptName: $scriptName . '/1 2' + ) + ->expectBody([$scriptName, $scriptName . '/1 2', $sourceFilePath, '/1%202', $scriptName . '/1%202']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-invalid.phpt b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-invalid.phpt new file mode 100644 index 0000000000000..ebc86bf931eb8 --- /dev/null +++ b/sapi/fpm/tests/fcgi-env-pif-apache-pp-sn-strip-invalid.phpt @@ -0,0 +1,54 @@ +--TEST-- +FPM: FastCGI env var path info fix for Apache ProxyPass SCRIPT_NAME stripping with invalid path +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + uri: $scriptName . '/pinfox', + scriptFilename: "proxy:fcgi://" . $tester->getAddr() . $sourceFilePath . '/pinfoy', + scriptName: $scriptName . '/pinfox' // this would be a bug in Apache - just for testing + ) + ->expectBody([$scriptName . '/pinfox', 'none', $sourceFilePath, '/pinfoy', $scriptName . '/pinfox/pinfoy']); +$tester->terminate(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/gh8646.phpt b/sapi/fpm/tests/gh8646.phpt new file mode 100644 index 0000000000000..c35b57ec916c2 --- /dev/null +++ b/sapi/fpm/tests/gh8646.phpt @@ -0,0 +1,52 @@ +--TEST-- +GH-8646 (Memory leak PHP FPM 8.1) +--EXTENSIONS-- +zend_test +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +$map_ptr_last_values = []; +for ($i = 0; $i < 10; $i++) { + $map_ptr_last_values[] = (int) $tester->request()->getBody(); +} +// Ensure that map_ptr_last did not increase +var_dump(count(array_unique($map_ptr_last_values, SORT_REGULAR)) === 1); +$tester->terminate(); +$tester->expectLogTerminatingNotices(); +$tester->close(); + +?> +Done +--EXPECT-- +bool(true) +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/gh9981-fastcgi-error-header-reset.phpt b/sapi/fpm/tests/gh9981-fastcgi-error-header-reset.phpt new file mode 100644 index 0000000000000..5a1d65f1cb0bd --- /dev/null +++ b/sapi/fpm/tests/gh9981-fastcgi-error-header-reset.phpt @@ -0,0 +1,51 @@ +--TEST-- +FPM: gh9981 - fastcgi.error_header is not reset +--SKIPIF-- + +--FILE-- +start(iniEntries: [ + 'fastcgi.error_header' => '"HTTP/1.1 500 PHP Error"', + 'output_buffering' => 4096, +]); +$tester->expectLogStartNotices(); +$tester->request()->expectStatus('500 PHP Error'); +$tester->request('q=1')->expectNoStatus(); +$tester->terminate(); +$tester->expectLogTerminatingNotices(); +$tester->expectNoLogPattern('/Cannot modify header information/'); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-custom.phpt b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-custom.phpt new file mode 100644 index 0000000000000..efb41c9054e73 --- /dev/null +++ b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-custom.phpt @@ -0,0 +1,55 @@ +--TEST-- +FPM: GHSA-54hq-v5wp-fqgv - max_multipart_body_parts ini custom value +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +echo $tester + ->request(stdin: [ + 'parts' => [ + 'count' => 30, + ] + ]) + ->getBody(); +$tester->terminate(); +$tester->close(); + +?> +--EXPECT-- +Warning: PHP Request Startup: Multipart body parts limit exceeded 10. To increase the limit change max_multipart_body_parts in php.ini. in Unknown on line 0 +int(10) +--CLEAN-- + diff --git a/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-default.phpt b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-default.phpt new file mode 100644 index 0000000000000..2cb7612e650fd --- /dev/null +++ b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-body-parts-default.phpt @@ -0,0 +1,56 @@ +--TEST-- +FPM: GHSA-54hq-v5wp-fqgv - max_multipart_body_parts ini default +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +echo $tester + ->request(stdin: [ + 'parts' => [ + 'count' => 30, + ] + ]) + ->getBody(); +$tester->terminate(); +$tester->close(); + +?> +--EXPECT-- +Warning: PHP Request Startup: Input variables exceeded 20. To increase the limit change max_input_vars in php.ini. in Unknown on line 0 + +Warning: PHP Request Startup: Multipart body parts limit exceeded 25. To increase the limit change max_multipart_body_parts in php.ini. in Unknown on line 0 +int(20) +--CLEAN-- + diff --git a/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-file-uploads.phpt b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-file-uploads.phpt new file mode 100644 index 0000000000000..8c7ec54c799ba --- /dev/null +++ b/sapi/fpm/tests/ghsa-54hq-v5wp-fqgv-max-file-uploads.phpt @@ -0,0 +1,54 @@ +--TEST-- +FPM: GHSA-54hq-v5wp-fqgv - exceeding max_file_uploads +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +echo $tester + ->request(stdin: [ + 'parts' => [ + 'count' => 10, + 'param' => 'filename' + ] + ]) + ->getBody(); +$tester->terminate(); +$tester->close(); + +?> +--EXPECT-- +Warning: Maximum number of allowable file uploads has been exceeded in Unknown on line 0 +int(5) +--CLEAN-- + diff --git a/sapi/fpm/tests/response.inc b/sapi/fpm/tests/response.inc index 18f66a53617e0..0622f06a097e4 100644 --- a/sapi/fpm/tests/response.inc +++ b/sapi/fpm/tests/response.inc @@ -41,6 +41,11 @@ class Response */ private $expectInvalid; + /** + * @var bool + */ + private bool $debugOutputted = false; + /** * @param string|array|null $data * @param bool $expectInvalid @@ -71,9 +76,9 @@ class Response $body = implode("\n", $body); } - if (!$this->checkIfValid()) { + if ( ! $this->checkIfValid()) { $this->error('Response is invalid'); - } elseif (!$this->checkDefaultHeaders($contentType)) { + } elseif ( ! $this->checkDefaultHeaders($contentType)) { $this->error('Response default headers not found'); } elseif ($body !== $this->rawBody) { if ($multiLine) { @@ -145,6 +150,57 @@ class Response return $this; } + /** + * Expect error pattern in the response. + * + * @param string $errorMessagePattern Expected error message RegExp patter. + * + * @return Response + */ + public function expectErrorPattern(string $errorMessagePattern): Response + { + $errorData = $this->getErrorData(); + if (preg_match($errorMessagePattern, $errorData) === 0) { + $this->error( + "The expected error pattern $errorMessagePattern does not match the returned error '$errorData'" + ); + $this->debugOutput(); + } + + return $this; + } + + /** + * Expect response status. + * + * @param string|null $status Expected status. + * + * @return Response + */ + public function expectStatus(string|null $status): Response { + $headers = $this->getHeaders(); + if (is_null($status) && !isset($headers['status'])) { + return $this; + } + if (!is_null($status) && !isset($headers['status'])) { + $this->error('Status is expected but not supplied'); + } elseif ($status !== $headers['status']) { + $statusMessage = $status === null ? "expected not to be set": "expected to be $status"; + $this->error("Status is $statusMessage but the actual value is {$headers['status']}"); + } + + return $this; + } + + /** + * Expect response status not to be set. + * + * @return Response + */ + public function expectNoStatus(): Response { + return $this->expectStatus(null); + } + /** * Expect no error in the response. * @@ -198,6 +254,8 @@ class Response echo "----------------- ERR -----------------\n"; echo $this->data['err_response'] . "\n"; echo "---------------------------------------\n\n"; + + $this->debugOutputted = true; } /** @@ -357,8 +415,11 @@ class Response * * @return bool */ - private function error($message): bool + private function error(string $message): bool { + if ( ! $this->debugOutputted) { + $this->debugOutput(); + } echo "ERROR: $message\n"; return false; diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc index 50de960aa8dde..39c964761b282 100644 --- a/sapi/fpm/tests/tester.inc +++ b/sapi/fpm/tests/tester.inc @@ -269,10 +269,11 @@ class Tester static public function skipIfConfigFails(string $configTemplate) { $tester = new self($configTemplate, '', [], self::getCallerFileName()); - $testResult = $tester->testConfig(); + $testResult = $tester->testConfig(true); if ($testResult !== null) { self::clean(2); - die("skip $testResult"); + $message = $testResult[0] ?? 'Config failed'; + die("skip $message"); } } @@ -378,17 +379,26 @@ class Tester /** * Test configuration file. * - * @return null|string + * @return null|array * @throws \Exception */ - public function testConfig() + public function testConfig($silent = false) { $configFile = $this->createConfig(); $cmd = self::findExecutable() . ' -tt -y ' . $configFile . ' 2>&1'; $this->trace('Testing config using command', $cmd, true); exec($cmd, $output, $code); if ($code) { - return preg_replace("/\[.+?\]/", "", $output[0]); + $messages = []; + foreach ($output as $outputLine) { + $message = preg_replace("/\[.+?\]/", "", $outputLine, 1); + $messages[] = $message; + if ( ! $silent) { + $this->error($message, null, false); + } + } + + return $messages; } return null; @@ -604,21 +614,25 @@ class Tester array $headers = [], string $uri = null, string $scriptFilename = null, + string $scriptName = null, ?string $stdin = null ): array { if (is_null($scriptFilename)) { $scriptFilename = $this->makeSourceFile(); } if (is_null($uri)) { - $uri = "/" . basename($scriptFilename); + $uri = '/' . basename($scriptFilename); + } + if (is_null($scriptName)) { + $scriptName = $uri; } $params = array_merge( [ 'GATEWAY_INTERFACE' => 'FastCGI/1.0', 'REQUEST_METHOD' => is_null($stdin) ? 'GET' : 'POST', - 'SCRIPT_FILENAME' => $scriptFilename ?: $uri, - 'SCRIPT_NAME' => $uri, + 'SCRIPT_FILENAME' => $scriptFilename === '' ? null : $scriptFilename, + 'SCRIPT_NAME' => $scriptName, 'QUERY_STRING' => $query, 'REQUEST_URI' => $uri . ($query ? '?' . $query : ""), 'DOCUMENT_URI' => $uri, @@ -641,21 +655,87 @@ class Tester }); } + /** + * Parse stdin and generate data for multipart config. + * + * @param array $stdin + * @param array $headers + * + * @return void + * @throws \Exception + */ + private function parseStdin(array $stdin, array &$headers) + { + $parts = $stdin['parts'] ?? null; + if (empty($parts)) { + throw new \Exception('The stdin array needs to contain parts'); + } + $boundary = $stdin['boundary'] ?? 'AaB03x'; + if ( ! isset($headers['CONTENT_TYPE'])) { + $headers['CONTENT_TYPE'] = 'multipart/form-data; boundary=' . $boundary; + } + $count = $parts['count'] ?? null; + if ( ! is_null($count)) { + $dispositionType = $parts['disposition'] ?? 'form-data'; + $dispositionParam = $parts['param'] ?? 'name'; + $namePrefix = $parts['prefix'] ?? 'f'; + $nameSuffix = $parts['suffix'] ?? ''; + $value = $parts['value'] ?? 'test'; + $parts = []; + for ($i = 0; $i < $count; $i++) { + $parts[] = [ + 'disposition' => $dispositionType, + 'param' => $dispositionParam, + 'name' => "$namePrefix$i$nameSuffix", + 'value' => $value + ]; + } + } + $out = ''; + $nl = "\r\n"; + foreach ($parts as $part) { + if (!is_array($part)) { + $part = ['name' => $part]; + } elseif ( ! isset($part['name'])) { + throw new \Exception('Each part has to have a name'); + } + $name = $part['name']; + $dispositionType = $part['disposition'] ?? 'form-data'; + $dispositionParam = $part['param'] ?? 'name'; + $value = $part['value'] ?? 'test'; + $partHeaders = $part['headers'] ?? []; + + $out .= "--$boundary$nl"; + $out .= "Content-disposition: $dispositionType; $dispositionParam=\"$name\"$nl"; + foreach ($partHeaders as $headerName => $headerValue) { + $out .= "$headerName: $headerValue$nl"; + } + $out .= $nl; + $out .= "$value$nl"; + } + $out .= "--$boundary--$nl"; + + return $out; + } + /** * Execute request. * - * @param string $query - * @param array $headers - * @param string|null $uri - * @param string|null $address - * @param string|null $successMessage - * @param string|null $errorMessagereadLimit - * @param bool $connKeepAlive - * @param string|null $scriptFilename = null - * @param bool $expectError - * @param int $readLimit + * @param string $query + * @param array $headers + * @param string|null $uri + * @param string|null $address + * @param string|null $successMessage + * @param string|null $errorMessage + * @param bool $connKeepAlive + * @param string|null $scriptFilename = null + * @param string|null $scriptName = null + * @param string|array|null $stdin = null + * @param bool $expectError + * @param int $readLimit * * @return Response + * @throws \Exception */ public function request( string $query = '', @@ -666,7 +746,8 @@ class Tester string $errorMessage = null, bool $connKeepAlive = false, string $scriptFilename = null, - string $stdin = null, + string $scriptName = null, + string|array $stdin = null, bool $expectError = false, int $readLimit = -1, ): Response { @@ -674,7 +755,11 @@ class Tester return new Response(null, true); } - $params = $this->getRequestParams($query, $headers, $uri, $scriptFilename, $stdin); + if (is_array($stdin)) { + $stdin = $this->parseStdin($stdin, $headers); + } + + $params = $this->getRequestParams($query, $headers, $uri, $scriptFilename, $scriptName, $stdin); $this->trace('Request params', $params); try { @@ -1246,6 +1331,18 @@ class Tester return $this->makeFile('src.php', $this->code, overwrite: false); } + /** + * Create a source file and script name. + * + * @return string[] + */ + public function createSourceFileAndScriptName(): array + { + $sourceFile = $this->makeFile('src.php', $this->code, overwrite: false); + + return [$sourceFile, '/' . basename($sourceFile)]; + } + /** * @param string|null $msg */ @@ -1259,14 +1356,15 @@ class Tester /** * Display error. * - * @param string $msg - * @param \Exception|null $exception + * @param string $msg Error message. + * @param \Exception|null $exception If there is an exception, log its message + * @param bool $prefix Whether to prefix the error message * * @return false */ - private function error($msg, \Exception $exception = null): bool + private function error(string $msg, \Exception $exception = null, bool $prefix = true): bool { - $this->error = 'ERROR: ' . $msg; + $this->error = $prefix ? 'ERROR: ' . $msg : ltrim($msg); if ($exception) { $this->error .= '; EXCEPTION: ' . $exception->getMessage(); } diff --git a/sapi/fpm/www.conf.in b/sapi/fpm/www.conf.in index dfb41b680e42c..37ac8a194f7f8 100644 --- a/sapi/fpm/www.conf.in +++ b/sapi/fpm/www.conf.in @@ -17,9 +17,14 @@ ; Default Value: none ;prefix = /path/to/pools/$pool -; Unix user/group of processes -; Note: The user is mandatory. If the group is not set, the default user's group -; will be used. +; Unix user/group of the child processes. This can be used only if the master +; process running user is root. It is set after the child process is created. +; The user and group can be specified either by their name or by their numeric +; IDs. +; Note: If the user is root, the executable needs to be started with +; --allow-to-run-as-root option to work. +; Default Values: The user is set to master process running user by default. +; If the group is not set, the user's group is used. user = @php_fpm_user@ group = @php_fpm_group@ @@ -43,11 +48,12 @@ listen = 127.0.0.1:9000 ; permissions must be set in order to allow connections from a web server. Many ; BSD-derived systems allow connections regardless of permissions. The owner ; and group can be specified either by name or by their numeric IDs. -; Default Values: user and group are set as the running user -; mode is set to 0660 +; Default Values: Owner is set to the master process running user. If the group +; is not set, the owner's group is used. Mode is set to 0660. ;listen.owner = @php_fpm_user@ ;listen.group = @php_fpm_group@ ;listen.mode = 0660 + ; When POSIX Access Control Lists are supported you can set them using ; these options, value is a comma separated list of user/group names. ; When set, listen.owner and listen.group are ignored diff --git a/sapi/fuzzer/fuzzer-function-jit.c b/sapi/fuzzer/fuzzer-function-jit.c index c637bcfa608f6..bd99299984ae4 100644 --- a/sapi/fuzzer/fuzzer-function-jit.c +++ b/sapi/fuzzer/fuzzer-function-jit.c @@ -23,7 +23,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; } - zend_string *jit_option = zend_string_init("opcache.jit", sizeof("opcache.jit") - 1, 1); + zend_string *jit_option = ZSTR_INIT_LITERAL("opcache.jit", 1); /* First run without JIT to determine whether we bail out. We should not run JITed code if * we bail out here, as the JIT code may loop infinitely. */ diff --git a/sapi/fuzzer/fuzzer-mbstring.c b/sapi/fuzzer/fuzzer-mbstring.c index 61014b2399361..e8da3120acf19 100644 --- a/sapi/fuzzer/fuzzer-mbstring.c +++ b/sapi/fuzzer/fuzzer-mbstring.c @@ -20,6 +20,34 @@ #include "fuzzer-sapi.h" #include "ext/mbstring/mbstring.h" +zend_string* convert_encoding(const uint8_t *Data, size_t Size, const mbfl_encoding *FromEncoding, const mbfl_encoding *ToEncoding, size_t BufSize, unsigned int *NumErrors) +{ + uint32_t *wchar_buf = ecalloc(BufSize, sizeof(uint32_t)); + unsigned int state = 0; + + mb_convert_buf buf; + mb_convert_buf_init(&buf, Size, '?', MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR); + + while (Size) { + size_t out_len = FromEncoding->to_wchar((unsigned char**)&Data, &Size, wchar_buf, BufSize, &state); + ZEND_ASSERT(out_len <= BufSize); + ToEncoding->from_wchar(wchar_buf, out_len, &buf, !Size); + } + + *NumErrors = buf.errors; + zend_string *result = mb_convert_buf_result(&buf, ToEncoding); + efree(wchar_buf); + return result; +} + +void assert_zend_string_eql(zend_string *str1, zend_string *str2) +{ + ZEND_ASSERT(ZSTR_LEN(str1) == ZSTR_LEN(str2)); + for (int i = 0; i < ZSTR_LEN(str1); i++) { + ZEND_ASSERT(ZSTR_VAL(str1)[i] == ZSTR_VAL(str2)[i]); + } +} + int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { const uint8_t *Comma1 = memchr(Data, ',', Size); if (!Comma1) { @@ -45,14 +73,50 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { const mbfl_encoding *ToEncoding = mbfl_name2encoding(ToEncodingName); const mbfl_encoding *FromEncoding = mbfl_name2encoding(FromEncodingName); - if (!ToEncoding || !FromEncoding || fuzzer_request_startup() == FAILURE) { + if (!ToEncoding || !FromEncoding || Size < 2 || fuzzer_request_startup() == FAILURE) { efree(ToEncodingName); efree(FromEncodingName); return 0; } - zend_string *Result = php_mb_convert_encoding_ex((char *) Data, Size, ToEncoding, FromEncoding); - zend_string_release(Result); + /* Rather than converting an entire (possibly very long) string at once, mbstring converts + * strings 'chunk by chunk'; the decoder will run until it fills up its output buffer with + * wchars, then the encoder will process those wchars, then the decoder runs again until it + * again fills up its output buffer, and so on + * + * The most error-prone part of the decoder/encoder code is where we exit a decoder/encoder + * function and save its state to allow later resumption + * To stress-test that aspect of the decoders/encoders, try performing an encoding conversion + * operation with different, random buffer sizes + * If the code is correct, the result should always be the same either way */ + size_t bufsize1 = *Data++; + size_t bufsize2 = *Data++; + bufsize1 = MAX(bufsize1, MBSTRING_MIN_WCHAR_BUFSIZE); + bufsize2 = MAX(bufsize2, MBSTRING_MIN_WCHAR_BUFSIZE); + Size -= 2; + + unsigned int errors1 = 0, errors2 = 0; + + zend_string *Result1 = convert_encoding(Data, Size, FromEncoding, ToEncoding, bufsize1, &errors1); + zend_string *Result2 = convert_encoding(Data, Size, FromEncoding, ToEncoding, bufsize2, &errors2); + + assert_zend_string_eql(Result1, Result2); + ZEND_ASSERT(errors1 == errors2); + + /* For some text encodings, we have specialized validation functions. These should always be + * stricter than the conversion functions; if the conversion function receives invalid input + * and emits an error marker (MBFL_BAD_INPUT), then the validation function should always + * return false. However, if the conversion function does not emit any error marker, it may + * still happen in some cases that the validation function returns false. */ + if (FromEncoding->check != NULL) { + bool good = FromEncoding->check((unsigned char*)Data, Size); + if (errors1 > 0) { + ZEND_ASSERT(!good); + } + } + + zend_string_release(Result1); + zend_string_release(Result2); efree(ToEncodingName); efree(FromEncodingName); diff --git a/sapi/fuzzer/fuzzer-sapi.c b/sapi/fuzzer/fuzzer-sapi.c index 3a79e273106fa..cbb09e08f2730 100644 --- a/sapi/fuzzer/fuzzer-sapi.c +++ b/sapi/fuzzer/fuzzer-sapi.c @@ -144,7 +144,8 @@ int fuzzer_init_php(const char *extra_ini) if (extra_ini) { ini_len += extra_ini_len + 1; } - char *p = fuzzer_module.ini_entries = malloc(ini_len + 1); + char *p = malloc(ini_len + 1); + fuzzer_module.ini_entries = p; memcpy(p, HARDCODED_INI, sizeof(HARDCODED_INI) - 1); p += sizeof(HARDCODED_INI) - 1; if (extra_ini) { @@ -234,7 +235,7 @@ int fuzzer_shutdown_php(void) php_module_shutdown(); sapi_shutdown(); - free(fuzzer_module.ini_entries); + free((void *)fuzzer_module.ini_entries); return SUCCESS; } @@ -261,7 +262,9 @@ int fuzzer_do_request_from_buffer( zend_file_handle file_handle; zend_stream_init_filename(&file_handle, filename); file_handle.primary_script = 1; - file_handle.buf = estrndup(data, data_len); + file_handle.buf = emalloc(data_len + ZEND_MMAP_AHEAD); + memcpy(file_handle.buf, data, data_len); + memset(file_handle.buf + data_len, 0, ZEND_MMAP_AHEAD); file_handle.len = data_len; /* Avoid ZEND_HANDLE_FILENAME for opcache. */ file_handle.type = ZEND_HANDLE_STREAM; diff --git a/sapi/fuzzer/fuzzer-tracing-jit.c b/sapi/fuzzer/fuzzer-tracing-jit.c index 585bf55304a44..7113bf0796913 100644 --- a/sapi/fuzzer/fuzzer-tracing-jit.c +++ b/sapi/fuzzer/fuzzer-tracing-jit.c @@ -23,7 +23,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; } - zend_string *jit_option = zend_string_init("opcache.jit", sizeof("opcache.jit") - 1, 1); + zend_string *jit_option = ZSTR_INIT_LITERAL("opcache.jit", 1); /* First run without JIT to determine whether we bail out. We should not run JITed code if * we bail out here, as the JIT code may loop infinitely. */ diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c index 79fae63507c16..46ad97f2bf335 100644 --- a/sapi/litespeed/lsapi_main.c +++ b/sapi/litespeed/lsapi_main.c @@ -702,7 +702,7 @@ static void lsapi_clean_shutdown(void) setitimer(ITIMER_PROF, &tmv, NULL); #if PHP_MAJOR_VERSION >= 7 - key = zend_string_init("error_reporting", 15, 1); + key = ZSTR_INIT_LITERAL("error_reporting", 1); zend_alter_ini_entry_chars_ex(key, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_SHUTDOWN, 1); zend_string_release(key); diff --git a/sapi/phpdbg/phpdbg.1.in b/sapi/phpdbg/phpdbg.1.in index cf43a57be67c3..3ab0ff472f9b5 100644 --- a/sapi/phpdbg/phpdbg.1.in +++ b/sapi/phpdbg/phpdbg.1.in @@ -1,4 +1,4 @@ -.TH @program_prefix@phpdbg 1 "2022" "The PHP Group" "Scripting Language" +.TH @program_prefix@phpdbg 1 "2023" "The PHP Group" "Scripting Language" .SH NAME @program_prefix@phpdbg \- The interactive PHP debugger .SH SYNOPSIS diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 41e44a48cc935..ba70244c143f0 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -429,7 +429,7 @@ PHP_FUNCTION(phpdbg_start_oplog) PHPDBG_G(oplog_cur)->next = NULL; } -static zend_always_inline bool phpdbg_is_ignored_opcode(zend_uchar opcode) { +static zend_always_inline bool phpdbg_is_ignored_opcode(uint8_t opcode) { return opcode == ZEND_NOP || opcode == ZEND_OP_DATA || opcode == ZEND_FE_FREE || opcode == ZEND_FREE || opcode == ZEND_ASSERT_CHECK || opcode == ZEND_VERIFY_RETURN_TYPE || opcode == ZEND_DECLARE_CONST || opcode == ZEND_DECLARE_CLASS || opcode == ZEND_DECLARE_FUNCTION @@ -457,7 +457,7 @@ static void phpdbg_oplog_fill_executable(zend_op_array *op_array, HashTable *ins } for (; cur < end; cur++) { - zend_uchar opcode = cur->opcode; + uint8_t opcode = cur->opcode; if (phpdbg_is_ignored_opcode(opcode)) { continue; } @@ -912,21 +912,24 @@ void phpdbg_register_file_handles(void) /* {{{ */ ic.value = zin; Z_CONSTANT_FLAGS(ic.value) = 0; - ic.name = zend_string_init(ZEND_STRL("STDIN"), 0); - zend_hash_del(EG(zend_constants), ic.name); - zend_register_constant(&ic); + zend_string *stdin_name = zend_string_init(ZEND_STRL("STDIN"), 0); + zend_hash_del(EG(zend_constants), stdin_name); + zend_register_constant(stdin_name, &ic); + zend_string_release(stdin_name); oc.value = zout; Z_CONSTANT_FLAGS(oc.value) = 0; - oc.name = zend_string_init(ZEND_STRL("STDOUT"), 0); - zend_hash_del(EG(zend_constants), oc.name); - zend_register_constant(&oc); + zend_string *stdout_name = zend_string_init(ZEND_STRL("STDOUT"), 0); + zend_hash_del(EG(zend_constants), stdout_name); + zend_register_constant(stdout_name, &oc); + zend_string_release(stdout_name); ec.value = zerr; Z_CONSTANT_FLAGS(ec.value) = 0; - ec.name = zend_string_init(ZEND_STRL("STDERR"), 0); - zend_hash_del(EG(zend_constants), ec.name); - zend_register_constant(&ec); + zend_string *stderr_name = zend_string_init(ZEND_STRL("STDERR"), 0); + zend_hash_del(EG(zend_constants), stderr_name); + zend_register_constant(stderr_name, &ec); + zend_string_release(stderr_name); } /* }}} */ @@ -963,7 +966,7 @@ static sapi_module_struct phpdbg_sapi_module = { }; /* }}} */ -const opt_struct OPTIONS[] = { /* {{{ */ +static const opt_struct OPTIONS[] = { /* {{{ */ {'c', 1, "ini path override"}, {'d', 1, "define ini entry on command line"}, {'n', 0, "no php.ini"}, @@ -1378,6 +1381,8 @@ int main(int argc, char **argv) /* {{{ */ get_zend_version() ); } + PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; + php_module_shutdown(); sapi_deactivate(); sapi_shutdown(); php_ini_builder_deinit(&ini_builder); diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index a20b4bd65db92..90f8ed7bb1295 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -31,7 +31,7 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array*); static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function*); static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array*); static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t); -static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar); +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(uint8_t); static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data); /* }}} */ /* @@ -829,19 +829,21 @@ static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, co uint32_t cops = CG(compiler_options); zend_string *bp_code; - switch (param->type) { - case STR_PARAM: - case NUMERIC_FUNCTION_PARAM: - case METHOD_PARAM: - case NUMERIC_METHOD_PARAM: - case FILE_PARAM: - case ADDR_PARAM: - /* do nothing */ - break; + if (param) { + switch (param->type) { + case STR_PARAM: + case NUMERIC_FUNCTION_PARAM: + case METHOD_PARAM: + case NUMERIC_METHOD_PARAM: + case FILE_PARAM: + case ADDR_PARAM: + /* do nothing */ + break; - default: - phpdbg_error("Invalid parameter type for conditional breakpoint"); - return; + default: + phpdbg_error("Invalid parameter type for conditional breakpoint"); + return; + } } PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_COND); @@ -1007,7 +1009,7 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_pt return (phpdbg_breakbase_t *) brake; } /* }}} */ -static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar opcode) /* {{{ */ +static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(uint8_t opcode) /* {{{ */ { const char *opname = zend_get_opcode_name(opcode); diff --git a/sapi/phpdbg/phpdbg_bp.h b/sapi/phpdbg/phpdbg_bp.h index a6d6f29e5a985..e357b7388e699 100644 --- a/sapi/phpdbg/phpdbg_bp.h +++ b/sapi/phpdbg/phpdbg_bp.h @@ -39,7 +39,7 @@ typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */ /* {{{ breakpoint base structure */ #define phpdbg_breakbase(name) \ int id; \ - zend_uchar type; \ + uint8_t type; \ zend_ulong hits; \ bool disabled; \ const char *name /* }}} */ diff --git a/sapi/phpdbg/phpdbg_help.c b/sapi/phpdbg/phpdbg_help.c index b162c4b39feff..f1f9bf4fab1e7 100644 --- a/sapi/phpdbg/phpdbg_help.c +++ b/sapi/phpdbg/phpdbg_help.c @@ -38,9 +38,9 @@ const phpdbg_command_t phpdbg_help_commands[] = { }; /* }}} */ /* {{{ pretty_print. Formatting escapes and wrapping text in a string before printing it. */ -void pretty_print(char *text) +static void pretty_print(const char *text) { - char *new, *p, *q; + char *new, *q; const char *prompt_escape = phpdbg_get_prompt(); size_t prompt_escape_len = strlen(prompt_escape); @@ -60,6 +60,7 @@ void pretty_print(char *text) uint32_t line_count = 0; /* number printable chars on current line */ /* First pass calculates a safe size for the pretty print version */ + const char *p; for (p = text; *p; p++) { if (UNEXPECTED(p[0] == '*') && p[1] == '*') { size += bold_escape_len - 2; @@ -143,9 +144,9 @@ void summary_print(phpdbg_command_t const * const cmd) } /* {{{ get_help. Retries and formats text from the phpdbg help text table */ -static char *get_help(const char * const key) +static const char *get_help(const char * const key) { - phpdbg_help_text_t *p; + const phpdbg_help_text_t *p; /* Note that phpdbg_help_text is not assumed to be collated in key order. This is an inconvenience that means that help can't be logically grouped Not worth @@ -201,8 +202,8 @@ static int get_command( } /* }}} */ -void phpdbg_do_help_cmd(char *type) { /* {{{ */ - char *help; +void phpdbg_do_help_cmd(const char *type) { /* {{{ */ + const char *help; if (!type) { pretty_print(get_help("overview!")); @@ -329,7 +330,7 @@ PHPDBG_HELP(aliases) /* {{{ */ * has a key ending in ! */ #define CR "\n" -phpdbg_help_text_t phpdbg_help_text[] = { +const phpdbg_help_text_t phpdbg_help_text[] = { /******************************** General Help Topics ********************************/ {"overview!", CR diff --git a/sapi/phpdbg/phpdbg_help.h b/sapi/phpdbg/phpdbg_help.h index ef9a350798721..e4c9dd63881c0 100644 --- a/sapi/phpdbg/phpdbg_help.h +++ b/sapi/phpdbg/phpdbg_help.h @@ -42,7 +42,7 @@ typedef struct _phpdbg_help_text_t { char *text; } phpdbg_help_text_t; -extern phpdbg_help_text_t phpdbg_help_text[]; +extern const phpdbg_help_text_t phpdbg_help_text[]; -extern void phpdbg_do_help_cmd(char *type); +extern void phpdbg_do_help_cmd(const char *type); #endif /* PHPDBG_HELP_H */ diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c index 0a1e7570a493c..d6457ef805cf7 100644 --- a/sapi/phpdbg/phpdbg_info.c +++ b/sapi/phpdbg/phpdbg_info.c @@ -100,14 +100,15 @@ PHPDBG_INFO(constants) /* {{{ */ { HashTable consts; zend_constant *data; + zend_string *name; zend_hash_init(&consts, 8, NULL, NULL, 0); if (EG(zend_constants)) { phpdbg_try_access { - ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), data) { + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(zend_constants), name, data) { if (ZEND_CONSTANT_MODULE_NUMBER(data) == PHP_USER_CONSTANT) { - zend_hash_update_ptr(&consts, data->name, data); + zend_hash_update_ptr(&consts, name, data); } } ZEND_HASH_FOREACH_END(); } phpdbg_catch_access { @@ -119,14 +120,14 @@ PHPDBG_INFO(constants) /* {{{ */ if (zend_hash_num_elements(&consts)) { phpdbg_out("Address Refs Type Constant\n"); - ZEND_HASH_MAP_FOREACH_PTR(&consts, data) { + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&consts, name, data) { #define VARIABLEINFO(msg, ...) \ phpdbg_writeln( \ "%-18p %-7d %-9s %.*s" msg, &data->value, \ Z_REFCOUNTED(data->value) ? Z_REFCOUNT(data->value) : 1, \ zend_get_type_by_const(Z_TYPE(data->value)), \ - (int) ZSTR_LEN(data->name), ZSTR_VAL(data->name), ##__VA_ARGS__) + (int) ZSTR_LEN(name), ZSTR_VAL(name), ##__VA_ARGS__) switch (Z_TYPE(data->value)) { case IS_STRING: diff --git a/sapi/phpdbg/phpdbg_out.c b/sapi/phpdbg/phpdbg_out.c index a6eb84de2c182..af2f3b98d2bad 100644 --- a/sapi/phpdbg/phpdbg_out.c +++ b/sapi/phpdbg/phpdbg_out.c @@ -143,7 +143,11 @@ PHPDBG_API int phpdbg_vprint(int type, int fd, const char *strfmt, va_list args) return msglen; } - len = phpdbg_process_print(fd, type, msg, msglen); + if (UNEXPECTED(msglen == 0)) { + len = 0; + } else { + len = phpdbg_process_print(fd, type, msg, msglen); + } if (msg) { free(msg); diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 4c8c273f242d9..f8041c660f266 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -1253,11 +1253,10 @@ PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, const char * #if ZEND_EXTENSIONS_SUPPORT do { zend_extension *new_extension; - zend_extension_version_info *extension_version_info; - extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info"); + const zend_extension_version_info *extension_version_info = (const zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info"); if (!extension_version_info) { - extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info"); + extension_version_info = (const zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info"); } new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry"); if (!new_extension) { @@ -1320,7 +1319,7 @@ PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, const char * module_entry->handle = handle; if ((module_entry = zend_register_module_ex(module_entry)) == NULL) { - phpdbg_error("Unable to register module %s", module_entry->name); + phpdbg_error("Unable to register module %s", *name); goto quit; } diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c index 344b9c73e476d..964d82ef6c8d5 100644 --- a/sapi/phpdbg/phpdbg_utils.c +++ b/sapi/phpdbg/phpdbg_utils.c @@ -199,7 +199,7 @@ PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{ const char *p = str; char *new = NULL; - while (p && isspace(*p)) { + while (isspace(*p)) { ++p; --len; } @@ -466,6 +466,9 @@ PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable case ']': break; case '>': + if (!last_index) { + goto error; + } if (last_index[index_len - 1] == '-') { new_index = 1; index_len--; @@ -611,7 +614,7 @@ PHPDBG_API bool phpdbg_check_caught_ex(zend_execute_data *execute_data, zend_obj uint32_t op_num, i; zend_op_array *op_array = &execute_data->func->op_array; - if (execute_data->opline >= EG(exception_op) && execute_data->opline < EG(exception_op) + 3) { + if (execute_data->opline >= EG(exception_op) && execute_data->opline < EG(exception_op) + 3 && EG(opline_before_exception)) { op = EG(opline_before_exception); } else { op = execute_data->opline; diff --git a/sapi/phpdbg/phpdbg_watch.c b/sapi/phpdbg/phpdbg_watch.c index 86cd64a5721ff..0468d4614fd5d 100644 --- a/sapi/phpdbg/phpdbg_watch.c +++ b/sapi/phpdbg/phpdbg_watch.c @@ -306,6 +306,9 @@ int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context) { } #ifdef HAVE_USERFAULTFD_WRITEFAULT +# if defined(__GNUC__) && !defined(__clang__) +__attribute__((no_sanitize_address)) +# endif void *phpdbg_watchpoint_userfaultfd_thread(void *phpdbg_globals) { pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); zend_phpdbg_globals *globals = (zend_phpdbg_globals *) phpdbg_globals; diff --git a/sapi/phpdbg/tests/bug73615.phpt b/sapi/phpdbg/tests/bug73615.phpt index e5fccef0a85c3..2208cdebf707b 100644 --- a/sapi/phpdbg/tests/bug73615.phpt +++ b/sapi/phpdbg/tests/bug73615.phpt @@ -7,7 +7,7 @@ if (!getenv('TEST_PHPDBG_EXECUTABLE')) die("SKIP: No TEST_PHPDBG_EXECUTABLE spec --FILE-- +q +--EXPECTF-- +[Successful compilation of %s] +prompt> [Breakpoint #0 added at test] +prompt> [Breakpoint #0 in test() at %s:%d, hits: 1] +>00004: } + 00005: test(); + 00006: $a = 2; +prompt> [Malformed input] +prompt> +--FILE-- + 1997-05-28. # Adapted to Git by Stanislav Malyshev . +# Check whether gtar is present (GNU tar) +tar="$(which gtar)" +tar="${tar:-$(which tar)}" + +if [[ $($tar --version) == *"bsdtar"* ]]; then + echo "Found bsdtar at $tar, but this script needs GNU tar." + exit 1 +fi + # Go to project root directory. cd $(CDPATH= cd -- "$(dirname -- "$0")/../../" && pwd -P) @@ -124,7 +133,7 @@ fi # Export PHP. echo "makedist: Exporting $treeish from $git" -git archive --format=tar $remote_option --prefix=$prefix/ $treeish | tar xvf - || exit 4 +git archive --format=tar $remote_option --prefix=$prefix/ $treeish | "$tar" xvf - || exit 4 cd $prefix || exit 5 @@ -166,7 +175,7 @@ cd .. echo "" echo "makedist: Creating $prefix.tar archive." -tar cf "$prefix".tar "$prefix" +"$tar" cf "$prefix".tar --owner=0 --group=0 --numeric-owner --sort=name "$prefix" rm -rf "$prefix" "$prefix".tar.* echo "makedist: Creating $prefix.tar.gz archive." diff --git a/scripts/man1/php-config.1.in b/scripts/man1/php-config.1.in index 5ed77c574cb42..77d3b2d005f6e 100644 --- a/scripts/man1/php-config.1.in +++ b/scripts/man1/php-config.1.in @@ -1,4 +1,4 @@ -.TH @program_prefix@php\-config 1 "2022" "The PHP Group" "Scripting Language" +.TH @program_prefix@php\-config 1 "2023" "The PHP Group" "Scripting Language" .SH NAME @program_prefix@php\-config \- get information about PHP configuration and compile options .SH SYNOPSIS diff --git a/scripts/man1/phpize.1.in b/scripts/man1/phpize.1.in index bf50aa0c1df37..e14aa7cc6a0a9 100644 --- a/scripts/man1/phpize.1.in +++ b/scripts/man1/phpize.1.in @@ -1,4 +1,4 @@ -.TH @program_prefix@phpize 1 "2022" "The PHP Group" "Scripting Language" +.TH @program_prefix@phpize 1 "2023" "The PHP Group" "Scripting Language" .SH NAME @program_prefix@phpize \- prepare a PHP extension for compiling .SH SYNOPSIS diff --git a/tests/basic/bug71273.phpt b/tests/basic/bug71273.phpt index 7634d432d0a1d..3e26f500bc41a 100644 --- a/tests/basic/bug71273.phpt +++ b/tests/basic/bug71273.phpt @@ -4,7 +4,7 @@ Bug #71273 A wrong ext directory setup in php.ini leads to crash &1"; + $cmd = getenv('TEST_PHP_EXECUTABLE_ESCAPED') . " -n -d html_errors=on -d extension_dir=a//w -d extension=php_kartoffelbrei.dll -v 2>&1"; $out = shell_exec($cmd); var_dump(preg_match(",.+a[\\/].+[\\/]w.php_kartoffelbrei.dll.+,s", $out)); diff --git a/tests/classes/constants_error_004.phpt b/tests/classes/constants_error_004.phpt index 3d675652ba241..bd7a3fe69381a 100644 --- a/tests/classes/constants_error_004.phpt +++ b/tests/classes/constants_error_004.phpt @@ -12,5 +12,6 @@ Class constant whose initial value references a non-existent class --EXPECTF-- Fatal error: Uncaught Error: Class "D" not found in %s:%d Stack trace: -#0 {main} +#0 %s(%d): [constant expression]() +#1 {main} thrown in %s on line %d diff --git a/tests/classes/tostring_001.phpt b/tests/classes/tostring_001.phpt index abf41f97cdaca..ddbe4d152dde0 100644 --- a/tests/classes/tostring_001.phpt +++ b/tests/classes/tostring_001.phpt @@ -118,7 +118,7 @@ test2::__toString() Converted ====test7==== test2::__toString() -Illegal offset type +Cannot access offset of type object on array ====test8==== test2::__toString() string(9) "Converted" diff --git a/tests/lang/bug25922.phpt b/tests/lang/bug25922.phpt index a6b526ab780fa..4927bfea776ce 100644 --- a/tests/lang/bug25922.phpt +++ b/tests/lang/bug25922.phpt @@ -20,5 +20,5 @@ test(); ?> --EXPECT-- Undefined variable $data -Trying to access array offset on value of type null +Trying to access array offset on null Undefined index here: '' diff --git a/tests/lang/foreachLoop.003.phpt b/tests/lang/foreachLoop.003.phpt index c4ca3019f31f0..071e3bf422c34 100644 --- a/tests/lang/foreachLoop.003.phpt +++ b/tests/lang/foreachLoop.003.phpt @@ -33,7 +33,7 @@ echo "done.\n"; --EXPECTF-- Not an array. -Warning: foreach() argument must be of type array|object, bool given in %s on line 4 +Warning: foreach() argument must be of type array|object, true given in %s on line %d Warning: foreach() argument must be of type array|object, null given in %s on line 9 diff --git a/tests/lang/passByReference_003.phpt b/tests/lang/passByReference_003.phpt index 11c3e32c50bed..4d073822f48ce 100644 --- a/tests/lang/passByReference_003.phpt +++ b/tests/lang/passByReference_003.phpt @@ -27,7 +27,7 @@ Passing undefined by value Warning: Undefined variable $undef1 in %s on line %d -Warning: Trying to access array offset on value of type null in %s on line %d +Warning: Trying to access array offset on null in %s on line %d Inside passbyVal call: NULL diff --git a/tests/run-test/extensions-shared.phpt b/tests/run-test/extensions-shared.phpt index e8d9b52aa98a9..2bbe8b767655b 100644 --- a/tests/run-test/extensions-shared.phpt +++ b/tests/run-test/extensions-shared.phpt @@ -4,7 +4,7 @@ phpt EXTENSIONS directive - shared module openssl --SKIPIF-- = 1914) { AC_DEFINE('HAVE_STRNLEN', 1); +AC_DEFINE('ZEND_STACK_GROWS_DOWNWARDS', 1) +AC_DEFINE('ZEND_CHECK_STACK_LIMIT', 1) + ADD_SOURCES("main/streams", "streams.c cast.c memory.c filter.c plain_wrapper.c \ userspace.c transports.c xp_socket.c mmap.c glob_wrapper.c"); ADD_FLAG("CFLAGS_BD_MAIN_STREAMS", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); diff --git a/win32/build/config.w32.h.in b/win32/build/config.w32.h.in index 7686fb83a4a32..b513776eef70d 100644 --- a/win32/build/config.w32.h.in +++ b/win32/build/config.w32.h.in @@ -5,7 +5,7 @@ /* Define the minimum supported version */ #undef _WIN32_WINNT #undef NTDDI_VERSION -#define _WIN32_WINNT 0x0601 +#define _WIN32_WINNT 0x0602 #define NTDDI_VERSION 0x06010000 /* Default PHP / PEAR directories */ diff --git a/win32/build/cppcheck_x64.cfg b/win32/build/cppcheck_x64.cfg index 4c221a6fcd3a5..6003d5dc7af23 100644 --- a/win32/build/cppcheck_x64.cfg +++ b/win32/build/cppcheck_x64.cfg @@ -2,11 +2,8 @@ - - -