diff --git a/.cirrus.yml b/.cirrus.yml index a5209930b6e44..7d3db43a8a7e2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -3,6 +3,7 @@ env: freebsd_task: name: FREEBSD_DEBUG_NTS + skip: "changesIncludeOnly('NEWS', 'EXTENSIONS', 'UPGRADING', 'UPGRADING.INTERNALS', '**.md', 'docs/*', 'docs-old/*', '**/README.*', 'CONTRIBUTING.md', 'CODING_STANDARDS.md')" freebsd_instance: image_family: freebsd-13-3 env: diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 24a656eac19e0..6b57831db9ff9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -14,7 +14,7 @@ # 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 -/.github @iluuu1994 @TimWolla +/.github @TimWolla /build/gen_stub.php @kocsismate /ext/bcmath @Girgias @nielsdos @SakiTakamachi /ext/curl @adoy @@ -32,7 +32,7 @@ /ext/mbstring @alexdowad @youkidearitai /ext/mysqlnd @SakiTakamachi /ext/odbc @NattyNarwhal -/ext/opcache @dstogov @iluuu1994 +/ext/opcache @dstogov /ext/openssl @bukka /ext/pcntl @devnexen /ext/pdo @SakiTakamachi @@ -55,26 +55,24 @@ /ext/xsl @nielsdos /main @bukka /sapi/fpm @bukka -/Zend/Optimizer @dstogov @iluuu1994 +/Zend/Optimizer @dstogov /Zend/zend.* @dstogov /Zend/zend_alloc.* @dstogov -/Zend/zend_API.* @dstogov @iluuu1994 +/Zend/zend_API.* @dstogov /Zend/zend_call_stack.* @arnaud-lb /Zend/zend_closures.* @dstogov -/Zend/zend_compile.* @iluuu1994 -/Zend/zend_enum.* @iluuu1994 -/Zend/zend_execute.* @dstogov @iluuu1994 -/Zend/zend_execute_API.c @dstogov @iluuu1994 +/Zend/zend_execute.* @dstogov +/Zend/zend_execute_API.c @dstogov /Zend/zend_gc.* @dstogov @arnaud-lb /Zend/zend_hash.* @dstogov -/Zend/zend_inheritance.* @dstogov @iluuu1994 +/Zend/zend_inheritance.* @dstogov /Zend/zend_max_execution_timer.* @arnaud-lb -/Zend/zend_object_handlers.* @dstogov @iluuu1994 -/Zend/zend_objects.* @dstogov @iluuu1994 -/Zend/zend_objects_API.* @dstogov @iluuu1994 -/Zend/zend_opcode.* @dstogov @iluuu1994 +/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 @iluuu1994 +/Zend/zend_type*.h @dstogov /Zend/zend_variables.* @dstogov -/Zend/zend_vm* @dstogov @iluuu1994 +/Zend/zend_vm* @dstogov *.stub.php @kocsismate diff --git a/.github/actions/brew/action.yml b/.github/actions/brew/action.yml index 5868d3917b80c..360c0a85c99f7 100644 --- a/.github/actions/brew/action.yml +++ b/.github/actions/brew/action.yml @@ -12,31 +12,15 @@ runs: sudo sed -Ei '' "s/$code.*/$code, overwrite: true\)/" "$formula_installer" brew install \ - pkg-config \ - autoconf \ bison \ re2c brew install \ - openssl@1.1 \ - curl \ - krb5 \ bzip2 \ enchant \ libffi \ - libpng \ - webp \ - freetype \ intltool \ - icu4c \ libiconv \ - zlib \ t1lib \ - gd \ - libzip \ - gmp \ - tidy-html5 \ libxml2 \ libjpeg \ - libxslt \ - postgresql - brew link icu4c gettext --force + libxslt diff --git a/.github/actions/setup-mssql/action.yml b/.github/actions/setup-mssql/action.yml index c069744a21b59..dd372a5637aac 100644 --- a/.github/actions/setup-mssql/action.yml +++ b/.github/actions/setup-mssql/action.yml @@ -11,4 +11,4 @@ runs: -p 1433:1433 \ --name sql1 \ -h sql1 \ - -d mcr.microsoft.com/mssql/server:2019-CU8-ubuntu-16.04 + -d mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04 diff --git a/.github/actions/setup-x64/action.yml b/.github/actions/setup-x64/action.yml index 6cec51d4c8079..9d49107fb3ca6 100644 --- a/.github/actions/setup-x64/action.yml +++ b/.github/actions/setup-x64/action.yml @@ -6,15 +6,8 @@ runs: run: | 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;" + docker exec sql1 /opt/mssql-tools18/bin/sqlcmd -S 127.0.0.1 -U SA -C -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 diff --git a/.github/labeler.yml b/.github/labeler.yml index ddab485008955..94dda258ef557 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -241,3 +241,93 @@ "SAPI: phpdbg": - sapi/phpdbg/**/* + +"ABI break": +- 'TSRM/*.h' +- 'Zend/*.h' +- 'Zend/Optimizer/zend_call_graph.h' +- 'Zend/Optimizer/zend_cfg.h' +- 'Zend/Optimizer/zend_dump.h' +- 'Zend/Optimizer/zend_func_info.h' +- 'Zend/Optimizer/zend_inference.h' +- 'Zend/Optimizer/zend_optimizer.h' +- 'Zend/Optimizer/zend_ssa.h' +- 'ext/curl/php_curl.h' +- 'ext/date/lib/timelib.h' +- 'ext/date/lib/timelib_config.h' +- 'ext/date/php_date.h' +- 'ext/dom/xml_common.h' +- 'ext/filter/php_filter.h' +- 'ext/gd/*.h' +- 'ext/gd/libgd/*.h' +- 'ext/gmp/php_gmp_int.h' +- 'ext/hash/php_hash.h' +- 'ext/hash/php_hash_adler32.h' +- 'ext/hash/php_hash_crc32.h' +- 'ext/hash/php_hash_gost.h' +- 'ext/hash/php_hash_haval.h' +- 'ext/hash/php_hash_md.h' +- 'ext/hash/php_hash_murmur.h' +- 'ext/hash/php_hash_ripemd.h' +- 'ext/hash/php_hash_sha.h' +- 'ext/hash/php_hash_sha3.h' +- 'ext/hash/php_hash_snefru.h' +- 'ext/hash/php_hash_tiger.h' +- 'ext/hash/php_hash_whirlpool.h' +- 'ext/hash/php_hash_xxhash.h' +- 'ext/iconv/*.h' +- 'ext/json/php_json.h' +- 'ext/json/php_json_parser.h' +- 'ext/json/php_json_scanner.h' +- 'ext/libxml/php_libxml.h' +- 'ext/mbstring/libmbfl/config.h' +- 'ext/mbstring/libmbfl/mbfl/eaw_table.h' +- 'ext/mbstring/libmbfl/mbfl/mbfilter.h' +- 'ext/mbstring/libmbfl/mbfl/mbfilter_8bit.h' +- 'ext/mbstring/libmbfl/mbfl/mbfilter_pass.h' +- 'ext/mbstring/libmbfl/mbfl/mbfilter_wchar.h' +- 'ext/mbstring/libmbfl/mbfl/mbfl_consts.h' +- 'ext/mbstring/libmbfl/mbfl/mbfl_convert.h' +- 'ext/mbstring/libmbfl/mbfl/mbfl_defs.h' +- 'ext/mbstring/libmbfl/mbfl/mbfl_encoding.h' +- 'ext/mbstring/libmbfl/mbfl/mbfl_filter_output.h' +- 'ext/mbstring/libmbfl/mbfl/mbfl_language.h' +- 'ext/mbstring/libmbfl/mbfl/mbfl_memory_device.h' +- 'ext/mbstring/libmbfl/mbfl/mbfl_string.h' +- 'ext/mbstring/mbstring.h' +- 'ext/mbstring/php_mbregex.h' +- 'ext/mbstring/php_onig_compat.h' +- 'ext/mysqli/php_mysqli_structs.h' +- 'ext/mysqlnd/*.h' +- 'ext/pcre/pcre2lib/*.h' +- 'ext/pcre/php_pcre.h' +- 'ext/pdo/php_pdo.h' +- 'ext/pdo/php_pdo_driver.h' +- 'ext/pdo/php_pdo_error.h' +- 'ext/random/php_random.h' +- 'ext/session/mod_files.h' +- 'ext/session/mod_mm.h' +- 'ext/session/mod_user.h' +- 'ext/session/php_session.h' +- 'ext/simplexml/php_simplexml.h' +- 'ext/simplexml/php_simplexml_exports.h' +- 'ext/sockets/php_sockets.h' +- 'ext/sockets/windows_common.h' +- 'ext/sodium/php_libsodium.h' +- 'ext/spl/php_spl.h' +- 'ext/spl/spl_array.h' +- 'ext/spl/spl_directory.h' +- 'ext/spl/spl_dllist.h' +- 'ext/spl/spl_engine.h' +- 'ext/spl/spl_exceptions.h' +- 'ext/spl/spl_fixedarray.h' +- 'ext/spl/spl_functions.h' +- 'ext/spl/spl_heap.h' +- 'ext/spl/spl_iterators.h' +- 'ext/spl/spl_observer.h' +- 'ext/standard/*.h' +- 'ext/xml/*.h' +- 'main/*.h' +- 'main/streams/*.h' +- 'sapi/embed/php_embed.h' +- 'win32/*.h' diff --git a/.github/scripts/windows/test_task.bat b/.github/scripts/windows/test_task.bat index f41b11d06f6db..7856eb0fb0fe2 100644 --- a/.github/scripts/windows/test_task.bat +++ b/.github/scripts/windows/test_task.bat @@ -52,7 +52,12 @@ set ODBC_TEST_DSN=Driver={ODBC Driver 17 for SQL Server};Server=^(local^)\SQLEXP set PDOTEST_DSN=odbc:%ODBC_TEST_DSN% rem setup Firebird related exts -curl -sLo Firebird.zip https://github.com/FirebirdSQL/firebird/releases/download/v3.0.9/Firebird-3.0.9.33560-0_x64.zip +if "%PLATFORM%" == "x64" ( + set PHP_FIREBIRD_DOWNLOAD_URL=https://github.com/FirebirdSQL/firebird/releases/download/v3.0.9/Firebird-3.0.9.33560-0_x64.zip +) else ( + set PHP_FIREBIRD_DOWNLOAD_URL=https://github.com/FirebirdSQL/firebird/releases/download/v3.0.9/Firebird-3.0.9.33560-0_Win32.zip +) +curl -sLo Firebird.zip %PHP_FIREBIRD_DOWNLOAD_URL% 7z x -oC:\Firebird Firebird.zip set PDO_FIREBIRD_TEST_DATABASE=C:\test.fdb set PDO_FIREBIRD_TEST_DSN=firebird:dbname=%PDO_FIREBIRD_TEST_DATABASE% @@ -105,7 +110,7 @@ popd rem prepare for snmp set MIBDIRS=%DEPS_DIR%\share\mibs -start %DEPS_DIR%\bin\snmpd.exe -C -c %APPVEYOR_BUILD_FOLDER%\ext\snmp\tests\snmpd.conf -Ln +start %DEPS_DIR%\bin\snmpd.exe -C -c %GITHUB_WORKSPACE%\ext\snmp\tests\snmpd.conf -Ln set PHP_BUILD_DIR=%PHP_BUILD_OBJ_DIR%\Release if "%THREAD_SAFE%" equ "1" set PHP_BUILD_DIR=%PHP_BUILD_DIR%_TS diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 4822721f2c675..0ebbc2bb1cb61 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -39,6 +39,20 @@ jobs: LINUX_X64: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} + services: + mysql: + image: mysql:8.3 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test strategy: fail-fast: false matrix: @@ -255,6 +269,20 @@ jobs: COVERAGE_DEBUG_NTS: if: github.repository_owner == 'php' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-20.04 + services: + mysql: + image: mysql:8.3 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test steps: - name: git checkout uses: actions/checkout@v4 @@ -414,6 +442,20 @@ jobs: OPCACHE_VARIATION: needs: GENERATE_MATRIX if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} + services: + mysql: + image: mysql:8.3 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test strategy: fail-fast: false matrix: diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 8027bcdc85547..8baa2a1108e16 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -43,6 +43,22 @@ env: jobs: LINUX_X64: if: github.repository == 'php/php-src' || github.event_name == 'pull_request' + services: + mysql: + image: mysql:8.3 + ports: + - 3306:3306 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root + postgres: + image: postgres + ports: + - 5432:5432 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test strategy: fail-fast: false matrix: diff --git a/NEWS b/NEWS index 0f20c3548c4a8..9c7d5670e64a8 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,131 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.2.24 +24 Oct 2024, PHP 8.2.25 + +- Calendar: + . Fixed GH-16240: jdtounix overflow on argument value. (David Carlier) + . Fixed GH-16241: easter_days/easter_date overflow on year argument. + (David Carlier) + . Fixed GH-16263: jddayofweek overflow. (cmb) + . Fixed GH-16234: jewishtojd overflow. (nielsdos) + +- CLI: + . Fixed bug GH-16137: duplicate http headers when set several times by + the client. (David Carlier) + +- Core: + . Fixed bug GH-15712: zend_strtod overflow with precision INI set on + large value. (David Carlier) + . Fixed bug GH-15905 (Assertion failure for TRACK_VARS_SERVER). (cmb) + . Fixed bug GH-15907 (Failed assertion when promoting Serialize deprecation to + exception). (ilutov) + . Fixed bug GH-15851 (Segfault when printing backtrace during cleanup of + nested generator frame). (ilutov) + . Fixed bug GH-15866 (Core dumped in Zend/zend_generators.c). (Arnaud) + . Fixed bug GH-16188 (Assertion failure in Zend/zend_exceptions.c). (Arnaud) + . Fixed bug GH-16233 (Observer segfault when calling user function in + internal function via trampoline). (nielsdos) + +- Date: + . Fixed bug GH-15582: Crash when not calling parent constructor of + DateTimeZone. (Derick) + . Fixed regression where signs after the first one were ignored while parsing + a signed integer, with the DateTimeInterface::modify() function. (Derick) + +- DOM: + . Fixed bug GH-16039 (Segmentation fault (access null pointer) in + ext/dom/parentnode/tree.c). (nielsdos) + . Fixed bug GH-16151 (Assertion failure in ext/dom/parentnode/tree.c). + (nielsdos) + +- GD: + . Fixed bug GH-16232 (bitshift overflow on wbmp file content reading / + fix backport from upstream). (David Carlier) + . Fixed bug GH-12264 (overflow/underflow on imagerotate degrees value) + (David Carlier) + . Fixed bug GH-16274 (imagescale underflow on RBG channels / + fix backport from upstream). (David Carlier) + +- LDAP: + . Fixed bug GH-16032 (Various NULL pointer dereferencements in + ldap_modify_batch()). (Girgias) + . Fixed bug GH-16101 (Segfault in ldap_list(), ldap_read(), and ldap_search() + when LDAPs array is not a list). (Girgias) + . Fix GH-16132 (php_ldap_do_modify() attempts to free pointer not allocated + by ZMM.). (Girgias) + . Fix GH-16136 (Memory leak in php_ldap_do_modify() when entry is not a + proper dictionary). (Girgias) + +- MBString: + . Fixed bug GH-16261 (Reference invariant broken in mb_convert_variables()). + (nielsdos) + +- OpenSSL: + . Fixed stub for openssl_csr_new. (Jakub Zelenka) + +- PCRE: + . Fixed bug GH-16189 (underflow on offset argument). (David Carlier) + . Fixed bug GH-16184 (UBSan address overflowed in ext/pcre/php_pcre.c). + (nielsdos) + +- PHPDBG: + . Fixed bug GH-15901 (phpdbg: Assertion failure on i funcs). (cmb) + . Fixed bug GH-16181 (phpdbg: exit in exception handler reports fatal error). + (cmb) + +- Reflection: + . Fixed bug GH-16187 (Assertion failure in ext/reflection/php_reflection.c). + (DanielEScherzer) + +- SAPI: + . Fixed bug GH-15395 (php-fpm: zend_mm_heap corrupted with cgi-fcgi request). + (Jakub Zelenka, David Carlier) + +- SimpleXML: + . Fixed bug GH-15837 (Segmentation fault in ext/simplexml/simplexml.c). + (nielsdos) + +- Sockets: + . Fixed bug GH-16267 (socket_strerror overflow on errno argument). + (David Carlier) + +- SOAP: + . Fixed bug #62900 (Wrong namespace on xsd import error message). (nielsdos) + . Fixed bug GH-16237 (Segmentation fault when cloning SoapServer). (nielsdos) + . Fix Soap leaking http_msg on error. (nielsdos) + . Fixed bug GH-16256 (Assertion failure in ext/soap/php_encoding.c:460). + (nielsdos) + . Fixed bug GH-16259 (Soap segfault when classmap instantiation fails). + (nielsdos) + +- Standard: + . Fixed bug GH-15613 (overflow on unpack call hex string repeater). + (David Carlier) + . Fixed bug GH-15937 (overflow on stream timeout option value). + (David Carlier) + . Fixed bug GH-16053 (Assertion failure in Zend/zend_hash.c). (Arnaud) + +- Streams: + . Fixed bugs GH-15908 and GH-15026 (leak / assertion failure in streams.c). + (nielsdos) + . Fixed bug GH-15980 (Signed integer overflow in main/streams/streams.c). + (cmb) + +- TSRM: + . Prevent closing of unrelated handles. (cmb) + +- XML: + . Fixed bug GH-15868 (Assertion failure in xml_parse_into_struct after + exception). (nielsdos) + +26 Sep 2024, PHP 8.2.24 + +- CGI: + . Fixed bug GHSA-p99j-rfp4-xqvq (Bypass of CVE-2024-4577, Parameter Injection + Vulnerability). (CVE-2024-8926) (nielsdos) + . Fixed bug GHSA-94p6-54jq-9mwp (cgi.force_redirect configuration is + bypassable due to the environment variable collision). (CVE-2024-8927) + (nielsdos) - Core: . Fixed bug GH-15408 (MSan false-positve on zend_max_execution_timer). @@ -26,6 +151,10 @@ PHP NEWS . Fixed bug GH-15752 (Incorrect error message for finfo_file with an empty filename argument). (DanielEScherzer) +- FPM: + . Fixed bug GHSA-865w-9rf3-2wh5 (Logs from childrens may be altered). + (CVE-2024-9026) (Jakub Zelenka) + - MySQLnd: . Fixed bug GH-15432 (Heap corruption when querying a vector). (cmb, Kamil Tekiela) @@ -36,6 +165,10 @@ PHP NEWS . Fixed bug GH-15658 (Segmentation fault in Zend/zend_vm_execute.h). (nielsdos) +- SAPI: + . Fixed bug GHSA-9pqp-7h25-4f32 (Erroneous parsing of multipart form data). + (CVE-2024-8925) (Arnaud) + - SOAP: . Fixed bug #73182 (PHP SOAPClient does not support stream context HTTP headers in array form). (nielsdos) diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 0af03b6ed8985..5d48ea2678a6c 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -707,6 +707,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags) if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) { if (NULL != shm->segment) { CloseHandle(shm->segment); + shm->segment = INVALID_HANDLE_VALUE; } UnmapViewOfFile(shm->descriptor); shm->descriptor = NULL; diff --git a/Zend/tests/generators/gh15851.phpt b/Zend/tests/generators/gh15851.phpt new file mode 100644 index 0000000000000..8a7fa6294e255 --- /dev/null +++ b/Zend/tests/generators/gh15851.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-15851: Access on NULL when printing backtrace with freed generator +--FILE-- + +--EXPECTF-- +#0 %s(%d): Foo->__destruct() +#1 %s(%d): bar() diff --git a/Zend/tests/gh15712.phpt b/Zend/tests/gh15712.phpt new file mode 100644 index 0000000000000..7c4bd0b22ac11 --- /dev/null +++ b/Zend/tests/gh15712.phpt @@ -0,0 +1,9 @@ +--TEST-- +GH-15712: overflow on real number printing +--FILE-- + +--EXPECTF-- +%s diff --git a/Zend/tests/gh15866.phpt b/Zend/tests/gh15866.phpt new file mode 100644 index 0000000000000..99a3a6e6a9524 --- /dev/null +++ b/Zend/tests/gh15866.phpt @@ -0,0 +1,53 @@ +--TEST-- +GH-15866: Core dumped in Zend/zend_generators.c +--FILE-- +next(); + } finally { + print "Fiber finally\n"; + } +}); +$canary->value = $fiber; +$fiber->start(); + +// Reset roots +gc_collect_cycles(); + +// Add to roots, create garbage cycles +$fiber = $iterable = $canary = null; + +print "Collect cycles\n"; +gc_collect_cycles(); + +?> +==DONE== +--EXPECT-- +Collect cycles +Canary::__destruct +Generator finally +Fiber finally +==DONE== diff --git a/Zend/tests/gh15907.phpt b/Zend/tests/gh15907.phpt new file mode 100644 index 0000000000000..8d6dada36ad08 --- /dev/null +++ b/Zend/tests/gh15907.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-15907: Failed assertion when promoting inheritance error to exception +--FILE-- + +--EXPECTF-- +Fatal error: During inheritance of C, while implementing Serializable: Uncaught Exception: C 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:%d +%a diff --git a/Zend/tests/gh16188.phpt b/Zend/tests/gh16188.phpt new file mode 100644 index 0000000000000..4516f7cade90b --- /dev/null +++ b/Zend/tests/gh16188.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-16188 (Assertion failure in Zend/zend_exceptions.c) +--FILE-- +getTraceAsString()); +printf("getPrevious:\n%s\n\n", get_class($re->getPrevious())); +printf("__toString:\n%s\n\n", $re); + +?> +==DONE== +--EXPECTF-- +getTraceAsString: +#0 {main} + +getPrevious: +Exception + +__toString: +Exception in %s:%d +Stack trace:%A +#%d {main} + +Next TypeError in %s:%d +Stack trace:%A +#%d {main} + +==DONE== diff --git a/Zend/zend.h b/Zend/zend.h index a01354a48aeab..d59b2f203fb61 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.2.24-dev" +#define ZEND_VERSION "4.2.25" #define ZEND_ENGINE_3 diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 72cb07decbd38..898318102c1df 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1725,6 +1725,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } while (call && (limit == 0 || frameno < limit)) { + if (UNEXPECTED(!call->func)) { + /* This is the fake frame inserted for nested generators. Normally, + * this frame is preceded by the actual generator frame and then + * replaced by zend_generator_check_placeholder_frame() below. + * However, the frame is popped before cleaning the stack frame, + * which is observable by destructors. */ + call = zend_generator_check_placeholder_frame(call); + ZEND_ASSERT(call->func); + } + zend_execute_data *prev = call->prev_execute_data; if (!prev) { diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 8ad603e51e71c..d2547ced6f7f5 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -115,15 +115,18 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo ex = &zv; do { ancestor = zend_read_property_ex(i_get_exception_base(add_previous), add_previous, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); + ZVAL_DEREF(ancestor); while (Z_TYPE_P(ancestor) == IS_OBJECT) { if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) { OBJ_RELEASE(add_previous); return; } ancestor = zend_read_property_ex(i_get_exception_base(Z_OBJ_P(ancestor)), Z_OBJ_P(ancestor), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); + ZVAL_DEREF(ancestor); } base_ce = i_get_exception_base(Z_OBJ_P(ex)); previous = zend_read_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); + ZVAL_DEREF(previous); if (Z_TYPE_P(previous) == IS_NULL) { zend_update_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv); GC_DELREF(add_previous); @@ -630,6 +633,7 @@ ZEND_METHOD(Exception, getTraceAsString) RETURN_THROWS(); } + ZVAL_DEREF(trace); /* Type should be guaranteed by property type. */ ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY); RETURN_NEW_STR(zend_trace_to_string(Z_ARRVAL_P(trace), /* include_main */ true)); @@ -643,7 +647,7 @@ ZEND_METHOD(Exception, getPrevious) ZEND_PARSE_PARAMETERS_NONE(); - ZVAL_COPY(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS)); + ZVAL_COPY_DEREF(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS)); } /* }}} */ /* {{{ Obtain the string representation of the Exception object */ @@ -723,7 +727,8 @@ ZEND_METHOD(Exception, __toString) Z_PROTECT_RECURSION_P(exception); exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS); - if (exception && Z_TYPE_P(exception) == IS_OBJECT && Z_IS_RECURSIVE_P(exception)) { + ZVAL_DEREF(exception); + if (Z_TYPE_P(exception) == IS_OBJECT && Z_IS_RECURSIVE_P(exception)) { break; } } @@ -731,13 +736,14 @@ ZEND_METHOD(Exception, __toString) exception = ZEND_THIS; /* Reset apply counts */ - while (exception && Z_TYPE_P(exception) == IS_OBJECT && (base_ce = i_get_exception_base(Z_OBJ_P(exception))) && instanceof_function(Z_OBJCE_P(exception), base_ce)) { + while (Z_TYPE_P(exception) == IS_OBJECT && (base_ce = i_get_exception_base(Z_OBJ_P(exception))) && instanceof_function(Z_OBJCE_P(exception), base_ce)) { if (Z_IS_RECURSIVE_P(exception)) { Z_UNPROTECT_RECURSION_P(exception); } else { break; } exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS); + ZVAL_DEREF(exception); } exception = ZEND_THIS; diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 4ac45949bd34a..9089d821f3016 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -218,43 +218,30 @@ static zend_always_inline void clear_link_to_root(zend_generator *generator) { } } -/* In the context of zend_generator_dtor_storage during shutdown, check if - * the intermediate node 'generator' is running in a fiber */ +/* Check if the node 'generator' is running in a fiber */ static inline bool check_node_running_in_fiber(zend_generator *generator) { - ZEND_ASSERT(EG(flags) & EG_FLAGS_IN_SHUTDOWN); ZEND_ASSERT(generator->execute_data); - if (generator->flags & ZEND_GENERATOR_IN_FIBER) { + if (EXPECTED(generator->flags & ZEND_GENERATOR_IN_FIBER)) { return true; } - if (generator->node.children == 0) { + if (EXPECTED(generator->node.children == 0)) { return false; } - if (generator->flags & ZEND_GENERATOR_DTOR_VISITED) { - return false; - } - generator->flags |= ZEND_GENERATOR_DTOR_VISITED; - if (generator->node.children == 1) { - if (check_node_running_in_fiber(generator->node.child.single)) { - goto in_fiber; - } - return false; + return check_node_running_in_fiber(generator->node.child.single); } zend_generator *child; ZEND_HASH_FOREACH_PTR(generator->node.child.ht, child) { if (check_node_running_in_fiber(child)) { - goto in_fiber; + return true; } } ZEND_HASH_FOREACH_END(); - return false; -in_fiber: - generator->flags |= ZEND_GENERATOR_IN_FIBER; - return true; + return false; } static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index a41fb7699d842..00d38a9d28d3f 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -93,7 +93,6 @@ 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 zend_uchar ZEND_GENERATOR_IN_FIBER = 0x10; -static const zend_uchar ZEND_GENERATOR_DTOR_VISITED = 0x20; void zend_register_generator_ce(void); ZEND_API void zend_generator_close(zend_generator *generator, bool finished_execution); diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index b8cc5e94caca8..39d647c7e29f3 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -473,6 +473,10 @@ static int zend_implement_serializable(zend_class_entry *interface, zend_class_e if (!(class_type->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (!class_type->__serialize || !class_type->__unserialize)) { zend_error(E_DEPRECATED, "%s implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary)", ZSTR_VAL(class_type->name)); + if (EG(exception)) { + zend_exception_uncaught_error( + "During inheritance of %s, while implementing Serializable", ZSTR_VAL(class_type->name)); + } } return SUCCESS; } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index d4586e53e4b4a..def9695ed98bd 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -30,6 +30,7 @@ #include "zend_closures.h" #include "zend_compile.h" #include "zend_hash.h" +#include "zend_observer.h" #define DEBUG_OBJECT_HANDLERS 0 @@ -1294,7 +1295,8 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend * 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; + uint32_t min_T = 2 + ZEND_OBSERVER_ENABLED; + func->T = (fbc->type == ZEND_USER_FUNCTION)? MAX(fbc->op_array.last_var + fbc->op_array.T, min_T) : min_T; 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; func->line_end = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_end : 0; diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index e98956239ec3b..ce8b7f5e0a2a7 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -27,7 +27,20 @@ #include #ifdef HAVE_IEEEFP_H -#include +/** + * On FreeBSD with ubsan/clang we get the following: + * `/usr/include/machine/ieeefp.h:161:17: runtime error: left shift of negative value -1` + * `SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/include/machine/ieeefp.h:161:17` + * ... + * `_newcw |= (~_m << FP_MSKS_OFF) & FP_MSKS_FLD;` +**/ +# if __has_feature(undefined_behavior_sanitizer) && defined(__FreeBSD__) && defined(__clang__) +# pragma clang attribute push (__attribute__((no_sanitize("undefined"))), apply_to=function) +# endif +# include +# if __has_feature(undefined_behavior_sanitizer) && defined(__FreeBSD__) && defined(__clang__) +# pragma clang attribute pop +# endif #endif #include "zend_portability.h" diff --git a/Zend/zend_strtod.c b/Zend/zend_strtod.c index 3e7f90378ef5e..eb3a94332ae35 100644 --- a/Zend/zend_strtod.c +++ b/Zend/zend_strtod.c @@ -3613,11 +3613,11 @@ rv_alloc(i) int i; rv_alloc(int i) #endif { - int j, k, *r; + int k, *r; - j = sizeof(ULong); + size_t j = sizeof(ULong); for(k = 0; - sizeof(Bigint) - sizeof(ULong) - sizeof(int) + (size_t)j <= (size_t)i; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)i; j <<= 1) k++; r = (int*)Balloc(k); diff --git a/build/php.m4 b/build/php.m4 index 32487e4b389ec..e13fc3367ea1e 100644 --- a/build/php.m4 +++ b/build/php.m4 @@ -2735,3 +2735,15 @@ AC_DEFUN([PHP_PATCH_CONFIG_HEADERS], [ $SED -e 's/^#undef PACKAGE_[^ ]*/\/\* & \*\//g' < $srcdir/$1 \ > $srcdir/$1.tmp && mv $srcdir/$1.tmp $srcdir/$1 ]) + +dnl +dnl PHP_REMOVE_OPTIMIZATION_FLAGS +dnl +dnl Removes known compiler optimization flags like -O, -O0, -O1, ..., -Ofast +dnl from CFLAGS and CXXFLAGS. +dnl +AC_DEFUN([PHP_REMOVE_OPTIMIZATION_FLAGS], [ + sed_script='s/\([[\t ]]\|^\)-O\([[0-9gsz]]\|fast\|\)\([[\t ]]\|$\)/\1/g' + CFLAGS=$(echo "$CFLAGS" | $SED -e "$sed_script") + CXXFLAGS=$(echo "$CXXFLAGS" | $SED -e "$sed_script") +]) diff --git a/configure.ac b/configure.ac index fb59a81700f4b..8617033a55648 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.2.24-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.2.25],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER @@ -845,10 +845,7 @@ if test "$PHP_GCOV" = "yes"; then PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/build/Makefile.gcov, $abs_srcdir) dnl Remove all optimization flags from CFLAGS. - changequote({,}) - CFLAGS=`echo "$CFLAGS" | "${SED}" -e 's/-O[0-9s]*//g'` - CXXFLAGS=`echo "$CXXFLAGS" | "${SED}" -e 's/-O[0-9s]*//g'` - changequote([,]) + PHP_REMOVE_OPTIMIZATION_FLAGS dnl Add the special gcc flags. CFLAGS="$CFLAGS -O0 -fprofile-arcs -ftest-coverage" @@ -865,10 +862,7 @@ PHP_ARG_ENABLE([debug], if test "$PHP_DEBUG" = "yes"; then PHP_DEBUG=1 ZEND_DEBUG=yes - changequote({,}) - CFLAGS=`echo "$CFLAGS" | "${SED}" -e 's/-O[0-9s]*//g'` - CXXFLAGS=`echo "$CXXFLAGS" | "${SED}" -e 's/-O[0-9s]*//g'` - changequote([,]) + PHP_REMOVE_OPTIMIZATION_FLAGS dnl Add -O0 only if GCC or ICC is used. if test "$GCC" = "yes" || test "$ICC" = "yes"; then CFLAGS="$CFLAGS -O0" diff --git a/ext/calendar/cal_unix.c b/ext/calendar/cal_unix.c index 78a08fdef0aa5..c3fe5557d244e 100644 --- a/ext/calendar/cal_unix.c +++ b/ext/calendar/cal_unix.c @@ -60,13 +60,13 @@ PHP_FUNCTION(jdtounix) if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &uday) == FAILURE) { RETURN_THROWS(); } - uday -= 2440588 /* J.D. of 1.1.1970 */; - - if (uday < 0 || uday > ZEND_LONG_MAX / SECS_PER_DAY) { /* before beginning of unix epoch or greater than representable */ + if (uday < 2440588 || (uday - 2440588) > (ZEND_LONG_MAX / SECS_PER_DAY)) { /* before beginning of unix epoch or greater than representable */ zend_value_error("jday must be between 2440588 and " ZEND_LONG_FMT, ZEND_LONG_MAX / SECS_PER_DAY + 2440588); RETURN_THROWS(); } + uday -= 2440588 /* J.D. of 1.1.1970 */; + RETURN_LONG(uday * SECS_PER_DAY); } /* }}} */ diff --git a/ext/calendar/dow.c b/ext/calendar/dow.c index 38da7e157c279..079dd6c15ada4 100644 --- a/ext/calendar/dow.c +++ b/ext/calendar/dow.c @@ -33,14 +33,7 @@ int DayOfWeek( zend_long sdn) { - int dow; - - dow = (sdn + 1) % 7; - if (dow >= 0) { - return (dow); - } else { - return (dow + 7); - } + return (int)(sdn % 7 + 8) % 7; } const char * const DayNameShort[7] = diff --git a/ext/calendar/easter.c b/ext/calendar/easter.c index c319abd17fef0..00df5dcf1d592 100644 --- a/ext/calendar/easter.c +++ b/ext/calendar/easter.c @@ -28,6 +28,7 @@ static void _cal_easter(INTERNAL_FUNCTION_PARAMETERS, bool gm) struct tm te; zend_long year, golden, solar, lunar, pfm, dom, tmp, easter, result; zend_long method = CAL_EASTER_DEFAULT; + const zend_long max_year = (zend_long)(ZEND_LONG_MAX / 5) * 4; bool year_is_null = 1; if (zend_parse_parameters(ZEND_NUM_ARGS(), @@ -48,6 +49,11 @@ static void _cal_easter(INTERNAL_FUNCTION_PARAMETERS, bool gm) } } + if (year <= 0 || year > max_year) { + zend_argument_value_error(1, "must be between 1 and " ZEND_LONG_FMT, max_year); + RETURN_THROWS(); + } + if (gm && (year<1970 || year>2037)) { /* out of range for timestamps */ zend_argument_value_error(1, "must be between 1970 and 2037 (inclusive)"); RETURN_THROWS(); diff --git a/ext/calendar/jewish.c b/ext/calendar/jewish.c index 11318bd5bc619..bdfc9b4f91016 100644 --- a/ext/calendar/jewish.c +++ b/ext/calendar/jewish.c @@ -433,16 +433,31 @@ static void MoladOfMetonicCycle( zend_long *pMoladHalakim) { register zend_ulong r1, r2, d1, d2; + zend_long chk; /* Start with the time of the first molad after creation. */ r1 = NEW_MOON_OF_CREATION; + chk = (zend_long)metonicCycle; + + if (chk > (ZEND_LONG_MAX - NEW_MOON_OF_CREATION) / (HALAKIM_PER_METONIC_CYCLE & 0xFFFF)) { + *pMoladDay = 0; + *pMoladHalakim = 0; + return; + } /* Calculate metonicCycle * HALAKIM_PER_METONIC_CYCLE. The upper 32 * bits of the result will be in r2 and the lower 16 bits will be * in r1. */ - r1 += metonicCycle * (HALAKIM_PER_METONIC_CYCLE & 0xFFFF); + r1 += chk * (HALAKIM_PER_METONIC_CYCLE & 0xFFFF); + + if (chk > (ZEND_LONG_MAX - (r1 >> 16)) / ((HALAKIM_PER_METONIC_CYCLE >> 16) & 0xFFFF)) { + *pMoladDay = 0; + *pMoladHalakim = 0; + return; + } + r2 = r1 >> 16; - r2 += metonicCycle * ((HALAKIM_PER_METONIC_CYCLE >> 16) & 0xFFFF); + r2 += chk * ((HALAKIM_PER_METONIC_CYCLE >> 16) & 0xFFFF); /* Calculate r2r1 / HALAKIM_PER_DAY. The remainder will be in r1, the * upper 16 bits of the quotient will be in d2 and the lower 16 bits diff --git a/ext/calendar/tests/gh16228.phpt b/ext/calendar/tests/gh16228.phpt new file mode 100644 index 0000000000000..9ce80688195ba --- /dev/null +++ b/ext/calendar/tests/gh16228.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-16228 (easter_days, Overflow on year argument) +--EXTENSIONS-- +calendar +--FILE-- +getMessage() . PHP_EOL; +} +try { + easter_days(-1, 0); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + easter_date(PHP_INT_MAX, 0); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +?> +--EXPECTF-- +easter_days(): Argument #1 ($year) must be between 1 and %d +easter_days(): Argument #1 ($year) must be between 1 and %d +easter_date(): Argument #1 ($year) must be between 1 and %d diff --git a/ext/calendar/tests/gh16231.phpt b/ext/calendar/tests/gh16231.phpt new file mode 100644 index 0000000000000..89b09dd3f63ae --- /dev/null +++ b/ext/calendar/tests/gh16231.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-16231 (jdtounix argument overflow) +--EXTENSIONS-- +calendar +--FILE-- +getMessage() . PHP_EOL; +} + +try { + jdtounix(240587); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +jday must be between 2440588 and %d +jday must be between 2440588 and %d diff --git a/ext/calendar/tests/gh16234.phpt b/ext/calendar/tests/gh16234.phpt new file mode 100644 index 0000000000000..03777986dc8c3 --- /dev/null +++ b/ext/calendar/tests/gh16234.phpt @@ -0,0 +1,11 @@ +--TEST-- +GH-16234 jewishtojd overflow on year argument +--EXTENSIONS-- +calendar +--FILE-- + +--EXPECT-- +DONE diff --git a/ext/calendar/tests/gh16258.phpt b/ext/calendar/tests/gh16258.phpt new file mode 100644 index 0000000000000..9f2b70fac542b --- /dev/null +++ b/ext/calendar/tests/gh16258.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-16258 (jddayofweek overflow on argument) +--EXTENSIONS-- +calendar +--FILE-- + +--EXPECT-- +DONE diff --git a/ext/curl/tests/bug48203_multi.phpt b/ext/curl/tests/bug48203_multi.phpt index 19077147a611e..ec9748517ab85 100644 --- a/ext/curl/tests/bug48203_multi.phpt +++ b/ext/curl/tests/bug48203_multi.phpt @@ -2,6 +2,13 @@ Variation of bug #48203 with curl_multi_exec (Crash when file pointers passed to curl are closed before calling curl_multi_exec) --EXTENSIONS-- curl +--SKIPIF-- + --FILE-- --FILE-- --EXTENSIONS-- curl +--SKIPIF-- + --FILE-- --FILE-- '9')) && (**ptr != '+') && (**ptr != '-')) { if (**ptr == '\0') { add_error(s, TIMELIB_ERR_UNEXPECTED_DATA, "Found unexpected data"); - timelib_free(str); return 0; } ++*ptr; } + + /* Allocate string to feed to strtoll(): sign + length + '\0' */ + str = timelib_calloc(1, max_length + 2); + str[0] = '+'; /* First position is the sign */ + str_ptr = str + 1; - if ((**ptr == '+') || (**ptr == '-')) { - *str_ptr = **ptr; + while ((**ptr == '+') || (**ptr == '-')) { + if (**ptr == '-') { + str[0] = str[0] == '+' ? '-' : '+'; + } ++*ptr; - ++str_ptr; } while (((**ptr < '0') || (**ptr > '9'))) { @@ -715,7 +719,7 @@ static const timelib_relunit* timelib_lookup_relunit(const char **ptr) static void add_with_overflow(Scanner *s, timelib_sll *e, timelib_sll amount, int multiplier) { -#if defined(__has_builtin) && __has_builtin(__builtin_saddll_overflow) +#if TIMELIB_HAVE_BUILTIN_SADDLL_OVERFLOW if (__builtin_saddll_overflow(*e, amount * multiplier, e)) { add_error(s, TIMELIB_ERR_NUMBER_OUT_OF_RANGE, "Number out of range"); } @@ -1014,11 +1018,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) std: s->tok = cursor; s->len = 0; -#line 1147 "ext/date/lib/parse_date.re" +#line 1151 "ext/date/lib/parse_date.re" -#line 1022 "" +#line 1026 "" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -1199,23 +1203,23 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(2, *YYCURSOR); ++YYCURSOR; YYDEBUG(3, *YYCURSOR); -#line 1980 "ext/date/lib/parse_date.re" +#line 1984 "ext/date/lib/parse_date.re" { s->pos = cursor; s->line++; goto std; } -#line 1208 "" +#line 1212 "" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; yy5: YYDEBUG(5, *YYCURSOR); -#line 1986 "ext/date/lib/parse_date.re" +#line 1990 "ext/date/lib/parse_date.re" { add_error(s, TIMELIB_ERR_UNEXPECTED_CHARACTER, "Unexpected character"); goto std; } -#line 1219 "" +#line 1223 "" yy6: YYDEBUG(6, *YYCURSOR); yyaccept = 0; @@ -1230,11 +1234,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy58; yy8: YYDEBUG(8, *YYCURSOR); -#line 1975 "ext/date/lib/parse_date.re" +#line 1979 "ext/date/lib/parse_date.re" { goto std; } -#line 1238 "" +#line 1242 "" yy9: YYDEBUG(9, *YYCURSOR); yych = *++YYCURSOR; @@ -1268,11 +1272,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(11, *YYCURSOR); ++YYCURSOR; YYDEBUG(12, *YYCURSOR); -#line 1970 "ext/date/lib/parse_date.re" +#line 1974 "ext/date/lib/parse_date.re" { goto std; } -#line 1276 "" +#line 1280 "" yy13: YYDEBUG(13, *YYCURSOR); yyaccept = 1; @@ -1773,7 +1777,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy20: YYDEBUG(20, *YYCURSOR); -#line 1885 "ext/date/lib/parse_date.re" +#line 1889 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("tzcorrection | tz"); @@ -1787,7 +1791,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIMEZONE; } -#line 1791 "" +#line 1795 "" yy21: YYDEBUG(21, *YYCURSOR); yych = *++YYCURSOR; @@ -3592,7 +3596,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy81: YYDEBUG(81, *YYCURSOR); -#line 1632 "ext/date/lib/parse_date.re" +#line 1636 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenoyearrev"); TIMELIB_INIT; @@ -3603,7 +3607,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 3607 "" +#line 3611 "" yy82: YYDEBUG(82, *YYCURSOR); yych = *++YYCURSOR; @@ -4118,7 +4122,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } if (yych == '.') goto yy289; YYDEBUG(114, *YYCURSOR); -#line 1207 "ext/date/lib/parse_date.re" +#line 1211 "ext/date/lib/parse_date.re" { timelib_ull i; @@ -4143,7 +4147,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 4147 "" +#line 4151 "" yy115: YYDEBUG(115, *YYCURSOR); ++YYCURSOR; @@ -5869,7 +5873,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy177: YYDEBUG(177, *YYCURSOR); -#line 1373 "ext/date/lib/parse_date.re" +#line 1377 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("timetiny24 | timeshort24 | timelong24 | iso8601long"); @@ -5896,7 +5900,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 5900 "" +#line 5904 "" yy178: YYDEBUG(178, *YYCURSOR); yyaccept = 4; @@ -6925,7 +6929,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy224: YYDEBUG(224, *YYCURSOR); -#line 1467 "ext/date/lib/parse_date.re" +#line 1471 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("americanshort | american"); @@ -6940,7 +6944,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AMERICAN; } -#line 6944 "" +#line 6948 "" yy225: YYDEBUG(225, *YYCURSOR); yyaccept = 5; @@ -7183,7 +7187,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy431; yy251: YYDEBUG(251, *YYCURSOR); -#line 1549 "ext/date/lib/parse_date.re" +#line 1553 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datefull"); @@ -7197,7 +7201,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL; } -#line 7201 "" +#line 7205 "" yy252: YYDEBUG(252, *YYCURSOR); yyaccept = 3; @@ -7311,7 +7315,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy440; yy260: YYDEBUG(260, *YYCURSOR); -#line 1954 "ext/date/lib/parse_date.re" +#line 1958 "ext/date/lib/parse_date.re" { timelib_ull i; DEBUG_OUTPUT("relative"); @@ -7326,7 +7330,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7330 "" +#line 7334 "" yy261: YYDEBUG(261, *YYCURSOR); yych = *++YYCURSOR; @@ -7772,7 +7776,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy471; yy290: YYDEBUG(290, *YYCURSOR); -#line 1233 "ext/date/lib/parse_date.re" +#line 1237 "ext/date/lib/parse_date.re" { timelib_sll i; timelib_ull us; @@ -7811,7 +7815,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7815 "" +#line 7819 "" yy291: YYDEBUG(291, *YYCURSOR); yych = *++YYCURSOR; @@ -7836,7 +7840,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy293: YYDEBUG(293, *YYCURSOR); -#line 1795 "ext/date/lib/parse_date.re" +#line 1799 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("ago"); TIMELIB_INIT; @@ -7856,7 +7860,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AGO; } -#line 7860 "" +#line 7864 "" yy294: YYDEBUG(294, *YYCURSOR); yyaccept = 7; @@ -7895,7 +7899,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy295: YYDEBUG(295, *YYCURSOR); -#line 1875 "ext/date/lib/parse_date.re" +#line 1879 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("monthtext"); TIMELIB_INIT; @@ -7904,7 +7908,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 7908 "" +#line 7912 "" yy296: YYDEBUG(296, *YYCURSOR); yyaccept = 7; @@ -8479,7 +8483,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy315: YYDEBUG(315, *YYCURSOR); -#line 1816 "ext/date/lib/parse_date.re" +#line 1820 "ext/date/lib/parse_date.re" { const timelib_relunit* relunit; DEBUG_OUTPUT("daytext"); @@ -8496,7 +8500,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEKDAY; } -#line 8500 "" +#line 8504 "" yy316: YYDEBUG(316, *YYCURSOR); yych = *++YYCURSOR; @@ -8764,7 +8768,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy325: YYDEBUG(325, *YYCURSOR); -#line 1618 "ext/date/lib/parse_date.re" +#line 1622 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datetextual | datenoyear"); @@ -8777,7 +8781,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 8781 "" +#line 8785 "" yy326: YYDEBUG(326, *YYCURSOR); yyaccept = 10; @@ -9471,7 +9475,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy351: YYDEBUG(351, *YYCURSOR); -#line 1164 "ext/date/lib/parse_date.re" +#line 1168 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("now"); TIMELIB_INIT; @@ -9479,7 +9483,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 9483 "" +#line 9487 "" yy352: YYDEBUG(352, *YYCURSOR); yyaccept = 2; @@ -10982,7 +10986,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy420: YYDEBUG(420, *YYCURSOR); -#line 1401 "ext/date/lib/parse_date.re" +#line 1405 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnunocolon"); TIMELIB_INIT; @@ -11004,7 +11008,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_GNU_NOCOLON; } -#line 11008 "" +#line 11012 "" yy421: YYDEBUG(421, *YYCURSOR); yyaccept = 13; @@ -11085,7 +11089,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy422: YYDEBUG(422, *YYCURSOR); -#line 1786 "ext/date/lib/parse_date.re" +#line 1790 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("year4"); TIMELIB_INIT; @@ -11093,7 +11097,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 11097 "" +#line 11101 "" yy423: YYDEBUG(423, *YYCURSOR); yyaccept = 3; @@ -11700,7 +11704,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(456, *YYCURSOR); ++YYCURSOR; YYDEBUG(457, *YYCURSOR); -#line 1335 "ext/date/lib/parse_date.re" +#line 1339 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12"); TIMELIB_INIT; @@ -11717,7 +11721,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME12; } -#line 11721 "" +#line 11725 "" yy458: YYDEBUG(458, *YYCURSOR); yych = *++YYCURSOR; @@ -13044,7 +13048,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy526: YYDEBUG(526, *YYCURSOR); -#line 1173 "ext/date/lib/parse_date.re" +#line 1177 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("noon"); TIMELIB_INIT; @@ -13055,7 +13059,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 13059 "" +#line 13063 "" yy527: YYDEBUG(527, *YYCURSOR); yyaccept = 2; @@ -14101,7 +14105,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy567: YYDEBUG(567, *YYCURSOR); -#line 1535 "ext/date/lib/parse_date.re" +#line 1539 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshort"); @@ -14114,7 +14118,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 14118 "" +#line 14122 "" yy568: YYDEBUG(568, *YYCURSOR); yyaccept = 15; @@ -14565,7 +14569,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy600: YYDEBUG(600, *YYCURSOR); -#line 1604 "ext/date/lib/parse_date.re" +#line 1608 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenodayrev"); @@ -14578,7 +14582,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 14582 "" +#line 14586 "" yy601: YYDEBUG(601, *YYCURSOR); yych = *++YYCURSOR; @@ -15953,7 +15957,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(696, *YYCURSOR); ++YYCURSOR; YYDEBUG(697, *YYCURSOR); -#line 1590 "ext/date/lib/parse_date.re" +#line 1594 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenoday"); @@ -15966,7 +15970,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 15970 "" +#line 15974 "" yy698: YYDEBUG(698, *YYCURSOR); yych = *++YYCURSOR; @@ -16527,7 +16531,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy722: YYDEBUG(722, *YYCURSOR); -#line 1185 "ext/date/lib/parse_date.re" +#line 1189 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("midnight | today"); TIMELIB_INIT; @@ -16536,7 +16540,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 16540 "" +#line 16544 "" yy723: YYDEBUG(723, *YYCURSOR); yych = *++YYCURSOR; @@ -16846,7 +16850,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy897; yy739: YYDEBUG(739, *YYCURSOR); -#line 1576 "ext/date/lib/parse_date.re" +#line 1580 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pointed date YY"); @@ -16859,7 +16863,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 16863 "" +#line 16867 "" yy740: YYDEBUG(740, *YYCURSOR); yyaccept = 15; @@ -16971,7 +16975,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy752: YYDEBUG(752, *YYCURSOR); -#line 1521 "ext/date/lib/parse_date.re" +#line 1525 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshorter"); @@ -16984,7 +16988,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 16988 "" +#line 16992 "" yy753: YYDEBUG(753, *YYCURSOR); yyaccept = 18; @@ -17233,7 +17237,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy777: YYDEBUG(777, *YYCURSOR); -#line 1447 "ext/date/lib/parse_date.re" +#line 1451 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("iso8601nocolon"); @@ -17252,7 +17256,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_NOCOLON; } -#line 17256 "" +#line 17260 "" yy778: YYDEBUG(778, *YYCURSOR); yyaccept = 19; @@ -18480,7 +18484,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy849: YYDEBUG(849, *YYCURSOR); -#line 1924 "ext/date/lib/parse_date.re" +#line 1928 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz"); @@ -18509,7 +18513,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 18513 "" +#line 18517 "" yy850: YYDEBUG(850, *YYCURSOR); yyaccept = 20; @@ -19553,7 +19557,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy926: YYDEBUG(926, *YYCURSOR); -#line 1682 "ext/date/lib/parse_date.re" +#line 1686 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgydotd"); @@ -19566,7 +19570,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_YEARDAY; } -#line 19570 "" +#line 19574 "" yy927: YYDEBUG(927, *YYCURSOR); yyaccept = 21; @@ -19820,7 +19824,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '7') goto yy1059; yy942: YYDEBUG(942, *YYCURSOR); -#line 1715 "ext/date/lib/parse_date.re" +#line 1719 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweek"); @@ -19838,7 +19842,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 19842 "" +#line 19846 "" yy943: YYDEBUG(943, *YYCURSOR); yych = *++YYCURSOR; @@ -20314,7 +20318,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy1094; yy982: YYDEBUG(982, *YYCURSOR); -#line 1858 "ext/date/lib/parse_date.re" +#line 1862 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -20330,7 +20334,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 20334 "" +#line 20338 "" yy983: YYDEBUG(983, *YYCURSOR); yych = *++YYCURSOR; @@ -20677,7 +20681,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1020, *YYCURSOR); ++YYCURSOR; YYDEBUG(1021, *YYCURSOR); -#line 1564 "ext/date/lib/parse_date.re" +#line 1568 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pointed date YYYY"); TIMELIB_INIT; @@ -20688,7 +20692,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 20692 "" +#line 20696 "" yy1022: YYDEBUG(1022, *YYCURSOR); ++YYCURSOR; @@ -20717,7 +20721,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1025: YYDEBUG(1025, *YYCURSOR); -#line 1495 "ext/date/lib/parse_date.re" +#line 1499 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("iso8601date2"); @@ -20730,7 +20734,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20734 "" +#line 20738 "" yy1026: YYDEBUG(1026, *YYCURSOR); yyaccept = 15; @@ -20950,7 +20954,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1043: YYDEBUG(1043, *YYCURSOR); -#line 1483 "ext/date/lib/parse_date.re" +#line 1487 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash"); TIMELIB_INIT; @@ -20961,7 +20965,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20965 "" +#line 20969 "" yy1044: YYDEBUG(1044, *YYCURSOR); yyaccept = 26; @@ -21076,7 +21080,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1048: YYDEBUG(1048, *YYCURSOR); -#line 1644 "ext/date/lib/parse_date.re" +#line 1648 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenocolon"); TIMELIB_INIT; @@ -21087,7 +21091,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NOCOLON; } -#line 21091 "" +#line 21095 "" yy1049: YYDEBUG(1049, *YYCURSOR); yych = *++YYCURSOR; @@ -21157,7 +21161,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1059, *YYCURSOR); ++YYCURSOR; YYDEBUG(1060, *YYCURSOR); -#line 1696 "ext/date/lib/parse_date.re" +#line 1700 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweekday"); @@ -21175,7 +21179,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 21179 "" +#line 21183 "" yy1061: YYDEBUG(1061, *YYCURSOR); yych = *++YYCURSOR; @@ -21238,7 +21242,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1143; yy1070: YYDEBUG(1070, *YYCURSOR); -#line 1734 "ext/date/lib/parse_date.re" +#line 1738 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextshort"); @@ -21251,7 +21255,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 21255 "" +#line 21259 "" yy1071: YYDEBUG(1071, *YYCURSOR); yych = *++YYCURSOR; @@ -21724,7 +21728,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1107: YYDEBUG(1107, *YYCURSOR); -#line 1195 "ext/date/lib/parse_date.re" +#line 1199 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("tomorrow"); TIMELIB_INIT; @@ -21735,7 +21739,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 21739 "" +#line 21743 "" yy1108: YYDEBUG(1108, *YYCURSOR); yyaccept = 28; @@ -22072,7 +22076,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1140, *YYCURSOR); ++YYCURSOR; YYDEBUG(1141, *YYCURSOR); -#line 1748 "ext/date/lib/parse_date.re" +#line 1752 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextreverse"); @@ -22085,7 +22089,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 22089 "" +#line 22093 "" yy1142: YYDEBUG(1142, *YYCURSOR); ++YYCURSOR; @@ -22129,7 +22133,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1145: YYDEBUG(1145, *YYCURSOR); -#line 1290 "ext/date/lib/parse_date.re" +#line 1294 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("backof | frontof"); TIMELIB_INIT; @@ -22151,7 +22155,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 22155 "" +#line 22159 "" yy1146: YYDEBUG(1146, *YYCURSOR); yyaccept = 29; @@ -22475,7 +22479,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1172: YYDEBUG(1172, *YYCURSOR); -#line 1834 "ext/date/lib/parse_date.re" +#line 1838 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -22498,7 +22502,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22502 "" +#line 22506 "" yy1173: YYDEBUG(1173, *YYCURSOR); yych = *++YYCURSOR; @@ -22510,7 +22514,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1175: YYDEBUG(1175, *YYCURSOR); -#line 1152 "ext/date/lib/parse_date.re" +#line 1156 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("yesterday"); TIMELIB_INIT; @@ -22521,7 +22525,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22525 "" +#line 22529 "" yy1176: YYDEBUG(1176, *YYCURSOR); yyaccept = 31; @@ -23014,7 +23018,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1222, *YYCURSOR); ++YYCURSOR; YYDEBUG(1223, *YYCURSOR); -#line 1900 "ext/date/lib/parse_date.re" +#line 1904 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12"); TIMELIB_INIT; @@ -23037,7 +23041,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 23041 "" +#line 23045 "" yy1224: YYDEBUG(1224, *YYCURSOR); yych = *++YYCURSOR; @@ -23539,7 +23543,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1268, *YYCURSOR); ++YYCURSOR; YYDEBUG(1269, *YYCURSOR); -#line 1313 "ext/date/lib/parse_date.re" +#line 1317 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -23560,7 +23564,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEK_DAY_OF_MONTH; } -#line 23564 "" +#line 23568 "" yy1270: YYDEBUG(1270, *YYCURSOR); yyaccept = 24; @@ -23607,7 +23611,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1273, *YYCURSOR); ++YYCURSOR; YYDEBUG(1274, *YYCURSOR); -#line 1273 "ext/date/lib/parse_date.re" +#line 1277 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("firstdayof | lastdayof"); TIMELIB_INIT; @@ -23623,12 +23627,12 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 23627 "" +#line 23631 "" yy1275: YYDEBUG(1275, *YYCURSOR); ++YYCURSOR; YYDEBUG(1276, *YYCURSOR); -#line 1509 "ext/date/lib/parse_date.re" +#line 1513 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601datex"); TIMELIB_INIT; @@ -23639,7 +23643,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 23643 "" +#line 23647 "" yy1277: YYDEBUG(1277, *YYCURSOR); yych = *++YYCURSOR; @@ -23742,7 +23746,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1290, *YYCURSOR); ++YYCURSOR; YYDEBUG(1291, *YYCURSOR); -#line 1353 "ext/date/lib/parse_date.re" +#line 1357 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("mssqltime"); TIMELIB_INIT; @@ -23761,7 +23765,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 23765 "" +#line 23769 "" yy1292: YYDEBUG(1292, *YYCURSOR); yych = *++YYCURSOR; @@ -24185,7 +24189,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1331; yy1329: YYDEBUG(1329, *YYCURSOR); -#line 1656 "ext/date/lib/parse_date.re" +#line 1660 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif"); @@ -24210,7 +24214,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_XMLRPC_SOAP; } -#line 24214 "" +#line 24218 "" yy1330: YYDEBUG(1330, *YYCURSOR); yych = *++YYCURSOR; @@ -24580,7 +24584,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= ':') goto yy1383; yy1375: YYDEBUG(1375, *YYCURSOR); -#line 1762 "ext/date/lib/parse_date.re" +#line 1766 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("clf"); @@ -24603,7 +24607,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 24607 "" +#line 24611 "" yy1376: YYDEBUG(1376, *YYCURSOR); yyaccept = 33; @@ -24835,7 +24839,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == ':') goto yy1286; goto yy1329; } -#line 1990 "ext/date/lib/parse_date.re" +#line 1994 "ext/date/lib/parse_date.re" } diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index 5d259ed4e2c75..d32be9bfe7be7 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -547,22 +547,26 @@ static timelib_ull timelib_get_signed_nr(Scanner *s, const char **ptr, int max_l timelib_sll tmp_nr = 0; int len = 0; - str = timelib_calloc(1, max_length + 2); // for sign and \0 - str_ptr = str; + /* Skip over non-numeric chars */ while (((**ptr < '0') || (**ptr > '9')) && (**ptr != '+') && (**ptr != '-')) { if (**ptr == '\0') { add_error(s, TIMELIB_ERR_UNEXPECTED_DATA, "Found unexpected data"); - timelib_free(str); return 0; } ++*ptr; } + + /* Allocate string to feed to strtoll(): sign + length + '\0' */ + str = timelib_calloc(1, max_length + 2); + str[0] = '+'; /* First position is the sign */ + str_ptr = str + 1; - if ((**ptr == '+') || (**ptr == '-')) { - *str_ptr = **ptr; + while ((**ptr == '+') || (**ptr == '-')) { + if (**ptr == '-') { + str[0] = str[0] == '+' ? '-' : '+'; + } ++*ptr; - ++str_ptr; } while (((**ptr < '0') || (**ptr > '9'))) { @@ -713,7 +717,7 @@ static const timelib_relunit* timelib_lookup_relunit(const char **ptr) static void add_with_overflow(Scanner *s, timelib_sll *e, timelib_sll amount, int multiplier) { -#if defined(__has_builtin) && __has_builtin(__builtin_saddll_overflow) +#if TIMELIB_HAVE_BUILTIN_SADDLL_OVERFLOW if (__builtin_saddll_overflow(*e, amount * multiplier, e)) { add_error(s, TIMELIB_ERR_NUMBER_OUT_OF_RANGE, "Number out of range"); } diff --git a/ext/date/lib/parse_iso_intervals.c b/ext/date/lib/parse_iso_intervals.c index 6715d5cee525f..cdc329431ec45 100644 --- a/ext/date/lib/parse_iso_intervals.c +++ b/ext/date/lib/parse_iso_intervals.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.15.3 on Wed Sep 14 16:32:05 2022 */ +/* Generated by re2c 1.0.3 on Wed Sep 11 17:29:40 2024 */ #line 1 "ext/date/lib/parse_iso_intervals.re" /* * The MIT License (MIT) @@ -223,54 +223,72 @@ static int scan(Scanner *s) yych = *YYCURSOR; if (yych <= ',') { if (yych <= '\n') { - if (yych <= 0x00) goto yy9; - if (yych <= 0x08) goto yy11; - if (yych <= '\t') goto yy7; - goto yy9; + if (yych <= 0x00) goto yy2; + if (yych <= 0x08) goto yy4; + if (yych <= '\t') goto yy6; } else { - if (yych == ' ') goto yy7; - if (yych <= '+') goto yy11; - goto yy7; + if (yych == ' ') goto yy6; + if (yych <= '+') goto yy4; + goto yy6; } } else { if (yych <= 'O') { - if (yych <= '-') goto yy11; - if (yych <= '/') goto yy7; - if (yych <= '9') goto yy4; - goto yy11; + if (yych <= '-') goto yy4; + if (yych <= '/') goto yy6; + if (yych <= '9') goto yy8; + goto yy4; } else { - if (yych <= 'P') goto yy5; - if (yych != 'R') goto yy11; + if (yych <= 'P') goto yy9; + if (yych == 'R') goto yy11; + goto yy4; } } +yy2: YYDEBUG(2, *YYCURSOR); ++YYCURSOR; - if ((yych = *YYCURSOR) <= '/') goto yy3; - if (yych <= '9') goto yy98; -yy3: YYDEBUG(3, *YYCURSOR); -#line 317 "ext/date/lib/parse_iso_intervals.re" +#line 311 "ext/date/lib/parse_iso_intervals.re" { - add_error(s, "Unexpected character"); + s->pos = cursor; s->line++; goto std; } -#line 258 "" +#line 256 "" yy4: YYDEBUG(4, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '/') goto yy3; - if (yych <= '9') goto yy59; - goto yy3; + ++YYCURSOR; yy5: YYDEBUG(5, *YYCURSOR); - yyaccept = 1; - yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '/') goto yy6; - if (yych <= '9') goto yy12; - if (yych == 'T') goto yy14; +#line 317 "ext/date/lib/parse_iso_intervals.re" + { + add_error(s, "Unexpected character"); + goto std; + } +#line 267 "" yy6: YYDEBUG(6, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(7, *YYCURSOR); +#line 306 "ext/date/lib/parse_iso_intervals.re" + { + goto std; + } +#line 276 "" +yy8: + YYDEBUG(8, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '/') goto yy5; + if (yych <= '9') goto yy12; + goto yy5; +yy9: + YYDEBUG(9, *YYCURSOR); + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '/') goto yy10; + if (yych <= '9') goto yy14; + if (yych == 'T') goto yy15; +yy10: + YYDEBUG(10, *YYCURSOR); #line 244 "ext/date/lib/parse_iso_intervals.re" { timelib_sll nr; @@ -312,189 +330,197 @@ static int scan(Scanner *s) TIMELIB_DEINIT; return TIMELIB_PERIOD; } -#line 316 "" -yy7: - YYDEBUG(7, *YYCURSOR); - ++YYCURSOR; - YYDEBUG(8, *YYCURSOR); -#line 306 "ext/date/lib/parse_iso_intervals.re" - { - goto std; - } -#line 325 "" -yy9: - YYDEBUG(9, *YYCURSOR); - ++YYCURSOR; - YYDEBUG(10, *YYCURSOR); -#line 311 "ext/date/lib/parse_iso_intervals.re" - { - s->pos = cursor; s->line++; - goto std; - } -#line 335 "" +#line 334 "" yy11: YYDEBUG(11, *YYCURSOR); yych = *++YYCURSOR; - goto yy3; + if (yybm[0+yych] & 128) { + goto yy16; + } + goto yy5; yy12: YYDEBUG(12, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= 'L') { - if (yych <= '9') { - if (yych >= '0') goto yy25; - } else { - if (yych == 'D') goto yy24; - } - } else { - if (yych <= 'W') { - if (yych <= 'M') goto yy27; - if (yych >= 'W') goto yy26; - } else { - if (yych == 'Y') goto yy28; - } - } + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy19; yy13: YYDEBUG(13, *YYCURSOR); YYCURSOR = YYMARKER; if (yyaccept == 0) { - goto yy3; + goto yy5; } else { - goto yy6; + goto yy10; } yy14: YYDEBUG(14, *YYCURSOR); - yyaccept = 1; - yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy15; + yych = *++YYCURSOR; + if (yych <= 'L') { + if (yych <= '9') { + if (yych <= '/') goto yy13; + goto yy20; + } else { + if (yych == 'D') goto yy21; + goto yy13; + } + } else { + if (yych <= 'W') { + if (yych <= 'M') goto yy22; + if (yych <= 'V') goto yy13; + goto yy23; + } else { + if (yych == 'Y') goto yy24; + goto yy13; + } } - goto yy6; yy15: YYDEBUG(15, *YYCURSOR); + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '/') goto yy10; + if (yych <= '9') goto yy25; + goto yy10; +yy16: + YYDEBUG(16, *YYCURSOR); ++YYCURSOR; - if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + if (YYLIMIT <= YYCURSOR) YYFILL(1); yych = *YYCURSOR; - YYDEBUG(16, *YYCURSOR); + YYDEBUG(17, *YYCURSOR); if (yybm[0+yych] & 128) { - goto yy15; + goto yy16; } + YYDEBUG(18, *YYCURSOR); +#line 209 "ext/date/lib/parse_iso_intervals.re" + { + DEBUG_OUTPUT("recurrences"); + TIMELIB_INIT; + ptr++; + s->recurrences = timelib_get_unsigned_nr(&ptr, 9); + TIMELIB_DEINIT; + s->have_recurrences = 1; + return TIMELIB_PERIOD; + } +#line 403 "" +yy19: + YYDEBUG(19, *YYCURSOR); + yych = *++YYCURSOR; + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy27; + goto yy13; +yy20: + YYDEBUG(20, *YYCURSOR); + yych = *++YYCURSOR; if (yych <= 'L') { - if (yych == 'H') goto yy19; - goto yy13; + if (yych <= '9') { + if (yych <= '/') goto yy13; + goto yy28; + } else { + if (yych != 'D') goto yy13; + } } else { - if (yych <= 'M') goto yy18; - if (yych != 'S') goto yy13; + if (yych <= 'W') { + if (yych <= 'M') goto yy22; + if (yych <= 'V') goto yy13; + goto yy23; + } else { + if (yych == 'Y') goto yy24; + goto yy13; + } } -yy17: - YYDEBUG(17, *YYCURSOR); +yy21: + YYDEBUG(21, *YYCURSOR); yych = *++YYCURSOR; - goto yy6; -yy18: - YYDEBUG(18, *YYCURSOR); + if (yych == 'T') goto yy15; + goto yy10; +yy22: + YYDEBUG(22, *YYCURSOR); yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '/') goto yy6; - if (yych <= '9') goto yy22; - goto yy6; -yy19: - YYDEBUG(19, *YYCURSOR); + if (yych <= '/') goto yy10; + if (yych <= '9') goto yy29; + if (yych == 'T') goto yy15; + goto yy10; +yy23: + YYDEBUG(23, *YYCURSOR); yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '/') goto yy6; - if (yych >= ':') goto yy6; -yy20: - YYDEBUG(20, *YYCURSOR); + if (yych <= '/') goto yy10; + if (yych <= '9') goto yy31; + if (yych == 'T') goto yy15; + goto yy10; +yy24: + YYDEBUG(24, *YYCURSOR); + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '/') goto yy10; + if (yych <= '9') goto yy33; + if (yych == 'T') goto yy15; + goto yy10; +yy25: + YYDEBUG(25, *YYCURSOR); ++YYCURSOR; if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); yych = *YYCURSOR; - YYDEBUG(21, *YYCURSOR); - if (yych <= 'L') { + YYDEBUG(26, *YYCURSOR); + if (yych <= 'H') { if (yych <= '/') goto yy13; - if (yych <= '9') goto yy20; + if (yych <= '9') goto yy25; + if (yych <= 'G') goto yy13; + goto yy35; + } else { + if (yych <= 'M') { + if (yych <= 'L') goto yy13; + goto yy36; + } else { + if (yych == 'S') goto yy37; + goto yy13; + } + } +yy27: + YYDEBUG(27, *YYCURSOR); + yych = *++YYCURSOR; + if (yych <= '/') { + if (yych == '-') goto yy38; goto yy13; } else { - if (yych <= 'M') goto yy18; - if (yych == 'S') goto yy17; + if (yych <= '0') goto yy39; + if (yych <= '1') goto yy40; goto yy13; } -yy22: - YYDEBUG(22, *YYCURSOR); - ++YYCURSOR; - if (YYLIMIT <= YYCURSOR) YYFILL(1); - yych = *YYCURSOR; - YYDEBUG(23, *YYCURSOR); - if (yych <= '/') goto yy13; - if (yych <= '9') goto yy22; - if (yych == 'S') goto yy17; - goto yy13; -yy24: - YYDEBUG(24, *YYCURSOR); - yych = *++YYCURSOR; - if (yych == 'T') goto yy14; - goto yy6; -yy25: - YYDEBUG(25, *YYCURSOR); +yy28: + YYDEBUG(28, *YYCURSOR); yych = *++YYCURSOR; if (yych <= 'L') { if (yych <= '9') { if (yych <= '/') goto yy13; - goto yy35; + goto yy41; } else { - if (yych == 'D') goto yy24; + if (yych == 'D') goto yy21; goto yy13; } } else { if (yych <= 'W') { - if (yych <= 'M') goto yy27; + if (yych <= 'M') goto yy22; if (yych <= 'V') goto yy13; + goto yy23; } else { - if (yych == 'Y') goto yy28; + if (yych == 'Y') goto yy24; goto yy13; } } -yy26: - YYDEBUG(26, *YYCURSOR); - yyaccept = 1; - yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '/') goto yy6; - if (yych <= '9') goto yy33; - if (yych == 'T') goto yy14; - goto yy6; -yy27: - YYDEBUG(27, *YYCURSOR); - yyaccept = 1; - yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '/') goto yy6; - if (yych <= '9') goto yy31; - if (yych == 'T') goto yy14; - goto yy6; -yy28: - YYDEBUG(28, *YYCURSOR); - yyaccept = 1; - yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '/') goto yy6; - if (yych <= '9') goto yy29; - if (yych == 'T') goto yy14; - goto yy6; yy29: YYDEBUG(29, *YYCURSOR); ++YYCURSOR; if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; YYDEBUG(30, *YYCURSOR); - if (yych <= 'D') { + if (yych <= 'C') { if (yych <= '/') goto yy13; if (yych <= '9') goto yy29; - if (yych <= 'C') goto yy13; - goto yy24; + goto yy13; } else { - if (yych <= 'M') { - if (yych <= 'L') goto yy13; - goto yy27; - } else { - if (yych == 'W') goto yy26; - goto yy13; - } + if (yych <= 'D') goto yy21; + if (yych == 'W') goto yy23; + goto yy13; } yy31: YYDEBUG(31, *YYCURSOR); @@ -502,313 +528,372 @@ static int scan(Scanner *s) if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; YYDEBUG(32, *YYCURSOR); - if (yych <= 'C') { - if (yych <= '/') goto yy13; - if (yych <= '9') goto yy31; - goto yy13; - } else { - if (yych <= 'D') goto yy24; - if (yych == 'W') goto yy26; - goto yy13; - } + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy31; + if (yych == 'D') goto yy21; + goto yy13; yy33: YYDEBUG(33, *YYCURSOR); ++YYCURSOR; if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); yych = *YYCURSOR; YYDEBUG(34, *YYCURSOR); - if (yych <= '/') goto yy13; - if (yych <= '9') goto yy33; - if (yych == 'D') goto yy24; - goto yy13; -yy35: - YYDEBUG(35, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= 'L') { - if (yych <= '9') { - if (yych <= '/') goto yy13; - } else { - if (yych == 'D') goto yy24; - goto yy13; - } + if (yych <= 'D') { + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy33; + if (yych <= 'C') goto yy13; + goto yy21; } else { - if (yych <= 'W') { - if (yych <= 'M') goto yy27; - if (yych <= 'V') goto yy13; - goto yy26; + if (yych <= 'M') { + if (yych <= 'L') goto yy13; + goto yy22; } else { - if (yych == 'Y') goto yy28; + if (yych == 'W') goto yy23; goto yy13; } } +yy35: + YYDEBUG(35, *YYCURSOR); + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '/') goto yy10; + if (yych <= '9') goto yy42; + goto yy10; +yy36: YYDEBUG(36, *YYCURSOR); - yych = *++YYCURSOR; - if (yych != '-') goto yy39; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '/') goto yy10; + if (yych <= '9') goto yy44; + goto yy10; +yy37: YYDEBUG(37, *YYCURSOR); + ++YYCURSOR; + goto yy10; +yy38: + YYDEBUG(38, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '0') goto yy40; - if (yych <= '1') goto yy41; + if (yych <= '0') goto yy46; + if (yych <= '1') goto yy47; goto yy13; -yy38: - YYDEBUG(38, *YYCURSOR); - ++YYCURSOR; - if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); - yych = *YYCURSOR; yy39: YYDEBUG(39, *YYCURSOR); - if (yych <= 'L') { - if (yych <= '9') { - if (yych <= '/') goto yy13; - goto yy38; - } else { - if (yych == 'D') goto yy24; - goto yy13; - } - } else { - if (yych <= 'W') { - if (yych <= 'M') goto yy27; - if (yych <= 'V') goto yy13; - goto yy26; - } else { - if (yych == 'Y') goto yy28; - goto yy13; - } - } + yych = *++YYCURSOR; + if (yych <= '0') goto yy13; + if (yych <= '9') goto yy48; + goto yy13; yy40: YYDEBUG(40, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '9') goto yy42; + if (yych <= '2') goto yy48; goto yy13; yy41: YYDEBUG(41, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= '3') goto yy13; + if (yych == '-') goto yy49; + goto yy51; yy42: YYDEBUG(42, *YYCURSOR); - yych = *++YYCURSOR; - if (yych != '-') goto yy13; + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; YYDEBUG(43, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych <= '0') goto yy44; - if (yych <= '2') goto yy45; - if (yych <= '3') goto yy46; - goto yy13; + if (yych <= 'L') { + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy42; + goto yy13; + } else { + if (yych <= 'M') goto yy36; + if (yych == 'S') goto yy37; + goto yy13; + } yy44: YYDEBUG(44, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych <= '9') goto yy47; - goto yy13; -yy45: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; YYDEBUG(45, *YYCURSOR); - yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '9') goto yy47; + if (yych <= '9') goto yy44; + if (yych == 'S') goto yy37; goto yy13; yy46: YYDEBUG(46, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= '2') goto yy13; + if (yych <= '0') goto yy13; + if (yych <= '9') goto yy52; + goto yy13; yy47: YYDEBUG(47, *YYCURSOR); yych = *++YYCURSOR; - if (yych != 'T') goto yy13; + if (yych <= '/') goto yy13; + if (yych <= '2') goto yy52; + goto yy13; +yy48: YYDEBUG(48, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '1') goto yy49; - if (yych <= '2') goto yy50; + if (yych <= '0') goto yy53; + if (yych <= '2') goto yy54; + if (yych <= '3') goto yy55; goto yy13; yy49: YYDEBUG(49, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '9') goto yy51; + if (yych <= '0') goto yy56; + if (yych <= '1') goto yy57; goto yy13; yy50: YYDEBUG(50, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= '5') goto yy13; + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; yy51: YYDEBUG(51, *YYCURSOR); - yych = *++YYCURSOR; - if (yych != ':') goto yy13; + if (yych <= 'L') { + if (yych <= '9') { + if (yych <= '/') goto yy13; + goto yy50; + } else { + if (yych == 'D') goto yy21; + goto yy13; + } + } else { + if (yych <= 'W') { + if (yych <= 'M') goto yy22; + if (yych <= 'V') goto yy13; + goto yy23; + } else { + if (yych == 'Y') goto yy24; + goto yy13; + } + } +yy52: YYDEBUG(52, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= '6') goto yy13; + if (yych == '-') goto yy58; + goto yy13; +yy53: YYDEBUG(53, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= ':') goto yy13; + if (yych <= '0') goto yy13; + if (yych <= '9') goto yy59; + goto yy13; +yy54: YYDEBUG(54, *YYCURSOR); yych = *++YYCURSOR; - if (yych != ':') goto yy13; + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy59; + goto yy13; +yy55: YYDEBUG(55, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych >= '6') goto yy13; + if (yych <= '1') goto yy59; + goto yy13; +yy56: YYDEBUG(56, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych >= ':') goto yy13; + if (yych <= '9') goto yy60; + goto yy13; +yy57: YYDEBUG(57, *YYCURSOR); - ++YYCURSOR; + yych = *++YYCURSOR; + if (yych <= '/') goto yy13; + if (yych <= '2') goto yy60; + goto yy13; +yy58: YYDEBUG(58, *YYCURSOR); -#line 286 "ext/date/lib/parse_iso_intervals.re" - { - DEBUG_OUTPUT("combinedrep"); - TIMELIB_INIT; - s->period->y = timelib_get_unsigned_nr(&ptr, 4); - ptr++; - s->period->m = timelib_get_unsigned_nr(&ptr, 2); - ptr++; - s->period->d = timelib_get_unsigned_nr(&ptr, 2); - ptr++; - s->period->h = timelib_get_unsigned_nr(&ptr, 2); - ptr++; - s->period->i = timelib_get_unsigned_nr(&ptr, 2); - ptr++; - s->period->s = timelib_get_unsigned_nr(&ptr, 2); - s->have_period = 1; - TIMELIB_DEINIT; - return TIMELIB_PERIOD; - } -#line 684 "" + yych = *++YYCURSOR; + if (yych <= '/') goto yy13; + if (yych <= '0') goto yy61; + if (yych <= '2') goto yy62; + if (yych <= '3') goto yy63; + goto yy13; yy59: YYDEBUG(59, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= ':') goto yy13; + if (yych == 'T') goto yy64; + goto yy13; +yy60: YYDEBUG(60, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= ':') goto yy13; + if (yych == '-') goto yy65; + goto yy13; +yy61: YYDEBUG(61, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') { - if (yych == '-') goto yy64; - goto yy13; - } else { - if (yych <= '0') goto yy62; - if (yych <= '1') goto yy63; - goto yy13; - } + if (yych <= '0') goto yy13; + if (yych <= '9') goto yy66; + goto yy13; yy62: YYDEBUG(62, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '0') goto yy13; - if (yych <= '9') goto yy85; + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy66; goto yy13; yy63: YYDEBUG(63, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '2') goto yy85; + if (yych <= '1') goto yy66; goto yy13; yy64: YYDEBUG(64, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '0') goto yy65; - if (yych <= '1') goto yy66; + if (yych <= '1') goto yy67; + if (yych <= '2') goto yy68; goto yy13; yy65: YYDEBUG(65, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '0') goto yy13; - if (yych <= '9') goto yy67; + if (yych <= '/') goto yy13; + if (yych <= '2') goto yy69; + if (yych <= '3') goto yy70; goto yy13; yy66: YYDEBUG(66, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= '3') goto yy13; + if (yych == 'T') goto yy71; + goto yy13; yy67: YYDEBUG(67, *YYCURSOR); yych = *++YYCURSOR; - if (yych != '-') goto yy13; + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy72; + goto yy13; +yy68: YYDEBUG(68, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '0') goto yy69; - if (yych <= '2') goto yy70; - if (yych <= '3') goto yy71; + if (yych <= '4') goto yy72; goto yy13; yy69: YYDEBUG(69, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '0') goto yy13; - if (yych <= '9') goto yy72; + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy73; goto yy13; yy70: YYDEBUG(70, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '9') goto yy72; + if (yych <= '1') goto yy73; goto yy13; yy71: YYDEBUG(71, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych >= '2') goto yy13; + if (yych <= '1') goto yy74; + if (yych <= '2') goto yy75; + goto yy13; yy72: YYDEBUG(72, *YYCURSOR); yych = *++YYCURSOR; - if (yych != 'T') goto yy13; + if (yych <= '/') goto yy13; + if (yych <= '5') goto yy76; + goto yy13; +yy73: YYDEBUG(73, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych <= '1') goto yy74; - if (yych <= '2') goto yy75; + if (yych == 'T') goto yy77; goto yy13; yy74: YYDEBUG(74, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '9') goto yy76; + if (yych <= '9') goto yy78; goto yy13; yy75: YYDEBUG(75, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych >= '5') goto yy13; + if (yych <= '4') goto yy78; + goto yy13; yy76: YYDEBUG(76, *YYCURSOR); yych = *++YYCURSOR; - if (yych != ':') goto yy13; + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy79; + goto yy13; +yy77: YYDEBUG(77, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych >= '6') goto yy13; + if (yych <= '1') goto yy80; + if (yych <= '2') goto yy81; + goto yy13; +yy78: YYDEBUG(78, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= ':') goto yy13; + if (yych == ':') goto yy82; + goto yy13; +yy79: YYDEBUG(79, *YYCURSOR); yych = *++YYCURSOR; - if (yych != ':') goto yy13; + if (yych <= '/') goto yy13; + if (yych <= '5') goto yy83; + goto yy13; +yy80: YYDEBUG(80, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych >= '6') goto yy13; + if (yych <= '9') goto yy84; + goto yy13; +yy81: YYDEBUG(81, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych >= ':') goto yy13; + if (yych <= '4') goto yy84; + goto yy13; +yy82: YYDEBUG(82, *YYCURSOR); yych = *++YYCURSOR; - if (yych != 'Z') goto yy13; + if (yych <= '/') goto yy13; + if (yych <= '5') goto yy85; + goto yy13; yy83: YYDEBUG(83, *YYCURSOR); - ++YYCURSOR; + yych = *++YYCURSOR; + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy86; + goto yy13; +yy84: YYDEBUG(84, *YYCURSOR); + yych = *++YYCURSOR; + if (yych == ':') goto yy87; + goto yy13; +yy85: + YYDEBUG(85, *YYCURSOR); + yych = *++YYCURSOR; + if (yych <= '/') goto yy13; + if (yych <= '9') goto yy88; + goto yy13; +yy86: + YYDEBUG(86, *YYCURSOR); + yych = *++YYCURSOR; + if (yych == 'Z') goto yy89; + goto yy13; +yy87: + YYDEBUG(87, *YYCURSOR); + yych = *++YYCURSOR; + if (yych <= '/') goto yy13; + if (yych <= '5') goto yy91; + goto yy13; +yy88: + YYDEBUG(88, *YYCURSOR); + yych = *++YYCURSOR; + if (yych == ':') goto yy79; + goto yy13; +yy89: + YYDEBUG(89, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(90, *YYCURSOR); #line 220 "ext/date/lib/parse_iso_intervals.re" { timelib_time *current; @@ -832,54 +917,15 @@ static int scan(Scanner *s) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 836 "" -yy85: - YYDEBUG(85, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych <= '0') goto yy86; - if (yych <= '2') goto yy87; - if (yych <= '3') goto yy88; - goto yy13; -yy86: - YYDEBUG(86, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '0') goto yy13; - if (yych <= '9') goto yy89; - goto yy13; -yy87: - YYDEBUG(87, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych <= '9') goto yy89; - goto yy13; -yy88: - YYDEBUG(88, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= '2') goto yy13; -yy89: - YYDEBUG(89, *YYCURSOR); - yych = *++YYCURSOR; - if (yych != 'T') goto yy13; - YYDEBUG(90, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych <= '1') goto yy91; - if (yych <= '2') goto yy92; - goto yy13; +#line 921 "" yy91: YYDEBUG(91, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; - if (yych <= '9') goto yy93; - goto yy13; -yy92: + if (yych >= ':') goto yy13; YYDEBUG(92, *YYCURSOR); yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= '5') goto yy13; -yy93: + if (yych != ':') goto yy13; YYDEBUG(93, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '/') goto yy13; @@ -889,38 +935,28 @@ static int scan(Scanner *s) if (yych <= '/') goto yy13; if (yych >= ':') goto yy13; YYDEBUG(95, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= '6') goto yy13; - YYDEBUG(96, *YYCURSOR); - yych = *++YYCURSOR; - if (yych <= '/') goto yy13; - if (yych >= ':') goto yy13; - YYDEBUG(97, *YYCURSOR); - yych = *++YYCURSOR; - if (yych == 'Z') goto yy83; - goto yy13; -yy98: - YYDEBUG(98, *YYCURSOR); ++YYCURSOR; - if (YYLIMIT <= YYCURSOR) YYFILL(1); - yych = *YYCURSOR; - YYDEBUG(99, *YYCURSOR); - if (yych <= '/') goto yy100; - if (yych <= '9') goto yy98; -yy100: - YYDEBUG(100, *YYCURSOR); -#line 209 "ext/date/lib/parse_iso_intervals.re" + YYDEBUG(96, *YYCURSOR); +#line 286 "ext/date/lib/parse_iso_intervals.re" { - DEBUG_OUTPUT("recurrences"); + DEBUG_OUTPUT("combinedrep"); TIMELIB_INIT; + s->period->y = timelib_get_unsigned_nr(&ptr, 4); ptr++; - s->recurrences = timelib_get_unsigned_nr(&ptr, 9); + s->period->m = timelib_get_unsigned_nr(&ptr, 2); + ptr++; + s->period->d = timelib_get_unsigned_nr(&ptr, 2); + ptr++; + s->period->h = timelib_get_unsigned_nr(&ptr, 2); + ptr++; + s->period->i = timelib_get_unsigned_nr(&ptr, 2); + ptr++; + s->period->s = timelib_get_unsigned_nr(&ptr, 2); + s->have_period = 1; TIMELIB_DEINIT; - s->have_recurrences = 1; return TIMELIB_PERIOD; } -#line 924 "" +#line 960 "" } #line 321 "ext/date/lib/parse_iso_intervals.re" @@ -931,6 +967,7 @@ static int scan(Scanner *s) #define YYMAXFILL 20 + void timelib_strtointerval(const char *s, size_t len, timelib_time **begin, timelib_time **end, timelib_rel_time **period, int *recurrences, diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index 4582fcfd46917..a2c976af7ed9c 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2023 Derick Rethans + * Copyright (c) 2015-2024 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 202210 -#define TIMELIB_EXTENDED_VERSION 20221001 -#define TIMELIB_ASCII_VERSION "2022.10" +#define TIMELIB_VERSION 202212 +#define TIMELIB_EXTENDED_VERSION 20221201 +#define TIMELIB_ASCII_VERSION "2022.12" #include #include diff --git a/ext/date/lib/timelib_private.h b/ext/date/lib/timelib_private.h index 65ec6b014b894..3c5f9b22147c0 100644 --- a/ext/date/lib/timelib_private.h +++ b/ext/date/lib/timelib_private.h @@ -126,6 +126,15 @@ # define TIMELIB_BREAK_INTENTIONALLY_MISSING #endif +#if defined(__has_builtin) +# if __has_builtin(__builtin_saddll_overflow) +# define TIMELIB_HAVE_BUILTIN_SADDLL_OVERFLOW 1 +# endif +#endif + +#ifndef TIMELIB_HAVE_BUILTIN_SADDLL_OVERFLOW +# define TIMELIB_HAVE_BUILTIN_SADDLL_OVERFLOW 0 +#endif struct _ttinfo { int32_t offset; diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 87dd917749187..dc9eb995b8f65 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -687,8 +687,11 @@ static zend_string *date_format(const char *format, size_t format_len, timelib_t (offset->offset < 0) ? '-' : '+', abs(offset->offset / 3600), abs((offset->offset % 3600) / 60)); - } else { + } else if (t->zone_type == TIMELIB_ZONETYPE_ID) { offset = timelib_get_time_zone_info(t->sse, t->tz_info); + } else { + /* Shouldn't happen, but code defensively */ + offset = timelib_time_offset_ctor(); } } @@ -2418,6 +2421,9 @@ PHPAPI bool php_date_initialize(php_date_obj *dateobj, const char *time_str, siz new_dst = tzobj->tzi.z.dst; new_abbr = timelib_strdup(tzobj->tzi.z.abbr); break; + default: + zend_throw_error(NULL, "The DateTimeZone object has not been correctly initialized by its constructor"); + return 0; } type = tzobj->type; } else if (dateobj->time->tz_info) { @@ -3816,7 +3822,6 @@ PHP_METHOD(DateTimeZone, __set_state) 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); RETURN_THROWS(); } } diff --git a/ext/date/tests/bug-gh15582.phpt b/ext/date/tests/bug-gh15582.phpt new file mode 100644 index 0000000000000..ab03e190e4bc3 --- /dev/null +++ b/ext/date/tests/bug-gh15582.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug GH-15582: Crash when not calling parent constructor of DateTimeZone +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Error: The DateTimeZone object has not been correctly initialized by its constructor diff --git a/ext/date/tests/bug40861.phpt b/ext/date/tests/bug40861.phpt index 224d8eb0a71de..d4ef96198c7ff 100644 --- a/ext/date/tests/bug40861.phpt +++ b/ext/date/tests/bug40861.phpt @@ -28,6 +28,6 @@ echo $result . "\n"; ?> --EXPECT-- 2000-01-01 13:00:00 -2000-01-01 13:00:00 2000-01-01 11:00:00 2000-01-01 13:00:00 +2000-01-01 13:00:00 diff --git a/ext/dom/node.c b/ext/dom/node.c index c80f9c3333c6c..bb80408f2689f 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -843,6 +843,39 @@ static xmlNodePtr _php_dom_insert_fragment(xmlNodePtr nodep, xmlNodePtr prevsib, } /* }}} */ +static bool dom_node_check_legacy_insertion_validity(xmlNodePtr parentp, xmlNodePtr child, bool stricterror) +{ + if (dom_node_is_read_only(parentp) == SUCCESS || + (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) { + php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror); + return false; + } + + if (dom_hierarchy(parentp, child) == FAILURE) { + php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror); + return false; + } + + if (child->doc != parentp->doc && child->doc != NULL) { + php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror); + return false; + } + + if (child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) { + /* TODO Drop Warning? */ + php_error_docref(NULL, E_WARNING, "Document Fragment is empty"); + return false; + } + + /* In old DOM only text nodes and entity nodes can be added as children to attributes. */ + if (parentp->type == XML_ATTRIBUTE_NODE && child->type != XML_TEXT_NODE && child->type != XML_ENTITY_REF_NODE) { + php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror); + return false; + } + + return true; +} + /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-952280727 Since: */ @@ -870,25 +903,7 @@ PHP_METHOD(DOMNode, insertBefore) stricterror = dom_get_strict_error(intern->document); - if (dom_node_is_read_only(parentp) == SUCCESS || - (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) { - php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror); - RETURN_FALSE; - } - - if (dom_hierarchy(parentp, child) == FAILURE) { - php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror); - RETURN_FALSE; - } - - if (child->doc != parentp->doc && child->doc != NULL) { - php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror); - RETURN_FALSE; - } - - if (child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) { - /* TODO Drop Warning? */ - php_error_docref(NULL, E_WARNING, "Document Fragment is empty"); + if (!dom_node_check_legacy_insertion_validity(parentp, child, stricterror)) { RETURN_FALSE; } @@ -1170,25 +1185,7 @@ PHP_METHOD(DOMNode, appendChild) stricterror = dom_get_strict_error(intern->document); - if (dom_node_is_read_only(nodep) == SUCCESS || - (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) { - php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror); - RETURN_FALSE; - } - - if (dom_hierarchy(nodep, child) == FAILURE) { - php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror); - RETURN_FALSE; - } - - if (!(child->doc == NULL || child->doc == nodep->doc)) { - php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror); - RETURN_FALSE; - } - - if (child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) { - /* TODO Drop Warning? */ - php_error_docref(NULL, E_WARNING, "Document Fragment is empty"); + if (!dom_node_check_legacy_insertion_validity(nodep, child, stricterror)) { RETURN_FALSE; } diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c index c30db6fcd745f..ea4edb0774376 100644 --- a/ext/dom/parentnode.c +++ b/ext/dom/parentnode.c @@ -272,6 +272,11 @@ static zend_result dom_sanity_check_node_list_for_insertion(php_libxml_ref_obj * if (instanceof_function(ce, dom_node_class_entry)) { xmlNodePtr node = dom_object_get_node(Z_DOMOBJ_P(nodes + i)); + if (!node) { + php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true); + return FAILURE; + } + if (node->doc != documentNode) { php_dom_throw_error(WRONG_DOCUMENT_ERR, dom_get_strict_error(document)); return FAILURE; diff --git a/ext/dom/tests/gh16039.phpt b/ext/dom/tests/gh16039.phpt new file mode 100644 index 0000000000000..48a862eda7b20 --- /dev/null +++ b/ext/dom/tests/gh16039.phpt @@ -0,0 +1,31 @@ +--TEST-- +GH-16039 (Segmentation fault (access null pointer) in ext/dom/parentnode/tree.c) +--EXTENSIONS-- +dom +--FILE-- +appendChild($dom->createElement('root')); +try { + $element->prepend('x', new DOMEntity); +} catch (DOMException $e) { + echo $e->getMessage(), "\n"; +} +echo $dom->saveXML(); +$dom->strictErrorChecking = false; // Should not have influence +try { + $element->prepend('x', new DOMEntity); +} catch (DOMException $e) { + echo $e->getMessage(), "\n"; +} +echo $dom->saveXML(); + +?> +--EXPECT-- +Invalid State Error + + +Invalid State Error + + diff --git a/ext/dom/tests/gh16151.phpt b/ext/dom/tests/gh16151.phpt new file mode 100644 index 0000000000000..e11d3df4a56bb --- /dev/null +++ b/ext/dom/tests/gh16151.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-16151 (Assertion failure in ext/dom/parentnode/tree.c) +--EXTENSIONS-- +dom +--FILE-- +appendChild($element); +$element->setAttributeNodeNS($attr); + +try { + $attr->insertBefore(new DOMComment("h")); +} catch (DOMException $e) { + echo $e->getMessage(), "\n"; +} +try { + $attr->appendChild(new DOMComment("h")); +} catch (DOMException $e) { + echo $e->getMessage(), "\n"; +} + +$attr->insertBefore($doc->createEntityReference('amp')); +$attr->appendChild($doc->createEntityReference('amp')); + +echo $doc->saveXML(); + +?> +--EXPECT-- +Hierarchy Request Error +Hierarchy Request Error + +W diff --git a/ext/gd/gd.c b/ext/gd/gd.c index ef5bc9a03a342..3b824430597b6 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -1195,6 +1195,11 @@ PHP_FUNCTION(imagerotate) RETURN_THROWS(); } + if (degrees < (double)(INT_MIN / 100) || degrees > (double)(INT_MAX / 100)) { + zend_argument_value_error(2, "must be between %d and %d", (INT_MIN / 100), (INT_MAX / 100)); + RETURN_THROWS(); + } + im_src = php_gd_libgdimageptr_from_zval_p(SIM); im_dst = gdImageRotateInterpolated(im_src, (const float)degrees, color); diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c index cf8821372d923..2fde78be19895 100644 --- a/ext/gd/libgd/gd_interpolation.c +++ b/ext/gd/libgd/gd_interpolation.c @@ -929,6 +929,24 @@ static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsi return res; } +static inline unsigned char +uchar_clamp(double clr) { + unsigned short result; + assert(fabs(clr) <= SHRT_MAX); + /* Casting a negative float to an unsigned short is undefined. + * However, casting a float to a signed truncates toward zero and + * casting a negative signed value to an unsigned of the same size + * results in a bit-identical value (assuming twos-complement + * arithmetic). This is what we want: all legal negative values + * for clr will be greater than 255. */ + /* Convert and clamp. */ + result = (unsigned short)(short)(clr + 0.5); + if (result > 255) { + result = (clr < 0) ? 0 : 255; + }/* if */ + return result; +}/* uchar_clamp*/ + static inline void _gdScaleRow(gdImagePtr pSrc, unsigned int src_width, gdImagePtr dst, unsigned int dst_width, unsigned int row, LineContribType *contrib) { int *p_src_row = pSrc->tpixels[row]; @@ -936,20 +954,20 @@ static inline void _gdScaleRow(gdImagePtr pSrc, unsigned int src_width, gdImage unsigned int x; for (x = 0; x < dst_width; x++) { - register unsigned char r = 0, g = 0, b = 0, a = 0; + double r = 0, g = 0, b = 0, a = 0; const int left = contrib->ContribRow[x].Left; const int right = contrib->ContribRow[x].Right; - int i; + int i; - /* Accumulate each channel */ - for (i = left; i <= right; i++) { - const int left_channel = i - left; - r += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetRed(p_src_row[i]))); - g += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetGreen(p_src_row[i]))); - b += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetBlue(p_src_row[i]))); - a += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetAlpha(p_src_row[i]))); - } - p_dst_row[x] = gdTrueColorAlpha(r, g, b, a); + /* Accumulate each channel */ + for (i = left; i <= right; i++) { + const int left_channel = i - left; + r += contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetRed(p_src_row[i])); + g += contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetGreen(p_src_row[i])); + b += contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetBlue(p_src_row[i])); + a += contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetAlpha(p_src_row[i])); + } + p_dst_row[x] = gdTrueColorAlpha(uchar_clamp(r), uchar_clamp(g), uchar_clamp(b), uchar_clamp(a)); } } @@ -982,7 +1000,7 @@ static inline void _gdScaleCol (gdImagePtr pSrc, unsigned int src_width, gdImag { unsigned int y; for (y = 0; y < dst_height; y++) { - register unsigned char r = 0, g = 0, b = 0, a = 0; + double r = 0, g = 0, b = 0, a = 0; const int iLeft = contrib->ContribRow[y].Left; const int iRight = contrib->ContribRow[y].Right; int i; @@ -991,12 +1009,12 @@ static inline void _gdScaleCol (gdImagePtr pSrc, unsigned int src_width, gdImag for (i = iLeft; i <= iRight; i++) { const int pCurSrc = pSrc->tpixels[i][uCol]; const int i_iLeft = i - iLeft; - r += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetRed(pCurSrc))); - g += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetGreen(pCurSrc))); - b += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetBlue(pCurSrc))); - a += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetAlpha(pCurSrc))); + r += contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetRed(pCurSrc)); + g += contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetGreen(pCurSrc)); + b += contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetBlue(pCurSrc)); + a += contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetAlpha(pCurSrc)); } - pRes->tpixels[y][uCol] = gdTrueColorAlpha(r, g, b, a); + pRes->tpixels[y][uCol] = gdTrueColorAlpha(uchar_clamp(r), uchar_clamp(g), uchar_clamp(b), uchar_clamp(a)); } } diff --git a/ext/gd/libgd/wbmp.c b/ext/gd/libgd/wbmp.c index 4c3eeee7df8cb..dbca0f0178c68 100644 --- a/ext/gd/libgd/wbmp.c +++ b/ext/gd/libgd/wbmp.c @@ -37,7 +37,8 @@ int getmbi (int (*getin) (void *in), void *in) { - int i, mbi = 0; + unsigned int mbi = 0; + int i; do { diff --git a/ext/gd/tests/gh16232.phpt b/ext/gd/tests/gh16232.phpt new file mode 100644 index 0000000000000..7f839d737bb5b --- /dev/null +++ b/ext/gd/tests/gh16232.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-16232 (Overflow on reading wbmp content) +--EXTENSIONS-- +gd +--FILE-- + +--EXPECT-- +DONE diff --git a/ext/gd/tests/gh16260.phpt b/ext/gd/tests/gh16260.phpt new file mode 100644 index 0000000000000..563fc8d162786 --- /dev/null +++ b/ext/gd/tests/gh16260.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-16260 (Overflow/underflow on imagerotate degrees argument) +--EXTENSIONS-- +gd +--FILE-- +getMessage() . PHP_EOL; +} + +try { + imagerotate($im, PHP_INT_MAX, 0); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +--EXPECTF-- +imagerotate(): Argument #2 ($angle) must be between %s and %s +imagerotate(): Argument #2 ($angle) must be between %s and %s diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 51eca3d7cc4de..e33201f10d154 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -1429,6 +1429,11 @@ static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope) ret = 0; goto cleanup; } + if (!zend_array_is_list(Z_ARRVAL_P(link))) { + zend_argument_value_error(1, "must be a list"); + ret = 0; + goto cleanup; + } if (base_dn_ht) { nbases = zend_hash_num_elements(base_dn_ht); @@ -2145,17 +2150,11 @@ static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper, int ext) ldap_mods[i]->mod_type = estrndup(ZSTR_VAL(attribute), ZSTR_LEN(attribute)); } else { php_error_docref(NULL, E_WARNING, "Unknown attribute in the data"); - /* Free allocated memory */ - while (i >= 0) { - if (ldap_mods[i]->mod_type) { - efree(ldap_mods[i]->mod_type); - } - efree(ldap_mods[i]); - i--; - } - efree(num_berval); - efree(ldap_mods); - RETURN_FALSE; + RETVAL_FALSE; + num_berval[i] = 0; + num_attribs = i + 1; + ldap_mods[i]->mod_bvalues = NULL; + goto cleanup; } value = zend_hash_get_current_data(Z_ARRVAL_P(entry)); @@ -2176,6 +2175,8 @@ static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper, int ext) convert_to_string(value); if (EG(exception)) { RETVAL_FALSE; + num_berval[i] = 0; + num_attribs = i + 1; goto cleanup; } ldap_mods[i]->mod_bvalues[0] = (struct berval *) emalloc (sizeof(struct berval)); @@ -2192,6 +2193,8 @@ static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper, int ext) } convert_to_string(ivalue); if (EG(exception)) { + num_berval[i] = j; + num_attribs = i + 1; RETVAL_FALSE; goto cleanup; } @@ -2544,8 +2547,11 @@ PHP_FUNCTION(ldap_modify_batch) /* for the modification hashtable... */ zend_hash_internal_pointer_reset(Z_ARRVAL_P(mod)); num_modprops = zend_hash_num_elements(Z_ARRVAL_P(mod)); + bool has_attrib_key = false; + bool has_modtype_key = false; for (j = 0; j < num_modprops; j++) { + /* are the keys strings? */ if (zend_hash_get_current_key(Z_ARRVAL_P(mod), &modkey, &tmpUlong) != HASH_KEY_IS_STRING) { zend_argument_type_error(3, "must only contain string-indexed arrays"); @@ -2567,6 +2573,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)) { + has_attrib_key = true; 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)); RETURN_THROWS(); @@ -2578,6 +2585,7 @@ PHP_FUNCTION(ldap_modify_batch) } } else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_MODTYPE)) { + has_modtype_key = true; 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)); RETURN_THROWS(); @@ -2641,6 +2649,15 @@ PHP_FUNCTION(ldap_modify_batch) zend_hash_move_forward(Z_ARRVAL_P(mod)); } + + if (!has_attrib_key) { + zend_value_error("%s(): Required option \"" LDAP_MODIFY_BATCH_ATTRIB "\" is missing", get_active_function_name()); + RETURN_THROWS(); + } + if (!has_modtype_key) { + zend_value_error("%s(): Required option \"" LDAP_MODIFY_BATCH_MODTYPE "\" is missing", get_active_function_name()); + RETURN_THROWS(); + } } } /* validation was successful */ diff --git a/ext/ldap/tests/gh16032-1.phpt b/ext/ldap/tests/gh16032-1.phpt new file mode 100644 index 0000000000000..dbaf8213933d7 --- /dev/null +++ b/ext/ldap/tests/gh16032-1.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug GH-16032: Various NULL pointer dereferencements in ldap_modify_batch() +--EXTENSIONS-- +ldap +--FILE-- + LDAP_MODIFY_BATCH_ADD, + "values" => ["value1"], + ], +]; +try { + var_dump(ldap_modify_batch($ldap, $valid_dn, $modification_missing_attrib_key)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +ValueError: ldap_modify_batch(): Required option "attrib" is missing diff --git a/ext/ldap/tests/gh16032-2.phpt b/ext/ldap/tests/gh16032-2.phpt new file mode 100644 index 0000000000000..531415807f674 --- /dev/null +++ b/ext/ldap/tests/gh16032-2.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug GH-16032: Various NULL pointer dereferencements in ldap_modify_batch() +--EXTENSIONS-- +ldap +--FILE-- + "attrib1", + "values" => ["value1"], + ], +]; +try { + var_dump(ldap_modify_batch($ldap, $valid_dn, $modification_missing_modtype_key)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +ValueError: ldap_modify_batch(): Required option "modtype" is missing diff --git a/ext/ldap/tests/gh16101.phpt b/ext/ldap/tests/gh16101.phpt new file mode 100644 index 0000000000000..1e9d57334378b --- /dev/null +++ b/ext/ldap/tests/gh16101.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug GH-16101: Segfault in ldap_list(), ldap_read(), and ldap_search() when LDAPs array is not a list +--EXTENSIONS-- +ldap +--FILE-- + $ldap, + "world" => $ldap, +]; +try { + var_dump(ldap_list($ldaps_dict, $valid_dn, $valid_filter)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +ValueError: ldap_list(): Argument #1 ($ldap) must be a list diff --git a/ext/ldap/tests/gh16132-1.phpt b/ext/ldap/tests/gh16132-1.phpt new file mode 100644 index 0000000000000..1979796446daa --- /dev/null +++ b/ext/ldap/tests/gh16132-1.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug GH-16132: Attempting to free pointer not allocated by ZMM +--EXTENSIONS-- +ldap +--FILE-- + new stdClass(), + 'attribute2' => [ + 'value1', + 'value2', + ], +]; +try { + var_dump(ldap_add($ldap, $valid_dn, $dict_key_value_not_string)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Error: Object of class stdClass could not be converted to string diff --git a/ext/ldap/tests/gh16132-2.phpt b/ext/ldap/tests/gh16132-2.phpt new file mode 100644 index 0000000000000..eaf3bd67dfcb3 --- /dev/null +++ b/ext/ldap/tests/gh16132-2.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug GH-16132: Attempting to free pointer not allocated by ZMM +--EXTENSIONS-- +ldap +--FILE-- + 'value', + 'attribute2' => [ + 'value1', + new stdClass(), + ], +]; +try { + var_dump(ldap_add($ldap, $valid_dn, $dict_key_multi_value_not_list_of_strings2)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Error: Object of class stdClass could not be converted to string diff --git a/ext/ldap/tests/gh16136.phpt b/ext/ldap/tests/gh16136.phpt new file mode 100644 index 0000000000000..14f21e3e757f2 --- /dev/null +++ b/ext/ldap/tests/gh16136.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug GH-16136: Memory leak in php_ldap_do_modify() when entry is not a proper dictionary +--EXTENSIONS-- +ldap +--FILE-- + 'value', + 'not_key_entry', + 'attribute3' => [ + 'value1', + 'value2', + ], +]; +try { + var_dump(ldap_add($ldap, $valid_dn, $not_dict_of_attributes)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECTF-- +Warning: ldap_add(): Unknown attribute in the data in %s on line %d +bool(false) diff --git a/ext/libxml/tests/bug61367-read_2.phpt b/ext/libxml/tests/bug61367-read_2.phpt index bbcf696773bf0..f4b0f300293c8 100644 --- a/ext/libxml/tests/bug61367-read_2.phpt +++ b/ext/libxml/tests/bug61367-read_2.phpt @@ -58,6 +58,6 @@ bool(true) int(4) bool(true) -Warning: DOMDocument::loadXML(): %Sfailed to load external entity "file:///%s/test_bug_61367-read/bad" in %s on line %d +%s: DOMDocument::loadXML(): %Sfailed to load %s Warning: Attempt to read property "nodeValue" on null in %s on line %d diff --git a/ext/libxml/tests/libxml_disable_entity_loader_2.phpt b/ext/libxml/tests/libxml_disable_entity_loader_2.phpt index 182fe13cfda96..216792600bf0b 100644 --- a/ext/libxml/tests/libxml_disable_entity_loader_2.phpt +++ b/ext/libxml/tests/libxml_disable_entity_loader_2.phpt @@ -39,6 +39,6 @@ bool(true) Deprecated: Function libxml_disable_entity_loader() is deprecated in %s on line %d bool(false) -Warning: DOMDocument::loadXML(): %Sfailed to load external entity "%s" in %s on line %d +%s: DOMDocument::loadXML(): %Sfailed to load %s bool(true) Done diff --git a/ext/libxml/tests/libxml_set_external_entity_loader_variation1.phpt b/ext/libxml/tests/libxml_set_external_entity_loader_variation1.phpt index b480652209d53..e56e59c38698b 100644 --- a/ext/libxml/tests/libxml_set_external_entity_loader_variation1.phpt +++ b/ext/libxml/tests/libxml_set_external_entity_loader_variation1.phpt @@ -61,7 +61,7 @@ string(13) "-//FOO/ENTITY" string(32) "http://example.com/fooentity.ent" array(4) { ["directory"]=> - string(%d) "%s" + %r(NULL|string\(%d\) "%s")%r ["intSubName"]=> string(3) "foo" ["extSubURI"]=> diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 5aa25b57f01a2..70125dc909748 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -3289,7 +3289,7 @@ static int mb_recursive_convert_variable(mbfl_buffer_converter *convd, zval *var if (ret != NULL) { zval_ptr_dtor(orig_var); // TODO: avoid reallocation ??? - ZVAL_STRINGL(orig_var, (char *)ret->val, ret->len); + ZVAL_STRINGL(orig_var, (const char *) ret->val, ret->len); efree(ret->val); } } else if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) { @@ -3305,7 +3305,22 @@ static int mb_recursive_convert_variable(mbfl_buffer_converter *convd, zval *var ht = HASH_OF(var); if (ht != NULL) { - ZEND_HASH_FOREACH_VAL_IND(ht, entry) { + ZEND_HASH_FOREACH_VAL(ht, entry) { + /* Can be a typed property declaration, in which case we need to remove the reference from the source list. + * Just using ZEND_TRY_ASSIGN_STRINGL is not sufficient because that would not unwrap the reference + * and change values through references (see bug #26639). */ + if (Z_TYPE_P(entry) == IS_INDIRECT) { + ZEND_ASSERT(Z_TYPE_P(var) == IS_OBJECT); + + entry = Z_INDIRECT_P(entry); + if (Z_ISREF_P(entry) && Z_TYPE_P(Z_REFVAL_P(entry)) == IS_STRING) { + zend_property_info *info = zend_get_typed_property_info_for_slot(Z_OBJ_P(var), entry); + if (info) { + ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(entry), info); + } + } + } + if (mb_recursive_convert_variable(convd, entry)) { if (Z_REFCOUNTED_P(var)) { Z_UNPROTECT_RECURSION_P(var); @@ -4179,7 +4194,8 @@ PHP_FUNCTION(mb_send_mail) #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: " - if (str_headers != NULL) { + + if (str_headers != NULL && ZSTR_LEN(str_headers) > 0) { p = ZSTR_VAL(str_headers); n = ZSTR_LEN(str_headers); mbfl_memory_device_strncat(&device, p, n); diff --git a/ext/mbstring/tests/gh16229.phpt b/ext/mbstring/tests/gh16229.phpt new file mode 100644 index 0000000000000..1fe558d9b1025 --- /dev/null +++ b/ext/mbstring/tests/gh16229.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-16229 (Address overflowed in ext/mbstring/mbstring.c:4613 #16229) +--EXTENSIONS-- +mbstring +--INI-- +sendmail_path={MAIL:{PWD}/mb_send_mail_gh16229.eml} +mail.add_x_header=off +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- diff --git a/ext/mbstring/tests/gh16261.phpt b/ext/mbstring/tests/gh16261.phpt new file mode 100644 index 0000000000000..3573bd191c63d --- /dev/null +++ b/ext/mbstring/tests/gh16261.phpt @@ -0,0 +1,44 @@ +--TEST-- +GH-16261 (Reference invariant broken in mb_convert_variables()) +--EXTENSIONS-- +mbstring +--FILE-- +x =& $ref; +$test->z =& $ref3; +mb_convert_variables("EUC-JP", "Shift_JIS", $test); + +class Test2 { + public function __construct(public string $x) {} +} +$test2 = new Test2("foo"); + +mb_convert_variables("EUC-JP", "Shift_JIS", $test->x); + +var_dump($test, $test2); +?> +--EXPECT-- +object(Test)#1 (2) { + ["x"]=> + string(5) "hello" + ["y"]=> + uninitialized(string) + ["z"]=> + &array(1) { + [0]=> + string(5) "world" + } +} +object(Test2)#2 (1) { + ["x"]=> + string(3) "foo" +} diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index 05219b3cfae31..90e27fcf5165c 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -13829,7 +13829,9 @@ static int zend_jit_load_this(dasm_State **Dst, uint32_t var) static int zend_jit_fetch_this(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, bool check_only) { - if (!op_array->scope || (op_array->fn_flags & ZEND_ACC_STATIC)) { + if (!op_array->scope || + (op_array->fn_flags & ZEND_ACC_STATIC) || + ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE)) == ZEND_ACC_CLOSURE)) { if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { if (!JIT_G(current_frame) || !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) { diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index e599c335b1b69..4602376b097d3 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1247,7 +1247,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin } } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) { if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) { - if (p->func != (zend_function*)&zend_pass_function + if (p->func + && p->func != (zend_function*)&zend_pass_function && (zend_string_equals_literal(p->func->common.function_name, "extract") || zend_string_equals_literal(p->func->common.function_name, "compact") || zend_string_equals_literal(p->func->common.function_name, "get_defined_vars"))) { @@ -6221,7 +6222,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par goto jit_failure; } if ((p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func) { - if (opline->opcode == ZEND_NEW && ssa_op->result_def >= 0) { + if (opline->opcode == ZEND_NEW && opline->result_type != IS_UNUSED) { SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_OBJECT, 1); } if (zend_jit_may_be_polymorphic_call(opline) || diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 999295ef01a94..c5622141f564f 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -14749,7 +14749,9 @@ static int zend_jit_load_this(dasm_State **Dst, uint32_t var) static int zend_jit_fetch_this(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, bool check_only) { - if (!op_array->scope || (op_array->fn_flags & ZEND_ACC_STATIC)) { + if (!op_array->scope || + (op_array->fn_flags & ZEND_ACC_STATIC) || + ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE)) == ZEND_ACC_CLOSURE)) { if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { if (!JIT_G(current_frame) || !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) { diff --git a/ext/opcache/tests/jit/gh15973.phpt b/ext/opcache/tests/jit/gh15973.phpt new file mode 100644 index 0000000000000..fcf893bccf1b5 --- /dev/null +++ b/ext/opcache/tests/jit/gh15973.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-15973 (Segmentation fault in JIT mode 1135) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit=1215 +opcache.jit_buffer_size=64M +--FILE-- +prop[] = 1; +})->bindTo($test, Test::class); +$appendProp2(); +?> +--EXPECTF-- +Warning: Undefined variable $test in %sgh15973.php on line 6 + +Fatal error: Uncaught Error: Using $this when not in object context in %sgh15973.php:5 +Stack trace: +#0 %sgh15973.php(7): Test::{closure}() +#1 {main} + thrown in %sgh15973.php on line 5 \ No newline at end of file diff --git a/ext/openssl/openssl.stub.php b/ext/openssl/openssl.stub.php index a9fad2eaeae90..523640c825920 100644 --- a/ext/openssl/openssl.stub.php +++ b/ext/openssl/openssl.stub.php @@ -433,9 +433,9 @@ function openssl_csr_export(OpenSSLCertificateSigningRequest|string $csr, &$outp function openssl_csr_sign(OpenSSLCertificateSigningRequest|string $csr, OpenSSLCertificate|string|null $ca_certificate, #[\SensitiveParameter] $private_key, int $days, ?array $options = null, int $serial = 0): OpenSSLCertificate|false {} /** - * @param OpenSSLAsymmetricKey $private_key + * @param OpenSSLAsymmetricKey|null $private_key */ -function openssl_csr_new(array $distinguished_names, #[\SensitiveParameter] &$private_key, ?array $options = null, ?array $extra_attributes = null): OpenSSLCertificateSigningRequest|false {} +function openssl_csr_new(array $distinguished_names, #[\SensitiveParameter] &$private_key, ?array $options = null, ?array $extra_attributes = null): OpenSSLCertificateSigningRequest|bool {} /** * @return array|false diff --git a/ext/openssl/openssl_arginfo.h b/ext/openssl/openssl_arginfo.h index 3e1b4a778a967..bfdf674b07d6a 100644 --- a/ext/openssl/openssl_arginfo.h +++ b/ext/openssl/openssl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: be79b4cc0d9eb4469c43f10208b86369dcc1239d */ + * Stub hash: f68e5002b3f1b224b3dd979307f0e4093f42d5e9 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 2, _IS_BOOL, 0) ZEND_ARG_OBJ_TYPE_MASK(0, certificate, OpenSSLCertificate, MAY_BE_STRING, NULL) @@ -92,7 +92,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_openssl_csr_sign, 0, 4, Open ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, serial, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_openssl_csr_new, 0, 2, OpenSSLCertificateSigningRequest, MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_openssl_csr_new, 0, 2, OpenSSLCertificateSigningRequest, MAY_BE_BOOL) ZEND_ARG_TYPE_INFO(0, distinguished_names, IS_ARRAY, 0) ZEND_ARG_INFO(1, private_key) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index ea5e6a01ff065..4c1d8db47c11b 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1135,6 +1135,11 @@ static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, int global) /* {{{ * RETURN_FALSE; } + if (start_offset == ZEND_LONG_MIN) { + zend_argument_value_error(5, "must be greater than " ZEND_LONG_FMT, ZEND_LONG_MIN); + RETURN_THROWS(); + } + pce->refcount++; php_pcre_match_impl(pce, subject, return_value, subpats, global, ZEND_NUM_ARGS() >= 4, flags, start_offset); @@ -1742,9 +1747,11 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su } if (preg_get_backref(&walk, &backref)) { if (backref < count) { - match_len = offsets[(backref<<1)+1] - offsets[backref<<1]; - memcpy(walkbuf, subject + offsets[backref<<1], match_len); - walkbuf += match_len; + if (offsets[backref<<1] < SIZE_MAX) { + match_len = offsets[(backref<<1)+1] - offsets[backref<<1]; + memcpy(walkbuf, subject + offsets[backref<<1], match_len); + walkbuf += match_len; + } } continue; } diff --git a/ext/pcre/tests/gh16184.phpt b/ext/pcre/tests/gh16184.phpt new file mode 100644 index 0000000000000..ba915d19af74b --- /dev/null +++ b/ext/pcre/tests/gh16184.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-16184 (UBSan address overflowed in ext/pcre/php_pcre.c) +--CREDITS-- +YuanchengJiang +--FILE-- + +--EXPECT-- +This test a string. It contains numbers * to 0* to 9* test well test parentheses and some other things* diff --git a/ext/pcre/tests/gh16189.phpt b/ext/pcre/tests/gh16189.phpt new file mode 100644 index 0000000000000..c77ab7699eed1 --- /dev/null +++ b/ext/pcre/tests/gh16189.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-16189 (preg_match/preg_match_all underflow on start_offset argument) +--FILE-- +/', '
', $matches, 0, PHP_INT_MIN); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + preg_match_all( '/<(\w+)[\s\w\-]+ id="S44_i89ew">/', '
', $matches, 0, PHP_INT_MIN); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +?> +--EXPECTF-- +preg_match(): Argument #5 ($offset) must be greater than %s +preg_match_all(): Argument #5 ($offset) must be greater than %s diff --git a/ext/phar/phar.c b/ext/phar/phar.c index b774f22e2d565..e3d6ea74c6182 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -457,14 +457,14 @@ void phar_entry_remove(phar_entry_data *idata, char **error) /* {{{ */ #ifdef WORDS_BIGENDIAN # define PHAR_GET_32(buffer, var) \ - var = ((((unsigned char*)(buffer))[3]) << 24) \ - | ((((unsigned char*)(buffer))[2]) << 16) \ - | ((((unsigned char*)(buffer))[1]) << 8) \ - | (((unsigned char*)(buffer))[0]); \ + var = ((uint32_t)(((unsigned char*)(buffer))[3]) << 24) \ + | ((uint32_t)(((unsigned char*)(buffer))[2]) << 16) \ + | ((uint32_t)(((unsigned char*)(buffer))[1]) << 8) \ + | ((uint32_t)((unsigned char*)(buffer))[0]); \ (buffer) += 4 # define PHAR_GET_16(buffer, var) \ - var = ((((unsigned char*)(buffer))[1]) << 8) \ - | (((unsigned char*)(buffer))[0]); \ + var = ((uint16_t)(((unsigned char*)(buffer))[1]) << 8) \ + | ((uint16_t)((unsigned char*)(buffer))[0]); \ (buffer) += 2 #else # define PHAR_GET_32(buffer, var) \ diff --git a/ext/phar/tests/033a.phpt b/ext/phar/tests/033a.phpt index c36c5c6853985..355617b29f93f 100644 --- a/ext/phar/tests/033a.phpt +++ b/ext/phar/tests/033a.phpt @@ -5,6 +5,12 @@ phar --INI-- phar.readonly=1 phar.require_hash=0 +--SKIPIF-- + --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- properties_info, prop_name)) { count++; diff --git a/ext/reflection/tests/gh16187.phpt b/ext/reflection/tests/gh16187.phpt new file mode 100644 index 0000000000000..64aec52de93ba --- /dev/null +++ b/ext/reflection/tests/gh16187.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-16187 (ReflectionClass::__toString() with unpacked properties) +--EXTENSIONS-- +simplexml +--FILE-- +'; +$simplexml = simplexml_load_string($xml); +$reflector = new ReflectionObject($simplexml['name']); +$reflector->__toString(); +?> +DONE +--EXPECT-- +DONE diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 6bcb9edcfface..21cd5cdb4c7bd 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -2547,6 +2547,11 @@ static void php_sxe_iterator_current_key(zend_object_iterator *iter, zval *key) { php_sxe_iterator *iterator = (php_sxe_iterator *)iter; zval *curobj = &iterator->sxe->iter.data; + if (Z_ISUNDEF_P(curobj)) { + ZVAL_NULL(key); + return; + } + php_sxe_object *intern = Z_SXEOBJ_P(curobj); xmlNodePtr curnode = NULL; diff --git a/ext/simplexml/tests/gh15837.phpt b/ext/simplexml/tests/gh15837.phpt new file mode 100644 index 0000000000000..302db064ee0e7 --- /dev/null +++ b/ext/simplexml/tests/gh15837.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-15837 (Segmentation fault in ext/simplexml/simplexml.c) +--CREDITS-- +YuanchengJiang +--FILE-- + + + + + + + + +EOF; +$sxe = new SimpleXMLIterator($xml); +$rit = new RecursiveIteratorIterator($sxe, RecursiveIteratorIterator::LEAVES_ONLY); +foreach ($rit as $child) { + $ancestry = $child->xpath('ancestor-or-self::*'); + // Exhaust internal iterator + foreach ($ancestry as $ancestor) { + } +} +var_dump($rit->valid()); +var_dump($rit->key()); +?> +--EXPECT-- +bool(false) +NULL diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 6568446249a31..29cf8fbc9086b 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -1408,7 +1408,9 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z return ret; } - object_init_ex(ret, ce); + if (object_init_ex(ret, ce) != SUCCESS) { + return ret; + } master_to_zval_int(&base, enc, data); set_zval_property(ret, "_", &base); } else { @@ -1417,7 +1419,9 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z if (soap_check_xml_ref(ret, data)) { return ret; } - object_init_ex(ret, ce); + if (object_init_ex(ret, ce) != SUCCESS) { + return ret; + } soap_add_xml_ref(ret, data); } } else if (sdlType->kind == XSD_TYPEKIND_EXTENSION && @@ -1462,7 +1466,9 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z return ret; } - object_init_ex(ret, ce); + if (object_init_ex(ret, ce) != SUCCESS) { + return ret; + } soap_add_xml_ref(ret, data); master_to_zval_int(&base, sdlType->encode, data); set_zval_property(ret, "_", &base); @@ -1473,7 +1479,9 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z if (soap_check_xml_ref(ret, data)) { return ret; } - object_init_ex(ret, ce); + if (object_init_ex(ret, ce) != SUCCESS) { + return ret; + } soap_add_xml_ref(ret, data); } if (sdlType->model) { @@ -1533,7 +1541,9 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z return ret; } - object_init_ex(ret, ce); + if (object_init_ex(ret, ce) != SUCCESS) { + return ret; + } soap_add_xml_ref(ret, data); trav = data->children; diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index 0c71c4f963166..00aa54c83efdb 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -461,6 +461,7 @@ int make_http_soap_request(zval *this_ptr, } add_soap_fault(this_ptr, "HTTP", "Unable to parse URL", NULL, NULL); smart_str_free(&soap_headers_z); + efree(http_msg); return FALSE; } @@ -474,6 +475,7 @@ int make_http_soap_request(zval *this_ptr, } add_soap_fault(this_ptr, "HTTP", "Unknown protocol. Only http and https are allowed.", NULL, NULL); smart_str_free(&soap_headers_z); + efree(http_msg); return FALSE; } @@ -487,6 +489,7 @@ int make_http_soap_request(zval *this_ptr, add_soap_fault(this_ptr, "HTTP", "SSL support is not available in this build", NULL, NULL); PG(allow_url_fopen) = old_allow_url_fopen; smart_str_free(&soap_headers_z); + efree(http_msg); return FALSE; } @@ -541,6 +544,7 @@ int make_http_soap_request(zval *this_ptr, add_soap_fault(this_ptr, "HTTP", "Could not connect to host", NULL, NULL); PG(allow_url_fopen) = old_allow_url_fopen; smart_str_free(&soap_headers_z); + efree(http_msg); return FALSE; } } @@ -684,6 +688,7 @@ int make_http_soap_request(zval *this_ptr, convert_to_null(Z_CLIENT_USE_PROXY_P(this_ptr)); smart_str_free(&soap_headers_z); smart_str_free(&soap_headers); + efree(http_msg); return FALSE; } @@ -901,12 +906,14 @@ int make_http_soap_request(zval *this_ptr, convert_to_null(Z_CLIENT_USE_PROXY_P(this_ptr)); add_soap_fault(this_ptr, "HTTP", "Failed Sending HTTP SOAP request", NULL, NULL); smart_str_free(&soap_headers_z); + efree(http_msg); return FALSE; } smart_str_free(&soap_headers); } else { add_soap_fault(this_ptr, "HTTP", "Failed to create stream??", NULL, NULL); smart_str_free(&soap_headers_z); + efree(http_msg); return FALSE; } @@ -915,6 +922,7 @@ int make_http_soap_request(zval *this_ptr, convert_to_null(Z_CLIENT_HTTPSOCKET_P(this_ptr)); convert_to_null(Z_CLIENT_USE_PROXY_P(this_ptr)); smart_str_free(&soap_headers_z); + efree(http_msg); return TRUE; } @@ -929,6 +937,7 @@ int make_http_soap_request(zval *this_ptr, convert_to_null(Z_CLIENT_USE_PROXY_P(this_ptr)); add_soap_fault(this_ptr, "HTTP", "Error Fetching http headers", NULL, NULL); smart_str_free(&soap_headers_z); + efree(http_msg); return FALSE; } @@ -1157,6 +1166,7 @@ int make_http_soap_request(zval *this_ptr, if (--redirect_max < 1) { add_soap_fault(this_ptr, "HTTP", "Redirection limit reached, aborting", NULL, NULL); smart_str_free(&soap_headers_z); + efree(http_msg); return FALSE; } diff --git a/ext/soap/php_schema.c b/ext/soap/php_schema.c index 17ece4fe770f8..423714545ae30 100644 --- a/ext/soap/php_schema.c +++ b/ext/soap/php_schema.c @@ -92,6 +92,13 @@ static encodePtr get_create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlCh return enc; } +/* Necessary for some error paths to avoid leaking persistent memory. */ +static void requestify_string(xmlChar **str) { + xmlChar *copy = (xmlChar *) estrdup((const char *) *str); + xmlFree(*str); + *str = copy; +} + static void schema_load_file(sdlCtx *ctx, xmlAttrPtr ns, xmlChar *location, xmlAttrPtr tns, int import) { if (location != NULL && !zend_hash_str_exists(&ctx->docs, (char*)location, xmlStrlen(location))) { @@ -104,22 +111,35 @@ static void schema_load_file(sdlCtx *ctx, xmlAttrPtr ns, xmlChar *location, xmlA sdl_restore_uri_credentials(ctx); if (doc == NULL) { + requestify_string(&location); soap_error1(E_ERROR, "Parsing Schema: can't import schema from '%s'", location); } schema = get_node(doc->children, "schema"); if (schema == NULL) { + requestify_string(&location); xmlFreeDoc(doc); soap_error1(E_ERROR, "Parsing Schema: can't import schema from '%s'", location); } new_tns = get_attribute(schema->properties, "targetNamespace"); if (import) { if (ns != NULL && (new_tns == NULL || xmlStrcmp(ns->children->content, new_tns->children->content) != 0)) { - xmlFreeDoc(doc); - soap_error2(E_ERROR, "Parsing Schema: can't import schema from '%s', unexpected 'targetNamespace'='%s'", location, ns->children->content); + requestify_string(&location); + if (new_tns == NULL) { + xmlFreeDoc(doc); + soap_error2(E_ERROR, "Parsing Schema: can't import schema from '%s', missing 'targetNamespace', expected '%s'", location, ns->children->content); + } else { + /* Have to make a copy to avoid a UAF after freeing `doc` */ + const char *target_ns_copy = estrdup((const char *) new_tns->children->content); + xmlFreeDoc(doc); + soap_error3(E_ERROR, "Parsing Schema: can't import schema from '%s', unexpected 'targetNamespace'='%s', expected '%s'", location, target_ns_copy, ns->children->content); + } } if (ns == NULL && new_tns != NULL) { + requestify_string(&location); + /* Have to make a copy to avoid a UAF after freeing `doc` */ + const char *target_ns_copy = estrdup((const char *) new_tns->children->content); xmlFreeDoc(doc); - soap_error2(E_ERROR, "Parsing Schema: can't import schema from '%s', unexpected 'targetNamespace'='%s'", location, new_tns->children->content); + soap_error2(E_ERROR, "Parsing Schema: can't import schema from '%s', unexpected 'targetNamespace'='%s', expected no 'targetNamespace'", location, target_ns_copy); } } else { new_tns = get_attribute(schema->properties, "targetNamespace"); @@ -128,6 +148,7 @@ static void schema_load_file(sdlCtx *ctx, xmlAttrPtr ns, xmlChar *location, xmlA xmlSetProp(schema, BAD_CAST("targetNamespace"), tns->children->content); } } else if (tns != NULL && xmlStrcmp(tns->children->content, new_tns->children->content) != 0) { + requestify_string(&location); xmlFreeDoc(doc); soap_error1(E_ERROR, "Parsing Schema: can't include schema from '%s', different 'targetNamespace'", location); } diff --git a/ext/soap/soap.c b/ext/soap/soap.c index e98820c630eda..0996927cee092 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -412,6 +412,7 @@ PHP_MINIT_FUNCTION(soap) memcpy(&soap_server_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); soap_server_object_handlers.offset = XtOffsetOf(soap_server_object, std); soap_server_object_handlers.free_obj = soap_server_object_free; + soap_server_object_handlers.clone_obj = NULL; /* Register SoapFault class */ soap_fault_class_entry = register_class_SoapFault(zend_ce_exception); @@ -837,6 +838,9 @@ PHP_METHOD(SoapServer, __construct) if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL && Z_TYPE_P(tmp) == IS_ARRAY) { + if (HT_IS_PACKED(Z_ARRVAL_P(tmp))) { + php_error_docref(NULL, E_ERROR, "'classmap' option must be an associative array"); + } service->class_map = zend_array_dup(Z_ARRVAL_P(tmp)); } @@ -2003,6 +2007,9 @@ PHP_METHOD(SoapClient, __construct) } if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL && Z_TYPE_P(tmp) == IS_ARRAY) { + if (HT_IS_PACKED(Z_ARRVAL_P(tmp))) { + php_error_docref(NULL, E_ERROR, "'classmap' option must be an associative array"); + } ZVAL_COPY(Z_CLIENT_CLASSMAP_P(this_ptr), tmp); } diff --git a/ext/soap/tests/bug71610.phpt b/ext/soap/tests/bug71610.phpt index ef0803134fb42..13913cfde7396 100644 --- a/ext/soap/tests/bug71610.phpt +++ b/ext/soap/tests/bug71610.phpt @@ -4,11 +4,20 @@ SOAP Bug #71610 - Type Confusion Vulnerability - SOAP / make_http_soap_request() soap --SKIPIF-- --FILE-- blahblah(); } catch(SoapFault $e) { diff --git a/ext/soap/tests/bugs/bug27722.phpt b/ext/soap/tests/bugs/bug27722.phpt index 3315b71401840..1bfc2fe6ee3b4 100644 --- a/ext/soap/tests/bugs/bug27722.phpt +++ b/ext/soap/tests/bugs/bug27722.phpt @@ -2,8 +2,6 @@ Bug #27722 (Segfault on schema without targetNamespace) --EXTENSIONS-- soap ---GET-- -wsdl --INI-- soap.wsdl_cache_enabled=0 --FILE-- diff --git a/ext/soap/tests/bugs/bug27742.phpt b/ext/soap/tests/bugs/bug27742.phpt index 02b27dc0144ec..1c7c8fc09f7e4 100644 --- a/ext/soap/tests/bugs/bug27742.phpt +++ b/ext/soap/tests/bugs/bug27742.phpt @@ -2,8 +2,6 @@ Bug #27742 (WDSL SOAP Parsing Schema bug) --EXTENSIONS-- soap ---GET-- -wsdl --INI-- soap.wsdl_cache_enabled=0 --FILE-- diff --git a/ext/soap/tests/bugs/bug62900.phpt b/ext/soap/tests/bugs/bug62900.phpt new file mode 100644 index 0000000000000..c78afda5304af --- /dev/null +++ b/ext/soap/tests/bugs/bug62900.phpt @@ -0,0 +1,95 @@ +--TEST-- +Bug #62900 (Wrong namespace on xsd import error message) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- + + + + + + + +XML; + +$wsdl_without_ns = << + + + + + + +XML; + +$xsd_with_wrong_ns = << + +XML; + +$xsd_without_ns = << + +XML; + +$combinations = [ + [$wsdl_with_ns, $xsd_with_wrong_ns], + [$wsdl_with_ns, $xsd_without_ns], + [$wsdl_without_ns, $xsd_with_wrong_ns], + [$wsdl_without_ns, $xsd_without_ns], +]; + +chdir(__DIR__); + +$args = ["-d", "display_startup_errors=0", "-d", "extension_dir=" . ini_get("extension_dir"), "-d", "extension=" . (substr(PHP_OS, 0, 3) == "WIN" ? "php_" : "") . "soap." . PHP_SHLIB_SUFFIX]; +if (php_ini_loaded_file()) { + // Necessary such that it works from a development directory in which case extension_dir might not be the real extension dir + $args[] = "-c"; + $args[] = php_ini_loaded_file(); +} + +foreach ($combinations as list($wsdl, $xsd)) { + file_put_contents(__DIR__."/bug62900.wsdl", $wsdl); + file_put_contents(__DIR__."/bug62900.xsd", $xsd); + + $proc = proc_open([PHP_BINARY, ...$args, __DIR__.'/bug62900_run'], [1 => ["pipe", "w"], 2 => ["pipe", "w"]], $pipes); + echo stream_get_contents($pipes[1]); + fclose($pipes[1]); + proc_close($proc); +} + +?> +--CLEAN-- + +--EXPECTF-- +Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing Schema: can't import schema from '%sbug62900.xsd', unexpected 'targetNamespace'='http://www.w3.org/XML/1998/namespacex', expected 'http://www.w3.org/XML/1998/namespace' in %s:%d +Stack trace: +#0 %s(%d): SoapClient->__construct(%s) +#1 {main} + thrown in %s on line %d + +Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing Schema: can't import schema from '%sbug62900.xsd', missing 'targetNamespace', expected 'http://www.w3.org/XML/1998/namespace' in %s:%d +Stack trace: +#0 %s(%d): SoapClient->__construct(%s) +#1 {main} + thrown in %s on line %d + +Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing Schema: can't import schema from '%sbug62900.xsd', unexpected 'targetNamespace'='http://www.w3.org/XML/1998/namespacex', expected no 'targetNamespace' in %s:%d +Stack trace: +#0 %s(%d): SoapClient->__construct(%s) +#1 {main} + thrown in %s on line %d + +Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't bind to service in %s:%d +Stack trace: +#0 %s(%d): SoapClient->__construct(%s) +#1 {main} + thrown in %s on line %d diff --git a/ext/soap/tests/bugs/bug62900_run b/ext/soap/tests/bugs/bug62900_run new file mode 100644 index 0000000000000..0b7f7a0f33a98 --- /dev/null +++ b/ext/soap/tests/bugs/bug62900_run @@ -0,0 +1,2 @@ +"http://testuri.org/"]); +try { + clone $server; +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Trying to clone an uncloneable object of class SoapServer diff --git a/ext/soap/tests/bugs/gh16256.phpt b/ext/soap/tests/bugs/gh16256.phpt new file mode 100644 index 0000000000000..ca8c00af5bbfb --- /dev/null +++ b/ext/soap/tests/bugs/gh16256.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-16256 (Assertion failure in ext/soap/php_encoding.c:460) +--EXTENSIONS-- +soap +--FILE-- + $classmap]); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +try { + new SoapServer($wsdl, ["classmap" => $classmap]); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +SoapClient::__construct(): 'classmap' option must be an associative array + +SOAP-ENV:ServerSoapServer::__construct(): 'classmap' option must be an associative array diff --git a/ext/soap/tests/bugs/gh16259.phpt b/ext/soap/tests/bugs/gh16259.phpt new file mode 100644 index 0000000000000..dd7e0e1585d29 --- /dev/null +++ b/ext/soap/tests/bugs/gh16259.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-16259 (Soap segfault when classmap instantiation fails) +--EXTENSIONS-- +soap +--FILE-- + "CT_A1", "A2" => "CT_A2"); +$client = new SoapClient(__DIR__."/bug36575.wsdl", array("trace" => 1, "exceptions" => 0)); +$a2 = new CT_A2(); +$client->test($a2); +$soapRequest = $client->__getLastRequest(); + +$server = new SoapServer(__DIR__."/bug36575.wsdl", array("classmap" => $classMap)); +$server->handle($soapRequest); +?> +--EXPECT-- + +SOAP-ENV:ServerCannot instantiate abstract class CT_A1 diff --git a/ext/soap/tests/server011.phpt b/ext/soap/tests/server011.phpt index ad4a626c79016..f236ec3affc59 100644 --- a/ext/soap/tests/server011.phpt +++ b/ext/soap/tests/server011.phpt @@ -1,5 +1,11 @@ --TEST-- SOAP Server 11: bind +--SKIPIF-- + --EXTENSIONS-- soap --GET-- diff --git a/ext/soap/tests/server012.phpt b/ext/soap/tests/server012.phpt index 230108e2b9202..703aefbaa7874 100644 --- a/ext/soap/tests/server012.phpt +++ b/ext/soap/tests/server012.phpt @@ -1,5 +1,11 @@ --TEST-- SOAP Server 12: WSDL generation +--SKIPIF-- + --EXTENSIONS-- soap --GET-- diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 8183398a8d322..f1a62c719291a 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -1211,6 +1211,11 @@ PHP_FUNCTION(socket_strerror) RETURN_THROWS(); } + if (ZEND_LONG_EXCEEDS_INT(arg1)) { + zend_argument_value_error(1, "must be between %d and %d", INT_MIN, INT_MAX); + RETURN_THROWS(); + } + RETURN_STRING(sockets_strerror(arg1)); } /* }}} */ diff --git a/ext/sockets/tests/gh16267.phpt b/ext/sockets/tests/gh16267.phpt new file mode 100644 index 0000000000000..d2462b3164530 --- /dev/null +++ b/ext/sockets/tests/gh16267.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-16267 - overflow on socket_strerror argument +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; +} +try { + socket_strerror(PHP_INT_MAX); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +?> +--EXPECTF-- +socket_strerror(): Argument #1 ($error_code) must be between %s and %s +socket_strerror(): Argument #1 ($error_code) must be between %s and %s diff --git a/ext/standard/array.c b/ext/standard/array.c index 4d1dca5002c1d..6c1975b121749 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -3700,7 +3700,6 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */ } ZEND_ASSERT(!Z_ISREF_P(dest_entry) || Z_REFCOUNT_P(dest_entry) > 1); - SEPARATE_ZVAL(dest_entry); dest_zval = dest_entry; if (Z_TYPE_P(dest_zval) == IS_NULL) { @@ -3709,6 +3708,8 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */ } else { convert_to_array(dest_zval); } + SEPARATE_ZVAL(dest_zval); + ZVAL_UNDEF(&tmp); if (Z_TYPE_P(src_zval) == IS_OBJECT) { ZVAL_COPY(&tmp, src_zval); diff --git a/ext/standard/pack.c b/ext/standard/pack.c index d12cd280a812f..24d116d302052 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -979,6 +979,13 @@ PHP_FUNCTION(unpack) zend_string *buf; zend_long ipos, opos; + + if (size > INT_MAX / 2) { + zend_string_release(real_name); + zend_argument_value_error(1, "repeater must be less than or equal to %d", INT_MAX / 2); + RETURN_THROWS(); + } + /* If size was given take minimum of len and size */ if (size >= 0 && len > (size * 2)) { len = size * 2; diff --git a/ext/standard/tests/array/gh16053.phpt b/ext/standard/tests/array/gh16053.phpt new file mode 100644 index 0000000000000..7106fb989abae --- /dev/null +++ b/ext/standard/tests/array/gh16053.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-16053: Assertion failure in Zend/zend_hash.c +--FILE-- + $x); +$arr2 = array("string" => "hello"); +var_dump($arr1); +var_dump(array_merge_recursive($arr1, $arr2)); + +?> +--EXPECTF-- +array(1) { + ["string"]=> + object(test)#%d (0) { + } +} +array(1) { + ["string"]=> + array(1) { + [0]=> + string(5) "hello" + } +} diff --git a/ext/standard/tests/file/file_get_contents_basic.phpt b/ext/standard/tests/file/file_get_contents_basic.phpt index 5c060fdae1ba5..e4b8173e7a144 100644 --- a/ext/standard/tests/file/file_get_contents_basic.phpt +++ b/ext/standard/tests/file/file_get_contents_basic.phpt @@ -13,15 +13,15 @@ echo "*** Testing the basic functionality of the file_get_contents() function ** echo "-- Testing with simple valid data file --\n"; -create_files($file_path, 1, "text", 0755, 100, "w", "file", 1, "byte"); -var_dump( file_get_contents($file_path."/file1.tmp") ); -delete_files($file_path, 1); +create_files($file_path, 1, "text", 0755, 100, "w", "file_get_contents_basic", 1, "byte"); +var_dump( file_get_contents($file_path."/file_get_contents_basic1.tmp") ); +delete_files($file_path, 1, "file_get_contents_basic", 1); echo "\n-- Testing with empty file --\n"; -create_files($file_path, 1, "empty", 0755, 100, "w", "file", 1, "byte"); -var_dump( file_get_contents($file_path."/file1.tmp") ); -delete_files($file_path, 1); +create_files($file_path, 1, "empty", 0755, 100, "w", "file_get_contents_basic", 1, "byte"); +var_dump( file_get_contents($file_path."/file_get_contents_basic1.tmp") ); +delete_files($file_path, 1, "file_get_contents_basic", 1); echo "\n*** Done ***"; ?> diff --git a/ext/standard/tests/file/file_get_contents_error.phpt b/ext/standard/tests/file/file_get_contents_error.phpt index 12ddfc73f5787..5ac352123b309 100644 --- a/ext/standard/tests/file/file_get_contents_error.phpt +++ b/ext/standard/tests/file/file_get_contents_error.phpt @@ -13,17 +13,17 @@ include($file_path."/file.inc"); echo "\n-- Testing with Non-existing file --\n"; print( file_get_contents("/no/such/file/or/dir") ); -create_files($file_path, 1, "text", 0755, 100, "w", "file", 1, "byte"); +create_files($file_path, 1, "text", 0755, 100, "w", "file_get_contents_error", 1, "byte"); $file_handle = fopen($file_path."/file_put_contents_error.tmp", "w"); echo "\n-- Testing for invalid negative maxlen values --\n"; try { - file_get_contents($file_path."/file1.tmp", FALSE, $file_handle, 0, -5); + file_get_contents($file_path."/file_get_contents_error1.tmp", FALSE, $file_handle, 0, -5); } catch (ValueError $exception) { echo $exception->getMessage() . "\n"; } -delete_files($file_path, 1); +delete_files($file_path, 1, "file_get_contents_error", 1); fclose($file_handle); unlink($file_path."/file_put_contents_error.tmp"); diff --git a/ext/standard/tests/general_functions/phpinfo.phpt b/ext/standard/tests/general_functions/phpinfo.phpt index 57ba13bb7bf7c..a8c4f392a38f8 100644 --- a/ext/standard/tests/general_functions/phpinfo.phpt +++ b/ext/standard/tests/general_functions/phpinfo.phpt @@ -16,21 +16,21 @@ phpinfo() PHP Version => %s System => %s -Build Date => %s%a +Build Date => %r(.+?)%r Configure Command => %s Server API => Command Line Interface Virtual Directory Support => %s Configuration File (php.ini) Path => %s -Loaded Configuration File => %a -Scan this dir for additional .ini files => %a -Additional .ini files parsed => %a +Loaded Configuration File => %r(.+?)%r +Scan this dir for additional .ini files => %r(.+?)%r +Additional .ini files parsed => %r(.+?)%r PHP API => %d PHP Extension => %d Zend Extension => %d Zend Extension Build => API%s PHP Extension Build => API%s Debug Build => %s -Thread Safety => %s%A +Thread Safety => %r(.+?)%r Zend Signal Handling => %s Zend Memory Manager => %s Zend Multibyte Support => %s @@ -42,22 +42,22 @@ Registered PHP Streams => %s Registered Stream Socket Transports => %s Registered Stream Filters => %s -%a +%r(.+?)%r _______________________________________________________________________ Configuration -%A +%r(.*?)%r Core -%A +%r(.*?)%r Additional Modules -%A +%r(.*?)%r Environment -%A +%r(.*?)%r PHP Variables -%A +%r(.*?)%r PHP License -%A +%r(.*?)%r bool(true) -- phpinfo() @@ -66,5 +66,5 @@ bool(true) phpinfo() PHP License -%a +%r(.+?)%r bool(true) diff --git a/ext/standard/tests/streams/gh15908.phpt b/ext/standard/tests/streams/gh15908.phpt new file mode 100644 index 0000000000000..31714b20530af --- /dev/null +++ b/ext/standard/tests/streams/gh15908.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-15908 (leak / assertion failure in streams.c) +--CREDITS-- +YuanchengJiang +LuMingYinDetect +--FILE-- +s++ == 0) + return "a\nbb\ncc"; + return ""; + } + function stream_eof() { + return $this->s >= 2; + } +} +touch(__DIR__."/gh15908.tmp"); +stream_wrapper_register("test", "TestStream"); +$f = fopen("test://", "r"); +try { + file_put_contents(__DIR__."/gh15908.tmp", $f, FILE_USE_INCLUDE_PATH, $f); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--CLEAN-- + +--EXPECT-- +file_put_contents(): supplied resource is not a valid Stream-Context resource diff --git a/ext/standard/tests/streams/gh15937.phpt b/ext/standard/tests/streams/gh15937.phpt new file mode 100644 index 0000000000000..db0564342b13b --- /dev/null +++ b/ext/standard/tests/streams/gh15937.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-15937 (stream overflow on timeout setting) +--SKIPIF-- + +--FILE-- + [ + 'timeout' => PHP_INT_MAX, + ], +]; +$ctx = stream_context_create($config); +var_dump(fopen("http://www.example.com/", "r", false, $ctx)); +?> +--EXPECTF-- +resource(%d) of type (stream) diff --git a/ext/standard/tests/streams/gh15980.phpt b/ext/standard/tests/streams/gh15980.phpt new file mode 100644 index 0000000000000..7a9d8364a90ae --- /dev/null +++ b/ext/standard/tests/streams/gh15980.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-15980 (Signed integer overflow in main/streams/streams.c) +--FILE-- + 1); +?> +--EXPECT-- +bool(true) diff --git a/ext/standard/tests/strings/gh15613.phpt b/ext/standard/tests/strings/gh15613.phpt new file mode 100644 index 0000000000000..8f40ee820c9a2 --- /dev/null +++ b/ext/standard/tests/strings/gh15613.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-15613 overflow on hex strings repeater value +--SKIPIF-- + +--INI-- +memory_limit=-1 +--FILE-- +getMessage() . PHP_EOL; +} + +try { + unpack('H2147483647', str_repeat('X', 2**31 + 10)); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +unpack(): Argument #1 ($format) repeater must be less than or equal to %d +unpack(): Argument #1 ($format) repeater must be less than or equal to %d diff --git a/ext/xml/tests/gh15868.phpt b/ext/xml/tests/gh15868.phpt new file mode 100644 index 0000000000000..17ed80558d786 --- /dev/null +++ b/ext/xml/tests/gh15868.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-15868 (Assertion failure in xml_parse_into_struct after exception) +--EXTENSIONS-- +xml +--FILE-- +", $values, $tags); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$parser = xml_parser_create(); +xml_set_element_handler($parser, + function ($parser, $name, $attrs) { + }, function ($parser, $name) { + throw new Error('stop 2'); + } +); +try { + xml_parse_into_struct($parser, "", $values, $tags); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$parser = xml_parser_create(); +xml_set_character_data_handler($parser, function() { + throw new Error('stop 3'); +}); +try { + xml_parse_into_struct($parser, "", $values, $tags); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +stop 1 +stop 2 +stop 3 diff --git a/ext/xml/xml.c b/ext/xml/xml.c index 59d50faed111e..eef78474281bb 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -628,7 +628,7 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch zval_ptr_dtor(&retval); } - if (!Z_ISUNDEF(parser->data)) { + if (!Z_ISUNDEF(parser->data) && !EG(exception)) { if (parser->level <= XML_MAXLEVEL) { zval tag, atr; int atcnt = 0; @@ -699,7 +699,7 @@ void _xml_endElementHandler(void *userData, const XML_Char *name) zval_ptr_dtor(&retval); } - if (!Z_ISUNDEF(parser->data)) { + if (!Z_ISUNDEF(parser->data) && !EG(exception)) { zval tag; if (parser->lastwasopen) { @@ -747,7 +747,7 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len) zval_ptr_dtor(&retval); } - if (Z_ISUNDEF(parser->data)) { + if (Z_ISUNDEF(parser->data) || EG(exception)) { return; } diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 2df6c2027498a..8989413317d76 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -879,6 +879,23 @@ static ZEND_METHOD(_ZendTestMagicCall, __call) RETURN_ARR(zend_new_pair(&name_zv, arguments)); } +static ZEND_METHOD(_ZendTestMagicCallForward, __call) +{ + zend_string *name; + zval *arguments; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_STR(name) + Z_PARAM_ARRAY(arguments) + ZEND_PARSE_PARAMETERS_END(); + + ZEND_IGNORE_VALUE(arguments); + + zval func; + ZVAL_STR(&func, name); + call_user_function(NULL, NULL, &func, return_value, 0, NULL); +} + 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) @@ -993,6 +1010,8 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_magic_call = register_class__ZendTestMagicCall(); + register_class__ZendTestMagicCallForward(); + zend_register_functions(NULL, ext_function_legacy, NULL, EG(current_module)->type); // Loading via dl() not supported with the observer API diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 7dc348934400f..8a605bdcd3280 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -52,6 +52,11 @@ class _ZendTestMagicCall public function __call(string $name, array $args): mixed {} } + class _ZendTestMagicCallForward + { + public function __call(string $name, array $args): mixed {} + } + class _ZendTestChildClass extends _ZendTestClass { public function returnsThrowable(): Exception {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 19ea9e7a2adf5..9c0735a1d6f89 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: 07ce28cd75080118509ac0d30d8ce5ef54110747 */ + * Stub hash: 5d861e05edfd57c385167b11b8b1ea977ed130a2 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -161,6 +161,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestMagicCall___call, ZEND_ARG_TYPE_INFO(0, args, IS_ARRAY, 0) ZEND_END_ARG_INFO() +#define arginfo_class__ZendTestMagicCallForward___call arginfo_class__ZendTestMagicCall___call + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestChildClass_returnsThrowable, 0, 0, Exception, 0) ZEND_END_ARG_INFO() @@ -245,6 +247,7 @@ static ZEND_METHOD(_ZendTestClass, returnsStatic); static ZEND_METHOD(_ZendTestClass, returnsThrowable); static ZEND_METHOD(_ZendTestClass, variadicTest); static ZEND_METHOD(_ZendTestMagicCall, __call); +static ZEND_METHOD(_ZendTestMagicCallForward, __call); static ZEND_METHOD(_ZendTestChildClass, returnsThrowable); static ZEND_METHOD(_ZendTestTrait, testMethod); static ZEND_METHOD(ZendTestParameterAttribute, __construct); @@ -332,6 +335,12 @@ static const zend_function_entry class__ZendTestMagicCall_methods[] = { }; +static const zend_function_entry class__ZendTestMagicCallForward_methods[] = { + ZEND_ME(_ZendTestMagicCallForward, __call, arginfo_class__ZendTestMagicCallForward___call, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + + static const zend_function_entry class__ZendTestChildClass_methods[] = { ZEND_ME(_ZendTestChildClass, returnsThrowable, arginfo_class__ZendTestChildClass_returnsThrowable, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -532,6 +541,16 @@ static zend_class_entry *register_class__ZendTestMagicCall(void) return class_entry; } +static zend_class_entry *register_class__ZendTestMagicCallForward(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestMagicCallForward", class__ZendTestMagicCallForward_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + + return class_entry; +} + static zend_class_entry *register_class__ZendTestChildClass(zend_class_entry *class_entry__ZendTestClass) { zend_class_entry ce, *class_entry; diff --git a/ext/zend_test/tests/gh16233.phpt b/ext/zend_test/tests/gh16233.phpt new file mode 100644 index 0000000000000..e3143b6c7ce11 --- /dev/null +++ b/ext/zend_test/tests/gh16233.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-16233 (Observer segfault when calling user function in internal function via trampoline) +--EXTENSIONS-- +zend_test +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.show_output=1 +zend_test.observer.observe_all=1 +--FILE-- +callee(); +echo "done\n"; + +?> +--EXPECTF-- + + + + <_ZendTestMagicCallForward::__call> + + +in callee + + +done + diff --git a/ext/zend_test/tests/observer_error_04.phpt b/ext/zend_test/tests/observer_error_04.phpt index bb3ee1013ec47..2a45bfe78c48d 100644 --- a/ext/zend_test/tests/observer_error_04.phpt +++ b/ext/zend_test/tests/observer_error_04.phpt @@ -47,9 +47,9 @@ echo 'Done.' . PHP_EOL; - -SOAP-ERROR: Parsing WSDL: Couldn't load from 'foo' : failed to load external entity "foo" +SOAP-ERROR: Parsing WSDL: %s Done. diff --git a/ext/zend_test/tests/observer_fiber_functions_03.phpt b/ext/zend_test/tests/observer_fiber_functions_03.phpt index 3468120ef4b58..147e6f7229d49 100644 --- a/ext/zend_test/tests/observer_fiber_functions_03.phpt +++ b/ext/zend_test/tests/observer_fiber_functions_03.phpt @@ -10,6 +10,10 @@ zend_test.observer.fiber_init=1 zend_test.observer.fiber_switch=1 zend_test.observer.fiber_destroy=1 memory_limit=100M +--SKIPIF-- + --FILE-- 0) { + SG(request_info).auth_password = estrdup(pass); + } ret = 0; } zend_string_free(user); diff --git a/main/php_network.h b/main/php_network.h index a3b7ba7ab3180..fda61b87cb4c9 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -162,7 +162,7 @@ PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout); /* timeval-to-timeout (for poll(2)) */ static inline int php_tvtoto(struct timeval *timeouttv) { - if (timeouttv) { + if (timeouttv && timeouttv->tv_sec >= 0 && timeouttv->tv_sec <= ((INT_MAX - 1000) / 1000)) { return (timeouttv->tv_sec * 1000) + (timeouttv->tv_usec / 1000); } return -1; diff --git a/main/php_variables.c b/main/php_variables.c index eb442c3d2f99f..bac5b1b673b61 100644 --- a/main/php_variables.c +++ b/main/php_variables.c @@ -897,6 +897,7 @@ static bool php_auto_globals_create_server(zend_string *name) } else { zval_ptr_dtor_nogc(&PG(http_globals)[TRACK_VARS_SERVER]); array_init(&PG(http_globals)[TRACK_VARS_SERVER]); + zend_hash_real_init_mixed(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER])); } check_http_proxy(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER])); diff --git a/main/php_version.h b/main/php_version.h index 44f5ed7ccc5d1..c58b7a36e5b50 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 2 -#define PHP_RELEASE_VERSION 24 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.2.24-dev" -#define PHP_VERSION_ID 80224 +#define PHP_RELEASE_VERSION 25 +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.2.25" +#define PHP_VERSION_ID 80225 diff --git a/main/rfc1867.c b/main/rfc1867.c index 919843928b6af..12794c414b342 100644 --- a/main/rfc1867.c +++ b/main/rfc1867.c @@ -752,6 +752,13 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ boundary_len = boundary_end-boundary; } + /* Boundaries larger than FILLUNIT-strlen("\r\n--") characters lead to + * erroneous parsing */ + if (boundary_len > FILLUNIT-strlen("\r\n--")) { + sapi_module.sapi_error(E_WARNING, "Boundary too large in multipart/form-data POST data"); + return; + } + /* Initialize the buffer */ if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) { sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer"); diff --git a/main/streams/streams.c b/main/streams/streams.c index 33f8b7e7a80cd..4c66d8aadc39b 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1354,8 +1354,13 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) switch(whence) { case SEEK_CUR: - offset = stream->position + offset; - whence = SEEK_SET; + ZEND_ASSERT(stream->position >= 0); + if (UNEXPECTED(offset > ZEND_LONG_MAX - stream->position)) { + offset = ZEND_LONG_MAX; + } else { + offset = stream->position + offset; + } + whence = SEEK_SET; break; } ret = stream->ops->seek(stream, offset, whence, &stream->position); @@ -2175,6 +2180,9 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod options &= ~USE_PATH; } if (EG(exception)) { + if (resolved_path) { + zend_string_release_ex(resolved_path, false); + } return NULL; } } diff --git a/run-tests.php b/run-tests.php index bb422e41c0fe4..5add428aaddc5 100755 --- a/run-tests.php +++ b/run-tests.php @@ -2159,6 +2159,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('flaky', $output, 5)) { + // Pretend we have a FLAKY section + $test->setSection('FLAKY', ltrim(substr($output, 5))); } elseif ($output !== '') { show_result("BORK", $output, $tested_file, 'reason: invalid output from SKIPIF', $temp_filenames); $PHP_FAILED_TESTS['BORKED'][] = [ diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 01fdebae0bde1..689dce2be6398 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -1746,7 +1746,6 @@ int main(int argc, char *argv[]) int status = 0; #endif char *query_string; - char *decoded_query_string; int skip_getopt = 0; #if defined(SIGPIPE) && defined(SIG_IGN) @@ -1801,10 +1800,15 @@ int main(int argc, char *argv[]) * the executable. Ideally we skip argument parsing when we're in cgi or fastcgi mode, * but that breaks PHP scripts on Linux with a hashbang: `#!/php-cgi -d option=value`. * Therefore, this code only prevents passing arguments if the query string starts with a '-'. - * Similarly, scripts spawned in subprocesses on Windows may have the same issue. */ + * Similarly, scripts spawned in subprocesses on Windows may have the same issue. + * However, Windows has lots of conversion rules and command line parsing rules that + * are too difficult and dangerous to reliably emulate. */ if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) { +#ifdef PHP_WIN32 + skip_getopt = cgi || fastcgi; +#else unsigned char *p; - decoded_query_string = strdup(query_string); + char *decoded_query_string = strdup(query_string); php_url_decode(decoded_query_string, strlen(decoded_query_string)); for (p = (unsigned char *)decoded_query_string; *p && *p <= ' '; p++) { /* skip all leading spaces */ @@ -1813,22 +1817,8 @@ int main(int argc, char *argv[]) skip_getopt = 1; } - /* On Windows we have to take into account the "best fit" mapping behaviour. */ -#ifdef PHP_WIN32 - if (*p >= 0x80) { - wchar_t wide_buf[1]; - wide_buf[0] = *p; - char char_buf[4]; - size_t wide_buf_len = sizeof(wide_buf) / sizeof(wide_buf[0]); - size_t char_buf_len = sizeof(char_buf) / sizeof(char_buf[0]); - if (WideCharToMultiByte(CP_ACP, 0, wide_buf, wide_buf_len, char_buf, char_buf_len, NULL, NULL) == 0 - || char_buf[0] == '-') { - skip_getopt = 1; - } - } -#endif - free(decoded_query_string); +#endif } php_ini_builder_init(&ini_builder); @@ -1895,18 +1885,17 @@ int main(int argc, char *argv[]) /* check force_cgi after startup, so we have proper output */ if (cgi && CGIG(force_redirect)) { - /* Apache will generate REDIRECT_STATUS, - * Netscape and redirect.so will generate HTTP_REDIRECT_STATUS. - * redirect.so and installation instructions available from - * http://www.koehntopp.de/php. - * -- kk@netuse.de - */ - if (!getenv("REDIRECT_STATUS") && - !getenv ("HTTP_REDIRECT_STATUS") && - /* this is to allow a different env var to be configured - * in case some server does something different than above */ - (!CGIG(redirect_status_env) || !getenv(CGIG(redirect_status_env))) - ) { + /* This is to allow a different environment variable to be configured + * in case the we cannot auto-detect which environment variable to use. + * Checking this first to allow user overrides in case the environment + * variable can be set by an untrusted party. */ + const char *redirect_status_env = CGIG(redirect_status_env); + if (!redirect_status_env) { + /* Apache will generate REDIRECT_STATUS. */ + redirect_status_env = "REDIRECT_STATUS"; + } + + if (!getenv(redirect_status_env)) { zend_try { SG(sapi_headers).http_response_code = 400; PUTS("Security Alert! The PHP CGI cannot be accessed directly.\n\n\ diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index ff525438ebc03..34046466ae7ea 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -1075,6 +1075,7 @@ static int do_cli(int argc, char **argv) /* {{{ */ object_init_ex(&ref, pce); memset(&execute_data, 0, sizeof(zend_execute_data)); + execute_data.func = (zend_function *) &zend_pass_function; EG(current_execute_data) = &execute_data; zend_call_known_instance_method_with_1_params( pce->constructor, Z_OBJ(ref), NULL, &arg); diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 379ee70974d8e..732ac27c9a207 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -1680,14 +1680,33 @@ static void php_cli_server_client_save_header(php_cli_server_client *client) { /* Wrap header value in a zval to add is to the HashTable which acts as an array */ zval tmp; - ZVAL_STR(&tmp, client->current_header_value); /* strip off the colon */ zend_string *lc_header_name = zend_string_tolower_ex(client->current_header_name, /* persistent */ true); GC_MAKE_PERSISTENT_LOCAL(lc_header_name); - /* Add the wrapped zend_string to the HashTable */ - zend_hash_add(&client->request.headers, lc_header_name, &tmp); - zend_hash_add(&client->request.headers_original_case, client->current_header_name, &tmp); + zval *entry = zend_hash_find(&client->request.headers, lc_header_name); + bool with_comma = !zend_string_equals_literal(lc_header_name, "set-cookie"); + + /** + * `Set-Cookie` HTTP header being the exception, they can have 1 or more values separated + * by a comma while still possibly be set separately by the client. + **/ + if (!with_comma || entry == NULL) { + ZVAL_STR(&tmp, client->current_header_value); + } else { + zend_string *curval = Z_STR_P(entry); + zend_string *newval = zend_string_safe_alloc(1, ZSTR_LEN(curval), ZSTR_LEN(client->current_header_value) + 2, /* persistent */true); + + memcpy(ZSTR_VAL(newval), ZSTR_VAL(curval), ZSTR_LEN(curval)); + memcpy(ZSTR_VAL(newval) + ZSTR_LEN(curval), ", ", 2); + memcpy(ZSTR_VAL(newval) + ZSTR_LEN(curval) + 2, ZSTR_VAL(client->current_header_value), ZSTR_LEN(client->current_header_value) + 1); + + ZVAL_STR(&tmp, newval); + } + + /* Add/Update the wrapped zend_string to the HashTable */ + zend_hash_update(&client->request.headers, lc_header_name, &tmp); + zend_hash_update(&client->request.headers_original_case, client->current_header_name, &tmp); zend_string_release_ex(lc_header_name, /* persistent */ true); zend_string_release_ex(client->current_header_name, /* persistent */ true); diff --git a/sapi/cli/tests/gh16137.phpt b/sapi/cli/tests/gh16137.phpt new file mode 100644 index 0000000000000..165b8b1afd300 --- /dev/null +++ b/sapi/cli/tests/gh16137.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug GH-16137 duplicate *Forwarded* HTTP headers values. +--INI-- +allow_url_fopen=1 +--SKIPIF-- + +--FILE-- + array ( + 'method' => 'POST', + 'header' => array('x-forwarded-for: 127.0.0.1', 'x-forwarded-for: 192.168.1.254') +))); +var_dump(file_get_contents("http://" . PHP_CLI_SERVER_ADDRESS, true, $ctx)); +?> +--EXPECT-- +string(24) "127.0.0.1, 192.168.1.254" diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c index c796f17197381..eecdfc8f2d828 100644 --- a/sapi/fpm/fpm/fpm_stdio.c +++ b/sapi/fpm/fpm/fpm_stdio.c @@ -229,7 +229,7 @@ static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg) if ((sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos) <= in_buf && !memcmp(buf, &FPM_STDIO_CMD_FLUSH[cmd_pos], sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos)) { zlog_stream_finish(log_stream); - start = cmd_pos; + start = sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos; } else { zlog_stream_str(log_stream, &FPM_STDIO_CMD_FLUSH[0], cmd_pos); } diff --git a/sapi/fpm/tests/gh15395-php-auth-shutdown.phpt b/sapi/fpm/tests/gh15395-php-auth-shutdown.phpt new file mode 100644 index 0000000000000..b9875dd10ef5e --- /dev/null +++ b/sapi/fpm/tests/gh15395-php-auth-shutdown.phpt @@ -0,0 +1,61 @@ +--TEST-- +FPM: GH-15335 - PHP_AUTH shutdown use after free +--SKIPIF-- + +--FILE-- +createSourceFileAndScriptName(); +$tester->start(); +$tester->expectLogStartNotices(); +$tester + ->request( + headers: [ "HTTP_AUTHORIZATION" => "Basic Zm9vOg==", "REQUEST_METHOD" => "GET"], + uri: $scriptName, + address: '{{ADDR}}', + scriptFilename: __DIR__ . "/__unknown.php", + scriptName: "/", + ) + ->expectStatus('404 Not Found'); +$tester + ->request( + uri: $scriptName, + address: '{{ADDR}}', + params: [], + ); +$tester->expectNoLogPattern("/zend_mm_heap corrupted/"); +$tester->terminate(); +$tester->expectLogTerminatingNotices(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt new file mode 100644 index 0000000000000..528263200803e --- /dev/null +++ b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt @@ -0,0 +1,47 @@ +--TEST-- +FPM: Buffered worker output plain log with msg with flush split position towards separator end +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +$tester->request()->expectEmptyBody(); +$tester->expectLogLine(str_repeat('a', 1013) . "Quarkslab", decorated: false); +$tester->expectLogLine("Quarkslab", decorated: false); +$tester->terminate(); +$tester->expectLogTerminatingNotices(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt new file mode 100644 index 0000000000000..3490593855328 --- /dev/null +++ b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt @@ -0,0 +1,47 @@ +--TEST-- +FPM: Buffered worker output plain log with msg with flush split position towards separator start +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +$tester->request()->expectEmptyBody(); +$tester->expectLogLine(str_repeat('a', 1009) . "Quarkslab", decorated: false); +$tester->expectLogLine("Quarkslab", decorated: false); +$tester->terminate(); +$tester->expectLogTerminatingNotices(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc index ed0988f883ac1..bf4f3d918131c 100644 --- a/sapi/fpm/tests/tester.inc +++ b/sapi/fpm/tests/tester.inc @@ -762,6 +762,7 @@ class Tester string|array $stdin = null, bool $expectError = false, int $readLimit = -1, + array $params = null, ): Response { if ($this->hasError()) { return $this->createResponse(expectInvalid: true); @@ -771,7 +772,7 @@ class Tester $stdin = $this->parseStdin($stdin, $headers); } - $params = $this->getRequestParams($query, $headers, $uri, $scriptFilename, $scriptName, $stdin); + $params = $params ?? $this->getRequestParams($query, $headers, $uri, $scriptFilename, $scriptName, $stdin); $this->trace('Request params', $params); try { diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c index b6c48d548f1f0..d64703755cbe0 100644 --- a/sapi/phpdbg/phpdbg_info.c +++ b/sapi/phpdbg/phpdbg_info.c @@ -399,27 +399,29 @@ PHPDBG_INFO(classes) /* {{{ */ phpdbg_notice("User Classes (%d)", zend_hash_num_elements(&classes)); /* once added, assume that classes are stable... until shutdown. */ - ZEND_HASH_PACKED_FOREACH_PTR(&classes, ce) { - phpdbg_print_class_name(ce); - - if (ce->parent) { - if (ce->ce_flags & ZEND_ACC_LINKED) { - zend_class_entry *pce = ce->parent; - do { - phpdbg_out("|-------- "); - phpdbg_print_class_name(pce); - } while ((pce = pce->parent)); - } else { - phpdbg_writeln("|-------- User Class %s (not yet linked because declaration for parent was not encountered when declaring the class)", ZSTR_VAL(ce->parent_name)); + if (HT_IS_INITIALIZED(&classes)) { + ZEND_HASH_PACKED_FOREACH_PTR(&classes, ce) { + phpdbg_print_class_name(ce); + + if (ce->parent) { + if (ce->ce_flags & ZEND_ACC_LINKED) { + zend_class_entry *pce = ce->parent; + do { + phpdbg_out("|-------- "); + phpdbg_print_class_name(pce); + } while ((pce = pce->parent)); + } else { + phpdbg_writeln("|-------- User Class %s (not yet linked because declaration for parent was not encountered when declaring the class)", ZSTR_VAL(ce->parent_name)); + } } - } - if (ce->info.user.filename) { - phpdbg_writeln("|---- in %s on line %u", ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start); - } else { - phpdbg_writeln("|---- no source code"); - } - } ZEND_HASH_FOREACH_END(); + if (ce->info.user.filename) { + phpdbg_writeln("|---- in %s on line %u", ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start); + } else { + phpdbg_writeln("|---- no source code"); + } + } ZEND_HASH_FOREACH_END(); + } zend_hash_destroy(&classes); @@ -445,17 +447,19 @@ PHPDBG_INFO(funcs) /* {{{ */ phpdbg_notice("User Functions (%d)", zend_hash_num_elements(&functions)); - ZEND_HASH_PACKED_FOREACH_PTR(&functions, zf) { - zend_op_array *op_array = &zf->op_array; + if (HT_IS_INITIALIZED(&functions)) { + ZEND_HASH_PACKED_FOREACH_PTR(&functions, zf) { + zend_op_array *op_array = &zf->op_array; - phpdbg_write("|-------- %s", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "{main}"); + phpdbg_write("|-------- %s", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "{main}"); - if (op_array->filename) { - phpdbg_writeln(" in %s on line %d", ZSTR_VAL(op_array->filename), op_array->line_start); - } else { - phpdbg_writeln(" (no source code)"); - } - } ZEND_HASH_FOREACH_END(); + if (op_array->filename) { + phpdbg_writeln(" in %s on line %d", ZSTR_VAL(op_array->filename), op_array->line_start); + } else { + phpdbg_writeln(" (no source code)"); + } + } ZEND_HASH_FOREACH_END(); + } zend_hash_destroy(&functions); diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 887064cf2e70b..448194f13d261 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -907,7 +907,7 @@ PHPDBG_COMMAND(run) /* {{{ */ } } zend_end_try(); - if (EG(exception)) { + if (EG(exception) && !zend_is_unwind_exit(EG(exception))) { phpdbg_handle_exception(); } } diff --git a/sapi/phpdbg/tests/gh15901.phpt b/sapi/phpdbg/tests/gh15901.phpt new file mode 100644 index 0000000000000..00783b71968a2 --- /dev/null +++ b/sapi/phpdbg/tests/gh15901.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-15901 (phpdbg: Assertion failure on `i funcs`) +--PHPDBG-- +i funcs +i classes +--EXPECT-- +prompt> [User Functions (0)] +prompt> [User Classes (0)] +prompt> [User Classes (0)] +prompt> diff --git a/sapi/phpdbg/tests/gh16181.phpt b/sapi/phpdbg/tests/gh16181.phpt new file mode 100644 index 0000000000000..478bbb98ca0d9 --- /dev/null +++ b/sapi/phpdbg/tests/gh16181.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-16181 (phpdbg: exit in exception handler reports fatal error) +--PHPDBG-- +r +c +q +--FILE-- + +--EXPECTF-- +[Successful compilation of %s] +prompt> throwing exception +[Uncaught Exception in %s on line %d: oh noes] +>00008: throw new \Exception("oh noes"); + 00009: ?> + 00010: +prompt> exception caught +[Script ended normally] +prompt> diff --git a/scripts/phpize.m4 b/scripts/phpize.m4 index 616d16420a5a1..b713dcc650593 100644 --- a/scripts/phpize.m4 +++ b/scripts/phpize.m4 @@ -115,10 +115,7 @@ dnl Discard optimization flags when debugging is enabled. if test "$PHP_DEBUG" = "yes"; then PHP_DEBUG=1 ZEND_DEBUG=yes - changequote({,}) - CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9s]*//g'` - CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9s]*//g'` - changequote([,]) + PHP_REMOVE_OPTIMIZATION_FLAGS dnl Add -O0 only if GCC or ICC is used. if test "$GCC" = "yes" || test "$ICC" = "yes"; then CFLAGS="$CFLAGS -O0" diff --git a/tests/basic/GHSA-9pqp-7h25-4f32.inc b/tests/basic/GHSA-9pqp-7h25-4f32.inc new file mode 100644 index 0000000000000..adf72a361a2cb --- /dev/null +++ b/tests/basic/GHSA-9pqp-7h25-4f32.inc @@ -0,0 +1,3 @@ + +--FILE-- + '1', + 'CONTENT_TYPE' => "multipart/form-data; boundary=$boundary", + 'CONTENT_LENGTH' => strlen($body), + 'REQUEST_METHOD' => 'POST', + 'SCRIPT_FILENAME' => __DIR__ . '/GHSA-9pqp-7h25-4f32.inc', + ]); + + $spec = [ + 0 => ['pipe', 'r'], + 1 => STDOUT, + 2 => STDOUT, + ]; + + $pipes = []; + + print "Starting...\n"; + + $handle = proc_open($cmd, $spec, $pipes, getcwd(), $env); + + fwrite($pipes[0], $body); + + $status = proc_close($handle); + + print "\n"; +} + +for ($offset = -1; $offset <= 1; $offset++) { + test(FILLUNIT - strlen("\r\n--") + $offset); +} + +?> +--EXPECTF-- +Boundary len: 5115 +Starting... +X-Powered-By: %s +Content-type: text/html; charset=UTF-8 + +Hello world +array(1) { + ["koko"]=> + string(5124) "BBB +--AAA%sCCC" +} + +Boundary len: 5116 +Starting... +X-Powered-By: %s +Content-type: text/html; charset=UTF-8 + +Hello world +array(1) { + ["koko"]=> + string(5125) "BBB +--AAA%sCCC" +} + +Boundary len: 5117 +Starting... +X-Powered-By: %s +Content-type: text/html; charset=UTF-8 + +
+Warning: Boundary too large in multipart/form-data POST data in Unknown on line 0
+Hello world +array(0) { +} + diff --git a/tests/basic/gh15905.phpt b/tests/basic/gh15905.phpt new file mode 100644 index 0000000000000..6636b97024276 --- /dev/null +++ b/tests/basic/gh15905.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-15905 (Assertion failure for TRACK_VARS_SERVER) +--INI-- +variables_order=E +auto_globals_jit=0 +register_argc_argv=1 +--FILE-- + +--EXPECT-- +okay