diff --git a/.github/actions/macos-update-clang/action.yml b/.github/actions/macos-update-clang/action.yml new file mode 100644 index 0000000000000..916b4dfe41f48 --- /dev/null +++ b/.github/actions/macos-update-clang/action.yml @@ -0,0 +1,17 @@ +name: Update clang +runs: + using: composite + steps: + - shell: bash + run: | + softwareupdate -l + label=$((softwareupdate -l 2>/dev/null | grep 'Label:' | grep -o 'Command Line Tools for Xcode.*' | head -1) || echo '') + if [ -n "$label" ]; then + softwareupdate -i "$label" + xcode_path=$(ls -1 '/Applications' | grep 'Xcode_.*\.app' | sort -r | head -1) + sudo xcode-select -s "/Applications/$xcode_path" + else + echo "Not found." + fi + which clang + clang -v diff --git a/.github/actions/verify-generated-files/action.yml b/.github/actions/verify-generated-files/action.yml index 13f0cf9f128bb..79c49dbfcfffb 100644 --- a/.github/actions/verify-generated-files/action.yml +++ b/.github/actions/verify-generated-files/action.yml @@ -13,5 +13,4 @@ runs: ext/tokenizer/tokenizer_data_gen.php build/gen_stub.php -f --generate-optimizer-info --verify ext/phar/makestub.php - # Use the -a flag for a bug in git 2.46.0, which doesn't consider changed -diff files. - git add . -N && git diff -a --exit-code + .github/scripts/test-directory-unchanged.sh . diff --git a/.github/nightly_matrix.php b/.github/nightly_matrix.php index c1f5627542684..0032da7dbcea8 100644 --- a/.github/nightly_matrix.php +++ b/.github/nightly_matrix.php @@ -6,7 +6,6 @@ ['ref' => 'PHP-8.4', 'version' => [8, 4]], ['ref' => 'PHP-8.3', 'version' => [8, 3]], ['ref' => 'PHP-8.2', 'version' => [8, 2]], - ['ref' => 'PHP-8.1', 'version' => [8, 1]], ]; function get_branch_commit_cache_file_path(): string { diff --git a/.github/scripts/download-bundled/pcre2.sh b/.github/scripts/download-bundled/pcre2.sh new file mode 100755 index 0000000000000..b43554206c929 --- /dev/null +++ b/.github/scripts/download-bundled/pcre2.sh @@ -0,0 +1,32 @@ +#!/bin/sh +set -ex +cd "$(dirname "$0")/../../.." + +revision=refs/tags/pcre2-10.44 + +git clone --depth 1 --recurse-submodules --revision="$revision" https://github.com/PCRE2Project/pcre2.git /tmp/php-src-bundled/pcre2 + +rm -rf ext/pcre/pcre2lib +cp -R /tmp/php-src-bundled/pcre2/src ext/pcre/pcre2lib + +cd ext/pcre/pcre2lib + +# remove unneeded files +rm config.h.generic +rm pcre2.h.in +rm pcre2_dftables.c +rm pcre2_fuzzsupport.c +rm pcre2_jit_test.c +rm pcre2demo.c +rm pcre2grep.c +rm pcre2posix.c +rm pcre2posix.h +rm pcre2posix_test.c +rm pcre2test.c + +# move renamed files +mv pcre2.h.generic pcre2.h +mv pcre2_chartables.c.dist pcre2_chartables.c + +# add extra files +git restore config.h # based on config.h.generic but with many changes diff --git a/.github/scripts/test-directory-unchanged.sh b/.github/scripts/test-directory-unchanged.sh new file mode 100755 index 0000000000000..0ce7fd4cc4afd --- /dev/null +++ b/.github/scripts/test-directory-unchanged.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -ex + +cd "$(dirname "$0")/../../$1" + +# notify git about untracked (except ignored) files +git add -N . + +# display overview of changed files +git status . + +# display diff of working directory vs HEAD commit and set exit code +git diff -a --exit-code HEAD . diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3e59990742cbe..0ab56f77ab3f8 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -17,7 +17,7 @@ jobs: if: github.repository == 'php/php-src' steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install dependencies run: pip install -r docs/requirements.txt - name: Check formatting diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index dbddbdc5d89b3..4cf6357c491fd 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -12,6 +12,6 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@v6 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index adf07313a4c59..9ab95da2d935d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -41,9 +41,9 @@ on: skip_laravel: required: true type: boolean - skip_symfony: + symfony_version: required: true - type: boolean + type: string skip_wordpress: required: true type: boolean @@ -60,7 +60,7 @@ jobs: runs-on: [self-hosted, gentoo, ppc64] steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: System info @@ -101,7 +101,7 @@ jobs: image: 'alpine:3.22' steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: apk @@ -202,7 +202,7 @@ jobs: runs-on: ubuntu-${{ matrix.asan && inputs.asan_ubuntu_version || inputs.ubuntu_version }} steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: Create MSSQL container @@ -297,7 +297,7 @@ jobs: FIREBIRD_PASSWORD: test steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: apt @@ -360,9 +360,11 @@ jobs: runs-on: macos-${{ matrix.arch == 'X64' && '15-intel' || inputs.macos_arm64_version }} steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} + - name: Update clang + uses: ./.github/actions/macos-update-clang - name: brew uses: ./.github/actions/brew - name: ./configure @@ -430,7 +432,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: Create MSSQL container @@ -478,7 +480,7 @@ jobs: USE_TRACKED_ALLOC: 1 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: apt @@ -590,9 +592,9 @@ jobs: exit 1 fi - name: Test Symfony - if: ${{ !cancelled() && !inputs.skip_symfony }} + if: ${{ !cancelled() && inputs.symfony_version != '' }} run: | - git clone https://github.com/symfony/symfony.git --depth=1 + git clone https://github.com/symfony/symfony.git --depth=1 --branch="${{ inputs.symfony_version }}" cd symfony git rev-parse HEAD php /usr/bin/composer install --no-progress --ignore-platform-req=php+ @@ -626,7 +628,8 @@ jobs: exit 1 fi - name: 'Symfony Preloading' - if: ${{ !cancelled() && !inputs.skip_symfony }} + # composer create-project will automatically pick the right Symfony version for us. + if: ${{ !cancelled() && inputs.symfony_version != '' }} run: | php /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress --ignore-platform-req=php+ cd symfony_demo @@ -676,7 +679,7 @@ jobs: runs-on: ubuntu-${{ inputs.ubuntu_version }} steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: Create MSSQL container @@ -734,7 +737,7 @@ jobs: runs-on: ubuntu-${{ inputs.ubuntu_version }} steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: apt @@ -820,7 +823,7 @@ jobs: runs-on: ubuntu-${{ inputs.ubuntu_version }} steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: apt @@ -865,38 +868,38 @@ jobs: CXX: ccache g++ steps: - name: git checkout PHP - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: path: php ref: ${{ inputs.branch }} - name: git checkout apcu - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: krakjoe/apcu path: apcu - name: git checkout imagick - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: Imagick/imagick path: imagick - name: git checkout memcached - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: php-memcached-dev/php-memcached path: memcached - name: git checkout redis - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: phpredis/phpredis path: redis - name: git checkout xdebug if: false - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: xdebug/xdebug path: xdebug - name: git checkout yaml - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: php/pecl-file_formats-yaml path: yaml @@ -1001,7 +1004,7 @@ jobs: - name: git config run: git config --global core.autocrlf false && git config --global core.eol lf - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: Setup @@ -1022,7 +1025,7 @@ jobs: timeout-minutes: 50 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: FreeBSD diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 41a9d51e99361..64dc1ce6b60ed 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -40,7 +40,7 @@ jobs: image: 'alpine:3.22' steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: apk uses: ./.github/actions/apk - name: System info @@ -115,7 +115,7 @@ jobs: timeout-minutes: 50 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: apt uses: ./.github/actions/apt-x64 - name: System info @@ -200,7 +200,7 @@ jobs: FIREBIRD_PASSWORD: test steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: apt uses: ./.github/actions/apt-x32 - name: ccache @@ -238,7 +238,9 @@ jobs: timeout-minutes: 50 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 + - name: Update clang + uses: ./.github/actions/macos-update-clang - name: brew uses: ./.github/actions/brew - name: ccache @@ -285,7 +287,7 @@ jobs: - name: git config run: git config --global core.autocrlf false && git config --global core.eol lf - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup uses: ./.github/actions/setup-windows - name: Build @@ -299,7 +301,7 @@ jobs: timeout-minutes: 50 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 # ASLR can cause a lot of noise due to missed sse opportunities for memcpy @@ -361,7 +363,7 @@ jobs: mysql -uroot -proot -e "CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'wordpress'; FLUSH PRIVILEGES;" mysql -uroot -proot -e "GRANT ALL PRIVILEGES ON *.* TO 'wordpress'@'localhost' WITH GRANT OPTION;" - name: git checkout benchmarking-data - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: php/benchmarking-data ssh-key: ${{ secrets.BENCHMARKING_DATA_DEPLOY_KEY }} @@ -392,7 +394,7 @@ jobs: ${{ github.sha }} \ $(git merge-base ${{ github.event.pull_request.base.sha }} ${{ github.sha }}) \ > $GITHUB_STEP_SUMMARY - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v6 with: name: profiles path: ${{ github.workspace }}/benchmark/profiles @@ -404,6 +406,6 @@ jobs: timeout-minutes: 50 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: FreeBSD uses: ./.github/actions/freebsd diff --git a/.github/workflows/real-time-benchmark.yml b/.github/workflows/real-time-benchmark.yml index 539e9768f4ac1..9276539841e72 100644 --- a/.github/workflows/real-time-benchmark.yml +++ b/.github/workflows/real-time-benchmark.yml @@ -118,21 +118,21 @@ jobs: sudo apt-get update -y sudo apt-get install -y terraform=1.5.7-* - name: Checkout benchmark suite - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: 'kocsismate/php-version-benchmarks' ref: 'main' fetch-depth: 1 path: 'php-version-benchmarks' - name: Checkout php-src (benchmarked version) - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: '${{ env.REPOSITORY }}' ref: '${{ env.COMMIT }}' fetch-depth: 100 path: 'php-version-benchmarks/tmp/php_${{ env.ID }}' - name: Checkout php-src (baseline version) - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: '${{ env.REPOSITORY }}' ref: '${{ env.BASELINE_COMMIT }}' @@ -146,7 +146,7 @@ jobs: rm -rf ./php-version-benchmarks/docs/results - name: Checkout benchmark data if: github.event_name != 'workflow_dispatch' - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: php/real-time-benchmark-data ssh-key: ${{ secrets.PHP_VERSION_BENCHMARK_RESULTS_DEPLOY_KEY }} @@ -290,7 +290,7 @@ jobs: git push - name: Upload artifact if: github.event_name == 'workflow_dispatch' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: results path: ./php-version-benchmarks/docs/results/${{ env.YEAR }} diff --git a/.github/workflows/root.yml b/.github/workflows/root.yml index 000f51f13cc16..123ccc17c611d 100644 --- a/.github/workflows/root.yml +++ b/.github/workflows/root.yml @@ -13,14 +13,14 @@ jobs: outputs: branches: ${{ steps.set-matrix.outputs.branches }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: # Set fetch-depth to 0 to clone the full repository # including all branches. This is required to find # the correct commit hashes. fetch-depth: 0 - name: Grab the commit mapping - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: branch-commit-cache.json # The cache key needs to change every time for the @@ -58,7 +58,7 @@ jobs: windows_version: '2022' vs_crt_version: ${{ ((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) && 'vs17') || 'vs16' }} skip_laravel: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} - skip_symfony: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} + symfony_version: ${{ (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9) && '8.1') || '7.4' }} skip_wordpress: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} variation_enable_zend_max_execution_timers: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 3) || matrix.branch.version[0] >= 9 }} secrets: inherit diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index dc52a152f7abd..6338a1cb945db 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -35,7 +35,7 @@ jobs: timeout-minutes: 20 steps: - name: git checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install dependencies run: | diff --git a/.github/workflows/verify-bundled-files.yml b/.github/workflows/verify-bundled-files.yml new file mode 100644 index 0000000000000..6cce1a14cf7f3 --- /dev/null +++ b/.github/workflows/verify-bundled-files.yml @@ -0,0 +1,43 @@ +name: Verify Bundled Files + +on: + push: + paths: &paths + - '.github/scripts/download-bundled/pcre2.sh' + - 'ext/pcre/pcre2lib/**' + pull_request: + paths: *paths + schedule: + - cron: "0 1 * * *" + workflow_dispatch: ~ + +permissions: + contents: read + +jobs: + VERIFY_BUNDLED_FILES: + name: Verify Bundled Files + runs-on: ubuntu-24.04 + steps: + - name: git checkout + uses: actions/checkout@v6 + + - name: Detect changed files + uses: dorny/paths-filter@v3 + id: changes + with: + base: master + filters: | + pcre2: + - '.github/scripts/download-bundled/pcre2.sh' + - 'ext/pcre/pcre2lib/**' + + - name: PCRE2 + if: ${{ !cancelled() && (steps.changes.outputs.pcre2 == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') }} + run: | + echo "::group::Download" + .github/scripts/download-bundled/pcre2.sh + echo "::endgroup::" + echo "::group::Verify files" + .github/scripts/test-directory-unchanged.sh ext/pcre/pcre2lib + echo "::endgroup::" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index caaca316575e7..32e8098c08e48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,6 +100,7 @@ scattered across different websites, and often outdated. Nonetheless, they can provide a good starting point for learning about the fundamentals of the code base. +* https://php.github.io/php-src/ * https://www.phpinternalsbook.com/ * https://www.npopov.com/ * [Internal value representation](https://www.npopov.com/2015/05/05/Internal-value-representation-in-PHP-7-part-1.html), [part 2](https://www.npopov.com/2015/06/19/Internal-value-representation-in-PHP-7-part-2.html) diff --git a/LICENSE b/LICENSE index 0815d7eb79119..b155a18c2fb73 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ -------------------------------------------------------------------- The PHP License, version 3.01 -Copyright (c) 1999 - 2024 The PHP Group. All rights reserved. +Copyright (c) 1999 - 2025 The PHP Group. All rights reserved. -------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without diff --git a/NEWS b/NEWS index 938aa1f72edb6..12740c65c3c89 100644 --- a/NEWS +++ b/NEWS @@ -6,7 +6,8 @@ PHP NEWS . Added first-class callable cache to share instances for the duration of the request. (ilutov) . It is now possible to use reference assign on WeakMap without the key - needing to be present beforehand. (nielsdos) + needing to be present beforehand. (ndossche) + . Added `clamp()`. (kylekatarnls, thinkverse) - Hash: . Upgrade xxHash to 0.8.2. (timwolla) @@ -15,20 +16,58 @@ PHP NEWS . Added IntlNumberRangeFormatter class to format an interval of two numbers with a given skeleton, locale, collapse type and identity fallback. (BogdanUngureanu) + . Fixed bug GH-20426 (Spoofchecker::setRestrictionLevel() error message + suggests missing constants). (DanielEScherzer) + +- Mbstring + . Fixed bug GH-20674 (Fix GH-20674 mb_decode_mimeheader does not handle + separator). (Yuya Hamada) + +- Fibers: + . Fixed bug GH-20483 (ASAN stack overflow with fiber.stack_size INI + small value). (David Carlier) + +- Mbstring: + . ini_set() with mbstring.detect_order changes the order of mb_detect_order + as intended, since mbstring.detect_order is an INI_ALL setting. (tobee94) + . Added GB18030-2022 to default encoding list for zh-CN. (HeRaNO) + . Fixed bug GH-20674 (Fix GH-20674 mb_decode_mimeheader does not handle + separator). (Yuya Hamada) - Opcache: . Fixed bug GH-20051 (apache2 shutdowns when restart is requested during preloading). (Arnaud, welcomycozyhom) +- PDO_PGSQL: + . Clear session-local state disconnect-equivalent processing. + (KentarouTakeda) + - Phar: - . Support reference values in Phar::mungServer(). (nielsdos) + . Support reference values in Phar::mungServer(). (ndossche) . Invalid values now throw in Phar::mungServer() instead of being silently - ignored. (nielsdos) + ignored. (ndossche) + . Support overridden methods in SplFileInfo for getMTime() and getPathname() + when building a phar. (ndossche) - Reflection: . Fixed bug GH-20217 (ReflectionClass::isIterable() incorrectly returns true for classes with property hooks). (alexandre-daubois) +- Soap: + . Soap::__setCookie() when cookie name is a digit is now not stored and represented + as a string anymore but a int. (David Carlier) + +- Sockets: + . Added the TCP_USER_TIMEOUT constant for Linux to set the maximum time in milliseconds + transmitted data can remain unacknowledged. (James Lucas) + +- SPL: + . DirectoryIterator key can now work better with filesystem supporting larger + directory indexing. (David Carlier) + +- Sqlite3: + . Fix NUL byte truncation in sqlite3 TEXT column handling. (ndossche) + - Standard: . Fixed bug GH-19926 (reset internal pointer earlier while splicing array while COW violation flag is still set). (alexandre-daubois) @@ -36,6 +75,8 @@ PHP NEWS - Streams: . Added so_reuseaddr streams context socket option that allows disabling address resuse. + . Fixed bug GH-20370 (User stream filters could violate typed property + constraints). (alexandre-daubois) - Zip: . Fixed ZipArchive callback being called after executor has shut down. diff --git a/UPGRADING b/UPGRADING index 3b0301522d460..d52827bf96154 100644 --- a/UPGRADING +++ b/UPGRADING @@ -37,6 +37,11 @@ PHP 8.6 UPGRADE NOTES IntlNumberRangeFormatter::IDENTITY_FALLBACK_RANGE identity fallbacks. It is supported from icu 63. +- Phar: + . Overriding the getMTime() and getPathname() methods of SplFileInfo now + influences the result of the phar buildFrom family of functions. + This makes it possible to override the timestamp and names of files. + - Streams: . Added stream socket context option so_reuseaddr that allows disabling address reuse (SO_REUSEADDR) and explicitly uses SO_EXCLUSIVEADDRUSE on @@ -66,6 +71,10 @@ PHP 8.6 UPGRADE NOTES 6. New Functions ======================================== +- Standard: + . `clamp()` returns the given value if in range, else return the nearest bound. + RFC: https://wiki.php.net/rfc/clamp_v2 + ======================================== 7. New Classes and Interfaces ======================================== @@ -85,6 +94,9 @@ PHP 8.6 UPGRADE NOTES 10. New Global Constants ======================================== +- Sockets: + . TCP_USER_TIMEOUT (Linux only). + ======================================== 11. Changes to INI File Handling ======================================== @@ -98,6 +110,13 @@ PHP 8.6 UPGRADE NOTES When used along with ZEND_JIT_DEBUG_TRACE_EXIT_INFO, the source of exit points is printed in exit info output, in debug builds. +- Mbstring: + . The mbstring.detect_order INI directive now updates the internal detection + order when changed at runtime via ini_set(). Previously, runtime changes + using ini_set() did not take effect for mb_detect_order(). Setting the + directive to NULL or an empty string at runtime now leaves the previously + configured detection order unchanged. + ======================================== 12. Windows Support ======================================== @@ -130,3 +149,6 @@ PHP 8.6 UPGRADE NOTES . Improved performance of array_walk(). . Improved performance of intval('+0b...', 2) and intval('0b...', 2). . Improved performance of str_split(). + +- Zip: + . Avoid string copies in ZipArchive::addFromString(). diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 88df8f6edb2f5..22b9e6f660cb1 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -45,6 +45,13 @@ PHP 8.6 INTERNALS UPGRADE NOTES __callStatic zend_function* instead of a CE and a boolean argument. . The zend_set_hash_symbol() API has been removed. . Added zend_hash_str_lookup(). + . The WRONG_PARAM_COUNT and ZEND_WRONG_PARAM_COUNT() macros have been + removed. Call zend_wrong_param_count(); followed by RETURN_THROWS(); + instead. + . PHP_HAVE_STREAMS macro removed from . + . zend_function.arg_info is now always a zend_arg_info*. Before, it was a + zend_internal_arg_info on internal functions, unless the + ZEND_ACC_USER_ARG_INFO flag was set. ======================== 2. Build system changes @@ -54,6 +61,21 @@ PHP 8.6 INTERNALS UPGRADE NOTES 3. Module changes ======================== +- ext/xml: + . Removed the XML_ExpatVersion() libxml compatibility wrapper, + as it was unused. + . Removed the XML_GetCurrentByteCount() libxml compatibility wrapper, + as it was unused and could return the wrong result. + +- ext/mbstring: + . Added GB18030-2022 to default encoding list for zh-CN. + +- ext/standard: + . _php_error_log() now has a formal return type of zend_result. + . _php_error_log() now accepts zend_string* values instead of char*. + . _php_error_log_ex() has been removed. + . php_mail()'s extra_cmd parameter is now a zend_string*. + ======================== 4. OpCode changes ======================== diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 1e1853167cfe3..33009e9909f5a 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -474,7 +474,7 @@ dnl expectations. dnl AC_DEFUN([ZEND_CHECK_PRESERVE_NONE], [dnl AC_CACHE_CHECK([for preserve_none calling convention], - [php_cv_preverve_none], + [php_cv_preserve_none], [AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include @@ -504,7 +504,11 @@ uintptr_t __attribute__((preserve_none)) test(void) { "movq %2, %%r13\n" "xorq %3, %%r13\n" "xorq %%rax, %%rax\n" +#if defined(__APPLE__) + "call _fun\n" +#else "call fun\n" +#endif : "=a" (ret) : "r" (const1), "r" (const2), "r" (key) : "r12", "r13" @@ -515,7 +519,11 @@ uintptr_t __attribute__((preserve_none)) test(void) { "eor x20, %1, %3\n" "eor x21, %2, %3\n" "eor x0, x0, x0\n" +#if defined(__APPLE__) + "bl _fun\n" +#else "bl fun\n" +#endif "mov %0, x0\n" : "=r" (ret) : "r" (const1), "r" (const2), "r" (key) diff --git a/Zend/tests/closures/gh19653_3.phpt b/Zend/tests/closures/gh19653_3.phpt new file mode 100644 index 0000000000000..7a9ac589182c3 --- /dev/null +++ b/Zend/tests/closures/gh19653_3.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-19653 (Closure named argument unpacking between temporary closures can cause a crash) - temporary method variation +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Unknown named parameter $tmpMethodParamName in %s:%d +Stack trace: +#0 %s(%d): usage1(Object(Closure)) +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/fibers/gh20483.phpt b/Zend/tests/fibers/gh20483.phpt new file mode 100644 index 0000000000000..e06cf87258ea1 --- /dev/null +++ b/Zend/tests/fibers/gh20483.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-20483 (ASAN stack overflow with small fiber.stack_size INI value) +--INI-- +fiber.stack_size=1024 +--FILE-- +start(); +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECTF-- +Fiber stack size is too small, it needs to be at least %d bytes diff --git a/Zend/tests/function_arguments/gh20435.phpt b/Zend/tests/function_arguments/gh20435.phpt new file mode 100644 index 0000000000000..e360b873d3ced --- /dev/null +++ b/Zend/tests/function_arguments/gh20435.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-20435 (SensitiveParameter doesn't work for named argument passing to variadic parameter) +--FILE-- + +--EXPECTF-- +#0 %s(%d): test(2, b: Object(SensitiveParameterValue), c: Object(SensitiveParameterValue)) diff --git a/Zend/tests/function_arguments/gh20435_2.phpt b/Zend/tests/function_arguments/gh20435_2.phpt new file mode 100644 index 0000000000000..a58c4d6be1ca5 --- /dev/null +++ b/Zend/tests/function_arguments/gh20435_2.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-20435: ZEND_CALL_HAS_EXTRA_NAMED_PARAMS & magic methods in debug_backtrace_get_args() +--FILE-- +__toString(), "\n\n"; + } + public function __call($name, $args) { + echo (new Exception())->__toString(), "\n\n"; + } + public function __invoke(...$args) { + echo (new Exception())->__toString(), "\n"; + } +} + +$c = new C(); +$c->foo(bar: 'bar'); +C::foo(bar: 'bar'); +$c(bar: 'bar'); + +?> +--EXPECTF-- +Exception in %s:%d +Stack trace: +#0 %s(%d): C->__call('foo', Array) +#1 {main} + +Exception in %s:%d +Stack trace: +#0 %s(%d): C::__callStatic('foo', Array) +#1 {main} + +Exception in %s:%d +Stack trace: +#0 %s(%d): C->__invoke(bar: 'bar') +#1 {main} diff --git a/Zend/tests/gh20714.phpt b/Zend/tests/gh20714.phpt new file mode 100644 index 0000000000000..10ffde555f896 --- /dev/null +++ b/Zend/tests/gh20714.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-20714: Uncatchable exception thrown in generator +--CREDITS-- +Grégoire Paris (greg0ire) +--FILE-- + +--EXPECT-- +Caught diff --git a/Zend/tests/oss-fuzz-465488618.phpt b/Zend/tests/oss-fuzz-465488618.phpt new file mode 100644 index 0000000000000..517c481b33e0a --- /dev/null +++ b/Zend/tests/oss-fuzz-465488618.phpt @@ -0,0 +1,16 @@ +--TEST-- +OSS-Fuzz #465488618: Dump function signature with dynamic class const lookup default argument +--FILE-- + +--EXPECTF-- +Fatal error: Declaration of B::test(string $x = ) must be compatible with A::test(int $x) in %s on line %d diff --git a/Zend/tests/unified_arg_infos_001.phpt b/Zend/tests/unified_arg_infos_001.phpt new file mode 100644 index 0000000000000..d6699aa8d8cb5 --- /dev/null +++ b/Zend/tests/unified_arg_infos_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +Declaring non persistent method with arg info +--EXTENSIONS-- +zend_test +--FILE-- +testTmpMethodWithArgInfo(null); + +echo new ReflectionFunction($o->testTmpMethodWithArgInfo(...)); + +?> +--EXPECT-- +Closure [ public method testTmpMethodWithArgInfo ] { + + - Parameters [2] { + Parameter #0 [ Foo|Bar|null $tmpMethodParamName = null ] + Parameter #1 [ string $tmpMethodParamWithStringDefaultValue = "tmpMethodParamWithStringDefaultValue" ] + } +} diff --git a/Zend/zend.c b/Zend/zend.c index 4d024444a4be9..c46c8e9ada86c 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -38,6 +38,8 @@ #include "zend_call_stack.h" #include "zend_max_execution_timer.h" #include "zend_hrtime.h" +#include "zend_enum.h" +#include "zend_closures.h" #include "Optimizer/zend_optimizer.h" #include "php.h" #include "php_globals.h" @@ -1054,6 +1056,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ ZVAL_UNDEF(&EG(last_fatal_error_backtrace)); zend_interned_strings_init(); + zend_object_handlers_startup(); zend_startup_builtin_functions(); zend_register_standard_constants(); zend_register_auto_global(zend_string_init_interned("GLOBALS", sizeof("GLOBALS") - 1, 1), 1, php_auto_globals_create_globals); @@ -1077,6 +1080,9 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ tsrm_set_new_thread_end_handler(zend_new_thread_end_handler); tsrm_set_shutdown_handler(zend_interned_strings_dtor); #endif + + zend_enum_startup(); + zend_closure_startup(); } /* }}} */ diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 4a08952677627..0881a169dfa7d 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -20,6 +20,7 @@ */ #include "zend.h" +#include "zend_compile.h" #include "zend_execute.h" #include "zend_API.h" #include "zend_hash.h" @@ -592,9 +593,6 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(const zval *arg, zend_long return 0; } } - if (UNEXPECTED(EG(exception))) { - return 0; - } } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) { if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("int", arg_num)) { return 0; @@ -641,9 +639,6 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(const zval *arg, double * return 0; } } - if (UNEXPECTED(EG(exception))) { - return 0; - } } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) { if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("float", arg_num)) { return 0; @@ -2933,6 +2928,80 @@ static zend_always_inline void zend_normalize_internal_type(zend_type *type) { } ZEND_TYPE_FOREACH_END(); } +static void zend_convert_internal_arg_info_type(zend_type *type, bool persistent) +{ + if (ZEND_TYPE_HAS_LITERAL_NAME(*type)) { + // gen_stubs.php does not support codegen for compound types. As a + // temporary workaround, we support union types by splitting + // the type name on `|` characters if necessary. + const char *class_name = ZEND_TYPE_LITERAL_NAME(*type); + type->type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT; + + size_t num_types = 1; + const char *p = class_name; + while ((p = strchr(p, '|'))) { + num_types++; + p++; + } + + if (num_types == 1) { + /* Simple class type */ + zend_string *str = zend_string_init_interned(class_name, strlen(class_name), persistent); + zend_alloc_ce_cache(str); + ZEND_TYPE_SET_PTR(*type, str); + type->type_mask |= _ZEND_TYPE_NAME_BIT; + } else { + /* Union type */ + zend_type_list *list = pemalloc(ZEND_TYPE_LIST_SIZE(num_types), persistent); + list->num_types = num_types; + ZEND_TYPE_SET_LIST(*type, list); + ZEND_TYPE_FULL_MASK(*type) |= _ZEND_TYPE_UNION_BIT; + + const char *start = class_name; + uint32_t j = 0; + while (true) { + const char *end = strchr(start, '|'); + zend_string *str = zend_string_init_interned(start, end ? end - start : strlen(start), persistent); + zend_alloc_ce_cache(str); + list->types[j] = (zend_type) ZEND_TYPE_INIT_CLASS(str, 0, 0); + if (!end) { + break; + } + start = end + 1; + j++; + } + } + } + if (ZEND_TYPE_IS_ITERABLE_FALLBACK(*type)) { + /* Warning generated an extension load warning which is emitted for every test + zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable," + " regenerate the argument info via the php-src gen_stub build script"); + */ + zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK( + ZSTR_KNOWN(ZEND_STR_TRAVERSABLE), + (type->type_mask | MAY_BE_ARRAY) + ); + *type = legacy_iterable; + } +} + +ZEND_API void zend_convert_internal_arg_info(zend_arg_info *new_arg_info, const zend_internal_arg_info *arg_info, bool is_return_info, bool persistent) +{ + if (!is_return_info) { + new_arg_info->name = zend_string_init_interned(arg_info->name, strlen(arg_info->name), persistent); + if (arg_info->default_value) { + new_arg_info->default_value = zend_string_init_interned(arg_info->default_value, strlen(arg_info->default_value), persistent); + } else { + new_arg_info->default_value = NULL; + } + } else { + new_arg_info->name = NULL; + new_arg_info->default_value = NULL; + } + new_arg_info->type = arg_info->type; + zend_convert_internal_arg_info_type(&new_arg_info->type, persistent); +} + /* registers all functions in *library_functions in the function hash */ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type) /* {{{ */ { @@ -2944,6 +3013,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend int error_type; zend_string *lowercase_name; size_t fname_len; + const zend_internal_arg_info *internal_arg_info; if (type==MODULE_PERSISTENT) { error_type = E_CORE_WARNING; @@ -3000,7 +3070,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend if (ptr->arg_info) { zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info; - internal_function->arg_info = (zend_internal_arg_info*)ptr->arg_info+1; + internal_arg_info = ptr->arg_info+1; internal_function->num_args = ptr->num_args; /* Currently you cannot denote that the function can accept less arguments than num_args */ if (info->required_num_args == (uintptr_t)-1) { @@ -3030,7 +3100,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend zend_error(E_CORE_WARNING, "Missing arginfo for %s%s%s()", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); - internal_function->arg_info = NULL; + internal_arg_info = NULL; internal_function->num_args = 0; internal_function->required_num_args = 0; } @@ -3041,13 +3111,11 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend !(internal_function->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { zend_error(E_CORE_WARNING, "%s::__toString() implemented without string return type", ZSTR_VAL(scope->name)); - internal_function->arg_info = (zend_internal_arg_info *) arg_info_toString + 1; + internal_arg_info = (zend_internal_arg_info *) arg_info_toString + 1; internal_function->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE; internal_function->num_args = internal_function->required_num_args = 0; } - - zend_set_function_arg_flags((zend_function*)internal_function); if (ptr->flags & ZEND_ACC_ABSTRACT) { if (scope) { /* This is a class that must be abstract itself. Here we set the check info. */ @@ -3112,17 +3180,17 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend } /* If types of arguments have to be checked */ - if (reg_function->arg_info && num_args) { + if (internal_arg_info && num_args) { uint32_t i; for (i = 0; i < num_args; i++) { - zend_internal_arg_info *arg_info = ®_function->arg_info[i]; + const zend_internal_arg_info *arg_info = &internal_arg_info[i]; ZEND_ASSERT(arg_info->name && "Parameter must have a name"); if (ZEND_TYPE_IS_SET(arg_info->type)) { reg_function->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; } #if ZEND_DEBUG for (uint32_t j = 0; j < i; j++) { - if (!strcmp(arg_info->name, reg_function->arg_info[j].name)) { + if (!strcmp(arg_info->name, internal_arg_info[j].name)) { zend_error_noreturn(E_CORE_ERROR, "Duplicate parameter name $%s for function %s%s%s()", arg_info->name, scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname); @@ -3132,78 +3200,24 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend } } - /* Rebuild arginfos if parameter/property types and/or a return type are used */ - if (reg_function->arg_info && - (reg_function->fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { - /* convert "const char*" class type names into "zend_string*" */ + /* Convert zend_internal_arg_info to zend_arg_info */ + if (internal_arg_info) { uint32_t i; - zend_internal_arg_info *arg_info = reg_function->arg_info - 1; - zend_internal_arg_info *new_arg_info; + const zend_internal_arg_info *arg_info = internal_arg_info - 1; + zend_arg_info *new_arg_info; /* Treat return type as an extra argument */ num_args++; - new_arg_info = malloc(sizeof(zend_internal_arg_info) * num_args); - memcpy(new_arg_info, arg_info, sizeof(zend_internal_arg_info) * num_args); + new_arg_info = malloc(sizeof(zend_arg_info) * num_args); reg_function->arg_info = new_arg_info + 1; for (i = 0; i < num_args; i++) { - if (ZEND_TYPE_HAS_LITERAL_NAME(new_arg_info[i].type)) { - // gen_stubs.php does not support codegen for DNF types in arg infos. - // As a temporary workaround, we split the type name on `|` characters, - // converting it to an union type if necessary. - const char *class_name = ZEND_TYPE_LITERAL_NAME(new_arg_info[i].type); - new_arg_info[i].type.type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT; - - size_t num_types = 1; - const char *p = class_name; - while ((p = strchr(p, '|'))) { - num_types++; - p++; - } - - if (num_types == 1) { - /* Simple class type */ - zend_string *str = zend_string_init_interned(class_name, strlen(class_name), 1); - zend_alloc_ce_cache(str); - ZEND_TYPE_SET_PTR(new_arg_info[i].type, str); - new_arg_info[i].type.type_mask |= _ZEND_TYPE_NAME_BIT; - } else { - /* Union type */ - zend_type_list *list = malloc(ZEND_TYPE_LIST_SIZE(num_types)); - list->num_types = num_types; - ZEND_TYPE_SET_LIST(new_arg_info[i].type, list); - ZEND_TYPE_FULL_MASK(new_arg_info[i].type) |= _ZEND_TYPE_UNION_BIT; - - const char *start = class_name; - uint32_t j = 0; - while (true) { - const char *end = strchr(start, '|'); - zend_string *str = zend_string_init_interned(start, end ? end - start : strlen(start), 1); - zend_alloc_ce_cache(str); - list->types[j] = (zend_type) ZEND_TYPE_INIT_CLASS(str, 0, 0); - if (!end) { - break; - } - start = end + 1; - j++; - } - } - } - if (ZEND_TYPE_IS_ITERABLE_FALLBACK(new_arg_info[i].type)) { - /* Warning generated an extension load warning which is emitted for every test - zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable," - " regenerate the argument info via the php-src gen_stub build script"); - */ - zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK( - ZSTR_KNOWN(ZEND_STR_TRAVERSABLE), - (new_arg_info[i].type.type_mask | MAY_BE_ARRAY) - ); - new_arg_info[i].type = legacy_iterable; - } - - zend_normalize_internal_type(&new_arg_info[i].type); + zend_convert_internal_arg_info(&new_arg_info[i], &arg_info[i], + i == 0, true); } } + zend_set_function_arg_flags((zend_function*)reg_function); + if (scope) { zend_check_magic_method_implementation( scope, (zend_function *)reg_function, lowercase_name, E_CORE_ERROR); @@ -4390,14 +4404,8 @@ ZEND_API void zend_get_callable_zval_from_fcc(const zend_fcall_info_cache *fcc, ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */ { - zend_string *lname; size_t name_len = strlen(module_name); - zend_module_entry *module; - - lname = zend_string_alloc(name_len, 0); - zend_str_tolower_copy(ZSTR_VAL(lname), module_name, name_len); - module = zend_hash_find_ptr(&module_registry, lname); - zend_string_efree(lname); + zend_module_entry *module = zend_hash_str_find_ptr_lc(&module_registry, module_name, name_len); return module ? module->version : NULL; } /* }}} */ @@ -5254,48 +5262,43 @@ static zend_string *try_parse_string(const char *str, size_t len, char quote) { } ZEND_API zend_result zend_get_default_from_internal_arg_info( - zval *default_value_zval, const zend_internal_arg_info *arg_info) + zval *default_value_zval, const zend_arg_info *arg_info) { - const char *default_value = arg_info->default_value; + const zend_string *default_value = arg_info->default_value; if (!default_value) { return FAILURE; } /* Avoid going through the full AST machinery for some simple and common cases. */ - size_t default_value_len = strlen(default_value); zend_ulong lval; - if (default_value_len == sizeof("null")-1 - && !memcmp(default_value, "null", sizeof("null")-1)) { + if (zend_string_equals_literal(default_value, "null")) { ZVAL_NULL(default_value_zval); return SUCCESS; - } else if (default_value_len == sizeof("true")-1 - && !memcmp(default_value, "true", sizeof("true")-1)) { + } else if (zend_string_equals_literal(default_value, "true")) { ZVAL_TRUE(default_value_zval); return SUCCESS; - } else if (default_value_len == sizeof("false")-1 - && !memcmp(default_value, "false", sizeof("false")-1)) { + } else if (zend_string_equals_literal(default_value, "false")) { ZVAL_FALSE(default_value_zval); return SUCCESS; - } else if (default_value_len >= 2 - && (default_value[0] == '\'' || default_value[0] == '"') - && default_value[default_value_len - 1] == default_value[0]) { + } else if (ZSTR_LEN(default_value) >= 2 + && (ZSTR_VAL(default_value)[0] == '\'' || ZSTR_VAL(default_value)[0] == '"') + && ZSTR_VAL(default_value)[ZSTR_LEN(default_value) - 1] == ZSTR_VAL(default_value)[0]) { zend_string *str = try_parse_string( - default_value + 1, default_value_len - 2, default_value[0]); + ZSTR_VAL(default_value) + 1, ZSTR_LEN(default_value) - 2, ZSTR_VAL(default_value)[0]); if (str) { ZVAL_STR(default_value_zval, str); return SUCCESS; } - } else if (default_value_len == sizeof("[]")-1 - && !memcmp(default_value, "[]", sizeof("[]")-1)) { + } else if (zend_string_equals_literal(default_value, "[]")) { ZVAL_EMPTY_ARRAY(default_value_zval); return SUCCESS; - } else if (ZEND_HANDLE_NUMERIC_STR(default_value, default_value_len, lval)) { + } else if (ZEND_HANDLE_NUMERIC(default_value, lval)) { ZVAL_LONG(default_value_zval, lval); return SUCCESS; } #if 0 - fprintf(stderr, "Evaluating %s via AST\n", default_value); + fprintf(stderr, "Evaluating %s via AST\n", ZSTR_VAL(default_value)); #endif - return get_default_via_ast(default_value_zval, default_value); + return get_default_via_ast(default_value_zval, ZSTR_VAL(default_value)); } diff --git a/Zend/zend_API.h b/Zend/zend_API.h index e6d5a024cf61b..c1ccbf13666a5 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -523,9 +523,7 @@ ZEND_API const char *zend_get_type_by_const(int type); #define getThis() (hasThis() ? ZEND_THIS : NULL) #define ZEND_IS_METHOD_CALL() (EX(func)->common.scope != NULL) -#define WRONG_PARAM_COUNT ZEND_WRONG_PARAM_COUNT() #define ZEND_NUM_ARGS() EX_NUM_ARGS() -#define ZEND_WRONG_PARAM_COUNT() { zend_wrong_param_count(); return; } #ifndef ZEND_WIN32 #define DLEXPORT @@ -924,8 +922,12 @@ ZEND_API bool zend_is_iterable(const zval *iterable); ZEND_API bool zend_is_countable(const zval *countable); +ZEND_API void zend_convert_internal_arg_info(zend_arg_info *new_arg_info, + const zend_internal_arg_info *arg_info, bool is_return_info, + bool permanent); + ZEND_API zend_result zend_get_default_from_internal_arg_info( - zval *default_value_zval, const zend_internal_arg_info *arg_info); + zval *default_value_zval, const zend_arg_info *arg_info); END_EXTERN_C() diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 9774cce39db2b..30bd4a9c05dd0 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1124,12 +1124,12 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( if (!(fptr->common.fn_flags & ZEND_ACC_STATIC)) { zend_non_static_method_call(fptr); - + return FAILURE; } if ((fptr->common.fn_flags & ZEND_ACC_ABSTRACT)) { zend_abstract_method_call(fptr); - + return FAILURE; } else if (fptr->common.scope->ce_flags & ZEND_ACC_TRAIT) { zend_error(E_DEPRECATED, diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c index b69e192701e48..cba95810ba496 100644 --- a/Zend/zend_attributes.c +++ b/Zend/zend_attributes.c @@ -38,7 +38,7 @@ static zend_object_handlers attributes_object_handlers_sensitive_parameter_value static HashTable internal_attributes; -uint32_t zend_attribute_attribute_get_flags(zend_attribute *attr, zend_class_entry *scope) +uint32_t zend_attribute_attribute_get_flags(const zend_attribute *attr, zend_class_entry *scope) { // TODO: More proper signature validation: Too many args, incorrect arg names. if (attr->argc > 0) { @@ -265,7 +265,7 @@ ZEND_METHOD(NoDiscard, __construct) } } -static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset) +static zend_attribute *get_attribute(const HashTable *attributes, const zend_string *lcname, uint32_t offset) { if (attributes) { zend_attribute *attr; @@ -280,7 +280,7 @@ static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, return NULL; } -static zend_attribute *get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset) +static zend_attribute *get_attribute_str(const HashTable *attributes, const char *str, size_t len, uint32_t offset) { if (attributes) { zend_attribute *attr; @@ -295,27 +295,27 @@ static zend_attribute *get_attribute_str(HashTable *attributes, const char *str, return NULL; } -ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname) +ZEND_API zend_attribute *zend_get_attribute(const HashTable *attributes, const zend_string *lcname) { return get_attribute(attributes, lcname, 0); } -ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len) +ZEND_API zend_attribute *zend_get_attribute_str(const HashTable *attributes, const char *str, size_t len) { return get_attribute_str(attributes, str, len, 0); } -ZEND_API zend_attribute *zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset) +ZEND_API zend_attribute *zend_get_parameter_attribute(const HashTable *attributes, const zend_string *lcname, uint32_t offset) { return get_attribute(attributes, lcname, offset + 1); } -ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset) +ZEND_API zend_attribute *zend_get_parameter_attribute_str(const HashTable *attributes, const char *str, size_t len, uint32_t offset) { return get_attribute_str(attributes, str, len, offset + 1); } -ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, uint32_t i, zend_class_entry *scope) +ZEND_API zend_result zend_get_attribute_value(zval *ret, const zend_attribute *attr, uint32_t i, zend_class_entry *scope) { if (i >= attr->argc) { return FAILURE; @@ -447,7 +447,7 @@ ZEND_API zend_string *zend_get_attribute_target_names(uint32_t flags) return smart_str_extract(&str); } -ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr) +ZEND_API bool zend_is_attribute_repeated(const HashTable *attributes, const zend_attribute *attr) { zend_attribute *other; diff --git a/Zend/zend_attributes.h b/Zend/zend_attributes.h index 10227c2d1e8ef..f8b61ac9d1666 100644 --- a/Zend/zend_attributes.h +++ b/Zend/zend_attributes.h @@ -77,17 +77,17 @@ typedef struct _zend_internal_attribute { zend_string* (*validator)(zend_attribute *attr, uint32_t target, zend_class_entry *scope); } zend_internal_attribute; -ZEND_API zend_attribute *zend_get_attribute(HashTable *attributes, zend_string *lcname); -ZEND_API zend_attribute *zend_get_attribute_str(HashTable *attributes, const char *str, size_t len); +ZEND_API zend_attribute *zend_get_attribute(const HashTable *attributes, const zend_string *lcname); +ZEND_API zend_attribute *zend_get_attribute_str(const HashTable *attributes, const char *str, size_t len); -ZEND_API zend_attribute *zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset); -ZEND_API zend_attribute *zend_get_parameter_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset); +ZEND_API zend_attribute *zend_get_parameter_attribute(const HashTable *attributes, const zend_string *lcname, uint32_t offset); +ZEND_API zend_attribute *zend_get_parameter_attribute_str(const HashTable *attributes, const char *str, size_t len, uint32_t offset); -ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, uint32_t i, zend_class_entry *scope); +ZEND_API zend_result zend_get_attribute_value(zval *ret, const zend_attribute *attr, uint32_t i, zend_class_entry *scope); ZEND_API zend_result zend_get_attribute_object(zval *out, zend_class_entry *attribute_ce, zend_attribute *attribute_data, zend_class_entry *scope, zend_string *filename); ZEND_API zend_string *zend_get_attribute_target_names(uint32_t targets); -ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr); +ZEND_API bool zend_is_attribute_repeated(const HashTable *attributes, const zend_attribute *attr); ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce); ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags); @@ -97,7 +97,7 @@ ZEND_API zend_attribute *zend_add_attribute( HashTable **attributes, zend_string *name, uint32_t argc, uint32_t flags, uint32_t offset, uint32_t lineno); -uint32_t zend_attribute_attribute_get_flags(zend_attribute *attr, zend_class_entry *scope); +uint32_t zend_attribute_attribute_get_flags(const zend_attribute *attr, zend_class_entry *scope); END_EXTERN_C() @@ -119,13 +119,13 @@ static zend_always_inline zend_attribute *zend_add_parameter_attribute(zend_func return zend_add_attribute(&func->common.attributes, name, argc, flags, offset + 1, 0); } -static zend_always_inline zend_attribute *zend_add_property_attribute(zend_class_entry *ce, zend_property_info *info, zend_string *name, uint32_t argc) +static zend_always_inline zend_attribute *zend_add_property_attribute(const zend_class_entry *ce, zend_property_info *info, zend_string *name, uint32_t argc) { uint32_t flags = ce->type != ZEND_USER_CLASS ? ZEND_ATTRIBUTE_PERSISTENT : 0; return zend_add_attribute(&info->attributes, name, argc, flags, 0, 0); } -static zend_always_inline zend_attribute *zend_add_class_constant_attribute(zend_class_entry *ce, zend_class_constant *c, zend_string *name, uint32_t argc) +static zend_always_inline zend_attribute *zend_add_class_constant_attribute(const zend_class_entry *ce, zend_class_constant *c, zend_string *name, uint32_t argc) { uint32_t flags = ce->type != ZEND_USER_CLASS ? ZEND_ATTRIBUTE_PERSISTENT : 0; return zend_add_attribute(&c->attributes, name, argc, flags, 0, 0); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index ca1a84631b250..a4ece3061d5d0 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1715,6 +1715,18 @@ ZEND_FUNCTION(get_defined_constants) } /* }}} */ +static bool backtrace_is_arg_sensitive(const zend_execute_data *call, uint32_t offset) +{ + zend_attribute *attribute = zend_get_parameter_attribute_str( + call->func->common.attributes, + "sensitiveparameter", + sizeof("sensitiveparameter") - 1, + offset + ); + + return attribute != NULL; +} + static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */ { uint32_t num_args = ZEND_CALL_NUM_ARGS(call); @@ -1738,14 +1750,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / zend_string *arg_name = call->func->op_array.vars[i]; zval original_arg; zval *arg = zend_hash_find_ex_ind(call->symbol_table, arg_name, 1); - zend_attribute *attribute = zend_get_parameter_attribute_str( - call->func->common.attributes, - "sensitiveparameter", - sizeof("sensitiveparameter") - 1, - i - ); - - bool is_sensitive = attribute != NULL; + bool is_sensitive = backtrace_is_arg_sensitive(call, i); if (arg) { ZVAL_DEREF(arg); @@ -1756,8 +1761,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / if (is_sensitive) { zval redacted_arg; - object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value); - zend_call_known_function(Z_OBJCE_P(&redacted_arg)->constructor, Z_OBJ_P(&redacted_arg), Z_OBJCE_P(&redacted_arg), NULL, 1, &original_arg, NULL); + object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, &original_arg, NULL); ZEND_HASH_FILL_SET(&redacted_arg); } else { Z_TRY_ADDREF_P(&original_arg); @@ -1770,13 +1774,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / } else { while (i < first_extra_arg) { zval original_arg; - zend_attribute *attribute = zend_get_parameter_attribute_str( - call->func->common.attributes, - "sensitiveparameter", - sizeof("sensitiveparameter") - 1, - i - ); - bool is_sensitive = attribute != NULL; + bool is_sensitive = backtrace_is_arg_sensitive(call, i); if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) { zval *arg = p; @@ -1788,8 +1786,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / if (is_sensitive) { zval redacted_arg; - object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value); - zend_call_known_function(Z_OBJCE_P(&redacted_arg)->constructor, Z_OBJ_P(&redacted_arg), Z_OBJCE_P(&redacted_arg), NULL, 1, &original_arg, NULL); + object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, &original_arg, NULL); ZEND_HASH_FILL_SET(&redacted_arg); } else { Z_TRY_ADDREF_P(&original_arg); @@ -1809,13 +1806,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / bool is_sensitive = 0; if (i < call->func->common.num_args || call->func->common.fn_flags & ZEND_ACC_VARIADIC) { - zend_attribute *attribute = zend_get_parameter_attribute_str( - call->func->common.attributes, - "sensitiveparameter", - sizeof("sensitiveparameter") - 1, - MIN(i, call->func->common.num_args) - ); - is_sensitive = attribute != NULL; + is_sensitive = backtrace_is_arg_sensitive(call, MIN(i, call->func->common.num_args)); } if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) { @@ -1828,8 +1819,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / if (is_sensitive) { zval redacted_arg; - object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value); - zend_call_known_function(Z_OBJCE_P(&redacted_arg)->constructor, Z_OBJ_P(&redacted_arg), Z_OBJCE_P(&redacted_arg), NULL, 1, &original_arg, NULL); + object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, &original_arg, NULL); ZEND_HASH_FILL_SET(&redacted_arg); } else { Z_TRY_ADDREF_P(&original_arg); @@ -1846,14 +1836,27 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / ZVAL_EMPTY_ARRAY(arg_array); } - if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + if ((ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) + /* __call and __callStatic are non-variadic, potentially with + * HAS_EXTRA_NAMED_PARAMS set. Don't add extra args, as they're already + * contained in the 2nd param. */ + && (call->func->common.fn_flags & ZEND_ACC_VARIADIC)) { zend_string *name; zval *arg; + + bool is_sensitive = backtrace_is_arg_sensitive(call, call->func->common.num_args); + SEPARATE_ARRAY(arg_array); ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) { ZVAL_DEREF(arg); - Z_TRY_ADDREF_P(arg); - zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg); + if (is_sensitive) { + zval redacted_arg; + object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, arg, NULL); + zend_hash_add_new(Z_ARRVAL_P(arg_array), name, &redacted_arg); + } else { + Z_TRY_ADDREF_P(arg); + zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg); + } } ZEND_HASH_FOREACH_END(); } } diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 4ecb6b2c493b9..05b6862044816 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -510,7 +510,7 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object) /* { * ZEND_ACC_USER_ARG_INFO flag to prevent invalid usage by Reflection */ invoke->type = ZEND_INTERNAL_FUNCTION; invoke->internal_function.fn_flags = - ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & keep_flags); + ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | ZEND_ACC_NEVER_CACHE | (closure->func.common.fn_flags & keep_flags); if (closure->func.type != ZEND_INTERNAL_FUNCTION || (closure->func.common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { invoke->internal_function.fn_flags |= ZEND_ACC_USER_ARG_INFO; @@ -618,7 +618,6 @@ static HashTable *zend_closure_get_debug_info(zend_object *object, int *is_temp) zval val; struct _zend_arg_info *arg_info = closure->func.common.arg_info; HashTable *debug_info; - bool zstr_args = (closure->func.type == ZEND_USER_FUNCTION) || (closure->func.common.fn_flags & ZEND_ACC_USER_ARG_INFO); *is_temp = 1; @@ -694,15 +693,9 @@ static HashTable *zend_closure_get_debug_info(zend_object *object, int *is_temp) zend_string *name; zval info; ZEND_ASSERT(arg_info->name && "Argument should have name"); - if (zstr_args) { - name = zend_strpprintf(0, "%s$%s", - ZEND_ARG_SEND_MODE(arg_info) ? "&" : "", - ZSTR_VAL(arg_info->name)); - } else { - name = zend_strpprintf(0, "%s$%s", - ZEND_ARG_SEND_MODE(arg_info) ? "&" : "", - ((zend_internal_arg_info*)arg_info)->name); - } + name = zend_strpprintf(0, "%s$%s", + ZEND_ARG_SEND_MODE(arg_info) ? "&" : "", + ZSTR_VAL(arg_info->name)); ZVAL_NEW_STR(&info, zend_strpprintf(0, "%s", i >= required ? "" : "")); zend_hash_update(Z_ARRVAL(val), name, &info); zend_string_release_ex(name, 0); @@ -885,8 +878,7 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas } /* }}} */ -/* __call and __callStatic name the arguments "$arguments" in the docs. */ -static zend_internal_arg_info trampoline_arg_info[] = {ZEND_ARG_VARIADIC_TYPE_INFO(false, arguments, IS_MIXED, false)}; +static zend_arg_info trampoline_arg_info[1]; void zend_closure_from_frame(zval *return_value, const zend_execute_data *call) { /* {{{ */ zval instance; @@ -951,3 +943,11 @@ void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val) /* { ZVAL_COPY_VALUE(var, val); } /* }}} */ + +void zend_closure_startup(void) +{ + /* __call and __callStatic name the arguments "$arguments" in the docs. */ + trampoline_arg_info[0].name = zend_string_init_interned("arguments", strlen("arguments"), true); + trampoline_arg_info[0].type = (zend_type)ZEND_TYPE_INIT_CODE(IS_MIXED, false, _ZEND_ARG_INFO_FLAGS(false, 1, 0)); + trampoline_arg_info[0].default_value = NULL; +} diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h index 8bea4ffb051e8..a118044c6e248 100644 --- a/Zend/zend_closures.h +++ b/Zend/zend_closures.h @@ -28,6 +28,7 @@ BEGIN_EXTERN_C() #define ZEND_CLOSURE_OBJECT(op_array) \ ((zend_object*)((char*)(op_array) - sizeof(zend_object))) +void zend_closure_startup(void); void zend_register_closure_ce(void); void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var); void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 50ba8029873ad..5eba2ec1366fa 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3688,21 +3688,10 @@ static void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */ static uint32_t zend_get_arg_num(const zend_function *fn, const zend_string *arg_name) { // TODO: Caching? - if (fn->type == ZEND_USER_FUNCTION) { - for (uint32_t i = 0; i < fn->common.num_args; i++) { - const zend_arg_info *arg_info = &fn->op_array.arg_info[i]; - if (zend_string_equals(arg_info->name, arg_name)) { - return i + 1; - } - } - } else { - ZEND_ASSERT(fn->common.num_args == 0 || fn->internal_function.arg_info); - for (uint32_t i = 0; i < fn->common.num_args; i++) { - const zend_internal_arg_info *arg_info = &fn->internal_function.arg_info[i]; - size_t len = strlen(arg_info->name); - if (zend_string_equals_cstr(arg_name, arg_info->name, len)) { - return i + 1; - } + for (uint32_t i = 0; i < fn->common.num_args; i++) { + zend_arg_info *arg_info = &fn->op_array.arg_info[i]; + if (zend_string_equals(arg_info->name, arg_name)) { + return i + 1; } } @@ -4702,7 +4691,7 @@ static uint32_t zend_compile_frameless_icall_ex(znode *result, const zend_ast_li if (i < args->children) { zend_compile_expr(&arg_zvs[i], args->child[i]); } else { - const zend_internal_arg_info *arg_info = (const zend_internal_arg_info *)&fbc->common.arg_info[i]; + const zend_arg_info *arg_info = &fbc->common.arg_info[i]; arg_zvs[i].op_type = IS_CONST; if (zend_get_default_from_internal_arg_info(&arg_zvs[i].u.constant, arg_info) == FAILURE) { ZEND_UNREACHABLE(); @@ -7934,6 +7923,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 arg_info = &arg_infos[i]; arg_info->name = zend_string_copy(name); arg_info->type = (zend_type) ZEND_TYPE_INIT_NONE(0); + arg_info->default_value = NULL; if (attributes_ast) { zend_compile_attributes( diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 86fab4b57ded6..d2a3b47bf92f4 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -592,7 +592,7 @@ typedef struct _zend_internal_function { zend_function *prototype; uint32_t num_args; uint32_t required_num_args; - zend_internal_arg_info *arg_info; + zend_arg_info *arg_info; HashTable *attributes; ZEND_MAP_PTR_DEF(void **, run_time_cache); zend_string *doc_comment; @@ -976,7 +976,8 @@ ZEND_API ZEND_COLD void zend_user_exception_handler(void); } \ } while (0) -void zend_free_internal_arg_info(zend_internal_function *function); +ZEND_API void zend_free_internal_arg_info(zend_internal_function *function, + bool permanent); ZEND_API void destroy_zend_function(zend_function *function); ZEND_API void zend_function_dtor(zval *zv); ZEND_API void destroy_zend_class(zval *zv); diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c index ae9e7b701213f..00fbab22a056e 100644 --- a/Zend/zend_enum.c +++ b/Zend/zend_enum.c @@ -36,6 +36,10 @@ ZEND_API zend_class_entry *zend_ce_unit_enum; ZEND_API zend_class_entry *zend_ce_backed_enum; ZEND_API zend_object_handlers zend_enum_object_handlers; +static zend_arg_info zarginfo_class_UnitEnum_cases[sizeof(arginfo_class_UnitEnum_cases)/sizeof(zend_internal_arg_info)]; +static zend_arg_info zarginfo_class_BackedEnum_from[sizeof(arginfo_class_BackedEnum_from)/sizeof(zend_internal_arg_info)]; +static zend_arg_info zarginfo_class_BackedEnum_tryFrom[sizeof(arginfo_class_BackedEnum_tryFrom)/sizeof(zend_internal_arg_info)]; + zend_object *zend_enum_new(zval *result, zend_class_entry *ce, zend_string *case_name, zval *backing_value_zv) { zend_object *zobj = zend_objects_new(ce); @@ -446,7 +450,7 @@ void zend_enum_register_funcs(zend_class_entry *ce) cases_function->function_name = ZSTR_KNOWN(ZEND_STR_CASES); cases_function->fn_flags = fn_flags; cases_function->doc_comment = NULL; - cases_function->arg_info = (zend_internal_arg_info *) (arginfo_class_UnitEnum_cases + 1); + cases_function->arg_info = zarginfo_class_UnitEnum_cases + 1; zend_enum_register_func(ce, ZEND_STR_CASES, cases_function); if (ce->enum_backing_type != IS_UNDEF) { @@ -457,7 +461,7 @@ void zend_enum_register_funcs(zend_class_entry *ce) from_function->doc_comment = NULL; from_function->num_args = 1; from_function->required_num_args = 1; - from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_from + 1); + from_function->arg_info = zarginfo_class_BackedEnum_from + 1; zend_enum_register_func(ce, ZEND_STR_FROM, from_function); zend_internal_function *try_from_function = zend_arena_calloc(&CG(arena), sizeof(zend_internal_function), 1); @@ -467,7 +471,7 @@ void zend_enum_register_funcs(zend_class_entry *ce) try_from_function->doc_comment = NULL; try_from_function->num_args = 1; try_from_function->required_num_args = 1; - try_from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_tryFrom + 1); + try_from_function->arg_info = zarginfo_class_BackedEnum_tryFrom + 1; zend_enum_register_func(ce, ZEND_STR_TRYFROM_LOWERCASE, try_from_function); } } @@ -633,3 +637,16 @@ ZEND_API zend_object *zend_enum_get_case_cstr(zend_class_entry *ce, const char * zend_class_constant *c = zend_hash_str_find_ptr(CE_CONSTANTS_TABLE(ce), name, strlen(name)); return zend_enum_case_from_class_constant(c); } + +void zend_enum_startup(void) +{ + for (size_t i = 0; i < sizeof(zarginfo_class_UnitEnum_cases)/sizeof(zend_arg_info); i++) { + zend_convert_internal_arg_info(&zarginfo_class_UnitEnum_cases[i], &arginfo_class_UnitEnum_cases[i], i == 0, true); + } + for (size_t i = 0; i < sizeof(zarginfo_class_BackedEnum_from)/sizeof(zend_arg_info); i++) { + zend_convert_internal_arg_info(&zarginfo_class_BackedEnum_from[i], &arginfo_class_BackedEnum_from[i], i == 0, true); + } + for (size_t i = 0; i < sizeof(zarginfo_class_BackedEnum_tryFrom)/sizeof(zend_arg_info); i++) { + zend_convert_internal_arg_info(&zarginfo_class_BackedEnum_tryFrom[i], &arginfo_class_BackedEnum_tryFrom[i], i == 0, true); + } +} diff --git a/Zend/zend_enum.h b/Zend/zend_enum.h index 7b3b0184b4eb5..d6c820189475a 100644 --- a/Zend/zend_enum.h +++ b/Zend/zend_enum.h @@ -30,6 +30,7 @@ extern ZEND_API zend_class_entry *zend_ce_unit_enum; extern ZEND_API zend_class_entry *zend_ce_backed_enum; extern ZEND_API zend_object_handlers zend_enum_object_handlers; +void zend_enum_startup(void); void zend_register_enum_ce(void); void zend_enum_add_interfaces(zend_class_entry *ce); zend_result zend_enum_build_backed_enum_table(zend_class_entry *ce); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index d411dcbc3b953..518cbb98fc0f8 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -136,8 +136,7 @@ static ZEND_FUNCTION(pass) { } -ZEND_BEGIN_ARG_INFO_EX(zend_pass_function_arg_info, 0, 0, 0) -ZEND_END_ARG_INFO() +static zend_arg_info zend_pass_function_arg_info[1] = {0}; ZEND_API const zend_internal_function zend_pass_function = { ZEND_INTERNAL_FUNCTION, /* type */ @@ -148,7 +147,7 @@ ZEND_API const zend_internal_function zend_pass_function = { NULL, /* prototype */ 0, /* num_args */ 0, /* required_num_args */ - (zend_internal_arg_info *) zend_pass_function_arg_info + 1, /* arg_info */ + zend_pass_function_arg_info + 1, /* arg_info */ NULL, /* attributes */ NULL, /* run_time_cache */ NULL, /* doc_comment */ @@ -1480,7 +1479,7 @@ static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, con ZEND_API bool zend_verify_internal_return_type(const zend_function *zf, zval *ret) { - const zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1; + const zend_arg_info *ret_info = zf->internal_function.arg_info - 1; if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) { if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) { @@ -5474,28 +5473,17 @@ static zend_always_inline uint32_t zend_get_arg_offset_by_name( // TODO: Use a hash table? uint32_t num_args = fbc->common.num_args; - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) - || EXPECTED(fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { - for (uint32_t i = 0; i < num_args; i++) { - const zend_arg_info *arg_info = &fbc->common.arg_info[i]; - if (zend_string_equals(arg_name, arg_info->name)) { - if (fbc->type == ZEND_USER_FUNCTION && (!fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE))) { - *cache_slot = unique_id; - *(uintptr_t *)(cache_slot + 1) = i; - } - return i; - } - } - } else { - ZEND_ASSERT(num_args == 0 || fbc->internal_function.arg_info); - for (uint32_t i = 0; i < num_args; i++) { - const zend_internal_arg_info *arg_info = &fbc->internal_function.arg_info[i]; - size_t len = strlen(arg_info->name); - if (zend_string_equals_cstr(arg_name, arg_info->name, len)) { + for (uint32_t i = 0; i < num_args; i++) { + const zend_arg_info *arg_info = &fbc->common.arg_info[i]; + if (zend_string_equals(arg_name, arg_info->name)) { + if ((fbc->type == ZEND_USER_FUNCTION + && (!fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE))) + || (fbc->type == ZEND_INTERNAL_FUNCTION + && !(fbc->common.fn_flags & ZEND_ACC_NEVER_CACHE))) { *cache_slot = unique_id; *(uintptr_t *)(cache_slot + 1) = i; - return i; } + return i; } } @@ -5503,7 +5491,7 @@ static zend_always_inline uint32_t zend_get_arg_offset_by_name( if ((fbc->type == ZEND_USER_FUNCTION && (!fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE))) || (fbc->type == ZEND_INTERNAL_FUNCTION - && !(fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO))) { + && !(fbc->common.fn_flags & ZEND_ACC_NEVER_CACHE))) { *cache_slot = unique_id; *(uintptr_t *)(cache_slot + 1) = fbc->common.num_args; } @@ -5661,7 +5649,7 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal continue; } - zend_internal_arg_info *arg_info = &fbc->internal_function.arg_info[i]; + zend_arg_info *arg_info = &fbc->internal_function.arg_info[i]; if (i < fbc->common.required_num_args) { zend_execute_data *old = start_fake_frame(call, NULL); zend_argument_error(zend_ce_argument_count_error, i + 1, "not passed"); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 660975f9bc1b5..e134d3d496b6d 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -652,11 +652,7 @@ ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t a return NULL; } - if (func->type == ZEND_USER_FUNCTION || (func->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { - return ZSTR_VAL(func->common.arg_info[arg_num - 1].name); - } else { - return ((zend_internal_arg_info*) func->common.arg_info)[arg_num - 1].name; - } + return ZSTR_VAL(func->common.arg_info[arg_num - 1].name); } /* }}} */ diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index 97b7cdcc911b7..d571a622e476b 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -207,7 +207,12 @@ static zend_fiber_stack *zend_fiber_stack_allocate(size_t size) { void *pointer; const size_t page_size = zend_fiber_get_page_size(); - const size_t minimum_stack_size = page_size + ZEND_FIBER_GUARD_PAGES * page_size; + const size_t minimum_stack_size = page_size + ZEND_FIBER_GUARD_PAGES * page_size +#ifdef __SANITIZE_ADDRESS__ + // necessary correction due to ASAN redzones + * 6 +#endif + ; if (size < minimum_stack_size) { zend_throw_exception_ex(NULL, 0, "Fiber stack size is too small, it needs to be at least %zu bytes", minimum_stack_size); diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index d227795f66b0d..d85c0f2da4a94 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -312,7 +312,9 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ zend_object *old_exception = NULL; const zend_op *old_opline_before_exception = NULL; if (EG(exception)) { - if (EG(current_execute_data)) { + if (EG(current_execute_data) + && EG(current_execute_data)->opline + && EG(current_execute_data)->opline->opcode == ZEND_HANDLE_EXCEPTION) { EG(current_execute_data)->opline = EG(opline_before_exception); old_opline_before_exception = EG(opline_before_exception); } @@ -329,7 +331,7 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ zend_generator_resume(generator); if (old_exception) { - if (EG(current_execute_data)) { + if (old_opline_before_exception) { EG(current_execute_data)->opline = EG(exception_op); EG(opline_before_exception) = old_opline_before_exception; } diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 1f128764bdd3d..3c3931cdca164 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -953,18 +953,14 @@ static ZEND_COLD zend_string *zend_get_function_declaration( } smart_str_appendc(&str, '$'); - if (fptr->type == ZEND_INTERNAL_FUNCTION) { - smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name); - } else { - smart_str_appendl(&str, ZSTR_VAL(arg_info->name), ZSTR_LEN(arg_info->name)); - } + smart_str_append(&str, arg_info->name); if (i >= required && !ZEND_ARG_IS_VARIADIC(arg_info)) { smart_str_appends(&str, " = "); if (fptr->type == ZEND_INTERNAL_FUNCTION) { - if (((zend_internal_arg_info*)arg_info)->default_value) { - smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->default_value); + if (arg_info->default_value) { + smart_str_append(&str, arg_info->default_value); } else { smart_str_appends(&str, ""); } @@ -1011,7 +1007,9 @@ static ZEND_COLD zend_string *zend_get_function_declaration( zend_ast *ast = Z_ASTVAL_P(zv); if (ast->kind == ZEND_AST_CONSTANT) { smart_str_append(&str, zend_ast_get_constant_name(ast)); - } else if (ast->kind == ZEND_AST_CLASS_CONST) { + } else if (ast->kind == ZEND_AST_CLASS_CONST + && ast->child[1]->kind == ZEND_AST_ZVAL + && Z_TYPE_P(zend_ast_get_zval(ast->child[1])) == IS_STRING) { smart_str_append(&str, zend_ast_get_str(ast->child[0])); smart_str_appends(&str, "::"); smart_str_append(&str, zend_ast_get_str(ast->child[1])); diff --git a/Zend/zend_ini_scanner.l b/Zend/zend_ini_scanner.l index d3f71ba8bc340..5f9b77e6a3d8a 100644 --- a/Zend/zend_ini_scanner.l +++ b/Zend/zend_ini_scanner.l @@ -145,10 +145,10 @@ ZEND_API zend_ini_scanner_globals ini_scanner_globals; if (SCNG(scanner_mode) == ZEND_INI_SCANNER_TYPED && \ (YYSTATE == STATE(ST_VALUE) || YYSTATE == STATE(ST_RAW))) {\ zend_ini_copy_typed_value(ini_lval, type, str, len); \ - Z_EXTRA_P(ini_lval) = 0; \ } else { \ zend_ini_copy_value(ini_lval, str, len); \ } \ + Z_EXTRA_P(ini_lval) = 0; \ return type; \ } diff --git a/Zend/zend_language_scanner.h b/Zend/zend_language_scanner.h index 612c845479272..c494564ba2349 100644 --- a/Zend/zend_language_scanner.h +++ b/Zend/zend_language_scanner.h @@ -20,6 +20,7 @@ #ifndef ZEND_SCANNER_H #define ZEND_SCANNER_H +/* The zend_php_scanner_event enum is declared in zend_globals and we don't want everything to include zend_language_scanner.h */ #include "zend_globals.h" typedef struct _zend_lex_state { @@ -71,7 +72,7 @@ typedef struct _zend_heredoc_label { /* Track locations of unclosed {, [, (, etc. for better syntax error reporting */ typedef struct _zend_nest_location { char text; - int lineno; + uint32_t lineno; } zend_nest_location; BEGIN_EXTERN_C() diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 3ecb2f8d0ee45..1e26ddbd99199 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -30,6 +30,7 @@ #include "zend_language_scanner_defs.h" #include +#include #include "zend.h" #ifdef ZEND_WIN32 # include @@ -600,7 +601,7 @@ static zend_op_array *zend_compile(int type) CG(ast_arena) = zend_arena_create(1024 * 32); if (!zendparse()) { - int last_lineno = CG(zend_lineno); + uint32_t last_lineno = CG(zend_lineno); zend_file_context original_file_context; zend_oparray_context original_oparray_context; zend_op_array *original_active_op_array = CG(active_op_array); @@ -1140,7 +1141,7 @@ skip_escape_conversion: unsigned char *str; // TODO: avoid realocation ??? s = Z_STRVAL_P(zendlval); - SCNG(output_filter)(&str, &sz, (unsigned char *)s, (size_t)Z_STRLEN_P(zendlval)); + SCNG(output_filter)(&str, &sz, (unsigned char *)s, Z_STRLEN_P(zendlval)); zval_ptr_dtor(zendlval); ZVAL_STRINGL(zendlval, (char *) str, sz); efree(str); @@ -1172,7 +1173,7 @@ static bool strip_multiline_string_indentation( const char *str = Z_STRVAL_P(zendlval), *end = str + Z_STRLEN_P(zendlval); char *copy = Z_STRVAL_P(zendlval); - int newline_count = 0; + uint32_t newline_count = 0; size_t newline_len; const char *nl; @@ -1253,7 +1254,7 @@ static void copy_heredoc_label_stack(void *void_heredoc_label) } /* Check that { }, [ ], ( ) are nested correctly */ -static void report_bad_nesting(char opening, int opening_lineno, char closing) +static void report_bad_nesting(char opening, uint32_t opening_lineno, char closing) { char buf[256]; size_t used = 0; @@ -1361,7 +1362,7 @@ int ZEND_FASTCALL lex_scan(zval *zendlval, zend_parser_stack_elem *elem) { int token; int offset; -int start_line = CG(zend_lineno); +uint32_t start_line = CG(zend_lineno); ZVAL_UNDEF(zendlval); restart: @@ -2499,7 +2500,7 @@ inline_char_handler: if (YYCURSOR < YYLIMIT) { YYCURSOR++; } else { - zend_throw_exception_ex(zend_ce_parse_error, 0, "Unterminated comment starting line %d", CG(zend_lineno)); + zend_throw_exception_ex(zend_ce_parse_error, 0, "Unterminated comment starting line %" PRIu32, CG(zend_lineno)); if (PARSER_MODE()) { RETURN_TOKEN(T_ERROR); } @@ -2616,7 +2617,7 @@ skip_escape_conversion: zend_string *new_str; s = Z_STRVAL_P(zendlval); // TODO: avoid reallocation ??? - SCNG(output_filter)((unsigned char **)&str, &sz, (unsigned char *)s, (size_t)Z_STRLEN_P(zendlval)); + SCNG(output_filter)((unsigned char **)&str, &sz, (unsigned char *)s, Z_STRLEN_P(zendlval)); new_str = zend_string_init(str, sz, 0); if (str != s) { efree(str); diff --git a/Zend/zend_list.c b/Zend/zend_list.c index 5add19256a691..10aa9174cfccb 100644 --- a/Zend/zend_list.c +++ b/Zend/zend_list.c @@ -214,21 +214,34 @@ void zend_init_rsrc_plist(void) void zend_close_rsrc_list(HashTable *ht) { - /* Reload ht->arData on each iteration, as it may be reallocated. */ uint32_t i = ht->nNumUsed; + uint32_t num = ht->nNumUsed; retry: zend_try { while (i-- > 0) { + /* Reload ht->arData on each iteration, as it may be reallocated. */ zval *p = ZEND_HASH_ELEMENT(ht, i); if (Z_TYPE_P(p) != IS_UNDEF) { zend_resource *res = Z_PTR_P(p); if (res->type >= 0) { zend_resource_dtor(res); + + if (UNEXPECTED(ht->nNumUsed != num)) { + /* New resources were added, reloop from the start. + * We need to keep the top->down order to avoid freeing resources + * in use by the newly created resources. */ + i = num = ht->nNumUsed; + } } } } } zend_catch { + if (UNEXPECTED(ht->nNumUsed != num)) { + /* See above */ + i = num = ht->nNumUsed; + } + /* If we have bailed, we probably executed user code (e.g. user stream * API). Keep closing resources so they don't leak. User handlers must be * called now so they aren't called in zend_deactivate() on diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 470fb76ec14e1..88b7b1112d7b1 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -46,6 +46,9 @@ #define IN_ISSET ZEND_GUARD_PROPERTY_ISSET #define IN_HOOK ZEND_GUARD_PROPERTY_HOOK +static zend_arg_info zend_call_trampoline_arginfo[1] = {{0}}; +static zend_arg_info zend_property_hook_arginfo[1] = {{0}}; + static zend_always_inline bool zend_objects_check_stack_limit(void) { #ifdef ZEND_CHECK_STACK_LIMIT @@ -1782,9 +1785,6 @@ ZEND_API zend_function *zend_get_property_hook_trampoline( const zend_property_info *prop_info, zend_property_hook_kind kind, zend_string *prop_name) { - static const zend_internal_arg_info arg_info[2] = { - { .name = "value" } - }; zend_function *func; if (EXPECTED(EG(trampoline).common.function_name == NULL)) { func = &EG(trampoline); @@ -1810,7 +1810,7 @@ ZEND_API zend_function *zend_get_property_hook_trampoline( func->common.scope = prop_info->ce; func->common.prototype = NULL; func->common.prop_info = prop_info; - func->common.arg_info = (zend_arg_info *) arg_info; + func->common.arg_info = zend_property_hook_arginfo; func->internal_function.handler = kind == ZEND_PROPERTY_HOOK_GET ? ZEND_FN(zend_parent_hook_get_trampoline) : ZEND_FN(zend_parent_hook_set_trampoline); @@ -2574,3 +2574,8 @@ ZEND_API const zend_object_handlers std_object_handlers = { zend_std_compare_objects, /* compare */ NULL, /* get_properties_for */ }; + +void zend_object_handlers_startup(void) { + zend_call_trampoline_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_ARGS); + zend_property_hook_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_VALUE); +} diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 59277c09d8024..3e922343eb15a 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -334,6 +334,8 @@ ZEND_API zend_function *zend_get_property_hook_trampoline( ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_property_info *prop_info); +void zend_object_handlers_startup(void); + #define zend_release_properties(ht) do { \ if (ht) { \ zend_array_release(ht); \ diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 1962c7b5a56d1..5e9e7b20d869b 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -124,21 +124,32 @@ ZEND_API void zend_type_release(zend_type type, bool persistent) { } } -void zend_free_internal_arg_info(zend_internal_function *function) { - if ((function->fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) && - function->arg_info) { +ZEND_API void zend_free_internal_arg_info(zend_internal_function *function, + bool persistent) { + if (function->arg_info) { + ZEND_ASSERT((persistent || (function->fn_flags & ZEND_ACC_NEVER_CACHE)) + && "Functions with non-persistent arg_info must be flagged ZEND_ACC_NEVER_CACHE"); uint32_t i; uint32_t num_args = function->num_args + 1; - zend_internal_arg_info *arg_info = function->arg_info - 1; + zend_arg_info *arg_info = function->arg_info - 1; if (function->fn_flags & ZEND_ACC_VARIADIC) { num_args++; } for (i = 0 ; i < num_args; i++) { - zend_type_release(arg_info[i].type, /* persistent */ true); + bool is_return_info = i == 0; + if (!is_return_info) { + zend_string_release_ex(arg_info[i].name, persistent); + if (arg_info[i].default_value) { + zend_string_release_ex(arg_info[i].default_value, + persistent); + } + } + zend_type_release(arg_info[i].type, persistent); } - free(arg_info); + + pefree(arg_info, persistent); } } @@ -157,7 +168,7 @@ ZEND_API void zend_function_dtor(zval *zv) /* For methods this will be called explicitly. */ if (!function->common.scope) { - zend_free_internal_arg_info(&function->internal_function); + zend_free_internal_arg_info(&function->internal_function, true); if (function->common.attributes) { zend_hash_release(function->common.attributes); @@ -474,12 +485,9 @@ ZEND_API void destroy_zend_class(zval *zv) zend_hash_destroy(&ce->properties_info); zend_string_release_ex(ce->name, 1); - /* TODO: eliminate this loop for classes without functions with arg_info / attributes */ ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) { if (fn->common.scope == ce) { - if (fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) { - zend_free_internal_arg_info(&fn->internal_function); - } + zend_free_internal_arg_info(&fn->internal_function, true); if (fn->common.attributes) { zend_hash_release(fn->common.attributes); diff --git a/Zend/zend_simd.h b/Zend/zend_simd.h index 9bd16ce9e9afb..2f0df203733ca 100644 --- a/Zend/zend_simd.h +++ b/Zend/zend_simd.h @@ -1,17 +1,17 @@ /******************************************************************************** * MIT License * Copyright (c) 2025 Saki Takamachi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -22,389 +22,389 @@ *********************************************************************************/ - #ifndef XSSE_H - #define XSSE_H - - #define XSSE_VERSION 10000 - - #ifdef _MSC_VER - # define XSSE_FORCE_INLINE __forceinline - #elif defined(__GNUC__) || defined(__clang__) - # define XSSE_FORCE_INLINE inline __attribute__((always_inline)) - # define XSSE_HAS_MACRO_EXTENSION - #else - # define XSSE_FORCE_INLINE inline - #endif - - - #if defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) - #include - #define XSSE2 - - - #elif defined(__aarch64__) || defined(_M_ARM64) - #include - #define XSSE2 - - typedef int8x16_t __m128i; - - - /***************************************************************************** - * Load / Store * - *****************************************************************************/ - - #define _mm_set_epi8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) \ - ((int8x16_t) { \ - (int8_t) (x15), (int8_t) (x14), (int8_t) (x13), (int8_t) (x12), \ - (int8_t) (x11), (int8_t) (x10), (int8_t) (x9), (int8_t) (x8), \ - (int8_t) (x7), (int8_t) (x6), (int8_t) (x5), (int8_t) (x4), \ - (int8_t) (x3), (int8_t) (x2), (int8_t) (x1), (int8_t) (x0) }) - #define _mm_set_epi16(x0, x1, x2, x3, x4, x5, x6, x7) \ - (vreinterpretq_s8_s16((int16x8_t) { \ - (int16_t) (x7), (int16_t) (x6), (int16_t) (x5), (int16_t) (x4), \ - (int16_t) (x3), (int16_t) (x2), (int16_t) (x1), (int16_t) (x0) })) - #define _mm_set_epi32(x0, x1, x2, x3) \ - (vreinterpretq_s8_s32((int32x4_t) { (int32_t) (x3), (int32_t) (x2), (int32_t) (x1), (int32_t) (x0) })) - #define _mm_set_epi64x(x0, x1) (vreinterpretq_s8_s64((int64x2_t) { (int64_t) (x1), (int64_t) (x0) })) - #define _mm_set1_epi8(x) (vdupq_n_s8((int8_t) (x))) - #define _mm_set1_epi16(x) (vreinterpretq_s8_s16(vdupq_n_s16((int16_t) (x)))) - #define _mm_set1_epi32(x) (vreinterpretq_s8_s32(vdupq_n_s32((int32_t) (x)))) - #define _mm_set1_epi64x(x) (vreinterpretq_s8_s64(vdupq_n_s64((int64_t) (x)))) - - #define _mm_setr_epi8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) \ - ((int8x16_t) { \ - (int8_t) (x0), (int8_t) (x1), (int8_t) (x2), (int8_t) (x3), \ - (int8_t) (x4), (int8_t) (x5), (int8_t) (x6), (int8_t) (x7), \ - (int8_t) (x8), (int8_t) (x9), (int8_t) (x10), (int8_t) (x11), \ - (int8_t) (x12), (int8_t) (x13), (int8_t) (x14), (int8_t) (x15) }) - #define _mm_setr_epi16(x0, x1, x2, x3, x4, x5, x6, x7) \ - (vreinterpretq_s8_s16((int16x8_t) { \ - (int16_t) (x0), (int16_t) (x1), (int16_t) (x2), (int16_t) (x3), \ - (int16_t) (x4), (int16_t) (x5), (int16_t) (x6), (int16_t) (x7) })) - #define _mm_setr_epi32(x0, x1, x2, x3) \ - (vreinterpretq_s8_s32((int32x4_t) { (int32_t) (x0), (int32_t) (x1), (int32_t) (x2), (int32_t) (x3) })) - - #define _mm_setzero_si128() (vdupq_n_s8(0)) - - #define _mm_load_si128(x) (vld1q_s8((const int8_t *) (x))) - #define _mm_loadu_si128(x) _mm_load_si128(x) - - #define _mm_store_si128(to, x) (vst1q_s8((int8_t *) (to), x)) - #define _mm_storeu_si128(to, x) _mm_store_si128(to, x) - #define _mm_stream_si128(to, x) _mm_store_si128(to, x) - #define _mm_stream_si32(to, x) (*(volatile int32_t *)(to) = (int32_t)(x)) - - - /***************************************************************************** - * Bit shift / Bit wise * - *****************************************************************************/ - - #define _mm_or_si128(a, b) (vorrq_s8((a), (b))) - #define _mm_xor_si128(a, b) (veorq_s8((a), (b))) - #define _mm_and_si128(a, b) (vandq_s8((a), (b))) - #define _mm_andnot_si128(a, b) (vbicq_s8((b), (a))) - - #define _mm_slli_epi16(x, count) (vreinterpretq_s8_u16(vshlq_n_u16(vreinterpretq_u16_s8(x), (count)))) - #define _mm_slli_epi32(x, count) (vreinterpretq_s8_u32(vshlq_n_u32(vreinterpretq_u32_s8(x), (count)))) - #define _mm_slli_epi64(x, count) (vreinterpretq_s8_u64(vshlq_n_u64(vreinterpretq_u64_s8(x), (count)))) - static XSSE_FORCE_INLINE __m128i _mm_sll_epi16(__m128i x, __m128i count) - { - uint16_t shift = (uint16_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFF); - return vreinterpretq_s8_u16( - vshlq_u16(vreinterpretq_u16_s8(x), vdupq_n_s16((int16_t) shift)) - ); - } - static XSSE_FORCE_INLINE __m128i _mm_sll_epi32(__m128i x, __m128i count) - { - uint32_t shift = (uint32_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFFFFFF); - return vreinterpretq_s8_u32( - vshlq_u32(vreinterpretq_u32_s8(x), vdupq_n_s32((int32_t) shift)) - ); - } - static XSSE_FORCE_INLINE __m128i _mm_sll_epi64(__m128i x, __m128i count) - { - uint64_t shift = (uint64_t) vgetq_lane_s64(vreinterpretq_s64_s8(count), 0); - return vreinterpretq_s8_u64( - vshlq_u64(vreinterpretq_u64_s8(x), vdupq_n_s64((int64_t) shift)) - ); - } - - #define _mm_slli_si128(x, imm) \ - ((imm) >= 16 ? vdupq_n_s8(0) : vreinterpretq_s8_u8(vextq_u8(vdupq_n_u8(0), vreinterpretq_u8_s8(x), 16 - (imm)))) - - #define _mm_srai_epi16(x, count) (vreinterpretq_s8_s16(vshrq_n_s16(vreinterpretq_s16_s8(x), (count)))) - #define _mm_srai_epi32(x, count) (vreinterpretq_s8_s32(vshrq_n_s32(vreinterpretq_s32_s8(x), (count)))) - static inline __m128i _mm_sra_epi16(__m128i x, __m128i count) - { - uint16_t shift = (uint16_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFF); - return vreinterpretq_s8_s16( - vshlq_s16(vreinterpretq_s16_s8(x), vdupq_n_s16(-(int16_t) shift)) - ); - } - static inline __m128i _mm_sra_epi32(__m128i x, __m128i count) - { - uint32_t shift = (uint32_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFFFFFF); - return vreinterpretq_s8_s32( - vshlq_s32(vreinterpretq_s32_s8(x), vdupq_n_s32(-(int32_t) shift)) - ); - } - - #define _mm_srli_epi16(x, count) (vreinterpretq_s8_u16(vshrq_n_u16(vreinterpretq_u16_s8(x), (count)))) - #define _mm_srli_epi32(x, count) (vreinterpretq_s8_u32(vshrq_n_u32(vreinterpretq_u32_s8(x), (count)))) - #define _mm_srli_epi64(x, count) (vreinterpretq_s8_u64(vshrq_n_u64(vreinterpretq_u64_s8(x), (count)))) - static XSSE_FORCE_INLINE __m128i _mm_srl_epi16(__m128i x, __m128i count) - { - uint16_t shift = (uint16_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFF); - return vreinterpretq_s8_u16( - vshlq_u16(vreinterpretq_u16_s8(x), vdupq_n_s16(-(int16_t) shift)) - ); - } - static XSSE_FORCE_INLINE __m128i _mm_srl_epi32(__m128i x, __m128i count) - { - uint32_t shift = (uint32_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFFFFFF); - return vreinterpretq_s8_u32( - vshlq_u32(vreinterpretq_u32_s8(x), vdupq_n_s32(-(int32_t) shift)) - ); - } - static XSSE_FORCE_INLINE __m128i _mm_srl_epi64(__m128i x, __m128i count) - { - uint64_t shift = (uint64_t) vgetq_lane_s64(vreinterpretq_s64_s8(count), 0); - return vreinterpretq_s8_u64( - vshlq_u64(vreinterpretq_u64_s8(x), vdupq_n_s64(-(int64_t) shift)) - ); - } - - #define _mm_srli_si128(x, imm) \ - ((imm) >= 16 ? vdupq_n_s8(0) : vreinterpretq_s8_u8(vextq_u8(vreinterpretq_u8_s8(x), vdupq_n_u8(0), (imm)))) - - - /***************************************************************************** - * Integer Arithmetic Operations * - *****************************************************************************/ - - /** - * In practice, there is no problem, but a runtime error for signed integer overflow is triggered by UBSAN, - * so perform the calculation as unsigned. Since it is optimized at compile time, there are no unnecessary casts at runtime. - */ - #define _mm_add_epi8(a, b) (vreinterpretq_s8_u8(vaddq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) - #define _mm_add_epi16(a, b) (vreinterpretq_s8_u16(vaddq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) - #define _mm_add_epi32(a, b) (vreinterpretq_s8_u32(vaddq_u32(vreinterpretq_u32_s8(a), vreinterpretq_u32_s8(b)))) - #define _mm_add_epi64(a, b) (vreinterpretq_s8_u64(vaddq_u64(vreinterpretq_u64_s8(a), vreinterpretq_u64_s8(b)))) - - #define _mm_adds_epi8(a, b) (vqaddq_s8((a), (b))) - #define _mm_adds_epi16(a, b) (vreinterpretq_s8_s16(vqaddq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - #define _mm_adds_epu8(a, b) (vreinterpretq_s8_u8(vqaddq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) - #define _mm_adds_epu16(a, b) (vreinterpretq_s8_u16(vqaddq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) - - #define _mm_avg_epu8(a, b) (vreinterpretq_s8_u8(vrhaddq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) - #define _mm_avg_epu16(a, b) (vreinterpretq_s8_u16(vrhaddq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) - - static XSSE_FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) - { - int32x4_t mul_lo = vmull_s16(vget_low_s16(vreinterpretq_s16_s8(a)), vget_low_s16(vreinterpretq_s16_s8(b))); - int32x4_t mul_hi = vmull_s16(vget_high_s16(vreinterpretq_s16_s8(a)), vget_high_s16(vreinterpretq_s16_s8(b))); - - return vreinterpretq_s8_s32(vcombine_s32( - vpadd_s32(vget_low_s32(mul_lo), vget_high_s32(mul_lo)), - vpadd_s32(vget_low_s32(mul_hi), vget_high_s32(mul_hi)) - )); - } - - #define _mm_max_epu8(a, b) (vreinterpretq_s8_u8(vmaxq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) - #define _mm_max_epi16(a, b) (vreinterpretq_s8_s16(vmaxq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - #define _mm_min_epu8(a, b) (vreinterpretq_s8_u8(vminq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) - #define _mm_min_epi16(a, b) (vreinterpretq_s8_s16(vminq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - - static XSSE_FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b) - { - int32x4_t lo = vmull_s16(vget_low_s16(vreinterpretq_s16_s8(a)), vget_low_s16(vreinterpretq_s16_s8(b))); - int32x4_t hi = vmull_s16(vget_high_s16(vreinterpretq_s16_s8(a)), vget_high_s16(vreinterpretq_s16_s8(b))); - return vreinterpretq_s8_s16(vcombine_s16(vshrn_n_s32(lo, 16), vshrn_n_s32(hi, 16))); - } - static XSSE_FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b) - { - uint32x4_t lo = vmull_u16(vget_low_u16(vreinterpretq_u16_s8(a)), vget_low_u16(vreinterpretq_u16_s8(b))); - uint32x4_t hi = vmull_u16(vget_high_u16(vreinterpretq_u16_s8(a)), vget_high_u16(vreinterpretq_u16_s8(b))); - return vreinterpretq_s8_u16(vcombine_u16(vshrn_n_u32(lo, 16), vshrn_n_u32(hi, 16))); - } - static XSSE_FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b) - { - int32x4_t lo = vmull_s16(vget_low_s16(vreinterpretq_s16_s8(a)), vget_low_s16(vreinterpretq_s16_s8(b))); - int32x4_t hi = vmull_s16(vget_high_s16(vreinterpretq_s16_s8(a)), vget_high_s16(vreinterpretq_s16_s8(b))); - return vreinterpretq_s8_s16(vcombine_s16(vmovn_s32(lo), vmovn_s32(hi))); - } - static XSSE_FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b) - { - uint32x4_t evens = vuzpq_u32(vreinterpretq_u32_s8(a), vreinterpretq_u32_s8(b)).val[0]; - return vreinterpretq_s8_u64(vmull_u32(vget_low_u32(evens), vget_high_u32(evens))); - } - static XSSE_FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b) - { - uint16x8_t abs_diffs_16 = vpaddlq_u8(vabdq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b))); - uint32x4_t abs_diffs_32 = vpaddlq_u16(abs_diffs_16); - uint64x2_t abs_diffs_64 = vpaddlq_u32(abs_diffs_32); - - return vreinterpretq_s8_u16((uint16x8_t) { - (int16_t) vgetq_lane_u64(abs_diffs_64, 0), 0, 0, 0, - (int16_t) vgetq_lane_u64(abs_diffs_64, 1), 0, 0, 0 - }); - } - - #define _mm_sub_epi8(a, b) (vreinterpretq_s8_u8(vsubq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) - #define _mm_sub_epi16(a, b) (vreinterpretq_s8_u16(vsubq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) - #define _mm_sub_epi32(a, b) (vreinterpretq_s8_u32(vsubq_u32(vreinterpretq_u32_s8(a), vreinterpretq_u32_s8(b)))) - #define _mm_sub_epi64(a, b) (vreinterpretq_s8_u64(vsubq_u64(vreinterpretq_u64_s8(a), vreinterpretq_u64_s8(b)))) - - #define _mm_subs_epi8(a, b) (vqsubq_s8((a), (b))) - #define _mm_subs_epi16(a, b) (vreinterpretq_s8_s16(vqsubq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - #define _mm_subs_epu8(a, b) (vreinterpretq_s8_u8(vqsubq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) - #define _mm_subs_epu16(a, b) (vreinterpretq_s8_u16(vqsubq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) - - - /***************************************************************************** - * Comparison * - *****************************************************************************/ - - #define _mm_cmpeq_epi8(a, b) (vreinterpretq_s8_u8(vceqq_s8((a), (b)))) - #define _mm_cmpeq_epi16(a, b) (vreinterpretq_s8_u16(vceqq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - #define _mm_cmpeq_epi32(a, b) (vreinterpretq_s8_u32(vceqq_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) - - #define _mm_cmplt_epi8(a, b) (vreinterpretq_s8_u8(vcltq_s8((a), (b)))) - #define _mm_cmplt_epi16(a, b) (vreinterpretq_s8_u16(vcltq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - #define _mm_cmplt_epi32(a, b) (vreinterpretq_s8_u32(vcltq_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) - - #define _mm_cmpgt_epi8(a, b) (vreinterpretq_s8_u8(vcgtq_s8((a), (b)))) - #define _mm_cmpgt_epi16(a, b) (vreinterpretq_s8_u16(vcgtq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - #define _mm_cmpgt_epi32(a, b) (vreinterpretq_s8_u32(vcgtq_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) - - - /***************************************************************************** - * Convert * - *****************************************************************************/ - - #define _mm_cvtsi32_si128(x) (vreinterpretq_s8_s32((int32x4_t) { (int32_t) (x), 0, 0, 0 })) - #define _mm_cvtsi64_si128(x) (vreinterpretq_s8_s64((int64x2_t) { (int64_t) (x), 0 })) - #define _mm_cvtsi128_si32(x) (vgetq_lane_s32(vreinterpretq_s32_s8(x), 0)) - #define _mm_cvtsi128_si64(x) (vgetq_lane_s64(vreinterpretq_s64_s8(x), 0)) - - - /***************************************************************************** - * Others * - *****************************************************************************/ - - #define _mm_packs_epi16(a, b) (vcombine_s8(vqmovn_s16(vreinterpretq_s16_s8(a)), vqmovn_s16(vreinterpretq_s16_s8(b)))) - #define _mm_packs_epi32(a, b) \ - (vreinterpretq_s8_s16(vcombine_s16(vqmovn_s32(vreinterpretq_s32_s8(a)), vqmovn_s32(vreinterpretq_s32_s8(b))))) - #define _mm_packus_epi16(a, b) \ - (vreinterpretq_s8_u8(vcombine_u8(vqmovun_s16(vreinterpretq_s16_s8(a)), vqmovun_s16(vreinterpretq_s16_s8(b))))) - - #define _mm_extract_epi16(x, imm) (vgetq_lane_s16(vreinterpretq_s16_s8(x), (imm))) - #define _mm_insert_epi16(x, val, imm) (vreinterpretq_s8_s16(vsetq_lane_s16((int16_t) (val), vreinterpretq_s16_s8(x), (imm)))) - - static XSSE_FORCE_INLINE int _mm_movemask_epi8(__m128i x) - { - /** - * based on code from - * https://community.arm.com/arm-community-blogs/b/servers-and-cloud-computing-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon - */ - uint16x8_t high_bits = vreinterpretq_u16_u8(vshrq_n_u8(vreinterpretq_u8_s8(x), 7)); - uint32x4_t paired16 = vreinterpretq_u32_u16(vsraq_n_u16(high_bits, high_bits, 7)); - uint64x2_t paired32 = vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14)); - uint8x16_t paired64 = vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28)); - return vgetq_lane_u8(paired64, 0) | ((int) vgetq_lane_u8(paired64, 8) << 8); - } - - #define _MM_SHUFFLE(a, b, c, d) (((a) << 6) | ((b) << 4) | ((c) << 2) | (d)) - #ifdef XSSE_HAS_MACRO_EXTENSION - #define _mm_shuffle_epi32(x, imm) __extension__({ \ - int32x4_t __xsse_tmp = vreinterpretq_s32_s8(x); \ - vreinterpretq_s8_s32((int32x4_t) { \ - (int32_t) vgetq_lane_s32(__xsse_tmp, ((imm) >> 0) & 0x3), \ - (int32_t) vgetq_lane_s32(__xsse_tmp, ((imm) >> 2) & 0x3), \ - (int32_t) vgetq_lane_s32(__xsse_tmp, ((imm) >> 4) & 0x3), \ - (int32_t) vgetq_lane_s32(__xsse_tmp, ((imm) >> 6) & 0x3) \ - }); \ - }) - #define _mm_shufflehi_epi16(x, imm) __extension__({ \ - int16x8_t __xsse_tmp = vreinterpretq_s16_s8(x); \ - vreinterpretq_s8_s16(vcombine_s16( \ - vget_low_s16(__xsse_tmp), \ - (int16x4_t) { \ - (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 0) & 0x3) + 4), \ - (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 2) & 0x3) + 4), \ - (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 4) & 0x3) + 4), \ - (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 6) & 0x3) + 4) \ - } \ - )); \ - }) - #define _mm_shufflelo_epi16(x, imm) __extension__({ \ - int16x8_t __xsse_tmp = vreinterpretq_s16_s8(x); \ - vreinterpretq_s8_s16(vcombine_s16( \ - (int16x4_t) { \ - (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 0) & 0x3)), \ - (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 2) & 0x3)), \ - (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 4) & 0x3)), \ - (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 6) & 0x3)) \ - }, \ - vget_high_s16(__xsse_tmp) \ - )); \ - }) - #else - static XSSE_FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i x, int imm) - { - int32x4_t vec = vreinterpretq_s32_s8(x); - int32_t arr[4]; - vst1q_s32(arr, vec); - - return vreinterpretq_s8_s32((int32x4_t) { - arr[(imm >> 0) & 0x3], - arr[(imm >> 2) & 0x3], - arr[(imm >> 4) & 0x3], - arr[(imm >> 6) & 0x3] - }); - } - static XSSE_FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i x, int imm) - { - int16x8_t vec = vreinterpretq_s16_s8(x); - int16_t arr[8]; - vst1q_s16(arr, vec); - - return vreinterpretq_s8_s16((int16x8_t) { - arr[0], arr[1], arr[2], arr[3], - arr[((imm >> 0) & 0x3) + 4], - arr[((imm >> 2) & 0x3) + 4], - arr[((imm >> 4) & 0x3) + 4], - arr[((imm >> 6) & 0x3) + 4] - }); - } - static XSSE_FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i x, int imm) - { - int16x8_t vec = vreinterpretq_s16_s8(x); - int16_t arr[8]; - vst1q_s16(arr, vec); - - return vreinterpretq_s8_s16((int16x8_t) { - arr[((imm >> 0) & 0x3)], - arr[((imm >> 2) & 0x3)], - arr[((imm >> 4) & 0x3)], - arr[((imm >> 6) & 0x3)], - arr[4], arr[5], arr[6], arr[7] - }); - } - #endif - - #define _mm_unpackhi_epi8(a, b) (vzip2q_s8((a), (b))) - #define _mm_unpackhi_epi16(a, b) (vreinterpretq_s8_s16(vzip2q_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - #define _mm_unpackhi_epi32(a, b) (vreinterpretq_s8_s32(vzip2q_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) - #define _mm_unpackhi_epi64(a, b) (vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(a), vreinterpretq_s64_s8(b)))) - - #define _mm_unpacklo_epi8(a, b) (vzip1q_s8((a), (b))) - #define _mm_unpacklo_epi16(a, b) (vreinterpretq_s8_s16(vzip1q_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) - #define _mm_unpacklo_epi32(a, b) (vreinterpretq_s8_s32(vzip1q_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) - #define _mm_unpacklo_epi64(a, b) (vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(a), vreinterpretq_s64_s8(b)))) - - #define _mm_move_epi64(x) (vreinterpretq_s8_s64((int64x2_t) { vgetq_lane_s64(vreinterpretq_s64_s8(x), 0), 0 })) - - #endif - - #endif /* XSSE_H */ +#ifndef XSSE_H +#define XSSE_H + +#define XSSE_VERSION 10000 + +#ifdef _MSC_VER +# define XSSE_FORCE_INLINE __forceinline +#elif defined(__GNUC__) || defined(__clang__) +# define XSSE_FORCE_INLINE inline __attribute__((always_inline)) +# define XSSE_HAS_MACRO_EXTENSION +#else +# define XSSE_FORCE_INLINE inline +#endif + + +#if defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) +#include +#define XSSE2 + + +#elif defined(__aarch64__) || defined(_M_ARM64) +#include +#define XSSE2 + +typedef int8x16_t __m128i; + + +/***************************************************************************** + * Load / Store * + *****************************************************************************/ + +#define _mm_set_epi8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) \ + ((int8x16_t) { \ + (int8_t) (x15), (int8_t) (x14), (int8_t) (x13), (int8_t) (x12), \ + (int8_t) (x11), (int8_t) (x10), (int8_t) (x9), (int8_t) (x8), \ + (int8_t) (x7), (int8_t) (x6), (int8_t) (x5), (int8_t) (x4), \ + (int8_t) (x3), (int8_t) (x2), (int8_t) (x1), (int8_t) (x0) }) +#define _mm_set_epi16(x0, x1, x2, x3, x4, x5, x6, x7) \ + (vreinterpretq_s8_s16((int16x8_t) { \ + (int16_t) (x7), (int16_t) (x6), (int16_t) (x5), (int16_t) (x4), \ + (int16_t) (x3), (int16_t) (x2), (int16_t) (x1), (int16_t) (x0) })) +#define _mm_set_epi32(x0, x1, x2, x3) \ + (vreinterpretq_s8_s32((int32x4_t) { (int32_t) (x3), (int32_t) (x2), (int32_t) (x1), (int32_t) (x0) })) +#define _mm_set_epi64x(x0, x1) (vreinterpretq_s8_s64((int64x2_t) { (int64_t) (x1), (int64_t) (x0) })) +#define _mm_set1_epi8(x) (vdupq_n_s8((int8_t) (x))) +#define _mm_set1_epi16(x) (vreinterpretq_s8_s16(vdupq_n_s16((int16_t) (x)))) +#define _mm_set1_epi32(x) (vreinterpretq_s8_s32(vdupq_n_s32((int32_t) (x)))) +#define _mm_set1_epi64x(x) (vreinterpretq_s8_s64(vdupq_n_s64((int64_t) (x)))) + +#define _mm_setr_epi8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) \ + ((int8x16_t) { \ + (int8_t) (x0), (int8_t) (x1), (int8_t) (x2), (int8_t) (x3), \ + (int8_t) (x4), (int8_t) (x5), (int8_t) (x6), (int8_t) (x7), \ + (int8_t) (x8), (int8_t) (x9), (int8_t) (x10), (int8_t) (x11), \ + (int8_t) (x12), (int8_t) (x13), (int8_t) (x14), (int8_t) (x15) }) +#define _mm_setr_epi16(x0, x1, x2, x3, x4, x5, x6, x7) \ + (vreinterpretq_s8_s16((int16x8_t) { \ + (int16_t) (x0), (int16_t) (x1), (int16_t) (x2), (int16_t) (x3), \ + (int16_t) (x4), (int16_t) (x5), (int16_t) (x6), (int16_t) (x7) })) +#define _mm_setr_epi32(x0, x1, x2, x3) \ + (vreinterpretq_s8_s32((int32x4_t) { (int32_t) (x0), (int32_t) (x1), (int32_t) (x2), (int32_t) (x3) })) + +#define _mm_setzero_si128() (vdupq_n_s8(0)) + +#define _mm_load_si128(x) (vld1q_s8((const int8_t *) (x))) +#define _mm_loadu_si128(x) _mm_load_si128(x) + +#define _mm_store_si128(to, x) (vst1q_s8((int8_t *) (to), x)) +#define _mm_storeu_si128(to, x) _mm_store_si128(to, x) +#define _mm_stream_si128(to, x) _mm_store_si128(to, x) +#define _mm_stream_si32(to, x) (*(volatile int32_t *)(to) = (int32_t)(x)) + + +/***************************************************************************** + * Bit shift / Bit wise * + *****************************************************************************/ + +#define _mm_or_si128(a, b) (vorrq_s8((a), (b))) +#define _mm_xor_si128(a, b) (veorq_s8((a), (b))) +#define _mm_and_si128(a, b) (vandq_s8((a), (b))) +#define _mm_andnot_si128(a, b) (vbicq_s8((b), (a))) + +#define _mm_slli_epi16(x, count) (vreinterpretq_s8_u16(vshlq_n_u16(vreinterpretq_u16_s8(x), (count)))) +#define _mm_slli_epi32(x, count) (vreinterpretq_s8_u32(vshlq_n_u32(vreinterpretq_u32_s8(x), (count)))) +#define _mm_slli_epi64(x, count) (vreinterpretq_s8_u64(vshlq_n_u64(vreinterpretq_u64_s8(x), (count)))) +static XSSE_FORCE_INLINE __m128i _mm_sll_epi16(__m128i x, __m128i count) +{ + uint16_t shift = (uint16_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFF); + return vreinterpretq_s8_u16( + vshlq_u16(vreinterpretq_u16_s8(x), vdupq_n_s16((int16_t) shift)) + ); +} +static XSSE_FORCE_INLINE __m128i _mm_sll_epi32(__m128i x, __m128i count) +{ + uint32_t shift = (uint32_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFFFFFF); + return vreinterpretq_s8_u32( + vshlq_u32(vreinterpretq_u32_s8(x), vdupq_n_s32((int32_t) shift)) + ); +} +static XSSE_FORCE_INLINE __m128i _mm_sll_epi64(__m128i x, __m128i count) +{ + uint64_t shift = (uint64_t) vgetq_lane_s64(vreinterpretq_s64_s8(count), 0); + return vreinterpretq_s8_u64( + vshlq_u64(vreinterpretq_u64_s8(x), vdupq_n_s64((int64_t) shift)) + ); +} + +#define _mm_slli_si128(x, imm) \ + ((imm) >= 16 ? vdupq_n_s8(0) : vreinterpretq_s8_u8(vextq_u8(vdupq_n_u8(0), vreinterpretq_u8_s8(x), 16 - (imm)))) + +#define _mm_srai_epi16(x, count) (vreinterpretq_s8_s16(vshrq_n_s16(vreinterpretq_s16_s8(x), (count)))) +#define _mm_srai_epi32(x, count) (vreinterpretq_s8_s32(vshrq_n_s32(vreinterpretq_s32_s8(x), (count)))) +static inline __m128i _mm_sra_epi16(__m128i x, __m128i count) +{ + uint16_t shift = (uint16_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFF); + return vreinterpretq_s8_s16( + vshlq_s16(vreinterpretq_s16_s8(x), vdupq_n_s16(-(int16_t) shift)) + ); +} +static inline __m128i _mm_sra_epi32(__m128i x, __m128i count) +{ + uint32_t shift = (uint32_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFFFFFF); + return vreinterpretq_s8_s32( + vshlq_s32(vreinterpretq_s32_s8(x), vdupq_n_s32(-(int32_t) shift)) + ); +} + +#define _mm_srli_epi16(x, count) (vreinterpretq_s8_u16(vshrq_n_u16(vreinterpretq_u16_s8(x), (count)))) +#define _mm_srli_epi32(x, count) (vreinterpretq_s8_u32(vshrq_n_u32(vreinterpretq_u32_s8(x), (count)))) +#define _mm_srli_epi64(x, count) (vreinterpretq_s8_u64(vshrq_n_u64(vreinterpretq_u64_s8(x), (count)))) +static XSSE_FORCE_INLINE __m128i _mm_srl_epi16(__m128i x, __m128i count) +{ + uint16_t shift = (uint16_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFF); + return vreinterpretq_s8_u16( + vshlq_u16(vreinterpretq_u16_s8(x), vdupq_n_s16(-(int16_t) shift)) + ); +} +static XSSE_FORCE_INLINE __m128i _mm_srl_epi32(__m128i x, __m128i count) +{ + uint32_t shift = (uint32_t) (vgetq_lane_s64(vreinterpretq_s64_s8(count), 0) & 0xFFFFFFFF); + return vreinterpretq_s8_u32( + vshlq_u32(vreinterpretq_u32_s8(x), vdupq_n_s32(-(int32_t) shift)) + ); +} +static XSSE_FORCE_INLINE __m128i _mm_srl_epi64(__m128i x, __m128i count) +{ + uint64_t shift = (uint64_t) vgetq_lane_s64(vreinterpretq_s64_s8(count), 0); + return vreinterpretq_s8_u64( + vshlq_u64(vreinterpretq_u64_s8(x), vdupq_n_s64(-(int64_t) shift)) + ); +} + +#define _mm_srli_si128(x, imm) \ + ((imm) >= 16 ? vdupq_n_s8(0) : vreinterpretq_s8_u8(vextq_u8(vreinterpretq_u8_s8(x), vdupq_n_u8(0), (imm)))) + + +/***************************************************************************** + * Integer Arithmetic Operations * + *****************************************************************************/ + +/** + * In practice, there is no problem, but a runtime error for signed integer overflow is triggered by UBSAN, + * so perform the calculation as unsigned. Since it is optimized at compile time, there are no unnecessary casts at runtime. + */ +#define _mm_add_epi8(a, b) (vreinterpretq_s8_u8(vaddq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) +#define _mm_add_epi16(a, b) (vreinterpretq_s8_u16(vaddq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) +#define _mm_add_epi32(a, b) (vreinterpretq_s8_u32(vaddq_u32(vreinterpretq_u32_s8(a), vreinterpretq_u32_s8(b)))) +#define _mm_add_epi64(a, b) (vreinterpretq_s8_u64(vaddq_u64(vreinterpretq_u64_s8(a), vreinterpretq_u64_s8(b)))) + +#define _mm_adds_epi8(a, b) (vqaddq_s8((a), (b))) +#define _mm_adds_epi16(a, b) (vreinterpretq_s8_s16(vqaddq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) +#define _mm_adds_epu8(a, b) (vreinterpretq_s8_u8(vqaddq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) +#define _mm_adds_epu16(a, b) (vreinterpretq_s8_u16(vqaddq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) + +#define _mm_avg_epu8(a, b) (vreinterpretq_s8_u8(vrhaddq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) +#define _mm_avg_epu16(a, b) (vreinterpretq_s8_u16(vrhaddq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) + +static XSSE_FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) +{ + int32x4_t mul_lo = vmull_s16(vget_low_s16(vreinterpretq_s16_s8(a)), vget_low_s16(vreinterpretq_s16_s8(b))); + int32x4_t mul_hi = vmull_s16(vget_high_s16(vreinterpretq_s16_s8(a)), vget_high_s16(vreinterpretq_s16_s8(b))); + + return vreinterpretq_s8_s32(vcombine_s32( + vpadd_s32(vget_low_s32(mul_lo), vget_high_s32(mul_lo)), + vpadd_s32(vget_low_s32(mul_hi), vget_high_s32(mul_hi)) + )); +} + +#define _mm_max_epu8(a, b) (vreinterpretq_s8_u8(vmaxq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) +#define _mm_max_epi16(a, b) (vreinterpretq_s8_s16(vmaxq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) +#define _mm_min_epu8(a, b) (vreinterpretq_s8_u8(vminq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) +#define _mm_min_epi16(a, b) (vreinterpretq_s8_s16(vminq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) + +static XSSE_FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b) +{ + int32x4_t lo = vmull_s16(vget_low_s16(vreinterpretq_s16_s8(a)), vget_low_s16(vreinterpretq_s16_s8(b))); + int32x4_t hi = vmull_s16(vget_high_s16(vreinterpretq_s16_s8(a)), vget_high_s16(vreinterpretq_s16_s8(b))); + return vreinterpretq_s8_s16(vcombine_s16(vshrn_n_s32(lo, 16), vshrn_n_s32(hi, 16))); +} +static XSSE_FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b) +{ + uint32x4_t lo = vmull_u16(vget_low_u16(vreinterpretq_u16_s8(a)), vget_low_u16(vreinterpretq_u16_s8(b))); + uint32x4_t hi = vmull_u16(vget_high_u16(vreinterpretq_u16_s8(a)), vget_high_u16(vreinterpretq_u16_s8(b))); + return vreinterpretq_s8_u16(vcombine_u16(vshrn_n_u32(lo, 16), vshrn_n_u32(hi, 16))); +} +static XSSE_FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b) +{ + int32x4_t lo = vmull_s16(vget_low_s16(vreinterpretq_s16_s8(a)), vget_low_s16(vreinterpretq_s16_s8(b))); + int32x4_t hi = vmull_s16(vget_high_s16(vreinterpretq_s16_s8(a)), vget_high_s16(vreinterpretq_s16_s8(b))); + return vreinterpretq_s8_s16(vcombine_s16(vmovn_s32(lo), vmovn_s32(hi))); +} +static XSSE_FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b) +{ + uint32x4_t evens = vuzpq_u32(vreinterpretq_u32_s8(a), vreinterpretq_u32_s8(b)).val[0]; + return vreinterpretq_s8_u64(vmull_u32(vget_low_u32(evens), vget_high_u32(evens))); +} +static XSSE_FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b) +{ + uint16x8_t abs_diffs_16 = vpaddlq_u8(vabdq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b))); + uint32x4_t abs_diffs_32 = vpaddlq_u16(abs_diffs_16); + uint64x2_t abs_diffs_64 = vpaddlq_u32(abs_diffs_32); + + return vreinterpretq_s8_u16((uint16x8_t) { + (int16_t) vgetq_lane_u64(abs_diffs_64, 0), 0, 0, 0, + (int16_t) vgetq_lane_u64(abs_diffs_64, 1), 0, 0, 0 + }); +} + +#define _mm_sub_epi8(a, b) (vreinterpretq_s8_u8(vsubq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) +#define _mm_sub_epi16(a, b) (vreinterpretq_s8_u16(vsubq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) +#define _mm_sub_epi32(a, b) (vreinterpretq_s8_u32(vsubq_u32(vreinterpretq_u32_s8(a), vreinterpretq_u32_s8(b)))) +#define _mm_sub_epi64(a, b) (vreinterpretq_s8_u64(vsubq_u64(vreinterpretq_u64_s8(a), vreinterpretq_u64_s8(b)))) + +#define _mm_subs_epi8(a, b) (vqsubq_s8((a), (b))) +#define _mm_subs_epi16(a, b) (vreinterpretq_s8_s16(vqsubq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) +#define _mm_subs_epu8(a, b) (vreinterpretq_s8_u8(vqsubq_u8(vreinterpretq_u8_s8(a), vreinterpretq_u8_s8(b)))) +#define _mm_subs_epu16(a, b) (vreinterpretq_s8_u16(vqsubq_u16(vreinterpretq_u16_s8(a), vreinterpretq_u16_s8(b)))) + + +/***************************************************************************** + * Comparison * + *****************************************************************************/ + +#define _mm_cmpeq_epi8(a, b) (vreinterpretq_s8_u8(vceqq_s8((a), (b)))) +#define _mm_cmpeq_epi16(a, b) (vreinterpretq_s8_u16(vceqq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) +#define _mm_cmpeq_epi32(a, b) (vreinterpretq_s8_u32(vceqq_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) + +#define _mm_cmplt_epi8(a, b) (vreinterpretq_s8_u8(vcltq_s8((a), (b)))) +#define _mm_cmplt_epi16(a, b) (vreinterpretq_s8_u16(vcltq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) +#define _mm_cmplt_epi32(a, b) (vreinterpretq_s8_u32(vcltq_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) + +#define _mm_cmpgt_epi8(a, b) (vreinterpretq_s8_u8(vcgtq_s8((a), (b)))) +#define _mm_cmpgt_epi16(a, b) (vreinterpretq_s8_u16(vcgtq_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) +#define _mm_cmpgt_epi32(a, b) (vreinterpretq_s8_u32(vcgtq_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) + + +/***************************************************************************** + * Convert * + *****************************************************************************/ + +#define _mm_cvtsi32_si128(x) (vreinterpretq_s8_s32((int32x4_t) { (int32_t) (x), 0, 0, 0 })) +#define _mm_cvtsi64_si128(x) (vreinterpretq_s8_s64((int64x2_t) { (int64_t) (x), 0 })) +#define _mm_cvtsi128_si32(x) (vgetq_lane_s32(vreinterpretq_s32_s8(x), 0)) +#define _mm_cvtsi128_si64(x) (vgetq_lane_s64(vreinterpretq_s64_s8(x), 0)) + + +/***************************************************************************** + * Others * + *****************************************************************************/ + +#define _mm_packs_epi16(a, b) (vcombine_s8(vqmovn_s16(vreinterpretq_s16_s8(a)), vqmovn_s16(vreinterpretq_s16_s8(b)))) +#define _mm_packs_epi32(a, b) \ + (vreinterpretq_s8_s16(vcombine_s16(vqmovn_s32(vreinterpretq_s32_s8(a)), vqmovn_s32(vreinterpretq_s32_s8(b))))) +#define _mm_packus_epi16(a, b) \ + (vreinterpretq_s8_u8(vcombine_u8(vqmovun_s16(vreinterpretq_s16_s8(a)), vqmovun_s16(vreinterpretq_s16_s8(b))))) + +#define _mm_extract_epi16(x, imm) (vgetq_lane_s16(vreinterpretq_s16_s8(x), (imm))) +#define _mm_insert_epi16(x, val, imm) (vreinterpretq_s8_s16(vsetq_lane_s16((int16_t) (val), vreinterpretq_s16_s8(x), (imm)))) + +static XSSE_FORCE_INLINE int _mm_movemask_epi8(__m128i x) +{ + /** + * based on code from + * https://community.arm.com/arm-community-blogs/b/servers-and-cloud-computing-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon + */ + uint16x8_t high_bits = vreinterpretq_u16_u8(vshrq_n_u8(vreinterpretq_u8_s8(x), 7)); + uint32x4_t paired16 = vreinterpretq_u32_u16(vsraq_n_u16(high_bits, high_bits, 7)); + uint64x2_t paired32 = vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14)); + uint8x16_t paired64 = vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28)); + return vgetq_lane_u8(paired64, 0) | ((int) vgetq_lane_u8(paired64, 8) << 8); +} + +#define _MM_SHUFFLE(a, b, c, d) (((a) << 6) | ((b) << 4) | ((c) << 2) | (d)) +#ifdef XSSE_HAS_MACRO_EXTENSION +#define _mm_shuffle_epi32(x, imm) __extension__({ \ + int32x4_t __xsse_tmp = vreinterpretq_s32_s8(x); \ + vreinterpretq_s8_s32((int32x4_t) { \ + (int32_t) vgetq_lane_s32(__xsse_tmp, ((imm) >> 0) & 0x3), \ + (int32_t) vgetq_lane_s32(__xsse_tmp, ((imm) >> 2) & 0x3), \ + (int32_t) vgetq_lane_s32(__xsse_tmp, ((imm) >> 4) & 0x3), \ + (int32_t) vgetq_lane_s32(__xsse_tmp, ((imm) >> 6) & 0x3) \ + }); \ + }) +#define _mm_shufflehi_epi16(x, imm) __extension__({ \ + int16x8_t __xsse_tmp = vreinterpretq_s16_s8(x); \ + vreinterpretq_s8_s16(vcombine_s16( \ + vget_low_s16(__xsse_tmp), \ + (int16x4_t) { \ + (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 0) & 0x3) + 4), \ + (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 2) & 0x3) + 4), \ + (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 4) & 0x3) + 4), \ + (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 6) & 0x3) + 4) \ + } \ + )); \ + }) +#define _mm_shufflelo_epi16(x, imm) __extension__({ \ + int16x8_t __xsse_tmp = vreinterpretq_s16_s8(x); \ + vreinterpretq_s8_s16(vcombine_s16( \ + (int16x4_t) { \ + (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 0) & 0x3)), \ + (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 2) & 0x3)), \ + (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 4) & 0x3)), \ + (int16_t) vgetq_lane_s16(__xsse_tmp, (((imm) >> 6) & 0x3)) \ + }, \ + vget_high_s16(__xsse_tmp) \ + )); \ + }) +#else +static XSSE_FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i x, int imm) +{ + int32x4_t vec = vreinterpretq_s32_s8(x); + int32_t arr[4]; + vst1q_s32(arr, vec); + + return vreinterpretq_s8_s32((int32x4_t) { + arr[(imm >> 0) & 0x3], + arr[(imm >> 2) & 0x3], + arr[(imm >> 4) & 0x3], + arr[(imm >> 6) & 0x3] + }); +} +static XSSE_FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i x, int imm) +{ + int16x8_t vec = vreinterpretq_s16_s8(x); + int16_t arr[8]; + vst1q_s16(arr, vec); + + return vreinterpretq_s8_s16((int16x8_t) { + arr[0], arr[1], arr[2], arr[3], + arr[((imm >> 0) & 0x3) + 4], + arr[((imm >> 2) & 0x3) + 4], + arr[((imm >> 4) & 0x3) + 4], + arr[((imm >> 6) & 0x3) + 4] + }); +} +static XSSE_FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i x, int imm) +{ + int16x8_t vec = vreinterpretq_s16_s8(x); + int16_t arr[8]; + vst1q_s16(arr, vec); + + return vreinterpretq_s8_s16((int16x8_t) { + arr[((imm >> 0) & 0x3)], + arr[((imm >> 2) & 0x3)], + arr[((imm >> 4) & 0x3)], + arr[((imm >> 6) & 0x3)], + arr[4], arr[5], arr[6], arr[7] + }); +} +#endif + +#define _mm_unpackhi_epi8(a, b) (vzip2q_s8((a), (b))) +#define _mm_unpackhi_epi16(a, b) (vreinterpretq_s8_s16(vzip2q_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) +#define _mm_unpackhi_epi32(a, b) (vreinterpretq_s8_s32(vzip2q_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) +#define _mm_unpackhi_epi64(a, b) (vreinterpretq_s8_s64(vzip2q_s64(vreinterpretq_s64_s8(a), vreinterpretq_s64_s8(b)))) + +#define _mm_unpacklo_epi8(a, b) (vzip1q_s8((a), (b))) +#define _mm_unpacklo_epi16(a, b) (vreinterpretq_s8_s16(vzip1q_s16(vreinterpretq_s16_s8(a), vreinterpretq_s16_s8(b)))) +#define _mm_unpacklo_epi32(a, b) (vreinterpretq_s8_s32(vzip1q_s32(vreinterpretq_s32_s8(a), vreinterpretq_s32_s8(b)))) +#define _mm_unpacklo_epi64(a, b) (vreinterpretq_s8_s64(vzip1q_s64(vreinterpretq_s64_s8(a), vreinterpretq_s64_s8(b)))) + +#define _mm_move_epi64(x) (vreinterpretq_s8_s64((int64x2_t) { vgetq_lane_s64(vreinterpretq_s64_s8(x), 0), 0 })) + +#endif + +#endif /* XSSE_H */ diff --git a/Zend/zend_types.h b/Zend/zend_types.h index a3d3e4da6362d..43aa2aa86a00e 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -62,19 +62,8 @@ typedef enum { typedef ZEND_RESULT_CODE zend_result; -#ifdef ZEND_ENABLE_ZVAL_LONG64 -# ifdef ZEND_WIN32 -# define ZEND_SIZE_MAX _UI64_MAX -# else -# define ZEND_SIZE_MAX SIZE_MAX -# endif -#else -# if defined(ZEND_WIN32) -# define ZEND_SIZE_MAX _UI32_MAX -# else -# define ZEND_SIZE_MAX SIZE_MAX -# endif -#endif +/* This constant is deprecated, use SIZE_MAX instead */ +#define ZEND_SIZE_MAX SIZE_MAX #ifdef ZTS #define ZEND_TLS static TSRM_TLS diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 07a0ecf1e2631..1b91f11662c7a 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -9800,7 +9800,7 @@ ZEND_VM_HANDLER(204, ZEND_FRAMELESS_ICALL_0, UNUSED, UNUSED, SPEC(OBSERVER)) #endif { zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline); - function(EX_VAR(opline->result.var)); + function(result); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a6b79495d7c03..801bf0ee69e0d 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -39304,7 +39304,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA #endif { zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline); - function(EX_VAR(opline->result.var)); + function(result); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -39324,7 +39324,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICA #endif { zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline); - function(EX_VAR(opline->result.var)); + function(result); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -94770,7 +94770,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_0_ #endif { zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline); - function(EX_VAR(opline->result.var)); + function(result); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -94790,7 +94790,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_0_ #endif { zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline); - function(EX_VAR(opline->result.var)); + function(result); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_weakrefs.c b/Zend/zend_weakrefs.c index 83a28808811d5..8c1263885bf6c 100644 --- a/Zend/zend_weakrefs.c +++ b/Zend/zend_weakrefs.c @@ -776,9 +776,7 @@ ZEND_METHOD(WeakMap, offsetUnset) ZEND_METHOD(WeakMap, count) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_long count; zend_weakmap_count_elements(Z_OBJ_P(ZEND_THIS), &count); @@ -787,9 +785,7 @@ ZEND_METHOD(WeakMap, count) ZEND_METHOD(WeakMap, getIterator) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_create_internal_iterator_zval(return_value, ZEND_THIS); } diff --git a/build/gen_stub.php b/build/gen_stub.php index acee1e6ca0981..fcf33cd0b9dd5 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2215,11 +2215,11 @@ public function toArgInfoCode(?int $minPHPCompatability): string { $this->numRequiredArgs, $minPHPCompatability === null || $minPHPCompatability >= PHP_81_VERSION_ID ); - + foreach ($this->args as $argInfo) { $code .= $argInfo->toZendInfo(); } - + $code .= "ZEND_END_ARG_INFO()"; return $code . "\n"; } @@ -4310,13 +4310,13 @@ protected function pName_FullyQualified(Name\FullyQualified $node): string { return implode('\\', $node->getParts()); } }; - + $stmts = $parser->parse($code); $nodeTraverser->traverse($stmts); - + $fileTags = DocCommentTag::parseDocComments(self::getFileDocComments($stmts)); $fileInfo = new FileInfo($fileTags); - + $fileInfo->handleStatements($stmts, $prettyPrinter); return $fileInfo; } @@ -4337,16 +4337,16 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri $conds = []; foreach ($stmts as $stmt) { $cond = self::handlePreprocessorConditions($conds, $stmt); - + if ($stmt instanceof Stmt\Nop) { continue; } - + if ($stmt instanceof Stmt\Namespace_) { $this->handleStatements($stmt->stmts, $prettyPrinter); continue; } - + if ($stmt instanceof Stmt\Const_) { foreach ($stmt->consts as $const) { $this->constInfos[] = parseConstLike( @@ -4364,7 +4364,7 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri } continue; } - + if ($stmt instanceof Stmt\Function_) { $this->funcInfos[] = parseFunctionLike( $prettyPrinter, @@ -4378,7 +4378,7 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri ); continue; } - + if ($stmt instanceof Stmt\ClassLike) { $className = $stmt->namespacedName; $constInfos = []; @@ -4390,10 +4390,10 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri if ($classStmt instanceof Stmt\Nop) { continue; } - + $classFlags = $stmt instanceof Class_ ? $stmt->flags : 0; $abstractFlag = $stmt instanceof Stmt\Interface_ ? Modifiers::ABSTRACT : 0; - + if ($classStmt instanceof Stmt\ClassConst) { foreach ($classStmt->consts as $const) { $constInfos[] = parseConstLike( @@ -4447,7 +4447,7 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri throw new Exception("Not implemented {$classStmt->getType()}"); } } - + $this->classInfos[] = parseClass( $className, $stmt, @@ -4461,7 +4461,7 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri ); continue; } - + if ($stmt instanceof Stmt\Expression) { $expr = $stmt->expr; if ($expr instanceof Expr\Include_) { @@ -4469,7 +4469,7 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri continue; } } - + throw new Exception("Unexpected node {$stmt->getType()}"); } if (!empty($conds)) { @@ -4501,7 +4501,7 @@ private static function handlePreprocessorConditions(array &$conds, Stmt $stmt): throw new Exception("Unrecognized preprocessor directive \"$text\""); } } - + return empty($conds) ? null : implode(' && ', $conds); } @@ -4540,7 +4540,7 @@ public function getType(): string { $matches = []; if ($this->name === "param") { - preg_match('/^\s*([\w\|\\\\\[\]<>, ]+)\s*(?:[{(]|\$\w+).*$/', $value, $matches); + preg_match('/^\s*([\w\|\\\\\[\]<>, ]+)\s*(?:[{(]|(\.\.\.)?\$\w+).*$/', $value, $matches); } elseif ($this->name === "return" || $this->name === "var") { preg_match('/^\s*([\w\|\\\\\[\]<>, ]+)/', $value, $matches); } @@ -4562,7 +4562,7 @@ public function getVariableName(): string { if ($this->name === "param") { // Allow for parsing extended types like callable(string):mixed in docblocks - preg_match('/^\s*(?[\w\|\\\\]+(?\((?(?:(?&parens)|[^(){}[\]<>]*+))++\)|\{(?&inparens)\}|\[(?&inparens)\]|<(?&inparens)>)*+(?::(?&type))?)\s*\$(?\w+).*$/', $value, $matches); + preg_match('/^\s*(?[\w\|\\\\]+(?\((?(?:(?&parens)|[^(){}[\]<>]*+))++\)|\{(?&inparens)\}|\[(?&inparens)\]|<(?&inparens)>)*+(?::(?&type))?)\s*(\.\.\.)?\$(?\w+).*$/', $value, $matches); } elseif ($this->name === "prefer-ref") { preg_match('/^\s*\$(?\w+).*$/', $value, $matches); } @@ -6048,9 +6048,10 @@ function installPhpParser(string $version, string $phpParserDir) { chdir(__DIR__); $tarName = "v$version.tar.gz"; - passthru("wget https://github.com/nikic/PHP-Parser/archive/$tarName", $exit); + $downloadUrl = "https://github.com/nikic/PHP-Parser/archive/$tarName"; + passthru("wget -O $tarName $downloadUrl", $exit); if ($exit !== 0) { - passthru("curl -LO https://github.com/nikic/PHP-Parser/archive/$tarName", $exit); + passthru("curl -LO $downloadUrl", $exit); } if ($exit !== 0) { throw new Exception("Failed to download PHP-Parser tarball"); @@ -6060,6 +6061,7 @@ function installPhpParser(string $version, string $phpParserDir) { } passthru("tar xvzf $tarName -C PHP-Parser-$version --strip-components 1", $exit); if ($exit !== 0) { + rmdir($phpParserDir); throw new Exception("Failed to extract PHP-Parser tarball"); } unlink(__DIR__ . "/$tarName"); diff --git a/docs/release-process.md b/docs/release-process.md index 08b95df53513f..e053728feb0aa 100644 --- a/docs/release-process.md +++ b/docs/release-process.md @@ -169,10 +169,10 @@ slightly different steps. We'll call attention where the steps differ. 4. Using your local-only release branch, bump the version numbers in `main/php_version.h`, `Zend/zend.h`, `configure.ac`, and possibly `NEWS`. - + The date for NEWS should be the date of the announcement (Thursday), *not* the date of the tagging (Tuesday). - + For examples, see [Update versions for PHP 8.1.0beta3][] (for a pre-GA example) or [Update versions for PHP 8.1.6RC1][] along with [Update NEWS for PHP 8.1.6RC1][] (for a post-GA example). @@ -506,8 +506,8 @@ slightly different steps. We'll call attention where the steps differ. You can send a PR to [toot-together](https://github.com/derickr/toot-together/) with highlights from the NEWS file yourself, if you want. - * [Annonce 8.5.0alpha1](https://github.com/derickr/toot-together/pull/42) - * [Annonce 8.5.0alpha2](https://github.com/derickr/toot-together/pull/47) + * [Announce 8.5.0alpha1](https://github.com/derickr/toot-together/pull/42) + * [Announce 8.5.0alpha2](https://github.com/derickr/toot-together/pull/47) We post to [@php@fosstodon.org](https://fosstodon.org/@php). diff --git a/docs/source/miscellaneous/stubs.rst b/docs/source/miscellaneous/stubs.rst index 616d306895542..395034afe8d5d 100644 --- a/docs/source/miscellaneous/stubs.rst +++ b/docs/source/miscellaneous/stubs.rst @@ -489,7 +489,7 @@ generated. You can include this file conditionally, such as: #endif When ``@generate-legacy-arginfo`` is passed the minimum PHP version ID that needs to be supported, -then only one arginfo file is going to be generated, and ``#if`` prepocessor directives will ensure +then only one arginfo file is going to be generated, and ``#if`` preprocessor directives will ensure compatibility with all the required PHP 8 versions. PHP Version IDs are as follows: ``80000`` for PHP 8.0, ``80100`` for PHP PHP 8.1, ``80200`` for PHP diff --git a/docs/source/miscellaneous/writing-tests.rst b/docs/source/miscellaneous/writing-tests.rst index fd09d80f1275e..4c46dad638b6c 100644 --- a/docs/source/miscellaneous/writing-tests.rst +++ b/docs/source/miscellaneous/writing-tests.rst @@ -132,7 +132,7 @@ below illustrates a minimal test. string(32) "# hello All, I sAid hi planet! #" As you can see the file is divided into several sections. The TEST section holds a one line title of -the phpt test, this should be a simple description and shouldn't ever excede one line, if you need +the phpt test, this should be a simple description and shouldn't ever exceed one line, if you need to write more explanation add comments in the body of the test case. The phpt files name is used when generating a .php file. The FILE section is used as the body of the .php file, so don't forget to open and close your php tags. The EXPECT section is the part used as a comparison to see if the @@ -580,7 +580,7 @@ Example 1 (snippet): .. code:: text --DESCRIPTION-- - This test covers both valid and invalid usages of filter_input() with INPUT_GET and INPUT_POST data and several differnet filter sanitizers. + This test covers both valid and invalid usages of filter_input() with INPUT_GET and INPUT_POST data and several different filter sanitizers. Example 1 (full): :ref:`sample001.phpt` @@ -1310,7 +1310,7 @@ Example 1 (full): :ref:`sample017.phpt` ``--FLAKY--`` ------------- -**Description:** This section identifies this test as one that occassionally fails. If the test +**Description:** This section identifies this test as one that occasionally fails. If the test actually fails, it will be retried one more time, and that result will be reported. The section should include a brief description of why the test is flaky. Reasons for this include tests that rely on relatively precise timing, or temporary disc states. Available as of PHP 8.1.22 and 8.2.9, @@ -1884,7 +1884,7 @@ sample001.phpt --DESCRIPTION-- This test covers both valid and invalid usages of filter_input() with INPUT_GET and INPUT_POST data - and several differnt filter sanitizers. + and several different filter sanitizers. --CREDITS-- Felipe Pena --INI-- diff --git a/ext/bz2/bz2.c b/ext/bz2/bz2.c index e7491f12cf315..a8153d7d11938 100644 --- a/ext/bz2/bz2.c +++ b/ext/bz2/bz2.c @@ -476,8 +476,15 @@ PHP_FUNCTION(bzcompress) + .01 x length of data + 600 which is the largest size the results of the compression could possibly be, at least that's what the libbz2 docs say (thanks to jeremy@nirvani.net for pointing this out). */ - // TODO Check source string length fits in unsigned int - dest_len = (unsigned int) (source_len + (0.01 * source_len) + 600); + size_t chunk_len = source_len + source_len / 100 + 600; + const size_t min = MIN(ZSTR_MAX_LEN, UINT_MAX); + + if (chunk_len < source_len || chunk_len > min) { + zend_argument_value_error(1, "must have a length less than or equal to %zu", min); + RETURN_THROWS(); + } + + dest_len = (unsigned int) chunk_len; /* Allocate the destination buffer */ dest = zend_string_alloc(dest_len, 0); @@ -504,11 +511,7 @@ PHP_FUNCTION(bzdecompress) size_t source_len; int error; bool small = 0; -#ifdef PHP_WIN32 - unsigned __int64 size = 0; -#else - unsigned long long size = 0; -#endif + uint64_t size = 0; bz_stream bzs; if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &source, &source_len, &small)) { @@ -535,26 +538,22 @@ PHP_FUNCTION(bzdecompress) /* compression is better then 2:1, need to allocate more memory */ bzs.avail_out = source_len; size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32; -#ifndef ZEND_ENABLE_ZVAL_LONG64 - if (size > SIZE_MAX) { + if (UNEXPECTED(size > SIZE_MAX)) { /* no reason to continue if we're going to drop it anyway */ break; } -#endif + dest = zend_string_safe_realloc(dest, 1, bzs.avail_out+1, (size_t) size, 0); bzs.next_out = ZSTR_VAL(dest) + size; } if (error == BZ_STREAM_END || error == BZ_OK) { size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32; -#ifndef ZEND_ENABLE_ZVAL_LONG64 if (UNEXPECTED(size > SIZE_MAX)) { - php_error_docref(NULL, E_WARNING, "Decompressed size too big, max is %zd", SIZE_MAX); + php_error_docref(NULL, E_WARNING, "Decompressed size too big, max is %zu", SIZE_MAX); zend_string_efree(dest); RETVAL_LONG(BZ_MEM_ERROR); - } else -#endif - { + } else { dest = zend_string_safe_realloc(dest, 1, (size_t)size, 1, 0); ZSTR_LEN(dest) = (size_t)size; ZSTR_VAL(dest)[(size_t)size] = '\0'; diff --git a/ext/bz2/bz2_filter.c b/ext/bz2/bz2_filter.c index 2fbdf9452dad3..27059391dacb9 100644 --- a/ext/bz2/bz2_filter.c +++ b/ext/bz2/bz2_filter.c @@ -337,12 +337,14 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi zval *tmpzval = NULL; if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) { - if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated")-1))) { + HashTable *ht = HASH_OF(filterparams); + + if ((tmpzval = zend_hash_str_find_ind(ht, "concatenated", sizeof("concatenated")-1))) { data->expect_concatenated = zend_is_true(tmpzval); tmpzval = NULL; } - tmpzval = zend_hash_str_find(HASH_OF(filterparams), "small", sizeof("small")-1); + tmpzval = zend_hash_str_find_ind(ht, "small", sizeof("small")-1); } else { tmpzval = filterparams; } @@ -362,7 +364,9 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi zval *tmpzval; if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) { - if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "blocks", sizeof("blocks")-1))) { + HashTable *ht = HASH_OF(filterparams); + + if ((tmpzval = zend_hash_str_find_ind(ht, "blocks", sizeof("blocks")-1))) { /* How much memory to allocate (1 - 9) x 100kb */ zend_long blocks = zval_get_long(tmpzval); if (blocks < 1 || blocks > 9) { @@ -372,7 +376,7 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi } } - if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "work", sizeof("work")-1))) { + if ((tmpzval = zend_hash_str_find_ind(ht, "work", sizeof("work")-1))) { /* Work Factor (0 - 250) */ zend_long work = zval_get_long(tmpzval); if (work < 0 || work > 250) { diff --git a/ext/bz2/tests/filter_broken_object_options.phpt b/ext/bz2/tests/filter_broken_object_options.phpt new file mode 100644 index 0000000000000..84e49a64ccb62 --- /dev/null +++ b/ext/bz2/tests/filter_broken_object_options.phpt @@ -0,0 +1,25 @@ +--TEST-- +bz2 filter assertion failure with non-dynamic properties in filter param object +--EXTENSIONS-- +bz2 +--FILE-- + +--EXPECT-- +Hello world, hopefully not broken diff --git a/ext/bz2/tests/gh20620.phpt b/ext/bz2/tests/gh20620.phpt new file mode 100644 index 0000000000000..351ba488b2bd6 --- /dev/null +++ b/ext/bz2/tests/gh20620.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug GH-20620 (bzcompress with large source) +--EXTENSIONS-- +bz2 +--SKIPIF-- + +--INI-- +memory_limit=-1 +--FILE-- +getMessage(), PHP_EOL; +} +?> +--EXPECTF-- +bzcompress(): Argument #1 ($data) must have a length less than or equal to %d diff --git a/ext/dom/document.c b/ext/dom/document.c index 8c54418620561..b46722d854c5e 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1597,12 +1597,16 @@ PHP_METHOD(DOMDocument, save) libxml_doc_props const* doc_props = dom_get_doc_props_read_only(intern->document); bool format = doc_props->formatoutput; if (options & LIBXML_SAVE_NOEMPTYTAG) { + ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") saveempty = xmlSaveNoEmptyTags; xmlSaveNoEmptyTags = 1; + ZEND_DIAGNOSTIC_IGNORED_END } zend_long bytes = intern->document->handlers->dump_doc_to_file(file, docp, format, (const char *) docp->encoding); if (options & LIBXML_SAVE_NOEMPTYTAG) { + ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") xmlSaveNoEmptyTags = saveempty; + ZEND_DIAGNOSTIC_IGNORED_END } if (bytes == -1) { RETURN_FALSE; @@ -1643,10 +1647,14 @@ static void dom_document_save_xml(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry /* Save libxml2 global, override its value, and restore after saving (don't move me or risk breaking the state * w.r.t. the implicit return in DOM_GET_OBJ). */ + ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") old_xml_save_no_empty_tags = xmlSaveNoEmptyTags; xmlSaveNoEmptyTags = (options & LIBXML_SAVE_NOEMPTYTAG) ? 1 : 0; + ZEND_DIAGNOSTIC_IGNORED_END res = intern->document->handlers->dump_node_to_str(docp, node, format, (const char *) docp->encoding); + ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") xmlSaveNoEmptyTags = old_xml_save_no_empty_tags; + ZEND_DIAGNOSTIC_IGNORED_END } else { int converted_options = XML_SAVE_AS_XML; if (options & XML_SAVE_NO_DECL) { @@ -1657,10 +1665,14 @@ static void dom_document_save_xml(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry } /* Save libxml2 global, override its value, and restore after saving. */ + ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") old_xml_save_no_empty_tags = xmlSaveNoEmptyTags; xmlSaveNoEmptyTags = (options & LIBXML_SAVE_NOEMPTYTAG) ? 1 : 0; + ZEND_DIAGNOSTIC_IGNORED_END res = intern->document->handlers->dump_doc_to_str(docp, converted_options, (const char *) docp->encoding); + ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") xmlSaveNoEmptyTags = old_xml_save_no_empty_tags; + ZEND_DIAGNOSTIC_IGNORED_END } if (!res) { diff --git a/ext/dom/element.c b/ext/dom/element.c index cf1a762768a87..797f215e173d1 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -1210,19 +1210,17 @@ Since: DOM Level 2 */ PHP_METHOD(DOMElement, getAttributeNodeNS) { - zval *id; xmlNodePtr elemp; xmlAttrPtr attrp; dom_object *intern; size_t uri_len, name_len; char *uri, *name; - id = ZEND_THIS; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &uri_len, &name, &name_len) == FAILURE) { RETURN_THROWS(); } - DOM_GET_OBJ(elemp, id, xmlNodePtr, intern); + DOM_GET_OBJ(elemp, ZEND_THIS, xmlNodePtr, intern); bool follow_spec = php_dom_follow_spec_intern(intern); if (follow_spec && uri_len == 0) { @@ -1239,16 +1237,11 @@ PHP_METHOD(DOMElement, getAttributeNodeNS) /* Keep parent alive, because we're a fake child. */ GC_ADDREF(&intern->std); (void) php_dom_create_fake_namespace_decl(elemp, nsptr, return_value, intern); - } else { - RETURN_NULL(); } - } else { - RETURN_NULL(); } } else { DOM_RET_OBJ((xmlNodePtr) attrp, intern); } - } /* }}} end dom_element_get_attribute_node_ns */ diff --git a/ext/dom/lexbor/selectors-adapted/selectors.c b/ext/dom/lexbor/selectors-adapted/selectors.c index b547a3a586b2e..0bb285b39e99b 100644 --- a/ext/dom/lexbor/selectors-adapted/selectors.c +++ b/ext/dom/lexbor/selectors-adapted/selectors.c @@ -35,7 +35,22 @@ static void dom_lxb_str_wrapper_release(dom_lxb_str_wrapper *wrapper) } } -static zend_always_inline bool lxb_selectors_adapted_cmp_local_name_literal(const xmlNode *node, const char *name) +static bool lxb_selectors_str_cmp_loright(const char *lhs, const char *rhs) +{ + while (true) { + if (*rhs != zend_tolower_ascii(*lhs)) { + return false; + } + if (!*lhs) { + return true; + } + ++rhs; + ++lhs; + } +} + +/* `name` is lowercase */ +static zend_always_inline bool lxb_selectors_cmp_html_name_lit(const xmlNode *node, const char *name) { return strcmp((const char *) node->name, name) == 0; } @@ -48,14 +63,15 @@ static zend_always_inline bool lxb_selectors_adapted_cmp_ns(const xmlNode *a, co static zend_always_inline bool lxb_selectors_adapted_cmp_local_name_id(const xmlNode *node, const lxb_selectors_adapted_id *id) { - uintptr_t ptr = (uintptr_t) node->name; - if (id->interned && (ptr & (ZEND_MM_ALIGNMENT - 1)) != 0) { - /* It cannot be a heap-allocated string because the pointer is not properly aligned for a heap allocation. - * Therefore, it must be interned into the dictionary pool. */ - return node->name == id->name; + ZEND_ASSERT(node->doc != NULL); + if (php_dom_ns_is_html_and_document_is_html(node)) { + /* From https://html.spec.whatwg.org/#case-sensitivity-of-selectors: + * The element name must be compared case sensitively _after_ converting the selector to lowercase. + * E.g. selector "DIV" must match element "div" but not "Div". */ + return lxb_selectors_str_cmp_loright((const char *) id->name, (const char *) node->name); + } else { + return strcmp((const char *) node->name, (const char *) id->name) == 0; } - - return strcmp((const char *) node->name, (const char *) id->name) == 0; } static zend_always_inline const xmlAttr *lxb_selectors_adapted_attr(const xmlNode *node, const lxb_char_t *name) @@ -64,9 +80,8 @@ static zend_always_inline const xmlAttr *lxb_selectors_adapted_attr(const xmlNod ZEND_ASSERT(node->doc != NULL); if (php_dom_ns_is_html_and_document_is_html(node)) { /* No need to handle DTD entities as we're in HTML. */ - size_t name_bound = strlen((const char *) name) + 1; for (const xmlAttr *cur = node->properties; cur != NULL; cur = cur->next) { - if (lexbor_str_data_nlocmp_right(cur->name, name, name_bound)) { + if (lxb_selectors_str_cmp_loright((const char *) name, (const char *) cur->name)) { attr = cur; break; } @@ -154,18 +169,7 @@ static bool lxb_selectors_is_lowercased_html_attrib_name(const lxb_css_selector_ static void lxb_selectors_adapted_set_entry_id_ex(lxb_selectors_entry_t *entry, const lxb_css_selector_t *selector, const xmlNode *node) { entry->id.attr_case_insensitive = lxb_selectors_is_lowercased_html_attrib_name(selector); - - if (node->doc != NULL && node->doc->dict != NULL) { - const xmlChar *interned = xmlDictExists(node->doc->dict, selector->name.data, selector->name.length); - if (interned != NULL) { - entry->id.name = interned; - entry->id.interned = true; - return; - } - } - entry->id.name = selector->name.data; - entry->id.interned = false; } static zend_always_inline void lxb_selectors_adapted_set_entry_id(lxb_selectors_entry_t *entry, const lxb_css_selector_t *selector, const xmlNode *node) @@ -1686,8 +1690,8 @@ lxb_selectors_pseudo_class(const lxb_css_selector_t *selector, case LXB_CSS_SELECTOR_PSEUDO_CLASS_ANY_LINK: /* https://drafts.csswg.org/selectors/#the-any-link-pseudo */ if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token) - && (lxb_selectors_adapted_cmp_local_name_literal(node, "a") - || lxb_selectors_adapted_cmp_local_name_literal(node, "area"))) + && (lxb_selectors_cmp_html_name_lit(node, "a") + || lxb_selectors_cmp_html_name_lit(node, "area"))) { return lxb_selectors_adapted_has_attr(node, "href"); } @@ -1705,7 +1709,7 @@ lxb_selectors_pseudo_class(const lxb_css_selector_t *selector, if (!php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token)) { return false; } - if (lxb_selectors_adapted_cmp_local_name_literal(node, "input")) { + if (lxb_selectors_cmp_html_name_lit(node, "input")) { const xmlAttr *dom_attr = lxb_selectors_adapted_attr(node, (const lxb_char_t *) "type"); if (dom_attr == NULL) { return false; @@ -1729,7 +1733,7 @@ lxb_selectors_pseudo_class(const lxb_css_selector_t *selector, return res; } - else if(lxb_selectors_adapted_cmp_local_name_literal(node, "option")) { + else if(lxb_selectors_cmp_html_name_lit(node, "option")) { return lxb_selectors_adapted_has_attr(node, "selected"); } @@ -1802,8 +1806,8 @@ lxb_selectors_pseudo_class(const lxb_css_selector_t *selector, case LXB_CSS_SELECTOR_PSEUDO_CLASS_LINK: /* https://html.spec.whatwg.org/multipage/semantics-other.html#selector-link */ if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token) - && (lxb_selectors_adapted_cmp_local_name_literal(node, "a") - || lxb_selectors_adapted_cmp_local_name_literal(node, "area"))) + && (lxb_selectors_cmp_html_name_lit(node, "a") + || lxb_selectors_cmp_html_name_lit(node, "area"))) { return lxb_selectors_adapted_has_attr(node, "href"); } @@ -1823,9 +1827,9 @@ lxb_selectors_pseudo_class(const lxb_css_selector_t *selector, case LXB_CSS_SELECTOR_PSEUDO_CLASS_OPTIONAL: if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token) - && (lxb_selectors_adapted_cmp_local_name_literal(node, "input") - || lxb_selectors_adapted_cmp_local_name_literal(node, "select") - || lxb_selectors_adapted_cmp_local_name_literal(node, "textarea"))) + && (lxb_selectors_cmp_html_name_lit(node, "input") + || lxb_selectors_cmp_html_name_lit(node, "select") + || lxb_selectors_cmp_html_name_lit(node, "textarea"))) { return !lxb_selectors_adapted_has_attr(node, "required"); } @@ -1840,8 +1844,8 @@ lxb_selectors_pseudo_class(const lxb_css_selector_t *selector, case LXB_CSS_SELECTOR_PSEUDO_CLASS_PLACEHOLDER_SHOWN: if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token) - && (lxb_selectors_adapted_cmp_local_name_literal(node, "input") - || lxb_selectors_adapted_cmp_local_name_literal(node, "textarea"))) + && (lxb_selectors_cmp_html_name_lit(node, "input") + || lxb_selectors_cmp_html_name_lit(node, "textarea"))) { return lxb_selectors_adapted_has_attr(node, "placeholder"); } @@ -1856,9 +1860,9 @@ lxb_selectors_pseudo_class(const lxb_css_selector_t *selector, case LXB_CSS_SELECTOR_PSEUDO_CLASS_REQUIRED: if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token) - && (lxb_selectors_adapted_cmp_local_name_literal(node, "input") - || lxb_selectors_adapted_cmp_local_name_literal(node, "select") - || lxb_selectors_adapted_cmp_local_name_literal(node, "textarea"))) + && (lxb_selectors_cmp_html_name_lit(node, "input") + || lxb_selectors_cmp_html_name_lit(node, "select") + || lxb_selectors_cmp_html_name_lit(node, "textarea"))) { return lxb_selectors_adapted_has_attr(node, "required"); } @@ -2104,24 +2108,24 @@ lxb_selectors_pseudo_class_disabled(const xmlNode *node) } if (lxb_selectors_adapted_has_attr(node, "disabled") - && (lxb_selectors_adapted_cmp_local_name_literal(node, "button") - || lxb_selectors_adapted_cmp_local_name_literal(node, "input") - || lxb_selectors_adapted_cmp_local_name_literal(node, "select") - || lxb_selectors_adapted_cmp_local_name_literal(node, "textarea") - || lxb_selectors_adapted_cmp_local_name_literal(node, "optgroup") - || lxb_selectors_adapted_cmp_local_name_literal(node, "fieldset"))) + && (lxb_selectors_cmp_html_name_lit(node, "button") + || lxb_selectors_cmp_html_name_lit(node, "input") + || lxb_selectors_cmp_html_name_lit(node, "select") + || lxb_selectors_cmp_html_name_lit(node, "textarea") + || lxb_selectors_cmp_html_name_lit(node, "optgroup") + || lxb_selectors_cmp_html_name_lit(node, "fieldset"))) { return true; } - if (lxb_selectors_adapted_cmp_local_name_literal(node, "fieldset")) { + if (lxb_selectors_cmp_html_name_lit(node, "fieldset")) { const xmlNode *fieldset = node; node = node->parent; while (node != NULL && CMP_NODE_TYPE(node, XML_ELEMENT_NODE)) { /* node is a disabled fieldset that is an ancestor of fieldset */ if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token) - && lxb_selectors_adapted_cmp_local_name_literal(node, "fieldset") + && lxb_selectors_cmp_html_name_lit(node, "fieldset") && lxb_selectors_adapted_has_attr(node, "disabled")) { /* Search first legend child and figure out if fieldset is a descendent from that. */ @@ -2129,7 +2133,7 @@ lxb_selectors_pseudo_class_disabled(const xmlNode *node) do { if (search_current->type == XML_ELEMENT_NODE && php_dom_ns_is_fast(search_current, php_dom_ns_is_html_magic_token) - && lxb_selectors_adapted_cmp_local_name_literal(search_current, "legend")) { + && lxb_selectors_cmp_html_name_lit(search_current, "legend")) { /* search_current is a legend element. */ const xmlNode *inner_search_current = fieldset; @@ -2235,8 +2239,8 @@ static bool lxb_selectors_pseudo_class_read_write(const xmlNode *node) { if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token)) { - if (lxb_selectors_adapted_cmp_local_name_literal(node, "input") - || lxb_selectors_adapted_cmp_local_name_literal(node, "textarea")) { + if (lxb_selectors_cmp_html_name_lit(node, "input") + || lxb_selectors_cmp_html_name_lit(node, "textarea")) { return !lxb_selectors_adapted_has_attr(node, "readonly") && !lxb_selectors_adapted_has_attr(node, "disabled"); } else { const xmlAttr *attr = lxb_selectors_adapted_attr(node, (const lxb_char_t *) "contenteditable"); diff --git a/ext/dom/lexbor/selectors-adapted/selectors.h b/ext/dom/lexbor/selectors-adapted/selectors.h index c0f76cce3d5cc..b64a9e49ee262 100644 --- a/ext/dom/lexbor/selectors-adapted/selectors.h +++ b/ext/dom/lexbor/selectors-adapted/selectors.h @@ -77,7 +77,6 @@ typedef lxb_selectors_entry_t * typedef struct { const xmlChar *name; - bool interned; bool attr_case_insensitive; } lxb_selectors_adapted_id; diff --git a/ext/dom/node.c b/ext/dom/node.c index 40aaf27669268..d89d49124fd9d 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -1878,8 +1878,7 @@ static void dom_node_lookup_prefix(INTERNAL_FUNCTION_PARAMETERS, bool modern) case XML_DOCUMENT_FRAG_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_DTD_NODE: - RETURN_NULL(); - break; + return; default: lookupp = nodep->parent; } @@ -1898,8 +1897,6 @@ static void dom_node_lookup_prefix(INTERNAL_FUNCTION_PARAMETERS, bool modern) } } } - - RETURN_NULL(); } PHP_METHOD(DOMNode, lookupPrefix) @@ -2065,16 +2062,14 @@ PHP_METHOD(DOMNode, lookupNamespaceURI) prefix = NULL; } const char *ns_uri = dom_locate_a_namespace(nodep, prefix); - if (ns_uri == NULL) { - RETURN_NULL(); - } else { + if (ns_uri != NULL) { RETURN_STRING(ns_uri); } } else { if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) { nodep = xmlDocGetRootElement((xmlDocPtr) nodep); if (nodep == NULL) { - RETURN_NULL(); + return; } } @@ -2083,11 +2078,100 @@ PHP_METHOD(DOMNode, lookupNamespaceURI) RETURN_STRING((char *) nsptr->href); } } - - RETURN_NULL(); } /* }}} end dom_node_lookup_namespace_uri */ +static void dom_relink_ns_decls_element(HashTable *links, xmlNodePtr node) +{ + if (node->type == XML_ELEMENT_NODE) { + for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) { + if (php_dom_ns_is_fast((const xmlNode *) attr, php_dom_ns_is_xmlns_magic_token)) { + xmlNsPtr ns = xmlMalloc(sizeof(*ns)); + if (!ns) { + return; + } + + zval *zv = zend_hash_index_lookup(links, (zend_ulong) node); + if (Z_ISNULL_P(zv)) { + ZVAL_LONG(zv, 1); + } else { + Z_LVAL_P(zv)++; + } + + bool should_free; + xmlChar *attr_value = php_libxml_attr_value(attr, &should_free); + + memset(ns, 0, sizeof(*ns)); + ns->type = XML_LOCAL_NAMESPACE; + ns->href = should_free ? attr_value : xmlStrdup(attr_value); + ns->prefix = attr->ns->prefix ? xmlStrdup(attr->name) : NULL; + ns->next = node->nsDef; + node->nsDef = ns; + + ns->_private = attr; + if (attr->prev) { + attr->prev = attr->next; + } else { + node->properties = attr->next; + } + if (attr->next) { + attr->next->prev = attr->prev; + } + } + } + + /* The default namespace is handled separately from the other namespaces in C14N. + * The default namespace is explicitly looked up while the other namespaces are + * deduplicated and compared to a list of visible namespaces. */ + if (node->ns && !node->ns->prefix) { + /* Workaround for the behaviour where the xmlSearchNs() call inside c14n.c + * can return the current namespace. */ + zend_hash_index_add_new_ptr(links, (zend_ulong) node | 1, node->ns); + node->ns = xmlSearchNs(node->doc, node, NULL); + } + } +} + +static void dom_relink_ns_decls(HashTable *links, xmlNodePtr root) +{ + dom_relink_ns_decls_element(links, root); + + xmlNodePtr base = root; + xmlNodePtr node = base->children; + while (node != NULL) { + dom_relink_ns_decls_element(links, node); + node = php_dom_next_in_tree_order(node, base); + } +} + +static void dom_unlink_ns_decls(HashTable *links) +{ + ZEND_HASH_MAP_FOREACH_NUM_KEY_VAL(links, zend_ulong h, zval *data) { + if (h & 1) { + xmlNodePtr node = (xmlNodePtr) (h ^ 1); + node->ns = Z_PTR_P(data); + } else { + xmlNodePtr node = (xmlNodePtr) h; + while (Z_LVAL_P(data)-- > 0) { + xmlNsPtr ns = node->nsDef; + node->nsDef = ns->next; + + xmlAttrPtr attr = ns->_private; + if (attr->prev) { + attr->prev->next = attr; + } else { + node->properties = attr; + } + if (attr->next) { + attr->next->prev = attr; + } + + xmlFreeNs(ns); + } + } + } ZEND_HASH_FOREACH_END(); +} + static int dom_canonicalize_node_parent_lookup_cb(void *user_data, xmlNodePtr node, xmlNodePtr parent) { xmlNodePtr root = user_data; @@ -2133,7 +2217,7 @@ static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ } } else { if (zend_parse_parameters(ZEND_NUM_ARGS(), - "s|bba!a!", &file, &file_len, &exclusive, + "p|bba!a!", &file, &file_len, &exclusive, &with_comments, &xpath_array, &ns_prefixes) == FAILURE) { RETURN_THROWS(); } @@ -2143,7 +2227,23 @@ static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ docp = nodep->doc; - if (! docp) { + HashTable links; + bool modern = php_dom_follow_spec_node(nodep); + if (modern) { + xmlNodePtr root = nodep; + while (root->parent) { + root = root->parent; + } + + if (UNEXPECTED(root->type != XML_DOCUMENT_NODE && root->type != XML_HTML_DOCUMENT_NODE)) { + php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "Canonicalization can only happen on nodes attached to a document.", /* strict */ true); + RETURN_THROWS(); + } + + zend_hash_init(&links, 0, NULL, NULL, false); + dom_relink_ns_decls(&links, xmlDocGetRootElement(docp)); + } else if (!docp) { + /* Note: not triggerable with modern DOM */ zend_throw_error(NULL, "Node must be associated with a document"); RETURN_THROWS(); } @@ -2165,12 +2265,12 @@ static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ if (!tmp) { /* if mode == 0 then $xpath arg is 3, if mode == 1 then $xpath is 4 */ zend_argument_value_error(3 + mode, "must have a \"query\" key"); - RETURN_THROWS(); + goto clean_links; } if (Z_TYPE_P(tmp) != IS_STRING) { /* if mode == 0 then $xpath arg is 3, if mode == 1 then $xpath is 4 */ zend_argument_type_error(3 + mode, "\"query\" option must be a string, %s given", zend_zval_value_name(tmp)); - RETURN_THROWS(); + goto clean_links; } xquery = Z_STRVAL_P(tmp); @@ -2202,7 +2302,7 @@ static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ } xmlXPathFreeContext(ctxp); zend_throw_error(NULL, "XPath query did not return a nodeset"); - RETURN_THROWS(); + goto clean_links; } } @@ -2271,6 +2371,12 @@ static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ RETURN_LONG(bytes); } } + +clean_links: + if (modern) { + dom_unlink_ns_decls(&links); + zend_hash_destroy(&links); + } } /* }}} */ @@ -2294,13 +2400,12 @@ static void dom_node_get_node_path(INTERNAL_FUNCTION_PARAMETERS, bool throw) zval *id; xmlNode *nodep; dom_object *intern; - char *value; ZEND_PARSE_PARAMETERS_NONE(); DOM_GET_THIS_OBJ(nodep, id, xmlNodePtr, intern); - value = (char *) xmlGetNodePath(nodep); + char *value = (char *) xmlGetNodePath(nodep); if (value == NULL) { /* This is only possible when an invalid argument is passed (e.g. namespace declaration, but that's not the case for this call site), * or on allocation failure. So in other words, this only happens on allocation failure. */ @@ -2308,7 +2413,6 @@ static void dom_node_get_node_path(INTERNAL_FUNCTION_PARAMETERS, bool throw) php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true); RETURN_THROWS(); } - RETURN_NULL(); } else { RETVAL_STRING(value); xmlFree(value); diff --git a/ext/dom/notation.c b/ext/dom/notation.c index a15fae9ee9d8e..f83b31428e16c 100644 --- a/ext/dom/notation.c +++ b/ext/dom/notation.c @@ -31,8 +31,6 @@ * Since: */ -/* {{{ attribute protos, not implemented yet */ - /* {{{ publicId string readonly=yes URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-54F2B4D0 @@ -73,6 +71,4 @@ zend_result dom_notation_system_id_read(dom_object *obj, zval *retval) /* }}} */ -/* }}} */ - #endif diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 3619eaef12a5f..a39e5c1656e9e 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -714,15 +714,17 @@ static zend_object *dom_object_namespace_node_clone_obj(zend_object *zobject) zend_object *clone = dom_objects_namespace_node_new(intern->dom.std.ce); dom_object_namespace_node *clone_intern = php_dom_namespace_node_obj_from_obj(clone); - xmlNodePtr original_node = dom_object_get_node(&intern->dom); - ZEND_ASSERT(original_node->type == XML_NAMESPACE_DECL); - xmlNodePtr cloned_node = php_dom_create_fake_namespace_decl_node_ptr(original_node->parent, original_node->ns); - if (intern->parent_intern) { clone_intern->parent_intern = intern->parent_intern; GC_ADDREF(&clone_intern->parent_intern->std); } - dom_update_refcount_after_clone(&intern->dom, original_node, &clone_intern->dom, cloned_node); + + xmlNodePtr original_node = dom_object_get_node(&intern->dom); + if (original_node != NULL) { + ZEND_ASSERT(original_node->type == XML_NAMESPACE_DECL); + xmlNodePtr cloned_node = php_dom_create_fake_namespace_decl_node_ptr(original_node->parent, original_node->ns); + dom_update_refcount_after_clone(&intern->dom, original_node, &clone_intern->dom, cloned_node); + } zend_objects_clone_members(clone, &intern->dom.std); return clone; diff --git a/ext/dom/tests/DOMXPath_callables_errors.phpt b/ext/dom/tests/DOMXPath_callables_errors.phpt index d11437398b158..10019474e7e7f 100644 --- a/ext/dom/tests/DOMXPath_callables_errors.phpt +++ b/ext/dom/tests/DOMXPath_callables_errors.phpt @@ -57,6 +57,19 @@ try { echo $e->getMessage(), "\n"; } +$x = new class { + public static function dump() {} +}; + +$classes = get_declared_classes(); + +try { + $str = str_repeat($classes[count($classes) - 1] . '::dump', random_int(1, 1)); + $xpath->registerPhpFunctions([$str]); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} + ?> --EXPECT-- DOMXPath::registerPhpFunctions(): Argument #1 ($restrict) must be a callable, function "nonexistent" not found or invalid function name @@ -67,3 +80,4 @@ DOMXPath::registerPhpFunctions(): Argument #1 ($restrict) must be an array with DOMXPath::registerPhpFunctions(): Argument #1 ($restrict) must be an array containing valid callback names DOMXPath::registerPhpFunctions(): Argument #1 ($restrict) must be an array containing valid callback names DOMXPath::registerPhpFunctions(): Argument #1 ($restrict) must be a valid callback name +DOMXPath::registerPhpFunctions(): Argument #1 ($restrict) must be an array containing valid callback names diff --git a/ext/dom/tests/canonicalization.phpt b/ext/dom/tests/canonicalization.phpt index 4183b7cd41edc..fcd9b207bc24b 100644 --- a/ext/dom/tests/canonicalization.phpt +++ b/ext/dom/tests/canonicalization.phpt @@ -21,32 +21,46 @@ $dom = new DOMDocument(); $dom->loadXML($xml); $doc = $dom->documentElement->firstChild; +$newDom = Dom\XMLDocument::createFromString($xml); +$newDoc = $newDom->documentElement->firstChild; +$counter = 0; + +function check($doc, $newDoc, ...$args) { + global $counter; + $counter++; + echo $doc->C14N(...$args)."\n\n"; + if ($doc->C14N(...$args) !== $newDoc->C14N(...$args)) { + var_dump($doc->C14N(...$args), $newDoc->C14N(...$args)); + throw new Error("mismatch: $counter"); + } +} + /* inclusive/without comments first child element of doc element is context. */ -echo $doc->C14N()."\n\n"; +check($doc, $newDoc); /* exclusive/without comments first child element of doc element is context. */ -echo $doc->c14N(TRUE)."\n\n"; +check($doc, $newDoc, TRUE); /* inclusive/with comments first child element of doc element is context. */ -echo $doc->C14N(FALSE, TRUE)."\n\n"; +check($doc, $newDoc, FALSE, TRUE); /* exclusive/with comments first child element of doc element is context. */ -echo $doc->C14N(TRUE, TRUE)."\n\n"; +check($doc, $newDoc, TRUE, TRUE); /* exclusive/without comments using xpath query. */ -echo $doc->c14N(TRUE, FALSE, array('query'=>'(//. | //@* | //namespace::*)'))."\n\n"; +check($doc, $newDoc, TRUE, FALSE, array('query'=>'(//. | //@* | //namespace::*)'))."\n\n"; /* exclusive/without comments first child element of doc element is context. using xpath query with registered namespace. test namespace prefix is also included. */ -echo $doc->c14N(TRUE, FALSE, +check($doc, $newDoc, TRUE, FALSE, array('query'=>'(//a:contain | //a:bar | .//namespace::*)', 'namespaces'=>array('a'=>'http://www.example.com/ns/foo')), - array('test'))."\n\n"; + array('test')); /* exclusive/without comments first child element of doc element is context. test namespace prefix is also included */ -echo $doc->C14N(TRUE, FALSE, NULL, array('test')); +check($doc, $newDoc, TRUE, FALSE, NULL, array('test')); ?> --EXPECT-- diff --git a/ext/dom/tests/gh20722.phpt b/ext/dom/tests/gh20722.phpt new file mode 100644 index 0000000000000..38d3314618f3e --- /dev/null +++ b/ext/dom/tests/gh20722.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-20722 (Null pointer dereference in DOM namespace node cloning via clone on malformed objects) +--EXTENSIONS-- +dom +--FILE-- + +--EXPECT-- +Done diff --git a/ext/dom/tests/modern/css_selectors/gh20395.phpt b/ext/dom/tests/modern/css_selectors/gh20395.phpt new file mode 100644 index 0000000000000..af04cb1c27a42 --- /dev/null +++ b/ext/dom/tests/modern/css_selectors/gh20395.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-20395 (\Dom\ParentNode::querySelector and \Dom\ParentNode::querySelectorAll requires elements in $selectors to be lowercase) +--EXTENSIONS-- +dom +--CREDITS-- +DeveloperRob +--FILE-- +'; +$dom = Dom\HtmlDocument::createFromString($html); +var_dump(is_null($dom->querySelector('html'))); +var_dump(is_null($dom->querySelector('Html'))); +var_dump(is_null($dom->querySelector('HTML'))); + +$dom->body->appendChild($dom->createElement('div')); +$dom->body->appendChild($dom->createElementNS('http://www.w3.org/1999/xhtml', 'Div')); + +foreach ($dom->querySelectorAll('div') as $div) { + var_dump($div->localName); +} + +foreach ($dom->querySelectorAll('Div') as $div) { + var_dump($div->localName); +} + +?> +--EXPECT-- +bool(false) +bool(false) +bool(false) +string(3) "div" +string(3) "div" diff --git a/ext/dom/tests/modern/css_selectors/pseudo_classes_links.phpt b/ext/dom/tests/modern/css_selectors/pseudo_classes_links.phpt index 8a688286b6806..7afcb6e3cfbde 100644 --- a/ext/dom/tests/modern/css_selectors/pseudo_classes_links.phpt +++ b/ext/dom/tests/modern/css_selectors/pseudo_classes_links.phpt @@ -11,6 +11,7 @@ $dom = DOM\XMLDocument::createFromString(<< Link Link + Not actually a link Link XML); @@ -18,6 +19,7 @@ XML); test_helper($dom, ':any-link'); test_helper($dom, ':link'); test_helper($dom, 'a:not(:any-link)'); +test_helper($dom, ':not(:any-link)'); ?> --EXPECT-- @@ -29,3 +31,12 @@ test_helper($dom, 'a:not(:any-link)'); Link --- Selector: a:not(:any-link) --- Link +--- Selector: :not(:any-link) --- + + Link + Link + Not actually a link + Link + +Link +Not actually a link diff --git a/ext/dom/tests/modern/xml/canonicalize_unattached.phpt b/ext/dom/tests/modern/xml/canonicalize_unattached.phpt new file mode 100644 index 0000000000000..cec5f1085757b --- /dev/null +++ b/ext/dom/tests/modern/xml/canonicalize_unattached.phpt @@ -0,0 +1,20 @@ +--TEST-- +Canonicalize unattached node should fail +--EXTENSIONS-- +dom +--FILE-- +'); +$child = $d->documentElement->firstChild; +$child->remove(); + +try { + $child->C14N(); +} catch (Dom\DOMException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Canonicalization can only happen on nodes attached to a document. diff --git a/ext/dom/tests/modern/xml/gh20444.phpt b/ext/dom/tests/modern/xml/gh20444.phpt new file mode 100644 index 0000000000000..b3a77e3f13edb --- /dev/null +++ b/ext/dom/tests/modern/xml/gh20444.phpt @@ -0,0 +1,43 @@ +--TEST-- +GH-20444 (Dom\XMLDocument::C14N() seems broken compared to DOMDocument::C14N()) +--EXTENSIONS-- +dom +--FILE-- + + + + abc + +EOF; + +$d = \Dom\XMLDocument::createFromString($xml); +var_dump($d->C14N(true)); + +$xml = << + + + + 123 + + +EOF; + +$d = \Dom\XMLDocument::createFromString($xml); +var_dump($d->C14N()); + +?> +--EXPECT-- +string(128) " + + abc +" +string(134) " + + + 123 + +" diff --git a/ext/dom/xml_serializer.c b/ext/dom/xml_serializer.c index a4b46082b0ee5..7684057a391c0 100644 --- a/ext/dom/xml_serializer.c +++ b/ext/dom/xml_serializer.c @@ -1097,7 +1097,10 @@ static int dom_xml_serialize_element_node( /* 14. If ns is the HTML namespace, and the node's list of children is empty, and the node's localName matches * any one of the following void elements: ... */ if (element->children == NULL) { - if (xmlSaveNoEmptyTags) { + ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") + int saveNoEmptyTags = xmlSaveNoEmptyTags; + ZEND_DIAGNOSTIC_IGNORED_END + if (saveNoEmptyTags) { /* Do nothing, use the closing style. */ } else if (php_dom_ns_is_fast(element, php_dom_ns_is_html_magic_token)) { size_t name_length = strlen((const char *) element->name); diff --git a/ext/dom/xpath_callbacks.c b/ext/dom/xpath_callbacks.c index c4715fa67e80a..0974db475b3a9 100644 --- a/ext/dom/xpath_callbacks.c +++ b/ext/dom/xpath_callbacks.c @@ -215,6 +215,7 @@ static zend_result php_dom_xpath_callback_ns_update_method_handler( } zend_tmp_string_release(tmp_str); } else { + zend_tmp_string_release(tmp_str); zend_fcc_dtor(fcc); efree(fcc); return FAILURE; diff --git a/ext/enchant/enchant.c b/ext/enchant/enchant.c index eedb49b69e8f9..534908f9d1cc5 100644 --- a/ext/enchant/enchant.c +++ b/ext/enchant/enchant.c @@ -671,17 +671,18 @@ PHP_FUNCTION(enchant_dict_suggest) } PHP_ENCHANT_GET_DICT; - array_init(return_value); suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, &n_sugg); if (suggs && n_sugg) { - size_t i; + array_init_size(return_value, n_sugg); - for (i = 0; i < n_sugg; i++) { + for (size_t i = 0; i < n_sugg; i++) { add_next_index_string(return_value, suggs[i]); } enchant_dict_free_string_list(pdict->pdict, suggs); + } else { + RETURN_EMPTY_ARRAY(); } } /* }}} */ diff --git a/ext/exif/exif.c b/ext/exif/exif.c index 2906b8c7150e8..17dadc7539baf 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -4421,7 +4421,7 @@ static bool exif_scan_HEIF_header(image_info_type *ImageInfo, unsigned char *buf if (exif_read_from_stream_file_looped(ImageInfo->infile, (char*)(data + remain), limit - remain) == limit - remain) { exif_isobmff_parse_meta(data, data + limit, &pos); } - if ((pos.size) && + if ((pos.size >= 2) && (pos.size < ImageInfo->FileSize) && (ImageInfo->FileSize - pos.size >= pos.offset) && (php_stream_seek(ImageInfo->infile, pos.offset + 2, SEEK_SET) >= 0)) { diff --git a/ext/exif/tests/heic_iloc_underflow.phpt b/ext/exif/tests/heic_iloc_underflow.phpt new file mode 100644 index 0000000000000..9dd1878b60dd7 --- /dev/null +++ b/ext/exif/tests/heic_iloc_underflow.phpt @@ -0,0 +1,19 @@ +--TEST-- +HEIC iloc extent_length underflow +--EXTENSIONS-- +exif +--FILE-- + +--CLEAN-- + +--EXPECTF-- +Warning: exif_read_data(heic_iloc_underflow.heic): Invalid HEIF file in %s on line %d +bool(false) diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 86b8d29209f40..d5b8eb59f0c90 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -4717,9 +4717,8 @@ ZEND_METHOD(FFI, isNull) /* {{{ */ ZEND_METHOD(FFI_CType, getName) /* {{{ */ { zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + + ZEND_PARSE_PARAMETERS_NONE(); zend_ffi_ctype_name_buf buf; @@ -4739,9 +4738,7 @@ ZEND_METHOD(FFI_CType, getKind) /* {{{ */ const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); const zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); RETURN_LONG(type->kind); @@ -4753,9 +4750,7 @@ ZEND_METHOD(FFI_CType, getSize) /* {{{ */ const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); const zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); RETURN_LONG(type->size); @@ -4767,9 +4762,7 @@ ZEND_METHOD(FFI_CType, getAlignment) /* {{{ */ const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); const zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); RETURN_LONG(type->align); @@ -4781,9 +4774,7 @@ ZEND_METHOD(FFI_CType, getAttributes) /* {{{ */ const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); const zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); RETURN_LONG(type->attr); @@ -4795,9 +4786,7 @@ ZEND_METHOD(FFI_CType, getEnumKind) /* {{{ */ const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); const zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); if (type->kind != ZEND_FFI_TYPE_ENUM) { @@ -4814,9 +4803,7 @@ ZEND_METHOD(FFI_CType, getArrayElementType) /* {{{ */ zend_ffi_type *type; zend_ffi_ctype *ret; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); if (type->kind != ZEND_FFI_TYPE_ARRAY) { @@ -4835,9 +4822,7 @@ ZEND_METHOD(FFI_CType, getArrayLength) /* {{{ */ const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); const zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); if (type->kind != ZEND_FFI_TYPE_ARRAY) { @@ -4854,9 +4839,7 @@ ZEND_METHOD(FFI_CType, getPointerType) /* {{{ */ zend_ffi_ctype *ret; zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); if (type->kind != ZEND_FFI_TYPE_POINTER) { @@ -4878,9 +4861,7 @@ ZEND_METHOD(FFI_CType, getStructFieldNames) /* {{{ */ zend_string* name; zval zv; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); if (type->kind != ZEND_FFI_TYPE_STRUCT) { @@ -4958,9 +4939,7 @@ ZEND_METHOD(FFI_CType, getFuncABI) /* {{{ */ const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); const zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); if (type->kind != ZEND_FFI_TYPE_FUNC) { @@ -4977,9 +4956,7 @@ ZEND_METHOD(FFI_CType, getFuncReturnType) /* {{{ */ zend_ffi_ctype *ret; zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); if (type->kind != ZEND_FFI_TYPE_FUNC) { @@ -4998,9 +4975,7 @@ ZEND_METHOD(FFI_CType, getFuncParameterCount) /* {{{ */ const zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS)); const zend_ffi_type *type; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); type = ZEND_FFI_TYPE(ctype->type); if (type->kind != ZEND_FFI_TYPE_FUNC) { diff --git a/ext/ffi/tests/001.phpt b/ext/ffi/tests/001.phpt deleted file mode 100644 index 3196498aba0db..0000000000000 --- a/ext/ffi/tests/001.phpt +++ /dev/null @@ -1,12 +0,0 @@ ---TEST-- -FFI 001: Check if FFI is loaded ---EXTENSIONS-- -ffi ---INI-- -ffi.enable=1 ---FILE-- - ---EXPECT-- -The extension "FFI" is available diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index d7acb3edef68e..63f5c222c1924 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -147,11 +147,18 @@ PHP_FUNCTION(ftp_connect) RETURN_THROWS(); } + const uint64_t timeoutmax = (uint64_t)((double) PHP_TIMEOUT_ULL_MAX / 1000000.0); + if (timeout_sec <= 0) { zend_argument_value_error(3, "must be greater than 0"); RETURN_THROWS(); } + if (timeout_sec >= timeoutmax) { + zend_argument_value_error(3, "must be less than " ZEND_ULONG_FMT, timeoutmax); + RETURN_THROWS(); + } + /* connect */ if (!(ftp = ftp_open(host, (short)port, timeout_sec))) { RETURN_FALSE; diff --git a/ext/ftp/tests/gh20601.phpt b/ext/ftp/tests/gh20601.phpt new file mode 100644 index 0000000000000..3ece7736c3aaa --- /dev/null +++ b/ext/ftp/tests/gh20601.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-20601 (ftp_connect timeout overflow) +--EXTENSIONS-- +ftp +--SKIPIF-- + +--FILE-- +getMessage(); +} +?> +--EXPECTF-- +ftp_connect(): Argument #3 ($timeout) must be less than %d diff --git a/ext/gd/config.m4 b/ext/gd/config.m4 index 0d024c9ea1cf3..a997238b7f75c 100644 --- a/ext/gd/config.m4 +++ b/ext/gd/config.m4 @@ -265,6 +265,10 @@ if test "$PHP_GD" != "no"; then AC_DEFINE([HAVE_GD_BUNDLED], [1], [Define to 1 if gd extension uses GD library bundled in PHP.]) + AC_DEFINE([HAVE_GD_GET_INTERPOLATION], [1], + [Define to 1 if GD library has the 'gdImageGetInterpolationMethod' + function.]) + dnl Various checks for GD features PHP_SETUP_ZLIB([GD_SHARED_LIBADD]) PHP_GD_PNG diff --git a/ext/gd/gd.c b/ext/gd/gd.c index e946ec73d7dbb..60b2ad65bf65e 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -2453,11 +2453,21 @@ PHP_FUNCTION(imagegammacorrect) RETURN_THROWS(); } + if (!zend_finite(input)) { + zend_argument_value_error(2, "must be finite"); + RETURN_THROWS(); + } + if (output <= 0.0) { zend_argument_value_error(3, "must be greater than 0"); RETURN_THROWS(); } + if (!zend_finite(output)) { + zend_argument_value_error(3, "must be finite"); + RETURN_THROWS(); + } + gamma = input / output; im = php_gd_libgdimageptr_from_zval_p(IM); @@ -2966,7 +2976,8 @@ static void php_imagechar(INTERNAL_FUNCTION_PARAMETERS, int mode) zend_long X, Y, COL; zend_string *C; gdImagePtr im; - int ch = 0, col, x, y, i; + int ch = 0, col, i; + unsigned int x, y; size_t l = 0; unsigned char *str = NULL; zend_object *font_obj = NULL; @@ -2999,21 +3010,21 @@ static void php_imagechar(INTERNAL_FUNCTION_PARAMETERS, int mode) switch (mode) { case 0: - gdImageChar(im, font, x, y, ch, col); + gdImageChar(im, font, (int)x, (int)y, ch, col); break; case 1: php_gdimagecharup(im, font, x, y, ch, col); break; case 2: for (i = 0; (i < l); i++) { - gdImageChar(im, font, x, y, (int) ((unsigned char) str[i]), col); + gdImageChar(im, font, (int)x, (int)y, (int) ((unsigned char) str[i]), col); x += font->w; } break; case 3: { for (i = 0; (i < l); i++) { /* php_gdimagecharup(im, font, x, y, (int) str[i], col); */ - gdImageCharUp(im, font, x, y, (int) str[i], col); + gdImageCharUp(im, font, (int)x, (int)y, (int) str[i], col); y -= font->w; } break; @@ -3921,9 +3932,17 @@ PHP_FUNCTION(imagescale) src_y = gdImageSY(im); if (src_x && tmp_h < 0) { + if (tmp_w > (ZEND_LONG_MAX / src_y)) { + zend_argument_value_error(2, "must be less than or equal to " ZEND_LONG_FMT, (zend_long)(ZEND_LONG_MAX / src_y)); + RETURN_THROWS(); + } tmp_h = tmp_w * src_y / src_x; } if (src_y && tmp_w < 0) { + if (tmp_h > (ZEND_LONG_MAX / src_x)) { + zend_argument_value_error(3, "must be less than or equal to " ZEND_LONG_FMT, (zend_long)(ZEND_LONG_MAX / src_x)); + RETURN_THROWS(); + } tmp_w = tmp_h * src_x / src_y; } } diff --git a/ext/gd/tests/gh20551.phpt b/ext/gd/tests/gh20551.phpt new file mode 100644 index 0000000000000..32ca50ca5f626 --- /dev/null +++ b/ext/gd/tests/gh20551.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-20551: (imagegammacorrect out of range input/output value) +--EXTENSIONS-- +gd +--FILE-- +getMessage(), PHP_EOL; + } +} +?> +--EXPECT-- +imagegammacorrect(): Argument #2 ($input_gamma) must be finite +imagegammacorrect(): Argument #2 ($input_gamma) must be finite +imagegammacorrect(): Argument #2 ($input_gamma) must be finite +imagegammacorrect(): Argument #2 ($input_gamma) must be greater than 0 +imagegammacorrect(): Argument #3 ($output_gamma) must be finite +imagegammacorrect(): Argument #3 ($output_gamma) must be finite +imagegammacorrect(): Argument #3 ($output_gamma) must be finite +imagegammacorrect(): Argument #3 ($output_gamma) must be greater than 0 diff --git a/ext/gd/tests/gh20602.phpt b/ext/gd/tests/gh20602.phpt new file mode 100644 index 0000000000000..29c781e76a2d1 --- /dev/null +++ b/ext/gd/tests/gh20602.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-20551: (imagegammacorrect out of range input/output value) +--EXTENSIONS-- +gd +--FILE-- +getMessage(), PHP_EOL; +} +try { + imagescale($im, -1, PHP_INT_MAX); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} +?> +--EXPECTF-- +imagescale(): Argument #2 ($width) must be less than or equal to %d +imagescale(): Argument #3 ($height) must be less than or equal to %d diff --git a/ext/gd/tests/gh20622.phpt b/ext/gd/tests/gh20622.phpt new file mode 100644 index 0000000000000..42109ddc13e4d --- /dev/null +++ b/ext/gd/tests/gh20622.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-20622 (imagestring/imagestringup overflow/underflow) +--EXTENSIONS-- +gd +--FILE-- + +--EXPECT-- +OK diff --git a/ext/intl/ERROR_CONVENTIONS.md b/ext/intl/ERROR_CONVENTIONS.md index af2450c8186a0..432862afd6855 100644 --- a/ext/intl/ERROR_CONVENTIONS.md +++ b/ext/intl/ERROR_CONVENTIONS.md @@ -75,7 +75,7 @@ and `intl_get_error_message()`. parsing errors), not `NULL`. Constructors and factory methods are the exception; these should return `NULL`, not `FALSE`. -Not that constructors in Intl generally (always?) don't throws exceptions. They +Note that constructors in Intl generally (always?) don't throws exceptions. They instead destroy the object to that the result of new `IntlClass()` can be `NULL`. This may be surprising. diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index e734b2df27b84..25e8dbf869685 100644 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -455,6 +455,7 @@ U_CFUNC void umsg_format_helper(MessageFormatter_object *mfo, char *message; spprintf(&message, 0, "Invalid UTF-8 data in string argument: " "'%s'", ZSTR_VAL(str)); + zend_tmp_string_release(tmp_str); intl_errors_set(&err, err.code, message); efree(message); delete text; diff --git a/ext/intl/spoofchecker/spoofchecker_main.cpp b/ext/intl/spoofchecker/spoofchecker_main.cpp index ddbf02a0d3ded..e49ddec87a3cb 100644 --- a/ext/intl/spoofchecker/spoofchecker_main.cpp +++ b/ext/intl/spoofchecker/spoofchecker_main.cpp @@ -162,8 +162,8 @@ U_CFUNC PHP_METHOD(Spoofchecker, setRestrictionLevel) USPOOF_MINIMALLY_RESTRICTIVE != level && USPOOF_UNRESTRICTIVE != level) { zend_argument_value_error(1, "must be one of Spoofchecker::ASCII, Spoofchecker::SINGLE_SCRIPT_RESTRICTIVE, " - "Spoofchecker::SINGLE_HIGHLY_RESTRICTIVE, Spoofchecker::SINGLE_MODERATELY_RESTRICTIVE, " - "Spoofchecker::SINGLE_MINIMALLY_RESTRICTIVE, or Spoofchecker::UNRESTRICTIVE"); + "Spoofchecker::HIGHLY_RESTRICTIVE, Spoofchecker::MODERATELY_RESTRICTIVE, " + "Spoofchecker::MINIMALLY_RESTRICTIVE, or Spoofchecker::UNRESTRICTIVE"); RETURN_THROWS(); } diff --git a/ext/intl/tests/msgfmt_format_error4.phpt b/ext/intl/tests/msgfmt_format_error4.phpt index 451a55ad9da94..78dc27b4092e4 100644 --- a/ext/intl/tests/msgfmt_format_error4.phpt +++ b/ext/intl/tests/msgfmt_format_error4.phpt @@ -25,9 +25,22 @@ try { var_dump($e::class === 'IntlException'); var_dump("MessageFormatter::format(): Invalid UTF-8 data in string argument: '\x80'" === $e->getMessage()); } + +try { + var_dump($mf->format(array("foo" => new class { + function __toString(): string { + return str_repeat("\x80", random_int(1, 1)); + } + }))); +} catch (Throwable $e) { + var_dump($e::class === 'IntlException'); + var_dump("MessageFormatter::format(): Invalid UTF-8 data in string argument: '\x80'" === $e->getMessage()); +} ?> --EXPECT-- bool(true) bool(true) bool(true) bool(true) +bool(true) +bool(true) diff --git a/ext/intl/tests/msgfmt_format_intlcalendar_variant4.phpt b/ext/intl/tests/msgfmt_format_intlcalendar_variant4.phpt index 014bdd4749bca..9436a9e954386 100644 --- a/ext/intl/tests/msgfmt_format_intlcalendar_variant4.phpt +++ b/ext/intl/tests/msgfmt_format_intlcalendar_variant4.phpt @@ -29,4 +29,4 @@ echo "msgf2: ", $msgf->format(array($time, 'date')), " ", ?> --EXPECTF-- Deprecated: Calling IntlGregorianCalendar::__construct() with more than 2 arguments is deprecated, use either IntlGregorianCalendar::createFromDate() or IntlGregorianCalendar::createFromDateTime() instead in %s on line %d -quinta-feira, 17 de maio de 2012 5:35:36 da tarde ptlis +quinta-feira, 17 de maio de 2012 5:35:36 %r(da tarde|p.m.)%r ptlis diff --git a/ext/intl/tests/spoofchecker_unknown_restriction_level.phpt b/ext/intl/tests/spoofchecker_unknown_restriction_level.phpt index e8ed48d60a3eb..6b7e9474755de 100644 --- a/ext/intl/tests/spoofchecker_unknown_restriction_level.phpt +++ b/ext/intl/tests/spoofchecker_unknown_restriction_level.phpt @@ -20,4 +20,4 @@ try { ?> --EXPECT-- -Spoofchecker::setRestrictionLevel(): Argument #1 ($level) must be one of Spoofchecker::ASCII, Spoofchecker::SINGLE_SCRIPT_RESTRICTIVE, Spoofchecker::SINGLE_HIGHLY_RESTRICTIVE, Spoofchecker::SINGLE_MODERATELY_RESTRICTIVE, Spoofchecker::SINGLE_MINIMALLY_RESTRICTIVE, or Spoofchecker::UNRESTRICTIVE +Spoofchecker::setRestrictionLevel(): Argument #1 ($level) must be one of Spoofchecker::ASCII, Spoofchecker::SINGLE_SCRIPT_RESTRICTIVE, Spoofchecker::HIGHLY_RESTRICTIVE, Spoofchecker::MODERATELY_RESTRICTIVE, Spoofchecker::MINIMALLY_RESTRICTIVE, or Spoofchecker::UNRESTRICTIVE diff --git a/ext/intl/tests/timezone_getDisplayName_variant4.phpt b/ext/intl/tests/timezone_getDisplayName_variant4.phpt index 39d71f5aa2011..ccde7f8e0ea79 100644 --- a/ext/intl/tests/timezone_getDisplayName_variant4.phpt +++ b/ext/intl/tests/timezone_getDisplayName_variant4.phpt @@ -19,12 +19,12 @@ var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_COMMONLY_USED)) var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_GENERIC_LOCATION)); ?> ---EXPECT-- -string(3) "GMT" +--EXPECTF-- +string(%d) "%r(GMT|GMT\+0)%r" string(30) "Western European Standard Time" string(13) "Portugal Time" string(21) "Western European Time" string(5) "+0000" -string(3) "GMT" -string(3) "GMT" +string(%d) "%r(GMT|GMT\+00:00)%r" +string(%d) "%r(GMT|GMT\+0)%r" string(13) "Portugal Time" diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 366903b2c2ab1..9e566a4ed1dcb 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -425,7 +425,7 @@ static void _php_ldap_control_to_array(LDAP *ld, LDAPControl* ctrl, zval* array, static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashTable *control_ht) { zval* val; - zend_string *control_oid; + zend_string *control_oid, *control_oid_tmp; char** ldap_attrs = NULL; LDAPSortKey** sort_keys = NULL; zend_string *tmpstring = NULL, **tmpstrings1 = NULL, **tmpstrings2 = NULL; @@ -436,8 +436,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT return -1; } - control_oid = zval_get_string(val); - if (EG(exception)) { + control_oid = zval_try_get_tmp_string(val, &control_oid_tmp); + if (!control_oid) { return -1; } @@ -453,8 +453,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT if ((val = zend_hash_find(control_ht, ZSTR_KNOWN(ZEND_STR_VALUE))) != NULL) { if (Z_TYPE_P(val) != IS_ARRAY) { - tmpstring = zval_get_string(val); - if (EG(exception)) { + tmpstring = zval_try_get_string(val); + if (!tmpstring) { rc = -1; goto failure; } @@ -468,8 +468,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT pagesize = zval_get_long(tmp); } if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "cookie", sizeof("cookie") - 1)) != NULL) { - tmpstring = zval_get_string(tmp); - if (EG(exception)) { + tmpstring = zval_try_get_string(tmp); + if (!tmpstring) { rc = -1; goto failure; } @@ -488,8 +488,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT rc = -1; zend_value_error("%s(): Control must have a \"filter\" key", get_active_function_name()); } else { - zend_string* assert = zval_get_string(tmp); - if (EG(exception)) { + zend_string* assert = zval_try_get_string(tmp); + if (!assert) { rc = -1; goto failure; } @@ -516,8 +516,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT rc = -1; php_error_docref(NULL, E_WARNING, "Failed to allocate control value"); } else { - tmpstring = zval_get_string(tmp); - if (EG(exception)) { + tmpstring = zval_try_get_string(tmp); + if (!tmpstring) { rc = -1; goto failure; } @@ -555,8 +555,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT goto failure; } - tmpstrings1[num_tmpstrings1] = zval_get_string(attr); - if (EG(exception)) { + tmpstrings1[num_tmpstrings1] = zval_try_get_string(attr); + if (!tmpstrings1[num_tmpstrings1]) { rc = -1; goto failure; } @@ -603,8 +603,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT goto failure; } sort_keys[i] = emalloc(sizeof(LDAPSortKey)); - tmpstrings1[num_tmpstrings1] = zval_get_string(tmp); - if (EG(exception)) { + tmpstrings1[num_tmpstrings1] = zval_try_get_string(tmp); + if (!tmpstrings1[num_tmpstrings1]) { rc = -1; goto failure; } @@ -612,8 +612,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT ++num_tmpstrings1; if ((tmp = zend_hash_str_find(Z_ARRVAL_P(sortkey), "oid", sizeof("oid") - 1)) != NULL) { - tmpstrings2[num_tmpstrings2] = zval_get_string(tmp); - if (EG(exception)) { + tmpstrings2[num_tmpstrings2] = zval_try_get_string(tmp); + if (!tmpstrings2[num_tmpstrings2]) { rc = -1; goto failure; } @@ -659,8 +659,8 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT } if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "attrvalue", sizeof("attrvalue") - 1)) != NULL) { - tmpstring = zval_get_string(tmp); - if (EG(exception)) { + tmpstring = zval_try_get_string(tmp); + if (!tmpstring) { rc = -1; goto failure; } @@ -684,14 +684,15 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT goto failure; } + zend_string *context_str = NULL; if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "context", sizeof("context") - 1)) != NULL) { - tmpstring = zval_get_string(tmp); - if (EG(exception)) { + context_str = zval_try_get_string(tmp); + if (!context_str) { rc = -1; goto failure; } - context.bv_val = ZSTR_VAL(tmpstring); - context.bv_len = ZSTR_LEN(tmpstring); + context.bv_val = ZSTR_VAL(context_str); + context.bv_len = ZSTR_LEN(context_str); vlvInfo.ldvlv_context = &context; } else { vlvInfo.ldvlv_context = NULL; @@ -703,6 +704,9 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT if (rc != LDAP_SUCCESS) { php_error_docref(NULL, E_WARNING, "Failed to create VLV control value: %s (%d)", ldap_err2string(rc), rc); } + if (context_str) { + zend_string_release_ex(context_str, false); + } } else { zend_type_error("%s(): Control OID %s cannot be of type array", get_active_function_name(), ZSTR_VAL(control_oid)); rc = -1; @@ -714,7 +718,7 @@ static int php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, const HashT } failure: - zend_string_release(control_oid); + zend_tmp_string_release(control_oid_tmp); if (tmpstring != NULL) { zend_string_release(tmpstring); } @@ -980,7 +984,8 @@ PHP_FUNCTION(ldap_connect) #ifdef HAVE_ORALDAP if (ZEND_NUM_ARGS() == 3 || ZEND_NUM_ARGS() == 4) { - WRONG_PARAM_COUNT; + zend_wrong_param_count(); + RETURN_THROWS(); } if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!lssl", &host, &hostlen, &port, &wallet, &walletlen, &walletpasswd, &walletpasswdlen, &authmode) != SUCCESS) { @@ -2790,8 +2795,8 @@ PHP_FUNCTION(ldap_modify_batch) zend_ulong value_index = 0; zval *modification_value_zv = NULL; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(modification_values), modification_value_zv) { - zend_string *modval = zval_get_string(modification_value_zv); - if (EG(exception)) { + zend_string *modval = zval_try_get_string(modification_value_zv); + if (!modval) { RETVAL_FALSE; ldap_mods[modification_index]->mod_bvalues[value_index] = NULL; num_mods = modification_index + 1; diff --git a/ext/ldap/tests/ldap_set_option_leak_attrvalue_context.phpt b/ext/ldap/tests/ldap_set_option_leak_attrvalue_context.phpt new file mode 100644 index 0000000000000..5829ad24faf57 --- /dev/null +++ b/ext/ldap/tests/ldap_set_option_leak_attrvalue_context.phpt @@ -0,0 +1,34 @@ +--TEST-- +ldap_set_option() - Leaks attrvalue and context +--EXTENSIONS-- +ldap +--FILE-- + "2.16.840.1.113730.3.4.9", "value" => ["attrvalue" => $attrvalue, "context" => $context, "before" => 0, "after" => 0]], +]; + +ldap_set_option($link, LDAP_OPT_CLIENT_CONTROLS, $controls); +ldap_get_option($link, LDAP_OPT_CLIENT_CONTROLS, $controls_out); + +var_dump($controls_out); +?> +--EXPECTF-- +array(1) { + ["2.16.840.1.113730.3.4.9"]=> + array(3) { + ["oid"]=> + string(23) "2.16.840.1.113730.3.4.9" + ["iscritical"]=> + bool(false) + ["value"]=> + string(28) "0%0%0� attrvaluecontext" + } +} diff --git a/ext/lexbor/lexbor/url/url.c b/ext/lexbor/lexbor/url/url.c index 7bfc007e622ce..0eef7a6deba46 100644 --- a/ext/lexbor/lexbor/url/url.c +++ b/ext/lexbor/lexbor/url/url.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023-2024 Alexander Borisov + * Copyright (C) 2023-2025 Alexander Borisov * * Author: Alexander Borisov */ @@ -1029,27 +1029,34 @@ lxb_url_path_append_wo_slash(lxb_url_t *url, static lxb_status_t lxb_url_path_append(lxb_url_t *url, const lxb_char_t *data, size_t length) { - size_t len; - lxb_char_t *p; + lxb_char_t *p, *begin; lexbor_str_t *str; str = &url->path.str; if (str->data == NULL) { p = lexbor_str_init(str, url->mraw, length + 1); - if (p == NULL) { - return LXB_STATUS_ERROR_MEMORY_ALLOCATION; - } + } + else { + /* + 2 == begin '/' and end '\0' */ + p = lexbor_str_check_size(str, url->mraw, length + 2); } - len = str->length; - str->length += 1; + if (p == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } - p = lexbor_str_append(&url->path.str, url->mraw, data, length); + begin = &str->data[str->length]; + begin[0] = '/'; - str->data[len] = '/'; + if (length > 0) { + memcpy(&begin[1], data, sizeof(lxb_char_t) * length); + } - return (p != NULL) ? LXB_STATUS_OK : LXB_STATUS_ERROR_MEMORY_ALLOCATION; + str->length += length + 1; + str->data[str->length] = '\0'; + + return LXB_STATUS_OK; } static lxb_status_t @@ -1106,9 +1113,9 @@ lxb_url_host_copy(const lxb_url_host_t *src, lxb_url_host_t *dst, } } - if (src->type <= LXB_URL_HOST_TYPE_OPAQUE) { - dst->type = src->type; + dst->type = src->type; + if (src->type <= LXB_URL_HOST_TYPE_OPAQUE) { if (src->type == LXB_URL_HOST_TYPE__UNDEF) { return LXB_STATUS_OK; } @@ -1810,7 +1817,6 @@ lxb_url_parse_basic_h(lxb_url_parser_t *parser, lxb_url_t *url, if (override_state != LXB_URL_STATE__UNDEF && url->scheme.type == LXB_URL_SCHEMEL_TYPE_FILE) { - p -= 1; state = LXB_URL_STATE_FILE_HOST_STATE; goto again; } diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index b27985609cd39..0105106d9531b 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -526,6 +526,7 @@ static int php_libxml_streams_IO_close(void *context) return php_stream_close((php_stream*)context); } +/* TODO: This needs to be replaced by context-specific APIs in the future! */ static xmlParserInputBufferPtr php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc) { @@ -560,13 +561,10 @@ php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc) } /* Allocate the Input buffer front-end. */ - ret = xmlAllocParserInputBuffer(enc); - if (ret != NULL) { - ret->context = context; - ret->readcallback = php_libxml_streams_IO_read; - ret->closecallback = php_libxml_streams_IO_close; - } else + ret = xmlParserInputBufferCreateIO(php_libxml_streams_IO_read, php_libxml_streams_IO_close, context, enc); + if (ret == NULL) { php_libxml_streams_IO_close(context); + } return ret; } @@ -615,11 +613,10 @@ php_libxml_output_buffer_create_filename(const char *URI, } /* Allocate the Output buffer front-end. */ - ret = xmlAllocOutputBuffer(encoder); - if (ret != NULL) { - ret->context = context; - ret->writecallback = php_libxml_streams_IO_write; - ret->closecallback = php_libxml_streams_IO_close; + ret = xmlOutputBufferCreateIO(php_libxml_streams_IO_write, php_libxml_streams_IO_close, context, encoder); + if (ret == NULL) { + php_libxml_streams_IO_close(context); + goto err; } return ret; @@ -806,6 +803,7 @@ static xmlParserInputPtr php_libxml_external_entity_loader(const char *URL, zend_string_release(callable_name); zval_ptr_dtor(&callable); } else { +#if LIBXML_VERSION < 21400 /* TODO: allow storing the encoding in the stream context? */ xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; xmlParserInputBufferPtr pib = xmlAllocParserInputBuffer(enc); @@ -815,15 +813,24 @@ static xmlParserInputPtr php_libxml_external_entity_loader(const char *URL, } else { /* make stream not being closed when the zval is freed */ GC_ADDREF(stream->res); + + ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") pib->context = stream; pib->readcallback = php_libxml_streams_IO_read; pib->closecallback = php_libxml_streams_IO_close; + ZEND_DIAGNOSTIC_IGNORED_END ret = xmlNewIOInputStream(context, pib, enc); if (ret == NULL) { xmlFreeParserInputBuffer(pib); } } +#else + /* make stream not being closed when the zval is freed */ + GC_ADDREF(stream->res); + ret = xmlNewInputFromIO(NULL, php_libxml_streams_IO_read, php_libxml_streams_IO_close, stream, 0); + /* Note: if ret == NULL, the close operation will be executed, so don't DELREF stream->res upon failure! */ +#endif } } else if (Z_TYPE(retval) != IS_NULL) { /* retval not string nor resource nor null; convert to string */ diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index ceb182a0a258d..c5331ef017af6 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -116,7 +116,8 @@ static const enum mbfl_no_encoding php_mb_default_identify_list_cn[] = { mbfl_no_encoding_ascii, mbfl_no_encoding_utf8, mbfl_no_encoding_euc_cn, - mbfl_no_encoding_cp936 + mbfl_no_encoding_cp936, + mbfl_no_encoding_gb18030_2022 }; static const enum mbfl_no_encoding php_mb_default_identify_list_tw_hk[] = { @@ -718,6 +719,11 @@ static PHP_INI_MH(OnUpdate_mbstring_detect_order) } MBSTRG(detect_order_list) = list; MBSTRG(detect_order_list_size) = size; + + if (stage == PHP_INI_STAGE_RUNTIME) { + php_mb_populate_current_detect_order_list(); + } + return SUCCESS; } /* }}} */ @@ -2442,7 +2448,7 @@ PHP_FUNCTION(mb_strcut) if (len > string.len - from) { len = string.len - from; } - RETURN_STR(zend_string_init_fast((const char*)(string.val + from), len & -char_len)); + RETURN_STRINGL_FAST((const char*)(string.val + from), len & -char_len); } if (enc->mblen_table) { @@ -2465,7 +2471,7 @@ PHP_FUNCTION(mb_strcut) } end = p; } - RETURN_STR(zend_string_init_fast((const char*)start, end - start)); + RETURN_STRINGL_FAST((const char*)start, end - start); } ret = mbfl_strcut(&string, &result, from, len); @@ -4697,7 +4703,7 @@ PHP_FUNCTION(mb_send_mail) extra_cmd = php_escape_shell_cmd(extra_cmd); } - RETVAL_BOOL(php_mail(to_r, ZSTR_VAL(subject), message, ZSTR_VAL(str_headers), extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)); + RETVAL_BOOL(php_mail(to_r, ZSTR_VAL(subject), message, ZSTR_VAL(str_headers), extra_cmd)); if (extra_cmd) { zend_string_release_ex(extra_cmd, 0); @@ -5578,19 +5584,16 @@ static bool mb_check_str_encoding(zend_string *str, const mbfl_encoding *encodin static bool php_mb_check_encoding_recursive(HashTable *vars, const mbfl_encoding *encoding) { - zend_long idx; zend_string *key; zval *entry; bool valid = true; - (void)(idx); /* Suppress spurious compiler warning that `idx` is not used */ - if (GC_IS_RECURSIVE(vars)) { php_error_docref(NULL, E_WARNING, "Cannot not handle circular references"); return false; } GC_TRY_PROTECT_RECURSION(vars); - ZEND_HASH_FOREACH_KEY_VAL(vars, idx, key, entry) { + ZEND_HASH_FOREACH_STR_KEY_VAL(vars, key, entry) { ZVAL_DEREF(entry); if (key) { if (!mb_check_str_encoding(key, encoding)) { @@ -5984,6 +5987,11 @@ static void php_mb_populate_current_detect_order_list(void) entry[i] = mbfl_no2encoding(src[i]); } } + + if (MBSTRG(current_detect_order_list) != NULL) { + efree(ZEND_VOIDP(MBSTRG(current_detect_order_list))); + } + MBSTRG(current_detect_order_list) = entry; MBSTRG(current_detect_order_list_size) = nentries; } @@ -6667,13 +6675,15 @@ static zend_string* mb_mime_header_decode(zend_string *input, const mbfl_encodin p = temp; /* Decoding of MIME encoded word was successful; * Try to collapse a run of whitespace */ - if (p < e && (*p == '\n' || *p == '\r')) { + if (p < e && (*p == '\n' || *p == '\r' || *p == '\t' || *p == ' ')) { do { p++; } while (p < e && (*p == '\n' || *p == '\r' || *p == '\t' || *p == ' ')); /* We will only actually output a space if this is not immediately followed * by another valid encoded word */ space_pending = true; + } else { + space_pending = false; } continue; } diff --git a/ext/mbstring/php_onig_compat.h b/ext/mbstring/php_onig_compat.h index c97ba0c5cb674..5a1fa8eeaaf1b 100644 --- a/ext/mbstring/php_onig_compat.h +++ b/ext/mbstring/php_onig_compat.h @@ -5,4 +5,10 @@ #define regex_t php_mb_regex_t #define re_registers php_mb_re_registers +/* Required for some distros that conditionally override PV_. + * As we're in C99 this header is always available. */ +#ifndef HAVE_STDARG_H +# define HAVE_STDARG_H +#endif + #endif /* _PHP_ONIG_COMPAT_H */ diff --git a/ext/mbstring/tests/gh20674.phpt b/ext/mbstring/tests/gh20674.phpt new file mode 100644 index 0000000000000..2fb8206037dee --- /dev/null +++ b/ext/mbstring/tests/gh20674.phpt @@ -0,0 +1,40 @@ +--TEST-- +GH-20674 (mb_decode_mimeheader does not handle separator) +--EXTENSIONS-- +mbstring +--FILE-- + +--EXPECTF-- +string(11) "The PHP 8.5" +string(11) "The PHP 8.5" +string(11) "The PHP 8.5" +string(11) "The PHP 8.5" +string(3) "(a)" +string(5) "(a b)" +string(5) "(a b)" +string(4) "(ab)" +string(4) "(ab)" +string(4) "(ab)" diff --git a/ext/mbstring/tests/mb_detect_order_with_ini_set.phpt b/ext/mbstring/tests/mb_detect_order_with_ini_set.phpt new file mode 100644 index 0000000000000..ba59f3388b85e --- /dev/null +++ b/ext/mbstring/tests/mb_detect_order_with_ini_set.phpt @@ -0,0 +1,60 @@ +--TEST-- +Test mb_detect_order() function : ini set changes order +--EXTENSIONS-- +mbstring +--INI-- +mbstring.detect_order=UTF-8,ISO-8859-15,ISO-8859-1,ASCII +--FILE-- + +--EXPECT-- +array(4) { + [0]=> + string(5) "UTF-8" + [1]=> + string(11) "ISO-8859-15" + [2]=> + string(10) "ISO-8859-1" + [3]=> + string(5) "ASCII" +} +array(3) { + [0]=> + string(5) "UTF-8" + [1]=> + string(10) "ISO-8859-1" + [2]=> + string(5) "ASCII" +} +array(1) { + [0]=> + string(5) "UTF-8" +} +array(1) { + [0]=> + string(5) "UTF-8" +} +array(1) { + [0]=> + string(5) "UTF-8" +} + diff --git a/ext/mbstring/tests/zh_CN_default_encodings.phpt b/ext/mbstring/tests/zh_CN_default_encodings.phpt new file mode 100644 index 0000000000000..213c304b52c69 --- /dev/null +++ b/ext/mbstring/tests/zh_CN_default_encodings.phpt @@ -0,0 +1,24 @@ +--TEST-- +Default encodings in Simplified Chinese +--EXTENSIONS-- +mbstring +--INI-- +mbstring.language=Simplified Chinese +--FILE-- + +--EXPECT-- +array(5) { + [0]=> + string(5) "ASCII" + [1]=> + string(5) "UTF-8" + [2]=> + string(6) "EUC-CN" + [3]=> + string(5) "CP936" + [4]=> + string(12) "GB18030-2022" +} diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 65c423990bc9d..1bf74dd77eeab 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -1343,9 +1343,6 @@ PHP_FUNCTION(mysqli_real_query) } /* }}} */ -# define mysql_real_escape_string_quote(mysql, to, from, length, quote) \ - mysql_real_escape_string(mysql, to, from, length) - PHP_FUNCTION(mysqli_real_escape_string) { MY_MYSQL *mysql; zval *mysql_link = NULL; @@ -1359,7 +1356,7 @@ PHP_FUNCTION(mysqli_real_escape_string) { MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID); newstr = zend_string_safe_alloc(2, escapestr_len, 0, 0); - ZSTR_LEN(newstr) = mysql_real_escape_string_quote(mysql->mysql, ZSTR_VAL(newstr), escapestr, escapestr_len, '\''); + ZSTR_LEN(newstr) = mysql_real_escape_string(mysql->mysql, ZSTR_VAL(newstr), escapestr, escapestr_len); newstr = zend_string_truncate(newstr, ZSTR_LEN(newstr), 0); RETURN_NEW_STR(newstr); diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index 84d43a477edba..a3208b41574b1 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -1029,6 +1029,7 @@ PHP_FUNCTION(mysqli_begin_transaction) } if (FAIL == mysqlnd_begin_transaction(mysql->mysql, flags, name)) { + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; } RETURN_TRUE; @@ -1053,6 +1054,7 @@ PHP_FUNCTION(mysqli_savepoint) } if (FAIL == mysqlnd_savepoint(mysql->mysql, name)) { + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; } RETURN_TRUE; @@ -1076,6 +1078,7 @@ PHP_FUNCTION(mysqli_release_savepoint) RETURN_THROWS(); } if (FAIL == mysqlnd_release_savepoint(mysql->mysql, name)) { + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; } RETURN_TRUE; diff --git a/ext/mysqli/tests/mysqli_begin_transaction_error.phpt b/ext/mysqli/tests/mysqli_begin_transaction_error.phpt new file mode 100644 index 0000000000000..e4d63f366e86b --- /dev/null +++ b/ext/mysqli/tests/mysqli_begin_transaction_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +mysqli_begin_transaction() +--EXTENSIONS-- +mysqli +--SKIPIF-- +errno, $link->error)); +?> +--FILE-- + +--CLEAN-- + +--EXPECT-- +Expecting an exception. +done! diff --git a/ext/mysqli/tests/mysqli_connect_port.phpt b/ext/mysqli/tests/mysqli_connect_port.phpt new file mode 100644 index 0000000000000..cb7fd1d8d1628 --- /dev/null +++ b/ext/mysqli/tests/mysqli_connect_port.phpt @@ -0,0 +1,31 @@ +--TEST-- +mysqli_connect() with port in host +--EXTENSIONS-- +mysqli +--SKIPIF-- + +--FILE-- + +Done +--EXPECTF-- +Done diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index 8eb61a58acb4f..9065aaf579df5 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -548,13 +548,24 @@ MYSQLND_METHOD(mysqlnd_conn_data, get_scheme)(MYSQLND_CONN_DATA * conn, MYSQLND_ port = 3306; } - /* ipv6 addresses are in the format [address]:port */ if (hostname.s[0] != '[' && mysqlnd_fast_is_ipv6_address(hostname.s)) { + /* IPv6 without square brackets so without port */ transport.l = mnd_sprintf(&transport.s, 0, "tcp://[%s]:%u", hostname.s, port); } else { - /* Not ipv6, but could already contain a port number, in which case we should not add an extra port. + char *p; + + /* IPv6 addresses are in the format [address]:port */ + if (hostname.s[0] == '[') { /* IPv6 */ + p = strchr(hostname.s, ']'); + if (p && p[1] != ':') { + p = NULL; + } + } else { /* IPv4 or name */ + p = strchr(hostname.s, ':'); + } + /* Could already contain a port number, in which case we should not add an extra port. * See GH-8978. In a port doubling scenario, the first port would be used so we do the same to keep BC. */ - if (strchr(hostname.s, ':')) { + if (p) { /* TODO: Ideally we should be able to get rid of this workaround in the future. */ transport.l = mnd_sprintf(&transport.s, 0, "tcp://%s", hostname.s); } else { diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index e6a2b90e8fffc..7acb14b778f8d 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -89,7 +89,6 @@ typedef int gid_t; #ifndef ZEND_WIN32 # include # include -# include # include # include #endif @@ -664,8 +663,7 @@ static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_int if (Z_FUNC(p->val)->common.function_name) { Z_FUNC(p->val)->common.function_name = new_interned_string(Z_FUNC(p->val)->common.function_name); } - if (Z_FUNC(p->val)->common.arg_info && - (Z_FUNC(p->val)->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { + if (Z_FUNC(p->val)->common.arg_info) { uint32_t i; uint32_t num_args = Z_FUNC(p->val)->common.num_args + 1; zend_arg_info *arg_info = Z_FUNC(p->val)->common.arg_info - 1; @@ -674,6 +672,12 @@ static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_int num_args++; } for (i = 0 ; i < num_args; i++) { + if (i > 0) { + arg_info[i].name = new_interned_string(arg_info[i].name); + if (arg_info[i].default_value) { + arg_info[i].default_value = new_interned_string(arg_info[i].default_value); + } + } accel_copy_permanent_list_types(new_interned_string, arg_info[i].type); } } @@ -715,6 +719,24 @@ static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_int if (Z_FUNC(q->val)->common.function_name) { Z_FUNC(q->val)->common.function_name = new_interned_string(Z_FUNC(q->val)->common.function_name); } + if (Z_FUNC(q->val)->common.scope == ce) { + uint32_t i; + uint32_t num_args = Z_FUNC(q->val)->common.num_args + 1; + zend_arg_info *arg_info = Z_FUNC(q->val)->common.arg_info - 1; + + if (Z_FUNC(q->val)->common.fn_flags & ZEND_ACC_VARIADIC) { + num_args++; + } + for (i = 0 ; i < num_args; i++) { + if (i > 0) { + arg_info[i].name = new_interned_string(arg_info[i].name); + if (arg_info[i].default_value) { + arg_info[i].default_value = new_interned_string(arg_info[i].default_value); + } + } + accel_copy_permanent_list_types(new_interned_string, arg_info[i].type); + } + } } ZEND_HASH_FOREACH_END(); ZEND_HASH_MAP_FOREACH_BUCKET(&ce->constants_table, q) { diff --git a/ext/opcache/jit/ir/ir.c b/ext/opcache/jit/ir/ir.c index 81621ce11bd36..745a66b2163ae 100644 --- a/ext/opcache/jit/ir/ir.c +++ b/ext/opcache/jit/ir/ir.c @@ -118,7 +118,7 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted { char buf[128]; - if (insn->op == IR_FUNC || insn->op == IR_SYM) { + if (insn->op == IR_FUNC || insn->op == IR_SYM || insn->op == IR_LABEL) { fprintf(f, "%s", ir_get_str(ctx, insn->val.name)); return; } else if (insn->op == IR_STR) { @@ -290,6 +290,7 @@ void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted #define ir_op_kind_prb IR_OPND_PROB #define ir_op_kind_opt IR_OPND_PROB #define ir_op_kind_pro IR_OPND_PROTO +#define ir_op_kind_lbl IR_OPND_LABEL_REF #define _IR_OP_FLAGS(name, flags, op1, op2, op3) \ IR_OP_FLAGS(ir_op_flag_ ## flags, ir_op_kind_ ## op1, ir_op_kind_ ## op2, ir_op_kind_ ## op3), @@ -689,6 +690,13 @@ ir_ref ir_const_str(ir_ctx *ctx, ir_ref str) return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_STR, IR_ADDR, 0)); } +ir_ref ir_const_label(ir_ctx *ctx, ir_ref str) +{ + ir_val val; + val.u64 = str; + return ir_const_ex(ctx, val, IR_ADDR, IR_OPTX(IR_LABEL, IR_ADDR, 0)); +} + ir_ref ir_str(ir_ctx *ctx, const char *s) { size_t len; @@ -879,6 +887,17 @@ static ir_ref _ir_fold_cse(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir return IR_UNUSED; } +IR_ALWAYS_INLINE ir_ref _ir_fold_cast(ir_ctx *ctx, ir_ref ref, ir_type type) +{ + if (ctx->ir_base[ref].type == type) { + return ref; + } else if (IR_IS_CONST_REF(ref) && !IR_IS_SYM_CONST(ctx->ir_base[ref].op)) { + return ir_const(ctx, ctx->ir_base[ref].val, type); + } else { + return ir_emit1(ctx, IR_OPT(IR_BITCAST, type), ref); + } +} + #define IR_FOLD(X) IR_FOLD1(X, __LINE__) #define IR_FOLD1(X, Y) IR_FOLD2(X, Y) #define IR_FOLD2(X, Y) case IR_RULE_ ## Y: @@ -1158,7 +1177,7 @@ ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def) IR_ASSERT(var < 0); if (!ir_hashtab_add(ctx->binding, def, var)) { /* Add a copy with different binding */ - def = ir_emit2(ctx, IR_OPT(IR_COPY, ctx->ir_base[def].type), def, 1); + def = ir_emit2(ctx, IR_OPT(IR_COPY, ctx->ir_base[def].type), def, IR_COPY_HARD); ir_hashtab_add(ctx->binding, def, var); } return def; @@ -1836,8 +1855,49 @@ int ir_mem_flush(void *ptr, size_t size) return 1; } #else + +#if defined(__linux__) && defined(__x86_64__) && defined(PKEY_DISABLE_WRITE) +# define HAVE_PKEY_MPROTECT 1 +#endif + +#ifdef HAVE_PKEY_MPROTECT + +#ifndef PKEY_DISABLE_EXECUTE +# define PKEY_DISABLE_EXECUTE 0 +#endif + +int pkey_mprotect(void* addr, size_t len, int prot, int pkey) __attribute__((weak)); +int pkey_alloc(unsigned int, unsigned int) __attribute__((weak)); +int pkey_free(int) __attribute__((weak)); +int pkey_set(int, unsigned) __attribute__((weak)); + +static int ir_pkey = 0; +#endif + void *ir_mem_mmap(size_t size) { +#ifdef HAVE_PKEY_MPROTECT + if (!ir_pkey && pkey_mprotect) { + int key = pkey_alloc(0, PKEY_DISABLE_WRITE); + if (key > 0) { + ir_pkey = key; + } + } + if (ir_pkey > 0) { + void *ret = mmap(NULL, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ret == MAP_FAILED) { + return NULL; + } + if (pkey_mprotect(ret, size, PROT_EXEC|PROT_READ|PROT_WRITE, ir_pkey) != 0) { +#ifdef IR_DEBUG + fprintf(stderr, "pkey_mprotect() failed\n"); +#endif + munmap(ret, size); + return NULL; + } + return ret; + } +#endif int prot_flags = PROT_EXEC; #if defined(__NetBSD__) prot_flags |= PROT_MPROTECT(PROT_READ|PROT_WRITE); @@ -1852,11 +1912,28 @@ void *ir_mem_mmap(size_t size) int ir_mem_unmap(void *ptr, size_t size) { munmap(ptr, size); +#ifdef HAVE_PKEY_MPROTECT +// if (ir_pkey > 0) { +// pkey_free(ir_pkey); +// ir_pkey = 0; +// } +#endif return 1; } int ir_mem_protect(void *ptr, size_t size) { +#ifdef HAVE_PKEY_MPROTECT + if (ir_pkey > 0) { + if (pkey_set(ir_pkey, PKEY_DISABLE_WRITE)) { +#ifdef IR_DEBUG + fprintf(stderr, "mprotect() failed\n"); +#endif + return 0; + } + return 1; + } +#endif if (mprotect(ptr, size, PROT_READ | PROT_EXEC) != 0) { #ifdef IR_DEBUG fprintf(stderr, "mprotect() failed\n"); @@ -1868,6 +1945,17 @@ int ir_mem_protect(void *ptr, size_t size) int ir_mem_unprotect(void *ptr, size_t size) { +#ifdef HAVE_PKEY_MPROTECT + if (ir_pkey > 0) { + if (pkey_set(ir_pkey, PKEY_DISABLE_EXECUTE)) { +#ifdef IR_DEBUG + fprintf(stderr, "mprotect() failed\n"); +#endif + return 0; + } + return 1; + } +#endif if (mprotect(ptr, size, PROT_READ | PROT_WRITE) != 0) { #ifdef IR_DEBUG fprintf(stderr, "mprotect() failed\n"); @@ -2070,7 +2158,26 @@ IR_ALWAYS_INLINE ir_ref ir_find_aliasing_load_i(ir_ctx *ctx, ir_ref ref, ir_type } } else if (insn->op == IR_RSTORE) { modified_regset |= (1 << insn->op3); - } else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_CALL || insn->op == IR_VSTORE) { + } else if (insn->op == IR_CALL) { + ir_insn *func = &ctx->ir_base[insn->op2]; + ir_ref func_proto; + const ir_proto_t *proto; + + if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) { + func_proto = func->proto; + } else if (func->op == IR_PROTO) { + func_proto = func->op2; + } else { + break; + } + if (!func_proto) { + break; + } + proto = (const ir_proto_t *)ir_get_str(ctx, func_proto); + if (!(proto->flags & (IR_CONST_FUNC|IR_PURE_FUNC))) { + break; + } + } else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_VSTORE) { return IR_UNUSED; } ref = insn->op1; @@ -2116,7 +2223,26 @@ IR_ALWAYS_INLINE ir_ref ir_find_aliasing_vload_i(ir_ctx *ctx, ir_ref ref, ir_typ break; } } - } else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_CALL || insn->op == IR_STORE) { + } else if (insn->op == IR_CALL) { + ir_insn *func = &ctx->ir_base[insn->op2]; + ir_ref func_proto; + const ir_proto_t *proto; + + if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) { + func_proto = func->proto; + } else if (func->op == IR_PROTO) { + func_proto = func->op2; + } else { + break; + } + if (!func_proto) { + break; + } + proto = (const ir_proto_t *)ir_get_str(ctx, func_proto); + if (!(proto->flags & (IR_CONST_FUNC|IR_PURE_FUNC))) { + break; + } + } else if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN || insn->op == IR_STORE) { break; } ref = insn->op1; @@ -3013,6 +3139,16 @@ void _ir_IJMP(ir_ctx *ctx, ir_ref addr) ctx->control = IR_UNUSED; } +ir_ref _ir_IGOTO(ir_ctx *ctx, ir_ref addr) +{ + ir_ref ref; + + IR_ASSERT(ctx->control); + ctx->control = ref = ir_emit2(ctx, IR_IGOTO, ctx->control, addr); + ctx->control = IR_UNUSED; + return ref; +} + ir_ref _ir_ADD_OFFSET(ir_ctx *ctx, ir_ref addr, uintptr_t offset) { if (offset) { @@ -3135,6 +3271,18 @@ void _ir_VSTORE(ir_ctx *ctx, ir_ref var, ir_ref val) ctx->control = ir_emit3(ctx, IR_VSTORE, ctx->control, var, val); } +ir_ref _ir_VLOAD_v(ir_ctx *ctx, ir_type type, ir_ref var) +{ + IR_ASSERT(ctx->control); + return ctx->control = ir_emit2(ctx, IR_OPT(IR_VLOAD_v, type), ctx->control, var); +} + +void _ir_VSTORE_v(ir_ctx *ctx, ir_ref var, ir_ref val) +{ + IR_ASSERT(ctx->control); + ctx->control = ir_emit3(ctx, IR_VSTORE_v, ctx->control, var, val); +} + ir_ref _ir_TLS(ir_ctx *ctx, ir_ref index, ir_ref offset) { IR_ASSERT(ctx->control); @@ -3193,6 +3341,18 @@ void _ir_STORE(ir_ctx *ctx, ir_ref addr, ir_ref val) ctx->control = ir_emit3(ctx, IR_STORE, ctx->control, addr, val); } +ir_ref _ir_LOAD_v(ir_ctx *ctx, ir_type type, ir_ref addr) +{ + IR_ASSERT(ctx->control); + return ctx->control = ir_emit2(ctx, IR_OPT(IR_LOAD_v, type), ctx->control, addr); +} + +void _ir_STORE_v(ir_ctx *ctx, ir_ref addr, ir_ref val) +{ + IR_ASSERT(ctx->control); + ctx->control = ir_emit3(ctx, IR_STORE_v, ctx->control, addr, val); +} + void _ir_VA_START(ir_ctx *ctx, ir_ref list) { IR_ASSERT(ctx->control); @@ -3217,11 +3377,13 @@ ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list) return ctx->control = ir_emit2(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list); } -ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size) +ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size, size_t align) { IR_ASSERT(ctx->control); - IR_ASSERT(size <= 0x7fffffff); - return ctx->control = ir_emit3(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list, (ir_ref)size); + IR_ASSERT(size <= 0x0fffffff); + IR_ASSERT(align != 0 && ((align & (align - 1)) == 0) && align <= 128); + return ctx->control = ir_emit3(ctx, IR_OPT(IR_VA_ARG, type), ctx->control, list, + (ir_ref)IR_VA_ARG_OP3(size, align)); } ir_ref _ir_BLOCK_BEGIN(ir_ctx *ctx) diff --git a/ext/opcache/jit/ir/ir.h b/ext/opcache/jit/ir/ir.h index 8fcfbffa7d6bc..a96650597055a 100644 --- a/ext/opcache/jit/ir/ir.h +++ b/ext/opcache/jit/ir/ir.h @@ -216,6 +216,7 @@ typedef enum _ir_type { * prb - branch probability 1-99 (0 - unspecified): (IF_TRUE, IF_FALSE, CASE_VAL, CASE_DEFAULT) * opt - optional number * pro - function prototype + * lbl - label used as value (a reference to constant): (BEGIN) * * The order of IR opcodes is carefully selected for efficient folding. * - foldable instruction go first @@ -322,6 +323,7 @@ typedef enum _ir_type { _(FUNC_ADDR, r0, ___, ___, ___) /* constant func ref */ \ _(FUNC, r0, ___, ___, ___) /* constant func ref */ \ _(SYM, r0, ___, ___, ___) /* constant symbol ref */ \ + _(LABEL, r0, ___, ___, ___) /* label address ref */ \ _(STR, r0, ___, ___, ___) /* constant str ref */ \ \ /* call ops */ \ @@ -334,11 +336,15 @@ typedef enum _ir_type { _(BLOCK_BEGIN, a1, src, ___, ___) /* stacksave */ \ _(BLOCK_END, a2, src, def, ___) /* stackrestore */ \ _(VLOAD, l2, src, var, ___) /* load value of local var */ \ + _(VLOAD_v, l2, src, var, ___) /* volatile variant of VLOAD */ \ _(VSTORE, s3, src, var, def) /* store value to local var */ \ + _(VSTORE_v, s3, src, var, def) /* volatile variant of VSTORE */ \ _(RLOAD, l1X2, src, num, opt) /* load value from register */ \ _(RSTORE, s2X1, src, def, num) /* store value into register */ \ _(LOAD, l2, src, ref, ___) /* load from memory */ \ + _(LOAD_v, l2, src, ref, ___) /* volatile variant of VLOAD */ \ _(STORE, s3, src, ref, def) /* store to memory */ \ + _(STORE_v, s3, src, ref, def) /* volatile variant of VSTORE */ \ _(TLS, l1X2, src, num, num) /* thread local variable */ \ _(TRAP, x1, src, ___, ___) /* DebugBreak */ \ /* memory reference ops (A, H, U, S, TMP, STR, NEW, X, V) ??? */ \ @@ -360,7 +366,7 @@ typedef enum _ir_type { /* control-flow nodes */ \ _(START, S0X1, ret, ___, ___) /* function start */ \ _(ENTRY, S1X1, src, num, ___) /* entry with a fake src edge */ \ - _(BEGIN, S1, src, ___, ___) /* block start */ \ + _(BEGIN, S1X1, src, lbl, ___) /* block start, optional &&lbl */ \ _(IF_TRUE, S1X1, src, prb, ___) /* IF TRUE proj. */ \ _(IF_FALSE, S1X1, src, prb, ___) /* IF FALSE proj. */ \ _(CASE_VAL, S2X1, src, def, prb) /* switch proj. */ \ @@ -372,8 +378,9 @@ typedef enum _ir_type { _(LOOP_END, E1, src, ___, ___) /* loop end */ \ _(IF, E2, src, def, ___) /* conditional control split */ \ _(SWITCH, E2, src, def, ___) /* multi-way control split */ \ + _(IGOTO, E2, src, def, ___) /* computed goto (internal) */ \ + _(IJMP, T2X1, src, def, ret) /* computed goto (terminating) */ \ _(RETURN, T2X1, src, def, ret) /* function return */ \ - _(IJMP, T2X1, src, def, ret) /* computed goto */ \ _(UNREACHABLE, T1X2, src, ___, ret) /* unreachable (tailcall, etc) */ \ \ /* deoptimization helper */ \ @@ -400,6 +407,13 @@ typedef enum _ir_op { #define IR_OPTX(op, type, n) ((uint32_t)(op) | ((uint32_t)(type) << IR_OPT_TYPE_SHIFT) | ((uint32_t)(n) << IR_OPT_INPUTS_SHIFT)) #define IR_OPT_TYPE(opt) (((opt) & IR_OPT_TYPE_MASK) >> IR_OPT_TYPE_SHIFT) +/* "opt" modifiers */ +#define IR_COPY_HARD (1<<0) + +#define IR_VA_ARG_SIZE(op3) (((uint32_t)(op3) >> 3)) +#define IR_VA_ARG_ALIGN(op3) (1U << ((uint32_t)(op3) & 0x7)) +#define IR_VA_ARG_OP3(s, a) (((s) << 3) | ir_ntzl(a)) + /* IR References */ typedef int32_t ir_ref; @@ -533,6 +547,9 @@ void ir_strtab_free(ir_strtab *strtab); #define IR_EXTERN (1<<5) #define IR_CONST (1<<6) +#define IR_CONST_FUNC (1<<6) +#define IR_PURE_FUNC (1<<7) + #define IR_INITIALIZED (1<<7) /* sym data flag: constant or an initialized variable */ #define IR_CONST_STRING (1<<8) /* sym data flag: constant string */ @@ -648,7 +665,6 @@ struct _ir_ctx { ir_ref vars; /* list of VARs (used by register allocator) */ }; ir_snapshot_create_t snapshot_create; - int32_t stack_frame_alignment; int32_t stack_frame_size; /* spill stack frame size (used by register allocator and code generator) */ int32_t call_stack_size; /* stack for parameter passing (used by register allocator and code generator) */ uint64_t used_preserved_regs; @@ -698,6 +714,7 @@ ir_ref ir_const_func_addr(ir_ctx *ctx, uintptr_t c, ir_ref proto); ir_ref ir_const_func(ir_ctx *ctx, ir_ref str, ir_ref proto); ir_ref ir_const_sym(ir_ctx *ctx, ir_ref str); ir_ref ir_const_str(ir_ctx *ctx, ir_ref str); +ir_ref ir_const_label(ir_ctx *ctx, ir_ref str); ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t c); @@ -893,6 +910,7 @@ struct _ir_loader { void*(*resolve_sym_name) (ir_loader *loader, const char *name, uint32_t flags); bool (*has_sym) (ir_loader *loader, const char *name); bool (*add_sym) (ir_loader *loader, const char *name, void *addr); + bool (*add_label) (ir_loader *loader, const char *name, void *addr); }; void ir_loader_init(void); diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc index 12c3694d469f0..b553243309f54 100644 --- a/ext/opcache/jit/ir/ir_aarch64.dasc +++ b/ext/opcache/jit/ir/ir_aarch64.dasc @@ -218,6 +218,7 @@ typedef struct _ir_backend_data { dasm_State *dasm_state; ir_bitset emit_constants; int rodata_label, jmp_table_label; + bool resolved_label_syms; } ir_backend_data; #define IR_GP_REG_NAME(code, name64, name32) \ @@ -315,6 +316,7 @@ const char *ir_reg_name(int8_t reg, ir_type type) _(RETURN_VOID) \ _(RETURN_INT) \ _(RETURN_FP) \ + _(IGOTO_DUP) \ #define IR_RULE_ENUM(name) IR_ ## name, @@ -385,7 +387,7 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co n++; break; } - } else if (ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA) { + } else if (!IR_IS_CONST_REF(insn->op2) && ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA) { constraints->tmp_regs[n] = IR_TMP_REG(2, IR_ADDR, IR_LOAD_SUB_REF, IR_DEF_SUB_REF); n++; } @@ -478,10 +480,16 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co if (IR_IS_CONST_REF(insn->op1)) { constraints->tmp_regs[n] = IR_TMP_REG(1, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF); n++; + } else if (ir_rule(ctx, insn->op1) == IR_STATIC_ALLOCA) { + constraints->tmp_regs[n] = IR_TMP_REG(1, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF); + n++; } if (IR_IS_CONST_REF(insn->op2) && insn->op1 != insn->op2) { constraints->tmp_regs[n] = IR_TMP_REG(2, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF); n++; + } else if (!IR_IS_CONST_REF(insn->op2) && ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA) { + constraints->tmp_regs[n] = IR_TMP_REG(2, insn->type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF); + n++; } break; case IR_CMP_INT: @@ -520,6 +528,7 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co } break; case IR_VSTORE: + case IR_VSTORE_v: insn = &ctx->ir_base[ref]; if (IR_IS_CONST_REF(insn->op3)) { insn = &ctx->ir_base[insn->op3]; @@ -596,6 +605,19 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co } flags = IR_USE_SHOULD_BE_IN_REG | IR_OP2_MUST_BE_IN_REG | IR_OP3_SHOULD_BE_IN_REG; break; + case IR_IGOTO: + insn = &ctx->ir_base[ref]; + if (ctx->ir_base[insn->op1].op == IR_MERGE || ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN) { + ir_insn *merge = &ctx->ir_base[insn->op1]; + ir_ref *p, n = merge->inputs_count; + + for (p = merge->ops + 1; n > 0; p++, n--) { + ir_ref input = *p; + IR_ASSERT(ctx->ir_base[input].op == IR_END || ctx->ir_base[input].op == IR_LOOP_END); + ctx->rules[input] = IR_IGOTO_DUP; + } + } + return insn->op; case IR_COND: insn = &ctx->ir_base[ref]; n = 0; @@ -665,7 +687,7 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co } break; case IR_VA_ARG: - flags = IR_USE_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG; + flags = IR_USE_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG | IR_DEF_CONFLICTS_WITH_INPUT_REGS; constraints->tmp_regs[0] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_SAVE_SUB_REF); n = 1; insn = &ctx->ir_base[ref]; @@ -714,7 +736,8 @@ static void ir_match_fuse_addr(ir_ctx *ctx, ir_ref addr_ref, ir_type type) do { ir_insn *insn = &ctx->ir_base[*p]; - if (insn->op != IR_LOAD && (insn->op != IR_STORE || insn->op3 == addr_ref)) { + if (insn->op != IR_LOAD && insn->op != IR_LOAD_v + && ((insn->op != IR_STORE && insn->op != IR_STORE_v) || insn->op3 == addr_ref)) { return; } p++; @@ -961,7 +984,7 @@ binop_fp: ctx->flags2 |= IR_HAS_CALLS; return IR_CALL; case IR_VAR: - return IR_SKIPPED | IR_VAR; + return IR_STATIC_ALLOCA; case IR_PARAM: return ctx->use_lists[ref].count > 0 ? IR_PARAM : IR_SKIPPED | IR_PARAM; case IR_ALLOCA: @@ -978,6 +1001,7 @@ binop_fp: } return IR_ALLOCA; case IR_LOAD: + case IR_LOAD_v: ir_match_fuse_addr(ctx, insn->op2, insn->type); if (IR_IS_TYPE_INT(insn->type)) { return IR_LOAD_INT; @@ -986,6 +1010,7 @@ binop_fp: } break; case IR_STORE: + case IR_STORE_v: ir_match_fuse_addr(ctx, insn->op2, ctx->ir_base[insn->op3].type); if (IR_IS_TYPE_INT(ctx->ir_base[insn->op3].type)) { return IR_STORE_INT; @@ -1364,7 +1389,7 @@ static void ir_emit_load_imm_fp(ir_ctx *ctx, ir_type type, ir_reg reg, ir_ref sr } else if (type == IR_DOUBLE && insn->val.u64 == 0) { | fmov Rd(reg-IR_REG_FP_FIRST), xzr } else { - label = ir_const_label(ctx, src); + label = ir_get_const_label(ctx, src); if (type == IR_DOUBLE) { | ldr Rd(reg-IR_REG_FP_FIRST), =>label } else { @@ -1441,10 +1466,41 @@ static void ir_load_local_addr(ir_ctx *ctx, ir_reg reg, ir_ref src) | add Rx(reg), Rx(base), #offset } else { ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); - | add Rx(reg), sp, Rx(IR_REG_INT_TMP) + | add Rx(reg), Rx(base), Rx(IR_REG_INT_TMP) } } +static void ir_resolve_label_syms(ir_ctx *ctx) +{ + uint32_t b; + ir_block *bb; + + for (b = 1, bb = &ctx->cfg_blocks[b]; b <= ctx->cfg_blocks_count; bb++, b++) { + ir_insn *insn = &ctx->ir_base[bb->start]; + + if (insn->op == IR_BEGIN && insn->op2) { + IR_ASSERT(ctx->ir_base[insn->op2].op == IR_LABEL); + ctx->ir_base[insn->op2].val.u32_hi = b; + } + } +} + +static void ir_emit_load_label_addr(ir_ctx *ctx, ir_reg reg, ir_insn *label) +{ + ir_backend_data *data = ctx->data; + dasm_State **Dst = &data->dasm_state; + + if (!data->resolved_label_syms) { + data->resolved_label_syms = 1; + ir_resolve_label_syms(ctx); + } + + IR_ASSERT(label->op == IR_LABEL); + int b = label->val.u32_hi; + + b = ir_skip_empty_target_blocks(ctx, b); + | adr Rx(reg), =>b +} static void ir_emit_load(ir_ctx *ctx, ir_type type, ir_reg reg, ir_ref src) { @@ -1459,9 +1515,11 @@ static void ir_emit_load(ir_ctx *ctx, ir_type type, ir_reg reg, ir_ref src) } else if (insn->op == IR_STR) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; - int label = ir_const_label(ctx, src); + int label = ir_get_const_label(ctx, src); | adr Rx(reg), =>label + } else if (insn->op == IR_LABEL) { + ir_emit_load_label_addr(ctx, reg, insn); } else { ir_emit_load_imm_int(ctx, type, reg, insn->val.i64); } @@ -1697,6 +1755,7 @@ static void ir_emit_prologue(ir_ctx *ctx) | str Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset] } else { ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + offset -= sizeof(void*); | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] | sub Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 | str Rd(i-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] @@ -1795,7 +1854,12 @@ static void ir_emit_prologue(ir_ctx *ctx) offset += 16 * ctx->fp_reg_params; for (i = ctx->fp_reg_params; i < IR_REG_FP_ARGS; i++) { // TODO: Rd->Rq stur->str ??? - | str Rd(fp_reg_params[i]-IR_REG_FP_FIRST), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, 8)) { + | str Rd(fp_reg_params[i]-IR_REG_FP_FIRST), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rd(fp_reg_params[i]-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] + } offset += 16; } } @@ -1828,26 +1892,44 @@ static void ir_emit_epilogue(ir_ctx *ctx) offset -= sizeof(void*) * 2; if (aarch64_may_encode_imm7_addr_offset(offset, 8)) { | ldp Rx(prev), Rx(i), [Rx(fp), #offset] - } else { - IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8)); + } else if (aarch64_may_encode_addr_offset(offset + 8, 8)) { | ldr Rx(prev), [Rx(fp), #offset] | ldr Rx(i), [Rx(fp), #(offset+8)] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | ldr Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + | add Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 + | ldr Rx(i), [Rx(fp), Rx(IR_REG_INT_TMP)] } prev = IR_REG_NONE; } else { if (prev < IR_REG_FP_FIRST) { offset -= sizeof(void*); - | ldr Rx(prev), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, 8)) { + | ldr Rx(prev), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | ldr Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + } offset -= sizeof(void*); - | ldr Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, 8)) { + | ldr Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | ldr Rd(i-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } else { offset -= sizeof(void*) * 2; if (aarch64_may_encode_imm7_addr_offset(offset, 8)) { | ldp Rd(prev-IR_REG_FP_FIRST), Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset] - } else { - IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8)); + } else if (aarch64_may_encode_addr_offset(offset + 8, 8)) { | ldr Rd(prev-IR_REG_FP_FIRST), [Rx(fp), #offset] | ldr Rd(i-IR_REG_FP_FIRST), [Rx(fp), #(offset+8)] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | ldr Rx(prev-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] + | add Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 + | ldr Rx(i-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] } } prev = IR_REG_NONE; @@ -1857,10 +1939,20 @@ static void ir_emit_epilogue(ir_ctx *ctx) if (prev != IR_REG_NONE) { if (prev < IR_REG_FP_FIRST) { offset -= sizeof(void*); - | ldr Rx(prev), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, 8)) { + | ldr Rx(prev), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | ldr Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } else { offset -= sizeof(void*); - | ldr Rd(prev-IR_REG_FP_FIRST), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, 8)) { + | ldr Rd(prev-IR_REG_FP_FIRST), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | ldr Rd(prev-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } } } @@ -1909,6 +2001,9 @@ static void ir_emit_binop_int(ir_ctx *ctx, ir_ref def, ir_insn *insn) op1_reg = IR_REG_NUM(op1_reg); ir_emit_load(ctx, type, op1_reg, op1); } + if (op2_reg == IR_REG_NONE && op1 == op2) { + op2_reg = op1_reg; + } if (op2_reg != IR_REG_NONE) { if (IR_REG_SPILLED(op2_reg)) { op2_reg = IR_REG_NUM(op2_reg); @@ -3415,25 +3510,52 @@ static void ir_emit_sext(ir_ctx *ctx, ir_ref def, ir_insn *insn) int32_t offset = ir_ref_spill_slot_offset(ctx, insn->op1, &fp); if (ir_type_size[src_type] == 1) { - if (ir_type_size[dst_type] == 2) { - | ldrsb Rw(def_reg), [Rx(fp), #offset] - } else if (ir_type_size[dst_type] == 4) { - | ldrsb Rw(def_reg), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, ir_type_size[src_type])) { + if (ir_type_size[dst_type] == 2) { + | ldrsb Rw(def_reg), [Rx(fp), #offset] + } else if (ir_type_size[dst_type] == 4) { + | ldrsb Rw(def_reg), [Rx(fp), #offset] + } else { + IR_ASSERT(ir_type_size[dst_type] == 8); + | ldrsb Rx(def_reg), [Rx(fp), #offset] + } } else { - IR_ASSERT(ir_type_size[dst_type] == 8); - | ldrsb Rx(def_reg), [Rx(fp), #offset] + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + if (ir_type_size[dst_type] == 2) { + | ldrsb Rw(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } else if (ir_type_size[dst_type] == 4) { + | ldrsb Rw(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } else { + IR_ASSERT(ir_type_size[dst_type] == 8); + | ldrsb Rx(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } } else if (ir_type_size[src_type] == 2) { - if (ir_type_size[dst_type] == 4) { - | ldrsh Rw(def_reg), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, ir_type_size[src_type])) { + if (ir_type_size[dst_type] == 4) { + | ldrsh Rw(def_reg), [Rx(fp), #offset] + } else { + IR_ASSERT(ir_type_size[dst_type] == 8); + | ldrsh Rx(def_reg), [Rx(fp), #offset] + } } else { - IR_ASSERT(ir_type_size[dst_type] == 8); - | ldrsh Rx(def_reg), [Rx(fp), #offset] + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + if (ir_type_size[dst_type] == 4) { + | ldrsh Rw(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } else { + IR_ASSERT(ir_type_size[dst_type] == 8); + | ldrsh Rx(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } } else { IR_ASSERT(ir_type_size[src_type] == 4); IR_ASSERT(ir_type_size[dst_type] == 8); - | ldrsw Rx(def_reg), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, ir_type_size[src_type])) { + | ldrsw Rx(def_reg), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | ldrsw Rx(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } } if (IR_REG_SPILLED(ctx->regs[def][0])) { @@ -3473,14 +3595,27 @@ static void ir_emit_zext(ir_ctx *ctx, ir_ref def, ir_insn *insn) ir_reg fp; int32_t offset = ir_ref_spill_slot_offset(ctx, insn->op1, &fp); - if (ir_type_size[src_type] == 1) { - | ldrb Rw(def_reg), [Rx(fp), #offset] - } else if (ir_type_size[src_type] == 2) { - | ldrh Rw(def_reg), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, ir_type_size[src_type])) { + if (ir_type_size[src_type] == 1) { + | ldrb Rw(def_reg), [Rx(fp), #offset] + } else if (ir_type_size[src_type] == 2) { + | ldrh Rw(def_reg), [Rx(fp), #offset] + } else { + IR_ASSERT(ir_type_size[src_type] == 4); + IR_ASSERT(ir_type_size[dst_type] == 8); + | ldr Rw(def_reg), [Rx(fp), #offset] + } } else { - IR_ASSERT(ir_type_size[src_type] == 4); - IR_ASSERT(ir_type_size[dst_type] == 8); - | ldr Rw(def_reg), [Rx(fp), #offset] + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + if (ir_type_size[src_type] == 1) { + | ldrb Rw(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } else if (ir_type_size[src_type] == 2) { + | ldrh Rw(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } else { + IR_ASSERT(ir_type_size[src_type] == 4); + IR_ASSERT(ir_type_size[dst_type] == 8); + | ldr Rw(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } } if (IR_REG_SPILLED(ctx->regs[def][0])) { @@ -3579,11 +3714,21 @@ static void ir_emit_bitcast(ir_ctx *ctx, ir_ref def, ir_insn *insn) ir_reg fp; int32_t offset = ir_ref_spill_slot_offset(ctx, insn->op1, &fp); - if (src_type == IR_DOUBLE) { - | ldr Rx(def_reg), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, ir_type_size[src_type])) { + if (src_type == IR_DOUBLE) { + | ldr Rx(def_reg), [Rx(fp), #offset] + } else { + IR_ASSERT(src_type == IR_FLOAT); + | ldr Rw(def_reg), [Rx(fp), #offset] + } } else { - IR_ASSERT(src_type == IR_FLOAT); - | ldr Rw(def_reg), [Rx(fp), #offset] + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + if (src_type == IR_DOUBLE) { + | ldr Rx(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } else { + IR_ASSERT(src_type == IR_FLOAT); + | ldr Rw(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } } } else if (IR_IS_TYPE_FP(dst_type)) { @@ -3605,12 +3750,22 @@ static void ir_emit_bitcast(ir_ctx *ctx, ir_ref def, ir_insn *insn) ir_reg fp; int32_t offset = ir_ref_spill_slot_offset(ctx, insn->op1, &fp); - if (dst_type == IR_DOUBLE) { - | ldr Rd(def_reg), [Rx(fp), #offset] - } else { - IR_ASSERT(src_type == IR_FLOAT); - | ldr Rs(def_reg), [Rx(fp), #offset] - } + if (aarch64_may_encode_addr_offset(offset, ir_type_size[src_type])) { + if (dst_type == IR_DOUBLE) { + | ldr Rd(def_reg), [Rx(fp), #offset] + } else { + IR_ASSERT(dst_type == IR_FLOAT); + | ldr Rs(def_reg), [Rx(fp), #offset] + } + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + if (dst_type == IR_DOUBLE) { + | ldr Rd(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } else { + IR_ASSERT(dst_type == IR_FLOAT); + | ldr Rs(def_reg), [Rx(fp), Rx(IR_REG_INT_TMP)] + } + } } } if (IR_REG_SPILLED(ctx->regs[def][0])) { @@ -3833,7 +3988,12 @@ static void ir_emit_vaddr(ir_ctx *ctx, ir_ref def, ir_insn *insn) IR_ASSERT(def_reg != IR_REG_NONE); offset = ir_var_spill_slot(ctx, insn->op1, &fp); - | add Rx(def_reg), Rx(fp), #offset + if (aarch64_may_encode_imm12(offset)) { + | add Rx(def_reg), Rx(fp), #offset + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | add Rx(def_reg), Rx(fp), Rx(IR_REG_INT_TMP) + } if (IR_REG_SPILLED(ctx->regs[def][0])) { ir_emit_store(ctx, type, def, def_reg); } @@ -4221,7 +4381,12 @@ static void ir_emit_afree(ir_ctx *ctx, ir_ref def, ir_insn *insn) /* Stack must be 16 byte aligned */ size = IR_ALIGNED_SIZE(size, 16); - | add sp, sp, #size + if (aarch64_may_encode_imm12(size)) { + | add sp, sp, #size + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, size); + | add sp, sp, Rx(IR_REG_INT_TMP) + } if (!(ctx->flags & IR_USE_FRAME_POINTER)) { ctx->call_stack_size -= size; } @@ -4283,8 +4448,11 @@ static void ir_emit_frame_addr(ir_ctx *ctx, ir_ref def) if (ctx->flags & IR_USE_FRAME_POINTER) { | mov Rx(def_reg), Rx(IR_REG_X29) - } else { + } else if (aarch64_may_encode_imm12(ctx->stack_frame_size + ctx->call_stack_size)) { | add Rx(def_reg), Rx(IR_REG_X31), #(ctx->stack_frame_size + ctx->call_stack_size) + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, ctx->stack_frame_size + ctx->call_stack_size); + | add Rx(def_reg), Rx(IR_REG_X31), Rx(IR_REG_INT_TMP) } if (IR_REG_SPILLED(ctx->regs[def][0])) { ir_emit_store(ctx, IR_ADDR, def, def_reg); @@ -4377,7 +4545,7 @@ static void ir_emit_va_start(ir_ctx *ctx, ir_ref def, ir_insn *insn) if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < IR_REG_FP_ARGS) { reg_save_area_offset += 16 * IR_REG_FP_ARGS; /* Set va_list.vr_top */ - if (overflow_arg_area_offset != reg_save_area_offset) { + if (overflow_arg_area_offset != reg_save_area_offset || ctx->gp_reg_params < IR_REG_INT_ARGS) { | add Rx(tmp_reg), Rx(fp), #reg_save_area_offset } | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, vr_top))] @@ -5246,6 +5414,19 @@ static void ir_emit_ijmp(ir_ctx *ctx, ir_ref def, ir_insn *insn) } | br Rx(op2_reg) } else if (IR_IS_CONST_REF(insn->op2)) { + if (ctx->ir_base[insn->op2].op == IR_LABEL) { + if (!data->resolved_label_syms) { + data->resolved_label_syms = 1; + ir_resolve_label_syms(ctx); + } + + uint32_t target = ctx->ir_base[insn->op2].val.u32_hi; + target = ir_skip_empty_target_blocks(ctx, target); + + | b =>target + return; + } + void *addr = ir_jmp_addr(ctx, insn, &ctx->ir_base[insn->op2]); if (aarch64_may_use_b(ctx->code_buffer, addr)) { @@ -5636,6 +5817,7 @@ static void ir_emit_param_move(ir_ctx *ctx, uint8_t type, ir_reg from_reg, ir_re { ir_reg fp = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = IR_SPILL_POS_TO_OFFSET(offset); IR_ASSERT(from_reg != IR_REG_NONE || to_reg != IR_REG_NONE); if (IR_IS_TYPE_INT(type)) { @@ -5676,13 +5858,8 @@ static void ir_emit_load_params(ir_ctx *ctx) const int8_t *int_reg_params = _ir_int_reg_params; const int8_t *fp_reg_params = _ir_fp_reg_params; int32_t stack_offset = 0; + int32_t stack_start = ctx->stack_frame_size; - if (ctx->flags & IR_USE_FRAME_POINTER) { - /* skip old frame pointer and return address */ - stack_offset = sizeof(void*) * 2 + ctx->stack_frame_size + ctx->call_stack_size; - } else { - stack_offset = ctx->stack_frame_size + ctx->call_stack_size; - } n = use_list->count; for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) { use = *p; @@ -5706,12 +5883,9 @@ static void ir_emit_load_params(ir_ctx *ctx) if (ctx->vregs[use]) { dst_reg = IR_REG_NUM(ctx->regs[use][0]); IR_ASSERT(src_reg != IR_REG_NONE || dst_reg != IR_REG_NONE || - stack_offset == ctx->live_intervals[ctx->vregs[use]]->stack_spill_pos + - ((ctx->flags & IR_USE_FRAME_POINTER) ? - -(ctx->stack_frame_size - ctx->stack_frame_alignment) : - ctx->call_stack_size)); + stack_start + stack_offset == ctx->live_intervals[ctx->vregs[use]]->stack_spill_pos); if (src_reg != dst_reg) { - ir_emit_param_move(ctx, insn->type, src_reg, dst_reg, use, stack_offset); + ir_emit_param_move(ctx, insn->type, src_reg, dst_reg, use, stack_start + stack_offset); } if (dst_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[use][0])) { ir_emit_store(ctx, insn->type, use, dst_reg); @@ -5785,14 +5959,8 @@ static void ir_fix_param_spills(ir_ctx *ctx) const int8_t *int_reg_params = _ir_int_reg_params; const int8_t *fp_reg_params = _ir_fp_reg_params; int32_t stack_offset = 0; - int32_t param_stack_size = 0; + int32_t stack_start = ctx->stack_frame_size; - if (ctx->flags & IR_USE_FRAME_POINTER) { - /* skip old frame pointer and return address */ - stack_offset = sizeof(void*) * 2 + (ctx->stack_frame_size - ctx->stack_frame_alignment); - } else { - stack_offset = ctx->stack_frame_size; - } n = use_list->count; for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) { use = *p; @@ -5819,15 +5987,13 @@ static void ir_fix_param_spills(ir_ctx *ctx) if ((ival->flags & IR_LIVE_INTERVAL_MEM_PARAM) && ival->stack_spill_pos == -1 && (ival->next || ival->reg == IR_REG_NONE)) { - ival->stack_spill_pos = stack_offset; + ival->stack_spill_pos = stack_start + stack_offset; } } if (sizeof(void*) == 8) { stack_offset += sizeof(void*); - param_stack_size += sizeof(void*); } else { stack_offset += IR_MAX(sizeof(void*), ir_type_size[insn->type]); - param_stack_size += IR_MAX(sizeof(void*), ir_type_size[insn->type]); } } } @@ -5835,7 +6001,7 @@ static void ir_fix_param_spills(ir_ctx *ctx) ctx->gp_reg_params = IR_MIN(int_param_num, int_reg_params_count); ctx->fp_reg_params = IR_MIN(fp_param_num, fp_reg_params_count); - ctx->param_stack_size = param_stack_size; + ctx->param_stack_size = stack_offset; } static void ir_allocate_unique_spill_slots(ir_ctx *ctx) @@ -5876,6 +6042,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) case IR_MERGE: case IR_LOOP_BEGIN: case IR_LOOP_END: + case IR_IGOTO_DUP: break; default: def_flags = ir_get_target_constraints(ctx, i, &constraints); @@ -5892,7 +6059,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) IR_REGSET_EXCL(available, reg); ctx->regs[i][0] = reg | IR_REG_SPILL_STORE; } else if (def_flags & IR_USE_MUST_BE_IN_REG) { - if (insn->op == IR_VLOAD + if ((insn->op == IR_VLOAD || insn->op == IR_VLOAD_v) && ctx->live_intervals[ctx->vregs[i]] && ctx->live_intervals[ctx->vregs[i]]->stack_spill_pos != -1 && ir_is_same_mem_var(ctx, i, ctx->ir_base[insn->op2].op3)) { @@ -5932,7 +6099,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) { use = *p; use_insn = &ctx->ir_base[use]; - if (use_insn->op == IR_VLOAD) { + if (use_insn->op == IR_VLOAD || use_insn->op == IR_VLOAD_v) { if (ctx->vregs[use] && !ctx->live_intervals[ctx->vregs[use]]) { ir_live_interval *ival = ir_arena_alloc(&ctx->arena, sizeof(ir_live_interval)); @@ -5943,7 +6110,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) ival->vreg = ctx->vregs[use]; ival->stack_spill_pos = stack_spill_pos; } - } else if (use_insn->op == IR_VSTORE) { + } else if (use_insn->op == IR_VSTORE || use_insn->op == IR_STORE_v) { if (!IR_IS_CONST_REF(use_insn->op3) && ctx->vregs[use_insn->op3] && !ctx->live_intervals[ctx->vregs[use_insn->op3]]) { @@ -6080,25 +6247,21 @@ void ir_fix_stack_frame(ir_ctx *ctx) ctx->stack_frame_size = IR_ALIGNED_SIZE(ctx->stack_frame_size, sizeof(void*)); ctx->stack_frame_size += additional_size; - ctx->stack_frame_alignment = 0; ctx->call_stack_size = 0; if (!(ctx->flags & IR_FUNCTION)) { while (IR_ALIGNED_SIZE(ctx->stack_frame_size, 16) != ctx->stack_frame_size) { ctx->stack_frame_size += sizeof(void*); - ctx->stack_frame_alignment += sizeof(void*); } } else { /* Stack must be 16 byte aligned */ if (!(ctx->flags & IR_FUNCTION)) { while (IR_ALIGNED_SIZE(ctx->stack_frame_size, 16) != ctx->stack_frame_size) { ctx->stack_frame_size += sizeof(void*); - ctx->stack_frame_alignment += sizeof(void*); } } else if (ctx->flags & IR_USE_FRAME_POINTER) { while (IR_ALIGNED_SIZE(ctx->stack_frame_size + sizeof(void*) * 2, 16) != ctx->stack_frame_size + sizeof(void*) * 2) { ctx->stack_frame_size += sizeof(void*); - ctx->stack_frame_alignment += sizeof(void*); } } else { if (!(ctx->flags & IR_NO_STACK_COMBINE)) { @@ -6107,7 +6270,6 @@ void ir_fix_stack_frame(ir_ctx *ctx) while (IR_ALIGNED_SIZE(ctx->stack_frame_size + ctx->call_stack_size, 16) != ctx->stack_frame_size + ctx->call_stack_size) { ctx->stack_frame_size += sizeof(void*); - ctx->stack_frame_alignment += sizeof(void*); } } } @@ -6143,6 +6305,8 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) int ret; void *entry; size_t size; + ir_ref igoto_dup_ref = IR_UNUSED; + uint32_t igoto_dup_block = 0; data.ra_data.unused_slot_4 = 0; data.ra_data.unused_slot_2 = 0; @@ -6150,11 +6314,11 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) data.ra_data.handled = NULL; data.rodata_label = 0; data.jmp_table_label = 0; + data.resolved_label_syms = 0; ctx->data = &data; if (!ctx->live_intervals) { ctx->stack_frame_size = 0; - ctx->stack_frame_alignment = 0; ctx->call_stack_size = 0; ctx->used_preserved_regs = 0; ir_allocate_unique_spill_slots(ctx); @@ -6176,7 +6340,6 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) } ctx->stack_frame_size = ctx->fixed_stack_frame_size; ctx->call_stack_size = ctx->fixed_call_stack_size; - ctx->stack_frame_alignment = 0; } Dst = &data.dasm_state; @@ -6386,6 +6549,35 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) case IR_TAILCALL: ir_emit_tailcall(ctx, i, insn); break; + case IR_IGOTO_DUP: + if (bb->flags & IR_BB_DESSA_MOVES) { + ir_emit_dessa_moves(ctx, b, bb); + } + IR_ASSERT(!igoto_dup_ref && !igoto_dup_block); + igoto_dup_ref = i; + igoto_dup_block = b; + b = ctx->cfg_edges[bb->successors]; + bb = &ctx->cfg_blocks[b]; + i = bb->start; + insn = &ctx->ir_base[i]; + rule = &ctx->rules[i]; + break; + case IR_IGOTO: + if ((ctx->ir_base[insn->op1].op == IR_MERGE || ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN) + && (ctx->rules[ctx->ir_base[insn->op1].op1] & IR_RULE_MASK) == IR_IGOTO_DUP + && igoto_dup_ref) { + ir_emit_ijmp(ctx, i, insn); + b = igoto_dup_block; + bb = &ctx->cfg_blocks[b]; + i = igoto_dup_ref; + insn = &ctx->ir_base[i]; + rule = &ctx->rules[i]; + igoto_dup_block= 0; + igoto_dup_ref = 0; + break; + } + IR_ASSERT(!igoto_dup_ref && !igoto_dup_block); + IR_FALLTHROUGH; case IR_IJMP: ir_emit_ijmp(ctx, i, insn); break; @@ -6396,9 +6588,11 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) ir_emit_vaddr(ctx, i, insn); break; case IR_VLOAD: + case IR_VLOAD_v: ir_emit_vload(ctx, i, insn); break; case IR_VSTORE: + case IR_VSTORE_v: ir_emit_vstore(ctx, i, insn); break; case IR_RLOAD: @@ -6645,6 +6839,28 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) } while (i != 0); } + if ((ctx->flags2 & IR_HAS_BLOCK_ADDR) && ctx->loader && ctx->loader->add_label) { + for (b = 1, bb = &ctx->cfg_blocks[b]; b <= ctx->cfg_blocks_count; bb++, b++) { + ir_insn *insn = &ctx->ir_base[bb->start]; + + if (insn->op == IR_BEGIN && insn->op2) { + IR_ASSERT(ctx->ir_base[insn->op2].op == IR_LABEL); + ctx->ir_base[insn->op2].val.u32_hi = 0; + ctx->loader->add_label(ctx->loader, ir_get_str(ctx, ctx->ir_base[insn->op2].val.str), + (char*)entry + dasm_getpclabel(&data.dasm_state, ir_skip_empty_target_blocks(ctx, b))); + } + } + } else if (data.resolved_label_syms) { + for (b = 1, bb = &ctx->cfg_blocks[b]; b <= ctx->cfg_blocks_count; bb++, b++) { + ir_insn *insn = &ctx->ir_base[bb->start]; + + if (insn->op == IR_BEGIN && insn->op2) { + IR_ASSERT(ctx->ir_base[insn->op2].op == IR_LABEL); + ctx->ir_base[insn->op2].val.u32_hi = 0; + } + } + } + dasm_free(&data.dasm_state); if (ctx->code_buffer) { diff --git a/ext/opcache/jit/ir/ir_builder.h b/ext/opcache/jit/ir/ir_builder.h index c1dcffdbaa084..03add75906553 100644 --- a/ext/opcache/jit/ir/ir_builder.h +++ b/ext/opcache/jit/ir/ir_builder.h @@ -490,7 +490,7 @@ extern "C" { #define ir_ADD_OFFSET(_addr, _offset) _ir_ADD_OFFSET(_ir_CTX, (_addr), (_offset)) /* Unfoldable variant of COPY */ -#define ir_HARD_COPY(_type, _op1) ir_emit2(_ir_CTX, IR_OPT(IR_COPY, (_type)), (_op1), 1) +#define ir_HARD_COPY(_type, _op1) ir_emit2(_ir_CTX, IR_OPT(IR_COPY, (_type)), (_op1), IR_COPY_HARD) #define ir_HARD_COPY_B(_op1) ir_HARD_COPY(IR_BOOL, _op1) #define ir_HARD_COPY_U8(_op1) ir_HARD_COPY(IR_U8, _op1) #define ir_HARD_COPY_U16(_op1) ir_HARD_COPY(IR_U16, _op1) @@ -544,6 +544,8 @@ extern "C" { #define ir_VLOAD_D(_var) _ir_VLOAD(_ir_CTX, IR_DOUBLE, (_var)) #define ir_VLOAD_F(_var) _ir_VLOAD(_ir_CTX, IR_FLOAT, (_var)) #define ir_VSTORE(_var, _val) _ir_VSTORE(_ir_CTX, (_var), (_val)) +#define ir_VLOAD_v(_type, _var) _ir_VLOAD_v(_ir_CTX, (_type), (_var)) +#define ir_VSTORE_v(_var, _val) _ir_VSTORE_v(_ir_CTX, (_var), (_val)) #define ir_RLOAD(_type, _reg) _ir_RLOAD(_ir_CTX, (_type), (_reg)) #define ir_RLOAD_B(_reg) _ir_RLOAD(_ir_CTX, IR_BOOL, (_reg)) #define ir_RLOAD_U8(_reg) _ir_RLOAD(_ir_CTX, IR_U8, (_reg)) @@ -574,6 +576,8 @@ extern "C" { #define ir_LOAD_D(_addr) _ir_LOAD(_ir_CTX, IR_DOUBLE, (_addr)) #define ir_LOAD_F(_addr) _ir_LOAD(_ir_CTX, IR_FLOAT, (_addr)) #define ir_STORE(_addr, _val) _ir_STORE(_ir_CTX, (_addr), (_val)) +#define ir_LOAD_v(_type, _addr) _ir_LOAD_v(_ir_CTX, (_type), (_addr)) +#define ir_STORE_v(_addr, _val) _ir_STORE_v(_ir_CTX, (_addr), (_val)) #define ir_TLS(_index, _offset) _ir_TLS(_ir_CTX, (_index), (_offset)) #define ir_TRAP() do {_ir_CTX->control = ir_emit1(_ir_CTX, IR_TRAP, _ir_CTX->control);} while (0) @@ -586,7 +590,7 @@ extern "C" { #define ir_VA_END(_list) _ir_VA_END(_ir_CTX, _list) #define ir_VA_COPY(_dst, _src) _ir_VA_COPY(_ir_CTX, _dst, _src) #define ir_VA_ARG(_list, _type) _ir_VA_ARG(_ir_CTX, _type, _list) -#define ir_VA_ARG_EX(_list, _type, size) _ir_VA_ARG_EX(_ir_CTX, _type, _list, size) +#define ir_VA_ARG_EX(_list, _type, s, a) _ir_VA_ARG_EX(_ir_CTX, _type, _list, s, a) #define ir_START() _ir_START(_ir_CTX) #define ir_ENTRY(_src, _num) _ir_ENTRY(_ir_CTX, (_src), (_num)) @@ -607,6 +611,7 @@ extern "C" { #define ir_CASE_RANGE(_switch, _v1, _v2) _ir_CASE_RANGE(_ir_CTX, (_switch), (_v1), (_v2)) #define ir_CASE_DEFAULT(_switch) _ir_CASE_DEFAULT(_ir_CTX, (_switch)) #define ir_RETURN(_val) _ir_RETURN(_ir_CTX, (_val)) +#define ir_IGOTO(_addr) _ir_IGOTO(_ir_CTX, (_addr)) #define ir_IJMP(_addr) _ir_IJMP(_ir_CTX, (_addr)) #define ir_UNREACHABLE() _ir_UNREACHABLE(_ir_CTX) @@ -654,15 +659,19 @@ ir_ref _ir_ALLOCA(ir_ctx *ctx, ir_ref size); void _ir_AFREE(ir_ctx *ctx, ir_ref size); ir_ref _ir_VLOAD(ir_ctx *ctx, ir_type type, ir_ref var); void _ir_VSTORE(ir_ctx *ctx, ir_ref var, ir_ref val); +ir_ref _ir_VLOAD_v(ir_ctx *ctx, ir_type type, ir_ref var); +void _ir_VSTORE_v(ir_ctx *ctx, ir_ref var, ir_ref val); ir_ref _ir_RLOAD(ir_ctx *ctx, ir_type type, ir_ref reg); void _ir_RSTORE(ir_ctx *ctx, ir_ref reg, ir_ref val); ir_ref _ir_LOAD(ir_ctx *ctx, ir_type type, ir_ref addr); void _ir_STORE(ir_ctx *ctx, ir_ref addr, ir_ref val); +ir_ref _ir_LOAD_v(ir_ctx *ctx, ir_type type, ir_ref addr); +void _ir_STORE_v(ir_ctx *ctx, ir_ref addr, ir_ref val); void _ir_VA_START(ir_ctx *ctx, ir_ref list); void _ir_VA_END(ir_ctx *ctx, ir_ref list); void _ir_VA_COPY(ir_ctx *ctx, ir_ref dst, ir_ref src); ir_ref _ir_VA_ARG(ir_ctx *ctx, ir_type type, ir_ref list); -ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size); +ir_ref _ir_VA_ARG_EX(ir_ctx *ctx, ir_type type, ir_ref list, size_t size, size_t align); void _ir_START(ir_ctx *ctx); void _ir_ENTRY(ir_ctx *ctx, ir_ref src, ir_ref num); void _ir_BEGIN(ir_ctx *ctx, ir_ref src); @@ -688,6 +697,7 @@ void _ir_CASE_VAL(ir_ctx *ctx, ir_ref switch_ref, ir_ref val); void _ir_CASE_RANGE(ir_ctx *ctx, ir_ref switch_ref, ir_ref v1, ir_ref v2); void _ir_CASE_DEFAULT(ir_ctx *ctx, ir_ref switch_ref); void _ir_RETURN(ir_ctx *ctx, ir_ref val); +ir_ref _ir_IGOTO(ir_ctx *ctx, ir_ref addr); void _ir_IJMP(ir_ctx *ctx, ir_ref addr); void _ir_GUARD(ir_ctx *ctx, ir_ref condition, ir_ref addr); void _ir_GUARD_NOT(ir_ctx *ctx, ir_ref condition, ir_ref addr); diff --git a/ext/opcache/jit/ir/ir_cfg.c b/ext/opcache/jit/ir/ir_cfg.c index 00923387bb21c..46755067b2444 100644 --- a/ext/opcache/jit/ir/ir_cfg.c +++ b/ext/opcache/jit/ir/ir_cfg.c @@ -820,11 +820,14 @@ int ir_build_dominators_tree(ir_ctx *ctx) succ_b = ctx->cfg_edges[bb->successors]; if (bb->successors_count != 1) { /* LOOP_END/END may be linked with the following ENTRY by a fake edge */ - IR_ASSERT(bb->successors_count == 2); - if (blocks[succ_b].flags & IR_BB_ENTRY) { + if (bb->successors_count != 2) { + complete = 0; + break; + } else if (blocks[succ_b].flags & IR_BB_ENTRY) { succ_b = ctx->cfg_edges[bb->successors + 1]; - } else { - IR_ASSERT(blocks[ctx->cfg_edges[bb->successors + 1]].flags & IR_BB_ENTRY); + } else if (!(blocks[ctx->cfg_edges[bb->successors + 1]].flags & IR_BB_ENTRY)) { + complete = 0; + break; } } dom_depth = blocks[succ_b].dom_depth;; diff --git a/ext/opcache/jit/ir/ir_check.c b/ext/opcache/jit/ir/ir_check.c index c25a984aefc1d..ee951291b1b05 100644 --- a/ext/opcache/jit/ir/ir_check.c +++ b/ext/opcache/jit/ir/ir_check.c @@ -328,7 +328,9 @@ bool ir_check(const ir_ctx *ctx) } break; case IR_LOAD: + case IR_LOAD_v: case IR_STORE: + case IR_STORE_v: type = ctx->ir_base[insn->op2].type; if (type != IR_ADDR && (!IR_IS_TYPE_INT(type) || ir_type_size[type] != ir_type_size[IR_ADDR])) { @@ -338,7 +340,9 @@ bool ir_check(const ir_ctx *ctx) } break; case IR_VLOAD: + case IR_VLOAD_v: case IR_VSTORE: + case IR_VSTORE_v: if (ctx->ir_base[insn->op2].op != IR_VAR) { fprintf(stderr, "ir_base[%d].op2 must be 'VAR' (%s)\n", i, ir_op_name[ctx->ir_base[insn->op2].op]); @@ -408,6 +412,8 @@ bool ir_check(const ir_ctx *ctx) ok = 0; } break; + case IR_IGOTO: + break; default: /* skip data references */ count = n = use_list->count; diff --git a/ext/opcache/jit/ir/ir_dump.c b/ext/opcache/jit/ir/ir_dump.c index a501d261f30a7..5cc732927d412 100644 --- a/ext/opcache/jit/ir/ir_dump.c +++ b/ext/opcache/jit/ir/ir_dump.c @@ -129,6 +129,11 @@ void ir_dump_dot(const ir_ctx *ctx, const char *name, FILE *f) case IR_OPND_CONTROL_REF: fprintf(f, "\tn%d -> n%d [style=dashed,dir=back,weight=%d];\n", ref, i, REF_WEIGHT); break; + case IR_OPND_LABEL_REF: + if (ref) { + fprintf(f, "\tc%d -> n%d [color=blue,weight=%d];\n", -ref, i, REF_WEIGHT); + } + break; } } } @@ -491,6 +496,8 @@ void ir_dump_codegen(const ir_ctx *ctx, FILE *f) ir_print_proto(ctx, insn->proto, f); } else if (insn->op == IR_SYM) { fprintf(f, "sym(%s)", ir_get_str(ctx, insn->val.name)); + } else if (insn->op == IR_LABEL) { + fprintf(f, "label(%s)", ir_get_str(ctx, insn->val.name)); } else if (insn->op == IR_FUNC_ADDR) { fprintf(f, "func *"); ir_print_const(ctx, insn, f, true); @@ -648,6 +655,12 @@ void ir_dump_codegen(const ir_ctx *ctx, FILE *f) fprintf(f, "%s%d", first ? "(" : ", ", ref); first = 0; break; + case IR_OPND_LABEL_REF: + if (ref) { + IR_ASSERT(IR_IS_CONST_REF(ref)); + fprintf(f, "%sc_%d", first ? "(" : ", ", -ref); + } + break; } } else if (opnd_kind == IR_OPND_NUM) { fprintf(f, "%s%d", first ? "(" : ", ", ref); diff --git a/ext/opcache/jit/ir/ir_emit.c b/ext/opcache/jit/ir/ir_emit.c index 7a10da1322a72..847ca375b5bd0 100644 --- a/ext/opcache/jit/ir/ir_emit.c +++ b/ext/opcache/jit/ir/ir_emit.c @@ -244,32 +244,30 @@ static int ir_get_args_regs(const ir_ctx *ctx, const ir_insn *insn, int8_t *regs ir_insn *arg = &ctx->ir_base[ir_insn_op(insn, j)]; type = arg->type; if (IR_IS_TYPE_INT(type)) { - if (arg->op == IR_ARGVAL) { - continue; - } else if (int_param < int_reg_params_count) { + if (int_param < int_reg_params_count && arg->op != IR_ARGVAL) { regs[j] = int_reg_params[int_param]; count = j + 1; + int_param++; +#ifdef _WIN64 + /* WIN64 calling convention use common couter for int and fp registers */ + fp_param++; +#endif } else { regs[j] = IR_REG_NONE; } - int_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param++; -#endif } else { IR_ASSERT(IR_IS_TYPE_FP(type)); if (fp_param < fp_reg_params_count) { regs[j] = fp_reg_params[fp_param]; count = j + 1; + fp_param++; +#ifdef _WIN64 + /* WIN64 calling convention use common couter for int and fp registers */ + int_param++; +#endif } else { regs[j] = IR_REG_NONE; } - fp_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - int_param++; -#endif } } return count; @@ -426,7 +424,7 @@ typedef struct _ir_common_backend_data { ir_bitset emit_constants; } ir_common_backend_data; -static int ir_const_label(ir_ctx *ctx, ir_ref ref) +static int ir_get_const_label(ir_ctx *ctx, ir_ref ref) { ir_common_backend_data *data = ctx->data; int label = ctx->cfg_blocks_count - ref; @@ -1015,11 +1013,16 @@ int ir_match(ir_ctx *ctx) entries_count++; } ctx->rules[start] = IR_SKIPPED | IR_NOP; + if (ctx->ir_base[start].op == IR_BEGIN && ctx->ir_base[start].op2) { + ctx->flags2 |= IR_HAS_BLOCK_ADDR; + } ref = bb->end; if (bb->successors_count == 1) { insn = &ctx->ir_base[ref]; if (insn->op == IR_END || insn->op == IR_LOOP_END) { - ctx->rules[ref] = insn->op; + if (!ctx->rules[ref]) { + ctx->rules[ref] = insn->op; + } ref = prev_ref[ref]; if (ref == start && ctx->cfg_edges[bb->successors] != b) { if (EXPECTED(!(bb->flags & IR_BB_ENTRY))) { diff --git a/ext/opcache/jit/ir/ir_fold.h b/ext/opcache/jit/ir/ir_fold.h index 74f7818d747c4..bab6b2916075f 100644 --- a/ext/opcache/jit/ir/ir_fold.h +++ b/ext/opcache/jit/ir/ir_fold.h @@ -755,8 +755,35 @@ IR_FOLD(NEG(C_FLOAT)) } IR_FOLD(ABS(C_I8)) +{ + IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); + if (op1_insn->val.i64 >= 0) { + IR_FOLD_COPY(op1); + } else { + IR_FOLD_CONST_I(-op1_insn->val.i8); + } +} + IR_FOLD(ABS(C_I16)) +{ + IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); + if (op1_insn->val.i64 >= 0) { + IR_FOLD_COPY(op1); + } else { + IR_FOLD_CONST_I(-op1_insn->val.i16); + } +} + IR_FOLD(ABS(C_I32)) +{ + IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); + if (op1_insn->val.i64 >= 0) { + IR_FOLD_COPY(op1); + } else { + IR_FOLD_CONST_I((int32_t)-op1_insn->val.u32); + } +} + IR_FOLD(ABS(C_I64)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); @@ -847,7 +874,7 @@ IR_FOLD(MUL_OV(C_U64, C_U64)) uint64_t res; IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); res = op1_insn->val.u64 * op2_insn->val.u64; - if (op1_insn->val.u64 != 0 && res / op1_insn->val.u64 != op2_insn->val.u64 && res <= max) { + if ((op1_insn->val.u64 != 0 && res / op1_insn->val.u64 != op2_insn->val.u64) || res > max) { IR_FOLD_NEXT; } IR_FOLD_CONST_U(res); @@ -864,7 +891,7 @@ IR_FOLD(MUL_OV(C_I64, C_I64)) int64_t res; IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); res = op1_insn->val.u64 * op2_insn->val.u64; - if (op1_insn->val.i64 != 0 && res / op1_insn->val.i64 != op2_insn->val.i64 && res >= min && res <= max) { + if ((op1_insn->val.i64 != 0 && res / op1_insn->val.i64 != op2_insn->val.i64) || res < min || res > max) { IR_FOLD_NEXT; } IR_FOLD_CONST_U(res); @@ -1037,220 +1064,220 @@ IR_FOLD(SHL(C_U8, C_U8)) IR_FOLD(SHL(C_CHAR, C_CHAR)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(op1_insn->val.u8 << op2_insn->val.u8); + IR_FOLD_CONST_U(op1_insn->val.u8 << (op2_insn->val.u8 & 0x7)); } IR_FOLD(SHL(C_I8, C_I8)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int8_t)(op1_insn->val.u8 << op2_insn->val.u8)); + IR_FOLD_CONST_I((int8_t)(op1_insn->val.u8 << (op2_insn->val.u8 & 0x7))); } IR_FOLD(SHL(C_U16, C_U16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(op1_insn->val.u16 << op2_insn->val.u16); + IR_FOLD_CONST_U(op1_insn->val.u16 << (op2_insn->val.u16 & 0xf)); } IR_FOLD(SHL(C_I16, C_I16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int16_t)(op1_insn->val.u16 << op2_insn->val.u16)); + IR_FOLD_CONST_I((int16_t)(op1_insn->val.u16 << (op2_insn->val.u16 & 0xf))); } IR_FOLD(SHL(C_U32, C_U32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(op1_insn->val.u32 << op2_insn->val.u32); + IR_FOLD_CONST_U(op1_insn->val.u32 << (op2_insn->val.u32 & 0x1f)); } IR_FOLD(SHL(C_I32, C_I32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int32_t)(op1_insn->val.u32 << op2_insn->val.u32)); + IR_FOLD_CONST_I((int32_t)(op1_insn->val.u32 << (op2_insn->val.u32 & 0x1f))); } IR_FOLD(SHL(C_U64, C_U64)) IR_FOLD(SHL(C_I64, C_I64)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(op1_insn->val.u64 << op2_insn->val.u64); + IR_FOLD_CONST_U(op1_insn->val.u64 << (op2_insn->val.u64 & 0x3f)); } IR_FOLD(SHR(C_U8, C_U8)) IR_FOLD(SHR(C_CHAR, C_CHAR)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(op1_insn->val.u8 >> op2_insn->val.u8); + IR_FOLD_CONST_U(op1_insn->val.u8 >> (op2_insn->val.u8 & 0x7)); } IR_FOLD(SHR(C_I8, C_I8)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int8_t)(op1_insn->val.u8 >> op2_insn->val.u8)); + IR_FOLD_CONST_I((int8_t)(op1_insn->val.u8 >> (op2_insn->val.u8 & 0x7))); } IR_FOLD(SHR(C_U16, C_U16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(op1_insn->val.u16 >> op2_insn->val.u16); + IR_FOLD_CONST_U(op1_insn->val.u16 >> (op2_insn->val.u16 & 0xf)); } IR_FOLD(SHR(C_I16, C_I16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int16_t)(op1_insn->val.u16 >> op2_insn->val.u16)); + IR_FOLD_CONST_I((int16_t)(op1_insn->val.u16 >> (op2_insn->val.u16 & 0xf))); } IR_FOLD(SHR(C_U32, C_U32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(op1_insn->val.u32 >> op2_insn->val.u32); + IR_FOLD_CONST_U(op1_insn->val.u32 >> (op2_insn->val.u32 & 0x1f)); } IR_FOLD(SHR(C_I32, C_I32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int32_t)(op1_insn->val.u32 >> op2_insn->val.u32)); + IR_FOLD_CONST_I((int32_t)(op1_insn->val.u32 >> (op2_insn->val.u32 & 0x1f))); } IR_FOLD(SHR(C_U64, C_U64)) IR_FOLD(SHR(C_I64, C_I64)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(op1_insn->val.u64 >> op2_insn->val.u64); + IR_FOLD_CONST_U(op1_insn->val.u64 >> (op2_insn->val.u64 & 0x3f)); } IR_FOLD(SAR(C_U8, C_U8)) IR_FOLD(SAR(C_CHAR, C_CHAR)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U((uint8_t)(op1_insn->val.i8 >> op2_insn->val.i8)); + IR_FOLD_CONST_U((uint8_t)(op1_insn->val.i8 >> (op2_insn->val.i8 & 0x7))); } IR_FOLD(SAR(C_I8, C_I8)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I(op1_insn->val.i8 >> op2_insn->val.i8); + IR_FOLD_CONST_I(op1_insn->val.i8 >> (op2_insn->val.i8 & 0x7)); } IR_FOLD(SAR(C_U16, C_U16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U((uint16_t)(op1_insn->val.i16 >> op2_insn->val.i16)); + IR_FOLD_CONST_U((uint16_t)(op1_insn->val.i16 >> (op2_insn->val.i16 & 0xf))); } IR_FOLD(SAR(C_I16, C_I16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I(op1_insn->val.i16 >> op2_insn->val.i16); + IR_FOLD_CONST_I(op1_insn->val.i16 >> (op2_insn->val.i16 & 0xf)); } IR_FOLD(SAR(C_U32, C_U32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U((uint32_t)(op1_insn->val.i32 >> op2_insn->val.i32)); + IR_FOLD_CONST_U((uint32_t)(op1_insn->val.i32 >> (op2_insn->val.i32 & 0x1f))); } IR_FOLD(SAR(C_I32, C_I32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I(op1_insn->val.i32 >> op2_insn->val.i32); + IR_FOLD_CONST_I(op1_insn->val.i32 >> (op2_insn->val.i32 & 0x1f)); } IR_FOLD(SAR(C_U64, C_U64)) IR_FOLD(SAR(C_I64, C_I64)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I(op1_insn->val.i64 >> op2_insn->val.i64); + IR_FOLD_CONST_I(op1_insn->val.i64 >> (op2_insn->val.i64 & 0x3f)); } IR_FOLD(ROL(C_U8, C_U8)) IR_FOLD(ROL(C_CHAR, C_CHAR)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(ir_rol8(op1_insn->val.u8, op2_insn->val.u8)); + IR_FOLD_CONST_U(ir_rol8(op1_insn->val.u8, (op2_insn->val.u8 & 0x7))); } IR_FOLD(ROL(C_I8, C_I8)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int8_t)ir_rol8(op1_insn->val.u8, op2_insn->val.u8)); + IR_FOLD_CONST_I((int8_t)ir_rol8(op1_insn->val.u8, (op2_insn->val.u8 & 0x7))); } IR_FOLD(ROL(C_U16, C_U16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(ir_rol16(op1_insn->val.u16, op2_insn->val.u16)); + IR_FOLD_CONST_U(ir_rol16(op1_insn->val.u16, (op2_insn->val.u16 & 0xf))); } IR_FOLD(ROL(C_I16, C_I16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int16_t)ir_rol16(op1_insn->val.u16, op2_insn->val.u16)); + IR_FOLD_CONST_I((int16_t)ir_rol16(op1_insn->val.u16, (op2_insn->val.u16 & 0xf))); } IR_FOLD(ROL(C_U32, C_U32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(ir_rol32(op1_insn->val.u32, op2_insn->val.u32)); + IR_FOLD_CONST_U(ir_rol32(op1_insn->val.u32, (op2_insn->val.u32 & 0x1f))); } IR_FOLD(ROL(C_I32, C_I32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int32_t)ir_rol32(op1_insn->val.u32, op2_insn->val.u32)); + IR_FOLD_CONST_I((int32_t)ir_rol32(op1_insn->val.u32, (op2_insn->val.u32 & 0x1f))); } IR_FOLD(ROL(C_U64, C_U64)) IR_FOLD(ROL(C_I64, C_I64)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(ir_rol64(op1_insn->val.u64, op2_insn->val.u64)); + IR_FOLD_CONST_U(ir_rol64(op1_insn->val.u64, (op2_insn->val.u64 & 0x3f))); } IR_FOLD(ROR(C_U8, C_U8)) IR_FOLD(ROR(C_CHAR, C_CHAR)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(ir_ror8(op1_insn->val.u8, op2_insn->val.u8)); + IR_FOLD_CONST_U(ir_ror8(op1_insn->val.u8, (op2_insn->val.u8 & 0x7))); } IR_FOLD(ROR(C_I8, C_I8)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int8_t)ir_ror8(op1_insn->val.u8, op2_insn->val.u8)); + IR_FOLD_CONST_I((int8_t)ir_ror8(op1_insn->val.u8, (op2_insn->val.u8 & 0x7))); } IR_FOLD(ROR(C_U16, C_U16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(ir_ror16(op1_insn->val.u16, op2_insn->val.u16)); + IR_FOLD_CONST_U(ir_ror16(op1_insn->val.u16, (op2_insn->val.u16 & 0xf))); } IR_FOLD(ROR(C_I16, C_I16)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int16_t)ir_ror16(op1_insn->val.u16, op2_insn->val.u16)); + IR_FOLD_CONST_I((int16_t)ir_ror16(op1_insn->val.u16, (op2_insn->val.u16 & 0xf))); } IR_FOLD(ROR(C_U32, C_U32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(ir_ror32(op1_insn->val.u32, op2_insn->val.u32)); + IR_FOLD_CONST_U(ir_ror32(op1_insn->val.u32, (op2_insn->val.u32 & 0x1f))); } IR_FOLD(ROR(C_I32, C_I32)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_I((int32_t)ir_ror32(op1_insn->val.u32, op2_insn->val.u32)); + IR_FOLD_CONST_I((int32_t)ir_ror32(op1_insn->val.u32, (op2_insn->val.u32 & 0x1f))); } IR_FOLD(ROR(C_U64, C_U64)) IR_FOLD(ROR(C_I64, C_I64)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - IR_FOLD_CONST_U(ir_ror64(op1_insn->val.u64, op2_insn->val.u64)); + IR_FOLD_CONST_U(ir_ror64(op1_insn->val.u64, (op2_insn->val.u64 & 0x3f))); } //IR_FOLD(BSWAP(CONST)) @@ -1392,6 +1419,9 @@ IR_FOLD(TRUNC(C_U64)) IR_FOLD_CONST_U(op1_insn->val.u16); case IR_U32: IR_FOLD_CONST_U(op1_insn->val.u32); + case IR_ADDR: + IR_ASSERT(sizeof(void*) == 4); + IR_FOLD_CONST_U(op1_insn->val.u32); } } @@ -1545,7 +1575,7 @@ IR_FOLD(FP2FP(C_DOUBLE)) IR_FOLD(COPY(_)) { IR_ASSERT(IR_OPT_TYPE(opt) == op1_insn->type); - if (!op2) { + if (!(op2 & IR_COPY_HARD)) { IR_FOLD_COPY(op1); } /* skip CSE */ @@ -2075,23 +2105,23 @@ IR_FOLD(SUB(ADD, ADD)) IR_FOLD_CONST_U(0); } else if (op1_insn->op1 == op2_insn->op1) { /* (a + b) - (a + c) => b - c */ - op1 = op1_insn->op2; - op2 = op2_insn->op2; + op1 = _ir_fold_cast(ctx, op1_insn->op2, IR_OPT_TYPE(opt)); + op2 = _ir_fold_cast(ctx, op2_insn->op2, IR_OPT_TYPE(opt)); IR_FOLD_RESTART; } else if (op1_insn->op1 == op2_insn->op2) { /* (a + b) - (c + a) => b - c */ - op1 = op1_insn->op2; - op2 = op2_insn->op1; + op1 = _ir_fold_cast(ctx, op1_insn->op2, IR_OPT_TYPE(opt)); + op2 = _ir_fold_cast(ctx, op2_insn->op1, IR_OPT_TYPE(opt)); IR_FOLD_RESTART; } else if (op1_insn->op2 == op2_insn->op1) { /* (a + b) - (b + c) => a - c */ - op1 = op1_insn->op1; - op2 = op2_insn->op2; + op1 = _ir_fold_cast(ctx, op1_insn->op1, IR_OPT_TYPE(opt)); + op2 = _ir_fold_cast(ctx, op2_insn->op2, IR_OPT_TYPE(opt)); IR_FOLD_RESTART; } else if (op1_insn->op2 == op2_insn->op2) { /* (a + b) - (c + b) => a - c */ - op1 = op1_insn->op1; - op2 = op2_insn->op1; + op1 = _ir_fold_cast(ctx, op1_insn->op1, IR_OPT_TYPE(opt)); + op2 = _ir_fold_cast(ctx, op2_insn->op1, IR_OPT_TYPE(opt)); IR_FOLD_RESTART; } } diff --git a/ext/opcache/jit/ir/ir_gcm.c b/ext/opcache/jit/ir/ir_gcm.c index 043e1e7bdd853..e6486ba64a1c5 100644 --- a/ext/opcache/jit/ir/ir_gcm.c +++ b/ext/opcache/jit/ir/ir_gcm.c @@ -361,20 +361,20 @@ static bool ir_split_partially_dead_node(ir_ctx *ctx, ir_ref ref, uint32_t b) while (ir_sparse_set_in(&data->totally_useful, ctx->cfg_blocks[j].idom)) { j = ctx->cfg_blocks[j].idom; } + clone = ir_hashtab_find(&hash, j); + if (clone == IR_INVALID_VAL) { + clone = clones_count++; + ir_hashtab_add(&hash, j, clone); + clones[clone].block = j; + clones[clone].use_count = 0; + clones[clone].use = -1; + } + uses[uses_count].ref = use; + uses[uses_count].block = i; + uses[uses_count].next = clones[clone].use; + clones[clone].use_count++; + clones[clone].use = uses_count++; } - clone = ir_hashtab_find(&hash, j); - if (clone == IR_INVALID_VAL) { - clone = clones_count++; - ir_hashtab_add(&hash, j, clone); - clones[clone].block = j; - clones[clone].use_count = 0; - clones[clone].use = -1; - } - uses[uses_count].ref = use; - uses[uses_count].block = i; - uses[uses_count].next = clones[clone].use; - clones[clone].use_count++; - clones[clone].use = uses_count++; } } @@ -1007,7 +1007,11 @@ int ir_schedule(ir_ctx *ctx) start = i = bb->start; _xlat[i] = bb->start = insns_count; insn = &ctx->ir_base[i]; - if (insn->op == IR_CASE_VAL) { + if (insn->op == IR_BEGIN) { + if (insn->op2) { + consts_count += ir_count_constant(_xlat, insn->op2); + } + } else if (insn->op == IR_CASE_VAL) { IR_ASSERT(insn->op2 < IR_TRUE); consts_count += ir_count_constant(_xlat, insn->op2); } else if (insn->op == IR_CASE_RANGE) { @@ -1255,7 +1259,7 @@ int ir_schedule(ir_ctx *ctx) const char *proto = ir_get_strl(ctx, new_insn->proto, &len); new_insn->proto = ir_strl(&new_ctx, proto, len); } - } else if (new_insn->op == IR_SYM || new_insn->op == IR_STR) { + } else if (new_insn->op == IR_SYM || new_insn->op == IR_STR || new_insn->op == IR_LABEL) { size_t len; const char *str = ir_get_strl(ctx, new_insn->val.name, &len); new_insn->val.u64 = ir_strl(&new_ctx, str, len); @@ -1292,7 +1296,7 @@ int ir_schedule(ir_ctx *ctx) } else { new_insn->proto = 0; } - } else if (insn->op == IR_SYM || insn->op == IR_STR) { + } else if (insn->op == IR_SYM || insn->op == IR_STR || insn->op == IR_LABEL) { size_t len; const char *str = ir_get_strl(ctx, insn->val.name, &len); new_insn->val.u64 = ir_strl(&new_ctx, str, len); @@ -1364,6 +1368,8 @@ int ir_schedule(ir_ctx *ctx) size_t len; const char *str = ir_get_strl(ctx, insn->op2, &len); new_insn->op2 = ir_strl(&new_ctx, str, len); + } else if (new_insn->op == IR_BEGIN && insn->op2) { + new_insn->op2 = _xlat[insn->op2]; } else { new_insn->op2 = insn->op2; } diff --git a/ext/opcache/jit/ir/ir_private.h b/ext/opcache/jit/ir/ir_private.h index 2f457cbc99333..dbacc3967d0f7 100644 --- a/ext/opcache/jit/ir/ir_private.h +++ b/ext/opcache/jit/ir/ir_private.h @@ -887,7 +887,7 @@ void ir_print_escaped_str(const char *s, size_t len, FILE *f); #define IR_IS_CONST_OP(op) ((op) > IR_NOP && (op) <= IR_C_FLOAT) #define IR_IS_FOLDABLE_OP(op) ((op) <= IR_LAST_FOLDABLE_OP) -#define IR_IS_SYM_CONST(op) ((op) == IR_STR || (op) == IR_SYM || (op) == IR_FUNC) +#define IR_IS_SYM_CONST(op) ((op) == IR_STR || (op) == IR_SYM || (op) == IR_FUNC || (op) == IR_LABEL) ir_ref ir_const_ex(ir_ctx *ctx, ir_val val, uint8_t type, uint32_t optx); @@ -946,12 +946,13 @@ IR_ALWAYS_INLINE bool ir_ref_is_true(ir_ctx *ctx, ir_ref ref) #define IR_OPND_UNUSED 0x0 #define IR_OPND_DATA 0x1 #define IR_OPND_CONTROL 0x2 -#define IR_OPND_CONTROL_DEP 0x3 -#define IR_OPND_CONTROL_REF 0x4 -#define IR_OPND_STR 0x5 -#define IR_OPND_NUM 0x6 -#define IR_OPND_PROB 0x7 -#define IR_OPND_PROTO 0x8 +#define IR_OPND_LABEL_REF 0x3 +#define IR_OPND_CONTROL_DEP 0x4 +#define IR_OPND_CONTROL_REF 0x5 +#define IR_OPND_STR 0x6 +#define IR_OPND_NUM 0x7 +#define IR_OPND_PROB 0x8 +#define IR_OPND_PROTO 0x9 #define IR_OP_FLAGS(op_flags, op1_flags, op2_flags, op3_flags) \ ((op_flags) | ((op1_flags) << 20) | ((op2_flags) << 24) | ((op3_flags) << 28)) @@ -1013,6 +1014,7 @@ IR_ALWAYS_INLINE uint32_t ir_insn_len(const ir_insn *insn) #define IR_HAS_VA_ARG_FP (1<<9) #define IR_HAS_FP_RET_SLOT (1<<10) #define IR_16B_FRAME_ALIGNMENT (1<<11) +#define IR_HAS_BLOCK_ADDR (1<<12) /* Temporary: MEM2SSA -> SCCP */ #define IR_MEM2SSA_VARS (1<<25) @@ -1248,11 +1250,10 @@ struct _ir_live_range { #define IR_LIVE_INTERVAL_HAS_HINT_REGS (1<<2) #define IR_LIVE_INTERVAL_HAS_HINT_REFS (1<<3) #define IR_LIVE_INTERVAL_MEM_PARAM (1<<4) -#define IR_LIVE_INTERVAL_MEM_LOAD (1<<5) -#define IR_LIVE_INTERVAL_COALESCED (1<<6) -#define IR_LIVE_INTERVAL_SPILL_SPECIAL (1<<7) /* spill slot is pre-allocated in a special area (see ir_ctx.spill_reserved_base) */ -#define IR_LIVE_INTERVAL_SPILLED (1<<8) -#define IR_LIVE_INTERVAL_SPLIT_CHILD (1<<9) +#define IR_LIVE_INTERVAL_COALESCED (1<<5) +#define IR_LIVE_INTERVAL_SPILL_SPECIAL (1<<6) /* spill slot is pre-allocated in a special area (see ir_ctx.spill_reserved_base) */ +#define IR_LIVE_INTERVAL_SPILLED (1<<7) +#define IR_LIVE_INTERVAL_SPLIT_CHILD (1<<8) struct _ir_live_interval { uint8_t type; diff --git a/ext/opcache/jit/ir/ir_ra.c b/ext/opcache/jit/ir/ir_ra.c index 21c7ee3ac64e5..2e8a8e3f34f3f 100644 --- a/ext/opcache/jit/ir/ir_ra.c +++ b/ext/opcache/jit/ir/ir_ra.c @@ -776,9 +776,6 @@ int ir_compute_live_ranges(ir_ctx *ctx) if (insn->op == IR_PARAM) { /* We may reuse parameter stack slot for spilling */ ctx->live_intervals[v]->flags |= IR_LIVE_INTERVAL_MEM_PARAM; - } else if (insn->op == IR_VLOAD) { - /* Load may be fused into the usage instruction */ - ctx->live_intervals[v]->flags |= IR_LIVE_INTERVAL_MEM_LOAD; } def_pos = IR_DEF_LIVE_POS_FROM_REF(ref); } @@ -845,11 +842,17 @@ int ir_compute_live_ranges(ir_ctx *ctx) ival = ctx->live_intervals[v]; } ir_add_use(ctx, ival, j, use_pos, reg, IR_USE_FLAGS(def_flags, j), hint_ref); - } else if (ctx->rules) { - if (ctx->rules[input] & IR_FUSED) { - ir_add_fusion_ranges(ctx, ref, input, bb, live); - } else if (ctx->rules[input] == (IR_SKIPPED|IR_RLOAD)) { - ir_set_alocated_reg(ctx, ref, j, ctx->ir_base[input].op2); + } else { + if (ctx->rules) { + if ((ctx->rules[input] & (IR_FUSED|IR_SKIPPED)) == IR_FUSED) { + ir_add_fusion_ranges(ctx, ref, input, bb, live); + } else if (ctx->rules[input] == (IR_SKIPPED|IR_RLOAD)) { + ir_set_alocated_reg(ctx, ref, j, ctx->ir_base[input].op2); + } + } + if (reg != IR_REG_NONE) { + use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref); + ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF); } } } else if (reg != IR_REG_NONE) { @@ -1396,9 +1399,6 @@ int ir_compute_live_ranges(ir_ctx *ctx) if (insn->op == IR_PARAM) { /* We may reuse parameter stack slot for spilling */ ctx->live_intervals[v]->flags |= IR_LIVE_INTERVAL_MEM_PARAM; - } else if (insn->op == IR_VLOAD) { - /* Load may be fused into the usage instruction */ - ctx->live_intervals[v]->flags |= IR_LIVE_INTERVAL_MEM_LOAD; } def_pos = IR_DEF_LIVE_POS_FROM_REF(ref); } @@ -1465,17 +1465,17 @@ int ir_compute_live_ranges(ir_ctx *ctx) ival = ctx->live_intervals[v]; } ir_add_use(ctx, ival, j, use_pos, reg, IR_USE_FLAGS(def_flags, j), hint_ref); - } else if (ctx->rules) { - if (ctx->rules[input] & IR_FUSED) { - ir_add_fusion_ranges(ctx, ref, input, bb, live_in_block, b); - } else { - if (ctx->rules[input] == (IR_SKIPPED|IR_RLOAD)) { + } else { + if (ctx->rules) { + if ((ctx->rules[input] & (IR_FUSED|IR_SKIPPED)) == IR_FUSED) { + ir_add_fusion_ranges(ctx, ref, input, bb, live_in_block, b); + } else if (ctx->rules[input] == (IR_SKIPPED|IR_RLOAD)) { ir_set_alocated_reg(ctx, ref, j, ctx->ir_base[input].op2); } - if (reg != IR_REG_NONE) { - use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref); - ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF); - } + } + if (reg != IR_REG_NONE) { + use_pos = IR_LOAD_LIVE_POS_FROM_REF(ref); + ir_add_fixed_live_range(ctx, reg, use_pos, use_pos + IR_USE_SUB_REF); } } } else if (reg != IR_REG_NONE) { @@ -1605,7 +1605,7 @@ static void ir_vregs_join(ir_ctx *ctx, uint32_t r1, uint32_t r2) } while (*prev && ((*prev)->pos < use_pos->pos || ((*prev)->pos == use_pos->pos && - (use_pos->op_num == 0 || (*prev)->op_num < use_pos->op_num)))) { + (use_pos->op_num == 0 || ((*prev)->op_num != 0 && (*prev)->op_num < use_pos->op_num))))) { if ((*prev)->hint_ref > 0 && ctx->vregs[(*prev)->hint_ref] == r2) { (*prev)->hint_ref = 0; } @@ -1627,9 +1627,6 @@ static void ir_vregs_join(ir_ctx *ctx, uint32_t r1, uint32_t r2) ctx->live_intervals[r1]->flags |= IR_LIVE_INTERVAL_COALESCED | (ival->flags & (IR_LIVE_INTERVAL_HAS_HINT_REGS|IR_LIVE_INTERVAL_HAS_HINT_REFS)); - if (ctx->ir_base[IR_LIVE_POS_TO_REF(ctx->live_intervals[r1]->use_pos->pos)].op != IR_VLOAD) { - ctx->live_intervals[r1]->flags &= ~IR_LIVE_INTERVAL_MEM_LOAD; - } if (ival->flags & IR_LIVE_INTERVAL_MEM_PARAM) { IR_ASSERT(!(ctx->live_intervals[r1]->flags & IR_LIVE_INTERVAL_MEM_PARAM)); ctx->live_intervals[r1]->flags |= IR_LIVE_INTERVAL_MEM_PARAM; @@ -2343,16 +2340,6 @@ static ir_live_pos ir_first_use_pos_after(ir_live_interval *ival, ir_live_pos po return p ? p->pos : 0x7fffffff; } -static ir_live_pos ir_first_use_pos(ir_live_interval *ival, uint8_t flags) -{ - ir_use_pos *p = ival->use_pos; - - while (p && !(p->flags & flags)) { - p = p->next; - } - return p ? p->pos : 0x7fffffff; -} - static ir_block *ir_block_from_live_pos(ir_ctx *ctx, ir_live_pos pos) { ir_ref ref = IR_LIVE_POS_TO_REF(pos); @@ -3194,7 +3181,6 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li /* split current before its first use position that requires a register */ ir_live_pos split_pos; -spill_current: if (next_use_pos == ival->range.start) { IR_ASSERT(ival->use_pos && ival->use_pos->op_num == 0); /* split right after definition */ @@ -3228,7 +3214,6 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li return IR_REG_NONE; } if (split_pos >= blockPos[reg]) { -try_next_available_register: IR_REGSET_EXCL(available, reg); if (IR_REGSET_IS_EMPTY(available)) { fprintf(stderr, "LSRA Internal Error: Unsolvable conflict. Allocation is not possible\n"); @@ -3274,23 +3259,6 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li } IR_LOG_LSRA(" ---- Finish", other, ""); } else { - if (ir_first_use_pos(other, IR_USE_MUST_BE_IN_REG) <= other->end) { - if (!(ival->flags & IR_LIVE_INTERVAL_TEMP)) { - next_use_pos = ir_first_use_pos(ival, IR_USE_MUST_BE_IN_REG); - if (next_use_pos == ival->range.start) { - IR_ASSERT(ival->use_pos && ival->use_pos->op_num == 0); - /* split right after definition */ - split_pos = next_use_pos + 1; - } else { - split_pos = ir_find_optimal_split_position(ctx, ival, ival->range.start, next_use_pos - 1, 1); - } - - if (split_pos > ival->range.start) { - goto spill_current; - } - } - goto try_next_available_register; - } child = other; other->reg = IR_REG_NONE; if (prev) { @@ -3400,12 +3368,13 @@ static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to) static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival, ir_reg_alloc_data *data) { ir_use_pos *use_pos = ival->use_pos; - ir_insn *insn; if (ival->flags & IR_LIVE_INTERVAL_MEM_PARAM) { IR_ASSERT(!ival->next && use_pos && use_pos->op_num == 0); - insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)]; +#if IR_DEBUG + ir_insn *insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)]; IR_ASSERT(insn->op == IR_PARAM); +#endif use_pos = use_pos->next; if (use_pos && (use_pos->next || (use_pos->flags & IR_USE_MUST_BE_IN_REG))) { return 0; @@ -3418,38 +3387,6 @@ static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival, ir_ } } - return 1; - } else if (ival->flags & IR_LIVE_INTERVAL_MEM_LOAD) { - insn = &ctx->ir_base[IR_LIVE_POS_TO_REF(use_pos->pos)]; - IR_ASSERT(insn->op == IR_VLOAD); - IR_ASSERT(ctx->ir_base[insn->op2].op == IR_VAR); - use_pos = use_pos->next; - if (use_pos && (use_pos->next || (use_pos->flags & IR_USE_MUST_BE_IN_REG))) { - return 0; - } - - if (use_pos) { - ir_block *bb = ir_block_from_live_pos(ctx, use_pos->pos); - if (bb->loop_depth && bb != ir_block_from_live_pos(ctx, ival->use_pos->pos)) { - return 0; - } - /* check if VAR may be clobbered between VLOAD and use */ - ir_use_list *use_list = &ctx->use_lists[insn->op2]; - ir_ref n = use_list->count; - ir_ref *p = &ctx->use_edges[use_list->refs]; - for (; n > 0; p++, n--) { - ir_ref use = *p; - if (ctx->ir_base[use].op == IR_VSTORE) { - if (use > IR_LIVE_POS_TO_REF(ival->use_pos->pos) && use < IR_LIVE_POS_TO_REF(use_pos->pos)) { - return 0; - } - } else if (ctx->ir_base[use].op == IR_VADDR) { - return 0; - } - } - } - ival->stack_spill_pos = ctx->ir_base[insn->op2].op3; - return 1; } return 0; @@ -3554,7 +3491,7 @@ static int ir_linear_scan(ir_ctx *ctx) for (j = ctx->vregs_count; j != 0; j--) { ival = ctx->live_intervals[j]; if (ival) { - if (!(ival->flags & (IR_LIVE_INTERVAL_MEM_PARAM|IR_LIVE_INTERVAL_MEM_LOAD)) + if (!(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM) || !ir_ival_spill_for_fuse_load(ctx, ival, &data)) { ir_add_to_unhandled(&unhandled, ival); } diff --git a/ext/opcache/jit/ir/ir_save.c b/ext/opcache/jit/ir/ir_save.c index 5ba986fadd481..dd955172950c8 100644 --- a/ext/opcache/jit/ir/ir_save.c +++ b/ext/opcache/jit/ir/ir_save.c @@ -40,6 +40,11 @@ void ir_print_proto_ex(uint8_t flags, ir_type ret_type, uint32_t params_count, c } else if (flags & IR_BUILTIN_FUNC) { fprintf(f, " __builtin"); } + if (flags & IR_CONST_FUNC) { + fprintf(f, " __const"); + } else if (flags & IR_PURE_FUNC) { + fprintf(f, " __pure"); + } } static void ir_save_dessa_moves(const ir_ctx *ctx, int b, ir_block *bb, FILE *f) @@ -109,6 +114,10 @@ void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f) fprintf(f, "sym(%s%s)", (save_flags & IR_SAVE_SAFE_NAMES) ? "@" : "", ir_get_str(ctx, insn->val.name)); + } else if (insn->op == IR_LABEL) { + fprintf(f, "label(%s%s)", + (save_flags & IR_SAVE_SAFE_NAMES) ? "@" : "", + ir_get_str(ctx, insn->val.name)); } else if (insn->op == IR_FUNC_ADDR) { fprintf(f, "func *"); ir_print_const(ctx, insn, f, true); @@ -272,6 +281,13 @@ void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f) fprintf(f, "%s%d", first ? "(" : ", ", ref); first = 0; break; + case IR_OPND_LABEL_REF: + if (ref) { + IR_ASSERT(IR_IS_CONST_REF(ref)); + fprintf(f, "%sc_%d", first ? "(" : ", ", -ref); + first = 0; + } + break; } } else if (opnd_kind == IR_OPND_NUM) { fprintf(f, "%s%d", first ? "(" : ", ", ref); diff --git a/ext/opcache/jit/ir/ir_sccp.c b/ext/opcache/jit/ir/ir_sccp.c index 45df92ec2be6f..e2f38a058aeba 100644 --- a/ext/opcache/jit/ir/ir_sccp.c +++ b/ext/opcache/jit/ir/ir_sccp.c @@ -1508,8 +1508,8 @@ static bool ir_may_promote_f2d(ir_ctx *ctx, ir_ref ref) switch (insn->op) { case IR_FP2FP: return 1; - case IR_INT2FP: - return ctx->use_lists[ref].count == 1; +// case IR_INT2FP: +// return ctx->use_lists[ref].count == 1; case IR_NEG: case IR_ABS: return ctx->use_lists[ref].count == 1 && @@ -2110,7 +2110,9 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op1].op)) { ctx->ir_base[use].op1 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op1], op, type); } else { - ctx->ir_base[use].op1 = ir_ext_ref(ctx, use, use_insn->op1, op, type, worklist); + ir_ref tmp = ir_ext_ref(ctx, use, use_insn->op1, op, type, worklist); + use_insn = &ctx->ir_base[use]; + use_insn->op1 = tmp; } ir_bitqueue_add(worklist, use); } @@ -2119,7 +2121,9 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op2].op)) { ctx->ir_base[use].op2 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op2], op, type); } else { - ctx->ir_base[use].op2 = ir_ext_ref(ctx, use, use_insn->op2, op, type, worklist); + ir_ref tmp = ir_ext_ref(ctx, use, use_insn->op2, op, type, worklist); + use_insn = &ctx->ir_base[use]; + use_insn->op2 = tmp; } ir_bitqueue_add(worklist, use); } @@ -2147,7 +2151,9 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op1].op)) { ctx->ir_base[use].op1 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op1], op, type); } else { - ctx->ir_base[use].op1 = ir_ext_ref(ctx, use, use_insn->op1, op, type, worklist); + ir_ref tmp = ir_ext_ref(ctx, use, use_insn->op1, op, type, worklist); + use_insn = &ctx->ir_base[use]; + use_insn->op1 = tmp; } ir_bitqueue_add(worklist, use); } @@ -2156,7 +2162,9 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref && !IR_IS_SYM_CONST(ctx->ir_base[use_insn->op2].op)) { ctx->ir_base[use].op2 = ir_ext_const(ctx, &ctx->ir_base[use_insn->op2], op, type); } else { - ctx->ir_base[use].op2 = ir_ext_ref(ctx, use, use_insn->op2, op, type, worklist); + ir_ref tmp = ir_ext_ref(ctx, use, use_insn->op2, op, type, worklist); + use_insn = &ctx->ir_base[use]; + use_insn->op2 = tmp; } ir_bitqueue_add(worklist, use); } @@ -2178,7 +2186,8 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref && !IR_IS_SYM_CONST(ctx->ir_base[phi_insn->op2].op)) { ctx->ir_base[phi_ref].op2 = ir_ext_const(ctx, &ctx->ir_base[phi_insn->op2], op, type); } else { - ctx->ir_base[phi_ref].op2 = ir_ext_ref(ctx, phi_ref, phi_insn->op2, op, type, worklist); + ir_ref tmp = ir_ext_ref(ctx, phi_ref, phi_insn->op2, op, type, worklist); + ctx->ir_base[phi_ref].op2 = tmp; } return 1; @@ -2251,42 +2260,6 @@ static void ir_merge_blocks(ir_ctx *ctx, ir_ref end, ir_ref begin, ir_bitqueue * ir_ref prev, next; ir_use_list *use_list; - if (ctx->use_lists[begin].count > 1) { - ir_ref *p, n, i, use; - ir_insn *use_insn; - ir_ref region = end; - ir_ref next = IR_UNUSED; - - while (!IR_IS_BB_START(ctx->ir_base[region].op)) { - region = ctx->ir_base[region].op1; - } - - use_list = &ctx->use_lists[begin]; - n = use_list->count; - for (p = &ctx->use_edges[use_list->refs], i = 0; i < n; p++, i++) { - use = *p; - use_insn = &ctx->ir_base[use]; - if (ir_op_flags[use_insn->op] & IR_OP_FLAG_CONTROL) { - IR_ASSERT(!next); - next = use; - } else { - IR_ASSERT(use_insn->op == IR_VAR); - IR_ASSERT(use_insn->op1 == begin); - use_insn->op1 = region; - if (ir_use_list_add(ctx, region, use)) { - /* restore after reallocation */ - use_list = &ctx->use_lists[begin]; - n = use_list->count; - p = &ctx->use_edges[use_list->refs + i]; - } - } - } - - IR_ASSERT(next); - ctx->use_edges[use_list->refs] = next; - use_list->count = 1; - } - IR_ASSERT(ctx->ir_base[begin].op == IR_BEGIN); IR_ASSERT(ctx->ir_base[end].op == IR_END); IR_ASSERT(ctx->ir_base[begin].op1 == end); @@ -3595,7 +3568,10 @@ void ir_iter_opt(ir_ctx *ctx, ir_bitqueue *worklist) if (!(ctx->flags & IR_OPT_CFG)) { /* pass */ } else if (insn->op == IR_BEGIN) { - if (insn->op1 && ctx->ir_base[insn->op1].op == IR_END) { + if (insn->op1 + && !insn->op2 /* no computed goto label */ + && ctx->use_lists[i].count == 1 + && ctx->ir_base[insn->op1].op == IR_END) { ir_merge_blocks(ctx, insn->op1, i, worklist); } } else if (insn->op == IR_MERGE) { diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc index 42e4eee7da0fc..7f714dd11d27c 100644 --- a/ext/opcache/jit/ir/ir_x86.dasc +++ b/ext/opcache/jit/ir/ir_x86.dasc @@ -66,7 +66,7 @@ IR_ALWAYS_INLINE ir_mem IR_MEM(ir_reg base, int32_t offset, ir_reg index, int32_ #define IR_SPILL_POS_TO_OFFSET(offset) \ ((ctx->flags & IR_USE_FRAME_POINTER) ? \ - ((offset) - (ctx->stack_frame_size - ctx->stack_frame_alignment)) : \ + ((offset) - ctx->stack_frame_size) : \ ((offset) + ctx->call_stack_size)) |.macro ASM_EXPAND_OP_MEM, MACRO, op, type, op1 @@ -892,6 +892,9 @@ typedef struct _ir_backend_data { bool double_abs_const; bool float_abs_const; bool double_zero_const; + bool u2d_const; + bool u2f_const; + bool resolved_label_syms; } ir_backend_data; #define IR_GP_REG_NAME(code, name64, name32, name16, name8, name8h) \ @@ -1087,6 +1090,7 @@ const char *ir_reg_name(int8_t reg, ir_type type) _(SSE_TRUNC) \ _(SSE_NEARBYINT) \ _(BIT_OP) \ + _(IGOTO_DUP) \ #define IR_LEA_FIRST IR_LEA_OB #define IR_LEA_LAST IR_LEA_O_SYM @@ -1110,35 +1114,24 @@ const char *ir_rule_name[IR_LAST_OP] = { static bool ir_may_fuse_addr(ir_ctx *ctx, const ir_insn *addr_insn) { - if (sizeof(void*) == 4) { - return 1; + if (addr_insn->op == IR_LABEL) { + return 0; } else if (IR_IS_SYM_CONST(addr_insn->op)) { void *addr = ir_sym_addr(ctx, addr_insn); if (!addr) { return 0; } - return IR_IS_SIGNED_32BIT((int64_t)(intptr_t)addr); + return (sizeof(void*) == 4) || IR_IS_SIGNED_32BIT((int64_t)(intptr_t)addr); } else { - return IR_IS_SIGNED_32BIT(addr_insn->val.i64); + return (sizeof(void*) == 4) || IR_IS_SIGNED_32BIT(addr_insn->val.i64); } } static bool ir_may_fuse_imm(ir_ctx *ctx, const ir_insn *val_insn) { if (val_insn->type == IR_ADDR) { - if (sizeof(void*) == 4) { - return 1; - } else if (IR_IS_SYM_CONST(val_insn->op)) { - void *addr = ir_sym_addr(ctx, val_insn); - - if (!addr) { - return 0; - } - return IR_IS_SIGNED_32BIT((intptr_t)addr); - } else { - return IR_IS_SIGNED_32BIT(val_insn->val.i64); - } + return ir_may_fuse_addr(ctx, val_insn); } else { return (ir_type_size[val_insn->type] <= 4 || IR_IS_SIGNED_32BIT(val_insn->val.i64)); } @@ -1517,6 +1510,11 @@ op2_const: constraints->tmp_regs[0] = IR_TMP_REG(1, ctx->ir_base[insn->op1].type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF); n = 1; } + if (IR_IS_TYPE_UNSIGNED(ctx->ir_base[insn->op1].type) + && ir_type_size[ctx->ir_base[insn->op1].type] >= sizeof(void*)) { + constraints->tmp_regs[n] = IR_TMP_REG(2, ctx->ir_base[insn->op1].type, IR_USE_SUB_REF, IR_DEF_SUB_REF); + n++; + } break; case IR_ABS_INT: flags = IR_DEF_CONFLICTS_WITH_INPUT_REGS | IR_USE_MUST_BE_IN_REG | IR_OP1_MUST_BE_IN_REG; @@ -1542,6 +1540,7 @@ op2_const: case IR_GUARD_NOT: flags = IR_OP2_SHOULD_BE_IN_REG; break; + case IR_IGOTO: case IR_IJMP: flags = IR_OP2_SHOULD_BE_IN_REG; break; @@ -1574,7 +1573,7 @@ op2_const: } break; case IR_VA_ARG: - flags = IR_USE_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG; + flags = IR_USE_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG | IR_DEF_CONFLICTS_WITH_INPUT_REGS; constraints->tmp_regs[0] = IR_TMP_REG(3, IR_ADDR, IR_LOAD_SUB_REF, IR_SAVE_SUB_REF); n = 1; insn = &ctx->ir_base[ref]; @@ -1669,7 +1668,9 @@ static void ir_match_fuse_addr(ir_ctx *ctx, ir_ref addr_ref) do { ir_insn *insn = &ctx->ir_base[*p]; - if (insn->op != IR_LOAD && (insn->op != IR_STORE || insn->op3 == addr_ref)) { + if (insn->op != IR_LOAD + && insn->op != IR_LOAD_v + && ((insn->op != IR_STORE && insn->op != IR_STORE_v) || insn->op3 == addr_ref)) { return; } p++; @@ -1752,7 +1753,7 @@ static bool ir_match_has_mem_deps(ir_ctx *ctx, ir_ref ref, ir_ref root) do { ir_insn *insn = &ctx->ir_base[pos]; - if (insn->op == IR_STORE) { + if (insn->op == IR_STORE || insn->op == IR_STORE_v || insn->op == IR_VSTORE || insn->op == IR_VSTORE_v) { // TODO: check if LOAD and STORE addresses may alias return 1; } else if (insn->op == IR_CALL) { @@ -1766,8 +1767,9 @@ static bool ir_match_has_mem_deps(ir_ctx *ctx, ir_ref ref, ir_ref root) static void ir_match_fuse_load(ir_ctx *ctx, ir_ref ref, ir_ref root) { - if (ir_in_same_block(ctx, ref) - && ctx->ir_base[ref].op == IR_LOAD) { + if (ir_in_same_block(ctx, ref) && + (ctx->ir_base[ref].op == IR_LOAD || ctx->ir_base[ref].op == IR_LOAD_v || + ctx->ir_base[ref].op == IR_VLOAD || ctx->ir_base[ref].op == IR_VLOAD_v)) { if (ctx->use_lists[ref].count == 2 && !ir_match_has_mem_deps(ctx, ref, root)) { ir_ref addr_ref = ctx->ir_base[ref].op2; @@ -1792,7 +1794,7 @@ static bool ir_match_try_fuse_load(ir_ctx *ctx, ir_ref ref, ir_ref root) ir_insn *insn = &ctx->ir_base[ref]; if (ir_in_same_block(ctx, ref) - && insn->op == IR_LOAD) { + && (insn->op == IR_LOAD || insn->op == IR_LOAD_v || insn->op == IR_VLOAD || insn->op == IR_VLOAD_v)) { if (ctx->use_lists[ref].count == 2 && !ir_match_has_mem_deps(ctx, ref, root)) { ir_ref addr_ref = ctx->ir_base[ref].op2; @@ -1814,8 +1816,6 @@ static bool ir_match_try_fuse_load(ir_ctx *ctx, ir_ref ref, ir_ref root) && ir_get_param_reg(ctx, ref) == IR_REG_NONE) { return 1; } - } else if (ctx->ir_base[ref].op == IR_VLOAD) { - return 1; } return 0; } @@ -2462,8 +2462,21 @@ binop_fp: case IR_IJMP: ir_match_fuse_load(ctx, insn->op2, ref); return insn->op; + case IR_IGOTO: + if (ctx->ir_base[insn->op1].op == IR_MERGE || ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN) { + ir_insn *merge = &ctx->ir_base[insn->op1]; + ir_ref *p, n = merge->inputs_count; + + for (p = merge->ops + 1; n > 0; p++, n--) { + ir_ref input = *p; + IR_ASSERT(ctx->ir_base[input].op == IR_END || ctx->ir_base[input].op == IR_LOOP_END); + ctx->rules[input] = IR_IGOTO_DUP; + } + } + ir_match_fuse_load(ctx, insn->op2, ref); + return insn->op; case IR_VAR: - return IR_SKIPPED | IR_VAR; + return IR_STATIC_ALLOCA; case IR_PARAM: #ifndef _WIN64 if (ctx->value_params && ctx->value_params[insn->op3 - 1].align) { @@ -2617,7 +2630,15 @@ store_int: return IR_VSTORE_FP; } break; + case IR_VSTORE_v: + if (IR_IS_TYPE_INT(ctx->ir_base[insn->op3].type)) { + return IR_VSTORE_INT; + } else { + return IR_VSTORE_FP; + } + break; case IR_LOAD: + case IR_LOAD_v: ir_match_fuse_addr(ctx, insn->op2); if (IR_IS_TYPE_INT(insn->type)) { return IR_LOAD_INT; @@ -2635,6 +2656,14 @@ store_int: return IR_STORE_FP; } break; + case IR_STORE_v: + ir_match_fuse_addr(ctx, insn->op2); + if (IR_IS_TYPE_INT(ctx->ir_base[insn->op3].type)) { + return IR_STORE_INT; + } else { + return IR_STORE_FP; + } + break; case IR_RLOAD: if (IR_REGSET_IN(IR_REGSET_UNION((ir_regset)ctx->fixed_regset, IR_REGSET_FIXED), insn->op2)) { return IR_SKIPPED | IR_RLOAD; @@ -3175,7 +3204,7 @@ static void ir_emit_load_imm_fp(ir_ctx *ctx, ir_type type, ir_reg reg, ir_ref sr | xorpd xmm(reg-IR_REG_FP_FIRST), xmm(reg-IR_REG_FP_FIRST) } } else { - label = ir_const_label(ctx, src); + label = ir_get_const_label(ctx, src); | ASM_FP_REG_TXT_OP movs, type, reg, [=>label] } } @@ -3229,6 +3258,38 @@ static void ir_load_local_addr(ir_ctx *ctx, ir_reg reg, ir_ref src) } } +static void ir_resolve_label_syms(ir_ctx *ctx) +{ + uint32_t b; + ir_block *bb; + + for (b = 1, bb = &ctx->cfg_blocks[b]; b <= ctx->cfg_blocks_count; bb++, b++) { + ir_insn *insn = &ctx->ir_base[bb->start]; + + if (insn->op == IR_BEGIN && insn->op2) { + IR_ASSERT(ctx->ir_base[insn->op2].op == IR_LABEL); + ctx->ir_base[insn->op2].val.u32_hi = b; + } + } +} + +static void ir_emit_load_label_addr(ir_ctx *ctx, ir_reg reg, ir_insn *label) +{ + ir_backend_data *data = ctx->data; + dasm_State **Dst = &data->dasm_state; + + if (!data->resolved_label_syms) { + data->resolved_label_syms = 1; + ir_resolve_label_syms(ctx); + } + + IR_ASSERT(label->op == IR_LABEL); + int b = label->val.u32_hi; + + b = ir_skip_empty_target_blocks(ctx, b); + | lea Ra(reg), aword [=>b] +} + static void ir_emit_load(ir_ctx *ctx, ir_type type, ir_reg reg, ir_ref src) { if (IR_IS_CONST_REF(src)) { @@ -3241,9 +3302,11 @@ static void ir_emit_load(ir_ctx *ctx, ir_type type, ir_reg reg, ir_ref src) } else if (insn->op == IR_STR) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; - int label = ir_const_label(ctx, src); + int label = ir_get_const_label(ctx, src); | lea Ra(reg), aword [=>label] + } else if (insn->op == IR_LABEL) { + ir_emit_load_label_addr(ctx, reg, insn); } else { ir_emit_load_imm_int(ctx, type, reg, insn->val.i64); } @@ -3289,7 +3352,7 @@ static void ir_emit_store_mem_int_const(ir_ctx *ctx, ir_type type, ir_mem mem, i IR_ASSERT(IR_IS_CONST_REF(src)); if (val_insn->op == IR_STR) { - int label = ir_const_label(ctx, src); + int label = ir_get_const_label(ctx, src); IR_ASSERT(tmp_reg != IR_REG_NONE); |.if X64 @@ -3298,6 +3361,11 @@ static void ir_emit_store_mem_int_const(ir_ctx *ctx, ir_type type, ir_mem mem, i |.else | ASM_TMEM_TXT_OP mov, aword, mem, =>label |.endif + } else if (val_insn->op == IR_LABEL) { + IR_ASSERT(tmp_reg != IR_REG_NONE); + tmp_reg = IR_REG_NUM(tmp_reg); + ir_emit_load_label_addr(ctx, tmp_reg, val_insn); + ir_emit_store_mem_int(ctx, type, mem, tmp_reg); } else { int64_t val = val_insn->val.i64; @@ -3726,7 +3794,8 @@ static ir_mem ir_fuse_load(ir_ctx *ctx, ir_ref root, ir_ref ref) ir_insn *load_insn = &ctx->ir_base[ref]; ir_reg reg; - IR_ASSERT(load_insn->op == IR_LOAD); + IR_ASSERT(load_insn->op == IR_LOAD || load_insn->op == IR_LOAD_v || + load_insn->op == IR_VLOAD || load_insn->op == IR_VLOAD_v); if (UNEXPECTED(ctx->rules[ref] & IR_FUSED_REG)) { reg = ir_get_fused_reg(ctx, root, ref * sizeof(ir_ref) + 2); } else { @@ -3762,9 +3831,11 @@ static void ir_emit_load_ex(ir_ctx *ctx, ir_type type, ir_reg reg, ir_ref src, i } else if (insn->op == IR_STR) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; - int label = ir_const_label(ctx, src); + int label = ir_get_const_label(ctx, src); | lea Ra(reg), aword [=>label] + } else if (insn->op == IR_LABEL) { + ir_emit_load_label_addr(ctx, reg, insn); } else { ir_emit_load_imm_int(ctx, type, reg, insn->val.i64); } @@ -3862,7 +3933,7 @@ static void ir_emit_prologue(ir_ctx *ctx) if (ctx->flags & IR_USE_FRAME_POINTER) { fp = IR_REG_FRAME_POINTER; - offset = -(ctx->stack_frame_size - ctx->stack_frame_alignment - ctx->locals_area_size); + offset = -(ctx->stack_frame_size - ctx->locals_area_size); } else { fp = IR_REG_STACK_POINTER; offset = ctx->locals_area_size + ctx->call_stack_size; @@ -5607,7 +5678,7 @@ static void ir_emit_binop_sse2(ir_ctx *ctx, ir_ref def, ir_insn *insn) break; } } else if (IR_IS_CONST_REF(op2)) { - int label = ir_const_label(ctx, op2); + int label = ir_get_const_label(ctx, op2); switch (insn->op) { default: @@ -5714,7 +5785,7 @@ static void ir_emit_binop_avx(ir_ctx *ctx, ir_ref def, ir_insn *insn) break; } } else if (IR_IS_CONST_REF(op2)) { - int label = ir_const_label(ctx, op2); + int label = ir_get_const_label(ctx, op2); switch (insn->op) { default: @@ -6126,7 +6197,7 @@ static ir_op ir_emit_cmp_fp_common(ir_ctx *ctx, ir_ref root, ir_ref cmp_ref, ir_ } | ASM_FP_REG_REG_OP ucomis, type, op1_reg, op2_reg } else if (IR_IS_CONST_REF(op2)) { - int label = ir_const_label(ctx, op2); + int label = ir_get_const_label(ctx, op2); | ASM_FP_REG_TXT_OP ucomis, type, op1_reg, [=>label] } else { @@ -6975,7 +7046,7 @@ static void ir_emit_return_fp(ir_ctx *ctx, ir_ref ref, ir_insn *insn) } else if ((type == IR_FLOAT && value->val.f == 1.0) || (type == IR_DOUBLE && value->val.d == 1.0)) { | fld1 } else { - int label = ir_const_label(ctx, insn->op2); + int label = ir_get_const_label(ctx, insn->op2); if (type == IR_DOUBLE) { | fld qword [=>label] @@ -7260,7 +7331,20 @@ static void ir_emit_trunc(ir_ctx *ctx, ir_ref def, ir_insn *insn) ir_emit_load(ctx, src_type, op1_reg, insn->op1); } if (op1_reg != def_reg) { +#ifdef IR_TARGET_X86 + if (ir_type_size[dst_type] == 1 + && (op1_reg == IR_REG_RBP || op1_reg == IR_REG_RSI || op1_reg == IR_REG_RDI)) { + ir_backend_data *data = ctx->data; + dasm_State **Dst = &data->dasm_state; + + ir_emit_mov(ctx, src_type, def_reg, op1_reg); + | and Rb(def_reg), 0xff + } else { + ir_emit_mov(ctx, dst_type, def_reg, op1_reg); + } +#else ir_emit_mov(ctx, dst_type, def_reg, op1_reg); +#endif } } else { ir_emit_load_ex(ctx, dst_type, def_reg, insn->op1, def); @@ -7385,7 +7469,7 @@ static void ir_emit_bitcast(ir_ctx *ctx, ir_ref def, ir_insn *insn) } } } else if (IR_IS_CONST_REF(insn->op1)) { - int label = ir_const_label(ctx, insn->op1); + int label = ir_get_const_label(ctx, insn->op1); | ASM_FP_REG_TXT_OP movs, dst_type, def_reg, [=>label] } else { @@ -7417,13 +7501,80 @@ static void ir_emit_int2fp(ir_ctx *ctx, ir_ref def, ir_insn *insn) IR_ASSERT(IR_IS_TYPE_INT(src_type)); IR_ASSERT(IR_IS_TYPE_FP(dst_type)); IR_ASSERT(def_reg != IR_REG_NONE); + + if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { + op1_reg = IR_REG_NUM(op1_reg); + ir_emit_load(ctx, src_type, op1_reg, insn->op1); + } + + if (IR_IS_TYPE_UNSIGNED(src_type) && ir_type_size[src_type] >= sizeof(void*)) { + ir_reg tmp_reg = ctx->regs[def][2]; + + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op1_reg == IR_REG_NONE) { + if (IR_IS_CONST_REF(insn->op1)) { + IR_ASSERT(0); + } else { + ir_mem mem; + + if (ir_rule(ctx, insn->op1) & IR_FUSED) { + mem = ir_fuse_load(ctx, def, insn->op1); + } else { + mem = ir_ref_spill_slot(ctx, insn->op1); + } + ir_emit_load_mem_int(ctx, src_type, tmp_reg, mem); + op1_reg = tmp_reg; + } + } + if (sizeof(void*) == 4) { + if (tmp_reg == op1_reg) { + | add Rd(op1_reg), 0x80000000 + } else { + | lea Rd(tmp_reg), dword [Rd(op1_reg)+0x80000000] + op1_reg = tmp_reg; + } + } else { +|.if X64 + | test Rq(op1_reg), Rq(op1_reg) + | js >1 + |.cold_code + |1: + if (tmp_reg != op1_reg) { + | mov Rq(tmp_reg), Rq(op1_reg) + } + | shr Rq(tmp_reg), 1 + | adc Rq(tmp_reg), 0 + if (dst_type == IR_DOUBLE) { + if (ctx->mflags & IR_X86_AVX) { + | vxorps xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST) + | vcvtsi2sd xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST), Rq(tmp_reg) + | vaddsd xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST) + } else { + | pxor xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST) + | cvtsi2sd xmm(def_reg-IR_REG_FP_FIRST), Rq(tmp_reg) + | addsd xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST) + } + } else { + IR_ASSERT(dst_type == IR_FLOAT); + if (ctx->mflags & IR_X86_AVX) { + | vxorps xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST) + | vcvtsi2ss xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST), Rq(tmp_reg) + | vaddss xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST) + } else { + | pxor xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST) + | cvtsi2ss xmm(def_reg-IR_REG_FP_FIRST), Rq(tmp_reg) + | addss xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST) + } + } + | jmp >2 + |.code +|.endif + } + } + if (op1_reg != IR_REG_NONE) { bool src64 = 0; - if (IR_REG_SPILLED(op1_reg)) { - op1_reg = IR_REG_NUM(op1_reg); - ir_emit_load(ctx, src_type, op1_reg, insn->op1); - } if (IR_IS_TYPE_SIGNED(src_type)) { if (ir_type_size[src_type] < 4) { |.if X64 @@ -7462,7 +7613,6 @@ static void ir_emit_int2fp(ir_ctx *ctx, ir_ref def, ir_insn *insn) || } |.endif } else { - // TODO: uint64_t -> double src64 = 1; } } @@ -7508,6 +7658,40 @@ static void ir_emit_int2fp(ir_ctx *ctx, ir_ref def, ir_insn *insn) } |.endif } + |2: + if (sizeof(void*) == 4 && IR_IS_TYPE_UNSIGNED(src_type) && ir_type_size[src_type] >= sizeof(void*)) { + if (dst_type == IR_DOUBLE) { + uint32_t c = (sizeof(void*) == 4) ? 0x41e00000 : 0x43e00000; + if (!data->u2d_const) { + data->u2d_const = 1; + ir_rodata(ctx); + |.align 8 + |->u2d_const: + |.dword 0, c + |.code + } + if (ctx->mflags & IR_X86_AVX) { + | vaddsd xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST), qword [->u2d_const] + } else { + | addsd xmm(def_reg-IR_REG_FP_FIRST), qword [->u2d_const] + } + } else { + uint32_t c = (sizeof(void*) == 4) ? 0x4f000000 : 0x5f000000; + if (!data->u2f_const) { + data->u2f_const = 1; + ir_rodata(ctx); + |.align 4 + |->u2f_const: + |.dword c + |.code + } + if (ctx->mflags & IR_X86_AVX) { + | vaddss xmm(def_reg-IR_REG_FP_FIRST), xmm(def_reg-IR_REG_FP_FIRST), dword [->u2f_const] + } else { + | addss xmm(def_reg-IR_REG_FP_FIRST), dword [->u2f_const] + } + } + } } else if (IR_IS_CONST_REF(insn->op1)) { IR_ASSERT(0); } else { @@ -7625,7 +7809,7 @@ static void ir_emit_fp2int(ir_ctx *ctx, ir_ref def, ir_insn *insn) |.endif } } else if (IR_IS_CONST_REF(insn->op1)) { - int label = ir_const_label(ctx, insn->op1); + int label = ir_get_const_label(ctx, insn->op1); if (!dst64) { if (src_type == IR_DOUBLE) { @@ -7746,7 +7930,7 @@ static void ir_emit_fp2fp(ir_ctx *ctx, ir_ref def, ir_insn *insn) } } } else if (IR_IS_CONST_REF(insn->op1)) { - int label = ir_const_label(ctx, insn->op1); + int label = ir_get_const_label(ctx, insn->op1); if (src_type == IR_DOUBLE) { if (ctx->mflags & IR_X86_AVX) { @@ -8429,7 +8613,7 @@ static void ir_emit_va_start(ir_ctx *ctx, ir_ref def, ir_insn *insn) if (ctx->flags & IR_USE_FRAME_POINTER) { fp = IR_REG_FRAME_POINTER; - reg_save_area_offset = -(ctx->stack_frame_size - ctx->stack_frame_alignment - ctx->locals_area_size); + reg_save_area_offset = -(ctx->stack_frame_size - ctx->locals_area_size); overflow_arg_area_offset = sizeof(void*) * 2 + ctx->param_stack_size; } else { fp = IR_REG_STACK_POINTER; @@ -8588,11 +8772,11 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn) } | add Ra(tmp_reg), IR_MAX(ir_type_size[type], sizeof(void*)) } else { - int size = (uint32_t)insn->op3 >> 3; + int size = IR_VA_ARG_SIZE(insn->op3); if (def_reg != IR_REG_NONE) { IR_ASSERT(type == IR_ADDR); - int align = 1U << (insn->op3 & 0x7); + int align = IR_VA_ARG_ALIGN(insn->op3); if (align > (int)sizeof(void*)) { | add Ra(tmp_reg), (align-1) @@ -8604,7 +8788,7 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn) } #endif | mov aword [Ra(op2_reg)+offset], Ra(tmp_reg) - if (def_reg && IR_REG_SPILLED(ctx->regs[def][0])) { + if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) { ir_emit_store(ctx, type, def, def_reg); } #elif defined(IR_TARGET_X64) @@ -8632,8 +8816,8 @@ static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn) if (insn->op3) { /* long struct arguemnt */ IR_ASSERT(type == IR_ADDR); - int align = 1U << (insn->op3 & 0x7); - int size = (uint32_t)insn->op3 >> 3; + int align = IR_VA_ARG_ALIGN(insn->op3); + int size = IR_VA_ARG_SIZE(insn->op3); | mov Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, overflow_arg_area))] if (align > (int)sizeof(void*)) { @@ -9701,6 +9885,19 @@ static void ir_emit_ijmp(ir_ctx *ctx, ir_ref def, ir_insn *insn) ir_reg op2_reg = ctx->regs[def][2]; if (IR_IS_CONST_REF(insn->op2)) { + if (ctx->ir_base[insn->op2].op == IR_LABEL) { + if (!data->resolved_label_syms) { + data->resolved_label_syms = 1; + ir_resolve_label_syms(ctx); + } + + uint32_t target = ctx->ir_base[insn->op2].val.u32_hi; + target = ir_skip_empty_target_blocks(ctx, target); + + | jmp =>target + return; + } + void *addr = ir_jmp_addr(ctx, insn, &ctx->ir_base[insn->op2]); if (sizeof(void*) == 4 || IR_MAY_USE_32BIT_ADDR(ctx->code_buffer, addr)) { @@ -10478,6 +10675,7 @@ static void ir_emit_param_move(ir_ctx *ctx, uint8_t type, ir_reg from_reg, ir_re { ir_reg fp = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = IR_SPILL_POS_TO_OFFSET(offset); IR_ASSERT(from_reg != IR_REG_NONE || to_reg != IR_REG_NONE); if (IR_IS_TYPE_INT(type)) { @@ -10518,6 +10716,7 @@ static void ir_emit_load_params(ir_ctx *ctx) const int8_t *int_reg_params = _ir_int_reg_params; const int8_t *fp_reg_params = _ir_fp_reg_params; int32_t stack_offset = 0; + int32_t stack_start = 0; #ifdef IR_TARGET_X86 if (sizeof(void*) == 4 && (ctx->flags & IR_FASTCALL_FUNC)) { @@ -10529,9 +10728,11 @@ static void ir_emit_load_params(ir_ctx *ctx) #endif if (ctx->flags & IR_USE_FRAME_POINTER) { - stack_offset = sizeof(void*) * 2; /* skip old frame pointer and return address */ + /* skip old frame pointer and return address */ + stack_start = sizeof(void*) * 2 + ctx->stack_frame_size; } else { - stack_offset = sizeof(void*) + ctx->stack_frame_size + ctx->call_stack_size; /* skip return address */ + /* skip return address */ + stack_start = sizeof(void*) + ctx->stack_frame_size; } n = use_list->count; for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) { @@ -10573,12 +10774,9 @@ static void ir_emit_load_params(ir_ctx *ctx) if (ctx->vregs[use]) { dst_reg = IR_REG_NUM(ctx->regs[use][0]); IR_ASSERT(src_reg != IR_REG_NONE || dst_reg != IR_REG_NONE || - stack_offset == ctx->live_intervals[ctx->vregs[use]]->stack_spill_pos + - ((ctx->flags & IR_USE_FRAME_POINTER) ? - -(ctx->stack_frame_size - ctx->stack_frame_alignment) : - ctx->call_stack_size)); + stack_start + stack_offset == ctx->live_intervals[ctx->vregs[use]]->stack_spill_pos); if (src_reg != dst_reg) { - ir_emit_param_move(ctx, insn->type, src_reg, dst_reg, use, stack_offset); + ir_emit_param_move(ctx, insn->type, src_reg, dst_reg, use, stack_start + stack_offset); } if (dst_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[use][0])) { ir_emit_store(ctx, insn->type, use, dst_reg); @@ -10665,7 +10863,7 @@ static void ir_fix_param_spills(ir_ctx *ctx) if (ctx->flags & IR_USE_FRAME_POINTER) { /* skip old frame pointer and return address */ - stack_start = sizeof(void*) * 2 + (ctx->stack_frame_size - ctx->stack_frame_alignment); + stack_start = sizeof(void*) * 2 + ctx->stack_frame_size; } else { /* skip return address */ stack_start = sizeof(void*) + ctx->stack_frame_size; @@ -10786,6 +10984,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) case IR_MERGE: case IR_LOOP_BEGIN: case IR_LOOP_END: + case IR_IGOTO_DUP: break; #ifndef IR_REG_FP_RET1 case IR_CALL: @@ -10810,7 +11009,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) IR_REGSET_EXCL(available, reg); ctx->regs[i][0] = reg | IR_REG_SPILL_STORE; } else if (def_flags & IR_USE_MUST_BE_IN_REG) { - if (insn->op == IR_VLOAD + if ((insn->op == IR_VLOAD || insn->op == IR_VLOAD_v) && ctx->live_intervals[ctx->vregs[i]] && ctx->live_intervals[ctx->vregs[i]]->stack_spill_pos != -1 && ir_is_same_mem_var(ctx, i, ctx->ir_base[insn->op2].op3)) { @@ -10850,7 +11049,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) for (i = 0, p = &ctx->use_edges[use_list->refs]; i < n; i++, p++) { use = *p; use_insn = &ctx->ir_base[use]; - if (use_insn->op == IR_VLOAD) { + if (use_insn->op == IR_VLOAD || use_insn->op == IR_VLOAD_v) { if (ctx->vregs[use] && !ctx->live_intervals[ctx->vregs[use]]) { ir_live_interval *ival = ir_arena_alloc(&ctx->arena, sizeof(ir_live_interval)); @@ -10861,7 +11060,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) ival->vreg = ctx->vregs[use]; ival->stack_spill_pos = stack_spill_pos; } - } else if (use_insn->op == IR_VSTORE) { + } else if (use_insn->op == IR_VSTORE || use_insn->op == IR_VSTORE_v) { if (!IR_IS_CONST_REF(use_insn->op3) && ctx->vregs[use_insn->op3] && !ctx->live_intervals[ctx->vregs[use_insn->op3]]) { @@ -11006,7 +11205,6 @@ void ir_fix_stack_frame(ir_ctx *ctx) ctx->stack_frame_size = IR_ALIGNED_SIZE(ctx->stack_frame_size, sizeof(void*)); ctx->stack_frame_size += additional_size; - ctx->stack_frame_alignment = 0; ctx->call_stack_size = 0; if (ctx->flags2 & IR_16B_FRAME_ALIGNMENT) { @@ -11014,12 +11212,10 @@ void ir_fix_stack_frame(ir_ctx *ctx) if (!(ctx->flags & IR_FUNCTION)) { while (IR_ALIGNED_SIZE(ctx->stack_frame_size, 16) != ctx->stack_frame_size) { ctx->stack_frame_size += sizeof(void*); - ctx->stack_frame_alignment += sizeof(void*); } } else if (ctx->flags & IR_USE_FRAME_POINTER) { while (IR_ALIGNED_SIZE(ctx->stack_frame_size + sizeof(void*) * 2, 16) != ctx->stack_frame_size + sizeof(void*) * 2) { ctx->stack_frame_size += sizeof(void*); - ctx->stack_frame_alignment += sizeof(void*); } } else { if (!(ctx->flags & IR_NO_STACK_COMBINE)) { @@ -11028,7 +11224,6 @@ void ir_fix_stack_frame(ir_ctx *ctx) while (IR_ALIGNED_SIZE(ctx->stack_frame_size + ctx->call_stack_size + sizeof(void*), 16) != ctx->stack_frame_size + ctx->call_stack_size + sizeof(void*)) { ctx->stack_frame_size += sizeof(void*); - ctx->stack_frame_alignment += sizeof(void*); } } } @@ -11061,6 +11256,8 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) int ret; void *entry; size_t size; + ir_ref igoto_dup_ref = IR_UNUSED; + uint32_t igoto_dup_block = 0; data.ra_data.unused_slot_4 = 0; data.ra_data.unused_slot_2 = 0; @@ -11073,11 +11270,13 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) data.double_abs_const = 0; data.float_abs_const = 0; data.double_zero_const = 0; + data.u2d_const = 0; + data.u2f_const = 0; + data.resolved_label_syms = 0; ctx->data = &data; if (!ctx->live_intervals) { ctx->stack_frame_size = 0; - ctx->stack_frame_alignment = 0; ctx->call_stack_size = 0; ctx->used_preserved_regs = 0; ir_allocate_unique_spill_slots(ctx); @@ -11099,7 +11298,6 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) } ctx->stack_frame_size = ctx->fixed_stack_frame_size; ctx->call_stack_size = ctx->fixed_call_stack_size; - ctx->stack_frame_alignment = 0; } Dst = &data.dasm_state; @@ -11420,6 +11618,35 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) case IR_TAILCALL: ir_emit_tailcall(ctx, i, insn); break; + case IR_IGOTO_DUP: + if (bb->flags & IR_BB_DESSA_MOVES) { + ir_emit_dessa_moves(ctx, b, bb); + } + IR_ASSERT(!igoto_dup_ref && !igoto_dup_block); + igoto_dup_ref = i; + igoto_dup_block = b; + b = ctx->cfg_edges[bb->successors]; + bb = &ctx->cfg_blocks[b]; + i = bb->start; + insn = &ctx->ir_base[i]; + rule = &ctx->rules[i]; + break; + case IR_IGOTO: + if ((ctx->ir_base[insn->op1].op == IR_MERGE || ctx->ir_base[insn->op1].op == IR_LOOP_BEGIN) + && (ctx->rules[ctx->ir_base[insn->op1].op1] & IR_RULE_MASK) == IR_IGOTO_DUP + && igoto_dup_ref) { + ir_emit_ijmp(ctx, i, insn); + b = igoto_dup_block; + bb = &ctx->cfg_blocks[b]; + i = igoto_dup_ref; + insn = &ctx->ir_base[i]; + rule = &ctx->rules[i]; + igoto_dup_block= 0; + igoto_dup_ref = 0; + break; + } + IR_ASSERT(!igoto_dup_ref && !igoto_dup_block); + IR_FALLTHROUGH; case IR_IJMP: ir_emit_ijmp(ctx, i, insn); break; @@ -11449,6 +11676,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) ir_emit_vaddr(ctx, i, insn); break; case IR_VLOAD: + case IR_VLOAD_v: ir_emit_vload(ctx, i, insn); break; case IR_VSTORE_INT: @@ -11691,6 +11919,28 @@ next_block:; } while (i != 0); } + if ((ctx->flags2 & IR_HAS_BLOCK_ADDR) && ctx->loader && ctx->loader->add_label) { + for (b = 1, bb = &ctx->cfg_blocks[b]; b <= ctx->cfg_blocks_count; bb++, b++) { + ir_insn *insn = &ctx->ir_base[bb->start]; + + if (insn->op == IR_BEGIN && insn->op2) { + IR_ASSERT(ctx->ir_base[insn->op2].op == IR_LABEL); + ctx->ir_base[insn->op2].val.u32_hi = 0; + ctx->loader->add_label(ctx->loader, ir_get_str(ctx, ctx->ir_base[insn->op2].val.str), + (char*)entry + dasm_getpclabel(&data.dasm_state, ir_skip_empty_target_blocks(ctx, b))); + } + } + } else if (data.resolved_label_syms) { + for (b = 1, bb = &ctx->cfg_blocks[b]; b <= ctx->cfg_blocks_count; bb++, b++) { + ir_insn *insn = &ctx->ir_base[bb->start]; + + if (insn->op == IR_BEGIN && insn->op2) { + IR_ASSERT(ctx->ir_base[insn->op2].op == IR_LABEL); + ctx->ir_base[insn->op2].val.u32_hi = 0; + } + } + } + dasm_free(&data.dasm_state); ir_mem_flush(entry, size); diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 9dc6ea1c3b003..10be237d06b8e 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -493,7 +493,7 @@ static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, && func->type == ZEND_INTERNAL_FUNCTION && (func->internal_function.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0 && arg_num < func->internal_function.num_args) { - const zend_internal_arg_info *arg_info = &func->internal_function.arg_info[arg_num]; + const zend_arg_info *arg_info = &func->internal_function.arg_info[arg_num]; if (ZEND_ARG_SEND_MODE(arg_info) == ZEND_SEND_BY_VAL && ZEND_TYPE_IS_SET(arg_info->type) diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 4d1b5dff2e353..886a292ee290d 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -94,7 +94,7 @@ typedef cpuset_t *cpu_set_t; #elif defined(HAVE_PSET_BIND) #include typedef psetid_t cpu_set_t; - #define sched_getaffinity(p, c, m) pset_bind(PS_QUERY, P_PID, (p <= 0 ? getpid() : p), &m) + #define sched_getaffinity(p, c, m) pset_bind(PS_QUERY, P_PID, p, &m) #define sched_setaffinity(p, c, m) pset_bind(m, P_PID, (p <= 0 ? getpid() : p), NULL) #define PCNTL_CPUSET(mask) mask #define PCNTL_CPU_ISSET(i, mask) (pset_assign(PS_QUERY, (processorid_t)i, &query) == 0 && query == mask) diff --git a/ext/pcre/pcre2lib/pcre2_chartables.c b/ext/pcre/pcre2lib/pcre2_chartables.c index 861914d1ac3ac..7362c3f2345ab 100644 --- a/ext/pcre/pcre2lib/pcre2_chartables.c +++ b/ext/pcre/pcre2lib/pcre2_chartables.c @@ -5,7 +5,8 @@ /* This file was automatically written by the pcre2_dftables auxiliary program. It contains character tables that are used when no external tables are passed to PCRE2 by the application that calls it. The tables -are used only for characters whose code values are less than 256. */ +are used only for characters whose code values are less than 256, and +only relevant if not in UCP mode. */ /* This set of tables was written in the C locale. */ @@ -18,13 +19,6 @@ PCRE2 is configured with --enable-rebuild-chartables. However, you can run pcre2_dftables manually with the -L option to build tables using the LC_ALL locale. */ -/* The following #include is present because without it gcc 4.x may remove -the array definition from the final binary if PCRE2 is built into a static -library and dead code stripping is activated. This leads to link errors. -Pulling in the header ensures that the array gets flagged as "someone -outside this compilation unit might reference this" and so it will always -be supplied to the linker. */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -163,7 +157,7 @@ graph, print, punct, and cntrl. Other classes are built from combinations. */ 0x02 letter 0x04 lower case letter 0x08 decimal digit - 0x10 alphanumeric or '_' + 0x10 word (alphanumeric or '_') */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index beb3665c4d924..34f19e364faa7 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1321,6 +1321,7 @@ static void cls_method_dtor(zval *el) /* {{{ */ { if (func->common.attributes) { zend_hash_release(func->common.attributes); } + zend_free_internal_arg_info(&func->internal_function, false); efree(func); } /* }}} */ @@ -1336,6 +1337,7 @@ static void cls_method_pdtor(zval *el) /* {{{ */ { if (func->common.attributes) { zend_hash_release(func->common.attributes); } + zend_free_internal_arg_info(&func->internal_function, true); pefree(func, 1); } /* }}} */ @@ -1408,7 +1410,19 @@ bool pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind) if (funcs->arg_info) { zend_internal_function_info *info = (zend_internal_function_info*)funcs->arg_info; - func.arg_info = (zend_internal_arg_info*)funcs->arg_info + 1; + uint32_t num_arg_info = 1 + funcs->num_args; + if (func.fn_flags & ZEND_ACC_VARIADIC) { + num_arg_info++; + } + + zend_arg_info *arg_info = safe_pemalloc(num_arg_info, + sizeof(zend_arg_info), 0, dbh->is_persistent); + for (uint32_t i = 0; i < num_arg_info; i++) { + zend_convert_internal_arg_info(&arg_info[i], + &funcs->arg_info[i], i == 0, dbh->is_persistent); + } + + func.arg_info = arg_info + 1; func.num_args = funcs->num_args; if (info->required_num_args == (uint32_t)-1) { func.required_num_args = funcs->num_args; diff --git a/ext/pdo/pdo_sql_parser.re b/ext/pdo/pdo_sql_parser.re index a87fd473404ec..1897f9f238bf1 100644 --- a/ext/pdo/pdo_sql_parser.re +++ b/ext/pdo/pdo_sql_parser.re @@ -300,6 +300,12 @@ safe: } plc->quoted = stmt->dbh->methods->quoter(stmt->dbh, buf, param_type); + if (plc->quoted == NULL) { + /* bork */ + ret = -1; + strncpy(stmt->error_code, stmt->dbh->error_code, 6); + goto clean_up; + } } } diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index e87af66c75868..73d4530e8f657 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -771,9 +771,10 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified"); goto in_fetch_error; } - ctor_arguments = stmt->fetch.cls.ctor_args; } ZEND_ASSERT(ce != NULL); + + ctor_arguments = stmt->fetch.cls.ctor_args; if (flags & PDO_FETCH_SERIALIZE) { if (!ce->unserialize) { /* As this option is deprecated we do not bother to mention the class name. */ diff --git a/ext/pdo/tests/gh20553.phpt b/ext/pdo/tests/gh20553.phpt new file mode 100644 index 0000000000000..fe0b84c27ebb0 --- /dev/null +++ b/ext/pdo/tests/gh20553.phpt @@ -0,0 +1,97 @@ +--TEST-- +GH-20553: PHP 8.5.0 regression: PDO::FETCH_CLASSTYPE ignores $constructorArgs +--EXTENSIONS-- +pdo +--SKIPIF-- + +--FILE-- + PDO::FETCH_CLASS, + 'PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE' + => PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, + 'PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE' + => PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE, + 'PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE | PDO::FETCH_PROPS_LATE' + => PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE | PDO::FETCH_PROPS_LATE, +]; + +foreach ($fetchModes as $combinedModes => $fetchMode) { + echo '## ' . $combinedModes . PHP_EOL; + $db->query($sql)->fetchAll( + $fetchMode, + 'dumpy', + ['constructor argument #1'] + ); + echo PHP_EOL; +} +?> +--EXPECT-- +## PDO::FETCH_CLASS +'pdo_fetch_class_type_class' = 'dummy' +'foo' = 'bar' +'abc' = 'dfg' +constructor called, + my class is 'dumpy' + input parameters: array ( + 0 => 'constructor argument #1', +) + +## PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE +constructor called, + my class is 'dumpy' + input parameters: array ( + 0 => 'constructor argument #1', +) +'pdo_fetch_class_type_class' = 'dummy' +'foo' = 'bar' +'abc' = 'dfg' + +## PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE +'foo' = 'bar' +'abc' = 'dfg' +constructor called, + my class is 'dummy' + input parameters: array ( + 0 => 'constructor argument #1', +) + +## PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE | PDO::FETCH_PROPS_LATE +constructor called, + my class is 'dummy' + input parameters: array ( + 0 => 'constructor argument #1', +) +'foo' = 'bar' +'abc' = 'dfg' diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 8eea24a65353f..76384a187477c 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -758,7 +758,7 @@ static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) /* ret = -1; goto free_statement; } - while (result[i] != isc_info_end && i < result_size) { + while (i < result_size && result[i] != isc_info_end) { short len = (short)isc_vax_integer(&result[i+1],2); /* bail out on bad len */ if (len != 1 && len != 2 && len != 4) { diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index 96b5cb1da1240..d506aa69eed31 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -235,7 +235,7 @@ static int pdo_firebird_stmt_execute(pdo_stmt_t *stmt) /* {{{ */ if (result_size > sizeof(result)) { goto error; } - while (result[i] != isc_info_end && i < result_size) { + while (i < result_size && result[i] != isc_info_end) { short len = (short) isc_vax_integer(&result[i + 1], 2); if (len != 1 && len != 2 && len != 4) { goto error; diff --git a/ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt b/ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt index 2437e7ca12d16..910afceb27f08 100644 --- a/ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt @@ -73,7 +73,7 @@ MySQLPDOTest::skip(); } if (!is_object($db = new PDO($dsn, $user, $pass, array()))) - printf("[002] Expecting object got %s/%s¸\n", gettype($db), $db); + printf("[002] Expecting object got %s/%s\n", gettype($db), $db); $invalid = 999; if (is_object($db = new PDO($dsn, $user, $pass, array($invalid => true)))) diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index be865c1f86838..44f70e00236d2 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -1340,6 +1340,20 @@ static const zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, i } } +static void pdo_pgsql_request_shutdown(pdo_dbh_t *dbh) +{ + PGresult *res; + pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; + + if(H->server) { + res = PQexec(H->server, "DISCARD ALL"); + + if(res) { + PQclear(res); + } + } +} + static bool pdo_pgsql_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) { bool bval; @@ -1383,7 +1397,7 @@ static const struct pdo_dbh_methods pgsql_methods = { pdo_pgsql_get_attribute, pdo_pgsql_check_liveness, /* check_liveness */ pdo_pgsql_get_driver_methods, /* get_driver_methods */ - NULL, + pdo_pgsql_request_shutdown, pgsql_handle_in_transaction, NULL, /* get_gc */ pdo_pgsql_scanner diff --git a/ext/pdo_pgsql/tests/ghsa-8xr5-qppj-gvwj.phpt b/ext/pdo_pgsql/tests/ghsa-8xr5-qppj-gvwj.phpt new file mode 100644 index 0000000000000..736354cab13cb --- /dev/null +++ b/ext/pdo_pgsql/tests/ghsa-8xr5-qppj-gvwj.phpt @@ -0,0 +1,28 @@ +--TEST-- +#GHSA-8xr5-qppj-gvwj: NULL Pointer Derefernce for failed user input quoting +--EXTENSIONS-- +pdo +pdo_pgsql +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + +$sql = "SELECT * FROM users where username = :username"; +$stmt = $db->prepare($sql); + +$p1 = "alice\x99"; +var_dump($stmt->execute(['username' => $p1])); + +?> +--EXPECT-- +bool(false) diff --git a/ext/pdo_pgsql/tests/session_state_reset.phpt b/ext/pdo_pgsql/tests/session_state_reset.phpt new file mode 100644 index 0000000000000..ad892bb0da52e --- /dev/null +++ b/ext/pdo_pgsql/tests/session_state_reset.phpt @@ -0,0 +1,55 @@ +--TEST-- +Persistent connections: session state reset when performing disconnect-equivalent processing (general case) +--EXTENSIONS-- +pdo_pgsql +--SKIPIF-- + +--FILE-- + true])); + +require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; + +$pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt'); + +$pid1 = (int)$pdo1 + ->query('select pg_backend_pid()::int;') + ->fetchColumn(0); + +$defaultValue = (int)$pdo1 + ->query('show log_min_duration_statement;') + ->fetchColumn(0); + +$setValue = $defaultValue + 1; + +$pdo1->exec("set log_min_duration_statement = {$setValue};"); + +$pdo1 = null; + +$pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt'); + +$pid2 = (int)$pdo2 + ->query('select pg_backend_pid()::int;') + ->fetchColumn(0); + +assert($pid1 === $pid2); + +$expectedValue = (int)$pdo2 + ->query('show log_min_duration_statement;') + ->fetchColumn(0); + +echo "defaultValue: {$defaultValue}\n"; +echo "setValue: {$setValue}\n"; +echo "expectedValue: {$expectedValue}\n"; +echo "expected value should be reset to default: " . (($expectedValue === $defaultValue) ? 'success' : 'failure') . "\n"; + +?> +--EXPECTF-- +defaultValue: %i +setValue: %d +expectedValue: %i +expected value should be reset to default: success diff --git a/ext/pdo_pgsql/tests/session_state_reset_advisory_lock.phpt b/ext/pdo_pgsql/tests/session_state_reset_advisory_lock.phpt new file mode 100644 index 0000000000000..3435f6b7b402f --- /dev/null +++ b/ext/pdo_pgsql/tests/session_state_reset_advisory_lock.phpt @@ -0,0 +1,51 @@ +--TEST-- +Persistent connections: session state reset when performing disconnect-equivalent processing (advisory lock case) +--EXTENSIONS-- +pdo_pgsql +--SKIPIF-- + +--FILE-- + true])); + +require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; + +$pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt'); + +$pid1 = (int)$pdo1 + ->query('select pg_backend_pid()::int;') + ->fetchColumn(0); + +$lockResult1 = (bool)$pdo1 + ->query('select pg_try_advisory_lock(42)::int;') + ->fetchColumn(0); + +$pdo1 = null; + +$dsn = getenv('PDO_PGSQL_TEST_DSN'); +$dsn .= ';'; +putenv('PDO_PGSQL_TEST_DSN='.$dsn); + +$pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt'); + +$pid2 = (int)$pdo2 + ->query('select pg_backend_pid()::int;') + ->fetchColumn(0); + +assert($pid1 !== $pid2); + +$lockResult2 = (bool)$pdo2 + ->query('select pg_try_advisory_lock(42)::int;') + ->fetchColumn(0); + +echo "lock1: " . ($lockResult1 ? 'success' : 'failure') . "\n"; +echo "lock2: " . ($lockResult2 ? 'success' : 'failure') . "\n"; + +?> +--EXPECT-- +lock1: success +lock2: success diff --git a/ext/pdo_pgsql/tests/session_state_reset_after_interrupted.phpt b/ext/pdo_pgsql/tests/session_state_reset_after_interrupted.phpt new file mode 100644 index 0000000000000..fdafe8a00fc39 --- /dev/null +++ b/ext/pdo_pgsql/tests/session_state_reset_after_interrupted.phpt @@ -0,0 +1,52 @@ +--TEST-- +Persistent connections: session state reset after backend termination (interrupted case) +--EXTENSIONS-- +pdo_pgsql +--SKIPIF-- + +--FILE-- + true])); + +require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc'; + +$pdo1 = PDOTest::test_factory(__DIR__ . '/common.phpt'); + +$pid1 = (int)$pdo1 + ->query('select pg_backend_pid()::int;') + ->fetchColumn(0); + +$pid1 = (int)$pdo1 + ->query('select pg_backend_pid()::int;') + ->fetchColumn(0); + +$dsn = getenv('PDO_PGSQL_TEST_DSN'); +$dsn .= ';'; +putenv('PDO_PGSQL_TEST_DSN='.$dsn); + +$pdo2 = PDOTest::test_factory(__DIR__ . '/common.phpt'); + +$pid2 = (int)$pdo2 + ->query('select pg_backend_pid()::int;') + ->fetchColumn(0); + +assert($pid1 !== $pid2); + +$terminateResult = (bool)$pdo2 + ->query("select pg_terminate_backend({$pid1})::int") + ->fetchColumn(0); + +// Disconnect after being terminated by another connection +$pdo1 = null; + +echo 'pid of pdo1: ' . $pid1 . "\n"; +echo 'terminate result of pdo1 by pdo2: ' . ($terminateResult ? 'success' : 'failure') . "\n"; + +?> +--EXPECTF-- +pid of pdo1: %d +terminate result of pdo1 by pdo2: success diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 77425b25aee17..e3d8cb82ece91 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -3350,9 +3350,8 @@ PHP_FUNCTION(pg_copy_to) pgsql_link_handle *link; zend_string *table_name; zend_string *pg_delimiter = NULL; - char *pg_null_as = NULL; + char *pg_null_as = "\\\\N"; size_t pg_null_as_len = 0; - bool free_pg_null = false; char *query; PGconn *pgsql; PGresult *pgsql_result; @@ -3377,10 +3376,6 @@ PHP_FUNCTION(pg_copy_to) zend_argument_value_error(3, "must be one character"); RETURN_THROWS(); } - if (!pg_null_as) { - pg_null_as = estrdup("\\\\N"); - free_pg_null = true; - } spprintf(&query, 0, "COPY %s TO STDOUT DELIMITER E'%c' NULL AS E'%s'", ZSTR_VAL(table_name), *ZSTR_VAL(pg_delimiter), pg_null_as); @@ -3388,9 +3383,6 @@ PHP_FUNCTION(pg_copy_to) PQclear(pgsql_result); } pgsql_result = PQexec(pgsql, query); - if (free_pg_null) { - efree(pg_null_as); - } efree(query); if (pgsql_result) { @@ -3475,9 +3467,8 @@ PHP_FUNCTION(pg_copy_from) zval *value; zend_string *table_name; zend_string *pg_delimiter = NULL; - char *pg_null_as = NULL; + char *pg_null_as = "\\\\N"; size_t pg_null_as_len; - bool pg_null_as_free = false; char *query; PGconn *pgsql; PGresult *pgsql_result; @@ -3502,10 +3493,6 @@ PHP_FUNCTION(pg_copy_from) zend_argument_value_error(4, "must be one character"); RETURN_THROWS(); } - if (!pg_null_as) { - pg_null_as = estrdup("\\\\N"); - pg_null_as_free = true; - } spprintf(&query, 0, "COPY %s FROM STDIN DELIMITER E'%c' NULL AS E'%s'", ZSTR_VAL(table_name), *ZSTR_VAL(pg_delimiter), pg_null_as); while ((pgsql_result = PQgetResult(pgsql))) { @@ -3513,9 +3500,6 @@ PHP_FUNCTION(pg_copy_from) } pgsql_result = PQexec(pgsql, query); - if (pg_null_as_free) { - efree(pg_null_as); - } efree(query); if (pgsql_result) { diff --git a/ext/phar/phar.c b/ext/phar/phar.c index c5bfb1b34c24f..385e9afeda14d 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -260,20 +260,26 @@ bool phar_archive_delref(phar_archive_data *phar) /* {{{ */ PHAR_G(last_phar) = NULL; PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL; + /* This is a new phar that has perhaps had an alias/metadata set, but has never been flushed. */ + bool remove_fname_cache = !zend_hash_num_elements(&phar->manifest); + if (phar->fp && (!(phar->flags & PHAR_FILE_COMPRESSION_MASK) || !phar->alias)) { /* close open file handle - allows removal or rename of the file on windows, which has greedy locking - only close if the archive was not already compressed. If it - was compressed, then the fp does not refer to the original file. - We're also closing compressed files to save resources, - but only if the archive isn't aliased. */ + only close if the archive was not already compressed. + We're also closing compressed files to save resources, but only if the archive isn't aliased. + If it was compressed, then the fp does not refer to the original compressed file: + it refers to the **uncompressed** filtered file stream. + Therefore, upon closing a compressed file we need to invalidate the phar archive such + that the code that reopens the phar will not try to use the **compressed** file as if it was uncompressed. + That would result in treating compressed file data as if it were compressed and using uncompressed file offsets + on the compressed file. */ php_stream_close(phar->fp); phar->fp = NULL; + remove_fname_cache |= phar->flags & PHAR_FILE_COMPRESSION_MASK; } - if (!zend_hash_num_elements(&phar->manifest)) { - /* this is a new phar that has perhaps had an alias/metadata set, but has never - been flushed */ + if (remove_fname_cache) { if (zend_hash_str_del(&(PHAR_G(phar_fname_map)), phar->fname, phar->fname_len) != SUCCESS) { phar_destroy_phar_data(phar); } @@ -420,7 +426,7 @@ ZEND_ATTRIBUTE_NONNULL void phar_entry_remove(phar_entry_data *idata, char **err phar = idata->phar; - if (idata->internal_file->fp_refcount < 2) { + if (idata->internal_file->fp_refcount < 2 && idata->internal_file->fileinfo_lock_count == 0) { if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) { php_stream_close(idata->fp); } @@ -1149,15 +1155,9 @@ static zend_result phar_parse_pharfile(php_stream *fp, char *fname, size_t fname PHAR_GET_32(buffer, entry.uncompressed_filesize); PHAR_GET_32(buffer, entry.timestamp); - if (offset == halt_offset + manifest_len + 4) { - mydata->min_timestamp = entry.timestamp; + if (offset == halt_offset + manifest_len + 4 + || mydata->max_timestamp < entry.timestamp) { mydata->max_timestamp = entry.timestamp; - } else { - if (mydata->min_timestamp > entry.timestamp) { - mydata->min_timestamp = entry.timestamp; - } else if (mydata->max_timestamp < entry.timestamp) { - mydata->max_timestamp = entry.timestamp; - } } PHAR_GET_32(buffer, entry.compressed_filesize); @@ -1558,35 +1558,6 @@ zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias, } /* }}}*/ -static inline char *phar_strnstr(const char *buf, size_t buf_len, const char *search, size_t search_len) /* {{{ */ -{ - const char *c; - ptrdiff_t so_far = 0; - - if (buf_len < search_len) { - return NULL; - } - - c = buf - 1; - - do { - if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) { - return (char *) NULL; - } - - so_far = c - buf; - - if (so_far >= (buf_len - search_len)) { - return (char *) NULL; - } - - if (!memcmp(c, search, search_len)) { - return (char *) c; - } - } while (1); -} -/* }}} */ - /** * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify * that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS @@ -1598,14 +1569,15 @@ static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_l static const char zip_magic[] = "PK\x03\x04"; static const char gz_magic[] = "\x1f\x8b\x08"; static const char bz_magic[] = "BZh"; - char *pos, test = '\0'; + const char *pos; + char test = '\0'; int recursion_count = 3; // arbitrary limit to avoid too deep or even infinite recursion const int window_size = 1024; char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */ const zend_long readsize = sizeof(buffer) - sizeof(token); const zend_long tokenlen = sizeof(token) - 1; zend_long halt_offset; - size_t got; + ssize_t got; uint32_t compression = PHAR_FILE_COMPRESSED_NONE; if (error) { @@ -1623,7 +1595,7 @@ static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_l /* Maybe it's better to compile the file instead of just searching, */ /* but we only want the offset. So we want a .re scanner to find it. */ while(!php_stream_eof(fp)) { - if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) { + if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < tokenlen) { MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)") } @@ -1754,7 +1726,7 @@ static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_l } } - if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) { + if (got > 0 && (pos = php_memnistr(buffer, token, tokenlen, buffer + got + sizeof(token))) != NULL) { halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */ return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error); } @@ -2344,15 +2316,16 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_postprocess_file(phar_entry_data *idata, /* verify local file header */ phar_zip_file_header local; phar_zip_data_desc desc; + php_stream *stream = phar_open_archive_fp(idata->phar); - if (SUCCESS != phar_open_archive_fp(idata->phar)) { + if (!stream) { spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, ZSTR_VAL(entry->filename)); return FAILURE; } - php_stream_seek(phar_get_entrypfp(idata->internal_file), entry->header_offset, SEEK_SET); + php_stream_seek(stream, entry->header_offset, SEEK_SET); - if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file), (char *) &local, sizeof(local))) { + if (sizeof(local) != php_stream_read(stream, (char *) &local, sizeof(local))) { spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, ZSTR_VAL(entry->filename)); return FAILURE; @@ -2360,12 +2333,12 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_postprocess_file(phar_entry_data *idata, /* check for data descriptor */ if (((PHAR_ZIP_16(local.flags)) & 0x8) == 0x8) { - php_stream_seek(phar_get_entrypfp(idata->internal_file), + php_stream_seek(stream, entry->header_offset + sizeof(local) + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len) + entry->compressed_filesize, SEEK_SET); - if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file), + if (sizeof(desc) != php_stream_read(stream, (char *) &desc, sizeof(desc))) { spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local data descriptor for file \"%s\")", idata->phar->fname, ZSTR_VAL(entry->filename)); @@ -2487,8 +2460,8 @@ zend_string *phar_create_default_stub(const zend_string *php_index_str, const ze } /* }}} */ -ZEND_ATTRIBUTE_NONNULL void phar_flush(phar_archive_data *phar, char **error) { - phar_flush_ex(phar, NULL, false, error); +ZEND_ATTRIBUTE_NONNULL int phar_flush(phar_archive_data *phar, char **error) { + return phar_flush_ex(phar, NULL, false, error); } /** @@ -2496,7 +2469,7 @@ ZEND_ATTRIBUTE_NONNULL void phar_flush(phar_archive_data *phar, char **error) { * * if user_stub is NULL the default or existing stub should be used */ -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_flush_ex(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ { static const char halt_stub[] = "__HALT_COMPILER();"; @@ -2523,29 +2496,27 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze if (phar->is_persistent) { spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname); - return; + return EOF; } *error = NULL; if (!zend_hash_num_elements(&phar->manifest) && !user_stub) { - return; + return EOF; } zend_hash_clean(&phar->virtual_dirs); if (phar->is_zip) { - phar_zip_flush(phar, user_stub, is_default_stub, error); - return; + return phar_zip_flush(phar, user_stub, is_default_stub, error); } if (phar->is_tar) { - phar_tar_flush(phar, user_stub, is_default_stub, error); - return; + return phar_tar_flush(phar, user_stub, is_default_stub, error); } if (PHAR_G(readonly)) { - return; + return EOF; } if (phar->fp && !phar->is_brandnew) { @@ -2562,7 +2533,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze if (must_close_old_file) { php_stream_close(oldfile); } - return; + return EOF; } if (user_stub) { @@ -2574,7 +2545,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze } php_stream_close(newfile); spprintf(error, 0, "illegal stub for phar \"%s\" (__HALT_COMPILER(); is missing)", phar->fname); - return; + return EOF; } size_t len = pos - ZSTR_VAL(user_stub) + strlen(halt_stub); @@ -2590,7 +2561,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze } php_stream_close(newfile); spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname); - return; + return EOF; } phar->halt_offset = len + end_sequence_len; } else { @@ -2618,7 +2589,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze if (new_stub) { zend_string_free(new_stub); } - return; + return EOF; } if (new_stub) { zend_string_free(new_stub); @@ -2712,7 +2683,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze } php_stream_close(newfile); spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", ZSTR_VAL(entry->filename), phar->fname); - return; + return EOF; } newcrc32 = php_crc32_bulk_init(); php_crc32_stream_bulk_update(&newcrc32, file, entry->uncompressed_filesize); @@ -2733,7 +2704,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze entry->flags & PHAR_ENT_COMPRESSED_GZ ? "gzip" : "bzip2", ZSTR_VAL(entry->filename), phar->fname); - return; + return EOF; } /* create new file that holds the compressed versions */ @@ -3038,7 +3009,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze php_stream_close(oldfile); } php_stream_close(newfile); - return; + return EOF; } php_stream_write(newfile, digest, digest_len); @@ -3088,7 +3059,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze if (!phar->fp) { phar->fp = newfile; spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); - return; + return EOF; } if (phar->flags & PHAR_FILE_COMPRESSED_GZ) { @@ -3102,7 +3073,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze if (!filter) { spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname); - return; + return EOF; } php_stream_filter_append(&phar->fp->writefilters, filter); @@ -3130,9 +3101,10 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) { spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname); + return EOF; } - return; + return 0; cleanup: if (shared_cfp != NULL) { @@ -3144,6 +3116,8 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *phar, ze entry->header_offset = 0; } } ZEND_HASH_FOREACH_END(); + + return EOF; } /* }}} */ diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index bd3d7158c8e82..5ed213fb03e16 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -196,6 +196,7 @@ typedef struct _phar_metadata_tracker { typedef struct _phar_entry_info { /* first bytes are exactly as in file */ uint32_t uncompressed_filesize; + /* modification time */ uint32_t timestamp; uint32_t compressed_filesize; uint32_t crc32; @@ -215,6 +216,7 @@ typedef struct _phar_entry_info { php_stream *cfp; enum phar_fp_type fp_type; int fp_refcount; + unsigned int fileinfo_lock_count; char *tmp; phar_archive_data *phar; char *link; /* symbolic link to another file */ @@ -258,7 +260,6 @@ struct _phar_archive_data { /* hash of mounted directory paths */ HashTable mounted_dirs; uint32_t flags; - uint32_t min_timestamp; uint32_t max_timestamp; int refcount; php_stream *fp; @@ -439,19 +440,19 @@ php_stream *phar_get_efp(phar_entry_info *entry, bool follow_links); ZEND_ATTRIBUTE_NONNULL zend_result phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error); ZEND_ATTRIBUTE_NONNULL zend_result phar_open_entry_fp(phar_entry_info *entry, char **error, bool follow_links); phar_entry_info *phar_get_link_source(phar_entry_info *entry); -zend_result phar_open_archive_fp(phar_archive_data *phar); +php_stream *phar_open_archive_fp(phar_archive_data *phar); zend_result phar_copy_on_write(phar_archive_data **pphar); /* tar functions in tar.c */ -bool phar_is_tar(char *buf, char *fname); +bool phar_is_tar(const char *buf, const char *fname); zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data** pphar, uint32_t compression, char **error); ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_open_or_create_tar(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error); /* zip functions in zip.c */ zend_result phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data** pphar, char **error); ZEND_ATTRIBUTE_NONNULL_ARGS(1, 7, 8) zend_result phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error); -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_zip_flush(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); #ifdef PHAR_MAIN extern const php_stream_wrapper php_stream_phar_wrapper; @@ -465,10 +466,10 @@ void phar_entry_delref(phar_entry_data *idata); phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, size_t path_len, char **error, bool security); phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, size_t path_len, char dir, char **error, bool security); -ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security); +ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security, uint32_t timestamp); ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security); -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_flush_ex(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); -ZEND_ATTRIBUTE_NONNULL void phar_flush(phar_archive_data *archive, char **error); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_flush_ex(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); +ZEND_ATTRIBUTE_NONNULL int phar_flush(phar_archive_data *archive, char **error); zend_result phar_detect_phar_fname_ext(const char *filename, size_t filename_len, const char **ext_str, size_t *ext_len, int executable, int for_create, bool is_complete); zend_result phar_split_fname(const char *filename, size_t filename_len, char **arch, size_t *arch_len, char **entry, size_t *entry_len, int executable, int for_create); diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index acd9aa0cff655..17000ca3c0f17 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1341,6 +1341,44 @@ struct _phar_t { int count; }; +static zend_always_inline void phar_call_method_with_unwrap(zend_object *obj, const char *name, zval *rv) +{ + zend_call_method_with_0_params(obj, obj->ce, NULL, name, rv); + if (Z_ISREF_P(rv)) { + zend_unwrap_reference(rv); + } +} + +/* This is the same as phar_get_or_create_entry_data(), but allows overriding metadata via SplFileInfo. */ +static phar_entry_data *phar_build_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, char **error, zval *file_info) +{ + uint32_t timestamp; + + /* Expects an instance of SplFileInfo if it is an object, which is verified in phar_build(). */ + if (Z_TYPE_P(file_info) == IS_OBJECT && Z_OBJCE_P(file_info)->type == ZEND_USER_CLASS) { + zval rv; + phar_call_method_with_unwrap(Z_OBJ_P(file_info), "getMTime", &rv); + + if (UNEXPECTED(Z_TYPE(rv) != IS_LONG)) { + /* Either it's a tentative type failure, an exception happened, or the function returned false to indicate failure. */ + *error = estrdup("getMTime() must return an int"); + return NULL; + } + + /* Sanity check bounds. See GH-14141. */ + if (ZEND_LONG_UINT_OVFL(Z_LVAL(rv))) { + *error = estrdup("timestamp is limited to 32-bit"); + return NULL; + } + + timestamp = Z_LVAL(rv); + } else { + timestamp = time(NULL); + } + + return phar_get_or_create_entry_data(fname, fname_len, path, path_len, "w+b", 0, error, true, timestamp); +} + static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ { zval *value; @@ -1351,7 +1389,7 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ php_stream *fp; size_t fname_len; size_t contents_len; - char *fname, *error = NULL, *base = ZSTR_VAL(p_obj->base), *save = NULL, *temp = NULL; + char *fname = NULL, *error = NULL, *base = ZSTR_VAL(p_obj->base), *save = NULL, *temp = NULL; zend_string *opened; char *str_key; zend_class_entry *ce = p_obj->c; @@ -1411,7 +1449,6 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ goto after_open_fp; case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(value), spl_ce_SplFileInfo)) { - char *test = NULL; spl_filesystem_object *intern = PHAR_FETCH_INTERNAL_EX(value); if (!base_len) { @@ -1419,43 +1456,59 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ return ZEND_HASH_APPLY_STOP; } - switch (intern->type) { - case SPL_FS_DIR: { - zend_string *test_str = spl_filesystem_object_get_path(intern); - fname_len = spprintf(&fname, 0, "%s%c%s", ZSTR_VAL(test_str), DEFAULT_SLASH, intern->u.dir.entry.d_name); - zend_string_release_ex(test_str, /* persistent */ false); - if (php_stream_stat_path(fname, &ssb) == 0 && S_ISDIR(ssb.sb.st_mode)) { - /* ignore directories */ - efree(fname); - return ZEND_HASH_APPLY_KEEP; - } + zend_string *tmp_dir_str = NULL; - test = expand_filepath(fname, NULL); - efree(fname); + /* Take into account that SplFileObject may be overridden. + * The purpose here is to grab the path name of the file to add. */ + if (Z_OBJCE_P(value)->type == ZEND_USER_CLASS) { + zval rv; + phar_call_method_with_unwrap(Z_OBJ_P(value), "getPathname", &rv); - if (test) { - fname = test; - fname_len = strlen(fname); - } else { - zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Could not resolve file path"); - return ZEND_HASH_APPLY_STOP; + if (UNEXPECTED(Z_TYPE(rv) != IS_STRING)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "getPathname() must return a string"); + return ZEND_HASH_APPLY_STOP; + } + tmp_dir_str = Z_STR(rv); + } else { + /* Not a user class, so we can grab the data internally quickly. */ + switch (intern->type) { + case SPL_FS_DIR: { + zend_string *test_str = spl_filesystem_object_get_path(intern); + const char slash = DEFAULT_SLASH; + tmp_dir_str = zend_string_concat3( + ZSTR_VAL(test_str), ZSTR_LEN(test_str), + &slash, 1, + intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name) + ); + zend_string_release_ex(test_str, /* persistent */ false); + break; } + case SPL_FS_INFO: + case SPL_FS_FILE: + fname = expand_filepath(ZSTR_VAL(intern->file_name), NULL); + break; + } + } - save = fname; - goto phar_spl_fileinfo; + if (tmp_dir_str) { + if (php_stream_stat_path(ZSTR_VAL(tmp_dir_str), &ssb) == 0 && S_ISDIR(ssb.sb.st_mode)) { + /* ignore directories */ + zend_string_release_ex(tmp_dir_str, /* persistent */ false); + return ZEND_HASH_APPLY_KEEP; } - case SPL_FS_INFO: - case SPL_FS_FILE: - fname = expand_filepath(ZSTR_VAL(intern->file_name), NULL); - if (!fname) { - zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Could not resolve file path"); - return ZEND_HASH_APPLY_STOP; - } - fname_len = strlen(fname); - save = fname; - goto phar_spl_fileinfo; + fname = expand_filepath(ZSTR_VAL(tmp_dir_str), NULL); + zend_string_release_ex(tmp_dir_str, /* persistent */ false); } + + if (!fname) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Could not resolve file path"); + return ZEND_HASH_APPLY_STOP; + } + + fname_len = strlen(fname); + save = fname; + goto phar_spl_fileinfo; } ZEND_FALLTHROUGH; default: @@ -1586,7 +1639,7 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ return ZEND_HASH_APPLY_KEEP; } - if (!(data = phar_get_or_create_entry_data(phar_obj->archive->fname, phar_obj->archive->fname_len, str_key, str_key_len, "w+b", 0, &error, true))) { + if (!(data = phar_build_entry_data(phar_obj->archive->fname, phar_obj->archive->fname_len, str_key, str_key_len, &error, value))) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s cannot be created: %s", str_key, error); efree(error); @@ -1622,8 +1675,6 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ data->internal_file->offset_abs = data->internal_file->offset = php_stream_tell(p_obj->fp); data->fp = NULL; php_stream_copy_to_stream_ex(fp, p_obj->fp, PHP_STREAM_COPY_ALL, &contents_len); - data->internal_file->uncompressed_filesize = data->internal_file->compressed_filesize = - php_stream_tell(p_obj->fp) - data->internal_file->offset; if (php_stream_stat(fp, &ssb) != -1) { data->internal_file->flags = ssb.sb.st_mode & PHAR_ENT_PERM_MASK ; } else { @@ -3546,7 +3597,7 @@ static void phar_add_file(phar_archive_data **pphar, zend_string *file_name, con } #endif - if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, filename, filename_len, "w+b", 0, &error, true))) { + if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, filename, filename_len, "w+b", 0, &error, true, time(NULL)))) { if (error) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Entry %s does not exist and cannot be created: %s", filename, error); efree(error); @@ -3618,7 +3669,7 @@ static void phar_mkdir(phar_archive_data **pphar, zend_string *dir_name) char *error; phar_entry_data *data; - if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, ZSTR_VAL(dir_name), ZSTR_LEN(dir_name), "w+b", 2, &error, true))) { + if (!(data = phar_get_or_create_entry_data((*pphar)->fname, (*pphar)->fname_len, ZSTR_VAL(dir_name), ZSTR_LEN(dir_name), "w+b", 2, &error, true, time(NULL)))) { if (error) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Directory %s does not exist and cannot be created: %s", ZSTR_VAL(dir_name), error); efree(error); @@ -4390,7 +4441,7 @@ PHP_METHOD(PharFileInfo, __construct) entry_obj->entry = entry_info; if (!entry_info->is_persistent && !entry_info->is_temp_dir) { - ++entry_info->fp_refcount; + ++entry_info->fileinfo_lock_count; /* The phar data must exist to keep the alias locked. */ ZEND_ASSERT(!phar_data->is_persistent); ++phar_data->refcount; @@ -4435,7 +4486,7 @@ PHP_METHOD(PharFileInfo, __destruct) efree(entry); entry_obj->entry = NULL; } else if (!entry->is_persistent) { - --entry->fp_refcount; + --entry->fileinfo_lock_count; /* The entry itself still lives in the manifest, * which will either be freed here if the file info was the last reference; or freed later. */ entry_obj->entry = NULL; diff --git a/ext/phar/stream.c b/ext/phar/stream.c index 77ca7137fdf50..4bd1e85666b85 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -191,7 +191,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha /* strip leading "/" */ internal_file = estrndup(ZSTR_VAL(resource->path) + 1, ZSTR_LEN(resource->path) - 1); if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { - if (NULL == (idata = phar_get_or_create_entry_data(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), mode, 0, &error, true))) { + if (NULL == (idata = phar_get_or_create_entry_data(ZSTR_VAL(resource->host), ZSTR_LEN(resource->host), internal_file, strlen(internal_file), mode, 0, &error, true, time(NULL)))) { if (error) { php_stream_wrapper_log_error(wrapper, options, "%s", error); efree(error); @@ -209,18 +209,18 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha php_url_free(resource); efree(internal_file); - if (context && Z_TYPE(context->options) != IS_UNDEF && (pzoption = zend_hash_str_find(HASH_OF(&context->options), "phar", sizeof("phar")-1)) != NULL) { + if (context && Z_TYPE(context->options) != IS_UNDEF && (pzoption = zend_hash_str_find_ind(HASH_OF(&context->options), "phar", sizeof("phar")-1)) != NULL) { pharcontext = HASH_OF(pzoption); if (idata->internal_file->uncompressed_filesize == 0 && idata->internal_file->compressed_filesize == 0 - && (pzoption = zend_hash_str_find(pharcontext, "compress", sizeof("compress")-1)) != NULL + && (pzoption = zend_hash_str_find_ind(pharcontext, "compress", sizeof("compress")-1)) != NULL && Z_TYPE_P(pzoption) == IS_LONG && (Z_LVAL_P(pzoption) & ~PHAR_ENT_COMPRESSION_MASK) == 0 ) { idata->internal_file->flags &= ~PHAR_ENT_COMPRESSION_MASK; idata->internal_file->flags |= Z_LVAL_P(pzoption); } - if ((pzoption = zend_hash_str_find(pharcontext, "metadata", sizeof("metadata")-1)) != NULL) { + if ((pzoption = zend_hash_str_find_ind(pharcontext, "metadata", sizeof("metadata")-1)) != NULL) { phar_metadata_tracker_free(&idata->internal_file->metadata_tracker, idata->internal_file->is_persistent); metadata = pzoption; @@ -254,13 +254,13 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha } else { php_stream *stream = phar_get_pharfp(phar); if (stream == NULL) { - if (UNEXPECTED(FAILURE == phar_open_archive_fp(phar))) { + stream = phar_open_archive_fp(phar); + if (UNEXPECTED(!stream)) { php_stream_wrapper_log_error(wrapper, options, "phar error: could not reopen phar \"%s\"", ZSTR_VAL(resource->host)); efree(internal_file); php_url_free(resource); return NULL; } - stream = phar_get_pharfp(phar); } phar_entry_info *entry; @@ -424,11 +424,9 @@ static int phar_stream_seek(php_stream *stream, zend_off_t offset, int whence, z zend_off_t temp_signed = (zend_off_t) temp; if (temp_signed > data->zero + (zend_off_t) entry->uncompressed_filesize) { - *newoffset = -1; /* FIXME: this will invalidate the ZEND_ASSERT(stream->position >= 0); assertion in streams.c */ return -1; } if (temp_signed < data->zero) { - *newoffset = -1; /* FIXME: this will invalidate the ZEND_ASSERT(stream->position >= 0); assertion in streams.c */ return -1; } res = php_stream_seek(data->fp, temp_signed, SEEK_SET); @@ -467,16 +465,17 @@ static ssize_t phar_stream_write(php_stream *stream, const char *buf, size_t cou static int phar_stream_flush(php_stream *stream) /* {{{ */ { char *error; + int ret; phar_entry_data *data = (phar_entry_data *) stream->abstract; if (data->internal_file->is_modified) { data->internal_file->timestamp = time(0); - phar_flush(data->phar, &error); + ret = phar_flush(data->phar, &error); if (error) { php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS, "%s", error); efree(error); } - return EOF; + return ret; } else { return EOF; } diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 4847597cce2ea..91b6b04996d67 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -87,10 +87,10 @@ static zend_result phar_tar_octal(char *buf, uint32_t val, size_t len) /* {{{ */ } /* }}} */ -static uint32_t phar_tar_checksum(char *buf, size_t len) /* {{{ */ +static uint32_t phar_tar_checksum(const char *buf, size_t len) /* {{{ */ { uint32_t sum = 0; - char *end = buf + len; + const char *end = buf + len; while (buf != end) { sum += (unsigned char)*buf; @@ -100,7 +100,7 @@ static uint32_t phar_tar_checksum(char *buf, size_t len) /* {{{ */ } /* }}} */ -bool phar_is_tar(char *buf, char *fname) /* {{{ */ +bool phar_is_tar(const char *buf, const char *fname) /* {{{ */ { tar_header *header = (tar_header *) buf; uint32_t checksum = phar_tar_number(header->checksum, sizeof(header->checksum)); @@ -726,7 +726,7 @@ static int phar_tar_writeheaders_int(phar_entry_info *entry, void *argument) /* } if (entry->is_deleted) { - if (entry->fp_refcount <= 0) { + if (entry->fp_refcount <= 0 && entry->fileinfo_lock_count == 0) { return ZEND_HASH_APPLY_REMOVE; } else { /* we can't delete this in-memory until it is closed */ @@ -960,7 +960,7 @@ ZEND_ATTRIBUTE_NONNULL static int phar_tar_setupmetadata(zval *zv, void *argumen } /* }}} */ -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ { static const char newstub[] = "is_persistent) { spprintf(error, 0, "internal error: attempt to flush cached tar-based phar \"%s\"", phar->fname); - return; + return EOF; } if (phar->is_data) { @@ -997,12 +997,12 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { *error = estrdup("phar error: unable to create temporary file"); - return; + return EOF; } if (phar->alias_len != php_stream_write(entry.fp, phar->alias, phar->alias_len)) { spprintf(error, 0, "unable to set alias in tar-based phar \"%s\"", phar->fname); php_stream_close(entry.fp); - return; + return EOF; } entry.uncompressed_filesize = phar->alias_len; @@ -1021,7 +1021,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z if (pos == NULL) { spprintf(error, 0, "illegal stub for tar-based phar \"%s\"", phar->fname); - return; + return EOF; } size_t len = pos - ZSTR_VAL(user_stub) + strlen(halt_stub); @@ -1031,7 +1031,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { *error = estrdup("phar error: unable to create temporary file"); - return; + return EOF; } entry.uncompressed_filesize = len + end_sequence_len; @@ -1041,7 +1041,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z ) { spprintf(error, 0, "unable to create stub from string in new tar-based phar \"%s\"", phar->fname); php_stream_close(entry.fp); - return; + return EOF; } entry.filename = ZSTR_INIT_LITERAL(".phar/stub.php", false); @@ -1051,13 +1051,13 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { *error = estrdup("phar error: unable to create temporary file"); - return; + return EOF; } if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) { php_stream_close(entry.fp); spprintf(error, 0, "unable to %s stub in%star-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); - return; + return EOF; } entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1; @@ -1069,7 +1069,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z php_stream_close(entry.fp); zend_string_efree(entry.filename); spprintf(error, 0, "unable to create stub in tar-based phar \"%s\"", phar->fname); - return; + return EOF; } } else { php_stream_close(entry.fp); @@ -1095,7 +1095,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z if (must_close_old_file) { php_stream_close(oldfile); } - return; + return EOF; } pass.old = oldfile; @@ -1111,7 +1111,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z if (must_close_old_file) { php_stream_close(oldfile); } - return; + return EOF; } } else { phar_entry_info newentry = {0}; @@ -1127,7 +1127,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z if (must_close_old_file) { php_stream_close(oldfile); } - return; + return EOF; } if (ZEND_HASH_APPLY_KEEP != phar_tar_setmetadata(&phar->metadata_tracker, mentry, error)) { @@ -1135,7 +1135,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z if (must_close_old_file) { php_stream_close(oldfile); } - return; + return EOF; } } } @@ -1149,7 +1149,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z /* on error in the hash iterator above, error is set */ php_stream_close(newfile); - return; + return EOF; } zend_hash_apply_with_argument(&phar->manifest, phar_tar_writeheaders, (void *) &pass); @@ -1161,7 +1161,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z /* on error in the hash iterator above, error is set */ php_stream_close(newfile); - return; + return EOF; } /* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */ @@ -1176,7 +1176,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z } php_stream_close(newfile); - return; + return EOF; } entry.fp = php_stream_fopen_tmpfile(); @@ -1188,7 +1188,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z php_stream_close(oldfile); } php_stream_close(newfile); - return; + return EOF; } #ifdef WORDS_BIGENDIAN # define PHAR_SET_32(destination, source) do { \ @@ -1212,7 +1212,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z php_stream_close(oldfile); } php_stream_close(newfile); - return; + return EOF; } ALLOCA_FLAG(use_heap); @@ -1229,7 +1229,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z } /* error is set by writeheaders */ php_stream_close(newfile); - return; + return EOF; } } /* signature */ @@ -1264,7 +1264,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z if (!phar->fp) { phar->fp = newfile; spprintf(error, 0, "unable to open new phar \"%s\" for writing", phar->fname); - return; + return EOF; } if (phar->flags & PHAR_FILE_COMPRESSED_GZ) { @@ -1286,7 +1286,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL); php_stream_close(newfile); spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname); - return; + return EOF; } php_stream_filter_append(&phar->fp->writefilters, filter); @@ -1313,5 +1313,6 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_tar_flush(phar_archive_data *phar, z php_stream_close(newfile); } } + return 0; } /* }}} */ diff --git a/ext/phar/tests/022.phpt b/ext/phar/tests/022.phpt index 5363a65be9423..c484c4d3c06dc 100644 --- a/ext/phar/tests/022.phpt +++ b/ext/phar/tests/022.phpt @@ -80,28 +80,28 @@ int(1) fseek($fp, -1, SEEK_END)int(0) int(6) fseek($fp, -8, SEEK_END)int(-1) -bool(false) +int(6) fseek($fp, -7, SEEK_END)int(0) int(0) fseek($fp, 0, SEEK_END)int(0) int(7) fseek($fp, 1, SEEK_END)int(-1) -bool(false) +int(7) fseek($fp, -8, SEEK_END)int(-1) -bool(false) +int(7) fseek($fp, 6)int(0) int(6) fseek($fp, 8)int(-1) -bool(false) +int(6) fseek($fp, -1)int(-1) -bool(false) +int(6) next int(4) fseek($fp, -5, SEEK_CUR)int(-1) -bool(false) +int(4) int(4) fseek($fp, 5, SEEK_CUR)int(-1) -bool(false) +int(4) int(4) fseek($fp, -4, SEEK_CUR)int(0) int(0) diff --git a/ext/phar/tests/SplFileInfo_openFile_write.phpt b/ext/phar/tests/SplFileInfo_openFile_write.phpt new file mode 100644 index 0000000000000..f63baf5c7ad10 --- /dev/null +++ b/ext/phar/tests/SplFileInfo_openFile_write.phpt @@ -0,0 +1,31 @@ +--TEST-- +SplFileInfo::openFile() in write mode +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +--FILE-- +addFromString('test', 'contents'); +var_dump($phar['test']->openFile('w')); + +?> +--CLEAN-- + +--EXPECTF-- +object(SplFileObject)#%d (%d) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%stest" + ["fileName":"SplFileInfo":private]=> + string(4) "test" + ["openMode":"SplFileObject":private]=> + string(1) "w" + ["delimiter":"SplFileObject":private]=> + string(1) "," + ["enclosure":"SplFileObject":private]=> + string(1) """ +} diff --git a/ext/phar/tests/bug74154.phpt b/ext/phar/tests/bug74154.phpt new file mode 100644 index 0000000000000..ab3836ce87d46 --- /dev/null +++ b/ext/phar/tests/bug74154.phpt @@ -0,0 +1,41 @@ +--TEST-- +Bug #74154 (Phar extractTo creates empty files) +--EXTENSIONS-- +phar +zlib +--FILE-- +buildFromDirectory($dir); + +$compPhar = $phar->compress(Phar::GZ); +unset($phar); //make sure that test.tar is closed +unlink(__DIR__.'/bug74154.tar'); +unset($compPhar); //make sure that test.tar.gz is closed +$extractingPhar = new PharData(__DIR__.'/bug74154.tar.gz'); +$extractingPhar->extractTo($dir.'_out'); + +var_dump(file_get_contents($dir.'_out/1.txt')); +var_dump(file_get_contents($dir.'_out/2.txt')); + +?> +--CLEAN-- + +--EXPECT-- +string(64) "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" +string(64) "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii" diff --git a/ext/phar/tests/buildFromIterator_user_overrides/getMTime.phpt b/ext/phar/tests/buildFromIterator_user_overrides/getMTime.phpt new file mode 100644 index 0000000000000..eefe352a0cbb6 --- /dev/null +++ b/ext/phar/tests/buildFromIterator_user_overrides/getMTime.phpt @@ -0,0 +1,81 @@ +--TEST-- +buildFromIterator with user overrides - getMTime() +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +phar.require_hash=0 +--CREDITS-- +Arne Blankerts +N. Dossche +--FILE-- +getPathname() . " ]\n"; + return new MySplFileInfo(parent::current()->getPathname()); + } +} + +$workdir = __DIR__.'/getMTime'; +mkdir($workdir . '/content', recursive: true); +file_put_contents($workdir . '/content/hello.txt', "Hello world."); + +$phar = new \Phar($workdir . '/test.phar'); +$phar->startBuffering(); +$phar->buildFromIterator( + new RecursiveIteratorIterator( + new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) + ), + $workdir +); +$phar->stopBuffering(); + + +$result = new \Phar($workdir . '/test.phar', 0, 'test.phar'); +var_dump($result['content/hello.txt']); +var_dump($result['content/hello.txt']->getATime()); +var_dump($result['content/hello.txt']->getMTime()); +var_dump($result['content/hello.txt']->getCTime()); + +?> +--CLEAN-- + +--EXPECTF-- +[ Found: %shello.txt ] +[MTime] +object(PharFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%shello.txt" + ["fileName":"SplFileInfo":private]=> + string(%d) "hello.txt" +} +int(123) +int(123) +int(123) diff --git a/ext/phar/tests/buildFromIterator_user_overrides/getMTime_byRef.phpt b/ext/phar/tests/buildFromIterator_user_overrides/getMTime_byRef.phpt new file mode 100644 index 0000000000000..a7f81709a34e3 --- /dev/null +++ b/ext/phar/tests/buildFromIterator_user_overrides/getMTime_byRef.phpt @@ -0,0 +1,70 @@ +--TEST-- +buildFromIterator with user overrides - getMTime() by ref +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +phar.require_hash=0 +--CREDITS-- +Arne Blankerts +N. Dossche +--FILE-- +getPathname() . " ]\n"; + return new MySplFileInfo(parent::current()->getPathname()); + } +} + +$workdir = __DIR__.'/getMTime_byRef'; +mkdir($workdir . '/content', recursive: true); +file_put_contents($workdir . '/content/hello.txt', "Hello world."); + +$phar = new \Phar($workdir . '/test.phar'); +$phar->startBuffering(); +$phar->buildFromIterator( + new RecursiveIteratorIterator( + new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) + ), + $workdir +); +$phar->stopBuffering(); + + +$result = new \Phar($workdir . '/test.phar', 0, 'test.phar'); +var_dump($result['content/hello.txt']); +var_dump($result['content/hello.txt']->getATime()); +var_dump($result['content/hello.txt']->getMTime()); +var_dump($result['content/hello.txt']->getCTime()); + +?> +--CLEAN-- + +--EXPECTF-- +[ Found: %shello.txt ] +[MTime] +object(PharFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%shello.txt" + ["fileName":"SplFileInfo":private]=> + string(%d) "hello.txt" +} +int(123) +int(123) +int(123) diff --git a/ext/phar/tests/buildFromIterator_user_overrides/getMTime_errors.phpt b/ext/phar/tests/buildFromIterator_user_overrides/getMTime_errors.phpt new file mode 100644 index 0000000000000..f43a7a496a762 --- /dev/null +++ b/ext/phar/tests/buildFromIterator_user_overrides/getMTime_errors.phpt @@ -0,0 +1,117 @@ +--TEST-- +buildFromIterator with user overrides - errors in getMTime() +--EXTENSIONS-- +phar +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--CREDITS-- +Arne Blankerts +N. Dossche +--FILE-- +getPathname() . " ]\n"; + if ($counter === 1) { + return new MySplFileInfo1(parent::current()->getPathname()); + } else if ($counter === 2) { + return new MySplFileInfo2(parent::current()->getPathname()); + } else if ($counter === 3) { + return new MySplFileInfo3(parent::current()->getPathname()); + } else if ($counter === 4) { + return new MySplFileInfo4(parent::current()->getPathname()); + } + } +} + +$workdir = __DIR__.'/getMTime_errors'; +mkdir($workdir . '/content', recursive: true); +file_put_contents($workdir . '/content/hello.txt', "Hello world."); + +for ($i = 0; $i < 4; $i++) { + echo "--- Iteration $i ---\n"; + try { + $phar = new \Phar($workdir . "/test$i.phar"); + $phar->startBuffering(); + $phar->buildFromIterator( + new RecursiveIteratorIterator( + new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) + ), + $workdir + ); + $phar->stopBuffering(); + } catch (Throwable $e) { + echo $e->getMessage(), "\n"; + if ($previous = $e->getPrevious()) { + echo "Previous: ", $previous->getMessage(), "\n"; + } + } +} + +?> +--CLEAN-- + +--EXPECTF-- +--- Iteration 0 --- +[ Found: %shello.txt ] +[MTime] +Entry content%chello.txt cannot be created: timestamp is limited to 32-bit +--- Iteration 1 --- +[ Found: %shello.txt ] +[MTime] +Entry content%chello.txt cannot be created: getMTime() must return an int +--- Iteration 2 --- +[ Found: %shello.txt ] +[MTime] +Entry content%chello.txt cannot be created: getMTime() must return an int +Previous: Throwing an exception inside getMTime() +--- Iteration 3 --- +[ Found: %shello.txt ] +[MTime] +Entry content%chello.txt cannot be created: getMTime() must return an int diff --git a/ext/phar/tests/buildFromIterator_user_overrides/getPathname.phpt b/ext/phar/tests/buildFromIterator_user_overrides/getPathname.phpt new file mode 100644 index 0000000000000..144eed1d874a6 --- /dev/null +++ b/ext/phar/tests/buildFromIterator_user_overrides/getPathname.phpt @@ -0,0 +1,67 @@ +--TEST-- +buildFromIterator with user overrides - getPathname() +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +phar.require_hash=0 +--CREDITS-- +Arne Blankerts +N. Dossche +--FILE-- +getPathname() . " ]\n"; + return new MyGlobIterator(parent::current()->getPath() . '/*'); + } +} + +$workdir = __DIR__.'/getPathname'; +mkdir($workdir . '/content', recursive: true); +file_put_contents($workdir . '/content/hello1.txt', "Hello world 1."); +file_put_contents($workdir . '/content/hello2.txt', "Hello world 2."); + +$phar = new \Phar($workdir . "/test.phar"); +$phar->startBuffering(); +$phar->buildFromIterator( + new RecursiveIteratorIterator( + new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) + ), + $workdir +); +$phar->stopBuffering(); + +$result = new \Phar($workdir . '/test.phar', 0, 'test.phar'); +var_dump(isset($result['content/hello1.txt'])); +var_dump(isset($result['content/hello2.txt'])); + +?> +--CLEAN-- + +--EXPECTF-- +[ Found: %shello%d.txt ] +[getPathname] +string(%d) "%shello1.txt" +[ Found: %shello%d.txt ] +[getPathname] +string(%d) "%shello1.txt" +bool(false) +bool(true) diff --git a/ext/phar/tests/buildFromIterator_user_overrides/getPathname_byRef.phpt b/ext/phar/tests/buildFromIterator_user_overrides/getPathname_byRef.phpt new file mode 100644 index 0000000000000..0ae2946ce1ade --- /dev/null +++ b/ext/phar/tests/buildFromIterator_user_overrides/getPathname_byRef.phpt @@ -0,0 +1,58 @@ +--TEST-- +buildFromIterator with user overrides - getPathname() by ref +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +phar.require_hash=0 +--CREDITS-- +Arne Blankerts +N. Dossche +--FILE-- +getPathname() . " ]\n"; + return new MyGlobIterator(parent::current()->getPath() . '/*'); + } +} + +$workdir = __DIR__.'/getPathname_byRef'; +mkdir($workdir . '/content', recursive: true); +file_put_contents($workdir . '/content/hello.txt', "Hello world 1."); + +$phar = new \Phar($workdir . "/test.phar"); +$phar->startBuffering(); +$phar->buildFromIterator( + new RecursiveIteratorIterator( + new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) + ), + $workdir +); +$phar->stopBuffering(); + +$result = new \Phar($workdir . '/test.phar', 0, 'test.phar'); +var_dump(isset($result['content/hello.txt'])); + +?> +--CLEAN-- + +--EXPECTF-- +[ Found: %scontent%chello.txt ] +[getPathname] +bool(true) diff --git a/ext/phar/tests/buildFromIterator_user_overrides/getPathname_exception.phpt b/ext/phar/tests/buildFromIterator_user_overrides/getPathname_exception.phpt new file mode 100644 index 0000000000000..86b66050a973f --- /dev/null +++ b/ext/phar/tests/buildFromIterator_user_overrides/getPathname_exception.phpt @@ -0,0 +1,63 @@ +--TEST-- +buildFromIterator with user overrides - exception in getPathname() +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +phar.require_hash=0 +--CREDITS-- +Arne Blankerts +N. Dossche +--FILE-- +getPathname() . " ]\n"; + return new MyGlobIterator(parent::current()->getPath() . '/*'); + } +} + +$workdir = __DIR__.'/getPathname_exception'; +mkdir($workdir . '/content', recursive: true); +file_put_contents($workdir . '/content/hello.txt', "Hello world."); + +$phar = new \Phar($workdir . "/test.phar"); +$phar->startBuffering(); +try { + $phar->buildFromIterator( + new RecursiveIteratorIterator( + new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) + ), + $workdir + ); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; + if ($previous = $e->getPrevious()) { + echo "Previous: ", $previous->getMessage(), "\n"; + } +} +$phar->stopBuffering(); + +?> +--CLEAN-- + +--EXPECTF-- +[ Found: %shello.txt ] +[getPathname] +string(%d) "%shello.txt" +getPathname() must return a string +Previous: exception in getPathname() diff --git a/ext/phar/tests/buildFromIterator_user_overrides/getPathname_wrong_type.phpt b/ext/phar/tests/buildFromIterator_user_overrides/getPathname_wrong_type.phpt new file mode 100644 index 0000000000000..dfb3fb5f2c550 --- /dev/null +++ b/ext/phar/tests/buildFromIterator_user_overrides/getPathname_wrong_type.phpt @@ -0,0 +1,58 @@ +--TEST-- +buildFromIterator with user overrides - wrong return type in getPathname() +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +phar.require_hash=0 +--CREDITS-- +Arne Blankerts +N. Dossche +--FILE-- +getPathname() . " ]\n"; + return new MyGlobIterator(parent::current()->getPath() . '/*'); + } +} + +$workdir = __DIR__.'/getPathname_wrong_type'; +mkdir($workdir . '/content', recursive: true); +file_put_contents($workdir . '/content/hello.txt', "Hello world."); + +$phar = new \Phar($workdir . "/test.phar"); +$phar->startBuffering(); +try { + $phar->buildFromIterator( + new RecursiveIteratorIterator( + new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) + ), + $workdir + ); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +$phar->stopBuffering(); + +?> +--CLEAN-- + +--EXPECTF-- +[ Found: %scontent%chello.txt ] +[getPathname] +getPathname() must return a string diff --git a/ext/phar/tests/fflush_phar_file_report_success.phpt b/ext/phar/tests/fflush_phar_file_report_success.phpt new file mode 100644 index 0000000000000..615f4e58e5678 --- /dev/null +++ b/ext/phar/tests/fflush_phar_file_report_success.phpt @@ -0,0 +1,25 @@ +--TEST-- +fflush() on phar file should report success +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +--FILE-- +addFromString('test', 'contents'); +unset($phar); + +$f = fopen('phar://' . __DIR__.'/fflush_phar_file_report_success.phar/test', 'w'); +var_dump(fflush($f)); +var_dump(fclose($f)); + +?> +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/phar/tests/files/gh20442.phar b/ext/phar/tests/files/gh20442.phar new file mode 100644 index 0000000000000..26fac67ede587 Binary files /dev/null and b/ext/phar/tests/files/gh20442.phar differ diff --git a/ext/phar/tests/fseek_outside_bounds.phpt b/ext/phar/tests/fseek_outside_bounds.phpt new file mode 100644 index 0000000000000..0a35abb360d5f --- /dev/null +++ b/ext/phar/tests/fseek_outside_bounds.phpt @@ -0,0 +1,26 @@ +--TEST-- +Assertion failure when fseeking outside of bounds of phar file +--EXTENSIONS-- +phar +--INI-- +phar.require_hash=0 +--FILE-- +setInfoClass('SplFileObject'); +$f = $phar['a.php']; +var_dump($f->fseek(1, SEEK_SET)); +var_dump($f->fseek(999999, SEEK_SET)); +var_dump($f->fseek(999999, SEEK_CUR)); +var_dump($f->ftell()); +var_dump($f->fseek(1, SEEK_CUR)); +var_dump($f->fread(3)); +?> +--EXPECT-- +int(0) +int(-1) +int(-1) +int(1) +int(0) +string(3) "php" diff --git a/ext/phar/tests/gh17808.phpt b/ext/phar/tests/gh17808.phpt index 03e54ff264bfa..a5c13a5405e24 100644 --- a/ext/phar/tests/gh17808.phpt +++ b/ext/phar/tests/gh17808.phpt @@ -5,18 +5,26 @@ phar zlib --FILE-- getContent())); -unlink("$file"); +unlink($file); var_dump($file->getATime()); ?> +--CLEAN-- + --EXPECTF-- -string(%d) "phar://%spackage.xml" +object(PharFileInfo)#%d (%d) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%spackage.xml" + ["fileName":"SplFileInfo":private]=> + string(11) "package.xml" +} int(6747) - -Warning: unlink(): phar error: "package.xml" in phar %s, has open file pointers, cannot unlink in %s on line %d int(33188) diff --git a/ext/phar/tests/gh20442.phpt b/ext/phar/tests/gh20442.phpt new file mode 100644 index 0000000000000..e6862f3d33dbc --- /dev/null +++ b/ext/phar/tests/gh20442.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-20442 (Phar does not respect case-insensitiveness of __halt_compiler() when reading stub) +--EXTENSIONS-- +phar +--FILE-- +count()); +var_dump($phar->getStub()); + +?> +--EXPECT-- +int(1) +string(50) " +" diff --git a/ext/phar/tests/gh20732.phpt b/ext/phar/tests/gh20732.phpt new file mode 100644 index 0000000000000..b938d16d42caf --- /dev/null +++ b/ext/phar/tests/gh20732.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-20732 (Phar::LoadPhar undefined behavior when loading directory) +--EXTENSIONS-- +phar +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +%r(internal corruption of phar "%s" \(truncated entry\)|unable to open phar for reading ".")%r diff --git a/ext/phar/tests/tar/bug70417.phpt b/ext/phar/tests/tar/bug70417.phpt index 504d7e1e387b6..7bb6bbafbcfa4 100644 --- a/ext/phar/tests/tar/bug70417.phpt +++ b/ext/phar/tests/tar/bug70417.phpt @@ -10,10 +10,11 @@ $filename = __DIR__ . '/bug70417.tar'; $resBefore = count(get_resources()); $arch = new PharData($filename); $arch->addFromString('foo', 'bar'); +$arch->addFromString('foo2', 'baz'); $arch->compress(Phar::GZ); unset($arch); $resAfter = count(get_resources()); -var_dump($resBefore === $resAfter); +var_dump($resAfter - $resBefore); ?> --CLEAN-- --EXPECT-- -bool(true) +int(0) diff --git a/ext/phar/util.c b/ext/phar/util.c index 60607006f6712..fdadc4d9b6bf7 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -107,11 +107,12 @@ php_stream *phar_get_efp(phar_entry_info *entry, bool follow_links) /* {{{ */ } if (phar_get_fp_type(entry) == PHAR_FP) { - if (!phar_get_entrypfp(entry)) { + php_stream *stream = phar_get_entrypfp(entry); + if (!stream) { /* re-open just in time for cases where our refcount reached 0 on the phar archive */ - phar_open_archive_fp(entry->phar); + stream = phar_open_archive_fp(entry->phar); } - return phar_get_entrypfp(entry); + return stream; } else if (phar_get_fp_type(entry) == PHAR_UFP) { return phar_get_entrypufp(entry); } else if (entry->fp_type == PHAR_MOD) { @@ -606,7 +607,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, ch /** * Create a new dummy file slot within a writeable phar for a newly created file */ -ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, bool security, uint32_t timestamp) /* {{{ */ { phar_archive_data *phar; phar_entry_info *entry, etemp; @@ -668,7 +669,7 @@ ZEND_ATTRIBUTE_NONNULL phar_entry_data *phar_get_or_create_entry_data(char *fnam phar_add_virtual_dirs(phar, path, path_len); etemp.is_modified = 1; - etemp.timestamp = time(0); + etemp.timestamp = timestamp; etemp.is_crc_checked = 1; etemp.phar = phar; etemp.filename = zend_string_init(path, path_len, false); @@ -708,24 +709,23 @@ static inline void phar_set_pharfp(phar_archive_data *phar, php_stream *fp) PHAR_G(cached_fp)[phar->phar_pos].fp = fp; } -/* initialize a phar_archive_data's read-only fp for existing phar data */ -zend_result phar_open_archive_fp(phar_archive_data *phar) /* {{{ */ +/* Initialize a phar_archive_data's read-only fp for existing phar data. + * The stream is owned by the `phar` object and must not be closed manually. */ +php_stream *phar_open_archive_fp(phar_archive_data *phar) /* {{{ */ { - if (phar_get_pharfp(phar)) { - return SUCCESS; + php_stream *stream = phar_get_pharfp(phar); + if (stream) { + return stream; } if (php_check_open_basedir(phar->fname)) { - return FAILURE; + return NULL; } - phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL)); - - if (!phar_get_pharfp(phar)) { - return FAILURE; - } + stream = php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, NULL); + phar_set_pharfp(phar, stream); - return SUCCESS; + return stream; } /* }}} */ @@ -829,7 +829,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_open_entry_fp(phar_entry_info *entry, ch } if (!phar_get_pharfp(phar)) { - if (FAILURE == phar_open_archive_fp(phar)) { + if (!phar_open_archive_fp(phar)) { spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname); return FAILURE; } @@ -1881,7 +1881,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar if (!EVP_SignInit(md_ctx, mdtype)) { EVP_PKEY_free(key); - EVP_MD_CTX_free(md_ctx); + EVP_MD_CTX_destroy(md_ctx); efree(sigbuf); spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname); return FAILURE; @@ -1890,7 +1890,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) { if (!EVP_SignUpdate(md_ctx, buf, sig_len)) { EVP_PKEY_free(key); - EVP_MD_CTX_free(md_ctx); + EVP_MD_CTX_destroy(md_ctx); efree(sigbuf); spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname); return FAILURE; @@ -1899,7 +1899,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar if (!EVP_SignFinal (md_ctx, sigbuf, &siglen, key)) { EVP_PKEY_free(key); - EVP_MD_CTX_free(md_ctx); + EVP_MD_CTX_destroy(md_ctx); efree(sigbuf); spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname); return FAILURE; @@ -1907,7 +1907,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar sigbuf[siglen] = '\0'; EVP_PKEY_free(key); - EVP_MD_CTX_free(md_ctx); + EVP_MD_CTX_destroy(md_ctx); #else size_t siglen; sigbuf = NULL; diff --git a/ext/phar/zip.c b/ext/phar/zip.c index e38708e1337da..9e71a33ccf98a 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -851,7 +851,7 @@ static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg) /* {{{ } if (entry->is_deleted) { - if (entry->fp_refcount <= 0) { + if (entry->fp_refcount <= 0 && entry->fileinfo_lock_count == 0) { return ZEND_HASH_APPLY_REMOVE; } else { /* we can't delete this in-memory until it is closed */ @@ -1224,7 +1224,7 @@ static zend_result phar_zip_applysignature(phar_archive_data *phar, struct _phar } /* }}} */ -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */ { static const char newstub[] = "is_persistent) { spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname); - return; + return EOF; } if (phar->is_data) { @@ -1256,12 +1256,12 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { *error = estrdup("phar error: unable to create temporary file"); - return; + return EOF; } if (phar->alias_len != php_stream_write(entry.fp, phar->alias, phar->alias_len)) { php_stream_close(entry.fp); spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); - return; + return EOF; } entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len; @@ -1275,7 +1275,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z /* register alias */ if (phar->alias_len) { if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error)) { - return; + return EOF; } } @@ -1285,7 +1285,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z if (pos == NULL) { spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname); - return; + return EOF; } size_t len = pos - ZSTR_VAL(user_stub) + strlen(halt_stub); @@ -1295,7 +1295,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { *error = estrdup("phar error: unable to create temporary file"); - return; + return EOF; } entry.uncompressed_filesize = len + end_sequence_len; @@ -1305,7 +1305,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z ) { spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname); php_stream_close(entry.fp); - return; + return EOF; } entry.filename = ZSTR_INIT_LITERAL(".phar/stub.php", false); @@ -1316,12 +1316,12 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z entry.fp = php_stream_fopen_tmpfile(); if (entry.fp == NULL) { *error = estrdup("phar error: unable to create temporary file"); - return; + return EOF; } if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) { php_stream_close(entry.fp); spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); - return; + return EOF; } entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1; @@ -1333,7 +1333,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z php_stream_close(entry.fp); zend_string_efree(entry.filename); spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname); - return; + return EOF; } } else { php_stream_close(entry.fp); @@ -1366,7 +1366,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z php_stream_close(oldfile); } spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname); - return; + return EOF; } pass.centralfp = php_stream_fopen_tmpfile(); @@ -1404,7 +1404,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z if (must_close_old_file) { php_stream_close(oldfile); } - return; + return EOF; } /* save zip */ @@ -1471,7 +1471,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z } phar->fp = pass.filefp; spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); - return; + return EOF; } php_stream_rewind(pass.filefp); php_stream_copy_to_stream_ex(pass.filefp, phar->fp, PHP_STREAM_COPY_ALL, NULL); @@ -1482,5 +1482,6 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) void phar_zip_flush(phar_archive_data *phar, z if (must_close_old_file) { php_stream_close(oldfile); } + return 0; } /* }}} */ diff --git a/ext/posix/posix.c b/ext/posix/posix.c index ff878b3acfc1b..b7acf8c751270 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -699,7 +699,8 @@ static void php_posix_group_to_array(struct group *g, zval *array_group) /* {{{ for (count = 0;; count++) { /* gr_mem entries may be misaligned on macos. */ char *gr_mem; - memcpy(&gr_mem, &g->gr_mem[count], sizeof(char *)); + char *entry = (char *)g->gr_mem + (count * sizeof (char *)); + memcpy(&gr_mem, entry, sizeof(char *)); if (!gr_mem) { break; } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a86ce16feb407..64e79651913fb 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -763,11 +763,6 @@ static void format_default_value(smart_str *str, zval *value) { } } -static inline bool has_internal_arg_info(const zend_function *fptr) { - return fptr->type == ZEND_INTERNAL_FUNCTION - && !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO); -} - /* {{{ _parameter_string */ static void _parameter_string(smart_str *str, zend_function *fptr, struct _zend_arg_info *arg_info, uint32_t offset, bool required, char* indent) { @@ -789,17 +784,15 @@ static void _parameter_string(smart_str *str, zend_function *fptr, struct _zend_ if (ZEND_ARG_IS_VARIADIC(arg_info)) { smart_str_appends(str, "..."); } - smart_str_append_printf(str, "$%s", has_internal_arg_info(fptr) - ? ((zend_internal_arg_info*)arg_info)->name : ZSTR_VAL(arg_info->name)); + smart_str_append_printf(str, "$%s", ZSTR_VAL(arg_info->name)); if (!required && !ZEND_ARG_IS_VARIADIC(arg_info)) { if (fptr->type == ZEND_INTERNAL_FUNCTION) { smart_str_appends(str, " = "); /* TODO: We don't have a way to fetch the default value for an internal function * with userland arg info. */ - if (has_internal_arg_info(fptr) - && ((zend_internal_arg_info*)arg_info)->default_value) { - smart_str_appends(str, ((zend_internal_arg_info*)arg_info)->default_value); + if (arg_info->default_value) { + smart_str_append(str, arg_info->default_value); } else { smart_str_appends(str, ""); } @@ -1432,13 +1425,7 @@ static void reflection_extension_factory_ex(zval *object, zend_module_entry *mod static void reflection_extension_factory(zval *object, const char *name_str) { size_t name_len = strlen(name_str); - zend_string *lcname; - struct _zend_module_entry *module; - - lcname = zend_string_alloc(name_len, 0); - zend_str_tolower_copy(ZSTR_VAL(lcname), name_str, name_len); - module = zend_hash_find_ptr(&module_registry, lcname); - zend_string_efree(lcname); + struct _zend_module_entry *module = zend_hash_str_find_ptr_lc(&module_registry, name_str, name_len); if (!module) { return; } @@ -1469,11 +1456,7 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje } prop_name = reflection_prop_name(object); - if (has_internal_arg_info(fptr)) { - ZVAL_STRING(prop_name, ((zend_internal_arg_info*)arg_info)->name); - } else { - ZVAL_STR_COPY(prop_name, arg_info->name); - } + ZVAL_STR_COPY(prop_name, arg_info->name); } /* }}} */ @@ -1659,8 +1642,7 @@ static zend_result get_parameter_default(zval *result, parameter_reference *para /* We don't have a way to determine the default value for this case right now. */ return FAILURE; } - return zend_get_default_from_internal_arg_info( - result, (zend_internal_arg_info *) param->arg_info); + return zend_get_default_from_internal_arg_info(result, param->arg_info); } else { zval *default_value = get_default_from_recv((zend_op_array *) param->fptr, param->offset); if (!default_value) { @@ -2141,16 +2123,10 @@ ZEND_METHOD(ReflectionFunction, invoke) zend_call_known_fcc(&fcc, &retval, num_args, params, named_params); - if (Z_TYPE(retval) == IS_UNDEF && !EG(exception)) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name)); - RETURN_THROWS(); - } - if (Z_ISREF(retval)) { zend_unwrap_reference(&retval); } - ZVAL_COPY_VALUE(return_value, &retval); + RETURN_COPY_VALUE(&retval); } /* }}} */ @@ -2180,16 +2156,10 @@ ZEND_METHOD(ReflectionFunction, invokeArgs) zend_call_known_fcc(&fcc, &retval, /* num_params */ 0, /* params */ NULL, params); - if (Z_TYPE(retval) == IS_UNDEF && !EG(exception)) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name)); - RETURN_THROWS(); - } - if (Z_ISREF(retval)) { zend_unwrap_reference(&retval); } - ZVAL_COPY_VALUE(return_value, &retval); + RETURN_COPY_VALUE(&retval); } /* }}} */ @@ -2608,22 +2578,11 @@ ZEND_METHOD(ReflectionParameter, __construct) uint32_t i; position = -1; - if (has_internal_arg_info(fptr)) { - for (i = 0; i < num_args; i++) { - if (arg_info[i].name) { - if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, ZSTR_VAL(arg_name)) == 0) { - position = i; - break; - } - } - } - } else { - for (i = 0; i < num_args; i++) { - if (arg_info[i].name) { - if (zend_string_equals(arg_name, arg_info[i].name)) { - position = i; - break; - } + for (i = 0; i < num_args; i++) { + if (arg_info[i].name) { + if (zend_string_equals(arg_name, arg_info[i].name)) { + position = i; + break; } } } @@ -2664,11 +2623,7 @@ ZEND_METHOD(ReflectionParameter, __construct) prop_name = reflection_prop_name(object); zval_ptr_dtor(prop_name); - if (has_internal_arg_info(fptr)) { - ZVAL_STRING(prop_name, ((zend_internal_arg_info*)arg_info)[position].name); - } else { - ZVAL_STR_COPY(prop_name, arg_info[position].name); - } + ZVAL_STR_COPY(prop_name, arg_info[position].name); return; failure: @@ -2707,11 +2662,7 @@ ZEND_METHOD(ReflectionParameter, getName) ZEND_PARSE_PARAMETERS_NONE(); GET_REFLECTION_OBJECT_PTR(param); - if (has_internal_arg_info(param->fptr)) { - RETURN_STRING(((zend_internal_arg_info *) param->arg_info)->name); - } else { - RETURN_STR_COPY(param->arg_info->name); - } + RETURN_STR_COPY(param->arg_info->name); } /* }}} */ @@ -2965,8 +2916,7 @@ ZEND_METHOD(ReflectionParameter, isDefaultValueAvailable) GET_REFLECTION_OBJECT_PTR(param); if (param->fptr->type == ZEND_INTERNAL_FUNCTION) { - RETURN_BOOL(!(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO) - && ((zend_internal_arg_info*) (param->arg_info))->default_value); + RETURN_BOOL(param->arg_info->default_value); } else { zval *default_value = get_default_from_recv((zend_op_array *)param->fptr, param->offset); RETURN_BOOL(default_value != NULL); @@ -3496,16 +3446,10 @@ static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic) callback = _copy_function(mptr); zend_call_known_function(callback, (object ? Z_OBJ_P(object) : NULL), intern->ce, &retval, argc, params, named_params); - if (Z_TYPE(retval) == IS_UNDEF && !EG(exception)) { - zend_throw_exception_ex(reflection_exception_ptr, 0, - "Invocation of method %s::%s() failed", ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name)); - RETURN_THROWS(); - } - if (Z_ISREF(retval)) { zend_unwrap_reference(&retval); } - ZVAL_COPY_VALUE(return_value, &retval); + RETURN_COPY_VALUE(&retval); } /* }}} */ @@ -6661,28 +6605,21 @@ ZEND_METHOD(ReflectionProperty, isFinal) ZEND_METHOD(ReflectionExtension, __construct) { zval *object; - char *lcname; reflection_object *intern; zend_module_entry *module; - char *name_str; - size_t name_len; - ALLOCA_FLAG(use_heap) + zend_string *name_str; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name_str) == FAILURE) { RETURN_THROWS(); } object = ZEND_THIS; intern = Z_REFLECTION_P(object); - lcname = do_alloca(name_len + 1, use_heap); - zend_str_tolower_copy(lcname, name_str, name_len); - if ((module = zend_hash_str_find_ptr(&module_registry, lcname, name_len)) == NULL) { - free_alloca(lcname, use_heap); + if ((module = zend_hash_find_ptr_lc(&module_registry, name_str)) == NULL) { zend_throw_exception_ex(reflection_exception_ptr, 0, - "Extension \"%s\" does not exist", name_str); + "Extension \"%s\" does not exist", ZSTR_VAL(name_str)); RETURN_THROWS(); } - free_alloca(lcname, use_heap); zval *prop_name = reflection_prop_name(object); zval_ptr_dtor(prop_name); ZVAL_STRING(prop_name, module->name); @@ -7175,7 +7112,7 @@ ZEND_METHOD(ReflectionReference, getId) RETURN_THROWS(); } - REFLECTION_G(key_initialized) = 1; + REFLECTION_G(key_initialized) = true; } /* SHA1(ref || key) to avoid directly exposing memory addresses. */ @@ -8033,7 +7970,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflection_property_hook_type_ptr = register_class_PropertyHookType(); - REFLECTION_G(key_initialized) = 0; + REFLECTION_G(key_initialized) = false; return SUCCESS; } /* }}} */ diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index be372ac729912..91c70d6ffdb1a 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -226,7 +226,7 @@ public function getPrototype(): ReflectionMethod {} public function hasPrototype(): bool {} /** @tentative-return-type */ - #[\Deprecated(since: '8.5', message: "as it has no effect")] + #[\Deprecated(since: '8.5', message: "as it has no effect since PHP 8.1")] public function setAccessible(bool $accessible): void {} } @@ -543,7 +543,7 @@ public function getDeclaringClass(): ReflectionClass {} public function getDocComment(): string|false {} /** @tentative-return-type */ - #[\Deprecated(since: '8.5', message: "as it has no effect")] + #[\Deprecated(since: '8.5', message: "as it has no effect since PHP 8.1")] public function setAccessible(bool $accessible): void {} /** @tentative-return-type */ diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index d1f1ffed0cfb6..62275423b3caf 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 576229f7a0c4afd2f8902db6ce87daa51256965e */ + * Stub hash: fd645a0b0db39d94ca25b39ffe64d7f05bad6bea */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0) @@ -1497,7 +1497,7 @@ static zend_class_entry *register_class_ReflectionMethod(zend_class_entry *class zend_attribute *attribute_Deprecated_func_setaccessible_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setaccessible", sizeof("setaccessible") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2); ZVAL_STR(&attribute_Deprecated_func_setaccessible_0->args[0].value, ZSTR_KNOWN(ZEND_STR_8_DOT_5)); attribute_Deprecated_func_setaccessible_0->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE); - zend_string *attribute_Deprecated_func_setaccessible_0_arg1_str = zend_string_init("as it has no effect", strlen("as it has no effect"), 1); + zend_string *attribute_Deprecated_func_setaccessible_0_arg1_str = zend_string_init("as it has no effect since PHP 8.1", strlen("as it has no effect since PHP 8.1"), 1); ZVAL_STR(&attribute_Deprecated_func_setaccessible_0->args[1].value, attribute_Deprecated_func_setaccessible_0_arg1_str); attribute_Deprecated_func_setaccessible_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); @@ -1662,7 +1662,7 @@ static zend_class_entry *register_class_ReflectionProperty(zend_class_entry *cla zend_attribute *attribute_Deprecated_func_setaccessible_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setaccessible", sizeof("setaccessible") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2); ZVAL_STR(&attribute_Deprecated_func_setaccessible_0->args[0].value, ZSTR_KNOWN(ZEND_STR_8_DOT_5)); attribute_Deprecated_func_setaccessible_0->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE); - zend_string *attribute_Deprecated_func_setaccessible_0_arg1_str = zend_string_init("as it has no effect", strlen("as it has no effect"), 1); + zend_string *attribute_Deprecated_func_setaccessible_0_arg1_str = zend_string_init("as it has no effect since PHP 8.1", strlen("as it has no effect since PHP 8.1"), 1); ZVAL_STR(&attribute_Deprecated_func_setaccessible_0->args[1].value, attribute_Deprecated_func_setaccessible_0_arg1_str); attribute_Deprecated_func_setaccessible_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); diff --git a/ext/reflection/tests/ReflectionFunction__toString_bound_variables.phpt b/ext/reflection/tests/ReflectionFunction__toString_bound_variables.phpt new file mode 100644 index 0000000000000..142e661361496 --- /dev/null +++ b/ext/reflection/tests/ReflectionFunction__toString_bound_variables.phpt @@ -0,0 +1,32 @@ +--TEST-- +ReflectionFunction::__toString() with bound variables +--FILE-- + 0; + +$rf = new ReflectionFunction($closure_without_bounds); +echo (string) $rf; + +$global = ""; +$closure_with_bounds = function() use($global) { + static $counter = 0; + return $counter++; +}; + +$rf = new ReflectionFunction($closure_with_bounds); +echo (string) $rf; + +?> +--EXPECTF-- +Closure [ function {closure:%s:%d} ] { + @@ %sReflectionFunction__toString_bound_variables.php 3 - 3 +} +Closure [ function {closure:%s:%d} ] { + @@ %sReflectionFunction__toString_bound_variables.php 9 - 12 + + - Bound Variables [2] { + Variable #0 [ $global ] + Variable #1 [ $counter ] + } +} diff --git a/ext/reflection/tests/ReflectionMethod_setAccessible.phpt b/ext/reflection/tests/ReflectionMethod_setAccessible.phpt index ba4864d28ed86..be720a4044c78 100644 --- a/ext/reflection/tests/ReflectionMethod_setAccessible.phpt +++ b/ext/reflection/tests/ReflectionMethod_setAccessible.phpt @@ -47,13 +47,13 @@ A::aProtected A::aProtectedStatic A::aProtectedStatic -Deprecated: Method ReflectionMethod::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionMethod::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d -Deprecated: Method ReflectionMethod::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionMethod::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d -Deprecated: Method ReflectionMethod::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionMethod::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d -Deprecated: Method ReflectionMethod::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionMethod::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d A::aPrivate A::aPrivate A::aPrivateStatic diff --git a/ext/reflection/tests/ReflectionProperty_setAccessible.phpt b/ext/reflection/tests/ReflectionProperty_setAccessible.phpt index b63ab38c15981..5ccc1366060b0 100644 --- a/ext/reflection/tests/ReflectionProperty_setAccessible.phpt +++ b/ext/reflection/tests/ReflectionProperty_setAccessible.phpt @@ -96,13 +96,13 @@ string(1) "f" string(1) "g" string(1) "h" -Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d -Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d -Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d -Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d string(1) "e" string(1) "f" string(1) "g" @@ -120,11 +120,11 @@ string(1) "e" string(1) "f" string(1) "g" -Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d -Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d -Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect in %s on line %d +Deprecated: Method ReflectionProperty::setAccessible() is deprecated since 8.5, as it has no effect since PHP 8.1 in %s on line %d string(1) "e" string(1) "f" string(1) "g" diff --git a/ext/session/config.w32 b/ext/session/config.w32 index 825bc8b61d291..40f9f78a313ed 100644 --- a/ext/session/config.w32 +++ b/ext/session/config.w32 @@ -3,10 +3,10 @@ ARG_ENABLE("session", "session support", "yes"); if (PHP_SESSION == "yes") { - EXTENSION("session", "mod_user_class.c session.c mod_files.c mod_mm.c mod_user.c", false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); + EXTENSION("session", "mod_user_class.c session.c mod_files.c mod_user.c", false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); ADD_EXTENSION_DEP('session', 'date'); // https://bugs.php.net/53141 ADD_EXTENSION_DEP('session', 'spl', true); AC_DEFINE("HAVE_PHP_SESSION", 1, "Define to 1 if the PHP extension 'session' is available."); - PHP_INSTALL_HEADERS("ext/session", "mod_mm.h php_session.h mod_files.h mod_user.h"); + PHP_INSTALL_HEADERS("ext/session", "php_session.h mod_files.h mod_user.h"); } diff --git a/ext/session/mod_mm.c b/ext/session/mod_mm.c index 962e19666a2a3..76de6035a315c 100644 --- a/ext/session/mod_mm.c +++ b/ext/session/mod_mm.c @@ -264,7 +264,7 @@ static void ps_mm_destroy(ps_mm *data) PHP_MINIT_FUNCTION(ps_mm) { - size_t save_path_len = strlen(PS(save_path)); + size_t save_path_len = ZSTR_LEN(PS(save_path)); size_t mod_name_len = strlen(sapi_module.name); size_t euid_len; char *ps_mm_path, euid[30]; @@ -284,8 +284,8 @@ PHP_MINIT_FUNCTION(ps_mm) /* Directory + '/' + File + Module Name + Effective UID + \0 */ ps_mm_path = emalloc(save_path_len + 1 + (sizeof(PS_MM_FILE) - 1) + mod_name_len + euid_len + 1); - memcpy(ps_mm_path, PS(save_path), save_path_len); - if (save_path_len && PS(save_path)[save_path_len - 1] != DEFAULT_SLASH) { + memcpy(ps_mm_path, ZSTR_VAL(PS(save_path)), save_path_len); + if (save_path_len && ZSTR_VAL(PS(save_path))[save_path_len - 1] != DEFAULT_SLASH) { ps_mm_path[save_path_len] = DEFAULT_SLASH; save_path_len++; } diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index d3248bb812086..16a8aaa22fc3a 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -1413,14 +1413,10 @@ PHP_METHOD(SimpleXMLElement, asXML) static inline void sxe_add_namespace_name_raw(zval *return_value, const char *prefix, const char *href) { - zend_string *key = zend_string_init(prefix, strlen(prefix), 0); - zval zv; - - if (!zend_hash_exists(Z_ARRVAL_P(return_value), key)) { - ZVAL_STRING(&zv, href); - zend_hash_add_new(Z_ARRVAL_P(return_value), key, &zv); + zval *zv = zend_hash_str_lookup(Z_ARRVAL_P(return_value), prefix, strlen(prefix)); + if (Z_ISNULL_P(zv)) { + ZVAL_STRING(zv, href); } - zend_string_release_ex(key, 0); } static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */ diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index 48305ad627256..63c0093eb05c8 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -1014,8 +1014,7 @@ int make_http_soap_request( char *eqpos = strstr(cookie, "="); char *sempos = strstr(cookie, ";"); if (eqpos != NULL && (sempos == NULL || sempos > eqpos)) { - smart_str name = {0}; - int cookie_len; + size_t cookie_len; zval zcookie; if (sempos != NULL) { @@ -1024,8 +1023,7 @@ int make_http_soap_request( cookie_len = strlen(cookie)-(eqpos-cookie)-1; } - smart_str_appendl(&name, cookie, eqpos - cookie); - smart_str_0(&name); + zend_string *name = zend_string_init(cookie, eqpos - cookie, false); array_init(&zcookie); add_index_stringl(&zcookie, 0, eqpos + 1, cookie_len); @@ -1063,8 +1061,8 @@ int make_http_soap_request( GC_ADDREF(uri->host); } - zend_symtable_update(Z_ARRVAL_P(cookies), name.s, &zcookie); - smart_str_free(&name); + zend_symtable_update(Z_ARRVAL_P(cookies), name, &zcookie); + zend_string_release_ex(name, false); } cookie_itt = cookie_itt + cookie_len; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 23e74606e996a..471b2d622d98a 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -2835,12 +2835,12 @@ PHP_METHOD(SoapClient, __setCookie) zval *cookies = Z_CLIENT_COOKIES_P(ZEND_THIS); SEPARATE_ARRAY(cookies); if (val == NULL) { - zend_hash_del(Z_ARRVAL_P(cookies), name); + zend_symtable_del(Z_ARRVAL_P(cookies), name); } else { zval zcookie; array_init(&zcookie); add_index_str(&zcookie, 0, zend_string_copy(val)); - zend_hash_update(Z_ARRVAL_P(cookies), name, &zcookie); + zend_symtable_update(Z_ARRVAL_P(cookies), name, &zcookie); } } /* }}} */ diff --git a/ext/soap/tests/soap_set_cookie.phpt b/ext/soap/tests/soap_set_cookie.phpt new file mode 100644 index 0000000000000..a23aa18bb4b75 --- /dev/null +++ b/ext/soap/tests/soap_set_cookie.phpt @@ -0,0 +1,22 @@ +--TEST-- +SoapClient::__setCookie with numeric keys +--EXTENSIONS-- +soap +--FILE-- + 'mo:http://www.w3.org/', 'location' => 'http://example.com')); +$client->__setCookie("123", "456"); +var_dump($client->__getCookies()); +$client->__setCookie("123", NULL); +var_dump($client->__getCookies()); +?> +--EXPECT-- +array(1) { + [123]=> + array(1) { + [0]=> + string(3) "456" + } +} +array(0) { +} diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 4a9332498c3cc..b76818830fc06 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -1773,7 +1773,7 @@ PHP_FUNCTION(socket_sendto) RETURN_THROWS(); } - memset(&sll, 0, sizeof(sll)); + memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = port; @@ -2130,6 +2130,28 @@ PHP_FUNCTION(socket_set_option) } #endif +#if defined(TCP_USER_TIMEOUT) + case TCP_USER_TIMEOUT: { + zend_long timeout = zval_get_long(arg4); + + // TCP_USER_TIMEOUT unsigned int + if (timeout < 0 || timeout > UINT_MAX) { + zend_argument_value_error(4, "must be of between 0 and %u", UINT_MAX); + RETURN_THROWS(); + } + + unsigned int val = (unsigned int)timeout; + optlen = sizeof(val); + opt_ptr = &val; + if (setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen) != 0) { + PHP_SOCKET_ERROR(php_sock, "Unable to set socket option", errno); + RETURN_FALSE; + } + + RETURN_TRUE; + } +#endif + } } diff --git a/ext/sockets/sockets.stub.php b/ext/sockets/sockets.stub.php index 3df9b598a1e8f..04fb702807e0a 100644 --- a/ext/sockets/sockets.stub.php +++ b/ext/sockets/sockets.stub.php @@ -602,6 +602,13 @@ */ const TCP_SYNCNT = UNKNOWN; #endif +#ifdef TCP_USER_TIMEOUT +/** + * @var int + * @cvalue TCP_USER_TIMEOUT + */ +const TCP_USER_TIMEOUT = UNKNOWN; +#endif #ifdef SO_ZEROCOPY /** * @var int diff --git a/ext/sockets/sockets_arginfo.h b/ext/sockets/sockets_arginfo.h index edfc344ff8cc0..0145d01252881 100644 --- a/ext/sockets/sockets_arginfo.h +++ b/ext/sockets/sockets_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: f754368e28f6e45bf3a63a403e49f5659c29d2c6 */ + * Stub hash: 038081ca7bb98076d4b559d93b4c9300acc47160 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_socket_select, 0, 4, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1) @@ -527,6 +527,9 @@ static void register_sockets_symbols(int module_number) #if defined(TCP_SYNCNT) REGISTER_LONG_CONSTANT("TCP_SYNCNT", TCP_SYNCNT, CONST_PERSISTENT); #endif +#if defined(TCP_USER_TIMEOUT) + REGISTER_LONG_CONSTANT("TCP_USER_TIMEOUT", TCP_USER_TIMEOUT, CONST_PERSISTENT); +#endif #if defined(SO_ZEROCOPY) REGISTER_LONG_CONSTANT("SO_ZEROCOPY", SO_ZEROCOPY, CONST_PERSISTENT); #endif diff --git a/ext/sockets/tests/socket_setoption_tcpusertimeout_32bit.phpt b/ext/sockets/tests/socket_setoption_tcpusertimeout_32bit.phpt new file mode 100644 index 0000000000000..3f12120e54d89 --- /dev/null +++ b/ext/sockets/tests/socket_setoption_tcpusertimeout_32bit.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test if socket_set_option() works, option:TCP_USER_TIMEOUT +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +$timeout = 200; +$retval_2 = socket_set_option($socket, SOL_TCP, TCP_USER_TIMEOUT, $timeout); +$retval_3 = socket_get_option($socket, SOL_TCP, TCP_USER_TIMEOUT); +var_dump($retval_2); +var_dump($retval_3 === $timeout); +socket_close($socket); +?> +--EXPECTF-- +socket_setopt(): Argument #4 ($value) must be of between 0 and %d +bool(true) +bool(true) diff --git a/ext/sockets/tests/socket_setoption_tcpusertimeout_64bit.phpt b/ext/sockets/tests/socket_setoption_tcpusertimeout_64bit.phpt new file mode 100644 index 0000000000000..8dbb7f80e48b1 --- /dev/null +++ b/ext/sockets/tests/socket_setoption_tcpusertimeout_64bit.phpt @@ -0,0 +1,41 @@ +--TEST-- +Test if socket_set_option() works, option:TCP_USER_TIMEOUT +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +try { + socket_setopt($socket, SOL_TCP, TCP_USER_TIMEOUT, PHP_INT_MAX); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +$timeout = 200; +$retval_2 = socket_set_option($socket, SOL_TCP, TCP_USER_TIMEOUT, $timeout); +$retval_3 = socket_get_option($socket, SOL_TCP, TCP_USER_TIMEOUT); +var_dump($retval_2); +var_dump($retval_3 === $timeout); +socket_close($socket); +?> +--EXPECTF-- +socket_setopt(): Argument #4 ($value) must be of between 0 and %d +socket_setopt(): Argument #4 ($value) must be of between 0 and %d +bool(true) +bool(true) diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 6de7a6d6635af..0acfcbc5c16d0 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -216,9 +216,7 @@ PHP_FUNCTION(class_uses) /* {{{ Return an array containing the names of all classes and interfaces defined in SPL */ PHP_FUNCTION(spl_classes) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); array_init(return_value); @@ -619,9 +617,7 @@ PHP_FUNCTION(spl_autoload_functions) { autoload_func_info *alfi; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); array_init(return_value); if (spl_autoload_functions) { diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index d430513ca11fa..3d6870a7ee953 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -753,9 +753,7 @@ PHP_METHOD(ArrayObject, getArrayCopy) zval *object = ZEND_THIS; spl_array_object *intern = Z_SPLARRAY_P(object); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_ARR(zend_array_dup(spl_array_get_hash_table(intern))); } /* }}} */ @@ -1086,9 +1084,7 @@ PHP_METHOD(ArrayObject, getIteratorClass) zval *object = ZEND_THIS; spl_array_object *intern = Z_SPLARRAY_P(object); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_string_addref(intern->ce_get_iterator->name); RETURN_STR(intern->ce_get_iterator->name); @@ -1101,9 +1097,7 @@ PHP_METHOD(ArrayObject, getFlags) zval *object = ZEND_THIS; spl_array_object *intern = Z_SPLARRAY_P(object); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK); } @@ -1150,9 +1144,7 @@ PHP_METHOD(ArrayObject, getIterator) zval *object = ZEND_THIS; spl_array_object *intern = Z_SPLARRAY_P(object); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_OBJ(spl_array_object_new_ex(intern->ce_get_iterator, Z_OBJ_P(object), 0)); } @@ -1203,9 +1195,7 @@ PHP_METHOD(ArrayObject, count) { spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(spl_array_object_count_elements_helper(intern)); } /* }}} */ @@ -1305,9 +1295,7 @@ PHP_METHOD(ArrayObject, serialize) php_serialize_data_t var_hash; smart_str buf = {0}; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); PHP_VAR_SERIALIZE_INIT(var_hash); @@ -1453,9 +1441,7 @@ PHP_METHOD(ArrayObject, __serialize) spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS); zval tmp; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); array_init(return_value); @@ -1559,9 +1545,7 @@ PHP_METHOD(ArrayObject, __unserialize) /* {{{ */ PHP_METHOD(ArrayObject, __debugInfo) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_ARR(spl_array_get_debug_info(Z_OBJ_P(ZEND_THIS))); } /* }}} */ @@ -1739,9 +1723,7 @@ PHP_METHOD(ArrayIterator, rewind) zval *object = ZEND_THIS; spl_array_object *intern = Z_SPLARRAY_P(object); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_array_rewind(intern); } @@ -1783,9 +1765,7 @@ PHP_METHOD(ArrayIterator, current) zval *entry; HashTable *aht = spl_array_get_hash_table(intern); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) { RETURN_NULL(); @@ -1812,9 +1792,7 @@ void spl_array_iterator_key(zval *object, zval *return_value) /* {{{ */ /* {{{ Return current array key */ PHP_METHOD(ArrayIterator, key) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_array_iterator_key(ZEND_THIS, return_value); } /* }}} */ @@ -1826,9 +1804,7 @@ PHP_METHOD(ArrayIterator, next) spl_array_object *intern = Z_SPLARRAY_P(object); HashTable *aht = spl_array_get_hash_table(intern); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_array_next_ex(intern, aht); } @@ -1841,9 +1817,7 @@ PHP_METHOD(ArrayIterator, valid) spl_array_object *intern = Z_SPLARRAY_P(object); HashTable *aht = spl_array_get_hash_table(intern); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_BOOL(zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS); } @@ -1858,9 +1832,7 @@ PHP_METHOD(RecursiveArrayIterator, hasChildren) spl_array_object *intern = Z_SPLARRAY_P(object); HashTable *aht = spl_array_get_hash_table(intern); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) { RETURN_FALSE; @@ -1898,9 +1870,7 @@ PHP_METHOD(RecursiveArrayIterator, getChildren) spl_array_object *intern = Z_SPLARRAY_P(object); HashTable *aht = spl_array_get_hash_table(intern); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) { RETURN_NULL(); diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index a769d627a54cd..86e4b11334c81 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -292,6 +292,11 @@ static void spl_filesystem_dir_open(spl_filesystem_object* intern, zend_string * intern->type = SPL_FS_DIR; intern->u.dir.dirp = php_stream_opendir(ZSTR_VAL(path), REPORT_ERRORS, FG(default_context)); + if (intern->u.dir.dirp) { + /* we prevent potential UAF with conflicting explicit fclose(), relying on the object destructor for this */ + intern->u.dir.dirp->flags |= PHP_STREAM_FLAG_NO_FCLOSE; + } + if (ZSTR_LEN(path) > 1 && IS_SLASH_AT(ZSTR_VAL(path), ZSTR_LEN(path)-1)) { intern->path = zend_string_init(ZSTR_VAL(path), ZSTR_LEN(path)-1, 0); } else { @@ -409,7 +414,7 @@ static zend_object *spl_filesystem_object_clone(zend_object *old_object) spl_filesystem_dir_open(intern, source->path); /* read until we hit the position in which we were before */ bool skip_dots = SPL_HAS_FLAG(source->flags, SPL_FILE_DIR_SKIPDOTS); - int index; + zend_long index; for (index = 0; index < source->u.dir.index; ++index) { do { spl_filesystem_dir_read(intern); @@ -480,9 +485,8 @@ static spl_filesystem_object *spl_filesystem_object_create_info(zend_string *fil RETVAL_OBJ(&intern->std); if (ce->constructor->common.scope != spl_ce_SplFileInfo) { - ZVAL_STR_COPY(&arg1, file_path); + ZVAL_STR(&arg1, file_path); zend_call_method_with_1_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1); - zval_ptr_dtor(&arg1); } else { spl_filesystem_info_set_filename(intern, file_path); } @@ -520,9 +524,8 @@ static spl_filesystem_object *spl_filesystem_object_create_type(int num_args, sp } if (ce->constructor->common.scope != spl_ce_SplFileInfo) { - ZVAL_STR_COPY(&arg1, source->file_name); + ZVAL_STR(&arg1, source->file_name); zend_call_method_with_1_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1); - zval_ptr_dtor(&arg1); } else { intern->file_name = zend_string_copy(source->file_name); intern->path = spl_filesystem_object_get_path(source); @@ -549,11 +552,9 @@ static spl_filesystem_object *spl_filesystem_object_create_type(int num_args, sp } if (ce->constructor->common.scope != spl_ce_SplFileObject) { - ZVAL_STR_COPY(&arg1, source->file_name); - ZVAL_STR_COPY(&arg2, open_mode); + ZVAL_STR(&arg1, source->file_name); + ZVAL_STR(&arg2, open_mode); zend_call_method_with_2_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1, &arg2); - zval_ptr_dtor(&arg1); - zval_ptr_dtor(&arg2); } else { intern->file_name = source->file_name; intern->path = spl_filesystem_object_get_path(source); @@ -737,9 +738,7 @@ PHP_METHOD(DirectoryIterator, rewind) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern); intern->u.dir.index = 0; @@ -753,9 +752,7 @@ PHP_METHOD(DirectoryIterator, key) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern); RETURN_LONG(intern->u.dir.index); @@ -765,9 +762,7 @@ PHP_METHOD(DirectoryIterator, key) /* {{{ Return this (needed for Iterator interface) */ PHP_METHOD(DirectoryIterator, current) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS))); RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); @@ -780,9 +775,7 @@ PHP_METHOD(DirectoryIterator, next) spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); bool skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern); intern->u.dir.index++; @@ -831,9 +824,7 @@ PHP_METHOD(DirectoryIterator, valid) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern); RETURN_BOOL(intern->u.dir.entry.d_name[0] != '\0'); @@ -846,9 +837,7 @@ PHP_METHOD(SplFileInfo, getPath) spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); zend_string *path; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); path = spl_filesystem_object_get_path(intern); if (path) { @@ -865,9 +854,7 @@ PHP_METHOD(SplFileInfo, getFilename) spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); zend_string *path; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (!intern->file_name) { zend_throw_error(NULL, "Object not initialized"); @@ -894,9 +881,7 @@ PHP_METHOD(DirectoryIterator, getFilename) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern); RETURN_STRING(intern->u.dir.entry.d_name); @@ -914,9 +899,7 @@ PHP_METHOD(SplFileInfo, getExtension) size_t idx; zend_string *ret; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (!intern->file_name) { zend_throw_error(NULL, "Object not initialized"); @@ -959,9 +942,7 @@ PHP_METHOD(DirectoryIterator, getExtension) size_t idx; zend_string *fname; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern); fname = php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), NULL, 0); @@ -1039,9 +1020,7 @@ PHP_METHOD(SplFileInfo, getPathname) spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); zend_string *path; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); path = spl_filesystem_object_get_pathname(intern); if (path) { RETURN_STR_COPY(path); @@ -1056,9 +1035,7 @@ PHP_METHOD(FilesystemIterator, key) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (SPL_FILE_DIR_KEY(intern, SPL_FILE_DIR_KEY_AS_FILENAME)) { RETURN_STRING(intern->u.dir.entry.d_name); @@ -1076,9 +1053,7 @@ PHP_METHOD(FilesystemIterator, current) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) { if (spl_filesystem_object_get_file_name(intern) == FAILURE) { @@ -1101,9 +1076,7 @@ PHP_METHOD(DirectoryIterator, isDot) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern); RETURN_BOOL(spl_filesystem_is_dot(intern->u.dir.entry.d_name)); @@ -1137,9 +1110,7 @@ PHP_METHOD(SplFileInfo, func_name) \ { \ spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); \ zend_error_handling error_handling; \ - if (zend_parse_parameters_none() == FAILURE) { \ - RETURN_THROWS(); \ - } \ + ZEND_PARSE_PARAMETERS_NONE(); \ if (spl_filesystem_object_get_file_name(intern) == FAILURE) { \ RETURN_THROWS(); \ } \ @@ -1216,9 +1187,7 @@ PHP_METHOD(SplFileInfo, getLinkTarget) ssize_t ret; char buff[MAXPATHLEN]; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (intern->file_name == NULL) { if (spl_filesystem_object_get_file_name(intern) == FAILURE) { @@ -1263,9 +1232,7 @@ PHP_METHOD(SplFileInfo, getRealPath) char buff[MAXPATHLEN]; char *filename; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (intern->type == SPL_FS_DIR && !intern->file_name && intern->u.dir.entry.d_name[0]) { if (spl_filesystem_object_get_file_name(intern) == FAILURE) { @@ -1375,9 +1342,7 @@ PHP_METHOD(SplFileInfo, getPathInfo) /* {{{ */ PHP_METHOD(SplFileInfo, __debugInfo) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_ARR(spl_filesystem_object_get_debug_info(Z_OBJ_P(ZEND_THIS))); } /* }}} */ @@ -1385,9 +1350,7 @@ PHP_METHOD(SplFileInfo, __debugInfo) /* {{{ */ PHP_METHOD(SplFileInfo, _bad_state_ex) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_throw_error(NULL, "The parent constructor was not called: the object is in an invalid state"); RETURN_THROWS(); } @@ -1406,9 +1369,7 @@ PHP_METHOD(FilesystemIterator, rewind) spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); bool skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern->u.dir.index = 0; if (intern->u.dir.dirp) { @@ -1425,9 +1386,7 @@ PHP_METHOD(FilesystemIterator, getFlags) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK | SPL_FILE_DIR_OTHERS_MASK)); } /* }}} */ @@ -1491,9 +1450,7 @@ PHP_METHOD(RecursiveDirectoryIterator, getChildren) spl_filesystem_object *subdir; char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (spl_filesystem_object_get_file_name(intern) == FAILURE) { RETURN_THROWS(); @@ -1534,9 +1491,7 @@ PHP_METHOD(RecursiveDirectoryIterator, getSubPath) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (intern->u.dir.sub_path) { RETURN_STR_COPY(intern->u.dir.sub_path); @@ -1552,9 +1507,7 @@ PHP_METHOD(RecursiveDirectoryIterator, getSubPathname) spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (intern->u.dir.sub_path) { RETURN_NEW_STR(strpprintf(0, "%s%c%s", ZSTR_VAL(intern->u.dir.sub_path), slash, intern->u.dir.entry.d_name)); @@ -1583,9 +1536,7 @@ PHP_METHOD(GlobIterator, count) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (EXPECTED(spl_intern_is_glob(intern))) { RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL)); @@ -2100,9 +2051,7 @@ PHP_METHOD(SplFileObject, rewind) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_filesystem_file_rewind(ZEND_THIS, intern); } /* }}} */ @@ -2112,9 +2061,7 @@ PHP_METHOD(SplFileObject, eof) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); @@ -2126,9 +2073,7 @@ PHP_METHOD(SplFileObject, valid) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { RETURN_BOOL(intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval)); @@ -2144,9 +2089,7 @@ PHP_METHOD(SplFileObject, fgets) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); @@ -2161,9 +2104,7 @@ PHP_METHOD(SplFileObject, current) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); @@ -2185,9 +2126,7 @@ PHP_METHOD(SplFileObject, key) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); /* Do not read the next line to support correct counting with fgetc() if (!intern->u.file.current_line) { @@ -2201,9 +2140,7 @@ PHP_METHOD(SplFileObject, next) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_filesystem_file_free_line(intern); if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { @@ -2227,9 +2164,7 @@ PHP_METHOD(SplFileObject, getFlags) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->flags & SPL_FILE_OBJECT_MASK); } /* }}} */ @@ -2258,9 +2193,7 @@ PHP_METHOD(SplFileObject, getMaxLineLen) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG((zend_long)intern->u.file.max_line_len); } /* }}} */ @@ -2268,9 +2201,7 @@ PHP_METHOD(SplFileObject, getMaxLineLen) /* {{{ Return false */ PHP_METHOD(SplFileObject, hasChildren) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_FALSE; } /* }}} */ @@ -2278,9 +2209,7 @@ PHP_METHOD(SplFileObject, hasChildren) /* {{{ Read NULL */ PHP_METHOD(SplFileObject, getChildren) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); /* return NULL */ } /* }}} */ @@ -2431,9 +2360,7 @@ PHP_METHOD(SplFileObject, getCsvControl) spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); char delimiter[2], enclosure[2], escape[2]; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); array_init(return_value); @@ -2476,9 +2403,7 @@ PHP_METHOD(SplFileObject, fflush) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); @@ -2491,9 +2416,7 @@ PHP_METHOD(SplFileObject, ftell) spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); zend_long ret; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); @@ -2527,9 +2450,7 @@ PHP_METHOD(SplFileObject, fgetc) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); @@ -2552,9 +2473,7 @@ PHP_METHOD(SplFileObject, fpassthru) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); @@ -2583,7 +2502,8 @@ PHP_METHOD(SplFileObject, fscanf) int result = php_sscanf_internal(ZSTR_VAL(intern->u.file.current_line), ZSTR_VAL(format_str), (int)num_varargs, varargs, 0, return_value); if (SCAN_ERROR_WRONG_PARAM_COUNT == result) { - WRONG_PARAM_COUNT; + zend_wrong_param_count(); + RETURN_THROWS(); } } /* }}} */ @@ -2654,9 +2574,7 @@ PHP_METHOD(SplFileObject, fstat) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); @@ -2722,9 +2640,7 @@ PHP_METHOD(SplFileObject, seek) PHP_METHOD(SplFileObject, __toString) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); diff --git a/ext/spl/spl_directory.h b/ext/spl/spl_directory.h index 549dfb1dc4d0f..a2d1d8d854750 100644 --- a/ext/spl/spl_directory.h +++ b/ext/spl/spl_directory.h @@ -62,7 +62,7 @@ struct _spl_filesystem_object { struct { php_stream *dirp; zend_string *sub_path; - int index; + zend_long index; zend_function *func_rewind; zend_function *func_next; zend_function *func_valid; diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 9401af3ae00de..867f492fab16d 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -511,9 +511,7 @@ PHP_METHOD(SplDoublyLinkedList, pop) { spl_dllist_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLDLLIST_P(ZEND_THIS); spl_ptr_llist_pop(intern->llist, return_value); @@ -530,9 +528,7 @@ PHP_METHOD(SplDoublyLinkedList, shift) { spl_dllist_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLDLLIST_P(ZEND_THIS); spl_ptr_llist_shift(intern->llist, return_value); @@ -550,9 +546,7 @@ PHP_METHOD(SplDoublyLinkedList, top) zval *value; spl_dllist_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLDLLIST_P(ZEND_THIS); value = spl_ptr_llist_last(intern->llist); @@ -572,9 +566,7 @@ PHP_METHOD(SplDoublyLinkedList, bottom) zval *value; spl_dllist_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLDLLIST_P(ZEND_THIS); value = spl_ptr_llist_first(intern->llist); @@ -594,9 +586,7 @@ PHP_METHOD(SplDoublyLinkedList, count) zend_long count; spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); count = spl_ptr_llist_count(intern->llist); RETURN_LONG(count); @@ -608,9 +598,7 @@ PHP_METHOD(SplDoublyLinkedList, isEmpty) { zend_long count; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_dllist_object_count_elements(Z_OBJ_P(ZEND_THIS), &count); RETURN_BOOL(count == 0); @@ -646,9 +634,7 @@ PHP_METHOD(SplDoublyLinkedList, getIteratorMode) { spl_dllist_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLDLLIST_P(ZEND_THIS); @@ -914,9 +900,7 @@ PHP_METHOD(SplDoublyLinkedList, key) { spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->traverse_position); } @@ -927,9 +911,7 @@ PHP_METHOD(SplDoublyLinkedList, prev) { spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags ^ SPL_DLLIST_IT_LIFO); } @@ -940,9 +922,7 @@ PHP_METHOD(SplDoublyLinkedList, next) { spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags); } @@ -953,9 +933,7 @@ PHP_METHOD(SplDoublyLinkedList, valid) { spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_BOOL(intern->traverse_pointer != NULL); } @@ -966,9 +944,7 @@ PHP_METHOD(SplDoublyLinkedList, rewind) { spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_dllist_it_helper_rewind(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags); } @@ -980,9 +956,7 @@ PHP_METHOD(SplDoublyLinkedList, current) spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); spl_ptr_llist_element *element = intern->traverse_pointer; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (element == NULL || Z_ISUNDEF(element->data)) { RETURN_NULL(); @@ -1001,9 +975,7 @@ PHP_METHOD(SplDoublyLinkedList, serialize) zval flags; php_serialize_data_t var_hash; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); PHP_VAR_SERIALIZE_INIT(var_hash); @@ -1099,9 +1071,7 @@ PHP_METHOD(SplDoublyLinkedList, __serialize) spl_ptr_llist_element *current = intern->llist->head; zval tmp; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); array_init(return_value); @@ -1205,9 +1175,7 @@ PHP_METHOD(SplDoublyLinkedList, add) /* {{{ */ PHP_METHOD(SplDoublyLinkedList, __debugInfo) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_ARR(spl_dllist_object_get_debug_info(Z_OBJ_P(ZEND_THIS))); } /* }}} */ diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 61447e2d41bf4..6f976923341bc 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -562,9 +562,7 @@ PHP_METHOD(SplFixedArray, __wakeup) HashTable *intern_ht = zend_std_get_properties(Z_OBJ_P(ZEND_THIS)); zval *data; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (intern->array.size == 0) { int index = 0; @@ -589,9 +587,7 @@ PHP_METHOD(SplFixedArray, __serialize) zval *current; zend_string *key; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); HashTable *ht = zend_std_get_properties(&intern->std); uint32_t num_properties = zend_hash_num_elements(ht); @@ -639,7 +635,7 @@ PHP_METHOD(SplFixedArray, __unserialize) intern->array.size = 0; ZEND_HASH_FOREACH_STR_KEY_VAL(data, key, elem) { if (key == NULL) { - ZVAL_COPY(&intern->array.elements[intern->array.size], elem); + ZVAL_COPY_DEREF(&intern->array.elements[intern->array.size], elem); intern->array.size++; } else { Z_TRY_ADDREF_P(elem); @@ -666,9 +662,7 @@ PHP_METHOD(SplFixedArray, count) zval *object = ZEND_THIS; spl_fixedarray_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLFIXEDARRAY_P(object); RETURN_LONG(intern->array.size); @@ -678,9 +672,7 @@ PHP_METHOD(SplFixedArray, toArray) { spl_fixedarray_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); @@ -774,9 +766,7 @@ PHP_METHOD(SplFixedArray, getSize) zval *object = ZEND_THIS; spl_fixedarray_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLFIXEDARRAY_P(object); RETURN_LONG(intern->array.size); @@ -832,7 +822,7 @@ PHP_METHOD(SplFixedArray, offsetGet) value = spl_fixedarray_object_read_dimension_helper(intern, zindex); if (value) { - RETURN_COPY_DEREF(value); + RETURN_COPY(value); } else { RETURN_NULL(); } @@ -871,9 +861,7 @@ PHP_METHOD(SplFixedArray, offsetUnset) /* Create a new iterator from a SplFixedArray instance. */ PHP_METHOD(SplFixedArray, getIterator) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_create_internal_iterator_zval(return_value, ZEND_THIS); } diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 5d36266393b04..85fc5f8bb698b 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -575,9 +575,7 @@ PHP_METHOD(SplHeap, count) zend_long count; spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); count = spl_ptr_heap_count(intern->heap); RETURN_LONG(count); @@ -589,9 +587,7 @@ PHP_METHOD(SplHeap, isEmpty) { spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_BOOL(spl_ptr_heap_count(intern->heap) == 0); } @@ -640,9 +636,7 @@ PHP_METHOD(SplHeap, extract) { spl_heap_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLHEAP_P(ZEND_THIS); @@ -705,9 +699,7 @@ PHP_METHOD(SplPriorityQueue, extract) spl_pqueue_elem elem; spl_heap_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLHEAP_P(ZEND_THIS); @@ -731,9 +723,7 @@ PHP_METHOD(SplPriorityQueue, top) spl_heap_object *intern; spl_pqueue_elem *elem; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLHEAP_P(ZEND_THIS); @@ -780,9 +770,7 @@ PHP_METHOD(SplPriorityQueue, getExtractFlags) { spl_heap_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLHEAP_P(ZEND_THIS); @@ -795,9 +783,7 @@ PHP_METHOD(SplHeap, recoverFromCorruption) { spl_heap_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLHEAP_P(ZEND_THIS); @@ -812,9 +798,7 @@ PHP_METHOD(SplHeap, isCorrupted) { spl_heap_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLHEAP_P(ZEND_THIS); @@ -841,9 +825,7 @@ PHP_METHOD(SplHeap, top) zval *value; spl_heap_object *intern; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); intern = Z_SPLHEAP_P(ZEND_THIS); @@ -970,9 +952,7 @@ PHP_METHOD(SplHeap, key) { spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->heap->count - 1); } @@ -983,9 +963,7 @@ PHP_METHOD(SplHeap, next) { spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_ptr_heap_delete_top(intern->heap, NULL, ZEND_THIS); } @@ -996,9 +974,7 @@ PHP_METHOD(SplHeap, valid) { spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_BOOL(intern->heap->count != 0); } @@ -1007,9 +983,7 @@ PHP_METHOD(SplHeap, valid) /* {{{ Rewind the datastructure back to the start */ PHP_METHOD(SplHeap, rewind) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); /* do nothing, the iterator always points to the top element */ } /* }}} */ @@ -1019,9 +993,7 @@ PHP_METHOD(SplHeap, current) { spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (!intern->heap->count) { RETURN_NULL(); @@ -1037,9 +1009,7 @@ PHP_METHOD(SplPriorityQueue, current) { spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (!intern->heap->count) { RETURN_NULL(); @@ -1053,9 +1023,7 @@ PHP_METHOD(SplPriorityQueue, current) /* {{{ */ PHP_METHOD(SplHeap, __debugInfo) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_ARR(spl_heap_object_get_debug_info(spl_ce_SplHeap, Z_OBJ_P(ZEND_THIS))); } /* }}} */ @@ -1063,9 +1031,7 @@ PHP_METHOD(SplHeap, __debugInfo) /* {{{ */ PHP_METHOD(SplPriorityQueue, __debugInfo) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_ARR(spl_heap_object_get_debug_info(spl_ce_SplPriorityQueue, Z_OBJ_P(ZEND_THIS))); } /* }}} */ diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index 540e5c2c0ff94..801c091fbb42d 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -673,9 +673,7 @@ PHP_METHOD(SplObjectStorage, rewind) { spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); intern->index = 0; @@ -686,9 +684,7 @@ PHP_METHOD(SplObjectStorage, valid) { spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS); } /* }}} */ @@ -698,9 +694,7 @@ PHP_METHOD(SplObjectStorage, key) { spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->index); } /* }}} */ @@ -711,9 +705,7 @@ PHP_METHOD(SplObjectStorage, current) spl_SplObjectStorageElement *element; spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) == NULL) { zend_throw_exception(spl_ce_RuntimeException, "Called current() on invalid iterator", 0); @@ -728,9 +720,7 @@ PHP_METHOD(SplObjectStorage, getInfo) spl_SplObjectStorageElement *element; spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) == NULL) { RETURN_NULL(); @@ -763,9 +753,7 @@ PHP_METHOD(SplObjectStorage, next) { spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_hash_move_forward_ex(&intern->storage, &intern->pos); intern->index++; @@ -825,9 +813,7 @@ PHP_METHOD(SplObjectStorage, serialize) php_serialize_data_t var_hash; smart_str buf = {0}; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); PHP_VAR_SERIALIZE_INIT(var_hash); @@ -999,9 +985,7 @@ PHP_METHOD(SplObjectStorage, __serialize) spl_SplObjectStorageElement *elem; zval tmp; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); array_init(return_value); @@ -1069,9 +1053,7 @@ PHP_METHOD(SplObjectStorage, __unserialize) /* {{{ */ PHP_METHOD(SplObjectStorage, __debugInfo) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_ARR(spl_object_storage_debug_info(Z_OBJ_P(ZEND_THIS))); } @@ -1100,9 +1082,7 @@ PHP_METHOD(MultipleIterator, getFlags) { spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->flags); } /* }}} */ @@ -1193,9 +1173,7 @@ PHP_METHOD(MultipleIterator, countIterators) { spl_SplObjectStorage *intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(zend_hash_num_elements(&intern->storage)); } @@ -1208,9 +1186,7 @@ PHP_METHOD(MultipleIterator, rewind) intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) { @@ -1229,9 +1205,7 @@ PHP_METHOD(MultipleIterator, next) intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) { @@ -1252,9 +1226,7 @@ PHP_METHOD(MultipleIterator, valid) intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); if (!zend_hash_num_elements(&intern->storage)) { RETURN_FALSE; @@ -1361,9 +1333,7 @@ PHP_METHOD(MultipleIterator, current) spl_SplObjectStorage *intern; intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value); } @@ -1375,9 +1345,7 @@ PHP_METHOD(MultipleIterator, key) spl_SplObjectStorage *intern; intern = Z_SPLOBJSTORAGE_P(ZEND_THIS); - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value); } diff --git a/ext/spl/tests/gh20614.phpt b/ext/spl/tests/gh20614.phpt new file mode 100644 index 0000000000000..c13630d76469b --- /dev/null +++ b/ext/spl/tests/gh20614.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-20614 (SplFixedArray incorrectly handles references in deserialization) +--FILE-- +__unserialize($array); +var_dump($fa); +unset($fa[0]); +var_dump($fa); + +?> +--EXPECT-- +object(SplFixedArray)#1 (1) { + [0]=> + int(1) +} +object(SplFixedArray)#1 (1) { + [0]=> + NULL +} diff --git a/ext/spl/tests/gh20678.phpt b/ext/spl/tests/gh20678.phpt new file mode 100644 index 0000000000000..00364db7f8044 --- /dev/null +++ b/ext/spl/tests/gh20678.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-20678 (resource created by GlobalIterator crashes when it is called with fclose()) +--CREDITS-- +chongwick +--FILE-- + +--EXPECTF-- +Warning: fclose(): cannot close the provided stream, as it must not be manually closed in %s on line %d diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index ea2ca11ca2535..da24b037861a8 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -648,7 +648,7 @@ static void sqlite_value_to_zval(sqlite3_stmt *stmt, int column, zval *data) /* break; case SQLITE3_TEXT: - ZVAL_STRING(data, (char*)sqlite3_column_text(stmt, column)); + ZVAL_STRINGL(data, (const char *) sqlite3_column_text(stmt, column), sqlite3_column_bytes(stmt, column)); break; case SQLITE_BLOB: @@ -2043,6 +2043,7 @@ PHP_METHOD(SQLite3Result, fetchArray) default: php_sqlite3_error(result_obj->db_obj, sqlite3_errcode(sqlite3_db_handle(result_obj->stmt_obj->stmt)), "Unable to execute statement: %s", sqlite3_errmsg(sqlite3_db_handle(result_obj->stmt_obj->stmt))); + RETURN_FALSE; } } /* }}} */ diff --git a/ext/sqlite3/tests/gh20699.phpt b/ext/sqlite3/tests/gh20699.phpt new file mode 100644 index 0000000000000..1b53bfc98e39f --- /dev/null +++ b/ext/sqlite3/tests/gh20699.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-20699 (SQLite3Result fetchArray return array|false, null returned) +--EXTENSIONS-- +sqlite3 +--CREDITS-- +plusminmax +--FILE-- +prepare('BEGIN;')->execute()->fetchArray()); +?> +--EXPECTF-- +Warning: SQLite3Result::fetchArray(): Unable to execute statement: cannot start a transaction within a transaction in %s on line %d +bool(false) diff --git a/ext/sqlite3/tests/text_column_NUL_bytes.phpt b/ext/sqlite3/tests/text_column_NUL_bytes.phpt new file mode 100644 index 0000000000000..cf9403d91302d --- /dev/null +++ b/ext/sqlite3/tests/text_column_NUL_bytes.phpt @@ -0,0 +1,38 @@ +--TEST-- +Text column with NUL bytes +--EXTENSIONS-- +sqlite3 +--FILE-- +exec( + 'CREATE TABLE messages ( + content TEXT + )' +); + +$insert = $db->prepare( + 'INSERT INTO messages (content) VALUES (:content)' +); + +$insert->bindValue(':content', "with\0null", SQLITE3_TEXT); +$insert->execute(); +$insert->bindValue(':content', "\0", SQLITE3_TEXT); +$insert->execute(); + +$result = $db->query('SELECT * FROM messages'); +while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + var_dump($row); +} + +?> +--EXPECTF-- +array(1) { + ["content"]=> + string(9) "with%0null" +} +array(1) { + ["content"]=> + string(1) "%0" +} diff --git a/ext/standard/array.c b/ext/standard/array.c index 3a782ec1ea40c..893e07dd8f99a 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -214,7 +214,7 @@ static zend_always_inline int php_array_key_compare_string_unstable_i(Bucket *f, } /* }}} */ -static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, int fold_case) /* {{{ */ +static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, bool fold_case) /* {{{ */ { const char *s1, *s2; size_t l1, l2; @@ -241,25 +241,25 @@ static int php_array_key_compare_string_natural_general(Bucket *f, Bucket *s, in static int php_array_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */ { - RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, 1)); + RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, true)); } /* }}} */ static int php_array_reverse_key_compare_string_natural_case(Bucket *a, Bucket *b) /* {{{ */ { - RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, 1)); + RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, true)); } /* }}} */ static int php_array_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */ { - RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, 0)); + RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(a, b, false)); } /* }}} */ static int php_array_reverse_key_compare_string_natural(Bucket *a, Bucket *b) /* {{{ */ { - RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, 0)); + RETURN_STABLE_SORT(a, b, php_array_key_compare_string_natural_general(b, a, false)); } /* }}} */ @@ -327,7 +327,7 @@ static zend_always_inline int php_array_data_compare_string_unstable_i(Bucket *f } /* }}} */ -static int php_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case) /* {{{ */ +static int php_array_natural_general_compare(Bucket *f, Bucket *s, bool fold_case) /* {{{ */ { zend_string *tmp_str1, *tmp_str2; zend_string *str1 = zval_get_tmp_string(&f->val, &tmp_str1); @@ -343,13 +343,13 @@ static int php_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case static zend_always_inline int php_array_natural_compare_unstable_i(Bucket *a, Bucket *b) /* {{{ */ { - return php_array_natural_general_compare(a, b, 0); + return php_array_natural_general_compare(a, b, false); } /* }}} */ static zend_always_inline int php_array_natural_case_compare_unstable_i(Bucket *a, Bucket *b) /* {{{ */ { - return php_array_natural_general_compare(a, b, 1); + return php_array_natural_general_compare(a, b, true); } /* }}} */ @@ -372,135 +372,127 @@ DEFINE_SORT_VARIANTS(data_compare_string_locale); DEFINE_SORT_VARIANTS(natural_compare); DEFINE_SORT_VARIANTS(natural_case_compare); -static bucket_compare_func_t php_get_key_compare_func(zend_long sort_type, int reverse) /* {{{ */ +static bucket_compare_func_t php_get_key_compare_func(zend_long sort_type) { switch (sort_type & ~PHP_SORT_FLAG_CASE) { case PHP_SORT_NUMERIC: - if (reverse) { - return php_array_reverse_key_compare_numeric; - } else { - return php_array_key_compare_numeric; - } - break; + return php_array_key_compare_numeric; case PHP_SORT_STRING: if (sort_type & PHP_SORT_FLAG_CASE) { - if (reverse) { - return php_array_reverse_key_compare_string_case; - } else { - return php_array_key_compare_string_case; - } + return php_array_key_compare_string_case; } else { - if (reverse) { - return php_array_reverse_key_compare_string; - } else { - return php_array_key_compare_string; - } + return php_array_key_compare_string; } - break; case PHP_SORT_NATURAL: if (sort_type & PHP_SORT_FLAG_CASE) { - if (reverse) { - return php_array_reverse_key_compare_string_natural_case; - } else { - return php_array_key_compare_string_natural_case; - } + return php_array_key_compare_string_natural_case; } else { - if (reverse) { - return php_array_reverse_key_compare_string_natural; - } else { - return php_array_key_compare_string_natural; - } + return php_array_key_compare_string_natural; } - break; case PHP_SORT_LOCALE_STRING: - if (reverse) { - return php_array_reverse_key_compare_string_locale; - } else { - return php_array_key_compare_string_locale; - } - break; + return php_array_key_compare_string_locale; case PHP_SORT_REGULAR: default: - if (reverse) { - return php_array_reverse_key_compare; - } else { - return php_array_key_compare; - } - break; + return php_array_key_compare; } return NULL; } -/* }}} */ -static bucket_compare_func_t php_get_data_compare_func(zend_long sort_type, int reverse) /* {{{ */ +static bucket_compare_func_t php_get_key_reverse_compare_func(zend_long sort_type) { switch (sort_type & ~PHP_SORT_FLAG_CASE) { case PHP_SORT_NUMERIC: - if (reverse) { - return php_array_reverse_data_compare_numeric; - } else { - return php_array_data_compare_numeric; - } - break; + return php_array_reverse_key_compare_numeric; case PHP_SORT_STRING: if (sort_type & PHP_SORT_FLAG_CASE) { - if (reverse) { - return php_array_reverse_data_compare_string_case; - } else { - return php_array_data_compare_string_case; - } + return php_array_reverse_key_compare_string_case; } else { - if (reverse) { - return php_array_reverse_data_compare_string; - } else { - return php_array_data_compare_string; - } + return php_array_reverse_key_compare_string; } - break; case PHP_SORT_NATURAL: if (sort_type & PHP_SORT_FLAG_CASE) { - if (reverse) { - return php_array_reverse_natural_case_compare; - } else { - return php_array_natural_case_compare; - } + return php_array_reverse_key_compare_string_natural_case; } else { - if (reverse) { - return php_array_reverse_natural_compare; - } else { - return php_array_natural_compare; - } + return php_array_reverse_key_compare_string_natural; } - break; case PHP_SORT_LOCALE_STRING: - if (reverse) { - return php_array_reverse_data_compare_string_locale; + return php_array_reverse_key_compare_string_locale; + + case PHP_SORT_REGULAR: + default: + return php_array_reverse_key_compare; + } + return NULL; +} + +static bucket_compare_func_t php_get_data_compare_func(zend_long sort_type) /* {{{ */ +{ + switch (sort_type & ~PHP_SORT_FLAG_CASE) { + case PHP_SORT_NUMERIC: + return php_array_data_compare_numeric; + + case PHP_SORT_STRING: + if (sort_type & PHP_SORT_FLAG_CASE) { + return php_array_data_compare_string_case; } else { - return php_array_data_compare_string_locale; + return php_array_data_compare_string; } - break; + + case PHP_SORT_NATURAL: + if (sort_type & PHP_SORT_FLAG_CASE) { + return php_array_natural_case_compare; + } else { + return php_array_natural_compare; + } + + case PHP_SORT_LOCALE_STRING: + return php_array_data_compare_string_locale; case PHP_SORT_REGULAR: default: - if (reverse) { - return php_array_reverse_data_compare; + return php_array_data_compare; + } + return NULL; +} + +static bucket_compare_func_t php_get_data_reverse_compare_func(zend_long sort_type) /* {{{ */ +{ + switch (sort_type & ~PHP_SORT_FLAG_CASE) { + case PHP_SORT_NUMERIC: + return php_array_reverse_data_compare_numeric; + + case PHP_SORT_STRING: + if (sort_type & PHP_SORT_FLAG_CASE) { + return php_array_reverse_data_compare_string_case; } else { - return php_array_data_compare; + return php_array_reverse_data_compare_string; } - break; + + case PHP_SORT_NATURAL: + if (sort_type & PHP_SORT_FLAG_CASE) { + return php_array_reverse_natural_case_compare; + } else { + return php_array_reverse_natural_compare; + } + + case PHP_SORT_LOCALE_STRING: + return php_array_reverse_data_compare_string_locale; + + case PHP_SORT_REGULAR: + default: + return php_array_reverse_data_compare; } return NULL; } -/* }}} */ -static bucket_compare_func_t php_get_data_compare_func_unstable(zend_long sort_type, int reverse) /* {{{ */ +static bucket_compare_func_t php_get_data_compare_func_unstable(zend_long sort_type, bool reverse) /* {{{ */ { switch (sort_type & ~PHP_SORT_FLAG_CASE) { case PHP_SORT_NUMERIC: @@ -564,48 +556,6 @@ static bucket_compare_func_t php_get_data_compare_func_unstable(zend_long sort_t } /* }}} */ -/* {{{ Sort an array by key value in reverse order */ -PHP_FUNCTION(krsort) -{ - zval *array; - zend_long sort_type = PHP_SORT_REGULAR; - bucket_compare_func_t cmp; - - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ARRAY_EX(array, 0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(sort_type) - ZEND_PARSE_PARAMETERS_END(); - - cmp = php_get_key_compare_func(sort_type, 1); - - zend_hash_sort(Z_ARRVAL_P(array), cmp, 0); - - RETURN_TRUE; -} -/* }}} */ - -/* {{{ Sort an array by key */ -PHP_FUNCTION(ksort) -{ - zval *array; - zend_long sort_type = PHP_SORT_REGULAR; - bucket_compare_func_t cmp; - - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ARRAY_EX(array, 0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(sort_type) - ZEND_PARSE_PARAMETERS_END(); - - cmp = php_get_key_compare_func(sort_type, 0); - - zend_hash_sort(Z_ARRVAL_P(array), cmp, 0); - - RETURN_TRUE; -} -/* }}} */ - PHPAPI zend_long php_count_recursive(HashTable *ht) /* {{{ */ { zend_long cnt = 0; @@ -702,119 +652,92 @@ PHP_FUNCTION(count) } /* }}} */ -static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */ +static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t sort_fn) { - zval *array; + HashTable *array; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY_EX(array, 0, 1) + Z_PARAM_ARRAY_HT_EX(array, 0, 1) ZEND_PARSE_PARAMETERS_END(); - if (fold_case) { - zend_array_sort(Z_ARRVAL_P(array), php_array_natural_case_compare, 0); - } else { - zend_array_sort(Z_ARRVAL_P(array), php_array_natural_compare, 0); - } + zend_array_sort(array, sort_fn, false); RETURN_TRUE; } -/* }}} */ /* {{{ Sort an array using natural sort */ PHP_FUNCTION(natsort) { - php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_natural_compare); } /* }}} */ /* {{{ Sort an array using case-insensitive natural sort */ PHP_FUNCTION(natcasesort) { - php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); + php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_natural_case_compare); } /* }}} */ -/* {{{ Sort an array and maintain index association */ -PHP_FUNCTION(asort) -{ - zval *array; +typedef bucket_compare_func_t(*get_compare_function)(zend_long); + +static zend_always_inline void php_sort(INTERNAL_FUNCTION_PARAMETERS, get_compare_function get_cmp, bool renumber) { + HashTable *array; zend_long sort_type = PHP_SORT_REGULAR; bucket_compare_func_t cmp; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ARRAY_EX(array, 0, 1) + Z_PARAM_ARRAY_HT_EX(array, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_LONG(sort_type) ZEND_PARSE_PARAMETERS_END(); - cmp = php_get_data_compare_func(sort_type, 0); + cmp = get_cmp(sort_type); - zend_array_sort(Z_ARRVAL_P(array), cmp, 0); + zend_array_sort(array, cmp, renumber); RETURN_TRUE; } + +/* {{{ Sort an array and maintain index association */ +PHP_FUNCTION(asort) +{ + php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_data_compare_func, false); +} /* }}} */ /* {{{ Sort an array in reverse order and maintain index association */ PHP_FUNCTION(arsort) { - zval *array; - zend_long sort_type = PHP_SORT_REGULAR; - bucket_compare_func_t cmp; - - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ARRAY_EX(array, 0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(sort_type) - ZEND_PARSE_PARAMETERS_END(); - - cmp = php_get_data_compare_func(sort_type, 1); - - zend_array_sort(Z_ARRVAL_P(array), cmp, 0); - - RETURN_TRUE; + php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_data_reverse_compare_func, false); } /* }}} */ /* {{{ Sort an array */ PHP_FUNCTION(sort) { - zval *array; - zend_long sort_type = PHP_SORT_REGULAR; - bucket_compare_func_t cmp; - - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ARRAY_EX(array, 0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(sort_type) - ZEND_PARSE_PARAMETERS_END(); - - cmp = php_get_data_compare_func(sort_type, 0); - - zend_array_sort(Z_ARRVAL_P(array), cmp, 1); - - RETURN_TRUE; + php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_data_compare_func, true); } /* }}} */ /* {{{ Sort an array in reverse order */ PHP_FUNCTION(rsort) { - zval *array; - zend_long sort_type = PHP_SORT_REGULAR; - bucket_compare_func_t cmp; - - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ARRAY_EX(array, 0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(sort_type) - ZEND_PARSE_PARAMETERS_END(); - - cmp = php_get_data_compare_func(sort_type, 1); + php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_data_reverse_compare_func, true); +} +/* }}} */ - zend_array_sort(Z_ARRVAL_P(array), cmp, 1); +/* {{{ Sort an array by key value in reverse order */ +PHP_FUNCTION(krsort) +{ + php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_key_reverse_compare_func, false); +} +/* }}} */ - RETURN_TRUE; +/* {{{ Sort an array by key */ +PHP_FUNCTION(ksort) +{ + php_sort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_get_key_compare_func, false); } /* }}} */ @@ -912,14 +835,14 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compar /* {{{ Sort an array by values using a user-defined comparison function */ PHP_FUNCTION(usort) { - php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 1); + php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, true); } /* }}} */ /* {{{ Sort an array with a user-defined comparison function and maintain index association */ PHP_FUNCTION(uasort) { - php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, 0); + php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_compare, false); } /* }}} */ @@ -986,7 +909,7 @@ static int php_array_user_key_compare(Bucket *a, Bucket *b) /* {{{ */ /* {{{ Sort an array by keys using a user-defined comparison function */ PHP_FUNCTION(uksort) { - php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, 0); + php_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_array_user_key_compare, false); } /* }}} */ @@ -1752,9 +1675,8 @@ PHP_FUNCTION(array_search) } /* }}} */ -static zend_always_inline int php_valid_var_name(const char *var_name, size_t var_name_len) /* {{{ */ +static zend_always_inline bool php_valid_var_name(const zend_string *var_name) /* {{{ */ { -#if 1 /* first 256 bits for first character, and second 256 bits for the next */ static const uint32_t charset[8] = { /* 31 0 63 32 95 64 127 96 */ @@ -1764,67 +1686,37 @@ static zend_always_inline int php_valid_var_name(const char *var_name, size_t va /* 31 0 63 32 95 64 127 96 */ 0x00000000, 0x03ff0000, 0x87fffffe, 0x07fffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}; -#endif - size_t i; - uint32_t ch; - if (UNEXPECTED(!var_name_len)) { - return 0; + if (UNEXPECTED(!ZSTR_LEN(var_name))) { + return false; } /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */ - ch = (uint32_t)((unsigned char *)var_name)[0]; -#if 1 + uint32_t ch = (uint32_t)((unsigned char *)ZSTR_VAL(var_name))[0]; if (UNEXPECTED(!ZEND_BIT_TEST(charset, ch))) { -#else - if (var_name[0] != '_' && - (ch < 65 /* A */ || /* Z */ ch > 90) && - (ch < 97 /* a */ || /* z */ ch > 122) && - (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255) - ) { -#endif - return 0; + return false; } /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */ - if (var_name_len > 1) { - i = 1; + if (ZSTR_LEN(var_name) > 1) { + size_t i = 1; do { - ch = (uint32_t)((unsigned char *)var_name)[i]; -#if 1 + ch = (uint32_t)((unsigned char *)ZSTR_VAL(var_name))[i]; if (UNEXPECTED(!ZEND_BIT_TEST(charset2, ch))) { -#else - if (var_name[i] != '_' && - (ch < 48 /* 0 */ || /* 9 */ ch > 57) && - (ch < 65 /* A */ || /* Z */ ch > 90) && - (ch < 97 /* a */ || /* z */ ch > 122) && - (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255) - ) { -#endif - return 0; + return false; } - } while (++i < var_name_len); + } while (++i < ZSTR_LEN(var_name)); } - return 1; + return true; } /* }}} */ -PHPAPI int php_prefix_varname(zval *result, zend_string *prefix, const char *var_name, size_t var_name_len, bool add_underscore) /* {{{ */ +static zend_string* php_prefix_varname(const zend_string *prefix, const zend_string *var_name) { - ZVAL_NEW_STR(result, zend_string_alloc(ZSTR_LEN(prefix) + (add_underscore ? 1 : 0) + var_name_len, 0)); - memcpy(Z_STRVAL_P(result), ZSTR_VAL(prefix), ZSTR_LEN(prefix)); - - if (add_underscore) { - Z_STRVAL_P(result)[ZSTR_LEN(prefix)] = '_'; - } - - memcpy(Z_STRVAL_P(result) + ZSTR_LEN(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1); - - return SUCCESS; + return zend_string_concat3(ZSTR_VAL(prefix), ZSTR_LEN(prefix), ZEND_STRL("_"), ZSTR_VAL(var_name), ZSTR_LEN(var_name)); } -/* }}} */ -static zend_long php_extract_ref_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */ +static zend_long php_extract_ref_if_exists(const zend_array *arr, const zend_array *symbol_table) /* {{{ */ { zend_long count = 0; zend_string *var_name; @@ -1845,7 +1737,7 @@ static zend_long php_extract_ref_if_exists(zend_array *arr, zend_array *symbol_t continue; } } - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(var_name)) { continue; } if (zend_string_equals_literal(var_name, "GLOBALS")) { @@ -1870,7 +1762,7 @@ static zend_long php_extract_ref_if_exists(zend_array *arr, zend_array *symbol_t } /* }}} */ -static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table) /* {{{ */ +static zend_long php_extract_if_exists(const zend_array *arr, const zend_array *symbol_table) /* {{{ */ { zend_long count = 0; zend_string *var_name; @@ -1891,7 +1783,7 @@ static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table continue; } } - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(var_name)) { continue; } if (zend_string_equals_literal(var_name, "GLOBALS")) { @@ -1914,7 +1806,7 @@ static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table } /* }}} */ -static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */ +static zend_long php_extract_ref_overwrite(const zend_array *arr, zend_array *symbol_table) /* {{{ */ { zend_long count = 0; zend_string *var_name; @@ -1927,7 +1819,7 @@ static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_t if (!var_name) { continue; } - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(var_name)) { continue; } if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { @@ -1966,7 +1858,7 @@ static zend_long php_extract_ref_overwrite(zend_array *arr, zend_array *symbol_t } /* }}} */ -static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table) /* {{{ */ +static zend_long php_extract_overwrite(const zend_array *arr, zend_array *symbol_table) /* {{{ */ { zend_long count = 0; zend_string *var_name; @@ -1979,7 +1871,7 @@ static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table if (!var_name) { continue; } - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(var_name)) { continue; } if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { @@ -2011,11 +1903,11 @@ static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table } /* }}} */ -static zend_long php_extract_ref_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */ +static zend_long php_extract_ref_prefix_if_exists(const zend_array *arr, zend_array *symbol_table, const zend_string *prefix) /* {{{ */ { zend_long count = 0; zend_string *var_name; - zval *entry, *orig_var, final_name; + zval *entry, *orig_var; if (HT_IS_PACKED(arr)) { return 0; @@ -2039,30 +1931,28 @@ static zend_long php_extract_ref_prefix_if_exists(zend_array *arr, zend_array *s continue; } } - php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), true); - if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) { - zend_throw_error(NULL, "Cannot re-assign $this"); - return -1; + zend_string *final_name = php_prefix_varname(prefix, var_name); + if (php_valid_var_name(final_name)) { + /* Prefixed varname cannot be equal to "this" due to underscore between prefix and name */ + ZEND_ASSERT(!zend_string_equals(final_name, ZSTR_KNOWN(ZEND_STR_THIS))); + + if (Z_ISREF_P(entry)) { + Z_ADDREF_P(entry); } else { - if (Z_ISREF_P(entry)) { - Z_ADDREF_P(entry); - } else { - ZVAL_MAKE_REF_EX(entry, 2); - } - if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) { - if (Z_TYPE_P(orig_var) == IS_INDIRECT) { - orig_var = Z_INDIRECT_P(orig_var); - } - zval_ptr_dtor(orig_var); - ZVAL_REF(orig_var, Z_REF_P(entry)); - } else { - zend_hash_add_new(symbol_table, Z_STR(final_name), entry); + ZVAL_MAKE_REF_EX(entry, 2); + } + if ((orig_var = zend_hash_find(symbol_table, final_name)) != NULL) { + if (Z_TYPE_P(orig_var) == IS_INDIRECT) { + orig_var = Z_INDIRECT_P(orig_var); } - count++; + zval_ptr_dtor(orig_var); + ZVAL_REF(orig_var, Z_REF_P(entry)); + } else { + zend_hash_add_new(symbol_table, final_name, entry); } + count++; } - zval_ptr_dtor_str(&final_name); + zend_string_release_ex(final_name, false); } } ZEND_HASH_FOREACH_END(); @@ -2070,11 +1960,11 @@ static zend_long php_extract_ref_prefix_if_exists(zend_array *arr, zend_array *s } /* }}} */ -static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */ +static zend_long php_extract_prefix_if_exists(const zend_array *arr, zend_array *symbol_table, const zend_string *prefix) /* {{{ */ { zend_long count = 0; zend_string *var_name; - zval *entry, *orig_var, final_name; + zval *entry, *orig_var; if (HT_IS_PACKED(arr)) { return 0; @@ -2093,30 +1983,28 @@ static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbo continue; } } - php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), true); - if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) { - zend_throw_error(NULL, "Cannot re-assign $this"); - return -1; - } else { - ZVAL_DEREF(entry); - if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) { - if (Z_TYPE_P(orig_var) == IS_INDIRECT) { - orig_var = Z_INDIRECT_P(orig_var); - } - ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); - if (UNEXPECTED(EG(exception))) { - zend_string_release_ex(Z_STR(final_name), 0); - return -1; - } - } else { - Z_TRY_ADDREF_P(entry); - zend_hash_add_new(symbol_table, Z_STR(final_name), entry); + zend_string *final_name = php_prefix_varname(prefix, var_name); + if (php_valid_var_name(final_name)) { + /* Prefixed varname cannot be equal to "this" due to underscore between prefix and name */ + ZEND_ASSERT(!zend_string_equals(final_name, ZSTR_KNOWN(ZEND_STR_THIS))); + + ZVAL_DEREF(entry); + if ((orig_var = zend_hash_find(symbol_table, final_name)) != NULL) { + if (Z_TYPE_P(orig_var) == IS_INDIRECT) { + orig_var = Z_INDIRECT_P(orig_var); } - count++; + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(final_name, 0); + return -1; + } + } else { + Z_TRY_ADDREF_P(entry); + zend_hash_add_new(symbol_table, final_name, entry); } + count++; } - zval_ptr_dtor_str(&final_name); + zend_string_release_ex(final_name, false); } } ZEND_HASH_FOREACH_END(); @@ -2124,11 +2012,11 @@ static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbo } /* }}} */ -static zend_long php_extract_ref_prefix_same(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */ +static zend_long php_extract_ref_prefix_same(const zend_array *arr, zend_array *symbol_table, const zend_string *prefix) /* {{{ */ { zend_long count = 0; zend_string *var_name; - zval *entry, *orig_var, final_name; + zval *entry, *orig_var; if (HT_IS_PACKED(arr)) { return 0; @@ -2155,33 +2043,31 @@ static zend_long php_extract_ref_prefix_same(zend_array *arr, zend_array *symbol continue; } } -prefix: - php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), true); - if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) { - zend_throw_error(NULL, "Cannot re-assign $this"); - return -1; +prefix:; + zend_string *final_name = php_prefix_varname(prefix, var_name); + if (php_valid_var_name(final_name)) { + /* Prefixed varname cannot be equal to "this" due to underscore between prefix and name */ + ZEND_ASSERT(!zend_string_equals(final_name, ZSTR_KNOWN(ZEND_STR_THIS))); + + if (Z_ISREF_P(entry)) { + Z_ADDREF_P(entry); } else { - if (Z_ISREF_P(entry)) { - Z_ADDREF_P(entry); - } else { - ZVAL_MAKE_REF_EX(entry, 2); - } - if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) { - if (Z_TYPE_P(orig_var) == IS_INDIRECT) { - orig_var = Z_INDIRECT_P(orig_var); - } - zval_ptr_dtor(orig_var); - ZVAL_REF(orig_var, Z_REF_P(entry)); - } else { - zend_hash_add_new(symbol_table, Z_STR(final_name), entry); + ZVAL_MAKE_REF_EX(entry, 2); + } + if ((orig_var = zend_hash_find(symbol_table, final_name)) != NULL) { + if (Z_TYPE_P(orig_var) == IS_INDIRECT) { + orig_var = Z_INDIRECT_P(orig_var); } - count++; + zval_ptr_dtor(orig_var); + ZVAL_REF(orig_var, Z_REF_P(entry)); + } else { + zend_hash_add_new(symbol_table, final_name, entry); } + count++; } - zval_ptr_dtor_str(&final_name); + zend_string_release_ex(final_name, false); } else { - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(var_name)) { continue; } if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { @@ -2201,11 +2087,11 @@ static zend_long php_extract_ref_prefix_same(zend_array *arr, zend_array *symbol } /* }}} */ -static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */ +static zend_long php_extract_prefix_same(const zend_array *arr, zend_array *symbol_table, const zend_string *prefix) /* {{{ */ { zend_long count = 0; zend_string *var_name; - zval *entry, *orig_var, final_name; + zval *entry, *orig_var; if (HT_IS_PACKED(arr)) { return 0; @@ -2227,33 +2113,31 @@ static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_tab continue; } } -prefix: - php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), true); - if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) { - zend_throw_error(NULL, "Cannot re-assign $this"); - return -1; - } else { - ZVAL_DEREF(entry); - if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) { - if (Z_TYPE_P(orig_var) == IS_INDIRECT) { - orig_var = Z_INDIRECT_P(orig_var); - } - ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); - if (UNEXPECTED(EG(exception))) { - zend_string_release_ex(Z_STR(final_name), 0); - return -1; - } - } else { - Z_TRY_ADDREF_P(entry); - zend_hash_add_new(symbol_table, Z_STR(final_name), entry); +prefix:; + zend_string *final_name = php_prefix_varname(prefix, var_name); + if (php_valid_var_name(final_name)) { + /* Prefixed varname cannot be equal to "this" due to underscore between prefix and name */ + ZEND_ASSERT(!zend_string_equals(final_name, ZSTR_KNOWN(ZEND_STR_THIS))); + + ZVAL_DEREF(entry); + if ((orig_var = zend_hash_find(symbol_table, final_name)) != NULL) { + if (Z_TYPE_P(orig_var) == IS_INDIRECT) { + orig_var = Z_INDIRECT_P(orig_var); } - count++; + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(final_name, false); + return -1; + } + } else { + Z_TRY_ADDREF_P(entry); + zend_hash_add_new(symbol_table, final_name, entry); } + count++; } - zval_ptr_dtor_str(&final_name); + zend_string_release_ex(final_name, false); } else { - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(var_name)) { continue; } if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { @@ -2270,211 +2154,210 @@ static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_tab } /* }}} */ -static zend_long php_extract_ref_prefix_all(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */ +static zend_long php_extract_ref_prefix_all(const zend_array *arr, zend_array *symbol_table, const zend_string *prefix) /* {{{ */ { zend_long count = 0; zend_string *var_name; zend_ulong num_key; - zval *entry, *orig_var, final_name; + zval *entry, *orig_var; ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, var_name, entry) { + zend_string *final_name; if (var_name) { if (ZSTR_LEN(var_name) == 0) { continue; } - php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), true); + final_name = php_prefix_varname(prefix, var_name); } else { zend_string *str = zend_long_to_str(num_key); - php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), true); - zend_string_release_ex(str, 0); + final_name = php_prefix_varname(prefix, str); + zend_string_release_ex(str, false); } - if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) { - zend_throw_error(NULL, "Cannot re-assign $this"); - return -1; + if (php_valid_var_name(final_name)) { + /* Prefixed varname cannot be equal to "this" due to underscore between prefix and name */ + ZEND_ASSERT(!zend_string_equals(final_name, ZSTR_KNOWN(ZEND_STR_THIS))); + + if (Z_ISREF_P(entry)) { + Z_ADDREF_P(entry); } else { - if (Z_ISREF_P(entry)) { - Z_ADDREF_P(entry); - } else { - ZVAL_MAKE_REF_EX(entry, 2); - } - if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) { - if (Z_TYPE_P(orig_var) == IS_INDIRECT) { - orig_var = Z_INDIRECT_P(orig_var); - } - zval_ptr_dtor(orig_var); - ZVAL_REF(orig_var, Z_REF_P(entry)); - } else { - zend_hash_add_new(symbol_table, Z_STR(final_name), entry); + ZVAL_MAKE_REF_EX(entry, 2); + } + if ((orig_var = zend_hash_find(symbol_table, final_name)) != NULL) { + if (Z_TYPE_P(orig_var) == IS_INDIRECT) { + orig_var = Z_INDIRECT_P(orig_var); } - count++; + zval_ptr_dtor(orig_var); + ZVAL_REF(orig_var, Z_REF_P(entry)); + } else { + zend_hash_add_new(symbol_table, final_name, entry); } + count++; } - zval_ptr_dtor_str(&final_name); + zend_string_release_ex(final_name, false); } ZEND_HASH_FOREACH_END(); return count; } /* }}} */ -static zend_long php_extract_prefix_all(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */ +static zend_long php_extract_prefix_all(const zend_array *arr, zend_array *symbol_table, const zend_string *prefix) /* {{{ */ { zend_long count = 0; zend_string *var_name; zend_ulong num_key; - zval *entry, *orig_var, final_name; + zval *entry, *orig_var; ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, var_name, entry) { + zend_string *final_name; if (var_name) { if (ZSTR_LEN(var_name) == 0) { continue; } - php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), true); + final_name = php_prefix_varname(prefix, var_name); } else { zend_string *str = zend_long_to_str(num_key); - php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), true); - zend_string_release_ex(str, 0); + final_name = php_prefix_varname(prefix, str); + zend_string_release_ex(str, false); } - if (php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) { - zend_throw_error(NULL, "Cannot re-assign $this"); - return -1; - } else { - ZVAL_DEREF(entry); - if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) { - if (Z_TYPE_P(orig_var) == IS_INDIRECT) { - orig_var = Z_INDIRECT_P(orig_var); - } - ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); - if (UNEXPECTED(EG(exception))) { - zend_string_release_ex(Z_STR(final_name), 0); - return -1; - } - } else { - Z_TRY_ADDREF_P(entry); - zend_hash_add_new(symbol_table, Z_STR(final_name), entry); + if (php_valid_var_name(final_name)) { + /* Prefixed varname cannot be equal to "this" due to underscore between prefix and name */ + ZEND_ASSERT(!zend_string_equals(final_name, ZSTR_KNOWN(ZEND_STR_THIS))); + + ZVAL_DEREF(entry); + if ((orig_var = zend_hash_find(symbol_table, final_name)) != NULL) { + if (Z_TYPE_P(orig_var) == IS_INDIRECT) { + orig_var = Z_INDIRECT_P(orig_var); } - count++; + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(final_name, false); + return -1; + } + } else { + Z_TRY_ADDREF_P(entry); + zend_hash_add_new(symbol_table, final_name, entry); } + count++; } - zval_ptr_dtor_str(&final_name); + zend_string_release_ex(final_name, false); } ZEND_HASH_FOREACH_END(); return count; } /* }}} */ -static zend_long php_extract_ref_prefix_invalid(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */ +static zend_long php_extract_ref_prefix_invalid(const zend_array *arr, zend_array *symbol_table, const zend_string *prefix) /* {{{ */ { zend_long count = 0; zend_string *var_name; zend_ulong num_key; - zval *entry, *orig_var, final_name; + zval *entry, *orig_var; ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, var_name, entry) { + zend_string *final_name; if (var_name) { - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name)) - || zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { - php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), true); - if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - zval_ptr_dtor_str(&final_name); + if (!php_valid_var_name(var_name) || zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { + final_name = php_prefix_varname(prefix, var_name); + + if (!php_valid_var_name(final_name)) { + zend_string_release_ex(final_name, false); continue; } } else { - ZVAL_STR_COPY(&final_name, var_name); + final_name = zend_string_copy(var_name); } } else { zend_string *str = zend_long_to_str(num_key); - php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), true); - zend_string_release_ex(str, 0); - if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - zval_ptr_dtor_str(&final_name); + final_name = php_prefix_varname(prefix, str); + zend_string_release_ex(str, false); + if (!php_valid_var_name(final_name)) { + zend_string_release_ex(final_name, false); continue; } } - if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) { - zend_throw_error(NULL, "Cannot re-assign $this"); - return -1; + + /* We previously checked if the var name is "this" to prefix it */ + ZEND_ASSERT(!zend_string_equals(final_name, ZSTR_KNOWN(ZEND_STR_THIS))); + + if (Z_ISREF_P(entry)) { + Z_ADDREF_P(entry); } else { - if (Z_ISREF_P(entry)) { - Z_ADDREF_P(entry); - } else { - ZVAL_MAKE_REF_EX(entry, 2); - } - if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) { - if (Z_TYPE_P(orig_var) == IS_INDIRECT) { - orig_var = Z_INDIRECT_P(orig_var); - } - zval_ptr_dtor(orig_var); - ZVAL_REF(orig_var, Z_REF_P(entry)); - } else { - zend_hash_add_new(symbol_table, Z_STR(final_name), entry); + ZVAL_MAKE_REF_EX(entry, 2); + } + if ((orig_var = zend_hash_find(symbol_table, final_name)) != NULL) { + if (Z_TYPE_P(orig_var) == IS_INDIRECT) { + orig_var = Z_INDIRECT_P(orig_var); } - count++; + zval_ptr_dtor(orig_var); + ZVAL_REF(orig_var, Z_REF_P(entry)); + } else { + zend_hash_add_new(symbol_table, final_name, entry); } - zval_ptr_dtor_str(&final_name); + count++; + + zend_string_release_ex(final_name, false); } ZEND_HASH_FOREACH_END(); return count; } /* }}} */ -static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_table, zend_string *prefix) /* {{{ */ +static zend_long php_extract_prefix_invalid(const zend_array *arr, zend_array *symbol_table, const zend_string *prefix) /* {{{ */ { zend_long count = 0; zend_string *var_name; zend_ulong num_key; - zval *entry, *orig_var, final_name; + zval *entry, *orig_var; ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, var_name, entry) { + zend_string *final_name; if (var_name) { - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name)) - || zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { - php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), true); - if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - zval_ptr_dtor_str(&final_name); + if (!php_valid_var_name(var_name) || zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { + final_name = php_prefix_varname(prefix, var_name); + if (!php_valid_var_name(final_name)) { + zend_string_release_ex(final_name, false); continue; } } else { - ZVAL_STR_COPY(&final_name, var_name); + final_name = zend_string_copy(var_name); } } else { zend_string *str = zend_long_to_str(num_key); - php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), true); + final_name = php_prefix_varname(prefix, str); zend_string_release_ex(str, 0); - if (!php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) { - zval_ptr_dtor_str(&final_name); + if (!php_valid_var_name(final_name)) { + zend_string_release_ex(final_name, false); continue; } } - if (zend_string_equals(Z_STR(final_name), ZSTR_KNOWN(ZEND_STR_THIS))) { - zend_throw_error(NULL, "Cannot re-assign $this"); - return -1; - } else { - ZVAL_DEREF(entry); - if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) { - if (Z_TYPE_P(orig_var) == IS_INDIRECT) { - orig_var = Z_INDIRECT_P(orig_var); - } - ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); - if (UNEXPECTED(EG(exception))) { - zend_string_release_ex(Z_STR(final_name), 0); - return -1; - } - } else { - Z_TRY_ADDREF_P(entry); - zend_hash_add_new(symbol_table, Z_STR(final_name), entry); + + /* We previously checked if the var name is "this" to prefix it */ + ZEND_ASSERT(!zend_string_equals(final_name, ZSTR_KNOWN(ZEND_STR_THIS))); + + ZVAL_DEREF(entry); + if ((orig_var = zend_hash_find(symbol_table, final_name)) != NULL) { + if (Z_TYPE_P(orig_var) == IS_INDIRECT) { + orig_var = Z_INDIRECT_P(orig_var); } - count++; + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(final_name, false); + return -1; + } + } else { + Z_TRY_ADDREF_P(entry); + zend_hash_add_new(symbol_table, final_name, entry); } - zval_ptr_dtor_str(&final_name); + count++; + + zend_string_release_ex(final_name, false); } ZEND_HASH_FOREACH_END(); return count; } /* }}} */ -static zend_long php_extract_ref_skip(zend_array *arr, zend_array *symbol_table) /* {{{ */ +static zend_long php_extract_ref_skip(const zend_array *arr, zend_array *symbol_table) /* {{{ */ { zend_long count = 0; zend_string *var_name; @@ -2487,7 +2370,7 @@ static zend_long php_extract_ref_skip(zend_array *arr, zend_array *symbol_table) if (!var_name) { continue; } - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(var_name)) { continue; } if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { @@ -2522,7 +2405,7 @@ static zend_long php_extract_ref_skip(zend_array *arr, zend_array *symbol_table) } /* }}} */ -static zend_long php_extract_skip(zend_array *arr, zend_array *symbol_table) /* {{{ */ +static zend_long php_extract_skip(const zend_array *arr, zend_array *symbol_table) /* {{{ */ { zend_long count = 0; zend_string *var_name; @@ -2535,7 +2418,7 @@ static zend_long php_extract_skip(zend_array *arr, zend_array *symbol_table) /* if (!var_name) { continue; } - if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) { + if (!php_valid_var_name(var_name)) { continue; } if (zend_string_equals(var_name, ZSTR_KNOWN(ZEND_STR_THIS))) { @@ -2596,7 +2479,7 @@ PHP_FUNCTION(extract) } if (prefix) { - if (ZSTR_LEN(prefix) && !php_valid_var_name(ZSTR_VAL(prefix), ZSTR_LEN(prefix))) { + if (ZSTR_LEN(prefix) && !php_valid_var_name(prefix)) { zend_argument_value_error(3, "must be a valid identifier"); RETURN_THROWS(); } @@ -3040,18 +2923,18 @@ PHP_FUNCTION(range) if (start_type == IS_STRING || end_type == IS_STRING) { php_error_docref(NULL, E_WARNING, "Argument #3 ($step) must be of type int when generating an array" " of characters, inputs converted to 0"); - } - if (UNEXPECTED(EG(exception))) { - RETURN_THROWS(); + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } } end_type = IS_LONG; start_type = IS_LONG; goto handle_numeric_inputs; } - /* Generate array of characters */ - unsigned char low = (unsigned char)Z_STRVAL_P(user_start)[0]; - unsigned char high = (unsigned char)Z_STRVAL_P(user_end)[0]; + /* Generate array of characters, as zero-extended ints to make bounds checking possible in the loop condition */ + int low = (unsigned char) Z_STRVAL_P(user_start)[0]; + int high = (unsigned char) Z_STRVAL_P(user_end)[0]; /* Decreasing char range */ if (low > high) { @@ -3062,12 +2945,9 @@ PHP_FUNCTION(range) array_init_size(return_value, (uint32_t)(((low - high) / step) + 1)); zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { - for (; low >= high; low -= (unsigned int)step) { + for (; low >= high; low -= step) { ZEND_HASH_FILL_SET_INTERNED_STR(ZSTR_CHAR(low)); ZEND_HASH_FILL_NEXT(); - if (((signed int)low - step) < 0) { - break; - } } } ZEND_HASH_FILL_END(); } else if (high > low) { /* Increasing char range */ @@ -3080,12 +2960,9 @@ PHP_FUNCTION(range) array_init_size(return_value, (uint32_t)(((high - low) / step) + 1)); zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { - for (; low <= high; low += (unsigned int)step) { + for (; low <= high; low += step) { ZEND_HASH_FILL_SET_INTERNED_STR(ZSTR_CHAR(low)); ZEND_HASH_FILL_NEXT(); - if (((signed int)low + step) > 255) { - break; - } } } ZEND_HASH_FILL_END(); } else { @@ -4279,7 +4156,7 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET uint32_t argc, i; zval *src_entry; HashTable *src, *dest; - uint32_t count = 0; + uint64_t count = 0; ZEND_PARSE_PARAMETERS_START(0, -1) Z_PARAM_VARIADIC('+', args, argc) @@ -4299,6 +4176,11 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET count += zend_hash_num_elements(Z_ARRVAL_P(arg)); } + if (UNEXPECTED(count >= HT_MAX_SIZE)) { + zend_throw_error(NULL, "The total number of elements must be lower than %u", HT_MAX_SIZE); + RETURN_THROWS(); + } + if (argc == 2) { zval *ret = NULL; @@ -4310,22 +4192,20 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET if (ret) { if (HT_IS_PACKED(Z_ARRVAL_P(ret))) { if (HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(ret))) { - ZVAL_COPY(return_value, ret); - return; + RETURN_COPY(ret); } } else { - bool copy = 1; + bool copy = true; zend_string *string_key; - ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(ret), string_key) { + ZEND_HASH_MAP_FOREACH_STR_KEY(Z_ARRVAL_P(ret), string_key) { if (!string_key) { - copy = 0; + copy = false; break; } } ZEND_HASH_FOREACH_END(); if (copy) { - ZVAL_COPY(return_value, ret); - return; + RETURN_COPY(ret); } } } @@ -4340,7 +4220,7 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET if (HT_IS_WITHOUT_HOLES(src) && zend_may_modify_arg_in_place(arg)) { dest = src; in_place = true; - ZVAL_ARR(return_value, dest); + RETVAL_ARR(dest); } else { array_init_size(return_value, count); dest = Z_ARRVAL_P(return_value); @@ -5022,7 +4902,7 @@ PHP_FUNCTION(array_unique) return; } - cmp = php_get_data_compare_func_unstable(sort_type, 0); + cmp = php_get_data_compare_func_unstable(sort_type, false); bool in_place = zend_may_modify_arg_in_place(array); if (in_place) { @@ -7045,8 +6925,7 @@ PHP_FUNCTION(array_chunk) if (size > num_in) { if (num_in == 0) { - RETVAL_EMPTY_ARRAY(); - return; + RETURN_EMPTY_ARRAY(); } size = num_in; } @@ -7054,12 +6933,11 @@ PHP_FUNCTION(array_chunk) array_init_size(return_value, (uint32_t)(((num_in - 1) / size) + 1)); zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); - ZVAL_UNDEF(&chunk); - ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, str_key, entry) { /* If new chunk, create and initialize it. */ - if (Z_TYPE(chunk) == IS_UNDEF) { + if (current == 0) { array_init_size(&chunk, (uint32_t)size); + add_next_index_zval(return_value, &chunk); } /* Add entry to the chunk, preserving keys if necessary. */ @@ -7074,19 +6952,10 @@ PHP_FUNCTION(array_chunk) } zval_add_ref(entry); - /* If reached the chunk size, add it to the result array, and reset the - * pointer. */ if (++current == size) { - add_next_index_zval(return_value, &chunk); - ZVAL_UNDEF(&chunk); current = 0; } } ZEND_HASH_FOREACH_END(); - - /* Add the final chunk if there is one. */ - if (Z_TYPE(chunk) != IS_UNDEF) { - add_next_index_zval(return_value, &chunk); - } } /* }}} */ diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index e0c4230dae27c..c108900103cc1 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -561,7 +561,7 @@ PHP_FUNCTION(inet_pton) char buffer[17]; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(address, address_len) + Z_PARAM_PATH(address, address_len) ZEND_PARSE_PARAMETERS_END(); memset(buffer, 0, sizeof(buffer)); @@ -593,7 +593,7 @@ PHP_FUNCTION(ip2long) struct in_addr ip; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(addr, addr_len) + Z_PARAM_PATH(addr, addr_len) ZEND_PARSE_PARAMETERS_END(); if (addr_len == 0 || inet_pton(AF_INET, addr, &ip) != 1) { @@ -1330,34 +1330,22 @@ error options: /* {{{ Send an error message somewhere */ PHP_FUNCTION(error_log) { - char *message, *opt = NULL, *headers = NULL; - size_t message_len, opt_len = 0, headers_len = 0; + zend_string *message, *opt = NULL, *headers = NULL; zend_long erropt = 0; ZEND_PARSE_PARAMETERS_START(1, 4) - Z_PARAM_STRING(message, message_len) + Z_PARAM_STR(message) Z_PARAM_OPTIONAL Z_PARAM_LONG(erropt) - Z_PARAM_PATH_OR_NULL(opt, opt_len) - Z_PARAM_STRING_OR_NULL(headers, headers_len) + Z_PARAM_PATH_STR_OR_NULL(opt) + Z_PARAM_STR_OR_NULL(headers) ZEND_PARSE_PARAMETERS_END(); - if (_php_error_log_ex((int) erropt, message, message_len, opt, headers) == FAILURE) { - RETURN_FALSE; - } - - RETURN_TRUE; + RETURN_BOOL(_php_error_log((int) erropt, message, opt, headers) == SUCCESS); } /* }}} */ -/* For BC (not binary-safe!) */ -PHPAPI int _php_error_log(int opt_err, const char *message, const char *opt, const char *headers) /* {{{ */ -{ - return _php_error_log_ex(opt_err, message, (opt_err == 3) ? strlen(message) : 0, opt, headers); -} -/* }}} */ - -PHPAPI int _php_error_log_ex(int opt_err, const char *message, size_t message_len, const char *opt, const char *headers) /* {{{ */ +PHPAPI zend_result _php_error_log(int opt_err, const zend_string *message, const zend_string *opt, const zend_string *headers) /* {{{ */ { php_stream *stream = NULL; size_t nbytes; @@ -1365,7 +1353,7 @@ PHPAPI int _php_error_log_ex(int opt_err, const char *message, size_t message_le switch (opt_err) { case 1: /*send an email */ - if (!php_mail(opt, "PHP error_log message", message, headers, NULL)) { + if (!php_mail(ZSTR_VAL(opt), "PHP error_log message", ZSTR_VAL(message), ZSTR_VAL(headers), NULL)) { return FAILURE; } break; @@ -1375,27 +1363,27 @@ PHPAPI int _php_error_log_ex(int opt_err, const char *message, size_t message_le return FAILURE; case 3: /*save to a file */ - stream = php_stream_open_wrapper(opt, "a", REPORT_ERRORS, NULL); + stream = php_stream_open_wrapper(ZSTR_VAL(opt), "a", REPORT_ERRORS, NULL); if (!stream) { return FAILURE; } - nbytes = php_stream_write(stream, message, message_len); + nbytes = php_stream_write(stream, ZSTR_VAL(message), ZSTR_LEN(message)); php_stream_close(stream); - if (nbytes != message_len) { + if (nbytes != ZSTR_LEN(message)) { return FAILURE; } break; case 4: /* send to SAPI */ if (sapi_module.log_message) { - sapi_module.log_message(message, -1); + sapi_module.log_message(ZSTR_VAL(message), -1); } else { return FAILURE; } break; default: - php_log_err_with_severity(message, LOG_NOTICE); + php_log_err_with_severity(ZSTR_VAL(message), LOG_NOTICE); break; } return SUCCESS; @@ -2139,8 +2127,8 @@ PHP_FUNCTION(getservbyname) struct servent *serv; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_STR(name) - Z_PARAM_STRING(proto, proto_len) + Z_PARAM_PATH_STR(name) + Z_PARAM_PATH(proto, proto_len) ZEND_PARSE_PARAMETERS_END(); @@ -2183,7 +2171,7 @@ PHP_FUNCTION(getservbyport) ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_LONG(port) - Z_PARAM_STRING(proto, proto_len) + Z_PARAM_PATH(proto, proto_len) ZEND_PARSE_PARAMETERS_END(); serv = getservbyport(htons((unsigned short) port), proto); @@ -2210,7 +2198,7 @@ PHP_FUNCTION(getprotobyname) struct protoent *ent; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(name, name_len) + Z_PARAM_PATH(name, name_len) ZEND_PARSE_PARAMETERS_END(); ent = getprotobyname(name); @@ -2322,11 +2310,7 @@ PHP_FUNCTION(is_uploaded_file) RETURN_FALSE; } - if (zend_hash_exists(SG(rfc1867_uploaded_files), path)) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(zend_hash_exists(SG(rfc1867_uploaded_files), path)); } /* }}} */ diff --git a/ext/standard/basic_functions.h b/ext/standard/basic_functions.h index bad6fcf4e645e..e5b85fbc2d53c 100644 --- a/ext/standard/basic_functions.h +++ b/ext/standard/basic_functions.h @@ -46,10 +46,7 @@ PHP_MINIT_FUNCTION(user_filters); PHP_RSHUTDOWN_FUNCTION(user_filters); PHP_RSHUTDOWN_FUNCTION(browscap); -/* Left for BC (not binary safe!) */ -PHPAPI int _php_error_log(int opt_err, const char *message, const char *opt, const char *headers); -PHPAPI int _php_error_log_ex(int opt_err, const char *message, size_t message_len, const char *opt, const char *headers); -PHPAPI int php_prefix_varname(zval *result, zend_string *prefix, const char *var_name, size_t var_name_len, bool add_underscore); +PHPAPI zend_result _php_error_log(int opt_err, const zend_string *message, const zend_string *opt, const zend_string *headers); typedef struct _php_basic_globals { HashTable *user_shutdown_function_names; diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 7913ca0e00194..e27dca069c55b 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1606,6 +1606,12 @@ function min(mixed $value, mixed ...$values): mixed {} */ function max(mixed $value, mixed ...$values): mixed {} +/** + * @compile-time-eval + * @frameless-function {"arity": 3} + */ +function clamp(mixed $value, mixed $min, mixed $max): mixed {} + function array_walk(array|object &$array, callable $callback, mixed $arg = UNKNOWN): true {} function array_walk_recursive(array|object &$array, callable $callback, mixed $arg = UNKNOWN): true {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 0a21d7d76426c..6f202c01463fd 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: f6bf6cdd07080c01d3a0cb08d71409d05b1084f9 */ + * Stub hash: 1a1667a5c59111f096a758d5bb4aa7cf3ec09cfe */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -138,6 +138,12 @@ ZEND_END_ARG_INFO() #define arginfo_max arginfo_min +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_clamp, 0, 3, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, min, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, max, IS_MIXED, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_walk, 0, 2, IS_TRUE, 0) ZEND_ARG_TYPE_MASK(1, array, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) @@ -2197,6 +2203,12 @@ static const zend_frameless_function_info frameless_function_infos_max[] = { { 0 }, }; +ZEND_FRAMELESS_FUNCTION(clamp, 3); +static const zend_frameless_function_info frameless_function_infos_clamp[] = { + { ZEND_FRAMELESS_FUNCTION_NAME(clamp, 3), 3 }, + { 0 }, +}; + ZEND_FRAMELESS_FUNCTION(in_array, 2); ZEND_FRAMELESS_FUNCTION(in_array, 3); static const zend_frameless_function_info frameless_function_infos_in_array[] = { @@ -2332,6 +2344,7 @@ ZEND_FUNCTION(current); ZEND_FUNCTION(key); ZEND_FUNCTION(min); ZEND_FUNCTION(max); +ZEND_FUNCTION(clamp); ZEND_FUNCTION(array_walk); ZEND_FUNCTION(array_walk_recursive); ZEND_FUNCTION(in_array); @@ -2925,6 +2938,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(key, arginfo_key) ZEND_RAW_FENTRY("min", zif_min, arginfo_min, ZEND_ACC_COMPILE_TIME_EVAL, frameless_function_infos_min, NULL) ZEND_RAW_FENTRY("max", zif_max, arginfo_max, ZEND_ACC_COMPILE_TIME_EVAL, frameless_function_infos_max, NULL) + ZEND_RAW_FENTRY("clamp", zif_clamp, arginfo_clamp, ZEND_ACC_COMPILE_TIME_EVAL, frameless_function_infos_clamp, NULL) ZEND_FE(array_walk, arginfo_array_walk) ZEND_FE(array_walk_recursive, arginfo_array_walk_recursive) ZEND_RAW_FENTRY("in_array", zif_in_array, arginfo_in_array, ZEND_ACC_COMPILE_TIME_EVAL, frameless_function_infos_in_array, NULL) diff --git a/ext/standard/dir.c b/ext/standard/dir.c index 918b92fab456f..7c1f8efe68875 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -558,11 +558,15 @@ PHP_FUNCTION(scandir) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, n); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); - for (i = 0; i < n; i++) { - add_next_index_str(return_value, namelist[i]); - } + ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { + for (i = 0; i < n; i++) { + ZEND_HASH_FILL_SET_STR(namelist[i]); + ZEND_HASH_FILL_NEXT(); + } + } ZEND_HASH_FILL_END(); if (n) { efree(namelist); diff --git a/ext/standard/dns.c b/ext/standard/dns.c index bd5720210fdaf..a574d8dd9aeb8 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -382,7 +382,7 @@ PHP_FUNCTION(dns_check_record) #endif ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_STRING(hostname, hostname_len) + Z_PARAM_PATH(hostname, hostname_len) Z_PARAM_OPTIONAL Z_PARAM_STR(rectype) ZEND_PARSE_PARAMETERS_END(); @@ -829,7 +829,7 @@ PHP_FUNCTION(dns_get_record) bool raw = 0; ZEND_PARSE_PARAMETERS_START(1, 5) - Z_PARAM_STRING(hostname, hostname_len) + Z_PARAM_PATH(hostname, hostname_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(type_param) Z_PARAM_ZVAL(authns) @@ -1067,7 +1067,7 @@ PHP_FUNCTION(dns_get_mx) #endif ZEND_PARSE_PARAMETERS_START(2, 3) - Z_PARAM_STRING(hostname, hostname_len) + Z_PARAM_PATH(hostname, hostname_len) Z_PARAM_ZVAL(mx_list) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(weight_list) diff --git a/ext/standard/dns_win32.c b/ext/standard/dns_win32.c index b320b66b6a788..1f7c6c0146e47 100644 --- a/ext/standard/dns_win32.c +++ b/ext/standard/dns_win32.c @@ -32,7 +32,7 @@ PHP_FUNCTION(dns_get_mx) /* {{{ */ DNS_STATUS status; /* Return value of DnsQuery_A() function */ PDNS_RECORD pResult, pRec; /* Pointer to DNS_RECORD structure */ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "pz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) { RETURN_THROWS(); } @@ -86,7 +86,7 @@ PHP_FUNCTION(dns_check_record) DNS_STATUS status; /* Return value of DnsQuery_A() function */ PDNS_RECORD pResult; /* Pointer to DNS_RECORD structure */ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|S", &hostname, &hostname_len, &rectype) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|S", &hostname, &hostname_len, &rectype) == FAILURE) { RETURN_THROWS(); } @@ -343,7 +343,7 @@ PHP_FUNCTION(dns_get_record) int type, type_to_fetch, first_query = 1, store_results = 1; bool raw = false; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lz!z!b", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|lz!z!b", &hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) { RETURN_THROWS(); } diff --git a/ext/standard/file.c b/ext/standard/file.c index ab6ed4fbadd2d..bd6ee252875e5 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -663,11 +663,10 @@ PHP_FUNCTION(file) p = e; goto parse_eol; } - } - if (target_buf) { - zend_string_free(target_buf); + zend_string_efree(target_buf); } + php_stream_close(stream); } /* }}} */ @@ -961,7 +960,8 @@ PHP_FUNCTION(fscanf) efree(buf); if (SCAN_ERROR_WRONG_PARAM_COUNT == result) { - WRONG_PARAM_COUNT; + zend_wrong_param_count(); + RETURN_THROWS(); } } /* }}} */ @@ -1554,7 +1554,6 @@ PHPAPI PHP_FUNCTION(fread) str = php_stream_read_to_str(stream, len); if (!str) { - zval_ptr_dtor_str(return_value); RETURN_FALSE; } diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index c0246653dfe3f..b0fbfcc89099f 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -103,7 +103,7 @@ php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add, if (req_size > ZSTR_LEN(*buffer)) { size_t size = ZSTR_LEN(*buffer); while (req_size > size) { - if (size > ZEND_SIZE_MAX/2) { + if (size > SIZE_MAX/2) { zend_error_noreturn(E_ERROR, "Field width %zd is too long", req_size); } size <<= 1; diff --git a/ext/standard/http.c b/ext/standard/http.c index 9e070ee74f407..47443f74ffe98 100644 --- a/ext/standard/http.c +++ b/ext/standard/http.c @@ -83,6 +83,15 @@ static void php_url_encode_scalar(zval *scalar, smart_str *form_str, } } +static zend_always_inline bool php_url_check_stack_limit(void) +{ +#ifdef ZEND_CHECK_STACK_LIMIT + return zend_call_stack_overflowed(EG(stack_limit)); +#else + return false; +#endif +} + /* {{{ php_url_encode_hash */ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, const char *num_prefix, size_t num_prefix_len, @@ -101,6 +110,12 @@ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, return; } + /* Very deeply structured data could trigger a stack overflow, even without recursion. */ + if (UNEXPECTED(php_url_check_stack_limit())) { + zend_throw_error(NULL, "Maximum call stack size reached."); + return; + } + if (!arg_sep) { arg_sep = PG(arg_separator).output; if (ZSTR_LEN(arg_sep) == 0) { diff --git a/ext/standard/image.c b/ext/standard/image.c index 4eadace55ec8c..08cf8983d029c 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -406,6 +406,7 @@ static size_t php_read_stream_all_chunks(php_stream *stream, char *buffer, size_ if (read_now < stream->chunk_size && read_total != length) { return 0; } + buffer += read_now; } while (read_total < length); return read_total; diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c index 5078c0813ccb8..5482a3c6ff15f 100644 --- a/ext/standard/iptc.c +++ b/ext/standard/iptc.c @@ -73,19 +73,24 @@ #define M_APP15 0xef /* {{{ php_iptc_put1 */ -static int php_iptc_put1(FILE *fp, int spool, unsigned char c, unsigned char **spoolbuf) +static int php_iptc_put1(FILE *fp, int spool, unsigned char c, unsigned char **spoolbuf, const unsigned char *spoolbuf_end) { if (spool > 0) PUTC(c); - if (spoolbuf) *(*spoolbuf)++ = c; + if (spoolbuf) { + if (UNEXPECTED(*spoolbuf >= spoolbuf_end)) { + return EOF; + } + *(*spoolbuf)++ = c; + } return c; } /* }}} */ /* {{{ php_iptc_get1 */ -static int php_iptc_get1(FILE *fp, int spool, unsigned char **spoolbuf) +static int php_iptc_get1(FILE *fp, int spool, unsigned char **spoolbuf, const unsigned char *spoolbuf_end) { int c; char cc; @@ -99,66 +104,71 @@ static int php_iptc_get1(FILE *fp, int spool, unsigned char **spoolbuf) PUTC(cc); } - if (spoolbuf) *(*spoolbuf)++ = c; + if (spoolbuf) { + if (UNEXPECTED(*spoolbuf >= spoolbuf_end)) { + return EOF; + } + *(*spoolbuf)++ = c; + } return c; } /* }}} */ /* {{{ php_iptc_read_remaining */ -static int php_iptc_read_remaining(FILE *fp, int spool, unsigned char **spoolbuf) +static int php_iptc_read_remaining(FILE *fp, int spool, unsigned char **spoolbuf, const unsigned char *spoolbuf_end) { - while (php_iptc_get1(fp, spool, spoolbuf) != EOF) continue; + while (php_iptc_get1(fp, spool, spoolbuf, spoolbuf_end) != EOF) continue; return M_EOI; } /* }}} */ /* {{{ php_iptc_skip_variable */ -static int php_iptc_skip_variable(FILE *fp, int spool, unsigned char **spoolbuf) +static int php_iptc_skip_variable(FILE *fp, int spool, unsigned char **spoolbuf, const unsigned char *spoolbuf_end) { unsigned int length; int c1, c2; - if ((c1 = php_iptc_get1(fp, spool, spoolbuf)) == EOF) return M_EOI; + if ((c1 = php_iptc_get1(fp, spool, spoolbuf, spoolbuf_end)) == EOF) return M_EOI; - if ((c2 = php_iptc_get1(fp, spool, spoolbuf)) == EOF) return M_EOI; + if ((c2 = php_iptc_get1(fp, spool, spoolbuf, spoolbuf_end)) == EOF) return M_EOI; length = (((unsigned char) c1) << 8) + ((unsigned char) c2); length -= 2; while (length--) - if (php_iptc_get1(fp, spool, spoolbuf) == EOF) return M_EOI; + if (php_iptc_get1(fp, spool, spoolbuf, spoolbuf_end) == EOF) return M_EOI; return 0; } /* }}} */ /* {{{ php_iptc_next_marker */ -static int php_iptc_next_marker(FILE *fp, int spool, unsigned char **spoolbuf) +static int php_iptc_next_marker(FILE *fp, int spool, unsigned char **spoolbuf, const unsigned char *spoolbuf_end) { int c; /* skip unimportant stuff */ - c = php_iptc_get1(fp, spool, spoolbuf); + c = php_iptc_get1(fp, spool, spoolbuf, spoolbuf_end); if (c == EOF) return M_EOI; while (c != 0xff) { - if ((c = php_iptc_get1(fp, spool, spoolbuf)) == EOF) + if ((c = php_iptc_get1(fp, spool, spoolbuf, spoolbuf_end)) == EOF) return M_EOI; /* we hit EOF */ } /* get marker byte, swallowing possible padding */ do { - c = php_iptc_get1(fp, 0, 0); + c = php_iptc_get1(fp, 0, 0, NULL); if (c == EOF) return M_EOI; /* we hit EOF */ else if (c == 0xff) - php_iptc_put1(fp, spool, (unsigned char)c, spoolbuf); + php_iptc_put1(fp, spool, (unsigned char)c, spoolbuf, spoolbuf_end); } while (c == 0xff); return (unsigned int) c; @@ -178,6 +188,7 @@ PHP_FUNCTION(iptcembed) size_t inx; zend_string *spoolbuf = NULL; unsigned char *poi = NULL; + unsigned char *spoolbuf_end = NULL; zend_stat_t sb = {0}; bool written = 0; @@ -210,10 +221,11 @@ PHP_FUNCTION(iptcembed) spoolbuf = zend_string_safe_alloc(1, iptcdata_len + sizeof(psheader) + 1024 + 1, sb.st_size, 0); poi = (unsigned char*)ZSTR_VAL(spoolbuf); + spoolbuf_end = poi + ZSTR_LEN(spoolbuf); memset(poi, 0, iptcdata_len + sizeof(psheader) + sb.st_size + 1024 + 1); } - if (php_iptc_get1(fp, spool, poi?&poi:0) != 0xFF) { + if (php_iptc_get1(fp, spool, poi?&poi:0, spoolbuf_end) != 0xFF) { fclose(fp); if (spoolbuf) { zend_string_efree(spoolbuf); @@ -221,7 +233,8 @@ PHP_FUNCTION(iptcembed) RETURN_FALSE; } - if (php_iptc_get1(fp, spool, poi?&poi:0) != 0xD8) { + if (php_iptc_get1(fp, spool, poi?&poi:0, spoolbuf_end) != 0xD8) { +err: fclose(fp); if (spoolbuf) { zend_string_efree(spoolbuf); @@ -230,20 +243,22 @@ PHP_FUNCTION(iptcembed) } while (!done) { - marker = php_iptc_next_marker(fp, spool, poi?&poi:0); + marker = php_iptc_next_marker(fp, spool, poi?&poi:0, spoolbuf_end); if (marker == M_EOI) { /* EOF */ break; } else if (marker != M_APP13) { - php_iptc_put1(fp, spool, (unsigned char)marker, poi?&poi:0); + if (php_iptc_put1(fp, spool, (unsigned char)marker, poi?&poi:0, spoolbuf_end) < 0) { + goto err; + } } switch (marker) { case M_APP13: /* we are going to write a new APP13 marker, so don't output the old one */ - php_iptc_skip_variable(fp, 0, 0); + php_iptc_skip_variable(fp, 0, 0, spoolbuf_end); fgetc(fp); /* skip already copied 0xFF byte */ - php_iptc_read_remaining(fp, spool, poi?&poi:0); + php_iptc_read_remaining(fp, spool, poi?&poi:0, spoolbuf_end); done = 1; break; @@ -256,7 +271,7 @@ PHP_FUNCTION(iptcembed) } written = 1; - php_iptc_skip_variable(fp, spool, poi?&poi:0); + php_iptc_skip_variable(fp, spool, poi?&poi:0, spoolbuf_end); if (iptcdata_len & 1) { iptcdata_len++; /* make the length even */ @@ -266,25 +281,33 @@ PHP_FUNCTION(iptcembed) psheader[ 3 ] = (iptcdata_len+28)&0xff; for (inx = 0; inx < 28; inx++) { - php_iptc_put1(fp, spool, psheader[inx], poi?&poi:0); + if (php_iptc_put1(fp, spool, psheader[inx], poi?&poi:0, spoolbuf_end) < 0) { + goto err; + } } - php_iptc_put1(fp, spool, (unsigned char)(iptcdata_len>>8), poi?&poi:0); - php_iptc_put1(fp, spool, (unsigned char)(iptcdata_len&0xff), poi?&poi:0); + if (php_iptc_put1(fp, spool, (unsigned char)(iptcdata_len>>8), poi?&poi:0, spoolbuf_end) < 0) { + goto err; + } + if (php_iptc_put1(fp, spool, (unsigned char)(iptcdata_len&0xff), poi?&poi:0, spoolbuf_end) < 0) { + goto err; + } for (inx = 0; inx < iptcdata_len; inx++) { - php_iptc_put1(fp, spool, iptcdata[inx], poi?&poi:0); + if (php_iptc_put1(fp, spool, iptcdata[inx], poi?&poi:0, spoolbuf_end) < 0) { + goto err; + } } break; case M_SOS: /* we hit data, no more marker-inserting can be done! */ - php_iptc_read_remaining(fp, spool, poi?&poi:0); + php_iptc_read_remaining(fp, spool, poi?&poi:0, spoolbuf_end); done = 1; break; default: - php_iptc_skip_variable(fp, spool, poi?&poi:0); + php_iptc_skip_variable(fp, spool, poi?&poi:0, spoolbuf_end); break; } } @@ -292,6 +315,7 @@ PHP_FUNCTION(iptcembed) fclose(fp); if (spool < 2) { + *poi = '\0'; spoolbuf = zend_string_truncate(spoolbuf, poi - (unsigned char*)ZSTR_VAL(spoolbuf), 0); RETURN_NEW_STR(spoolbuf); } else { diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 8c8b4e6717e0b..395c7bb81d4f9 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -68,21 +68,20 @@ typedef enum { CONTAINS_NULL } php_mail_header_value_error_type; -static php_mail_header_value_error_type php_mail_build_headers_check_field_value(zval *val) +static php_mail_header_value_error_type php_mail_build_headers_check_field_value(const zend_string *value) { size_t len = 0; - zend_string *value = Z_STR_P(val); /* https://tools.ietf.org/html/rfc2822#section-2.2.1 */ /* https://tools.ietf.org/html/rfc2822#section-2.2.3 */ - while (len < value->len) { - if (*(value->val+len) == '\r') { - if (*(value->val+len+1) != '\n') { + while (len < ZSTR_LEN(value)) { + if (*(ZSTR_VAL(value)+len) == '\r') { + if (*(ZSTR_VAL(value)+len+1) != '\n') { return CONTAINS_CR_ONLY; } - if (value->len - len >= 3 - && (*(value->val+len+2) == ' ' || *(value->val+len+2) == '\t')) { + if (ZSTR_LEN(value) - len >= 3 + && (*(ZSTR_VAL(value)+len+2) == ' ' || *(ZSTR_VAL(value)+len+2) == '\t')) { len += 3; continue; } @@ -96,15 +95,15 @@ static php_mail_header_value_error_type php_mail_build_headers_check_field_value * Therefore, considering such an environment, folding with LF alone * is allowed. */ - if (*(value->val+len) == '\n') { - if (value->len - len >= 2 - && (*(value->val+len+1) == ' ' || *(value->val+len+1) == '\t')) { + if (*(ZSTR_VAL(value)+len) == '\n') { + if (ZSTR_LEN(value) - len >= 2 + && (*(ZSTR_VAL(value)+len+1) == ' ' || *(ZSTR_VAL(value)+len+1) == '\t')) { len += 2; continue; } return CONTAINS_LF_ONLY; } - if (*(value->val+len) == '\0') { + if (*(ZSTR_VAL(value)+len) == '\0') { return CONTAINS_NULL; } len++; @@ -112,14 +111,13 @@ static php_mail_header_value_error_type php_mail_build_headers_check_field_value return NO_HEADER_ERROR; } - -static bool php_mail_build_headers_check_field_name(zend_string *key) +static zend_result php_mail_build_headers_check_field_name(const zend_string *key) { size_t len = 0; /* https://tools.ietf.org/html/rfc2822#section-2.2 */ - while (len < key->len) { - if (*(key->val+len) < 33 || *(key->val+len) > 126 || *(key->val+len) == ':') { + while (len < ZSTR_LEN(key)) { + if (*(ZSTR_VAL(key)+len) < 33 || *(ZSTR_VAL(key)+len) > 126 || *(ZSTR_VAL(key)+len) == ':') { return FAILURE; } len++; @@ -128,9 +126,9 @@ static bool php_mail_build_headers_check_field_name(zend_string *key) } -static void php_mail_build_headers_elems(smart_str *s, zend_string *key, zval *val); +static void php_mail_build_headers_elems(smart_str *s, const zend_string *key, zval *val); -static void php_mail_build_headers_elem(smart_str *s, zend_string *key, zval *val) +static void php_mail_build_headers_elem(smart_str *s, const zend_string *key, zval *val) { switch(Z_TYPE_P(val)) { case IS_STRING: @@ -139,7 +137,8 @@ static void php_mail_build_headers_elem(smart_str *s, zend_string *key, zval *va return; } - php_mail_header_value_error_type error_type = php_mail_build_headers_check_field_value(val); + zend_string *str_value = Z_STR_P(val); + php_mail_header_value_error_type error_type = php_mail_build_headers_check_field_value(str_value); switch (error_type) { case NO_HEADER_ERROR: break; @@ -162,7 +161,7 @@ static void php_mail_build_headers_elem(smart_str *s, zend_string *key, zval *va } smart_str_append(s, key); smart_str_appendl(s, ": ", 2); - smart_str_appends(s, Z_STRVAL_P(val)); + smart_str_append(s, str_value); smart_str_appendl(s, "\r\n", 2); break; case IS_ARRAY: @@ -174,7 +173,7 @@ static void php_mail_build_headers_elem(smart_str *s, zend_string *key, zval *va } -static void php_mail_build_headers_elems(smart_str *s, zend_string *key, zval *val) +static void php_mail_build_headers_elems(smart_str *s, const zend_string *key, zval *val) { zend_string *tmp_key; zval *tmp_val; @@ -208,7 +207,7 @@ do { \ } \ } while(0) -PHPAPI zend_string *php_mail_build_headers(HashTable *headers) +PHPAPI zend_string *php_mail_build_headers(const HashTable *headers) { zend_ulong idx; zend_string *key; @@ -218,7 +217,8 @@ PHPAPI zend_string *php_mail_build_headers(HashTable *headers) ZEND_HASH_FOREACH_KEY_VAL(headers, idx, key, val) { if (!key) { zend_type_error("Header name cannot be numeric, " ZEND_LONG_FMT " given", idx); - break; + smart_str_free(&s); + return NULL; } ZVAL_DEREF(val); /* https://tools.ietf.org/html/rfc2822#section-3.6 */ @@ -245,13 +245,7 @@ PHPAPI zend_string *php_mail_build_headers(HashTable *headers) } else if (zend_string_equals_literal_ci(key, "subject")) { zend_value_error("The additional headers cannot contain the \"Subject\" header"); } else { - if (Z_TYPE_P(val) == IS_STRING) { - php_mail_build_headers_elem(&s, key, val); - } else if (Z_TYPE_P(val) == IS_ARRAY) { - php_mail_build_headers_elems(&s, key, val); - } else { - zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_value_name(val)); - } + php_mail_build_headers_elem(&s, key, val); } if (EG(exception)) { @@ -349,7 +343,7 @@ PHP_FUNCTION(mail) extra_cmd = php_escape_shell_cmd(extra_cmd); } - if (php_mail(to_r, subject_r, message, headers_str && ZSTR_LEN(headers_str) ? ZSTR_VAL(headers_str) : NULL, extra_cmd ? ZSTR_VAL(extra_cmd) : NULL)) { + if (php_mail(to_r, subject_r, message, headers_str && ZSTR_LEN(headers_str) ? ZSTR_VAL(headers_str) : NULL, extra_cmd)) { RETVAL_TRUE; } else { RETVAL_FALSE; @@ -391,10 +385,10 @@ static void php_mail_log_to_syslog(char *message) { } -static void php_mail_log_to_file(char *filename, char *message, size_t message_size) { +static void php_mail_log_to_file(const zend_string *filename, const char *message, size_t message_size) { /* Write 'message' to the given file. */ uint32_t flags = REPORT_ERRORS | STREAM_DISABLE_OPEN_BASEDIR; - php_stream *stream = php_stream_open_wrapper(filename, "a", flags, NULL); + php_stream *stream = php_stream_open_wrapper(ZSTR_VAL(filename), "a", flags, NULL); if (stream) { php_stream_write(stream, message, message_size); php_stream_close(stream); @@ -440,12 +434,12 @@ static int php_mail_detect_multiple_crlf(const char *hdr) { /* {{{ php_mail */ -PHPAPI bool php_mail(const char *to, const char *subject, const char *message, const char *headers, const char *extra_cmd) +PHPAPI bool php_mail(const char *to, const char *subject, const char *message, const char *headers, const zend_string *extra_cmd) { FILE *sendmail; char *sendmail_path = INI_STR("sendmail_path"); char *sendmail_cmd = NULL; - char *mail_log = INI_STR("mail.log"); + const zend_string *mail_log = zend_ini_str(ZEND_STRL("mail.log"), false); const char *hdr = headers; char *ahdr = NULL; #if PHP_SIGCHILD @@ -458,7 +452,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c } \ return val; \ - if (mail_log && *mail_log) { + if (mail_log && ZSTR_LEN(mail_log)) { char *logline; spprintf(&logline, 0, "mail() on [%s:%d]: To: %s -- Headers: %s -- Subject: %s", zend_get_executed_filename(), zend_get_executed_lineno(), to, hdr ? hdr : "", subject); @@ -467,7 +461,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c php_mail_log_crlf_to_spaces(logline); } - if (!strcmp(mail_log, "syslog")) { + if (zend_string_equals_literal(mail_log, "syslog")) { php_mail_log_to_syslog(logline); } else { /* Add date when logging to file */ @@ -494,7 +488,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c MAIL_RET(false); } - char *line_sep; + const char *line_sep; zend_string *cr_lf_mode = PG(mail_cr_lf_mode); if (cr_lf_mode && !zend_string_equals_literal(cr_lf_mode, "crlf")) { @@ -542,7 +536,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c char *tsm_errmsg = NULL; /* handle old style win smtp sending */ - if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message, NULL, NULL, NULL) == FAILURE) { + if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, hdr, subject, to, message) == FAILURE) { if (tsm_errmsg) { php_error_docref(NULL, E_WARNING, "%s", tsm_errmsg); efree(tsm_errmsg); @@ -557,7 +551,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c #endif } if (extra_cmd != NULL) { - spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, extra_cmd); + spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, ZSTR_VAL(extra_cmd)); } else { sendmail_cmd = sendmail_path; } diff --git a/ext/standard/math.c b/ext/standard/math.c index 142d473864f75..95384c06588ac 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -389,6 +389,62 @@ PHP_FUNCTION(round) } /* }}} */ +/* Return the given value if in range of min and max */ +static void php_math_clamp(zval *return_value, zval *value, zval *min, zval *max) +{ + if (Z_TYPE_P(min) == IS_DOUBLE && UNEXPECTED(zend_isnan(Z_DVAL_P(min)))) { + zend_argument_value_error(2, "must not be NAN"); + RETURN_THROWS(); + } + + if (Z_TYPE_P(max) == IS_DOUBLE && UNEXPECTED(zend_isnan(Z_DVAL_P(max)))) { + zend_argument_value_error(3, "must not be NAN"); + RETURN_THROWS(); + } + + if (zend_compare(max, min) == -1) { + zend_argument_value_error(2, "must be smaller than or equal to argument #3 ($max)"); + RETURN_THROWS(); + } + + if (zend_compare(max, value) == -1) { + RETURN_COPY(max); + } + + if (zend_compare(value, min) == -1) { + RETURN_COPY(min); + } + + RETURN_COPY(value); +} + +/* {{{ Return the given value if in range of min and max */ +PHP_FUNCTION(clamp) +{ + zval *zvalue, *zmin, *zmax; + + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_ZVAL(zvalue) + Z_PARAM_ZVAL(zmin) + Z_PARAM_ZVAL(zmax) + ZEND_PARSE_PARAMETERS_END(); + + php_math_clamp(return_value, zvalue, zmin, zmax); +} +/* }}} */ + +/* {{{ Return the given value if in range of min and max */ +ZEND_FRAMELESS_FUNCTION(clamp, 3) +{ + zval *zvalue, *zmin, *zmax; + Z_FLF_PARAM_ZVAL(1, zvalue); + Z_FLF_PARAM_ZVAL(2, zmin); + Z_FLF_PARAM_ZVAL(3, zmax); + + php_math_clamp(return_value, zvalue, zmin, zmax); +} +/* }}} */ + /* {{{ Returns the sine of the number in radians */ PHP_FUNCTION(sin) { diff --git a/ext/standard/php_mail.h b/ext/standard/php_mail.h index c2e22240c48e9..bebb526699d0b 100644 --- a/ext/standard/php_mail.h +++ b/ext/standard/php_mail.h @@ -19,7 +19,7 @@ PHP_MINFO_FUNCTION(mail); -PHPAPI zend_string *php_mail_build_headers(HashTable *headers); -PHPAPI extern bool php_mail(const char *to, const char *subject, const char *message, const char *headers, const char *extra_cmd); +PHPAPI zend_string *php_mail_build_headers(const HashTable *headers); +PHPAPI extern bool php_mail(const char *to, const char *subject, const char *message, const char *headers, const zend_string *extra_cmd); #endif /* PHP_MAIL_H */ diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 4dee37ba3cecc..55f4dd4849587 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -503,7 +503,7 @@ typedef struct _descriptorspec_item { } descriptorspec_item; static zend_string *get_valid_arg_string(zval *zv, uint32_t elem_num) { - zend_string *str = zval_get_string(zv); + zend_string *str = zval_try_get_string(zv); if (!str) { return NULL; } diff --git a/ext/standard/string.c b/ext/standard/string.c index ddf4221bf6edb..0b7d5be1a2576 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -4955,7 +4955,7 @@ PHP_FUNCTION(setlocale) for (uint32_t i = 0; i < num_args; i++) { if (UNEXPECTED(Z_TYPE(args[i]) != IS_ARRAY && !zend_parse_arg_str(&args[i], &strings[i], true, i + 2))) { - zend_wrong_parameter_type_error(i + 2, Z_EXPECTED_ARRAY_OR_STRING, &args[i]); + zend_wrong_parameter_type_error(i + 2, Z_EXPECTED_ARRAY_OR_STRING_OR_NULL, &args[i]); goto out; } } @@ -5873,7 +5873,8 @@ PHP_FUNCTION(sscanf) result = php_sscanf_internal(str, format, num_args, args, 0, return_value); if (SCAN_ERROR_WRONG_PARAM_COUNT == result) { - WRONG_PARAM_COUNT; + zend_wrong_param_count(); + RETURN_THROWS(); } } /* }}} */ diff --git a/ext/standard/tests/array/GHSA-h96m-rvf9-jgm2.phpt b/ext/standard/tests/array/GHSA-h96m-rvf9-jgm2.phpt new file mode 100644 index 0000000000000..2e3e85357e13c --- /dev/null +++ b/ext/standard/tests/array/GHSA-h96m-rvf9-jgm2.phpt @@ -0,0 +1,16 @@ +--TEST-- +GHSA-h96m-rvf9-jgm2 +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECTF-- +The total number of elements must be lower than %d diff --git a/ext/standard/tests/array/extract_negative_keys.phpt b/ext/standard/tests/array/extract_negative_keys.phpt new file mode 100644 index 0000000000000..55fce2a656570 --- /dev/null +++ b/ext/standard/tests/array/extract_negative_keys.phpt @@ -0,0 +1,31 @@ +--TEST-- +extract() with negative keys +--FILE-- + 'hello', 'world', 2 => 'positive', 'check' => 'extracted']; + +function foo(array $a) { + extract($a, EXTR_PREFIX_ALL, 'prefix'); + var_dump(get_defined_vars()); +} + +foo($a); +?> +--EXPECT-- +array(3) { + ["a"]=> + array(4) { + [-5]=> + string(5) "hello" + [-4]=> + string(5) "world" + [2]=> + string(8) "positive" + ["check"]=> + string(9) "extracted" + } + ["prefix_2"]=> + string(8) "positive" + ["prefix_check"]=> + string(9) "extracted" +} diff --git a/ext/standard/tests/array/extract_negative_keys2.phpt b/ext/standard/tests/array/extract_negative_keys2.phpt new file mode 100644 index 0000000000000..dd2a1fa7a18a4 --- /dev/null +++ b/ext/standard/tests/array/extract_negative_keys2.phpt @@ -0,0 +1,11 @@ +--TEST-- +extract() with negative keys +--FILE-- + "foo"]; +var_dump(extract($arr, EXTR_PREFIX_ALL | EXTR_REFS, "prefix")); + +?> +--EXPECT-- +int(0) diff --git a/ext/standard/tests/file/windows_mb_path/bug54028.phpt b/ext/standard/tests/file/windows_mb_path/bug54028.phpt index 61913a1a7218f..3603bced34d8a 100644 --- a/ext/standard/tests/file/windows_mb_path/bug54028.phpt +++ b/ext/standard/tests/file/windows_mb_path/bug54028.phpt @@ -4,12 +4,8 @@ Bug #54028 Directory::read() cannot handle non-unicode chars properly mbstring --SKIPIF-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- ---EXPECTF-- +--EXPECT-- Active code page: 65001 filetype()[dir ] == is_dir()[dir ] -> OK: . filetype()[dir ] == is_dir()[dir ] -> OK: .. @@ -58,4 +55,3 @@ filetype()[dir ] == is_dir()[dir ] -> OK: ソ filetype()[dir ] == is_dir()[dir ] -> OK: ゾ filetype()[dir ] == is_dir()[dir ] -> OK: 多国語 filetype()[dir ] == is_dir()[dir ] -> OK: 表 -Active code page: %d diff --git a/ext/standard/tests/file/windows_mb_path/bug70903.phpt b/ext/standard/tests/file/windows_mb_path/bug70903.phpt index 48cbf524c96d8..25a6f92b0abcc 100644 --- a/ext/standard/tests/file/windows_mb_path/bug70903.phpt +++ b/ext/standard/tests/file/windows_mb_path/bug70903.phpt @@ -2,12 +2,8 @@ Bug #70903 scandir wrongly interprets the Turkish "ı" character --SKIPIF-- --FILE-- --CONFLICTS-- bug71509 diff --git a/ext/standard/tests/file/windows_mb_path/bug74923.phpt b/ext/standard/tests/file/windows_mb_path/bug74923.phpt index 9cffd5860f601..fb87f2b266d54 100644 --- a/ext/standard/tests/file/windows_mb_path/bug74923.phpt +++ b/ext/standard/tests/file/windows_mb_path/bug74923.phpt @@ -2,11 +2,8 @@ Bug #74923 Crash when crawling through network share --SKIPIF-- --FILE-- --INI-- default_charset=cp1251 diff --git a/ext/standard/tests/file/windows_mb_path/bug75063_utf8.phpt b/ext/standard/tests/file/windows_mb_path/bug75063_utf8.phpt index a1878bb88a37c..615b76d196fb6 100644 --- a/ext/standard/tests/file/windows_mb_path/bug75063_utf8.phpt +++ b/ext/standard/tests/file/windows_mb_path/bug75063_utf8.phpt @@ -2,12 +2,8 @@ Bug #75063 Many filesystem-related functions do not work with multibyte file names, UTF-8 --SKIPIF-- --FILE-- 259) die("skip Unsuitable starting path length"); ?> --FILE-- diff --git a/ext/standard/tests/file/windows_mb_path/test_big5_0.phpt b/ext/standard/tests/file/windows_mb_path/test_big5_0.phpt index 794c1a2f7b878..7dc11a6167b5d 100644 --- a/ext/standard/tests/file/windows_mb_path/test_big5_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_big5_0.phpt @@ -4,9 +4,8 @@ Test fopen() for reading big5 path diff --git a/ext/standard/tests/file/windows_mb_path/test_big5_1.phpt b/ext/standard/tests/file/windows_mb_path/test_big5_1.phpt index d4821b23be0e4..7a88f57b7cf0d 100644 --- a/ext/standard/tests/file/windows_mb_path/test_big5_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_big5_1.phpt @@ -4,9 +4,8 @@ Test mkdir/rmdir big5 path diff --git a/ext/standard/tests/file/windows_mb_path/test_big5_2.phpt b/ext/standard/tests/file/windows_mb_path/test_big5_2.phpt index d7652615dea4e..89a8970344814 100644 --- a/ext/standard/tests/file/windows_mb_path/test_big5_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_big5_2.phpt @@ -4,9 +4,8 @@ Test fopen() for write big5 to UTF-8 path diff --git a/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_0.phpt index b355267f851d9..c68bd58be0fc6 100644 --- a/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_0.phpt @@ -2,12 +2,8 @@ Test fopen() for reading big5 to UTF-8 path --SKIPIF-- --CONFLICTS-- file_big5 diff --git a/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_1.phpt index 5076768c955b3..33573f04ec39e 100644 --- a/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_1.phpt @@ -2,12 +2,8 @@ Test mkdir/rmdir big5 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_big5 diff --git a/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_2.phpt index 4f94f898796f3..2451ebca18e95 100644 --- a/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_big5_to_utf8_2.phpt @@ -2,12 +2,8 @@ Test fopen() for write big5 to UTF-8 path --SKIPIF-- --CONFLICTS-- file_big5 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_0.phpt index 98c716678a6d7..20e5de98e07f9 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_0.phpt @@ -2,12 +2,8 @@ Test fopen() for reading UTF-8 path with cp1250 specific symbols --SKIPIF-- --CONFLICTS-- file_cp1250 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_1.phpt index ad09ff1967caf..1411911f6d54c 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_1.phpt @@ -2,12 +2,8 @@ Test mkdir/rmdir UTF-8 path with cp1250 specific symbols --SKIPIF-- --CONFLICTS-- dir_cp1250 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_2.phpt index 61e1b4eaa598b..72cf60068d246 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_2.phpt @@ -2,12 +2,8 @@ Test fopen() for write to UTF-8 path with cp1250 specific symbols --SKIPIF-- --CONFLICTS-- dir_cp1250 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_3.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_3.phpt index 2f3ae9afd608d..4c07d5a6de656 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_3.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_3.phpt @@ -2,12 +2,8 @@ Test fopen() for reading UTF-8 path with cp1250 specific symbols --SKIPIF-- --CONFLICTS-- file_cp1250 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_4.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_4.phpt index 8992a847eb507..9d2a13de2b949 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_4.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_4.phpt @@ -2,12 +2,8 @@ Test mkdir/rmdir UTF-8 path with cp1250 specific symbols --SKIPIF-- --CONFLICTS-- dir_cp1250 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_5.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_5.phpt index 392c486a767f7..4ed862f08b086 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_5.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1250_to_utf8_5.phpt @@ -2,12 +2,8 @@ Test fopen() for write to UTF-8 path with cp1250 specific symbols --SKIPIF-- --CONFLICTS-- dir_cp1250 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_0.phpt index bf30b4baeb040..7766d6dfd327e 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_0.phpt @@ -4,9 +4,8 @@ Test fopen() for reading CP1251 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_1.phpt index 0ea67f575e563..1ea343ae30ce1 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_1.phpt @@ -4,9 +4,8 @@ Test mkdir/rmdir CP1251 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_2.phpt index f65b38eafdad0..60a7dbf07fd89 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_2.phpt @@ -4,9 +4,8 @@ Test fopen() for write CP1251 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_0.phpt index 0cd657e94c596..6cb74e468eaeb 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_0.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for reading CP1251 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- file_cp1251 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_1.phpt index 6e53ff48c99d9..7776b908a8de9 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_1.phpt @@ -1,13 +1,11 @@ --TEST-- Test mkdir/rmdir CP1251 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir_cp1251 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_2.phpt index 95b75985c6188..90c9ddf01254c 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_to_utf8_2.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for write CP1251 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- file_cp1251 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_0.phpt index 8b800ed3bdeab..f962c5c0b0240 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_0.phpt @@ -7,12 +7,8 @@ zend.multibyte=1 zend.script_encoding=cp1251 --SKIPIF-- --CONFLICTS-- file_cp1251 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_1.phpt index 31db615f4d2c8..6d8a1f5d0050f 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_1.phpt @@ -7,12 +7,8 @@ zend.multibyte=1 zend.script_encoding=cp1251 --SKIPIF-- --CONFLICTS-- dir_cp1251 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_2.phpt index d6075da559c92..63745231771de 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1251_zend_multibyte_2.phpt @@ -7,12 +7,8 @@ zend.multibyte=1 zend.script_encoding=cp1251 --SKIPIF-- --CONFLICTS-- file_cp1251 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1252_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1252_0.phpt index f2671aa6054a5..aa3bc38dded21 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1252_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1252_0.phpt @@ -4,9 +4,8 @@ cp1252 cmd test diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_0.phpt index 45234243cee44..c7631eb601538 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_0.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for reading cp1252 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- file_cp1252 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_1.phpt index 5f5a6a78385a7..ea14608ad4c03 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_1.phpt @@ -1,13 +1,11 @@ --TEST-- Test mkdir/rmdir cp1252 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir_cp1252 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_2.phpt index 04baef95b0252..381b64eda6045 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_2.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for write cp1252 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir_cp1252 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_3.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_3.phpt index f6559253d2de4..ef441bcbbfddf 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_3.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_3.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for reading cp1252 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- file2_cp1252 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_4.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_4.phpt index a3359f686c1b3..739413dd74848 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_4.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_4.phpt @@ -1,13 +1,11 @@ --TEST-- Test mkdir/rmdir cp1252 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir2_cp1252 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_5.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_5.phpt index 42212d027126c..9cf7a31feea1b 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_5.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1252_to_utf8_5.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for write cp1252 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir2_cp1252 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1253_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1253_0.phpt index 93b63a536e839..11116849036b1 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1253_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1253_0.phpt @@ -4,9 +4,8 @@ Test fopen() for reading cp1253 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1253_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1253_1.phpt index 9ffdb11b2b83e..998ab348a0dc3 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1253_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1253_1.phpt @@ -4,9 +4,8 @@ Test mkdir/rmdir cp1253 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1253_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1253_2.phpt index 642e4aaabd194..01177620bd549 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1253_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1253_2.phpt @@ -4,9 +4,8 @@ Test fopen() for write cp1253 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_0.phpt index d12a174a7feaf..a592ed1f85bc6 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_0.phpt @@ -2,12 +2,8 @@ Test fopen() for reading cp1253 to UTF-8 path --SKIPIF-- --CONFLICTS-- file_cp1253 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_1.phpt index c84e9c95b3694..addc407f3e976 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_1.phpt @@ -2,12 +2,8 @@ Test mkdir/rmdir cp1253 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_cp1253 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_2.phpt index c0723d18b1228..cf88d95a4c696 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1253_to_utf8_2.phpt @@ -2,12 +2,8 @@ Test fopen() for write cp1253 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_cp1253 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1254_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1254_0.phpt index 77b52e0f1a2d6..83a413549ab31 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1254_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1254_0.phpt @@ -4,9 +4,8 @@ Test fopen() for reading cp1254 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1254_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1254_1.phpt index 82d74c750961b..9dc8225598358 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1254_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1254_1.phpt @@ -4,9 +4,8 @@ Test mkdir/rmdir cp1254 to UTF-8 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1254_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1254_2.phpt index f14a4c3de086e..2e386b3af45b9 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1254_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1254_2.phpt @@ -4,9 +4,8 @@ Test fopen() for write cp1254 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1254_3.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1254_3.phpt index 0e0e83d285a3b..076bf2eba50ea 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1254_3.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1254_3.phpt @@ -4,9 +4,8 @@ cp1254 cmd test diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_0.phpt index 211233de1c8e4..8dff7615dbfb5 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_0.phpt @@ -2,12 +2,8 @@ Test fopen() for reading cp1254 to UTF-8 path --SKIPIF-- --CONFLICTS-- file_cp1254 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_1.phpt index 42b241176ffb6..7b83cdbb395b3 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_1.phpt @@ -2,12 +2,8 @@ Test mkdir/rmdir cp1254 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_cp1254 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_2.phpt index b0c4f5ec83f0e..5ec63de4bc6e8 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_2.phpt @@ -2,12 +2,8 @@ Test fopen() for write cp1254 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_cp1254 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_3.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_3.phpt index 67549daf601d2..1e70dc8fe5b14 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_3.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1254_to_utf8_3.phpt @@ -2,12 +2,8 @@ cp1254 cmd test --SKIPIF-- --CONFLICTS-- file_cp1254 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1255_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1255_0.phpt index e9adaf843fb6a..61bb6b4155dc0 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1255_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1255_0.phpt @@ -4,9 +4,8 @@ Test fopen() for reading cp1255 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1255_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1255_1.phpt index 2cf42239267ad..a539ce8fd34e3 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1255_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1255_1.phpt @@ -4,9 +4,8 @@ Test mkdir/rmdir cp1255 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1255_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1255_2.phpt index e4779b721ba92..7fe2fecb7ea39 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1255_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1255_2.phpt @@ -4,9 +4,8 @@ Test fopen() for write cp1255 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_0.phpt index 1b65143553425..e8b35687e2fa8 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_0.phpt @@ -2,12 +2,8 @@ Test fopen() for reading cp1255 to UTF-8 path --SKIPIF-- --CONFLICTS-- file_cp1255 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_1.phpt index 356143ca7876a..48fa4f26a4b73 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_1.phpt @@ -2,12 +2,8 @@ Test mkdir/rmdir cp1255 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_cp1255 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_2.phpt index b378a7231d15e..358908ae56bd2 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1255_to_utf8_2.phpt @@ -2,12 +2,8 @@ Test fopen() for write cp1255 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_cp1255 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1256_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1256_0.phpt index 40910894b8ee7..9c0abe4c83269 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1256_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1256_0.phpt @@ -4,9 +4,8 @@ Test fopen() for reading cp1256 to UTF-8 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1256_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1256_1.phpt index 244758fe7bd67..f19bd04e9da98 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1256_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1256_1.phpt @@ -4,9 +4,8 @@ Test mkdir/rmdir cp1256 to UTF-8 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1256_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1256_2.phpt index f5b5db8935277..c734e24205d6a 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1256_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1256_2.phpt @@ -4,9 +4,8 @@ Test fopen() for write cp1256 to UTF-8 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_0.phpt index 901026f3899b0..9af7d83df2ad9 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_0.phpt @@ -2,12 +2,8 @@ Test fopen() for reading cp1256 to UTF-8 path --SKIPIF-- --CONFLICTS-- file_cp1256 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_1.phpt index b630f37648bc4..6da6d789e45ee 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_1.phpt @@ -2,12 +2,8 @@ Test mkdir/rmdir cp1256 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_cp1256 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_2.phpt index 6aa29f43c4268..2cce0b5411169 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp1256_to_utf8_2.phpt @@ -2,12 +2,8 @@ Test fopen() for write cp1256 to UTF-8 path --SKIPIF-- --CONFLICTS-- dir_cp1256 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp874_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp874_0.phpt index e8bc394a5d0d1..cbab58e84855c 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp874_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp874_0.phpt @@ -4,9 +4,8 @@ Thai cp874 basic test diff --git a/ext/standard/tests/file/windows_mb_path/test_cp874_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp874_1.phpt index 9d948d4023aa6..cd438c52f361e 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp874_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp874_1.phpt @@ -4,9 +4,8 @@ Thai cp874 cmd test diff --git a/ext/standard/tests/file/windows_mb_path/test_cp874_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp874_to_utf8_0.phpt index c21f124b6e195..b8ed1c23758a3 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp874_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp874_to_utf8_0.phpt @@ -2,12 +2,8 @@ Thai UTF-8 basic test --SKIPIF-- --FILE-- --CONFLICTS-- file_cp874 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp932_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp932_0.phpt index ccb273a94ce0f..d2a8e06a61cb0 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp932_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp932_0.phpt @@ -4,9 +4,8 @@ Test fopen() for reading cp932 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp932_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp932_1.phpt index 744d1a592be95..3f58aa5614f5c 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp932_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp932_1.phpt @@ -4,9 +4,8 @@ Test mkdir/rmdir cp932 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp932_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp932_2.phpt index 737a4d3eb869b..dc474cf9dff38 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp932_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp932_2.phpt @@ -4,9 +4,8 @@ Test fopen() for write to cp932 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp932_3.phpt b/ext/standard/tests/file/windows_mb_path/test_cp932_3.phpt index 4fdfb925a82db..d54d90e17beed 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp932_3.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp932_3.phpt @@ -4,9 +4,8 @@ cp932 cmd test diff --git a/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_0.phpt index df855aaca4e3b..925e0558ab26a 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_0.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for reading cp932 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- file_cp932 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_1.phpt index b9575302c8abc..8346c86a4d195 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_1.phpt @@ -1,13 +1,11 @@ --TEST-- Test mkdir/rmdir cp932 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir_cp932 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_2.phpt index 7c3870593692e..5d0f10f647acd 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp932_to_utf8_2.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for write cp932 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir_cp932 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp936_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp936_0.phpt index b1a4f8744f94c..3199aa979355e 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp936_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp936_0.phpt @@ -4,9 +4,8 @@ Test fopen() for reading cp936 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp936_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp936_1.phpt index 529808aad5fb2..8ee68392ff318 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp936_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp936_1.phpt @@ -4,9 +4,8 @@ Test mkdir/rmdir cp936 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp936_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp936_2.phpt index e872c05942a68..024e84d4317fc 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp936_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp936_2.phpt @@ -4,9 +4,8 @@ Test fopen() for write cp936 path diff --git a/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_0.phpt index 2797d25904f7f..39f989371968d 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_0.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for reading cp936 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- file_cp936 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_1.phpt index f9730b6fe9a08..7321ea0ed9d59 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_1.phpt @@ -1,13 +1,11 @@ --TEST-- Test mkdir/rmdir cp936 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir_cp936 diff --git a/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_2.phpt index 31ff1db318b84..8b3eb208f12fe 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cp936_to_utf8_2.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for write cp936 to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- file_cp936 diff --git a/ext/standard/tests/file/windows_mb_path/test_cwd_mb_names.phpt b/ext/standard/tests/file/windows_mb_path/test_cwd_mb_names.phpt index 3cb09f777d37f..9f9d1f24e6cdc 100644 --- a/ext/standard/tests/file/windows_mb_path/test_cwd_mb_names.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_cwd_mb_names.phpt @@ -2,15 +2,8 @@ Test chdir()/getcwd() with a dir for multibyte filenames --SKIPIF-- --CONFLICTS-- dir_mb @@ -24,8 +17,9 @@ $prefix = create_data("dir_mb"); $dirw = $prefix . DIRECTORY_SEPARATOR . "テストマルチバイト・パス42"; touch($dirw . DIRECTORY_SEPARATOR . "dummy.txt"); -$old_cp = get_active_cp(); -set_active_cp(65001); +$old_cp = sapi_windows_cp_get(); +sapi_windows_cp_set(65001); +echo "Active code page: ", sapi_windows_cp_get(), "\n"; $oldcwd = getcwd(); var_dump(chdir($dirw)); @@ -33,7 +27,7 @@ var_dump(getcwd()); var_dump(file_exists("dummy.txt")); -set_active_cp($old_cp); +sapi_windows_cp_set($old_cp); chdir($oldcwd); remove_data("dir_mb"); @@ -44,4 +38,3 @@ Active code page: 65001 bool(true) string(%d) "%s\テストマルチバイト・パス42" bool(true) -Active code page: %d diff --git a/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_0.phpt index 7a06f53b7dd0c..48f2443017d6c 100644 --- a/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_0.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for reading eucjp to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- file_eucjp diff --git a/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_1.phpt index e3111ba33af7e..922f9e8290644 100644 --- a/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_1.phpt @@ -1,13 +1,11 @@ --TEST-- Test mkdir/rmdir eucjp to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir_eucjp diff --git a/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_2.phpt index 9425a1cc1cea8..b4a9895428d53 100644 --- a/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_eucjp_to_utf8_2.phpt @@ -1,13 +1,11 @@ --TEST-- Test fopen() for write eucjp to UTF-8 path +--EXTENSIONS-- +iconv --SKIPIF-- --CONFLICTS-- dir_eucjp diff --git a/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_0.phpt b/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_0.phpt index 0840610c2058e..f3c4f18131fa7 100644 --- a/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_0.phpt @@ -2,12 +2,8 @@ Test fopen() for reading Kartuli UTF-8 path --SKIPIF-- --CONFLICTS-- file_kartuli diff --git a/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_1.phpt b/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_1.phpt index d348ccfd3c8fd..16f68f0f0ecb8 100644 --- a/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_1.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_1.phpt @@ -2,12 +2,8 @@ Test mkdir/rmdir Kartuli UTF-8 path --SKIPIF-- --CONFLICTS-- dir_kartuli diff --git a/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_2.phpt b/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_2.phpt index 2e57dc0c91fa0..ca6c887a24ed9 100644 --- a/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_2.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_2.phpt @@ -2,12 +2,8 @@ Test fopen() for write Kartuli UTF-8 path --SKIPIF-- --CONFLICTS-- dir_kartuli diff --git a/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_3.phpt b/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_3.phpt index 8d498d19907b1..e0984b0dd73bd 100644 --- a/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_3.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_kartuli_utf8_3.phpt @@ -2,12 +2,8 @@ Kartuli UTF-8 cmd test --SKIPIF-- --CONFLICTS-- file_kartuli diff --git a/ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt b/ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt index 6a5b60f08bbeb..daabfaad17fe4 100644 --- a/ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt @@ -4,12 +4,8 @@ Basic long path test mbstring --SKIPIF-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- 248 has be a long path --SKIPIF-- 260 || strlen($start) > 248) { +if (strlen($start) > 260 || strlen($start) < 248) { die("skip the starting path length is unsuitable for this test"); } diff --git a/ext/standard/tests/file/windows_mb_path/test_readdir_mb_names.phpt b/ext/standard/tests/file/windows_mb_path/test_readdir_mb_names.phpt index 84fe5e327335b..65a0dada9f4c4 100644 --- a/ext/standard/tests/file/windows_mb_path/test_readdir_mb_names.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_readdir_mb_names.phpt @@ -2,12 +2,8 @@ Test readdir() with a dir for multibyte filenames --SKIPIF-- --CONFLICTS-- mb_names @@ -38,8 +34,9 @@ create_verify_dir($prefix, "żółć"); $dirw = $prefix . DIRECTORY_SEPARATOR; -$old_cp = get_active_cp(); -set_active_cp(65001); +$old_cp = sapi_windows_cp_get(); +sapi_windows_cp_set(65001); +echo "Active code page: ", sapi_windows_cp_get(), "\n"; if (is_dir($dirw)) { if ($dh = opendir($dirw)) { @@ -51,12 +48,12 @@ if (is_dir($dirw)) { } else { echo "is_dir failed\n"; } -set_active_cp($old_cp); +sapi_windows_cp_set($old_cp); remove_data("mb_names"); ?> ---EXPECTF-- +--EXPECT-- Active code page: 65001 filename: . : filetype: dir filename: .. : filetype: dir @@ -76,4 +73,3 @@ filename: テストマルチバイト・パス : filetype: file filename: テストマルチバイト・パス42 : filetype: dir filename: 測試多字節路徑 : filetype: file filename: 測試多字節路徑5 : filetype: dir -Active code page: %d diff --git a/ext/standard/tests/file/windows_mb_path/test_rename_mb_names.phpt b/ext/standard/tests/file/windows_mb_path/test_rename_mb_names.phpt index 53dd1bd3ea862..ce040d1eda545 100644 --- a/ext/standard/tests/file/windows_mb_path/test_rename_mb_names.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_rename_mb_names.phpt @@ -2,62 +2,42 @@ Test rename() with a dir for multibyte filenames --SKIPIF-- --CONFLICTS-- file2_mb --FILE-- ---EXPECTF-- +--EXPECT-- Active code page: 65001 bool(true) string(21) "Ελλάδα_copy.txt" @@ -66,4 +46,3 @@ bool(true) string(27) "測試多字節路徑17.txt" bool(true) bool(true) -Active code page: %d diff --git a/ext/standard/tests/file/windows_mb_path/util.inc b/ext/standard/tests/file/windows_mb_path/util.inc index a26a66c01751b..c8f0f6c586cb3 100644 --- a/ext/standard/tests/file/windows_mb_path/util.inc +++ b/ext/standard/tests/file/windows_mb_path/util.inc @@ -1,36 +1,7 @@ --FILE-- +--EXTENSIONS-- +zlib --FILE-- +--EXTENSIONS-- +zlib --FILE-- datalen; + stream_bucket_append($out, $bucket); + } + return PSFS_PASS_ON; + } +} + +stream_filter_register("pass", "pass_filter"); +$fp = fopen("php://memory", "w"); +stream_filter_append($fp, "pass"); + +try { + fwrite($fp, "data"); +} catch (TypeError $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +try { + fclose($fp); +} catch (TypeError $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +unset($fp); // prevent cleanup at shutdown + +?> +--EXPECTF-- +Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d +TypeError: Cannot assign resource to property pass_filter::$stream of type int +TypeError: Cannot assign resource to property pass_filter::$stream of type int diff --git a/ext/standard/tests/filters/gh20370_dynamic_stream_property.phpt b/ext/standard/tests/filters/gh20370_dynamic_stream_property.phpt new file mode 100644 index 0000000000000..97f24b854c5ea --- /dev/null +++ b/ext/standard/tests/filters/gh20370_dynamic_stream_property.phpt @@ -0,0 +1,51 @@ +--TEST-- +GH-20370 (User filters should update dynamic stream property if it exists) +--FILE-- +stream = null; + return true; + } + + function filter($in, $out, &$consumed, $closing): int + { + while ($bucket = stream_bucket_make_writeable($in)) { + $consumed += $bucket->datalen; + stream_bucket_append($out, $bucket); + } + var_dump(property_exists($this, 'stream')); + if (is_resource($this->stream)) { + var_dump(get_resource_type($this->stream)); + } + return PSFS_PASS_ON; + } +} + +stream_filter_register("pass", "pass_filter"); +$fp = fopen("php://memory", "w"); +stream_filter_append($fp, "pass"); + +fwrite($fp, "data"); +rewind($fp); +echo fread($fp, 1024) . "\n"; + +?> +--EXPECTF-- +bool(true) +string(6) "stream" +bool(true) +string(6) "stream" +bool(true) +string(6) "stream" +bool(true) +string(6) "stream" +data +bool(true) diff --git a/ext/standard/tests/filters/gh20370_no_stream_property.phpt b/ext/standard/tests/filters/gh20370_no_stream_property.phpt new file mode 100644 index 0000000000000..1b52c4c4155b8 --- /dev/null +++ b/ext/standard/tests/filters/gh20370_no_stream_property.phpt @@ -0,0 +1,37 @@ +--TEST-- +GH-20370 (User filters should not create stream property if not declared) +--FILE-- +datalen; + stream_bucket_append($out, $bucket); + } + + var_dump(property_exists($this, 'stream')); + return PSFS_PASS_ON; + } +} + +stream_filter_register("pass", "pass_filter"); +$fp = fopen("php://memory", "w"); +stream_filter_append($fp, "pass"); +fwrite($fp, "data"); +rewind($fp); +echo fread($fp, 1024) . "\n"; + +?> +--EXPECT-- +bool(false) +bool(false) +bool(false) +bool(false) +data +bool(false) diff --git a/ext/standard/tests/filters/gh20370_private_stream_property.phpt b/ext/standard/tests/filters/gh20370_private_stream_property.phpt new file mode 100644 index 0000000000000..bfbbba6099ad0 --- /dev/null +++ b/ext/standard/tests/filters/gh20370_private_stream_property.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-20370 (User filters should handle private stream property correctly) +--FILE-- +datalen; + stream_bucket_append($out, $bucket); + } + return PSFS_PASS_ON; + } + + function onClose() + { + var_dump($this->stream); // should be null + } +} + +stream_filter_register("pass", "pass_filter"); +$fp = fopen("php://memory", "w"); +stream_filter_append($fp, "pass", STREAM_FILTER_WRITE); + +fwrite($fp, "data"); +rewind($fp); +echo fread($fp, 1024) . "\n"; + +?> +--EXPECT-- +data +NULL diff --git a/ext/standard/tests/streams/stream_filter_register.phpt b/ext/standard/tests/filters/stream_filter_register.phpt similarity index 100% rename from ext/standard/tests/streams/stream_filter_register.phpt rename to ext/standard/tests/filters/stream_filter_register.phpt diff --git a/ext/standard/tests/filters/stream_filter_register_class_coerce_consumed_by_ref_param.phpt b/ext/standard/tests/filters/stream_filter_register_class_coerce_consumed_by_ref_param.phpt new file mode 100644 index 0000000000000..f5f0ecca79751 --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_class_coerce_consumed_by_ref_param.phpt @@ -0,0 +1,32 @@ +--TEST-- +stream_filter_register() with a class that coerces the $consumed parameter of filter method +--XFAIL-- +This leaks memory +--FILE-- + +--EXPECTF-- +bool(true) +resource(4) of type (stream filter) + +Warning: Object of class stdClass could not be converted to int in %s on line %d + +Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d +int(1) + +Warning: Object of class stdClass could not be converted to int in Unknown on line 0 diff --git a/ext/standard/tests/filters/stream_filter_register_class_completely_invalid.phpt b/ext/standard/tests/filters/stream_filter_register_class_completely_invalid.phpt new file mode 100644 index 0000000000000..6bd3e7bc1c9dc --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_class_completely_invalid.phpt @@ -0,0 +1,33 @@ +--TEST-- +stream_filter_register() with a class name that exist but does not extend php_user_filter nor mock anything +--FILE-- + +--EXPECTF-- +bool(true) + +Deprecated: Creation of dynamic property foo::$filtername is deprecated in %s on line %d + +Deprecated: Creation of dynamic property foo::$params is deprecated in %s on line %d +resource(%d) of type (stream filter) + +Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d + +Fatal error: Uncaught Error: Invalid callback foo::filter, class foo does not have a method "filter" in %s:%d +Stack trace: +#0 %s(%d): fwrite(Resource id #%d, 'Hello\n') +#1 {main} + thrown in %s on line %d + +Fatal error: Invalid callback foo::filter, class foo does not have a method "filter" in Unknown on line 0 diff --git a/ext/standard/tests/filters/stream_filter_register_class_completely_invalid_filtername_prop_type.phpt b/ext/standard/tests/filters/stream_filter_register_class_completely_invalid_filtername_prop_type.phpt new file mode 100644 index 0000000000000..793c112791a99 --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_class_completely_invalid_filtername_prop_type.phpt @@ -0,0 +1,28 @@ +--TEST-- +stream_filter_register() with a class name exist but does not extend php_user_filter and defines a $filtername prop with different type +--FILE-- + +--EXPECTF-- +bool(true) + +Deprecated: Creation of dynamic property foo::$params is deprecated in %s on line %d + +Fatal error: Uncaught TypeError: Cannot assign string to property foo::$filtername of type array in %s:%d +Stack trace: +#0 %s(%d): stream_filter_append(Resource id #2, 'invalid_filter') +#1 {main} + thrown in %s on line %d + +Fatal error: Invalid callback foo::filter, class foo does not have a method "filter" in Unknown on line 0 diff --git a/ext/standard/tests/filters/stream_filter_register_class_completely_invalid_no_dynamic_props.phpt b/ext/standard/tests/filters/stream_filter_register_class_completely_invalid_no_dynamic_props.phpt new file mode 100644 index 0000000000000..86994d5c1b665 --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_class_completely_invalid_no_dynamic_props.phpt @@ -0,0 +1,28 @@ +--TEST-- +stream_filter_register() with a class name exist but does not extend php_user_filter and cannot have dynamic properties +--FILE-- + +--EXPECTF-- +bool(true) + +Fatal error: Uncaught Error: Cannot create dynamic property SensitiveParameter::$filtername in %s:%d +Stack trace: +#0 %s(%d): stream_filter_append(Resource id #%d, 'invalid_filter') +#1 {main} + +Next Error: Cannot create dynamic property SensitiveParameter::$params in %s:%d +Stack trace: +#0 %s(%d): stream_filter_append(Resource id #%d, 'invalid_filter') +#1 {main} + thrown in %s on line %d + +Fatal error: Invalid callback SensitiveParameter::filter, class SensitiveParameter does not have a method "filter" in Unknown on line 0 diff --git a/ext/standard/tests/filters/stream_filter_register_class_private_filtername_prop.phpt b/ext/standard/tests/filters/stream_filter_register_class_private_filtername_prop.phpt new file mode 100644 index 0000000000000..6b9be4bbbb4b7 --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_class_private_filtername_prop.phpt @@ -0,0 +1,28 @@ +--TEST-- +stream_filter_register() with a class name exist but does not extend php_user_filter and defines a private $filtername prop +--FILE-- + +--EXPECTF-- +bool(true) + +Deprecated: Creation of dynamic property foo::$params is deprecated in %s on line %d + +Fatal error: Uncaught Error: Cannot access private property foo::$filtername in %s:%d +Stack trace: +#0 %s(%d): stream_filter_append(Resource id #2, 'invalid_filter') +#1 {main} + thrown in %s on line %d + +Fatal error: Invalid callback foo::filter, class foo does not have a method "filter" in Unknown on line 0 diff --git a/ext/standard/tests/filters/stream_filter_register_class_throwing_onclose.phpt b/ext/standard/tests/filters/stream_filter_register_class_throwing_onclose.phpt new file mode 100644 index 0000000000000..76b925cc0483a --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_class_throwing_onclose.phpt @@ -0,0 +1,30 @@ +--TEST-- +stream_filter_register() with a class that has a onclose method that throws +--FILE-- + +--EXPECTF-- +bool(true) +resource(4) of type (stream filter) + +Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d +bool(false) + +Fatal error: Uncaught Exception: No in %s:%d +Stack trace: +#0 [internal function]: foo->onclose() +#1 {main} + thrown in %s on line %d diff --git a/ext/standard/tests/filters/stream_filter_register_class_throwing_oncreate.phpt b/ext/standard/tests/filters/stream_filter_register_class_throwing_oncreate.phpt new file mode 100644 index 0000000000000..3e429a2cc343a --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_class_throwing_oncreate.phpt @@ -0,0 +1,27 @@ +--TEST-- +stream_filter_register() with a class that has a oncreate method that throws +--FILE-- + +--EXPECTF-- +bool(true) + +Fatal error: Uncaught Exception: No in %s:%d +Stack trace: +#0 [internal function]: foo->oncreate() +#1 %s(%d): stream_filter_append(Resource id #2, 'invalid_filter') +#2 {main} + thrown in %s on line %d diff --git a/ext/standard/tests/filters/stream_filter_register_filter_always_feed.phpt b/ext/standard/tests/filters/stream_filter_register_filter_always_feed.phpt new file mode 100644 index 0000000000000..7a3d3f8899938 --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_filter_always_feed.phpt @@ -0,0 +1,24 @@ +--TEST-- +stream_filter_register() with a filter method always returning PSFS_FEED_ME +--FILE-- + +--EXPECTF-- +bool(true) +resource(4) of type (stream filter) + +Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d +int(0) diff --git a/ext/standard/tests/filters/stream_filter_register_mock_class_filter.phpt b/ext/standard/tests/filters/stream_filter_register_mock_class_filter.phpt new file mode 100644 index 0000000000000..4d2309a718eb5 --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_mock_class_filter.phpt @@ -0,0 +1,30 @@ +--TEST-- +stream_filter_register() with a class name exist that mocks php_user_filter with a filter method +--XFAIL-- +This leaks memory +--FILE-- + +--EXPECTF-- +bool(true) +resource(4) of type (stream filter) + +Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d +int(0) diff --git a/ext/standard/tests/filters/stream_filter_register_mock_class_filter_incorect_return_type.phpt b/ext/standard/tests/filters/stream_filter_register_mock_class_filter_incorect_return_type.phpt new file mode 100644 index 0000000000000..b5ec8da3dde1b --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_mock_class_filter_incorect_return_type.phpt @@ -0,0 +1,32 @@ +--TEST-- +stream_filter_register() with a class name exist that mocks php_user_filter with a filter method returning not an int +--FILE-- + +--EXPECTF-- +bool(true) +resource(4) of type (stream filter) + +Warning: Object of class stdClass could not be converted to int in %s on line %d + +Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d +int(0) + +Warning: Object of class stdClass could not be converted to int in Unknown on line 0 diff --git a/ext/standard/tests/filters/stream_filter_register_mock_class_filter_is_private.phpt b/ext/standard/tests/filters/stream_filter_register_mock_class_filter_is_private.phpt new file mode 100644 index 0000000000000..6abffe1ff5f80 --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_mock_class_filter_is_private.phpt @@ -0,0 +1,35 @@ +--TEST-- +stream_filter_register() with a class name exist that mocks php_user_filter with a private filter method +--FILE-- + +--EXPECTF-- +bool(true) +resource(%d) of type (stream filter) + +Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d + +Fatal error: Uncaught Error: Invalid callback foo::filter, cannot access private method foo::filter() in %s:%d +Stack trace: +#0 %s(%d): fwrite(Resource id #%d, 'Hello\n') +#1 {main} + thrown in %s on line %d + +Fatal error: Invalid callback foo::filter, cannot access private method foo::filter() in Unknown on line 0 diff --git a/ext/standard/tests/filters/stream_filter_register_non_existing_class.phpt b/ext/standard/tests/filters/stream_filter_register_non_existing_class.phpt new file mode 100644 index 0000000000000..1c08201cff0c5 --- /dev/null +++ b/ext/standard/tests/filters/stream_filter_register_non_existing_class.phpt @@ -0,0 +1,21 @@ +--TEST-- +stream_filter_register() with a class name that does not exist +--FILE-- + +--EXPECTF-- +bool(true) + +Warning: stream_filter_append(): User-filter "not_existing_filter" requires class "not_existing", but that class is not defined in %s on line %d + +Warning: stream_filter_append(): Unable to create or locate filter "not_existing_filter" in %s on line %d +Hello +int(6) diff --git a/ext/standard/tests/streams/stream_multi_filters_close.phpt b/ext/standard/tests/filters/stream_multi_filters_close.phpt similarity index 100% rename from ext/standard/tests/streams/stream_multi_filters_close.phpt rename to ext/standard/tests/filters/stream_multi_filters_close.phpt diff --git a/ext/standard/tests/streams/user_streams_consumed_bug.phpt b/ext/standard/tests/filters/user_streams_consumed_bug.phpt similarity index 100% rename from ext/standard/tests/streams/user_streams_consumed_bug.phpt rename to ext/standard/tests/filters/user_streams_consumed_bug.phpt diff --git a/ext/standard/tests/file/userfilters.phpt b/ext/standard/tests/filters/userfilters.phpt similarity index 100% rename from ext/standard/tests/file/userfilters.phpt rename to ext/standard/tests/filters/userfilters.phpt diff --git a/ext/standard/tests/gh20695.phpt b/ext/standard/tests/gh20695.phpt new file mode 100644 index 0000000000000..64c81ab9fdb54 --- /dev/null +++ b/ext/standard/tests/gh20695.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-20695 (Assertion failure in normalize_value() when parsing malformed INI input via parse_ini_string()) +--FILE-- + +--EXPECT-- +array(1) { + [8]=> + array(1) { + ["["]=> + int(0) + } +} diff --git a/ext/standard/tests/http/http_build_query/gh20583.phpt b/ext/standard/tests/http/http_build_query/gh20583.phpt new file mode 100644 index 0000000000000..5ea0dbe9006bc --- /dev/null +++ b/ext/standard/tests/http/http_build_query/gh20583.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-20583 (Stack overflow in http_build_query via deep structures) +--SKIPIF-- + +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- + $a]; +} +try { + http_build_query($a, 'p'); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Error: Maximum call stack size reached. diff --git a/ext/standard/tests/image/gh20582.phpt b/ext/standard/tests/image/gh20582.phpt new file mode 100644 index 0000000000000..63561534b2fd0 --- /dev/null +++ b/ext/standard/tests/image/gh20582.phpt @@ -0,0 +1,52 @@ +--TEST-- +GH-20582 (Heap Buffer Overflow in iptcembed) +--CREDITS-- +Nikita Sveshnikov (Positive Technologies) +ndossche +--SKIPIF-- + +--FILE-- + STDIN, + 1 => STDOUT, + 2 => STDOUT, +); +$pipes = []; +$proc = proc_open([PHP_BINARY, '-n', '-r', "var_dump(iptcembed('A', '$pipe'));"], $descriptorspec, $pipes); + +// Blocks until a reader opens it +$fp = fopen($pipe, 'wb') or die("Failed to open FIFO"); + +// Write header +$data = "\xFF\xD8"; // SOI marker +$data .= "\xFF\xE0\x00\x10"; // APP0 marker (JFIF) +$data .= "JFIF" . str_repeat("\x00", 9); +$data .= "\xFF\xDA\x00\x08"; // SOS marker +$data .= str_repeat("\x00", 6); +fwrite($fp, $data); + +// Write garbage +fwrite($fp, str_repeat("A", 5120)); + +fclose($fp); + +?> +--CLEAN-- + +--EXPECTF-- +string(1055) "����%0JFIF%0%0%0%0%0%0%0%0%0���%0Photoshop 3.0%08BIM%0%0%0%0%0A%0�%0%0%0%0%0%0%0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" diff --git a/ext/standard/tests/image/gh20584.phpt b/ext/standard/tests/image/gh20584.phpt new file mode 100644 index 0000000000000..d117f21820264 --- /dev/null +++ b/ext/standard/tests/image/gh20584.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-20584 (Information Leak of Memory) +--CREDITS-- +Nikita Sveshnikov (Positive Technologies) +--FILE-- + +--CLEAN-- + +--EXPECT-- +bool(true) diff --git a/ext/standard/tests/mail/gh20776.phpt b/ext/standard/tests/mail/gh20776.phpt new file mode 100644 index 0000000000000..aec68c4719202 --- /dev/null +++ b/ext/standard/tests/mail/gh20776.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-20776: mail() memory leak when header array contains numeric keys +--FILE-- + 'Value', 5 => 'invalid key'])); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +?> +--EXPECT-- +TypeError: Header name cannot be numeric, 5 given diff --git a/ext/standard/tests/math/clamp.phpt b/ext/standard/tests/math/clamp.phpt new file mode 100644 index 0000000000000..beb4c8d53148d --- /dev/null +++ b/ext/standard/tests/math/clamp.phpt @@ -0,0 +1,104 @@ +--TEST-- +clamp() tests +--INI-- +precision=14 +date.timezone=UTC +zend.assertions=1 +--FILE-- +getMessage(), "\n"; + } + + try { + var_dump(make_clamp_fcc()($value, $min, $max)); + } catch (ValueError $error) { + echo $error->getMessage(), "\n"; + } +} + +var_dump(check_clamp_result(2, 1, 3)); +var_dump(check_clamp_result(0, 1, 3)); +var_dump(check_clamp_result(6, 1, 3)); +var_dump(check_clamp_result(2, 1.3, 3.4)); +var_dump(check_clamp_result(2.5, 1, 3)); +var_dump(check_clamp_result(2.5, 1.3, 3.4)); +var_dump(check_clamp_result(0, 1.3, 3.4)); +var_dump(check_clamp_result(M_PI, -INF, INF)); +var_dump(check_clamp_result(NAN, 4, 6)); +var_dump(check_clamp_result("a", "c", "g")); +var_dump(check_clamp_result("d", "c", "g")); +echo check_clamp_result('2025-08-01', '2025-08-15', '2025-09-15'), "\n"; +echo check_clamp_result('2025-08-20', '2025-08-15', '2025-09-15'), "\n"; +echo check_clamp_result(new \DateTimeImmutable('2025-08-01'), new \DateTimeImmutable('2025-08-15'), new \DateTimeImmutable('2025-09-15'))->format('Y-m-d'), "\n"; +echo check_clamp_result(new \DateTimeImmutable('2025-08-20'), new \DateTimeImmutable('2025-08-15'), new \DateTimeImmutable('2025-09-15'))->format('Y-m-d'), "\n"; +var_dump(check_clamp_result(null, -1, 1)); +var_dump(check_clamp_result(null, 1, 3)); +var_dump(check_clamp_result(null, -3, -1)); +var_dump(check_clamp_result(-9999, null, 10)); +var_dump(check_clamp_result(12, null, 10)); + +$a = new \InvalidArgumentException('a'); +$b = new \RuntimeException('b'); +$c = new \LogicException('c'); +echo check_clamp_result($a, $b, $c)::class, "\n"; +echo check_clamp_result($b, $a, $c)::class, "\n"; +echo check_clamp_result($c, $a, $b)::class, "\n"; + +check_clamp_exception(4, NAN, 6); +check_clamp_exception(7, 6, NAN); +check_clamp_exception(1, 3, 2); +check_clamp_exception(-9999, 5, null); +check_clamp_exception(12, -5, null); + +?> +--EXPECT-- +int(2) +int(1) +int(3) +int(2) +float(2.5) +float(2.5) +float(1.3) +float(3.141592653589793) +float(NAN) +string(1) "c" +string(1) "d" +2025-08-15 +2025-08-20 +2025-08-15 +2025-08-20 +int(-1) +int(1) +int(-3) +int(-9999) +int(10) +InvalidArgumentException +RuntimeException +LogicException +clamp(): Argument #2 ($min) must not be NAN +clamp(): Argument #2 ($min) must not be NAN +clamp(): Argument #3 ($max) must not be NAN +clamp(): Argument #3 ($max) must not be NAN +clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max) +clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max) +clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max) +clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max) +clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max) +clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max) diff --git a/ext/standard/tests/network/ghsa-www2-q4fc-65wf.phpt b/ext/standard/tests/network/ghsa-www2-q4fc-65wf.phpt new file mode 100644 index 0000000000000..3d082c8e95226 --- /dev/null +++ b/ext/standard/tests/network/ghsa-www2-q4fc-65wf.phpt @@ -0,0 +1,62 @@ +--TEST-- +GHSA-www2-q4fc-65wf +--DESCRIPTION-- +This is a ZPP test but *keep* this as it is security-sensitive! +--FILE-- +getMessage(), "\n"; +} +try { + dns_get_mx("\0", $out); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + dns_get_record("\0"); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + getprotobyname("\0"); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + getservbyname("\0", "tcp"); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + getservbyname("x", "tcp\0"); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + getservbyport(0, "tcp\0"); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + inet_pton("\0"); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + ip2long("\0"); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +dns_check_record(): Argument #1 ($hostname) must not contain any null bytes +dns_get_mx(): Argument #1 ($hostname) must not contain any null bytes +dns_get_record(): Argument #1 ($hostname) must not contain any null bytes +getprotobyname(): Argument #1 ($protocol) must not contain any null bytes +getservbyname(): Argument #1 ($service) must not contain any null bytes +getservbyname(): Argument #2 ($protocol) must not contain any null bytes +getservbyport(): Argument #2 ($protocol) must not contain any null bytes +inet_pton(): Argument #1 ($ip) must not contain any null bytes +ip2long(): Argument #1 ($ip) must not contain any null bytes diff --git a/ext/standard/tests/streams/gh20286.phpt b/ext/standard/tests/streams/gh20286.phpt new file mode 100644 index 0000000000000..6d15e167aee90 --- /dev/null +++ b/ext/standard/tests/streams/gh20286.phpt @@ -0,0 +1,43 @@ +--TEST-- +GH-20286 use after destroy on userland stream_close +--CREDITS-- +vi3tL0u1s +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Fatal error: Cannot redeclare function a() (previously declared in %s:%d) in %s on line %d + +Fatal error: Cannot redeclare function a() (previously declared in %s:%d) in %s on line %d + +Fatal error: Cannot redeclare function a() (previously declared in %s:%d) in %s on line %d + +Fatal error: Cannot redeclare function a() (previously declared in %s:%d) in %s on line %d diff --git a/ext/standard/tests/strings/gh18823_strict.phpt b/ext/standard/tests/strings/gh18823_strict.phpt index 80b21d2093172..3735eab006707 100644 --- a/ext/standard/tests/strings/gh18823_strict.phpt +++ b/ext/standard/tests/strings/gh18823_strict.phpt @@ -15,5 +15,5 @@ try { } ?> --EXPECT-- -setlocale(): Argument #2 ($locales) must be of type array|string, int given -setlocale(): Argument #3 must be of type array|string, int given +setlocale(): Argument #2 ($locales) must be of type array|string|null, int given +setlocale(): Argument #3 must be of type array|string|null, int given diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index 40ad6a5da37d2..da8260dfd6de3 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -148,14 +148,31 @@ static php_stream_filter_status_t userfilter_filter( uint32_t orig_no_fclose = stream->flags & PHP_STREAM_FLAG_NO_FCLOSE; stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; - zval *stream_prop = zend_hash_str_find_ind(Z_OBJPROP_P(obj), "stream", sizeof("stream")-1); - if (stream_prop) { - /* Give the userfilter class a hook back to the stream */ - zval_ptr_dtor(stream_prop); - php_stream_to_zval(stream, stream_prop); - Z_ADDREF_P(stream_prop); + /* Give the userfilter class a hook back to the stream */ + const zend_class_entry *old_scope = EG(fake_scope); + EG(fake_scope) = Z_OBJCE_P(obj); + + zend_string *stream_name = ZSTR_INIT_LITERAL("stream", 0); + bool stream_property_exists = Z_OBJ_HT_P(obj)->has_property(Z_OBJ_P(obj), stream_name, ZEND_PROPERTY_EXISTS, NULL); + if (stream_property_exists) { + zval stream_zval; + php_stream_to_zval(stream, &stream_zval); + zend_update_property_ex(Z_OBJCE_P(obj), Z_OBJ_P(obj), stream_name, &stream_zval); + /* If property update threw an exception, skip filter execution */ + if (EG(exception)) { + EG(fake_scope) = old_scope; + if (buckets_in->head) { + php_error_docref(NULL, E_WARNING, "Unprocessed filter buckets remaining on input brigade"); + } + zend_string_release(stream_name); + stream->flags &= ~PHP_STREAM_FLAG_NO_FCLOSE; + stream->flags |= orig_no_fclose; + return PSFS_ERR_FATAL; + } } + EG(fake_scope) = old_scope; + ZVAL_STRINGL(&func_name, "filter", sizeof("filter")-1); /* Setup calling arguments */ @@ -196,11 +213,16 @@ static php_stream_filter_status_t userfilter_filter( /* filter resources are cleaned up by the stream destructor, * keeping a reference to the stream resource here would prevent it - * from being destroyed properly */ - if (stream_prop) { - convert_to_null(stream_prop); + * from being destroyed properly. + * Since the property accepted a resource assignment above, it must have + * no type hint or be typed as mixed, so we can safely assign null. + */ + if (stream_property_exists) { + zend_update_property_null(Z_OBJCE_P(obj), Z_OBJ_P(obj), ZSTR_VAL(stream_name), ZSTR_LEN(stream_name)); } + zend_string_release(stream_name); + zval_ptr_dtor(&args[3]); zval_ptr_dtor(&args[2]); zval_ptr_dtor(&args[1]); diff --git a/ext/uri/config.m4 b/ext/uri/config.m4 index 99e0d6b476779..390d8eb223cb9 100644 --- a/ext/uri/config.m4 +++ b/ext/uri/config.m4 @@ -33,7 +33,7 @@ if test "$PHP_EXTERNAL_URIPARSER" = "no"; then $URIPARSER_DIR/src/UriSetScheme.c $URIPARSER_DIR/src/UriSetUserInfo.c $URIPARSER_DIR/src/UriShorten.c $URIPARSER_DIR/src/UriVersion.c" URI_CFLAGS="-DURI_STATIC_BUILD" else - PKG_CHECK_MODULES([LIBURIPARSER], [liburiparser >= 0.9.10]) + PKG_CHECK_MODULES([LIBURIPARSER], [liburiparser >= 1.0.0]) PHP_EVAL_LIBLINE([$LIBURIPARSER_LIBS], [URI_SHARED_LIBADD]) PHP_EVAL_INCLINE([$LIBURIPARSER_CFLAGS]) fi diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index 4a1207de89942..77fc627b6a99d 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -30,7 +30,7 @@ #include "uri_parser_rfc3986.h" #include "uri_parser_php_parse_url.h" #include "php_uri_arginfo.h" -#include "uriparser/UriBase.h" +#include "uriparser/Uri.h" zend_class_entry *php_uri_ce_rfc3986_uri; zend_class_entry *php_uri_ce_whatwg_url; @@ -377,7 +377,7 @@ static void create_rfc3986_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor zend_object *base_url_object = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_PATH_STR(uri_str) + Z_PARAM_STR(uri_str) Z_PARAM_OPTIONAL Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, php_uri_ce_rfc3986_uri) ZEND_PARSE_PARAMETERS_END(); @@ -490,7 +490,7 @@ static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor) zval *errors = NULL; ZEND_PARSE_PARAMETERS_START(1, 3) - Z_PARAM_PATH_STR(uri_str) + Z_PARAM_STR(uri_str) Z_PARAM_OPTIONAL Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, php_uri_ce_whatwg_url) Z_PARAM_ZVAL(errors) @@ -553,7 +553,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, withUserInfo) zend_string *value; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR_OR_NULL(value) + Z_PARAM_STR_OR_NULL(value) ZEND_PARSE_PARAMETERS_END(); zval zv; @@ -769,7 +769,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, resolve) zend_string *uri_str; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR(uri_str) + Z_PARAM_STR(uri_str) ZEND_PARSE_PARAMETERS_END(); php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, @@ -956,7 +956,7 @@ PHP_METHOD(Uri_WhatWg_Url, resolve) zval *errors = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_PATH_STR(uri_str) + Z_PARAM_STR(uri_str) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(errors) ZEND_PARSE_PARAMETERS_END(); diff --git a/ext/uri/php_uri_common.c b/ext/uri/php_uri_common.c index 780cc95074159..da73bc59bf9cf 100644 --- a/ext/uri/php_uri_common.c +++ b/ext/uri/php_uri_common.c @@ -96,7 +96,7 @@ void php_uri_property_write_str_helper(INTERNAL_FUNCTION_PARAMETERS, php_uri_pro zend_string *value; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR(value) + Z_PARAM_STR(value) ZEND_PARSE_PARAMETERS_END(); zval zv; @@ -110,7 +110,7 @@ void php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAMETERS, php zend_string *value; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR_OR_NULL(value) + Z_PARAM_STR_OR_NULL(value) ZEND_PARSE_PARAMETERS_END(); zval zv; diff --git a/ext/uri/tests/035.phpt b/ext/uri/tests/035.phpt deleted file mode 100644 index 3c39870373742..0000000000000 --- a/ext/uri/tests/035.phpt +++ /dev/null @@ -1,39 +0,0 @@ ---TEST-- -Test URI parsing containing null bytes ---EXTENSIONS-- -uri ---FILE-- -getMessage() . "\n"; -} - -$uri = new Uri\Rfc3986\Uri("https://example.com"); -try { - $uri->withHost("exam\0ple.com"); -} catch (Error $e) { - echo $e->getMessage() . "\n"; -} - -try { - new Uri\WhatWg\Url("https://exam\0ple.com"); -} catch (Error $e) { - echo $e->getMessage() . "\n"; -} - -$url = new Uri\WhatWg\Url("https://example.com"); -try { - $url->withHost("exam\0ple.com"); -} catch (Error $e) { - echo $e->getMessage() . "\n"; -} - -?> ---EXPECT-- -Uri\Rfc3986\Uri::__construct(): Argument #1 ($uri) must not contain any null bytes -Uri\Rfc3986\Uri::withHost(): Argument #1 ($host) must not contain any null bytes -Uri\WhatWg\Url::__construct(): Argument #1 ($uri) must not contain any null bytes -Uri\WhatWg\Url::withHost(): Argument #1 ($host) must not contain any null bytes diff --git a/ext/uri/tests/rfc3986/modification/host_success_unset_existing.phpt b/ext/uri/tests/rfc3986/modification/host_success_unset_existing.phpt index 521b6397ec450..8f79d723be5dd 100644 --- a/ext/uri/tests/rfc3986/modification/host_success_unset_existing.phpt +++ b/ext/uri/tests/rfc3986/modification/host_success_unset_existing.phpt @@ -18,6 +18,6 @@ var_dump($uri2->toString()); --EXPECT-- string(11) "example.com" NULL -string(7) "https:/" +string(6) "https:" NULL -string(7) "https:/" +string(6) "https:" diff --git a/ext/uri/tests/rfc3986/modification/path_error_null_byte.phpt b/ext/uri/tests/rfc3986/modification/path_error_null_byte.phpt new file mode 100644 index 0000000000000..d02e3e8575f2d --- /dev/null +++ b/ext/uri/tests/rfc3986/modification/path_error_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\Rfc3986\Uri component modification - path - null byte +--EXTENSIONS-- +uri +--FILE-- +withPath("/\0foo"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\InvalidUriException: The specified path is malformed diff --git a/ext/uri/tests/rfc3986/parsing/basic_error_null_byte1.phpt b/ext/uri/tests/rfc3986/parsing/basic_error_null_byte.phpt similarity index 63% rename from ext/uri/tests/rfc3986/parsing/basic_error_null_byte1.phpt rename to ext/uri/tests/rfc3986/parsing/basic_error_null_byte.phpt index 5695b8487cd34..91d194e2ff5e5 100644 --- a/ext/uri/tests/rfc3986/parsing/basic_error_null_byte1.phpt +++ b/ext/uri/tests/rfc3986/parsing/basic_error_null_byte.phpt @@ -5,10 +5,10 @@ Test Uri\Rfc3986\Uri parsing - basic - URI contains null byte try { new Uri\Rfc3986\Uri("https://exam\0ple.com"); -} catch (ValueError $e) { +} catch (Throwable $e) { echo $e::class, ": ", $e->getMessage(), PHP_EOL; } ?> --EXPECT-- -ValueError: Uri\Rfc3986\Uri::__construct(): Argument #1 ($uri) must not contain any null bytes +Uri\InvalidUriException: The specified URI is malformed diff --git a/ext/uri/tests/rfc3986/parsing/basic_error_null_byte2.phpt b/ext/uri/tests/rfc3986/parsing/basic_error_null_byte2.phpt deleted file mode 100644 index 85c779cc5aff7..0000000000000 --- a/ext/uri/tests/rfc3986/parsing/basic_error_null_byte2.phpt +++ /dev/null @@ -1,14 +0,0 @@ ---TEST-- -Test Uri\Rfc3986\Uri parsing - basic - URI contains null byte ---FILE-- -getMessage(), PHP_EOL; -} - -?> ---EXPECT-- -ValueError: Uri\Rfc3986\Uri::parse(): Argument #1 ($uri) must not contain any null bytes diff --git a/ext/uri/tests/rfc3986/reference_resolution/resolve_error_null_byte.phpt b/ext/uri/tests/rfc3986/reference_resolution/resolve_error_null_byte.phpt new file mode 100644 index 0000000000000..16b2f61dce78b --- /dev/null +++ b/ext/uri/tests/rfc3986/reference_resolution/resolve_error_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\Rfc3986\Uri reference resolution - resolve() - null byte +--EXTENSIONS-- +uri +--FILE-- +resolve("/f\0o"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\InvalidUriException: The specified URI is malformed diff --git a/ext/uri/tests/whatwg/getters/gh20771.phpt b/ext/uri/tests/whatwg/getters/gh20771.phpt new file mode 100644 index 0000000000000..19f1d1fb0f500 --- /dev/null +++ b/ext/uri/tests/whatwg/getters/gh20771.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-20771 (Assertion failure when getUnicodeHost() returns empty string) +--EXTENSIONS-- +uri +--FILE-- +getUnicodeHost()); + +?> +--EXPECT-- +string(0) "" diff --git a/ext/uri/tests/whatwg/modification/fragment_success_hashmark.phpt b/ext/uri/tests/whatwg/modification/fragment_success_hashmark.phpt index 12ce6d6e6b64d..4639d993df04d 100644 --- a/ext/uri/tests/whatwg/modification/fragment_success_hashmark.phpt +++ b/ext/uri/tests/whatwg/modification/fragment_success_hashmark.phpt @@ -15,5 +15,5 @@ var_dump($url2->toAsciiString()); ?> --EXPECT-- NULL -NULL +string(0) "" string(21) "https://example.com/#" diff --git a/ext/uri/tests/whatwg/modification/fragment_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/fragment_success_null_byte.phpt new file mode 100644 index 0000000000000..faaf41796c746 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/fragment_success_null_byte.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - fragment - null byte +--EXTENSIONS-- +uri +--FILE-- +withFragment("frag\0ment"); + +var_dump($url1->getFragment()); +var_dump($url2->getFragment()); +var_dump($url2->toAsciiString()); + +?> +--EXPECT-- +NULL +string(11) "frag%00ment" +string(32) "https://example.com/#frag%00ment" diff --git a/ext/uri/tests/whatwg/modification/host_error_null_byte.phpt b/ext/uri/tests/whatwg/modification/host_error_null_byte.phpt new file mode 100644 index 0000000000000..84a6bc1ebdbc6 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/host_error_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - host - null byte +--EXTENSIONS-- +uri +--FILE-- +withHost("h\0st"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\WhatWg\InvalidUrlException: The specified host is malformed (DomainInvalidCodePoint) diff --git a/ext/uri/tests/whatwg/modification/password_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/password_success_null_byte.phpt new file mode 100644 index 0000000000000..2216fa4e8e845 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/password_success_null_byte.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - password - null byte +--EXTENSIONS-- +uri +--FILE-- +withPassword("pass\0word"); + +var_dump($url1->getPassword()); +var_dump($url2->getPassword()); +var_dump($url2->toAsciiString()); + + +?> +--EXPECT-- +NULL +string(11) "pass%00word" +string(33) "https://:pass%00word@example.com/" diff --git a/ext/uri/tests/whatwg/modification/path_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/path_success_null_byte.phpt new file mode 100644 index 0000000000000..c09a3aa2810f4 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/path_success_null_byte.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - path - null byte +--EXTENSIONS-- +uri +--FILE-- +withPath("/p\0th\0"); + +var_dump($url1->getPath()); +var_dump($url2->getPath()); +var_dump($url2->toAsciiString()); + +?> +--EXPECT-- +string(1) "/" +string(10) "/p%00th%00" +string(29) "https://example.com/p%00th%00" diff --git a/ext/uri/tests/whatwg/modification/query_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/query_success_null_byte.phpt new file mode 100644 index 0000000000000..81232d8b2aa2d --- /dev/null +++ b/ext/uri/tests/whatwg/modification/query_success_null_byte.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - query - null byte +--EXTENSIONS-- +uri +--FILE-- +withQuery("f\0o=bar&baz=q\0x"); + +var_dump($url1->getQuery()); +var_dump($url2->getQuery()); +var_dump($url2->toAsciiString()); + +?> +--EXPECT-- +NULL +string(19) "f%00o=bar&baz=q%00x" +string(40) "https://example.com/?f%00o=bar&baz=q%00x" diff --git a/ext/uri/tests/whatwg/modification/query_success_question_mark.phpt b/ext/uri/tests/whatwg/modification/query_success_question_mark.phpt index 18a1593a9819a..3e1bf5ab9dce5 100644 --- a/ext/uri/tests/whatwg/modification/query_success_question_mark.phpt +++ b/ext/uri/tests/whatwg/modification/query_success_question_mark.phpt @@ -15,5 +15,5 @@ var_dump($url2->toAsciiString()); ?> --EXPECT-- NULL -NULL +string(0) "" string(21) "https://example.com/?" diff --git a/ext/uri/tests/whatwg/modification/scheme_error_null_byte.phpt b/ext/uri/tests/whatwg/modification/scheme_error_null_byte.phpt new file mode 100644 index 0000000000000..ab2845ae64937 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/scheme_error_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - scheme - null byte +--EXTENSIONS-- +uri +--FILE-- +withScheme("sch\0me"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\WhatWg\InvalidUrlException: The specified scheme is malformed diff --git a/ext/uri/tests/whatwg/modification/username_success_null_byte.phpt b/ext/uri/tests/whatwg/modification/username_success_null_byte.phpt new file mode 100644 index 0000000000000..86f6a62e0f200 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/username_success_null_byte.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\WhatWg\Url component modification - username - null byte +--EXTENSIONS-- +uri +--FILE-- +withUsername("usern\0me"); + +var_dump($url1->getUsername()); +var_dump($url2->getUsername()); +var_dump($url2->toAsciiString()); + + +?> +--EXPECT-- +NULL +string(10) "usern%00me" +string(31) "https://usern%00me@example.com/" diff --git a/ext/uri/tests/whatwg/parsing/basic_error_null_byte2.phpt b/ext/uri/tests/whatwg/parsing/basic_error_null_byte2.phpt deleted file mode 100644 index 6aa631c74e93e..0000000000000 --- a/ext/uri/tests/whatwg/parsing/basic_error_null_byte2.phpt +++ /dev/null @@ -1,14 +0,0 @@ ---TEST-- -Test Uri\WhatWg\Url parsing - basic - URL contains null byte ---FILE-- -getMessage(), PHP_EOL; -} - -?> ---EXPECT-- -ValueError: Uri\WhatWg\Url::parse(): Argument #1 ($uri) must not contain any null bytes diff --git a/ext/uri/tests/whatwg/parsing/basic_error_null_byte1.phpt b/ext/uri/tests/whatwg/parsing/host_error_null_byte.phpt similarity index 63% rename from ext/uri/tests/whatwg/parsing/basic_error_null_byte1.phpt rename to ext/uri/tests/whatwg/parsing/host_error_null_byte.phpt index db5cd075a6fa0..f450d26c41648 100644 --- a/ext/uri/tests/whatwg/parsing/basic_error_null_byte1.phpt +++ b/ext/uri/tests/whatwg/parsing/host_error_null_byte.phpt @@ -5,10 +5,10 @@ Test Uri\WhatWg\Url parsing - basic - URL contains null byte try { new Uri\WhatWg\Url("https://exam\0ple.com"); -} catch (ValueError $e) { +} catch (Throwable $e) { echo $e::class, ": ", $e->getMessage(), PHP_EOL; } ?> --EXPECT-- -ValueError: Uri\WhatWg\Url::__construct(): Argument #1 ($uri) must not contain any null bytes +Uri\WhatWg\InvalidUrlException: The specified URI is malformed (DomainInvalidCodePoint) diff --git a/ext/uri/tests/whatwg/parsing/password_success_null_byte.phpt b/ext/uri/tests/whatwg/parsing/password_success_null_byte.phpt new file mode 100644 index 0000000000000..9dada6a9f387e --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/password_success_null_byte.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - password - null byte +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + string(8) "username" + ["password"]=> + string(7) "%00pass" + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(37) "https://username:%00pass@example.com/" diff --git a/ext/uri/tests/whatwg/parsing/path_success_null_byte.phpt b/ext/uri/tests/whatwg/parsing/path_success_null_byte.phpt new file mode 100644 index 0000000000000..d20242dcee53a --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/path_success_null_byte.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - path - null byte +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(8) "/pa%00th" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(27) "https://example.com/pa%00th" diff --git a/ext/uri/tests/whatwg/parsing/query_success_null_byte.phpt b/ext/uri/tests/whatwg/parsing/query_success_null_byte.phpt new file mode 100644 index 0000000000000..bf1364365156b --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/query_success_null_byte.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - query - null byte +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + string(9) "fo%00=bar" + ["fragment"]=> + NULL +} +string(30) "https://example.com/?fo%00=bar" diff --git a/ext/uri/tests/whatwg/parsing/scheme_error_null_byte.phpt b/ext/uri/tests/whatwg/parsing/scheme_error_null_byte.phpt new file mode 100644 index 0000000000000..5674c1f330932 --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/scheme_error_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - scheme - null byte +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\WhatWg\InvalidUrlException: The specified URI is malformed (MissingSchemeNonRelativeUrl) diff --git a/ext/uri/tests/whatwg/parsing/username_success_null_byte.phpt b/ext/uri/tests/whatwg/parsing/username_success_null_byte.phpt new file mode 100644 index 0000000000000..d99c3cefdc153 --- /dev/null +++ b/ext/uri/tests/whatwg/parsing/username_success_null_byte.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url parsing - username - null byte +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + string(11) "user%00name" + ["password"]=> + string(4) "pass" + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(37) "https://user%00name:pass@example.com/" diff --git a/ext/uri/tests/whatwg/reference_resolution/resolve_error_host_null_byte.phpt b/ext/uri/tests/whatwg/reference_resolution/resolve_error_host_null_byte.phpt new file mode 100644 index 0000000000000..ed31e0e5daead --- /dev/null +++ b/ext/uri/tests/whatwg/reference_resolution/resolve_error_host_null_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\WhatWg\Url reference resolution - resolve() - null byte +--EXTENSIONS-- +uri +--FILE-- +resolve("https://ex\0mple.com"); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Uri\WhatWg\InvalidUrlException: The specified URI is malformed (DomainInvalidCodePoint) diff --git a/ext/uri/tests/whatwg/reference_resolution/resolve_success_path_null_byte.phpt b/ext/uri/tests/whatwg/reference_resolution/resolve_success_path_null_byte.phpt new file mode 100644 index 0000000000000..abdcec98e8421 --- /dev/null +++ b/ext/uri/tests/whatwg/reference_resolution/resolve_success_path_null_byte.phpt @@ -0,0 +1,53 @@ +--TEST-- +Test Uri\WhatWg\Url reference resolution - resolve() - null byte in path +--EXTENSIONS-- +uri +--FILE-- +resolve("/f\0o"); + +var_dump($url1); +var_dump($url2); +var_dump($url2->toAsciiString()); + +?> +--EXPECT-- +object(Uri\WhatWg\Url)#1 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#2 (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(6) "/f%00o" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(25) "https://example.com/f%00o" diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index ef9bf0e020c34..055f130af7c65 100644 --- a/ext/uri/uri_parser_whatwg.c +++ b/ext/uri/uri_parser_whatwg.c @@ -365,7 +365,7 @@ static zend_result php_uri_parser_whatwg_host_read(void *uri, php_uri_component_ lxb_url_serialize_host_unicode(&lexbor_idna, &lexbor_uri->host, serialize_to_smart_str_callback, &host_str); lxb_unicode_idna_clean(&lexbor_idna); - ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); + ZVAL_STR(retval, smart_str_extract(&host_str)); break; } case PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII: @@ -431,7 +431,7 @@ static zend_result php_uri_parser_whatwg_path_read(void *uri, php_uri_component_ { const lxb_url_t *lexbor_uri = uri; - if (lexbor_uri->path.str.length) { + if (lexbor_uri->path.str.length > 0) { ZVAL_STRINGL(retval, (const char *) lexbor_uri->path.str.data, lexbor_uri->path.str.length); } else { ZVAL_EMPTY_STRING(retval); @@ -460,7 +460,7 @@ static zend_result php_uri_parser_whatwg_query_read(void *uri, php_uri_component { const lxb_url_t *lexbor_uri = uri; - if (lexbor_uri->query.length) { + if (lexbor_uri->query.data != NULL) { ZVAL_STRINGL(retval, (const char *) lexbor_uri->query.data, lexbor_uri->query.length); } else { ZVAL_NULL(retval); @@ -489,7 +489,7 @@ static zend_result php_uri_parser_whatwg_fragment_read(void *uri, php_uri_compon { const lxb_url_t *lexbor_uri = uri; - if (lexbor_uri->fragment.length) { + if (lexbor_uri->fragment.data != NULL) { ZVAL_STRINGL(retval, (const char *) lexbor_uri->fragment.data, lexbor_uri->fragment.length); } else { ZVAL_NULL(retval); diff --git a/ext/uri/uriparser/include/uriparser/Uri.h b/ext/uri/uriparser/include/uriparser/Uri.h index fbdb3d9a3798e..88976a4846271 100644 --- a/ext/uri/uriparser/include/uriparser/Uri.h +++ b/ext/uri/uriparser/include/uriparser/Uri.h @@ -1,4 +1,4 @@ -/* 207ee4485d5a4690064bec14d369884451a49ae32e907b5bc6502c2bfa338ca1 (0.9.9+) +/* 5abed1007be99942f49ffe603a894d277066b79b9cb824547af0f3b9481cb9ca (1.0.0+) * * uriparser - RFC 3986 URI parsing library * @@ -45,47 +45,41 @@ */ #if (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI)) \ - || (defined(URI_PASS_UNICODE) && !defined(URI_H_UNICODE)) \ - || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) + || (defined(URI_PASS_UNICODE) && !defined(URI_H_UNICODE)) \ + || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* What encodings are enabled? */ -#include "UriDefsConfig.h" -#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) +# include "UriDefsConfig.h" +# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "Uri.h" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "Uri.h" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "Uri.h" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "Uri.h" +# undef URI_PASS_UNICODE +# endif /* Only one pass for each encoding */ -#elif (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI) \ - && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ - && !defined(URI_H_UNICODE) && defined(URI_ENABLE_UNICODE)) -# ifdef URI_PASS_ANSI -# define URI_H_ANSI 1 -# include "UriDefsAnsi.h" -# else -# define URI_H_UNICODE 1 -# include "UriDefsUnicode.h" -# endif - - - -#ifdef __cplusplus +# elif (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI) && defined(URI_ENABLE_ANSI)) \ + || (defined(URI_PASS_UNICODE) && !defined(URI_H_UNICODE) \ + && defined(URI_ENABLE_UNICODE)) +# ifdef URI_PASS_ANSI +# define URI_H_ANSI 1 +# include "UriDefsAnsi.h" +# else +# define URI_H_UNICODE 1 +# include "UriDefsUnicode.h" +# endif + +# ifdef __cplusplus extern "C" { -#endif - - - -#ifndef URI_DOXYGEN -# include "UriBase.h" -#endif - +# endif +# ifndef URI_DOXYGEN +# include "UriBase.h" +# endif /** * Specifies a range of characters within a string. @@ -99,12 +93,10 @@ extern "C" { * @since 0.3.0 */ typedef struct URI_TYPE(TextRangeStruct) { - const URI_CHAR * first; /**< Pointer to first character */ - const URI_CHAR * afterLast; /**< Pointer to character after the last one still in */ + const URI_CHAR * first; /**< Pointer to first character */ + const URI_CHAR * afterLast; /**< Pointer to character after the last one still in */ } URI_TYPE(TextRange); /**< @copydoc UriTextRangeStructA */ - - /** * Represents a path segment within a %URI path. * More precisely it is a node in a linked @@ -114,14 +106,13 @@ typedef struct URI_TYPE(TextRangeStruct) { * @since 0.3.0 */ typedef struct URI_TYPE(PathSegmentStruct) { - URI_TYPE(TextRange) text; /**< Path segment name */ - struct URI_TYPE(PathSegmentStruct) * next; /**< Pointer to the next path segment in the list, can be NULL if last already */ + URI_TYPE(TextRange) text; /**< Path segment name */ + struct URI_TYPE(PathSegmentStruct) * next; /**< Pointer to the next path segment in + the list, can be NULL if last already */ - void * reserved; /**< Reserved to the parser */ + void * reserved; /**< Reserved to the parser */ } URI_TYPE(PathSegment); /**< @copydoc UriPathSegmentStructA */ - - /** * Holds structured host information. * This is either a IPv4, IPv6, plain @@ -132,17 +123,16 @@ typedef struct URI_TYPE(PathSegmentStruct) { * @since 0.3.0 */ typedef struct URI_TYPE(HostDataStruct) { - UriIp4 * ip4; /**< IPv4 address */ - UriIp6 * ip6; /**< IPv6 address */ - URI_TYPE(TextRange) ipFuture; /**< IPvFuture address - @note - With non-NULL members in UriUriStructA.hostData context, - this text range's pointers must be identical to those - of UriUriStructA.hostText at all times. */ + UriIp4 * ip4; /**< IPv4 address */ + UriIp6 * ip6; /**< IPv6 address */ + URI_TYPE(TextRange) + ipFuture; /**< IPvFuture address +@note +With non-NULL members in UriUriStructA.hostData context, +this text range's pointers must be identical to those +of UriUriStructA.hostText at all times. */ } URI_TYPE(HostData); /**< @copydoc UriHostDataStructA */ - - /** * Represents an RFC 3986 %URI. * Missing components can be {NULL, NULL} ranges. @@ -153,24 +143,23 @@ typedef struct URI_TYPE(HostDataStruct) { * @since 0.3.0 */ typedef struct URI_TYPE(UriStruct) { - URI_TYPE(TextRange) scheme; /**< Scheme (e.g. "http") */ - URI_TYPE(TextRange) userInfo; /**< User info (e.g. "user:pass") */ - URI_TYPE(TextRange) hostText; /**< Host text (set for all hosts, excluding square brackets) */ - URI_TYPE(HostData) hostData; /**< Structured host type specific data */ - URI_TYPE(TextRange) portText; /**< Port (e.g. "80") */ - URI_TYPE(PathSegment) * pathHead; /**< Head of a linked list of path segments */ - URI_TYPE(PathSegment) * pathTail; /**< Tail of the list behind pathHead */ - URI_TYPE(TextRange) query; /**< Query without leading "?" */ - URI_TYPE(TextRange) fragment; /**< Query without leading "#" */ - UriBool absolutePath; /**< Absolute path flag, distincting "a" and "/a"; - always URI_FALSE for URIs with host */ - UriBool owner; /**< Memory owner flag */ - - void * reserved; /**< Reserved to the parser */ + URI_TYPE(TextRange) scheme; /**< Scheme (e.g. "http") */ + URI_TYPE(TextRange) userInfo; /**< User info (e.g. "user:pass") */ + URI_TYPE(TextRange) + hostText; /**< Host text (set for all hosts, excluding square brackets) */ + URI_TYPE(HostData) hostData; /**< Structured host type specific data */ + URI_TYPE(TextRange) portText; /**< Port (e.g. "80") */ + URI_TYPE(PathSegment) * pathHead; /**< Head of a linked list of path segments */ + URI_TYPE(PathSegment) * pathTail; /**< Tail of the list behind pathHead */ + URI_TYPE(TextRange) query; /**< Query without leading "?" */ + URI_TYPE(TextRange) fragment; /**< Query without leading "#" */ + UriBool absolutePath; /**< Absolute path flag, distincting "a" and "/a"; always + URI_FALSE for URIs with host */ + UriBool owner; /**< Memory owner flag */ + + void * reserved; /**< Reserved to the parser */ } URI_TYPE(Uri); /**< @copydoc UriUriStructA */ - - /** * Represents a state of the %URI parser. * Missing components can be NULL to reflect @@ -181,15 +170,14 @@ typedef struct URI_TYPE(UriStruct) { * @since 0.3.0 */ typedef struct URI_TYPE(ParserStateStruct) { - URI_TYPE(Uri) * uri; /**< Plug in the %URI structure to be filled while parsing here */ - int errorCode; /**< Code identifying the error which occurred */ - const URI_CHAR * errorPos; /**< Pointer to position in case of a syntax error */ + URI_TYPE(Uri) + *uri; /**< Plug in the %URI structure to be filled while parsing here */ + int errorCode; /**< Code identifying the error which occurred */ + const URI_CHAR * errorPos; /**< Pointer to position in case of a syntax error */ - void * reserved; /**< Reserved to the parser */ + void * reserved; /**< Reserved to the parser */ } URI_TYPE(ParserState); /**< @copydoc UriParserStateStructA */ - - /** * Represents a query element. * More precisely it is a node in a linked @@ -198,13 +186,13 @@ typedef struct URI_TYPE(ParserStateStruct) { * @since 0.7.0 */ typedef struct URI_TYPE(QueryListStruct) { - const URI_CHAR * key; /**< Key of the query element */ - const URI_CHAR * value; /**< Value of the query element, can be NULL */ + const URI_CHAR * key; /**< Key of the query element */ + const URI_CHAR * value; /**< Value of the query element, can be NULL */ - struct URI_TYPE(QueryListStruct) * next; /**< Pointer to the next key/value pair in the list, can be NULL if last already */ + struct URI_TYPE(QueryListStruct) * next; /**< Pointer to the next key/value pair in + the list, can be NULL if last already */ } URI_TYPE(QueryList); /**< @copydoc UriQueryListStructA */ - /** * Checks if a URI has the host component set. * @@ -215,8 +203,6 @@ typedef struct URI_TYPE(QueryListStruct) { */ URI_PUBLIC UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri); - - /** * Converts an IPv6 text representation into 16 bytes. * @@ -232,11 +218,8 @@ URI_PUBLIC UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri); * @see uriIsWellFormedHostIp6A * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(ParseIpSixAddress)(UriIp6 * output, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(ParseIpSixAddress)(UriIp6 * output, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Converts an IPv6 text representation into 16 bytes. @@ -252,12 +235,9 @@ URI_PUBLIC int URI_FUNC(ParseIpSixAddress)(UriIp6 * output, * @see uriIsWellFormedHostIp6MmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Parses a RFC 3986 %URI. @@ -265,7 +245,8 @@ URI_PUBLIC int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output, * * @param state INOUT: Parser state with set output %URI, must not be NULL * @param first IN: Pointer to the first character to parse, must not be NULL - * @param afterLast IN: Pointer to the character after the last to parse, must not be NULL + * @param afterLast IN: Pointer to the character after the last to parse, must + * not be NULL * @return 0 on success, error code otherwise * * @see uriParseUriA @@ -273,12 +254,11 @@ URI_PUBLIC int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output, * @see uriParseSingleUriExA * @see uriToStringA * @since 0.3.0 - * @deprecated Deprecated since 0.9.0, please migrate to uriParseSingleUriExA (with "Single"). + * @deprecated Deprecated since 0.9.0, please migrate to uriParseSingleUriExA (with + * "Single"). */ -URI_PUBLIC int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Parses a RFC 3986 %URI. @@ -293,12 +273,10 @@ URI_PUBLIC int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, * @see uriParseSingleUriExA * @see uriToStringA * @since 0.3.0 - * @deprecated Deprecated since 0.9.0, please migrate to uriParseSingleUriA (with "Single"). + * @deprecated Deprecated since 0.9.0, please migrate to uriParseSingleUriA (with + * "Single"). */ -URI_PUBLIC int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, - const URI_CHAR * text); - - +URI_PUBLIC int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, const URI_CHAR * text); /** * Parses a single RFC 3986 %URI. @@ -317,10 +295,8 @@ URI_PUBLIC int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, * @see uriToStringA * @since 0.9.0 */ -URI_PUBLIC int URI_FUNC(ParseSingleUri)(URI_TYPE(Uri) * uri, - const URI_CHAR * text, const URI_CHAR ** errorPos); - - +URI_PUBLIC int URI_FUNC(ParseSingleUri)(URI_TYPE(Uri) * uri, const URI_CHAR * text, + const URI_CHAR ** errorPos); /** * Parses a single RFC 3986 %URI. @@ -342,11 +318,9 @@ URI_PUBLIC int URI_FUNC(ParseSingleUri)(URI_TYPE(Uri) * uri, * @see uriToStringA * @since 0.9.0 */ -URI_PUBLIC int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, const URI_CHAR * afterLast, - const URI_CHAR ** errorPos); - - +URI_PUBLIC int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + const URI_CHAR ** errorPos); /** * Parses a single RFC 3986 %URI. @@ -368,11 +342,10 @@ URI_PUBLIC int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri, * @see uriToStringA * @since 0.9.0 */ -URI_PUBLIC int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, const URI_CHAR * afterLast, - const URI_CHAR ** errorPos, UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + const URI_CHAR ** errorPos, + UriMemoryManager * memory); /** * Frees all memory associated with the members @@ -381,8 +354,8 @@ URI_PUBLIC int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri, * Uses default libc-based memory manager. * * @remarks - * Calling on an all-zeros structure (e.g. through memset or calloc) is safe.
- * Calling on an uninitialized structure is not safe. + * Calling on an all-zeros structure (e.g. through memset or calloc) is + * safe.
Calling on an uninitialized structure is not safe. * * @param uri INOUT: %URI structure whose members should be freed * @@ -391,16 +364,14 @@ URI_PUBLIC int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri, */ URI_PUBLIC void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri); - - /** * Frees all memory associated with the members * of the %URI structure. Note that the structure * itself is not freed, only its members. * * @remarks - * Calling on an all-zeros structure (e.g. through memset or calloc) is safe.
- * Calling on an uninitialized structure is not safe. + * Calling on an all-zeros structure (e.g. through memset or calloc) is + * safe.
Calling on an uninitialized structure is not safe. * * @param uri INOUT: %URI structure whose members should be freed * @param memory IN: Memory manager to use, NULL for default libc @@ -409,10 +380,7 @@ URI_PUBLIC void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri); * @see uriFreeUriMembersA * @since 0.9.0 */ -URI_PUBLIC int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory); /** * Percent-encodes all but unreserved characters from the input string and @@ -443,10 +411,8 @@ URI_PUBLIC int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, * @since 0.5.2 */ URI_PUBLIC URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, - const URI_CHAR * inAfterLast, URI_CHAR * out, - UriBool spaceToPlus, UriBool normalizeBreaks); - - + const URI_CHAR * inAfterLast, URI_CHAR * out, + UriBool spaceToPlus, UriBool normalizeBreaks); /** * Percent-encodes all but unreserved characters from the input string and @@ -476,9 +442,7 @@ URI_PUBLIC URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, * @since 0.5.0 */ URI_PUBLIC URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, - UriBool spaceToPlus, UriBool normalizeBreaks); - - + UriBool spaceToPlus, UriBool normalizeBreaks); /** * Unescapes percent-encoded groups in a given string. @@ -497,10 +461,9 @@ URI_PUBLIC URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, * @see uriEscapeExA * @since 0.5.0 */ -URI_PUBLIC const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, - UriBool plusToSpace, UriBreakConversion breakConversion); - - +URI_PUBLIC const URI_CHAR * + URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, UriBool plusToSpace, + UriBreakConversion breakConversion); /** * Unescapes percent-encoded groups in a given string. @@ -522,13 +485,11 @@ URI_PUBLIC const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, */ URI_PUBLIC const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout); - - /** * Performs reference resolution as described in - * section 5.2.2 of RFC 3986. - * Uses default libc-based memory manager. - * NOTE: On success you have to call uriFreeUriMembersA on \p absoluteDest manually later. + * section 5.2.2 of + * RFC 3986. Uses default libc-based memory manager. NOTE: On success you have to call + * uriFreeUriMembersA on \p absoluteDest manually later. * * @param absoluteDest OUT: Result %URI * @param relativeSource IN: Reference to resolve @@ -542,16 +503,14 @@ URI_PUBLIC const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout); * @since 0.4.0 */ URI_PUBLIC int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absoluteDest, - const URI_TYPE(Uri) * relativeSource, - const URI_TYPE(Uri) * absoluteBase); - - + const URI_TYPE(Uri) * relativeSource, + const URI_TYPE(Uri) * absoluteBase); /** * Performs reference resolution as described in - * section 5.2.2 of RFC 3986. - * Uses default libc-based memory manager. - * NOTE: On success you have to call uriFreeUriMembersA on \p absoluteDest manually later. + * section 5.2.2 of + * RFC 3986. Uses default libc-based memory manager. NOTE: On success you have to call + * uriFreeUriMembersA on \p absoluteDest manually later. * * @param absoluteDest OUT: Result %URI * @param relativeSource IN: Reference to resolve @@ -565,16 +524,15 @@ URI_PUBLIC int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absoluteDest, * @since 0.8.1 */ URI_PUBLIC int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absoluteDest, - const URI_TYPE(Uri) * relativeSource, - const URI_TYPE(Uri) * absoluteBase, - UriResolutionOptions options); - - + const URI_TYPE(Uri) * relativeSource, + const URI_TYPE(Uri) * absoluteBase, + UriResolutionOptions options); /** * Performs reference resolution as described in - * section 5.2.2 of RFC 3986. - * NOTE: On success you have to call uriFreeUriMembersMmA on \p absoluteDest manually later. + * section 5.2.2 of + * RFC 3986. NOTE: On success you have to call uriFreeUriMembersMmA on \p absoluteDest + * manually later. * * @param absoluteDest OUT: Result %URI * @param relativeSource IN: Reference to resolve @@ -590,11 +548,10 @@ URI_PUBLIC int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absoluteDest, * @since 0.9.0 */ URI_PUBLIC int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absoluteDest, - const URI_TYPE(Uri) * relativeSource, - const URI_TYPE(Uri) * absoluteBase, - UriResolutionOptions options, UriMemoryManager * memory); - - + const URI_TYPE(Uri) * relativeSource, + const URI_TYPE(Uri) * absoluteBase, + UriResolutionOptions options, + UriMemoryManager * memory); /** * Tries to make a relative %URI (a reference) from an @@ -619,11 +576,9 @@ URI_PUBLIC int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absoluteDest, * @since 0.5.2 */ URI_PUBLIC int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest, - const URI_TYPE(Uri) * absoluteSource, - const URI_TYPE(Uri) * absoluteBase, - UriBool domainRootMode); - - + const URI_TYPE(Uri) * absoluteSource, + const URI_TYPE(Uri) * absoluteBase, + UriBool domainRootMode); /** * Tries to make a relative %URI (a reference) from an @@ -648,11 +603,10 @@ URI_PUBLIC int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest, * @since 0.9.0 */ URI_PUBLIC int URI_FUNC(RemoveBaseUriMm)(URI_TYPE(Uri) * dest, - const URI_TYPE(Uri) * absoluteSource, - const URI_TYPE(Uri) * absoluteBase, - UriBool domainRootMode, UriMemoryManager * memory); - - + const URI_TYPE(Uri) * absoluteSource, + const URI_TYPE(Uri) * absoluteBase, + UriBool domainRootMode, + UriMemoryManager * memory); /** * Checks two URIs for equivalence. Comparison is done @@ -665,10 +619,7 @@ URI_PUBLIC int URI_FUNC(RemoveBaseUriMm)(URI_TYPE(Uri) * dest, * * @since 0.4.0 */ -URI_PUBLIC UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, - const URI_TYPE(Uri) * b); - - +URI_PUBLIC UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b); /** * Calculates the number of characters needed to store the @@ -676,38 +627,39 @@ URI_PUBLIC UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, * terminator. * * @param uri IN: %URI to measure - * @param charsRequired OUT: Length of the string representation in characters excluding terminator + * @param charsRequired OUT: Length of the string representation in characters + * excluding terminator * @return Error code or 0 on success * * @see uriToStringA * @since 0.5.0 */ URI_PUBLIC int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri, - int * charsRequired); - - + int * charsRequired); /** * Converts a %URI structure back to text as described in - * section 5.3 of RFC 3986. + * section 5.3 of RFC + * 3986. * * NOTE: Scheme-based normalization - * (section 6.2.3 of RFC 3986) - * is not applied and is considered a responsibility of the application using uriparser. + * (section 6.2.3 of + * RFC 3986) is not applied and is considered a responsibility of the application + * using uriparser. * * @param dest OUT: Output destination * @param uri IN: %URI to convert - * @param maxChars IN: Maximum number of characters to copy including terminator - * @param charsWritten OUT: Number of characters written, can be lower than maxChars even if the %URI is too long! + * @param maxChars IN: Maximum number of characters to copy including + * terminator + * @param charsWritten OUT: Number of characters written, can be lower than + * maxChars even if the %URI is too long! * @return Error code or 0 on success * * @see uriToStringCharsRequiredA * @since 0.4.0 */ URI_PUBLIC int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, - int maxChars, int * charsWritten); - - + int maxChars, int * charsWritten); /** * Copies a %URI structure. @@ -721,9 +673,8 @@ URI_PUBLIC int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, * @since 0.9.9 */ URI_PUBLIC int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, - const URI_TYPE(Uri) * sourceUri, UriMemoryManager * memory); - - + const URI_TYPE(Uri) * sourceUri, + UriMemoryManager * memory); /** * Copies a %URI structure. @@ -735,9 +686,8 @@ URI_PUBLIC int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, * @see uriCopyUriMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri); - - +URI_PUBLIC int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, + const URI_TYPE(Uri) * sourceUri); /** * Determines the components of a %URI that are not normalized. @@ -750,12 +700,10 @@ URI_PUBLIC int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * * @see uriNormalizeSyntaxExMmA * @see uriNormalizeSyntaxMaskRequiredExA * @since 0.5.0 - * @deprecated Deprecated since 0.9.0, please migrate to uriNormalizeSyntaxMaskRequiredExA (with "Ex"). + * @deprecated Deprecated since 0.9.0, please migrate to uriNormalizeSyntaxMaskRequiredExA + * (with "Ex"). */ -URI_PUBLIC unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)( - const URI_TYPE(Uri) * uri); - - +URI_PUBLIC unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri); /** * Determines the components of a %URI that are not normalized. @@ -770,10 +718,8 @@ URI_PUBLIC unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)( * @see uriNormalizeSyntaxMaskRequiredA * @since 0.9.0 */ -URI_PUBLIC int URI_FUNC(NormalizeSyntaxMaskRequiredEx)( - const URI_TYPE(Uri) * uri, unsigned int * outMask); - - +URI_PUBLIC int URI_FUNC(NormalizeSyntaxMaskRequiredEx)(const URI_TYPE(Uri) * uri, + unsigned int * outMask); /** * Normalizes a %URI using a normalization mask. @@ -792,10 +738,7 @@ URI_PUBLIC int URI_FUNC(NormalizeSyntaxMaskRequiredEx)( * @see uriNormalizeSyntaxMaskRequiredA * @since 0.5.0 */ -URI_PUBLIC int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, - unsigned int mask); - - +URI_PUBLIC int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask); /** * Normalizes a %URI using a normalization mask. @@ -814,10 +757,8 @@ URI_PUBLIC int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, * @see uriNormalizeSyntaxMaskRequiredA * @since 0.9.0 */ -URI_PUBLIC int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri, - unsigned int mask, UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri, unsigned int mask, + UriMemoryManager * memory); /** * Normalizes all components of a %URI. @@ -836,8 +777,6 @@ URI_PUBLIC int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri, */ URI_PUBLIC int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri); - - /** * Converts a Unix filename to a %URI string. * The destination buffer must be large enough to hold 7 + 3 * len(filename) + 1 @@ -857,9 +796,7 @@ URI_PUBLIC int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri); * @since 0.5.2 */ URI_PUBLIC int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename, - URI_CHAR * uriString); - - + URI_CHAR * uriString); /** * Converts a Windows filename to a %URI string. @@ -880,9 +817,7 @@ URI_PUBLIC int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename, * @since 0.5.2 */ URI_PUBLIC int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename, - URI_CHAR * uriString); - - + URI_CHAR * uriString); /** * Extracts a Unix filename from a %URI string. @@ -899,9 +834,7 @@ URI_PUBLIC int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename, * @since 0.5.2 */ URI_PUBLIC int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString, - URI_CHAR * filename); - - + URI_CHAR * filename); /** * Extracts a Windows filename from a %URI string. @@ -918,9 +851,7 @@ URI_PUBLIC int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString, * @since 0.5.2 */ URI_PUBLIC int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString, - URI_CHAR * filename); - - + URI_CHAR * filename); /** * Calculates the number of characters needed to store the @@ -929,17 +860,16 @@ URI_PUBLIC int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString, * normalized to "%0D%0A". * * @param queryList IN: Query list to measure - * @param charsRequired OUT: Length of the string representation in characters excluding terminator + * @param charsRequired OUT: Length of the string representation in characters + * excluding terminator * @return Error code or 0 on success * * @see uriComposeQueryCharsRequiredExA * @see uriComposeQueryA * @since 0.7.0 */ -URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)( - const URI_TYPE(QueryList) * queryList, int * charsRequired); - - +URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList, + int * charsRequired); /** * Calculates the number of characters needed to store the @@ -947,7 +877,8 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)( * terminator. * * @param queryList IN: Query list to measure - * @param charsRequired OUT: Length of the string representation in characters excluding terminator + * @param charsRequired OUT: Length of the string representation in characters + * excluding terminator * @param spaceToPlus IN: Whether to convert ' ' to '+' or not * @param normalizeBreaks IN: Whether to convert CR and LF to CR-LF or not. * @return Error code or 0 on success @@ -956,11 +887,10 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)( * @see uriComposeQueryExA * @since 0.7.0 */ -URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequiredEx)( - const URI_TYPE(QueryList) * queryList, - int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks); - - +URI_PUBLIC int + URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList, + int * charsRequired, UriBool spaceToPlus, + UriBool normalizeBreaks); /** * Converts a query list structure back to a query string. @@ -970,8 +900,10 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequiredEx)( * * @param dest OUT: Output destination * @param queryList IN: Query list to convert - * @param maxChars IN: Maximum number of characters to copy including terminator - * @param charsWritten OUT: Number of characters written, can be lower than maxChars even if the query list is too long! + * @param maxChars IN: Maximum number of characters to copy + * including terminator + * @param charsWritten OUT: Number of characters written, can be lower than + * maxChars even if the query list is too long! * @return Error code or 0 on success * * @see uriComposeQueryExA @@ -985,9 +917,8 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequiredEx)( * @since 0.7.0 */ URI_PUBLIC int URI_FUNC(ComposeQuery)(URI_CHAR * dest, - const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten); - - + const URI_TYPE(QueryList) * queryList, int maxChars, + int * charsWritten); /** * Converts a query list structure back to a query string. @@ -995,8 +926,10 @@ URI_PUBLIC int URI_FUNC(ComposeQuery)(URI_CHAR * dest, * * @param dest OUT: Output destination * @param queryList IN: Query list to convert - * @param maxChars IN: Maximum number of characters to copy including terminator - * @param charsWritten OUT: Number of characters written, can be lower than maxChars even if the query list is too long! + * @param maxChars IN: Maximum number of characters to copy + * including terminator + * @param charsWritten OUT: Number of characters written, can be lower than + * maxChars even if the query list is too long! * @param spaceToPlus IN: Whether to convert ' ' to '+' or not * @param normalizeBreaks IN: Whether to convert CR and LF to CR-LF or not. * @return Error code or 0 on success @@ -1012,10 +945,9 @@ URI_PUBLIC int URI_FUNC(ComposeQuery)(URI_CHAR * dest, * @since 0.7.0 */ URI_PUBLIC int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, - const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, - UriBool spaceToPlus, UriBool normalizeBreaks); - - + const URI_TYPE(QueryList) * queryList, + int maxChars, int * charsWritten, + UriBool spaceToPlus, UriBool normalizeBreaks); /** * Converts a query list structure back to a query string. @@ -1038,9 +970,7 @@ URI_PUBLIC int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, * @since 0.7.0 */ URI_PUBLIC int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, - const URI_TYPE(QueryList) * queryList); - - + const URI_TYPE(QueryList) * queryList); /** * Converts a query list structure back to a query string. @@ -1063,10 +993,9 @@ URI_PUBLIC int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, * @since 0.7.0 */ URI_PUBLIC int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, - const URI_TYPE(QueryList) * queryList, - UriBool spaceToPlus, UriBool normalizeBreaks); - - + const URI_TYPE(QueryList) * queryList, + UriBool spaceToPlus, + UriBool normalizeBreaks); /** * Converts a query list structure back to a query string. @@ -1089,11 +1018,10 @@ URI_PUBLIC int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, * @since 0.9.0 */ URI_PUBLIC int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest, - const URI_TYPE(QueryList) * queryList, - UriBool spaceToPlus, UriBool normalizeBreaks, - UriMemoryManager * memory); - - + const URI_TYPE(QueryList) * queryList, + UriBool spaceToPlus, + UriBool normalizeBreaks, + UriMemoryManager * memory); /** * Constructs a query list from the raw query string of a given URI. @@ -1113,10 +1041,9 @@ URI_PUBLIC int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest, * @see uriFreeQueryListMmA * @since 0.7.0 */ -URI_PUBLIC int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, - int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) * *dest, int * itemCount, + const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Constructs a query list from the raw query string of a given URI. @@ -1136,11 +1063,11 @@ URI_PUBLIC int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, * @see uriFreeQueryListA * @since 0.7.0 */ -URI_PUBLIC int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, - int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast, - UriBool plusToSpace, UriBreakConversion breakConversion); - - +URI_PUBLIC int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) * *dest, + int * itemCount, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriBool plusToSpace, + UriBreakConversion breakConversion); /** * Constructs a query list from the raw query string of a given URI. @@ -1161,12 +1088,12 @@ URI_PUBLIC int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, * @see uriFreeQueryListMmA * @since 0.9.0 */ -URI_PUBLIC int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, - int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast, - UriBool plusToSpace, UriBreakConversion breakConversion, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) * *dest, + int * itemCount, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriBool plusToSpace, + UriBreakConversion breakConversion, + UriMemoryManager * memory); /** * Frees all memory associated with the given query list. @@ -1179,8 +1106,6 @@ URI_PUBLIC int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, */ URI_PUBLIC void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList); - - /** * Frees all memory associated with the given query list. * The structure itself is freed as well. @@ -1193,9 +1118,7 @@ URI_PUBLIC void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList); * @since 0.9.0 */ URI_PUBLIC int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList, - UriMemoryManager * memory); - - + UriMemoryManager * memory); /** * Makes the %URI hold copies of strings so that it no longer depends @@ -1212,8 +1135,6 @@ URI_PUBLIC int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList, */ URI_PUBLIC int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri); - - /** * Makes the %URI hold copies of strings so that it no longer depends * on the original %URI string. If the %URI is already owner of copies, @@ -1226,10 +1147,7 @@ URI_PUBLIC int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri); * @see uriMakeOwnerA * @since 0.9.4 */ -URI_PUBLIC int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory); /** * Determines if the given text range contains a well-formed fragment @@ -1237,7 +1155,8 @@ URI_PUBLIC int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE + * @return URI_TRUE if non-NULL and well-formed, else + * URI_FALSE * * @see uriIsWellFormedHostIp4A * @see uriIsWellFormedHostIp6A @@ -1252,9 +1171,8 @@ URI_PUBLIC int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, * @see uriSetFragmentMmA * @since 0.9.9 */ -URI_PUBLIC UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first, const URI_CHAR * afterLast); - - +URI_PUBLIC UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Determines if the given text range contains a well-formed IPv4 address @@ -1262,7 +1180,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first, const * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE + * @return URI_TRUE if non-NULL and well-formed, else + * URI_FALSE * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp6A @@ -1277,9 +1196,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first, const * @see uriSetHostIp4MmA * @since 0.9.9 */ -URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first, const URI_CHAR * afterLast); - - +URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Determines if the given text range contains a well-formed IPv6 address @@ -1289,7 +1207,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first, const U * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_SUCCESS if non-NULL and well-formed, else an error code + * @return URI_SUCCESS if non-NULL and well-formed, else an error + * code * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1307,8 +1226,6 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first, const U */ int URI_FUNC(IsWellFormedHostIp6)(const URI_CHAR * first, const URI_CHAR * afterLast); - - /** * Determines if the given text range contains a well-formed IPv6 address * according to RFC 3986 or not. @@ -1316,7 +1233,8 @@ int URI_FUNC(IsWellFormedHostIp6)(const URI_CHAR * first, const URI_CHAR * after * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in * @param memory IN: Memory manager to use, NULL for default libc - * @return URI_SUCCESS if non-NULL and well-formed, else an error code + * @return URI_SUCCESS if non-NULL and well-formed, else an error + * code * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1330,9 +1248,8 @@ int URI_FUNC(IsWellFormedHostIp6)(const URI_CHAR * first, const URI_CHAR * after * @see uriIsWellFormedUserInfoA * @since 0.9.9 */ -int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); - - +int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Determines if the given text range contains a well-formed IPvFuture address @@ -1342,7 +1259,8 @@ int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * aft * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_SUCCESS if non-NULL and well-formed, else an error code + * @return URI_SUCCESS if non-NULL and well-formed, else an error + * code * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1358,9 +1276,8 @@ int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * aft * @see uriSetHostIpFutureMmA * @since 0.9.9 */ -int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first, const URI_CHAR * afterLast); - - +int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Determines if the given text range contains a well-formed IPvFuture address @@ -1369,7 +1286,8 @@ int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first, const URI_CHAR * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in * @param memory IN: Memory manager to use, NULL for default libc - * @return URI_SUCCESS if non-NULL and well-formed, else an error code + * @return URI_SUCCESS if non-NULL and well-formed, else an error + * code * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1385,9 +1303,9 @@ int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first, const URI_CHAR * * @see uriSetHostIpFutureMmA * @since 0.9.9 */ -int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); - - +int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Determines if the given text range contains a well-formed registered host name @@ -1395,7 +1313,8 @@ int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first, const URI_CHAR * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE + * @return URI_TRUE if non-NULL and well-formed, else + * URI_FALSE * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1410,9 +1329,8 @@ int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first, const URI_CHAR * @see uriSetHostRegNameMmA * @since 0.9.9 */ -URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, const URI_CHAR * afterLast); - - +URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Determines if the given text range contains a well-formed path @@ -1420,8 +1338,10 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, con * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @param hasHost IN: Whether the target %URI has a non-NULL host set or not - * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE + * @param hasHost IN: Whether the target %URI has a non-NULL host set or + * not + * @return URI_TRUE if non-NULL and well-formed, else + * URI_FALSE * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1437,9 +1357,9 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, con * @see uriSetPathMmA * @since 0.9.9 */ -URI_PUBLIC UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, const URI_CHAR * afterLast, UriBool hasHost); - - +URI_PUBLIC UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, + const URI_CHAR * afterLast, + UriBool hasHost); /** * Determines if the given text range contains a well-formed port text @@ -1447,7 +1367,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, const URI_ * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE + * @return URI_TRUE if non-NULL and well-formed, else + * URI_FALSE * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1462,9 +1383,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, const URI_ * @see uriSetPortTextMmA * @since 0.9.9 */ -URI_PUBLIC UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first, const URI_CHAR * afterLast); - - +URI_PUBLIC UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Determines if the given text range contains a well-formed query @@ -1472,7 +1392,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first, const URI_ * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE + * @return URI_TRUE if non-NULL and well-formed, else + * URI_FALSE * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1487,8 +1408,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first, const URI_ * @see uriSetQueryMmA * @since 0.9.9 */ -URI_PUBLIC UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first, const URI_CHAR * afterLast); - +URI_PUBLIC UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Determines if the given text range contains a well-formed scheme @@ -1496,7 +1417,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first, const URI * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE + * @return URI_TRUE if non-NULL and well-formed, else + * URI_FALSE * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1512,9 +1434,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first, const URI * @see uriSetSchemeMmA * @since 0.9.9 */ -URI_PUBLIC UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first, const URI_CHAR * afterLast); - - +URI_PUBLIC UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Determines if the given text range contains a well-formed user info @@ -1522,7 +1443,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first, const UR * * @param first IN: Pointer to first character * @param afterLast IN: Pointer to character after the last one still in - * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE + * @return URI_TRUE if non-NULL and well-formed, else + * URI_FALSE * * @see uriIsWellFormedFragmentA * @see uriIsWellFormedHostIp4A @@ -1537,9 +1459,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first, const UR * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first, const URI_CHAR * afterLast); - - +URI_PUBLIC UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the fragment of the given %URI to the given value. @@ -1557,7 +1478,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first, const * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedFragmentA @@ -1573,11 +1495,8 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first, const * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the fragment of the given %URI to the given value. @@ -1593,7 +1512,8 @@ URI_PUBLIC int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -1610,12 +1530,9 @@ URI_PUBLIC int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the host of the given %URI to the given value. @@ -1633,7 +1550,8 @@ URI_PUBLIC int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedHostIp4A @@ -1654,11 +1572,8 @@ URI_PUBLIC int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the host of the given %URI to the given value. @@ -1674,7 +1589,8 @@ URI_PUBLIC int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -1696,12 +1612,9 @@ URI_PUBLIC int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the host of the given %URI to the given value. @@ -1719,7 +1632,8 @@ URI_PUBLIC int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedHostRegNameA @@ -1735,11 +1649,8 @@ URI_PUBLIC int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the host of the given %URI to the given value. @@ -1755,7 +1666,8 @@ URI_PUBLIC int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -1772,12 +1684,9 @@ URI_PUBLIC int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the host of the given %URI to the given value. @@ -1795,7 +1704,8 @@ URI_PUBLIC int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedHostIp4A @@ -1811,11 +1721,8 @@ URI_PUBLIC int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the host of the given %URI to the given value. @@ -1831,7 +1738,8 @@ URI_PUBLIC int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -1848,12 +1756,9 @@ URI_PUBLIC int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the host of the given %URI to the given value. @@ -1871,7 +1776,8 @@ URI_PUBLIC int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedHostIp6A @@ -1887,11 +1793,8 @@ URI_PUBLIC int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the host of the given %URI to the given value. @@ -1907,7 +1810,8 @@ URI_PUBLIC int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -1924,12 +1828,9 @@ URI_PUBLIC int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the host of the given %URI to the given value. @@ -1947,7 +1848,8 @@ URI_PUBLIC int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedHostIp4A @@ -1963,11 +1865,8 @@ URI_PUBLIC int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the host of the given %URI to the given value. @@ -1983,7 +1882,8 @@ URI_PUBLIC int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -2000,12 +1900,9 @@ URI_PUBLIC int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the path of the given %URI to the given value. @@ -2025,7 +1922,8 @@ URI_PUBLIC int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedPathA @@ -2042,11 +1940,8 @@ URI_PUBLIC int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the path of the given %URI to the given value. @@ -2066,7 +1961,8 @@ URI_PUBLIC int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -2084,12 +1980,8 @@ URI_PUBLIC int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory); /** * Sets the port text of the given %URI to the given value. @@ -2109,7 +2001,8 @@ URI_PUBLIC int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedPortA @@ -2125,11 +2018,8 @@ URI_PUBLIC int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the port text of the given %URI to the given value. @@ -2147,7 +2037,8 @@ URI_PUBLIC int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -2164,12 +2055,9 @@ URI_PUBLIC int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the query of the given %URI to the given value. @@ -2187,7 +2075,8 @@ URI_PUBLIC int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedQueryA @@ -2203,11 +2092,8 @@ URI_PUBLIC int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the query of the given %URI to the given value. @@ -2223,7 +2109,8 @@ URI_PUBLIC int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -2240,12 +2127,9 @@ URI_PUBLIC int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the scheme of the given %URI to the given value. @@ -2263,7 +2147,8 @@ URI_PUBLIC int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedSchemeA @@ -2279,11 +2164,8 @@ URI_PUBLIC int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the scheme of the given %URI to the given value. @@ -2299,7 +2181,8 @@ URI_PUBLIC int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -2316,12 +2199,9 @@ URI_PUBLIC int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Sets the user info of the given %URI to the given value. @@ -2341,7 +2221,8 @@ URI_PUBLIC int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @return Error code or 0 on success * * @see uriIsWellFormedUserInfoA @@ -2357,11 +2238,8 @@ URI_PUBLIC int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoMmA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast); - - +URI_PUBLIC int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast); /** * Sets the user info of the given %URI to the given value. @@ -2379,7 +2257,8 @@ URI_PUBLIC int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri, * * @param uri INOUT: %URI to modify * @param first IN: Pointer to first character, can be NULL - * @param afterLast IN: Pointer to character after the last one still in, can be NULL + * @param afterLast IN: Pointer to character after the last one still in, can be + * NULL * @param memory IN: Memory manager to use, NULL for default libc * @return Error code or 0 on success * @@ -2396,12 +2275,9 @@ URI_PUBLIC int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri, * @see uriSetUserInfoA * @since 0.9.9 */ -URI_PUBLIC int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - +URI_PUBLIC int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); /** * Obtain the base runtime version of uriparser. @@ -2425,13 +2301,9 @@ URI_PUBLIC int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri, */ URI_PUBLIC const URI_CHAR * URI_FUNC(BaseRuntimeVersion)(void); - - -#ifdef __cplusplus +# ifdef __cplusplus } -#endif - +# endif - -#endif +# endif #endif diff --git a/ext/uri/uriparser/include/uriparser/UriBase.h b/ext/uri/uriparser/include/uriparser/UriBase.h index 92883278cff26..3a9a868e3bb18 100644 --- a/ext/uri/uriparser/include/uriparser/UriBase.h +++ b/ext/uri/uriparser/include/uriparser/UriBase.h @@ -43,152 +43,136 @@ */ #ifndef URI_BASE_H -#define URI_BASE_H 1 - - +# define URI_BASE_H 1 /* Version helper macro */ -#define URI_ANSI_TO_UNICODE_HELPER(x) L ## x -#define URI_ANSI_TO_UNICODE(x) URI_ANSI_TO_UNICODE_HELPER(x) - - +# define URI_ANSI_TO_UNICODE_HELPER(x) L##x +# define URI_ANSI_TO_UNICODE(x) URI_ANSI_TO_UNICODE_HELPER(x) /* Version */ -#define URI_VER_MAJOR 0 -#define URI_VER_MINOR 9 -#define URI_VER_RELEASE 9 -#define URI_VER_SUFFIX_ANSI "" -#define URI_VER_SUFFIX_UNICODE URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI) - - +# define URI_VER_MAJOR 1 +# define URI_VER_MINOR 0 +# define URI_VER_RELEASE 0 +# define URI_VER_SUFFIX_ANSI "" +# define URI_VER_SUFFIX_UNICODE URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI) /* More version helper macros */ -#define URI_INT_TO_ANSI_HELPER(x) #x -#define URI_INT_TO_ANSI(x) URI_INT_TO_ANSI_HELPER(x) +# define URI_INT_TO_ANSI_HELPER(x) #x +# define URI_INT_TO_ANSI(x) URI_INT_TO_ANSI_HELPER(x) -#define URI_INT_TO_UNICODE_HELPER(x) URI_ANSI_TO_UNICODE(#x) -#define URI_INT_TO_UNICODE(x) URI_INT_TO_UNICODE_HELPER(x) - -#define URI_VER_ANSI_HELPER(ma, mi, r, s) \ - URI_INT_TO_ANSI(ma) "." \ - URI_INT_TO_ANSI(mi) "." \ - URI_INT_TO_ANSI(r) \ - s - -#define URI_VER_UNICODE_HELPER(ma, mi, r, s) \ - URI_INT_TO_UNICODE(ma) L"." \ - URI_INT_TO_UNICODE(mi) L"." \ - URI_INT_TO_UNICODE(r) \ - s +# define URI_INT_TO_UNICODE_HELPER(x) URI_ANSI_TO_UNICODE(#x) +# define URI_INT_TO_UNICODE(x) URI_INT_TO_UNICODE_HELPER(x) +# define URI_VER_ANSI_HELPER(ma, mi, r, s) \ + URI_INT_TO_ANSI(ma) "." URI_INT_TO_ANSI(mi) "." URI_INT_TO_ANSI(r) s +# define URI_VER_UNICODE_HELPER(ma, mi, r, s) \ + URI_INT_TO_UNICODE(ma) L"." URI_INT_TO_UNICODE(mi) L"." URI_INT_TO_UNICODE(r) s /* Full version strings */ -#define URI_VER_ANSI URI_VER_ANSI_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_ANSI) -#define URI_VER_UNICODE URI_VER_UNICODE_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_UNICODE) - - +# define URI_VER_ANSI \ + URI_VER_ANSI_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, \ + URI_VER_SUFFIX_ANSI) +# define URI_VER_UNICODE \ + URI_VER_UNICODE_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, \ + URI_VER_SUFFIX_UNICODE) /* Unused parameter macro */ -#ifdef __GNUC__ -# define URI_UNUSED(x) unused_##x __attribute__((unused)) -#else -# define URI_UNUSED(x) x -#endif - - +# ifdef __GNUC__ +# define URI_UNUSED(x) unused_##x __attribute__((unused)) +# else +# define URI_UNUSED(x) x +# endif /* Import/export decorator */ -#if defined(_MSC_VER) -# if defined(URI_STATIC_BUILD) -# define URI_PUBLIC -# elif defined(URI_LIBRARY_BUILD) -# define URI_PUBLIC __declspec(dllexport) -# else -# define URI_PUBLIC __declspec(dllimport) -# endif -#else -# if ! defined(URI_LIBRARY_BUILD) || ! defined(URI_VISIBILITY) -# define URI_PUBLIC -# else -# define URI_PUBLIC __attribute__ ((visibility("default"))) -# endif -#endif - - +# if defined(_MSC_VER) +# if defined(URI_STATIC_BUILD) +# define URI_PUBLIC +# elif defined(URI_LIBRARY_BUILD) +# define URI_PUBLIC __declspec(dllexport) +# else +# define URI_PUBLIC __declspec(dllimport) +# endif +# else +# if !defined(URI_LIBRARY_BUILD) || !defined(URI_VISIBILITY) +# define URI_PUBLIC +# else +# define URI_PUBLIC __attribute__((visibility("default"))) +# endif +# endif typedef int UriBool; /**< Boolean type */ -#define URI_TRUE 1 -#define URI_FALSE 0 - - +# define URI_TRUE 1 +# define URI_FALSE 0 /* Shared errors */ -#define URI_SUCCESS 0 -#define URI_ERROR_SYNTAX 1 /* Parsed text violates expected format */ -#define URI_ERROR_NULL 2 /* One of the params passed was NULL - although it mustn't be */ -#define URI_ERROR_MALLOC 3 /* Requested memory could not be allocated */ -#define URI_ERROR_OUTPUT_TOO_LARGE 4 /* Some output is to large for the receiving buffer */ -#define URI_ERROR_NOT_IMPLEMENTED 8 /* The called function is not implemented yet */ -#define URI_ERROR_RANGE_INVALID 9 /* The parameters passed contained invalid ranges */ -#define URI_ERROR_MEMORY_MANAGER_INCOMPLETE 10 /* [>=0.9.0] The UriMemoryManager passed does not implement all needed functions */ - +# define URI_SUCCESS 0 +# define URI_ERROR_SYNTAX 1 /* Parsed text violates expected format */ +# define URI_ERROR_NULL \ + 2 /* One of the params passed was NULL although it mustn't be \ + */ +# define URI_ERROR_MALLOC 3 /* Requested memory could not be allocated */ +# define URI_ERROR_OUTPUT_TOO_LARGE \ + 4 /* Some output is to large for the receiving buffer */ +# define URI_ERROR_NOT_IMPLEMENTED 8 /* The called function is not implemented yet */ +# define URI_ERROR_RANGE_INVALID 9 /* The parameters passed contained invalid ranges */ +# define URI_ERROR_MEMORY_MANAGER_INCOMPLETE \ + 10 /* [>=0.9.0] The UriMemoryManager passed does not implement all needed \ + functions */ /* Errors specific to ToString */ -#define URI_ERROR_TOSTRING_TOO_LONG URI_ERROR_OUTPUT_TOO_LARGE /* Deprecated, test for URI_ERROR_OUTPUT_TOO_LARGE instead */ +# define URI_ERROR_TOSTRING_TOO_LONG \ + URI_ERROR_OUTPUT_TOO_LARGE /* Deprecated, test for URI_ERROR_OUTPUT_TOO_LARGE \ + instead */ /* Errors specific to AddBaseUri */ -#define URI_ERROR_ADDBASE_REL_BASE 5 /* Given base is not absolute */ +# define URI_ERROR_ADDBASE_REL_BASE 5 /* Given base is not absolute */ /* Errors specific to RemoveBaseUri */ -#define URI_ERROR_REMOVEBASE_REL_BASE 6 /* Given base is not absolute */ -#define URI_ERROR_REMOVEBASE_REL_SOURCE 7 /* Given base is not absolute */ +# define URI_ERROR_REMOVEBASE_REL_BASE 6 /* Given base is not absolute */ +# define URI_ERROR_REMOVEBASE_REL_SOURCE 7 /* Given base is not absolute */ /* Error specific to uriTestMemoryManager */ -#define URI_ERROR_MEMORY_MANAGER_FAULTY 11 /* [>=0.9.0] The UriMemoryManager given did not pass the test suite */ +# define URI_ERROR_MEMORY_MANAGER_FAULTY \ + 11 /* [>=0.9.0] The UriMemoryManager given did not pass the test suite */ /* Error specific to uriSetUserInfo */ -#define URI_ERROR_SETUSERINFO_HOST_NOT_SET 12 /* [>=0.9.9] The %URI given does not have the host set */ +# define URI_ERROR_SETUSERINFO_HOST_NOT_SET \ + 12 /* [>=0.9.9] The %URI given does not have the host set */ /* Error specific to uriSetPort */ -#define URI_ERROR_SETPORT_HOST_NOT_SET 13 /* [>=0.9.9] The %URI given does not have the host set */ +# define URI_ERROR_SETPORT_HOST_NOT_SET \ + 13 /* [>=0.9.9] The %URI given does not have the host set */ /* Error specific to uriSetHost* */ -#define URI_ERROR_SETHOST_USERINFO_SET 14 /* [>=0.9.9] The %URI given does have user info set */ -#define URI_ERROR_SETHOST_PORT_SET 15 /* [>=0.9.9] The %URI given does have a port set */ - - - -#ifndef URI_DOXYGEN -# include /* For NULL, snprintf */ -# include /* For wchar_t */ -# include /* For strlen, memset, memcpy */ -# include /* For malloc */ -#endif /* URI_DOXYGEN */ - - +# define URI_ERROR_SETHOST_USERINFO_SET \ + 14 /* [>=0.9.9] The %URI given does have user info set */ +# define URI_ERROR_SETHOST_PORT_SET \ + 15 /* [>=0.9.9] The %URI given does have a port set */ + +# ifndef URI_DOXYGEN +# include /* For NULL, snprintf */ +# include /* For wchar_t */ +# include /* For strlen, memset, memcpy */ +# include /* For malloc */ +# endif /* URI_DOXYGEN */ /** * Holds an IPv4 address. */ typedef struct UriIp4Struct { - unsigned char data[4]; /**< Each octet in one byte */ + unsigned char data[4]; /**< Each octet in one byte */ } UriIp4; /**< @copydoc UriIp4Struct */ - - /** * Holds an IPv6 address. */ typedef struct UriIp6Struct { - unsigned char data[16]; /**< Each quad in two bytes */ + unsigned char data[16]; /**< Each quad in two bytes */ } UriIp6; /**< @copydoc UriIp6Struct */ - -struct UriMemoryManagerStruct; /* forward declaration to break loop */ - +struct UriMemoryManagerStruct; /* forward declaration to break loop */ /** * Function signature that custom malloc(3) functions must conform to @@ -216,7 +200,8 @@ typedef void * (*UriFuncRealloc)(struct UriMemoryManagerStruct *, void *, size_t * * @since 0.9.0 */ -typedef void * (*UriFuncReallocarray)(struct UriMemoryManagerStruct *, void *, size_t, size_t); +typedef void * (*UriFuncReallocarray)(struct UriMemoryManagerStruct *, void *, size_t, + size_t); /** * Function signature that custom free(3) functions must conform to @@ -225,7 +210,6 @@ typedef void * (*UriFuncReallocarray)(struct UriMemoryManagerStruct *, void *, s */ typedef void (*UriFuncFree)(struct UriMemoryManagerStruct *, void *); - /** * Class-like interface of custom memory managers * @@ -236,56 +220,58 @@ typedef void (*UriFuncFree)(struct UriMemoryManagerStruct *, void *); * @since 0.9.0 */ typedef struct UriMemoryManagerStruct { - UriFuncMalloc malloc; /**< Pointer to custom malloc(3) */ - UriFuncCalloc calloc; /**< Pointer to custom calloc(3); to emulate using malloc and memset see uriEmulateCalloc */ - UriFuncRealloc realloc; /**< Pointer to custom realloc(3) */ - UriFuncReallocarray reallocarray; /**< Pointer to custom reallocarray(3); to emulate using realloc see uriEmulateReallocarray */ - UriFuncFree free; /**< Pointer to custom free(3) */ - void * userData; /**< Pointer to data that the other function members need access to */ + UriFuncMalloc malloc; /**< Pointer to custom malloc(3) */ + UriFuncCalloc calloc; /**< Pointer to custom calloc(3); to emulate using malloc and + memset see uriEmulateCalloc */ + UriFuncRealloc realloc; /**< Pointer to custom realloc(3) */ + UriFuncReallocarray reallocarray; /**< Pointer to custom reallocarray(3); to emulate + using realloc see uriEmulateReallocarray */ + UriFuncFree free; /**< Pointer to custom free(3) */ + void * + userData; /**< Pointer to data that the other function members need access to */ } UriMemoryManager; /**< @copydoc UriMemoryManagerStruct */ - /** * Specifies a line break conversion mode. */ typedef enum UriBreakConversionEnum { - URI_BR_TO_LF, /**< Convert to Unix line breaks ("\\x0a") */ - URI_BR_TO_CRLF, /**< Convert to Windows line breaks ("\\x0d\\x0a") */ - URI_BR_TO_CR, /**< Convert to Macintosh line breaks ("\\x0d") */ - URI_BR_TO_UNIX = URI_BR_TO_LF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_LF */ - URI_BR_TO_WINDOWS = URI_BR_TO_CRLF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CRLF */ - URI_BR_TO_MAC = URI_BR_TO_CR, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CR */ - URI_BR_DONT_TOUCH /**< Copy line breaks unmodified */ + URI_BR_TO_LF, /**< Convert to Unix line breaks ("\\x0a") */ + URI_BR_TO_CRLF, /**< Convert to Windows line breaks ("\\x0d\\x0a") */ + URI_BR_TO_CR, /**< Convert to Macintosh line breaks ("\\x0d") */ + URI_BR_TO_UNIX = URI_BR_TO_LF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_LF */ + URI_BR_TO_WINDOWS = + URI_BR_TO_CRLF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CRLF */ + URI_BR_TO_MAC = URI_BR_TO_CR, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CR */ + URI_BR_DONT_TOUCH /**< Copy line breaks unmodified */ } UriBreakConversion; /**< @copydoc UriBreakConversionEnum */ - - /** * Specifies which component of a %URI has to be normalized. */ typedef enum UriNormalizationMaskEnum { - URI_NORMALIZED = 0, /**< Do not normalize anything */ - URI_NORMALIZE_SCHEME = 1 << 0, /**< Normalize scheme (fix uppercase letters) */ - URI_NORMALIZE_USER_INFO = 1 << 1, /**< Normalize user info (fix uppercase percent-encodings) */ - URI_NORMALIZE_HOST = 1 << 2, /**< Normalize host (fix uppercase letters) */ - URI_NORMALIZE_PATH = 1 << 3, /**< Normalize path (fix uppercase percent-encodings and redundant dot segments) */ - URI_NORMALIZE_QUERY = 1 << 4, /**< Normalize query (fix uppercase percent-encodings) */ - URI_NORMALIZE_FRAGMENT = 1 << 5, /**< Normalize fragment (fix uppercase percent-encodings) */ - URI_NORMALIZE_PORT = 1 << 6 /**< Normalize port (drop leading zeros) @since 0.9.9 */ + URI_NORMALIZED = 0, /**< Do not normalize anything */ + URI_NORMALIZE_SCHEME = 1 << 0, /**< Normalize scheme (fix uppercase letters) */ + URI_NORMALIZE_USER_INFO = + 1 << 1, /**< Normalize user info (fix uppercase percent-encodings) */ + URI_NORMALIZE_HOST = 1 << 2, /**< Normalize host (fix uppercase letters) */ + URI_NORMALIZE_PATH = 1 << 3, /**< Normalize path (fix uppercase percent-encodings and + redundant dot segments) */ + URI_NORMALIZE_QUERY = + 1 << 4, /**< Normalize query (fix uppercase percent-encodings) */ + URI_NORMALIZE_FRAGMENT = + 1 << 5, /**< Normalize fragment (fix uppercase percent-encodings) */ + URI_NORMALIZE_PORT = 1 << 6 /**< Normalize port (drop leading zeros) @since 0.9.9 */ } UriNormalizationMask; /**< @copydoc UriNormalizationMaskEnum */ - - /** * Specifies how to resolve %URI references. */ typedef enum UriResolutionOptionsEnum { - URI_RESOLVE_STRICTLY = 0, /**< Full RFC conformance */ - URI_RESOLVE_IDENTICAL_SCHEME_COMPAT = 1 << 0 /**< Treat %URI to resolve with identical scheme as having no scheme */ + URI_RESOLVE_STRICTLY = 0, /**< Full RFC conformance */ + URI_RESOLVE_IDENTICAL_SCHEME_COMPAT = + 1 << 0 /**< Treat %URI to resolve with identical scheme as having no scheme */ } UriResolutionOptions; /**< @copydoc UriResolutionOptionsEnum */ - - /** * Wraps a memory manager backend that only provides malloc(3) and * free(3) to make a complete memory manager ready to be used. @@ -322,9 +308,7 @@ typedef enum UriResolutionOptionsEnum { * @since 0.9.0 */ URI_PUBLIC int uriCompleteMemoryManager(UriMemoryManager * memory, - UriMemoryManager * backend); - - + UriMemoryManager * backend); /** * Offers emulation of calloc(3) based on memory->malloc and memset. @@ -340,10 +324,7 @@ URI_PUBLIC int uriCompleteMemoryManager(UriMemoryManager * memory, * @see UriMemoryManager * @since 0.9.0 */ -URI_PUBLIC void * uriEmulateCalloc(UriMemoryManager * memory, - size_t nmemb, size_t size); - - +URI_PUBLIC void * uriEmulateCalloc(UriMemoryManager * memory, size_t nmemb, size_t size); /** * Offers emulation of reallocarray(3) based on memory->realloc. @@ -360,10 +341,8 @@ URI_PUBLIC void * uriEmulateCalloc(UriMemoryManager * memory, * @see UriMemoryManager * @since 0.9.0 */ -URI_PUBLIC void * uriEmulateReallocarray(UriMemoryManager * memory, - void * ptr, size_t nmemb, size_t size); - - +URI_PUBLIC void * uriEmulateReallocarray(UriMemoryManager * memory, void * ptr, + size_t nmemb, size_t size); /** * Run multiple tests against a given memory manager. @@ -392,8 +371,6 @@ URI_PUBLIC void * uriEmulateReallocarray(UriMemoryManager * memory, */ URI_PUBLIC int uriTestMemoryManager(UriMemoryManager * memory); - - /** * Run multiple tests against a given memory manager. * For example, one test @@ -417,10 +394,9 @@ URI_PUBLIC int uriTestMemoryManager(UriMemoryManager * memory); * @see uriEmulateReallocarray * @see UriMemoryManager * @see uriTestMemoryManager - * @since 0.9.10 + * @since 1.0.0 */ -URI_PUBLIC int uriTestMemoryManagerEx(UriMemoryManager * memory, UriBool challengeAlignment); - - +URI_PUBLIC int uriTestMemoryManagerEx(UriMemoryManager * memory, + UriBool challengeAlignment); #endif /* URI_BASE_H */ diff --git a/ext/uri/uriparser/include/uriparser/UriDefsAnsi.h b/ext/uri/uriparser/include/uriparser/UriDefsAnsi.h index af581b91a2152..17aed1b3b59e8 100644 --- a/ext/uri/uriparser/include/uriparser/UriDefsAnsi.h +++ b/ext/uri/uriparser/include/uriparser/UriDefsAnsi.h @@ -46,24 +46,18 @@ /* Allow multi inclusion */ #include "UriDefsConfig.h" - - #undef URI_CHAR #define URI_CHAR char #undef _UT #define _UT(x) x - - #undef URI_FUNC #define URI_FUNC(x) uri##x##A #undef URI_TYPE #define URI_TYPE(x) Uri##x##A - - #undef URI_STRLEN #define URI_STRLEN strlen #undef URI_STRCPY @@ -76,7 +70,7 @@ /* TODO Remove on next source-compatibility break */ #undef URI_SNPRINTF #if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32)) -# define URI_SNPRINTF _snprintf +# define URI_SNPRINTF _snprintf #else -# define URI_SNPRINTF snprintf +# define URI_SNPRINTF snprintf #endif diff --git a/ext/uri/uriparser/include/uriparser/UriDefsConfig.h b/ext/uri/uriparser/include/uriparser/UriDefsConfig.h index 51bc93eeddaae..79d485d90c380 100644 --- a/ext/uri/uriparser/include/uriparser/UriDefsConfig.h +++ b/ext/uri/uriparser/include/uriparser/UriDefsConfig.h @@ -43,59 +43,51 @@ */ #ifndef URI_DEFS_CONFIG_H -#define URI_DEFS_CONFIG_H 1 - - +# define URI_DEFS_CONFIG_H 1 /* Deny external overriding */ -#undef URI_ENABLE_ANSI /* Internal for !URI_NO_ANSI */ -#undef URI_ENABLE_UNICODE /* Internal for !URI_NO_UNICODE */ - - +# undef URI_ENABLE_ANSI /* Internal for !URI_NO_ANSI */ +# undef URI_ENABLE_UNICODE /* Internal for !URI_NO_UNICODE */ /* Encoding */ -#ifdef URI_NO_ANSI -# ifdef URI_NO_UNICODE +# ifdef URI_NO_ANSI +# ifdef URI_NO_UNICODE /* No encoding at all */ -# error URI_NO_ANSI and URI_NO_UNICODE cannot go together. -# else +# error URI_NO_ANSI and URI_NO_UNICODE cannot go together. +# else /* Wide strings only */ -# define URI_ENABLE_UNICODE 1 -# endif -#else -# ifdef URI_NO_UNICODE +# define URI_ENABLE_UNICODE 1 +# endif +# else +# ifdef URI_NO_UNICODE /* Narrow strings only */ -# define URI_ENABLE_ANSI 1 -# else +# define URI_ENABLE_ANSI 1 +# else /* Both narrow and wide strings */ -# define URI_ENABLE_ANSI 1 -# define URI_ENABLE_UNICODE 1 -# endif -#endif - - +# define URI_ENABLE_ANSI 1 +# define URI_ENABLE_UNICODE 1 +# endif +# endif /* Function inlining, not ANSI/ISO C! */ -#if defined(URI_DOXYGEN) -# define URI_INLINE -#elif defined(__INTEL_COMPILER) +# if defined(URI_DOXYGEN) +# define URI_INLINE +# elif defined(__INTEL_COMPILER) /* Intel C/C++ */ /* http://predef.sourceforge.net/precomp.html#sec20 */ /* http://www.intel.com/support/performancetools/c/windows/sb/CS-007751.htm#2 */ -# define URI_INLINE __forceinline -#elif defined(_MSC_VER) +# define URI_INLINE __forceinline +# elif defined(_MSC_VER) /* Microsoft Visual C++ */ /* http://predef.sourceforge.net/precomp.html#sec32 */ /* http://msdn2.microsoft.com/en-us/library/ms882281.aspx */ -# define URI_INLINE __forceinline -#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) +# define URI_INLINE __forceinline +# elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99, "inline" is a keyword */ -# define URI_INLINE inline -#else +# define URI_INLINE inline +# else /* No inlining */ -# define URI_INLINE -#endif - - +# define URI_INLINE +# endif #endif /* URI_DEFS_CONFIG_H */ diff --git a/ext/uri/uriparser/include/uriparser/UriDefsUnicode.h b/ext/uri/uriparser/include/uriparser/UriDefsUnicode.h index 01421f5f861df..6fce6725e69b7 100644 --- a/ext/uri/uriparser/include/uriparser/UriDefsUnicode.h +++ b/ext/uri/uriparser/include/uriparser/UriDefsUnicode.h @@ -46,24 +46,18 @@ /* Allow multi inclusion */ #include "UriDefsConfig.h" - - #undef URI_CHAR #define URI_CHAR wchar_t #undef _UT #define _UT(x) L##x - - #undef URI_FUNC #define URI_FUNC(x) uri##x##W #undef URI_TYPE #define URI_TYPE(x) Uri##x##W - - #undef URI_STRLEN #define URI_STRLEN wcslen #undef URI_STRCPY @@ -76,7 +70,7 @@ /* TODO Remove on next source-compatibility break */ #undef URI_SNPRINTF #if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32)) -# define URI_SNPRINTF _snwprintf +# define URI_SNPRINTF _snwprintf #else -# define URI_SNPRINTF swprintf +# define URI_SNPRINTF swprintf #endif diff --git a/ext/uri/uriparser/include/uriparser/UriIp4.h b/ext/uri/uriparser/include/uriparser/UriIp4.h index 4b847abe3ab7c..5f84b62dd2fce 100644 --- a/ext/uri/uriparser/include/uriparser/UriIp4.h +++ b/ext/uri/uriparser/include/uriparser/UriIp4.h @@ -44,48 +44,43 @@ */ #if (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI)) \ - || (defined(URI_PASS_UNICODE) && !defined(URI_IP4_TWICE_H_UNICODE)) \ - || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) + || (defined(URI_PASS_UNICODE) && !defined(URI_IP4_TWICE_H_UNICODE)) \ + || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* What encodings are enabled? */ -#include "UriDefsConfig.h" -#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) +# include "UriDefsConfig.h" +# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriIp4.h" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriIp4.h" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriIp4.h" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriIp4.h" +# undef URI_PASS_UNICODE +# endif /* Only one pass for each encoding */ -#elif (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI) \ - && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ - && !defined(URI_IP4_TWICE_H_UNICODE) && defined(URI_ENABLE_UNICODE)) -# ifdef URI_PASS_ANSI -# define URI_IP4_TWICE_H_ANSI 1 -# include "UriDefsAnsi.h" -# else -# define URI_IP4_TWICE_H_UNICODE 1 -# include "UriDefsUnicode.h" -# include -# endif - - - -#ifdef __cplusplus +# elif (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI) \ + && defined(URI_ENABLE_ANSI)) \ + || (defined(URI_PASS_UNICODE) && !defined(URI_IP4_TWICE_H_UNICODE) \ + && defined(URI_ENABLE_UNICODE)) +# ifdef URI_PASS_ANSI +# define URI_IP4_TWICE_H_ANSI 1 +# include "UriDefsAnsi.h" +# else +# define URI_IP4_TWICE_H_UNICODE 1 +# include "UriDefsUnicode.h" +# include +# endif + +# ifdef __cplusplus extern "C" { -#endif - - - -#ifndef URI_DOXYGEN -# include "UriBase.h" -#endif - +# endif +# ifndef URI_DOXYGEN +# include "UriBase.h" +# endif /** * Converts an IPv4 text representation into four bytes. @@ -99,15 +94,12 @@ extern "C" { * @see uriParseIpSixAddressMmA */ URI_PUBLIC int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput, - const URI_CHAR * first, const URI_CHAR * afterLast); - + const URI_CHAR * first, + const URI_CHAR * afterLast); - -#ifdef __cplusplus +# ifdef __cplusplus } -#endif +# endif - - -#endif +# endif #endif diff --git a/ext/uri/uriparser/src/UriCommon.c b/ext/uri/uriparser/src/UriCommon.c index a644eec475367..3644e8828f35f 100644 --- a/ext/uri/uriparser/src/UriCommon.c +++ b/ext/uri/uriparser/src/UriCommon.c @@ -41,669 +41,643 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriCommon.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriCommon.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriCommon.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriCommon.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -#endif - - - -#include +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriSets.h" +# endif +# include /*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X"); /*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT("."); /*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT(".."); - - void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) { - if (uri == NULL) { - return; - } - memset(uri, 0, sizeof(URI_TYPE(Uri))); + if (uri == NULL) { + return; + } + memset(uri, 0, sizeof(URI_TYPE(Uri))); } - - int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { - assert(uri != NULL); - assert(memory != NULL); - - if (uri->pathHead != NULL) { - URI_TYPE(PathSegment) * segWalk = uri->pathHead; - while (segWalk != NULL) { - URI_TYPE(PathSegment) * const next = segWalk->next; - if ((uri->owner == URI_TRUE) && (segWalk->text.first != segWalk->text.afterLast)) { - memory->free(memory, (URI_CHAR *)segWalk->text.first); - } - segWalk->text.first = NULL; - segWalk->text.afterLast = NULL; - segWalk->next = NULL; - memory->free(memory, segWalk); - segWalk = next; - } - uri->pathHead = NULL; - uri->pathTail = NULL; - } - - return URI_SUCCESS; + assert(uri != NULL); + assert(memory != NULL); + + if (uri->pathHead != NULL) { + URI_TYPE(PathSegment) * segWalk = uri->pathHead; + while (segWalk != NULL) { + URI_TYPE(PathSegment) * const next = segWalk->next; + if ((uri->owner == URI_TRUE) + && (segWalk->text.first != segWalk->text.afterLast)) { + memory->free(memory, (URI_CHAR *)segWalk->text.first); + } + segWalk->text.first = NULL; + segWalk->text.afterLast = NULL; + segWalk->next = NULL; + memory->free(memory, segWalk); + segWalk = next; + } + uri->pathHead = NULL; + uri->pathTail = NULL; + } + + return URI_SUCCESS; } - - /* Compares two text ranges for equal text content */ -int URI_FUNC(CompareRange)( - const URI_TYPE(TextRange) * a, - const URI_TYPE(TextRange) * b) { - int diff; - - /* NOTE: Both NULL means equal! */ - if ((a == NULL) || (b == NULL)) { - return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1); - } - - /* NOTE: Both NULL means equal! */ - if ((a->first == NULL) || (b->first == NULL)) { - return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1); - } - - diff = ((int)(a->afterLast - a->first) - (int)(b->afterLast - b->first)); - if (diff > 0) { - return 1; - } else if (diff < 0) { - return -1; - } - - diff = URI_STRNCMP(a->first, b->first, (a->afterLast - a->first)); - - if (diff > 0) { - return 1; - } else if (diff < 0) { - return -1; - } - - return diff; +int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b) { + int diff; + + /* NOTE: Both NULL means equal! */ + if ((a == NULL) || (b == NULL)) { + return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1); + } + + /* NOTE: Both NULL means equal! */ + if ((a->first == NULL) || (b->first == NULL)) { + return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1); + } + + diff = ((int)(a->afterLast - a->first) - (int)(b->afterLast - b->first)); + if (diff > 0) { + return 1; + } else if (diff < 0) { + return -1; + } + + diff = URI_STRNCMP(a->first, b->first, (a->afterLast - a->first)); + + if (diff > 0) { + return 1; + } else if (diff < 0) { + return -1; + } + + return diff; } - - UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange, - const URI_TYPE(TextRange) * sourceRange, UriMemoryManager * memory) { - const int lenInChars = (int)(sourceRange->afterLast - sourceRange->first); - const int lenInBytes = lenInChars * sizeof(URI_CHAR); - URI_CHAR * dup = memory->malloc(memory, lenInBytes); - if (dup == NULL) { - return URI_FALSE; - } - memcpy(dup, sourceRange->first, lenInBytes); - destRange->first = dup; - destRange->afterLast = dup + lenInChars; - - return URI_TRUE; + const URI_TYPE(TextRange) * sourceRange, + UriMemoryManager * memory) { + const int lenInChars = (int)(sourceRange->afterLast - sourceRange->first); + const int lenInBytes = lenInChars * sizeof(URI_CHAR); + URI_CHAR * dup = memory->malloc(memory, lenInBytes); + if (dup == NULL) { + return URI_FALSE; + } + memcpy(dup, sourceRange->first, lenInBytes); + destRange->first = dup; + destRange->afterLast = dup + lenInChars; + + return URI_TRUE; } - - UriBool URI_FUNC(CopyRangeAsNeeded)(URI_TYPE(TextRange) * destRange, - const URI_TYPE(TextRange) * sourceRange, UriMemoryManager * memory) { - if (sourceRange->first == NULL) { - destRange->first = NULL; - destRange->afterLast = NULL; - } else if (sourceRange->first == sourceRange->afterLast) { - destRange->first = URI_FUNC(SafeToPointTo); - destRange->afterLast = URI_FUNC(SafeToPointTo); - } else { - return URI_FUNC(CopyRange)(destRange, sourceRange, memory); - } - - return URI_TRUE; + const URI_TYPE(TextRange) * sourceRange, + UriMemoryManager * memory) { + if (sourceRange->first == NULL) { + destRange->first = NULL; + destRange->afterLast = NULL; + } else if (sourceRange->first == sourceRange->afterLast) { + destRange->first = URI_FUNC(SafeToPointTo); + destRange->afterLast = URI_FUNC(SafeToPointTo); + } else { + return URI_FUNC(CopyRange)(destRange, sourceRange, memory); + } + + return URI_TRUE; } - - -UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, - UriBool relative, UriBool pathOwned, UriMemoryManager * memory) { - URI_TYPE(PathSegment) * walker; - if ((uri == NULL) || (uri->pathHead == NULL)) { - return URI_TRUE; - } - - walker = uri->pathHead; - walker->reserved = NULL; /* Prev pointer */ - do { - UriBool removeSegment = URI_FALSE; - int len = (int)(walker->text.afterLast - walker->text.first); - switch (len) { - case 1: - if ((walker->text.first)[0] == _UT('.')) { - /* "." segment -> remove if not essential */ - URI_TYPE(PathSegment) * const prev = walker->reserved; - URI_TYPE(PathSegment) * const nextBackup = walker->next; - - /* - * Is this dot segment essential, - * i.e. is there a chance of changing semantics by dropping this dot segment? - * - * For example, changing "./http://foo" into "http://foo" would change semantics - * and hence the dot segment is essential to that case and cannot be removed. - * - * Other examples that would change semantics are: - * - cutting "/.//" down to "//" - * - cutting "scheme:/.//" down to "scheme://". - */ - removeSegment = URI_TRUE; - if ((walker == uri->pathHead) && (walker->next != NULL)) { - /* Detect case "/.//" (with or without scheme) */ - if ((walker->next->text.first == walker->next->text.afterLast) - && (URI_FUNC(HasHost)(uri) == URI_FALSE)) { - removeSegment = URI_FALSE; - /* Detect case "./withcolon:" */ - } else if (relative) { - const URI_CHAR * ch = walker->next->text.first; - for (; ch < walker->next->text.afterLast; ch++) { - if (*ch == _UT(':')) { - removeSegment = URI_FALSE; - break; - } - } - } - } - - if (removeSegment) { - /* .. then let's go remove that segment. */ - /* Last segment? */ - if (walker->next != NULL) { - /* Not last segment, i.e. first or middle segment - * OLD: (prev|NULL) <- walker <- next - * NEW: (prev|NULL) <----------- next */ - walker->next->reserved = prev; - - if (prev == NULL) { - /* First but not last segment - * OLD: head -> walker -> next - * NEW: head -----------> next */ - uri->pathHead = walker->next; - } else { - /* Middle segment - * OLD: prev -> walker -> next - * NEW: prev -----------> next */ - prev->next = walker->next; - } - - if (pathOwned && (walker->text.first != walker->text.afterLast)) { - memory->free(memory, (URI_CHAR *)walker->text.first); - } - memory->free(memory, walker); - } else { - /* Last segment */ - if (pathOwned && (walker->text.first != walker->text.afterLast)) { - memory->free(memory, (URI_CHAR *)walker->text.first); - } - - if (prev == NULL) { - /* Last and first */ - if (URI_FUNC(HasHost)(uri)) { - /* Replace "." with empty segment to represent trailing slash */ - walker->text.first = URI_FUNC(SafeToPointTo); - walker->text.afterLast = URI_FUNC(SafeToPointTo); - } else { - memory->free(memory, walker); - - uri->pathHead = NULL; - uri->pathTail = NULL; - } - } else { - /* Last but not first, replace "." with empty segment to represent trailing slash */ - walker->text.first = URI_FUNC(SafeToPointTo); - walker->text.afterLast = URI_FUNC(SafeToPointTo); - } - } - - walker = nextBackup; - } - } - break; - - case 2: - if (((walker->text.first)[0] == _UT('.')) - && ((walker->text.first)[1] == _UT('.'))) { - /* Path ".." -> remove this and the previous segment */ - URI_TYPE(PathSegment) * const prev = walker->reserved; - URI_TYPE(PathSegment) * prevPrev; - URI_TYPE(PathSegment) * const nextBackup = walker->next; - - removeSegment = URI_TRUE; - if (relative) { - if (prev == NULL) { - /* We cannot remove traversal beyond because the - * URI is relative and may be resolved later. - * So we can simplify "a/../b/d" to "b/d" but - * we cannot simplify "../b/d" (outside of reference resolution). */ - removeSegment = URI_FALSE; - } else if ((prev != NULL) - && ((prev->text.afterLast - prev->text.first) == 2) - && ((prev->text.first)[0] == _UT('.')) - && ((prev->text.first)[1] == _UT('.'))) { - /* We need to protect against mis-simplifying "a/../../b" to "a/b". */ - removeSegment = URI_FALSE; - } - } - - if (removeSegment) { - if (prev != NULL) { - /* Not first segment */ - prevPrev = prev->reserved; - if (prevPrev != NULL) { - /* Not even prev is the first one - * OLD: prevPrev -> prev -> walker -> (next|NULL) - * NEW: prevPrev -------------------> (next|NULL) */ - prevPrev->next = walker->next; - if (walker->next != NULL) { - /* Update parent relationship as well - * OLD: prevPrev <- prev <- walker <- next - * NEW: prevPrev <------------------- next */ - walker->next->reserved = prevPrev; - } else { - /* Last segment -> insert "" segment to represent trailing slash, update tail */ - URI_TYPE(PathSegment) * const segment = memory->calloc(memory, 1, sizeof(URI_TYPE(PathSegment))); - if (segment == NULL) { - if (pathOwned && (walker->text.first != walker->text.afterLast)) { - memory->free(memory, (URI_CHAR *)walker->text.first); - } - memory->free(memory, walker); - - if (pathOwned && (prev->text.first != prev->text.afterLast)) { - memory->free(memory, (URI_CHAR *)prev->text.first); - } - memory->free(memory, prev); - - return URI_FALSE; /* Raises malloc error */ - } - segment->text.first = URI_FUNC(SafeToPointTo); - segment->text.afterLast = URI_FUNC(SafeToPointTo); - prevPrev->next = segment; - uri->pathTail = segment; - } - - if (pathOwned && (walker->text.first != walker->text.afterLast)) { - memory->free(memory, (URI_CHAR *)walker->text.first); - } - memory->free(memory, walker); - - if (pathOwned && (prev->text.first != prev->text.afterLast)) { - memory->free(memory, (URI_CHAR *)prev->text.first); - } - memory->free(memory, prev); - - walker = nextBackup; - } else { - /* Prev is the first segment */ - if (walker->next != NULL) { - uri->pathHead = walker->next; - walker->next->reserved = NULL; - - if (pathOwned && (walker->text.first != walker->text.afterLast)) { - memory->free(memory, (URI_CHAR *)walker->text.first); - } - memory->free(memory, walker); - } else { - /* Reuse segment for "" path segment to represent trailing slash, update tail */ - URI_TYPE(PathSegment) * const segment = walker; - if (pathOwned && (segment->text.first != segment->text.afterLast)) { - memory->free(memory, (URI_CHAR *)segment->text.first); - } - segment->text.first = URI_FUNC(SafeToPointTo); - segment->text.afterLast = URI_FUNC(SafeToPointTo); - uri->pathHead = segment; - uri->pathTail = segment; - } - - if (pathOwned && (prev->text.first != prev->text.afterLast)) { - memory->free(memory, (URI_CHAR *)prev->text.first); - } - memory->free(memory, prev); - - walker = nextBackup; - } - } else { - URI_TYPE(PathSegment) * const anotherNextBackup = walker->next; - int freeWalker = URI_TRUE; - - /* First segment */ - if (walker->next != NULL) { - /* First segment of multiple -> update head - * OLD: head -> walker -> next - * NEW: head -----------> next */ - uri->pathHead = walker->next; - - /* Update parent link as well - * OLD: head <- walker <- next - * NEW: head <----------- next */ - walker->next->reserved = NULL; - } else { - if (uri->absolutePath) { - /* First and only segment -> update head - * OLD: head -> walker -> NULL - * NEW: head -----------> NULL */ - uri->pathHead = NULL; - - /* Last segment -> update tail - * OLD: tail -> walker - * NEW: tail -> NULL */ - uri->pathTail = NULL; - } else { - /* Reuse segment for "" path segment to represent trailing slash, - * then update head and tail */ - if (pathOwned && (walker->text.first != walker->text.afterLast)) { - memory->free(memory, (URI_CHAR *)walker->text.first); - } - walker->text.first = URI_FUNC(SafeToPointTo); - walker->text.afterLast = URI_FUNC(SafeToPointTo); - freeWalker = URI_FALSE; - } - } - - if (freeWalker) { - if (pathOwned && (walker->text.first != walker->text.afterLast)) { - memory->free(memory, (URI_CHAR *)walker->text.first); - } - memory->free(memory, walker); - } - - walker = anotherNextBackup; - } - } - } - break; - } /* end of switch */ - - if (!removeSegment) { - /* .. then let's move to the next element, and start again. */ - if (walker->next != NULL) { - walker->next->reserved = walker; - } else { - /* Last segment -> update tail */ - uri->pathTail = walker; - } - walker = walker->next; - } - } while (walker != NULL); - - return URI_TRUE; +UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool relative, + UriBool pathOwned, UriMemoryManager * memory) { + URI_TYPE(PathSegment) * walker; + if ((uri == NULL) || (uri->pathHead == NULL)) { + return URI_TRUE; + } + + walker = uri->pathHead; + walker->reserved = NULL; /* Prev pointer */ + do { + UriBool removeSegment = URI_FALSE; + int len = (int)(walker->text.afterLast - walker->text.first); + switch (len) { + case 1: + if ((walker->text.first)[0] == _UT('.')) { + /* "." segment -> remove if not essential */ + URI_TYPE(PathSegment) * const prev = walker->reserved; + URI_TYPE(PathSegment) * const nextBackup = walker->next; + + /* + * Is this dot segment essential, + * i.e. is there a chance of changing semantics by dropping this dot + * segment? + * + * For example, changing "./http://foo" into "http://foo" would change + * semantics and hence the dot segment is essential to that case and + * cannot be removed. + * + * Other examples that would change semantics are: + * - cutting "/.//" down to "//" + * - cutting "scheme:/.//" down to "scheme://". + */ + removeSegment = URI_TRUE; + if ((walker == uri->pathHead) && (walker->next != NULL)) { + /* Detect case "/.//" (with or without scheme) */ + if ((walker->next->text.first == walker->next->text.afterLast) + && (URI_FUNC(HasHost)(uri) == URI_FALSE)) { + removeSegment = URI_FALSE; + /* Detect case "./withcolon:" */ + } else if (relative) { + const URI_CHAR * ch = walker->next->text.first; + for (; ch < walker->next->text.afterLast; ch++) { + if (*ch == _UT(':')) { + removeSegment = URI_FALSE; + break; + } + } + } + } + + if (removeSegment) { + /* .. then let's go remove that segment. */ + /* Last segment? */ + if (walker->next != NULL) { + /* Not last segment, i.e. first or middle segment + * OLD: (prev|NULL) <- walker <- next + * NEW: (prev|NULL) <----------- next */ + walker->next->reserved = prev; + + if (prev == NULL) { + /* First but not last segment + * OLD: head -> walker -> next + * NEW: head -----------> next */ + uri->pathHead = walker->next; + } else { + /* Middle segment + * OLD: prev -> walker -> next + * NEW: prev -----------> next */ + prev->next = walker->next; + } + + if (pathOwned && (walker->text.first != walker->text.afterLast)) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + memory->free(memory, walker); + } else { + /* Last segment */ + if (pathOwned && (walker->text.first != walker->text.afterLast)) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + + if (prev == NULL) { + /* Last and first */ + if (URI_FUNC(HasHost)(uri)) { + /* Replace "." with empty segment to represent trailing + * slash */ + walker->text.first = URI_FUNC(SafeToPointTo); + walker->text.afterLast = URI_FUNC(SafeToPointTo); + } else { + memory->free(memory, walker); + + uri->pathHead = NULL; + uri->pathTail = NULL; + } + } else { + /* Last but not first, replace "." with empty segment to + * represent trailing slash */ + walker->text.first = URI_FUNC(SafeToPointTo); + walker->text.afterLast = URI_FUNC(SafeToPointTo); + } + } + + walker = nextBackup; + } + } + break; + + case 2: + if (((walker->text.first)[0] == _UT('.')) + && ((walker->text.first)[1] == _UT('.'))) { + /* Path ".." -> remove this and the previous segment */ + URI_TYPE(PathSegment) * const prev = walker->reserved; + URI_TYPE(PathSegment) * prevPrev; + URI_TYPE(PathSegment) * const nextBackup = walker->next; + + removeSegment = URI_TRUE; + if (relative) { + if (prev == NULL) { + /* We cannot remove traversal beyond because the + * URI is relative and may be resolved later. + * So we can simplify "a/../b/d" to "b/d" but + * we cannot simplify "../b/d" (outside of reference resolution). + */ + removeSegment = URI_FALSE; + } else if ((prev != NULL) + && ((prev->text.afterLast - prev->text.first) == 2) + && ((prev->text.first)[0] == _UT('.')) + && ((prev->text.first)[1] == _UT('.'))) { + /* We need to protect against mis-simplifying "a/../../b" to + * "a/b". */ + removeSegment = URI_FALSE; + } + } + + if (removeSegment) { + if (prev != NULL) { + /* Not first segment */ + prevPrev = prev->reserved; + if (prevPrev != NULL) { + /* Not even prev is the first one + * OLD: prevPrev -> prev -> walker -> (next|NULL) + * NEW: prevPrev -------------------> (next|NULL) */ + prevPrev->next = walker->next; + if (walker->next != NULL) { + /* Update parent relationship as well + * OLD: prevPrev <- prev <- walker <- next + * NEW: prevPrev <------------------- next */ + walker->next->reserved = prevPrev; + } else { + /* Last segment -> insert "" segment to represent trailing + * slash, update tail */ + URI_TYPE(PathSegment) * const segment = memory->calloc( + memory, 1, sizeof(URI_TYPE(PathSegment))); + if (segment == NULL) { + if (pathOwned + && (walker->text.first + != walker->text.afterLast)) { + memory->free(memory, + (URI_CHAR *)walker->text.first); + } + memory->free(memory, walker); + + if (pathOwned + && (prev->text.first != prev->text.afterLast)) { + memory->free(memory, + (URI_CHAR *)prev->text.first); + } + memory->free(memory, prev); + + return URI_FALSE; /* Raises malloc error */ + } + segment->text.first = URI_FUNC(SafeToPointTo); + segment->text.afterLast = URI_FUNC(SafeToPointTo); + prevPrev->next = segment; + uri->pathTail = segment; + } + + if (pathOwned + && (walker->text.first != walker->text.afterLast)) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + memory->free(memory, walker); + + if (pathOwned && (prev->text.first != prev->text.afterLast)) { + memory->free(memory, (URI_CHAR *)prev->text.first); + } + memory->free(memory, prev); + + walker = nextBackup; + } else { + /* Prev is the first segment */ + if (walker->next != NULL) { + uri->pathHead = walker->next; + walker->next->reserved = NULL; + + if (pathOwned + && (walker->text.first != walker->text.afterLast)) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + memory->free(memory, walker); + } else { + /* Reuse segment for "" path segment to represent trailing + * slash, update tail */ + URI_TYPE(PathSegment) * const segment = walker; + if (pathOwned + && (segment->text.first != segment->text.afterLast)) { + memory->free(memory, (URI_CHAR *)segment->text.first); + } + segment->text.first = URI_FUNC(SafeToPointTo); + segment->text.afterLast = URI_FUNC(SafeToPointTo); + uri->pathHead = segment; + uri->pathTail = segment; + } + + if (pathOwned && (prev->text.first != prev->text.afterLast)) { + memory->free(memory, (URI_CHAR *)prev->text.first); + } + memory->free(memory, prev); + + walker = nextBackup; + } + } else { + URI_TYPE(PathSegment) * const anotherNextBackup = walker->next; + int freeWalker = URI_TRUE; + + /* First segment */ + if (walker->next != NULL) { + /* First segment of multiple -> update head + * OLD: head -> walker -> next + * NEW: head -----------> next */ + uri->pathHead = walker->next; + + /* Update parent link as well + * OLD: head <- walker <- next + * NEW: head <----------- next */ + walker->next->reserved = NULL; + } else { + if (uri->absolutePath) { + /* First and only segment -> update head + * OLD: head -> walker -> NULL + * NEW: head -----------> NULL */ + uri->pathHead = NULL; + + /* Last segment -> update tail + * OLD: tail -> walker + * NEW: tail -> NULL */ + uri->pathTail = NULL; + } else { + /* Reuse segment for "" path segment to represent trailing + * slash, then update head and tail */ + if (pathOwned + && (walker->text.first != walker->text.afterLast)) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + walker->text.first = URI_FUNC(SafeToPointTo); + walker->text.afterLast = URI_FUNC(SafeToPointTo); + freeWalker = URI_FALSE; + } + } + + if (freeWalker) { + if (pathOwned + && (walker->text.first != walker->text.afterLast)) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + memory->free(memory, walker); + } + + walker = anotherNextBackup; + } + } + } + break; + } /* end of switch */ + + if (!removeSegment) { + /* .. then let's move to the next element, and start again. */ + if (walker->next != NULL) { + walker->next->reserved = walker; + } else { + /* Last segment -> update tail */ + uri->pathTail = walker; + } + walker = walker->next; + } + } while (walker != NULL); + + return URI_TRUE; } - - /* Properly removes "." and ".." path segments */ UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory) { - const UriBool ABSOLUTE = URI_FALSE; - if (uri == NULL) { - return URI_TRUE; - } - return URI_FUNC(RemoveDotSegmentsEx)(uri, ABSOLUTE, uri->owner, memory); + UriMemoryManager * memory) { + const UriBool ABSOLUTE = URI_FALSE; + if (uri == NULL) { + return URI_TRUE; + } + return URI_FUNC(RemoveDotSegmentsEx)(uri, ABSOLUTE, uri->owner, memory); } - - unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) { - switch (hexdig) { - case _UT('0'): - case _UT('1'): - case _UT('2'): - case _UT('3'): - case _UT('4'): - case _UT('5'): - case _UT('6'): - case _UT('7'): - case _UT('8'): - case _UT('9'): - return (unsigned char)(9 + hexdig - _UT('9')); - - case _UT('a'): - case _UT('b'): - case _UT('c'): - case _UT('d'): - case _UT('e'): - case _UT('f'): - return (unsigned char)(15 + hexdig - _UT('f')); - - case _UT('A'): - case _UT('B'): - case _UT('C'): - case _UT('D'): - case _UT('E'): - case _UT('F'): - return (unsigned char)(15 + hexdig - _UT('F')); - - default: - return 0; - } + switch (hexdig) { + case URI_SET_DIGIT(_UT): + return (unsigned char)(9 + hexdig - _UT('9')); + case URI_SET_HEX_LETTER_LOWER(_UT): + return (unsigned char)(15 + hexdig - _UT('f')); + case URI_SET_HEX_LETTER_UPPER(_UT): + return (unsigned char)(15 + hexdig - _UT('F')); + + default: + return 0; + } } - - URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) { - switch (value) { - case 0: return _UT('0'); - case 1: return _UT('1'); - case 2: return _UT('2'); - case 3: return _UT('3'); - case 4: return _UT('4'); - case 5: return _UT('5'); - case 6: return _UT('6'); - case 7: return _UT('7'); - case 8: return _UT('8'); - case 9: return _UT('9'); - - case 10: return (uppercase == URI_TRUE) ? _UT('A') : _UT('a'); - case 11: return (uppercase == URI_TRUE) ? _UT('B') : _UT('b'); - case 12: return (uppercase == URI_TRUE) ? _UT('C') : _UT('c'); - case 13: return (uppercase == URI_TRUE) ? _UT('D') : _UT('d'); - case 14: return (uppercase == URI_TRUE) ? _UT('E') : _UT('e'); - default: return (uppercase == URI_TRUE) ? _UT('F') : _UT('f'); - } + switch (value) { + case 0: + return _UT('0'); + case 1: + return _UT('1'); + case 2: + return _UT('2'); + case 3: + return _UT('3'); + case 4: + return _UT('4'); + case 5: + return _UT('5'); + case 6: + return _UT('6'); + case 7: + return _UT('7'); + case 8: + return _UT('8'); + case 9: + return _UT('9'); + + case 10: + return (uppercase == URI_TRUE) ? _UT('A') : _UT('a'); + case 11: + return (uppercase == URI_TRUE) ? _UT('B') : _UT('b'); + case 12: + return (uppercase == URI_TRUE) ? _UT('C') : _UT('c'); + case 13: + return (uppercase == URI_TRUE) ? _UT('D') : _UT('d'); + case 14: + return (uppercase == URI_TRUE) ? _UT('E') : _UT('e'); + default: + return (uppercase == URI_TRUE) ? _UT('F') : _UT('f'); + } } - - /* Checks if a URI has the host component set. */ UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri) { - /* NOTE: .hostData.ipFuture.first is not being checked, * - * because we do check .hostText.first and * - * .hostData.ipFuture.first has to be identical to * - * .hostText.first if set, and hence there is * - * no more information to be gained. */ - return (uri != NULL) - && ((uri->hostText.first != NULL) - || (uri->hostData.ip4 != NULL) - || (uri->hostData.ip6 != NULL) - ); + /* NOTE: .hostData.ipFuture.first is not being checked, * + * because we do check .hostText.first and * + * .hostData.ipFuture.first has to be identical to * + * .hostText.first if set, and hence there is * + * no more information to be gained. */ + return (uri != NULL) + && ((uri->hostText.first != NULL) || (uri->hostData.ip4 != NULL) + || (uri->hostData.ip6 != NULL)); } - - /* Copies the path segment list from one URI to another. */ -UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, - const URI_TYPE(Uri) * source, UriMemoryManager * memory) { - if (source->pathHead == NULL) { - /* No path component */ - dest->pathHead = NULL; - dest->pathTail = NULL; - } else { - /* Copy list but not the text contained */ - URI_TYPE(PathSegment) * sourceWalker = source->pathHead; - URI_TYPE(PathSegment) * destPrev = NULL; - do { - URI_TYPE(PathSegment) * cur = memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); - if (cur == NULL) { - /* Fix broken list */ - if (destPrev != NULL) { - destPrev->next = NULL; - } - return URI_FALSE; /* Raises malloc error */ - } - - /* From this functions usage we know that * - * the dest URI cannot be uri->owner */ - cur->text = sourceWalker->text; - if (destPrev == NULL) { - /* First segment ever */ - dest->pathHead = cur; - } else { - destPrev->next = cur; - } - destPrev = cur; - sourceWalker = sourceWalker->next; - } while (sourceWalker != NULL); - dest->pathTail = destPrev; - dest->pathTail->next = NULL; - } - - dest->absolutePath = source->absolutePath; - return URI_TRUE; +UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source, + UriMemoryManager * memory) { + if (source->pathHead == NULL) { + /* No path component */ + dest->pathHead = NULL; + dest->pathTail = NULL; + } else { + /* Copy list but not the text contained */ + URI_TYPE(PathSegment) * sourceWalker = source->pathHead; + URI_TYPE(PathSegment) * destPrev = NULL; + do { + URI_TYPE(PathSegment) * cur = + memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); + if (cur == NULL) { + /* Fix broken list */ + if (destPrev != NULL) { + destPrev->next = NULL; + } + return URI_FALSE; /* Raises malloc error */ + } + + /* From this functions usage we know that * + * the dest URI cannot be uri->owner */ + cur->text = sourceWalker->text; + if (destPrev == NULL) { + /* First segment ever */ + dest->pathHead = cur; + } else { + destPrev->next = cur; + } + destPrev = cur; + sourceWalker = sourceWalker->next; + } while (sourceWalker != NULL); + dest->pathTail = destPrev; + dest->pathTail->next = NULL; + } + + dest->absolutePath = source->absolutePath; + return URI_TRUE; } - - /* Copies the authority part of an URI over to another. */ -UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, - const URI_TYPE(Uri) * source, UriMemoryManager * memory) { - /* From this functions usage we know that * - * the dest URI cannot be uri->owner */ - - /* Copy userInfo */ - dest->userInfo = source->userInfo; - - /* Copy hostText */ - dest->hostText = source->hostText; - - /* Copy hostData */ - if (source->hostData.ip4 != NULL) { - dest->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4)); - if (dest->hostData.ip4 == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - *(dest->hostData.ip4) = *(source->hostData.ip4); - dest->hostData.ip6 = NULL; - dest->hostData.ipFuture.first = NULL; - dest->hostData.ipFuture.afterLast = NULL; - } else if (source->hostData.ip6 != NULL) { - dest->hostData.ip4 = NULL; - dest->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6)); - if (dest->hostData.ip6 == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - *(dest->hostData.ip6) = *(source->hostData.ip6); - dest->hostData.ipFuture.first = NULL; - dest->hostData.ipFuture.afterLast = NULL; - } else { - dest->hostData.ip4 = NULL; - dest->hostData.ip6 = NULL; - dest->hostData.ipFuture = source->hostData.ipFuture; - } - - /* Copy portText */ - dest->portText = source->portText; - - return URI_TRUE; +UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source, + UriMemoryManager * memory) { + /* From this functions usage we know that * + * the dest URI cannot be uri->owner */ + + /* Copy userInfo */ + dest->userInfo = source->userInfo; + + /* Copy hostText */ + dest->hostText = source->hostText; + + /* Copy hostData */ + if (source->hostData.ip4 != NULL) { + dest->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4)); + if (dest->hostData.ip4 == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + *(dest->hostData.ip4) = *(source->hostData.ip4); + dest->hostData.ip6 = NULL; + dest->hostData.ipFuture.first = NULL; + dest->hostData.ipFuture.afterLast = NULL; + } else if (source->hostData.ip6 != NULL) { + dest->hostData.ip4 = NULL; + dest->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6)); + if (dest->hostData.ip6 == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + *(dest->hostData.ip6) = *(source->hostData.ip6); + dest->hostData.ipFuture.first = NULL; + dest->hostData.ipFuture.afterLast = NULL; + } else { + dest->hostData.ip4 = NULL; + dest->hostData.ip6 = NULL; + dest->hostData.ipFuture = source->hostData.ipFuture; + } + + /* Copy portText */ + dest->portText = source->portText; + + return URI_TRUE; } - - -UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory) { - URI_TYPE(PathSegment) * segment; - - if ( /* Case 1: absolute path, empty first segment */ - (uri->absolutePath - && (uri->pathHead != NULL) - && (uri->pathHead->text.afterLast == uri->pathHead->text.first)) - - /* Case 2: relative path, empty first and second segment */ - || (!uri->absolutePath - && (uri->pathHead != NULL) - && (uri->pathHead->next != NULL) - && (uri->pathHead->text.afterLast == uri->pathHead->text.first) - && (uri->pathHead->next->text.afterLast == uri->pathHead->next->text.first))) { - /* NOOP */ - } else { - return URI_TRUE; - } - - segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment))); - if (segment == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - - /* Insert "." segment in front */ - segment->next = uri->pathHead; - segment->text.first = URI_FUNC(ConstPwd); - segment->text.afterLast = URI_FUNC(ConstPwd) + 1; - uri->pathHead = segment; - return URI_TRUE; +UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { + URI_TYPE(PathSegment) * segment; + + if (/* Case 1: absolute path, empty first segment */ + (uri->absolutePath && (uri->pathHead != NULL) + && (uri->pathHead->text.afterLast == uri->pathHead->text.first)) + + /* Case 2: relative path, empty first and second segment */ + || (!uri->absolutePath && (uri->pathHead != NULL) && (uri->pathHead->next != NULL) + && (uri->pathHead->text.afterLast == uri->pathHead->text.first) + && (uri->pathHead->next->text.afterLast + == uri->pathHead->next->text.first))) { + /* NOOP */ + } else { + return URI_TRUE; + } + + segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment))); + if (segment == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + + /* Insert "." segment in front */ + segment->next = uri->pathHead; + segment->text.first = URI_FUNC(ConstPwd); + segment->text.afterLast = URI_FUNC(ConstPwd) + 1; + uri->pathHead = segment; + return URI_TRUE; } +static UriBool URI_FUNC(PrependNewDotSegment)(URI_TYPE(Uri) * uri, + UriMemoryManager * memory) { + assert(uri != NULL); + assert(memory != NULL); + URI_TYPE(PathSegment) * const segment = + memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment))); -static UriBool URI_FUNC(PrependNewDotSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { - assert(uri != NULL); - assert(memory != NULL); + if (segment == NULL) { + return URI_FALSE; /* i.e. raise malloc error */ + } - { - URI_TYPE(PathSegment) * const segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment))); + segment->next = uri->pathHead; - if (segment == NULL) { - return URI_FALSE; /* i.e. raise malloc error */ - } + URI_TYPE(TextRange) dotRange; + dotRange.first = URI_FUNC(ConstPwd); + dotRange.afterLast = URI_FUNC(ConstPwd) + 1; - segment->next = uri->pathHead; + if (uri->owner == URI_TRUE) { + if (URI_FUNC(CopyRange)(&(segment->text), &dotRange, memory) == URI_FALSE) { + memory->free(memory, segment); + return URI_FALSE; /* i.e. raise malloc error */ + } + } else { + segment->text = dotRange; /* copies all members */ + } - { - URI_TYPE(TextRange) dotRange; - dotRange.first = URI_FUNC(ConstPwd); - dotRange.afterLast = URI_FUNC(ConstPwd) + 1; + uri->pathHead = segment; - if (uri->owner == URI_TRUE) { - if (URI_FUNC(CopyRange)(&(segment->text), &dotRange, memory) == URI_FALSE) { - memory->free(memory, segment); - return URI_FALSE; /* i.e. raise malloc error */ - } - } else { - segment->text = dotRange; /* copies all members */ - } - } - - uri->pathHead = segment; - } - - return URI_TRUE; + return URI_TRUE; } - - /* When dropping a scheme from a URI without a host and with a colon (":") * in the first path segment, a consecutive reparse would rightfully * mis-classify the first path segment as a scheme due to the colon. @@ -721,44 +695,37 @@ static UriBool URI_FUNC(PrependNewDotSegment)(URI_TYPE(Uri) * uri, UriMemoryMana * Returns URI_TRUE for (a) nothing to do or (b) successful changes. * Returns URI_FALSE to signal out-of-memory. */ -UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory) { - assert(uri != NULL); - assert(memory != NULL); - - if ((uri->absolutePath == URI_TRUE) - || (uri->pathHead == NULL) - || (uri->scheme.first != NULL) - || URI_FUNC(HasHost)(uri)) { - return URI_TRUE; /* i.e. nothing to do */ - } - - /* Check for troublesome first path segment containing a colon */ - { - UriBool colonFound = URI_FALSE; - const URI_CHAR * walker = uri->pathHead->text.first; - - while (walker < uri->pathHead->text.afterLast) { - if (walker[0] == _UT(':')) { - colonFound = URI_TRUE; - break; - } - walker++; - } - - assert((walker == uri->pathHead->text.afterLast) || (colonFound == URI_TRUE)); - - if (colonFound == URI_FALSE) { - return URI_TRUE; /* i.e. nothing to do */ - } - } - - /* Insert "." segment in front */ - return URI_FUNC(PrependNewDotSegment)(uri, memory); +UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { + assert(uri != NULL); + assert(memory != NULL); + + if ((uri->absolutePath == URI_TRUE) || (uri->pathHead == NULL) + || (uri->scheme.first != NULL) || URI_FUNC(HasHost)(uri)) { + return URI_TRUE; /* i.e. nothing to do */ + } + + /* Check for troublesome first path segment containing a colon */ + UriBool colonFound = URI_FALSE; + const URI_CHAR * walker = uri->pathHead->text.first; + + while (walker < uri->pathHead->text.afterLast) { + if (walker[0] == _UT(':')) { + colonFound = URI_TRUE; + break; + } + walker++; + } + + assert((walker == uri->pathHead->text.afterLast) || (colonFound == URI_TRUE)); + + if (colonFound == URI_FALSE) { + return URI_TRUE; /* i.e. nothing to do */ + } + + /* Insert "." segment in front */ + return URI_FUNC(PrependNewDotSegment)(uri, memory); } - - /* When dropping a host from a URI without a scheme, an absolute path * and and empty first path segment, a consecutive reparse would rightfully * mis-classify the first path segment as a host marker due to the "//". @@ -774,38 +741,30 @@ UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, * Returns URI_FALSE to signal out-of-memory. */ UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory) { - assert(uri != NULL); - assert(memory != NULL); - - if ((URI_FUNC(HasHost)(uri) == URI_TRUE) - || (uri->absolutePath == URI_FALSE) - || (uri->pathHead == NULL) - || (uri->pathHead == uri->pathTail) /* i.e. no second slash */ - || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) { - return URI_TRUE; /* i.e. nothing to do */ - } - - /* Insert "." segment in front */ - return URI_FUNC(PrependNewDotSegment)(uri, memory); + UriMemoryManager * memory) { + assert(uri != NULL); + assert(memory != NULL); + + if ((URI_FUNC(HasHost)(uri) == URI_TRUE) || (uri->absolutePath == URI_FALSE) + || (uri->pathHead == NULL) + || (uri->pathHead == uri->pathTail) /* i.e. no second slash */ + || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) { + return URI_TRUE; /* i.e. nothing to do */ + } + + /* Insert "." segment in front */ + return URI_FUNC(PrependNewDotSegment)(uri, memory); } - - -void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory) { - /* Fix path if only one empty segment */ - if (!uri->absolutePath - && !URI_FUNC(HasHost)(uri) - && (uri->pathHead != NULL) - && (uri->pathHead->next == NULL) - && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) { - memory->free(memory, uri->pathHead); - uri->pathHead = NULL; - uri->pathTail = NULL; - } +void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { + /* Fix path if only one empty segment */ + if (!uri->absolutePath && !URI_FUNC(HasHost)(uri) && (uri->pathHead != NULL) + && (uri->pathHead->next == NULL) + && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) { + memory->free(memory, uri->pathHead); + uri->pathHead = NULL; + uri->pathTail = NULL; + } } - - #endif diff --git a/ext/uri/uriparser/src/UriCommon.h b/ext/uri/uriparser/src/UriCommon.h index 96beb087a03d3..d141935f19e5a 100644 --- a/ext/uri/uriparser/src/UriCommon.h +++ b/ext/uri/uriparser/src/UriCommon.h @@ -38,35 +38,34 @@ */ #if (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI)) \ - || (defined(URI_PASS_UNICODE) && !defined(URI_COMMON_H_UNICODE)) \ - || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) + || (defined(URI_PASS_UNICODE) && !defined(URI_COMMON_H_UNICODE)) \ + || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* What encodings are enabled? */ -#include -#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) +# include +# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriCommon.h" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriCommon.h" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriCommon.h" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriCommon.h" +# undef URI_PASS_UNICODE +# endif /* Only one pass for each encoding */ -#elif (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI) \ - && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ - && !defined(URI_COMMON_H_UNICODE) && defined(URI_ENABLE_UNICODE)) -# ifdef URI_PASS_ANSI -# define URI_COMMON_H_ANSI 1 -# include -# else -# define URI_COMMON_H_UNICODE 1 -# include -# endif - - +# elif (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI) \ + && defined(URI_ENABLE_ANSI)) \ + || (defined(URI_PASS_UNICODE) && !defined(URI_COMMON_H_UNICODE) \ + && defined(URI_ENABLE_UNICODE)) +# ifdef URI_PASS_ANSI +# define URI_COMMON_H_ANSI 1 +# include +# else +# define URI_COMMON_H_UNICODE 1 +# include +# endif /* Used to point to from empty path segments. * X.first and X.afterLast must be the same non-NULL value then. */ @@ -74,40 +73,37 @@ extern const URI_CHAR * const URI_FUNC(SafeToPointTo); extern const URI_CHAR * const URI_FUNC(ConstPwd); extern const URI_CHAR * const URI_FUNC(ConstParent); - - void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri); int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory); -int URI_FUNC(CompareRange)( - const URI_TYPE(TextRange) * a, - const URI_TYPE(TextRange) * b); +int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b); UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange, - const URI_TYPE(TextRange) * sourceRange, UriMemoryManager * memory); + const URI_TYPE(TextRange) * sourceRange, + UriMemoryManager * memory); UriBool URI_FUNC(CopyRangeAsNeeded)(URI_TYPE(TextRange) * destRange, - const URI_TYPE(TextRange) * sourceRange, UriMemoryManager * memory); + const URI_TYPE(TextRange) * sourceRange, + UriMemoryManager * memory); UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory); -UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, - UriBool relative, UriBool pathOwned, UriMemoryManager * memory); + UriMemoryManager * memory); +UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool relative, + UriBool pathOwned, UriMemoryManager * memory); unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig); URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase); UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source, - UriMemoryManager * memory); -UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, - const URI_TYPE(Uri) * source, UriMemoryManager * memory); + UriMemoryManager * memory); +UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source, + UriMemoryManager * memory); UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri, UriMemoryManager * memory); UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, UriMemoryManager * memory); -UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri, UriMemoryManager * memory); -void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri, - UriMemoryManager * memory); - +UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri, + UriMemoryManager * memory); +void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory); -#endif +# endif #endif diff --git a/ext/uri/uriparser/src/UriCompare.c b/ext/uri/uriparser/src/UriCompare.c index bca3db92361d9..781100e7e6f49 100644 --- a/ext/uri/uriparser/src/UriCompare.c +++ b/ext/uri/uriparser/src/UriCompare.c @@ -41,128 +41,120 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriCompare.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriCompare.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriCompare.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriCompare.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include -# include "UriCommon.h" -#endif - - - -UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, - const URI_TYPE(Uri) * b) { - /* NOTE: Both NULL means equal! */ - if ((a == NULL) || (b == NULL)) { - return ((a == NULL) && (b == NULL)) ? URI_TRUE : URI_FALSE; - } - - /* scheme */ - if (URI_FUNC(CompareRange)(&(a->scheme), &(b->scheme))) { - return URI_FALSE; - } - - /* absolutePath */ - if ((a->scheme.first == NULL)&& (a->absolutePath != b->absolutePath)) { - return URI_FALSE; - } - - /* userInfo */ - if (URI_FUNC(CompareRange)(&(a->userInfo), &(b->userInfo))) { - return URI_FALSE; - } - - /* Host */ - if (((a->hostData.ip4 == NULL) != (b->hostData.ip4 == NULL)) - || ((a->hostData.ip6 == NULL) != (b->hostData.ip6 == NULL)) - || ((a->hostData.ipFuture.first == NULL) - != (b->hostData.ipFuture.first == NULL))) { - return URI_FALSE; - } - - if (a->hostData.ip4 != NULL) { - if (memcmp(a->hostData.ip4->data, b->hostData.ip4->data, 4)) { - return URI_FALSE; - } - } - - if (a->hostData.ip6 != NULL) { - if (memcmp(a->hostData.ip6->data, b->hostData.ip6->data, 16)) { - return URI_FALSE; - } - } - - if (a->hostData.ipFuture.first != NULL) { - if (URI_FUNC(CompareRange)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) { - return URI_FALSE; - } - } - - if ((a->hostData.ip4 == NULL) - && (a->hostData.ip6 == NULL) - && (a->hostData.ipFuture.first == NULL)) { - if (URI_FUNC(CompareRange)(&(a->hostText), &(b->hostText))) { - return URI_FALSE; - } - } - - /* portText */ - if (URI_FUNC(CompareRange)(&(a->portText), &(b->portText))) { - return URI_FALSE; - } - - /* Path */ - if ((a->pathHead == NULL) != (b->pathHead == NULL)) { - return URI_FALSE; - } - - if (a->pathHead != NULL) { - URI_TYPE(PathSegment) * walkA = a->pathHead; - URI_TYPE(PathSegment) * walkB = b->pathHead; - do { - if (URI_FUNC(CompareRange)(&(walkA->text), &(walkB->text))) { - return URI_FALSE; - } - if ((walkA->next == NULL) != (walkB->next == NULL)) { - return URI_FALSE; - } - walkA = walkA->next; - walkB = walkB->next; - } while (walkA != NULL); - } - - /* query */ - if (URI_FUNC(CompareRange)(&(a->query), &(b->query))) { - return URI_FALSE; - } - - /* fragment */ - if (URI_FUNC(CompareRange)(&(a->fragment), &(b->fragment))) { - return URI_FALSE; - } - - return URI_TRUE; /* Equal*/ +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include +# include "UriCommon.h" +# endif + +UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) { + /* NOTE: Both NULL means equal! */ + if ((a == NULL) || (b == NULL)) { + return ((a == NULL) && (b == NULL)) ? URI_TRUE : URI_FALSE; + } + + /* scheme */ + if (URI_FUNC(CompareRange)(&(a->scheme), &(b->scheme))) { + return URI_FALSE; + } + + /* absolutePath */ + if ((a->scheme.first == NULL) && (a->absolutePath != b->absolutePath)) { + return URI_FALSE; + } + + /* userInfo */ + if (URI_FUNC(CompareRange)(&(a->userInfo), &(b->userInfo))) { + return URI_FALSE; + } + + /* Host */ + if (((a->hostData.ip4 == NULL) != (b->hostData.ip4 == NULL)) + || ((a->hostData.ip6 == NULL) != (b->hostData.ip6 == NULL)) + || ((a->hostData.ipFuture.first == NULL) + != (b->hostData.ipFuture.first == NULL))) { + return URI_FALSE; + } + + if (a->hostData.ip4 != NULL) { + if (memcmp(a->hostData.ip4->data, b->hostData.ip4->data, 4)) { + return URI_FALSE; + } + } + + if (a->hostData.ip6 != NULL) { + if (memcmp(a->hostData.ip6->data, b->hostData.ip6->data, 16)) { + return URI_FALSE; + } + } + + if (a->hostData.ipFuture.first != NULL) { + if (URI_FUNC(CompareRange)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) { + return URI_FALSE; + } + } + + if ((a->hostData.ip4 == NULL) && (a->hostData.ip6 == NULL) + && (a->hostData.ipFuture.first == NULL)) { + if (URI_FUNC(CompareRange)(&(a->hostText), &(b->hostText))) { + return URI_FALSE; + } + } + + /* portText */ + if (URI_FUNC(CompareRange)(&(a->portText), &(b->portText))) { + return URI_FALSE; + } + + /* Path */ + if ((a->pathHead == NULL) != (b->pathHead == NULL)) { + return URI_FALSE; + } + + if (a->pathHead != NULL) { + URI_TYPE(PathSegment) * walkA = a->pathHead; + URI_TYPE(PathSegment) * walkB = b->pathHead; + do { + if (URI_FUNC(CompareRange)(&(walkA->text), &(walkB->text))) { + return URI_FALSE; + } + if ((walkA->next == NULL) != (walkB->next == NULL)) { + return URI_FALSE; + } + walkA = walkA->next; + walkB = walkB->next; + } while (walkA != NULL); + } + + /* query */ + if (URI_FUNC(CompareRange)(&(a->query), &(b->query))) { + return URI_FALSE; + } + + /* fragment */ + if (URI_FUNC(CompareRange)(&(a->fragment), &(b->fragment))) { + return URI_FALSE; + } + + return URI_TRUE; /* Equal*/ } - - #endif diff --git a/ext/uri/uriparser/src/UriConfig.h b/ext/uri/uriparser/src/UriConfig.h index 8c58a3222e210..e265c0a9a1154 100644 --- a/ext/uri/uriparser/src/UriConfig.h +++ b/ext/uri/uriparser/src/UriConfig.h @@ -37,17 +37,13 @@ */ #if !defined(URI_CONFIG_H) -# define URI_CONFIG_H 1 +# define URI_CONFIG_H 1 - - -#define PACKAGE_VERSION "@PROJECT_VERSION@" +# define PACKAGE_VERSION "@PROJECT_VERSION@" /* -#define HAVE_WPRINTF* +#define HAVE_WPRINTF #define HAVE_REALLOCARRAY */ - - -#endif /* !defined(URI_CONFIG_H) */ +#endif /* !defined(URI_CONFIG_H) */ diff --git a/ext/uri/uriparser/src/UriConfig.h.in b/ext/uri/uriparser/src/UriConfig.h.in index a16a93381c102..b9a85a8fe02af 100644 --- a/ext/uri/uriparser/src/UriConfig.h.in +++ b/ext/uri/uriparser/src/UriConfig.h.in @@ -37,15 +37,11 @@ */ #if !defined(URI_CONFIG_H) -# define URI_CONFIG_H 1 +# define URI_CONFIG_H 1 - - -#define PACKAGE_VERSION "@PROJECT_VERSION@" +# define PACKAGE_VERSION "@PROJECT_VERSION@" #cmakedefine HAVE_WPRINTF #cmakedefine HAVE_REALLOCARRAY - - -#endif /* !defined(URI_CONFIG_H) */ +#endif /* !defined(URI_CONFIG_H) */ diff --git a/ext/uri/uriparser/src/UriCopy.c b/ext/uri/uriparser/src/UriCopy.c index 85f2a8aa17926..3bc6b0dbe3f4c 100644 --- a/ext/uri/uriparser/src/UriCopy.c +++ b/ext/uri/uriparser/src/UriCopy.c @@ -48,192 +48,195 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriCopy.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriCopy.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriCopy.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriCopy.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -# include "UriNormalize.h" -# include "UriCopy.h" -#endif - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriNormalize.h" +# include "UriCopy.h" +# endif static void URI_FUNC(PreventLeakageAfterCopy)(URI_TYPE(Uri) * uri, - unsigned int revertMask, UriMemoryManager * memory) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - - if (uri->hostData.ip4 != NULL) { - memory->free(memory, uri->hostData.ip4); - uri->hostData.ip4 = NULL; - } else if (uri->hostData.ip6 != NULL) { - memory->free(memory, uri->hostData.ip6); - uri->hostData.ip6 = NULL; - } - - if (revertMask & URI_NORMALIZE_PORT) { - if (uri->portText.first != uri->portText.afterLast) { - memory->free(memory, (URI_CHAR *)uri->portText.first); - } - uri->portText.first = NULL; - uri->portText.afterLast = NULL; - } + unsigned int revertMask, + UriMemoryManager * memory) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + + if (uri->hostData.ip4 != NULL) { + memory->free(memory, uri->hostData.ip4); + uri->hostData.ip4 = NULL; + } else if (uri->hostData.ip6 != NULL) { + memory->free(memory, uri->hostData.ip6); + uri->hostData.ip6 = NULL; + } + + if (revertMask & URI_NORMALIZE_PORT) { + if (uri->portText.first != uri->portText.afterLast) { + memory->free(memory, (URI_CHAR *)uri->portText.first); + } + uri->portText.first = NULL; + uri->portText.afterLast = NULL; + } } - - -int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, - const URI_TYPE(Uri) * sourceUri, UriMemoryManager * memory) { - unsigned int revertMask = URI_NORMALIZED; - - if (sourceUri == NULL || destUri == NULL) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - URI_FUNC(ResetUri)(destUri); - - if (URI_FUNC(CopyRangeAsNeeded)(&destUri->scheme, &sourceUri->scheme, memory) == URI_FALSE) { - return URI_ERROR_MALLOC; - } - - revertMask |= URI_NORMALIZE_SCHEME; - - if (URI_FUNC(CopyRangeAsNeeded)(&destUri->userInfo, &sourceUri->userInfo, memory) == URI_FALSE) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - - revertMask |= URI_NORMALIZE_USER_INFO; - - if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostText, &sourceUri->hostText, memory) == URI_FALSE) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - - revertMask |= URI_NORMALIZE_HOST; - - if (sourceUri->hostData.ip4 == NULL) { - destUri->hostData.ip4 = NULL; - } else { - destUri->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4)); - if (destUri->hostData.ip4 == NULL) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - *(destUri->hostData.ip4) = *(sourceUri->hostData.ip4); - } - - if (sourceUri->hostData.ip6 == NULL) { - destUri->hostData.ip6 = NULL; - } else { - destUri->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6)); - if (destUri->hostData.ip6 == NULL) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - *(destUri->hostData.ip6) = *(sourceUri->hostData.ip6); - } - - if (sourceUri->hostData.ipFuture.first != NULL) { - destUri->hostData.ipFuture.first = destUri->hostText.first; - destUri->hostData.ipFuture.afterLast = destUri->hostText.afterLast; - } else if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostData.ipFuture, &sourceUri->hostData.ipFuture, memory) == URI_FALSE) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - - if (URI_FUNC(CopyRangeAsNeeded)(&destUri->portText, &sourceUri->portText, memory) == URI_FALSE) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - - revertMask |= URI_NORMALIZE_PORT; - - destUri->pathHead = NULL; - destUri->pathTail = NULL; - - if (sourceUri->pathHead != NULL) { - URI_TYPE(PathSegment) * sourceWalker = sourceUri->pathHead; - URI_TYPE(PathSegment) * destPrev = NULL; - - while (sourceWalker != NULL) { - URI_TYPE(PathSegment) * destWalker = memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); - if (destWalker == NULL) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - - destWalker->text.first = NULL; - destWalker->text.afterLast = NULL; - destWalker->next = NULL; - destWalker->reserved = NULL; - - if (destUri->pathHead == NULL) { - destUri->pathHead = destWalker; - revertMask |= URI_NORMALIZE_PATH; - } - - if (URI_FUNC(CopyRangeAsNeeded)(&destWalker->text, &sourceWalker->text, memory) == URI_FALSE) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - - if (destPrev != NULL) { - destPrev->next = destWalker; - } - - destPrev = destWalker; - sourceWalker = sourceWalker->next; - - destUri->pathTail = destWalker; - } - } - - if (URI_FUNC(CopyRangeAsNeeded)(&destUri->query, &sourceUri->query, memory) == URI_FALSE) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - - revertMask |= URI_NORMALIZE_QUERY; - - if (URI_FUNC(CopyRangeAsNeeded)(&destUri->fragment, &sourceUri->fragment, memory) == URI_FALSE) { - URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); - return URI_ERROR_MALLOC; - } - - destUri->absolutePath = sourceUri->absolutePath; - destUri->owner = URI_TRUE; - destUri->reserved = NULL; - - return URI_SUCCESS; +int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri, + UriMemoryManager * memory) { + unsigned int revertMask = URI_NORMALIZED; + + if (sourceUri == NULL || destUri == NULL) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + URI_FUNC(ResetUri)(destUri); + + if (URI_FUNC(CopyRangeAsNeeded)(&destUri->scheme, &sourceUri->scheme, memory) + == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + revertMask |= URI_NORMALIZE_SCHEME; + + if (URI_FUNC(CopyRangeAsNeeded)(&destUri->userInfo, &sourceUri->userInfo, memory) + == URI_FALSE) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + + revertMask |= URI_NORMALIZE_USER_INFO; + + if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostText, &sourceUri->hostText, memory) + == URI_FALSE) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + + revertMask |= URI_NORMALIZE_HOST; + + if (sourceUri->hostData.ip4 == NULL) { + destUri->hostData.ip4 = NULL; + } else { + destUri->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4)); + if (destUri->hostData.ip4 == NULL) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + *(destUri->hostData.ip4) = *(sourceUri->hostData.ip4); + } + + if (sourceUri->hostData.ip6 == NULL) { + destUri->hostData.ip6 = NULL; + } else { + destUri->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6)); + if (destUri->hostData.ip6 == NULL) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + *(destUri->hostData.ip6) = *(sourceUri->hostData.ip6); + } + + if (sourceUri->hostData.ipFuture.first != NULL) { + destUri->hostData.ipFuture.first = destUri->hostText.first; + destUri->hostData.ipFuture.afterLast = destUri->hostText.afterLast; + } else if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostData.ipFuture, + &sourceUri->hostData.ipFuture, memory) + == URI_FALSE) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + + if (URI_FUNC(CopyRangeAsNeeded)(&destUri->portText, &sourceUri->portText, memory) + == URI_FALSE) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + + revertMask |= URI_NORMALIZE_PORT; + + destUri->pathHead = NULL; + destUri->pathTail = NULL; + + if (sourceUri->pathHead != NULL) { + URI_TYPE(PathSegment) * sourceWalker = sourceUri->pathHead; + URI_TYPE(PathSegment) * destPrev = NULL; + + while (sourceWalker != NULL) { + URI_TYPE(PathSegment) * destWalker = + memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); + if (destWalker == NULL) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + + destWalker->text.first = NULL; + destWalker->text.afterLast = NULL; + destWalker->next = NULL; + destWalker->reserved = NULL; + + if (destUri->pathHead == NULL) { + destUri->pathHead = destWalker; + revertMask |= URI_NORMALIZE_PATH; + } + + if (URI_FUNC(CopyRangeAsNeeded)(&destWalker->text, &sourceWalker->text, + memory) + == URI_FALSE) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + + if (destPrev != NULL) { + destPrev->next = destWalker; + } + + destPrev = destWalker; + sourceWalker = sourceWalker->next; + + destUri->pathTail = destWalker; + } + } + + if (URI_FUNC(CopyRangeAsNeeded)(&destUri->query, &sourceUri->query, memory) + == URI_FALSE) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + + revertMask |= URI_NORMALIZE_QUERY; + + if (URI_FUNC(CopyRangeAsNeeded)(&destUri->fragment, &sourceUri->fragment, memory) + == URI_FALSE) { + URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory); + return URI_ERROR_MALLOC; + } + + destUri->absolutePath = sourceUri->absolutePath; + destUri->owner = URI_TRUE; + destUri->reserved = NULL; + + return URI_SUCCESS; } - - -int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, - const URI_TYPE(Uri) * sourceUri) { - return URI_FUNC(CopyUriMm)(destUri, sourceUri, NULL); +int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri) { + return URI_FUNC(CopyUriMm)(destUri, sourceUri, NULL); } #endif diff --git a/ext/uri/uriparser/src/UriCopy.h b/ext/uri/uriparser/src/UriCopy.h index 952b1df4f9cb3..430f5dc6da24a 100644 --- a/ext/uri/uriparser/src/UriCopy.h +++ b/ext/uri/uriparser/src/UriCopy.h @@ -39,40 +39,38 @@ */ #if (defined(URI_PASS_ANSI) && !defined(URI_COPY_H_ANSI)) \ - || (defined(URI_PASS_UNICODE) && !defined(URI_COPY_H_UNICODE)) \ - || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) + || (defined(URI_PASS_UNICODE) && !defined(URI_COPY_H_UNICODE)) \ + || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* What encodings are enabled? */ -#include -#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) +# include +# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriCopy.h" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriCopy.h" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriCopy.h" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriCopy.h" +# undef URI_PASS_UNICODE +# endif /* Only one pass for each encoding */ -#elif (defined(URI_PASS_ANSI) && !defined(URI_COPY_H_ANSI) \ - && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ - && !defined(URI_COPY_H_UNICODE) && defined(URI_ENABLE_UNICODE)) -# ifdef URI_PASS_ANSI -# define URI_COPY_H_ANSI 1 -# include -# else -# define URI_COPY_H_UNICODE 1 -# include -# endif +# elif (defined(URI_PASS_ANSI) && !defined(URI_COPY_H_ANSI) \ + && defined(URI_ENABLE_ANSI)) \ + || (defined(URI_PASS_UNICODE) && !defined(URI_COPY_H_UNICODE) \ + && defined(URI_ENABLE_UNICODE)) +# ifdef URI_PASS_ANSI +# define URI_COPY_H_ANSI 1 +# include +# else +# define URI_COPY_H_UNICODE 1 +# include +# endif +int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri, + UriMemoryManager * memory); +int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri); - -int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, - const URI_TYPE(Uri) * sourceUri, UriMemoryManager * memory); -int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, - const URI_TYPE(Uri) * sourceUri); - -#endif +# endif #endif diff --git a/ext/uri/uriparser/src/UriEscape.c b/ext/uri/uriparser/src/UriEscape.c index 366955f4adad4..a1763f97153cf 100644 --- a/ext/uri/uriparser/src/UriEscape.c +++ b/ext/uri/uriparser/src/UriEscape.c @@ -41,416 +41,293 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriEscape.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriEscape.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriEscape.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriEscape.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -#endif - - - -URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, - UriBool spaceToPlus, UriBool normalizeBreaks) { - return URI_FUNC(EscapeEx)(in, NULL, out, spaceToPlus, normalizeBreaks); +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriSets.h" +# endif + +URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, UriBool spaceToPlus, + UriBool normalizeBreaks) { + return URI_FUNC(EscapeEx)(in, NULL, out, spaceToPlus, normalizeBreaks); } - - -URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, - const URI_CHAR * inAfterLast, URI_CHAR * out, - UriBool spaceToPlus, UriBool normalizeBreaks) { - const URI_CHAR * read = inFirst; - URI_CHAR * write = out; - UriBool prevWasCr = URI_FALSE; - if ((out == NULL) || (inFirst == out)) { - return NULL; - } else if (inFirst == NULL) { - if (out != NULL) { - out[0] = _UT('\0'); - } - return out; - } - - for (;;) { - if ((inAfterLast != NULL) && (read >= inAfterLast)) { - write[0] = _UT('\0'); - return write; - } - - switch (read[0]) { - case _UT('\0'): - write[0] = _UT('\0'); - return write; - - case _UT(' '): - if (spaceToPlus) { - write[0] = _UT('+'); - write++; - } else { - write[0] = _UT('%'); - write[1] = _UT('2'); - write[2] = _UT('0'); - write += 3; - } - prevWasCr = URI_FALSE; - break; - - case _UT('a'): /* ALPHA */ - case _UT('A'): - case _UT('b'): - case _UT('B'): - case _UT('c'): - case _UT('C'): - case _UT('d'): - case _UT('D'): - case _UT('e'): - case _UT('E'): - case _UT('f'): - case _UT('F'): - case _UT('g'): - case _UT('G'): - case _UT('h'): - case _UT('H'): - case _UT('i'): - case _UT('I'): - case _UT('j'): - case _UT('J'): - case _UT('k'): - case _UT('K'): - case _UT('l'): - case _UT('L'): - case _UT('m'): - case _UT('M'): - case _UT('n'): - case _UT('N'): - case _UT('o'): - case _UT('O'): - case _UT('p'): - case _UT('P'): - case _UT('q'): - case _UT('Q'): - case _UT('r'): - case _UT('R'): - case _UT('s'): - case _UT('S'): - case _UT('t'): - case _UT('T'): - case _UT('u'): - case _UT('U'): - case _UT('v'): - case _UT('V'): - case _UT('w'): - case _UT('W'): - case _UT('x'): - case _UT('X'): - case _UT('y'): - case _UT('Y'): - case _UT('z'): - case _UT('Z'): - case _UT('0'): /* DIGIT */ - case _UT('1'): - case _UT('2'): - case _UT('3'): - case _UT('4'): - case _UT('5'): - case _UT('6'): - case _UT('7'): - case _UT('8'): - case _UT('9'): - case _UT('-'): /* "-" / "." / "_" / "~" */ - case _UT('.'): - case _UT('_'): - case _UT('~'): - /* Copy unmodified */ - write[0] = read[0]; - write++; - - prevWasCr = URI_FALSE; - break; - - case _UT('\x0a'): - if (normalizeBreaks) { - if (!prevWasCr) { - write[0] = _UT('%'); - write[1] = _UT('0'); - write[2] = _UT('D'); - write[3] = _UT('%'); - write[4] = _UT('0'); - write[5] = _UT('A'); - write += 6; - } - } else { - write[0] = _UT('%'); - write[1] = _UT('0'); - write[2] = _UT('A'); - write += 3; - } - prevWasCr = URI_FALSE; - break; - - case _UT('\x0d'): - if (normalizeBreaks) { - write[0] = _UT('%'); - write[1] = _UT('0'); - write[2] = _UT('D'); - write[3] = _UT('%'); - write[4] = _UT('0'); - write[5] = _UT('A'); - write += 6; - } else { - write[0] = _UT('%'); - write[1] = _UT('0'); - write[2] = _UT('D'); - write += 3; - } - prevWasCr = URI_TRUE; - break; - - default: - /* Percent encode */ - { - const unsigned char code = (unsigned char)read[0]; - /* Uppercase recommended in (last sentence of) section 2.1 * - * of RFC 3986: * - * https://datatracker.ietf.org/doc/html/rfc3986#section-2.1 */ - write[0] = _UT('%'); - write[1] = URI_FUNC(HexToLetterEx)(code >> 4, URI_TRUE); - write[2] = URI_FUNC(HexToLetterEx)(code & 0x0f, URI_TRUE); - write += 3; - } - prevWasCr = URI_FALSE; - break; - } - - read++; - } +URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, const URI_CHAR * inAfterLast, + URI_CHAR * out, UriBool spaceToPlus, + UriBool normalizeBreaks) { + const URI_CHAR * read = inFirst; + URI_CHAR * write = out; + UriBool prevWasCr = URI_FALSE; + if ((out == NULL) || (inFirst == out)) { + return NULL; + } else if (inFirst == NULL) { + if (out != NULL) { + out[0] = _UT('\0'); + } + return out; + } + + for (;;) { + if ((inAfterLast != NULL) && (read >= inAfterLast)) { + write[0] = _UT('\0'); + return write; + } + + switch (read[0]) { + case _UT('\0'): + write[0] = _UT('\0'); + return write; + + case _UT(' '): + if (spaceToPlus) { + write[0] = _UT('+'); + write++; + } else { + write[0] = _UT('%'); + write[1] = _UT('2'); + write[2] = _UT('0'); + write += 3; + } + prevWasCr = URI_FALSE; + break; + + case URI_SET_UNRESERVED(_UT): + /* Copy unmodified */ + write[0] = read[0]; + write++; + + prevWasCr = URI_FALSE; + break; + + case _UT('\x0a'): + if (normalizeBreaks) { + if (!prevWasCr) { + write[0] = _UT('%'); + write[1] = _UT('0'); + write[2] = _UT('D'); + write[3] = _UT('%'); + write[4] = _UT('0'); + write[5] = _UT('A'); + write += 6; + } + } else { + write[0] = _UT('%'); + write[1] = _UT('0'); + write[2] = _UT('A'); + write += 3; + } + prevWasCr = URI_FALSE; + break; + + case _UT('\x0d'): + if (normalizeBreaks) { + write[0] = _UT('%'); + write[1] = _UT('0'); + write[2] = _UT('D'); + write[3] = _UT('%'); + write[4] = _UT('0'); + write[5] = _UT('A'); + write += 6; + } else { + write[0] = _UT('%'); + write[1] = _UT('0'); + write[2] = _UT('D'); + write += 3; + } + prevWasCr = URI_TRUE; + break; + + default: + /* Percent encode */ + { + const unsigned char code = (unsigned char)read[0]; + /* Uppercase recommended in (last sentence of) section 2.1 * + * of RFC 3986: * + * https://datatracker.ietf.org/doc/html/rfc3986#section-2.1 */ + write[0] = _UT('%'); + write[1] = URI_FUNC(HexToLetterEx)(code >> 4, URI_TRUE); + write[2] = URI_FUNC(HexToLetterEx)(code & 0x0f, URI_TRUE); + write += 3; + } + prevWasCr = URI_FALSE; + break; + } + + read++; + } } - - const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout) { - return URI_FUNC(UnescapeInPlaceEx)(inout, URI_FALSE, URI_BR_DONT_TOUCH); + return URI_FUNC(UnescapeInPlaceEx)(inout, URI_FALSE, URI_BR_DONT_TOUCH); } - - -const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, - UriBool plusToSpace, UriBreakConversion breakConversion) { - URI_CHAR * read = inout; - URI_CHAR * write = inout; - UriBool prevWasCr = URI_FALSE; - - if (inout == NULL) { - return NULL; - } - - for (;;) { - switch (read[0]) { - case _UT('\0'): - if (read > write) { - write[0] = _UT('\0'); - } - return write; - - case _UT('%'): - switch (read[1]) { - case _UT('0'): - case _UT('1'): - case _UT('2'): - case _UT('3'): - case _UT('4'): - case _UT('5'): - case _UT('6'): - case _UT('7'): - case _UT('8'): - case _UT('9'): - case _UT('a'): - case _UT('b'): - case _UT('c'): - case _UT('d'): - case _UT('e'): - case _UT('f'): - case _UT('A'): - case _UT('B'): - case _UT('C'): - case _UT('D'): - case _UT('E'): - case _UT('F'): - switch (read[2]) { - case _UT('0'): - case _UT('1'): - case _UT('2'): - case _UT('3'): - case _UT('4'): - case _UT('5'): - case _UT('6'): - case _UT('7'): - case _UT('8'): - case _UT('9'): - case _UT('a'): - case _UT('b'): - case _UT('c'): - case _UT('d'): - case _UT('e'): - case _UT('f'): - case _UT('A'): - case _UT('B'): - case _UT('C'): - case _UT('D'): - case _UT('E'): - case _UT('F'): - { - /* Percent group found */ - const unsigned char left = URI_FUNC(HexdigToInt)(read[1]); - const unsigned char right = URI_FUNC(HexdigToInt)(read[2]); - const int code = 16 * left + right; - switch (code) { - case 10: - switch (breakConversion) { - case URI_BR_TO_LF: - if (!prevWasCr) { - write[0] = (URI_CHAR)10; - write++; - } - break; - - case URI_BR_TO_CRLF: - if (!prevWasCr) { - write[0] = (URI_CHAR)13; - write[1] = (URI_CHAR)10; - write += 2; - } - break; - - case URI_BR_TO_CR: - if (!prevWasCr) { - write[0] = (URI_CHAR)13; - write++; - } - break; - - case URI_BR_DONT_TOUCH: - default: - write[0] = (URI_CHAR)10; - write++; - - } - prevWasCr = URI_FALSE; - break; - - case 13: - switch (breakConversion) { - case URI_BR_TO_LF: - write[0] = (URI_CHAR)10; - write++; - break; - - case URI_BR_TO_CRLF: - write[0] = (URI_CHAR)13; - write[1] = (URI_CHAR)10; - write += 2; - break; - - case URI_BR_TO_CR: - write[0] = (URI_CHAR)13; - write++; - break; - - case URI_BR_DONT_TOUCH: - default: - write[0] = (URI_CHAR)13; - write++; - - } - prevWasCr = URI_TRUE; - break; - - default: - write[0] = (URI_CHAR)(code); - write++; - - prevWasCr = URI_FALSE; - - } - read += 3; - } - break; - - default: - /* Copy two chars unmodified and */ - /* look at this char again */ - if (read > write) { - write[0] = read[0]; - write[1] = read[1]; - } - read += 2; - write += 2; - - prevWasCr = URI_FALSE; - } - break; - - default: - /* Copy one char unmodified and */ - /* look at this char again */ - if (read > write) { - write[0] = read[0]; - } - read++; - write++; - - prevWasCr = URI_FALSE; - } - break; - - case _UT('+'): - if (plusToSpace) { - /* Convert '+' to ' ' */ - write[0] = _UT(' '); - } else { - /* Copy one char unmodified */ - if (read > write) { - write[0] = read[0]; - } - } - read++; - write++; - - prevWasCr = URI_FALSE; - break; - - default: - /* Copy one char unmodified */ - if (read > write) { - write[0] = read[0]; - } - read++; - write++; - - prevWasCr = URI_FALSE; - } - } +const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, UriBool plusToSpace, + UriBreakConversion breakConversion) { + URI_CHAR * read = inout; + URI_CHAR * write = inout; + UriBool prevWasCr = URI_FALSE; + + if (inout == NULL) { + return NULL; + } + + for (;;) { + switch (read[0]) { + case _UT('\0'): + if (read > write) { + write[0] = _UT('\0'); + } + return write; + + case _UT('%'): + switch (read[1]) { + case URI_SET_HEXDIG(_UT): + switch (read[2]) { + case URI_SET_HEXDIG(_UT): { + /* Percent group found */ + const unsigned char left = URI_FUNC(HexdigToInt)(read[1]); + const unsigned char right = URI_FUNC(HexdigToInt)(read[2]); + const int code = 16 * left + right; + switch (code) { + case 10: + switch (breakConversion) { + case URI_BR_TO_LF: + if (!prevWasCr) { + write[0] = (URI_CHAR)10; + write++; + } + break; + + case URI_BR_TO_CRLF: + if (!prevWasCr) { + write[0] = (URI_CHAR)13; + write[1] = (URI_CHAR)10; + write += 2; + } + break; + + case URI_BR_TO_CR: + if (!prevWasCr) { + write[0] = (URI_CHAR)13; + write++; + } + break; + + case URI_BR_DONT_TOUCH: + default: + write[0] = (URI_CHAR)10; + write++; + } + prevWasCr = URI_FALSE; + break; + + case 13: + switch (breakConversion) { + case URI_BR_TO_LF: + write[0] = (URI_CHAR)10; + write++; + break; + + case URI_BR_TO_CRLF: + write[0] = (URI_CHAR)13; + write[1] = (URI_CHAR)10; + write += 2; + break; + + case URI_BR_TO_CR: + write[0] = (URI_CHAR)13; + write++; + break; + + case URI_BR_DONT_TOUCH: + default: + write[0] = (URI_CHAR)13; + write++; + } + prevWasCr = URI_TRUE; + break; + + default: + write[0] = (URI_CHAR)(code); + write++; + + prevWasCr = URI_FALSE; + } + read += 3; + } break; + + default: + /* Copy two chars unmodified and */ + /* look at this char again */ + if (read > write) { + write[0] = read[0]; + write[1] = read[1]; + } + read += 2; + write += 2; + + prevWasCr = URI_FALSE; + } + break; + + default: + /* Copy one char unmodified and */ + /* look at this char again */ + if (read > write) { + write[0] = read[0]; + } + read++; + write++; + + prevWasCr = URI_FALSE; + } + break; + + case _UT('+'): + if (plusToSpace) { + /* Convert '+' to ' ' */ + write[0] = _UT(' '); + } else { + /* Copy one char unmodified */ + if (read > write) { + write[0] = read[0]; + } + } + read++; + write++; + + prevWasCr = URI_FALSE; + break; + + default: + /* Copy one char unmodified */ + if (read > write) { + write[0] = read[0]; + } + read++; + write++; + + prevWasCr = URI_FALSE; + } + } } - - #endif diff --git a/ext/uri/uriparser/src/UriFile.c b/ext/uri/uriparser/src/UriFile.c index 232957d3c8079..7510e701c9f5c 100644 --- a/ext/uri/uriparser/src/UriFile.c +++ b/ext/uri/uriparser/src/UriFile.c @@ -41,202 +41,181 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriFile.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriFile.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriFile.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriFile.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -#endif - - - -#include /* for size_t, avoiding stddef.h for older MSVCs */ +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif +# ifndef URI_DOXYGEN +# include +# endif +# include /* for size_t, avoiding stddef.h for older MSVCs */ static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename, - URI_CHAR * uriString, UriBool fromUnix) { - const URI_CHAR * input = filename; - const URI_CHAR * lastSep = input - 1; - UriBool firstSegment = URI_TRUE; - URI_CHAR * output = uriString; - UriBool absolute; - UriBool is_windows_network; - - if ((filename == NULL) || (uriString == NULL)) { - return URI_ERROR_NULL; - } - - is_windows_network = (filename[0] == _UT('\\')) && (filename[1] == _UT('\\')); - absolute = fromUnix - ? (filename[0] == _UT('/')) - : (((filename[0] != _UT('\0')) && (filename[1] == _UT(':'))) - || is_windows_network); - - if (absolute) { - const URI_CHAR * const prefix = fromUnix - ? _UT("file://") - : is_windows_network - ? _UT("file:") - : _UT("file:///"); - const size_t prefixLen = URI_STRLEN(prefix); - - /* Copy prefix */ - memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR)); - output += prefixLen; - } - - /* Copy and escape on the fly */ - for (;;) { - if ((input[0] == _UT('\0')) - || (fromUnix && input[0] == _UT('/')) - || (!fromUnix && input[0] == _UT('\\'))) { - /* Copy text after last separator */ - if (lastSep + 1 < input) { - if (!fromUnix && absolute && (firstSegment == URI_TRUE)) { - /* Quick hack to not convert "C:" to "C%3A" */ - const int charsToCopy = (int)(input - (lastSep + 1)); - memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR)); - output += charsToCopy; - } else { - output = URI_FUNC(EscapeEx)(lastSep + 1, input, output, - URI_FALSE, URI_FALSE); - } - } - firstSegment = URI_FALSE; - } - - if (input[0] == _UT('\0')) { - output[0] = _UT('\0'); - break; - } else if (fromUnix && (input[0] == _UT('/'))) { - /* Copy separators unmodified */ - output[0] = _UT('/'); - output++; - lastSep = input; - } else if (!fromUnix && (input[0] == _UT('\\'))) { - /* Convert backslashes to forward slashes */ - output[0] = _UT('/'); - output++; - lastSep = input; - } - input++; - } - - return URI_SUCCESS; + URI_CHAR * uriString, + UriBool fromUnix) { + const URI_CHAR * input = filename; + const URI_CHAR * lastSep = input - 1; + UriBool firstSegment = URI_TRUE; + URI_CHAR * output = uriString; + UriBool absolute; + UriBool is_windows_network; + + if ((filename == NULL) || (uriString == NULL)) { + return URI_ERROR_NULL; + } + + is_windows_network = (filename[0] == _UT('\\')) && (filename[1] == _UT('\\')); + absolute = fromUnix ? (filename[0] == _UT('/')) + : (((filename[0] != _UT('\0')) && (filename[1] == _UT(':'))) + || is_windows_network); + + if (absolute) { + const URI_CHAR * const prefix = fromUnix ? _UT("file://") + : is_windows_network ? _UT("file:") + : _UT("file:///"); + const size_t prefixLen = URI_STRLEN(prefix); + + /* Copy prefix */ + memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR)); + output += prefixLen; + } + + /* Copy and escape on the fly */ + for (;;) { + if ((input[0] == _UT('\0')) || (fromUnix && input[0] == _UT('/')) + || (!fromUnix && input[0] == _UT('\\'))) { + /* Copy text after last separator */ + if (lastSep + 1 < input) { + if (!fromUnix && absolute && (firstSegment == URI_TRUE)) { + /* Quick hack to not convert "C:" to "C%3A" */ + const int charsToCopy = (int)(input - (lastSep + 1)); + memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR)); + output += charsToCopy; + } else { + output = URI_FUNC(EscapeEx)(lastSep + 1, input, output, URI_FALSE, + URI_FALSE); + } + } + firstSegment = URI_FALSE; + } + + if (input[0] == _UT('\0')) { + output[0] = _UT('\0'); + break; + } else if (fromUnix && (input[0] == _UT('/'))) { + /* Copy separators unmodified */ + output[0] = _UT('/'); + output++; + lastSep = input; + } else if (!fromUnix && (input[0] == _UT('\\'))) { + /* Convert backslashes to forward slashes */ + output[0] = _UT('/'); + output++; + lastSep = input; + } + input++; + } + + return URI_SUCCESS; } - - static URI_INLINE int URI_FUNC(UriStringToFilename)(const URI_CHAR * uriString, - URI_CHAR * filename, UriBool toUnix) { - if ((uriString == NULL) || (filename == NULL)) { - return URI_ERROR_NULL; - } - - { - const UriBool file_unknown_slashes = - URI_STRNCMP(uriString, _UT("file:"), URI_STRLEN(_UT("file:"))) == 0; - const UriBool file_one_or_more_slashes = file_unknown_slashes - && (URI_STRNCMP(uriString, _UT("file:/"), URI_STRLEN(_UT("file:/"))) == 0); - const UriBool file_two_or_more_slashes = file_one_or_more_slashes - && (URI_STRNCMP(uriString, _UT("file://"), URI_STRLEN(_UT("file://"))) == 0); - const UriBool file_three_or_more_slashes = file_two_or_more_slashes - && (URI_STRNCMP(uriString, _UT("file:///"), URI_STRLEN(_UT("file:///"))) == 0); - - const size_t charsToSkip = file_two_or_more_slashes - ? file_three_or_more_slashes - ? toUnix - /* file:///bin/bash */ - ? URI_STRLEN(_UT("file://")) - /* file:///E:/Documents%20and%20Settings */ - : URI_STRLEN(_UT("file:///")) - /* file://Server01/Letter.txt */ - : URI_STRLEN(_UT("file://")) - : ((file_one_or_more_slashes && toUnix) - /* file:/bin/bash */ - /* https://tools.ietf.org/html/rfc8089#appendix-B */ - ? URI_STRLEN(_UT("file:")) - : ((! toUnix && file_unknown_slashes && ! file_one_or_more_slashes) - /* file:c:/path/to/file */ - /* https://tools.ietf.org/html/rfc8089#appendix-E.2 */ - ? URI_STRLEN(_UT("file:")) - : 0)); - const size_t charsToCopy = URI_STRLEN(uriString + charsToSkip) + 1; - - const UriBool is_windows_network_with_authority = - (toUnix == URI_FALSE) - && file_two_or_more_slashes - && ! file_three_or_more_slashes; - - URI_CHAR * const unescape_target = is_windows_network_with_authority - ? (filename + 2) - : filename; - - if (is_windows_network_with_authority) { - filename[0] = '\\'; - filename[1] = '\\'; - } - - memcpy(unescape_target, uriString + charsToSkip, charsToCopy * sizeof(URI_CHAR)); - URI_FUNC(UnescapeInPlaceEx)(filename, URI_FALSE, URI_BR_DONT_TOUCH); - } - - /* Convert forward slashes to backslashes */ - if (!toUnix) { - URI_CHAR * walker = filename; - while (walker[0] != _UT('\0')) { - if (walker[0] == _UT('/')) { - walker[0] = _UT('\\'); - } - walker++; - } - } - - return URI_SUCCESS; + URI_CHAR * filename, UriBool toUnix) { + if ((uriString == NULL) || (filename == NULL)) { + return URI_ERROR_NULL; + } + + const UriBool file_unknown_slashes = + URI_STRNCMP(uriString, _UT("file:"), URI_STRLEN(_UT("file:"))) == 0; + const UriBool file_one_or_more_slashes = + file_unknown_slashes + && (URI_STRNCMP(uriString, _UT("file:/"), URI_STRLEN(_UT("file:/"))) == 0); + const UriBool file_two_or_more_slashes = + file_one_or_more_slashes + && (URI_STRNCMP(uriString, _UT("file://"), URI_STRLEN(_UT("file://"))) == 0); + const UriBool file_three_or_more_slashes = + file_two_or_more_slashes + && (URI_STRNCMP(uriString, _UT("file:///"), URI_STRLEN(_UT("file:///"))) == 0); + + const size_t charsToSkip = + file_two_or_more_slashes + ? file_three_or_more_slashes ? toUnix + /* file:///bin/bash */ + ? URI_STRLEN(_UT("file://")) + /* file:///E:/Documents%20and%20Settings */ + : URI_STRLEN(_UT("file:///")) + /* file://Server01/Letter.txt */ + : URI_STRLEN(_UT("file://")) + : ((file_one_or_more_slashes && toUnix) + /* file:/bin/bash */ + /* https://tools.ietf.org/html/rfc8089#appendix-B */ + ? URI_STRLEN(_UT("file:")) + : ((!toUnix && file_unknown_slashes && !file_one_or_more_slashes) + /* file:c:/path/to/file */ + /* https://tools.ietf.org/html/rfc8089#appendix-E.2 */ + ? URI_STRLEN(_UT("file:")) + : 0)); + const size_t charsToCopy = URI_STRLEN(uriString + charsToSkip) + 1; + + const UriBool is_windows_network_with_authority = + (toUnix == URI_FALSE) && file_two_or_more_slashes && !file_three_or_more_slashes; + + URI_CHAR * const unescape_target = + is_windows_network_with_authority ? (filename + 2) : filename; + + if (is_windows_network_with_authority) { + filename[0] = '\\'; + filename[1] = '\\'; + } + + memcpy(unescape_target, uriString + charsToSkip, charsToCopy * sizeof(URI_CHAR)); + URI_FUNC(UnescapeInPlaceEx)(filename, URI_FALSE, URI_BR_DONT_TOUCH); + + /* Convert forward slashes to backslashes */ + if (!toUnix) { + URI_CHAR * walker = filename; + while (walker[0] != _UT('\0')) { + if (walker[0] == _UT('/')) { + walker[0] = _UT('\\'); + } + walker++; + } + } + + return URI_SUCCESS; } - - int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) { - return URI_FUNC(FilenameToUriString)(filename, uriString, URI_TRUE); + return URI_FUNC(FilenameToUriString)(filename, uriString, URI_TRUE); } - - -int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) { - return URI_FUNC(FilenameToUriString)(filename, uriString, URI_FALSE); +int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename, + URI_CHAR * uriString) { + return URI_FUNC(FilenameToUriString)(filename, uriString, URI_FALSE); } - - int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString, URI_CHAR * filename) { - return URI_FUNC(UriStringToFilename)(uriString, filename, URI_TRUE); + return URI_FUNC(UriStringToFilename)(uriString, filename, URI_TRUE); } - - -int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString, URI_CHAR * filename) { - return URI_FUNC(UriStringToFilename)(uriString, filename, URI_FALSE); +int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString, + URI_CHAR * filename) { + return URI_FUNC(UriStringToFilename)(uriString, filename, URI_FALSE); } - - #endif diff --git a/ext/uri/uriparser/src/UriIp4.c b/ext/uri/uriparser/src/UriIp4.c index a794265269da5..ae61141f7a3ad 100644 --- a/ext/uri/uriparser/src/UriIp4.c +++ b/ext/uri/uriparser/src/UriIp4.c @@ -47,97 +47,94 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriIp4.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriIp4.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriIp4.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriIp4.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriIp4Base.h" -# include -#endif - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriIp4Base.h" +# include +# include "UriSets.h" +# endif /* Prototypes */ static const URI_CHAR * URI_FUNC(ParseDecOctet)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast); + const URI_CHAR * first, + const URI_CHAR * afterLast); static const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast); + const URI_CHAR * first, + const URI_CHAR * afterLast); static const URI_CHAR * URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast); + const URI_CHAR * first, + const URI_CHAR * afterLast); static const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast); + const URI_CHAR * first, + const URI_CHAR * afterLast); static const URI_CHAR * URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast); - - + const URI_CHAR * first, + const URI_CHAR * afterLast); /* * [ipFourAddress]->[decOctet]<.>[decOctet]<.>[decOctet]<.>[decOctet] */ -int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput, - const URI_CHAR * first, const URI_CHAR * afterLast) { - const URI_CHAR * after; - UriIp4Parser parser; - - /* Essential checks */ - if ((octetOutput == NULL) || (first == NULL) - || (afterLast <= first)) { - return URI_ERROR_SYNTAX; - } - - /* Reset parser */ - parser.stackCount = 0; - - /* Octet #1 */ - after = URI_FUNC(ParseDecOctet)(&parser, first, afterLast); - if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { - return URI_ERROR_SYNTAX; - } - uriStackToOctet(&parser, octetOutput); - - /* Octet #2 */ - after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); - if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { - return URI_ERROR_SYNTAX; - } - uriStackToOctet(&parser, octetOutput + 1); - - /* Octet #3 */ - after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); - if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { - return URI_ERROR_SYNTAX; - } - uriStackToOctet(&parser, octetOutput + 2); - - /* Octet #4 */ - after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); - if (after != afterLast) { - return URI_ERROR_SYNTAX; - } - uriStackToOctet(&parser, octetOutput + 3); - - return URI_SUCCESS; +int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput, const URI_CHAR * first, + const URI_CHAR * afterLast) { + const URI_CHAR * after; + UriIp4Parser parser; + + /* Essential checks */ + if ((octetOutput == NULL) || (first == NULL) || (afterLast <= first)) { + return URI_ERROR_SYNTAX; + } + + /* Reset parser */ + parser.stackCount = 0; + + /* Octet #1 */ + after = URI_FUNC(ParseDecOctet)(&parser, first, afterLast); + if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { + return URI_ERROR_SYNTAX; + } + uriStackToOctet(&parser, octetOutput); + + /* Octet #2 */ + after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); + if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { + return URI_ERROR_SYNTAX; + } + uriStackToOctet(&parser, octetOutput + 1); + + /* Octet #3 */ + after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); + if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) { + return URI_ERROR_SYNTAX; + } + uriStackToOctet(&parser, octetOutput + 2); + + /* Octet #4 */ + after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast); + if (after != afterLast) { + return URI_ERROR_SYNTAX; + } + uriStackToOctet(&parser, octetOutput + 3); + + return URI_SUCCESS; } - - /* * [decOctet]-><0> * [decOctet]-><1>[decOctetOne] @@ -151,72 +148,63 @@ int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput, * [decOctet]-><9>[decOctetThree] */ static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctet)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast) { - if (first >= afterLast) { - return NULL; - } - - switch (*first) { - case _UT('0'): - uriPushToStack(parser, 0); - return first + 1; - - case _UT('1'): - uriPushToStack(parser, 1); - return (const URI_CHAR *)URI_FUNC(ParseDecOctetOne)(parser, first + 1, afterLast); - - case _UT('2'): - uriPushToStack(parser, 2); - return (const URI_CHAR *)URI_FUNC(ParseDecOctetTwo)(parser, first + 1, afterLast); - - case _UT('3'): - case _UT('4'): - case _UT('5'): - case _UT('6'): - case _UT('7'): - case _UT('8'): - case _UT('9'): - uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); - return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast); - - default: - return NULL; - } + const URI_CHAR * first, + const URI_CHAR * afterLast) { + if (first >= afterLast) { + return NULL; + } + + switch (*first) { + case _UT('0'): + uriPushToStack(parser, 0); + return first + 1; + + case _UT('1'): + uriPushToStack(parser, 1); + return (const URI_CHAR *)URI_FUNC(ParseDecOctetOne)(parser, first + 1, afterLast); + + case _UT('2'): + uriPushToStack(parser, 2); + return (const URI_CHAR *)URI_FUNC(ParseDecOctetTwo)(parser, first + 1, afterLast); + + case _UT('3'): + case _UT('4'): + case _UT('5'): + case _UT('6'): + case _UT('7'): + case _UT('8'): + case _UT('9'): + uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); + return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, + afterLast); + + default: + return NULL; + } } - - /* * [decOctetOne]-> * [decOctetOne]->[DIGIT][decOctetThree] */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('0'): - case _UT('1'): - case _UT('2'): - case _UT('3'): - case _UT('4'): - case _UT('5'): - case _UT('6'): - case _UT('7'): - case _UT('8'): - case _UT('9'): - uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); - return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast); - - default: - return first; - } +static URI_INLINE const URI_CHAR * +URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser, const URI_CHAR * first, + const URI_CHAR * afterLast) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_DIGIT(_UT): + uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); + return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, + afterLast); + + default: + return first; + } } - - /* * [decOctetTwo]-> * [decOctetTwo]-><0>[decOctetThree] @@ -229,71 +217,62 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * par * [decOctetTwo]-><7> * [decOctetTwo]-><8> * [decOctetTwo]-><9> -*/ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('0'): - case _UT('1'): - case _UT('2'): - case _UT('3'): - case _UT('4'): - uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); - return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast); - - case _UT('5'): - uriPushToStack(parser, 5); - return (const URI_CHAR *)URI_FUNC(ParseDecOctetFour)(parser, first + 1, afterLast); - - case _UT('6'): - case _UT('7'): - case _UT('8'): - case _UT('9'): - uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); - return first + 1; - - default: - return first; - } + */ +static URI_INLINE const URI_CHAR * +URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser, const URI_CHAR * first, + const URI_CHAR * afterLast) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case _UT('0'): + case _UT('1'): + case _UT('2'): + case _UT('3'): + case _UT('4'): + uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); + return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, + afterLast); + + case _UT('5'): + uriPushToStack(parser, 5); + return (const URI_CHAR *)URI_FUNC(ParseDecOctetFour)(parser, first + 1, + afterLast); + + case _UT('6'): + case _UT('7'): + case _UT('8'): + case _UT('9'): + uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); + return first + 1; + + default: + return first; + } } - - /* * [decOctetThree]-> * [decOctetThree]->[DIGIT] */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('0'): - case _UT('1'): - case _UT('2'): - case _UT('3'): - case _UT('4'): - case _UT('5'): - case _UT('6'): - case _UT('7'): - case _UT('8'): - case _UT('9'): - uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); - return first + 1; - - default: - return first; - } +static URI_INLINE const URI_CHAR * +URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser, const URI_CHAR * first, + const URI_CHAR * afterLast) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_DIGIT(_UT): + uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); + return first + 1; + + default: + return first; + } } - - /* * [decOctetFour]-> * [decOctetFour]-><0> @@ -303,27 +282,26 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * p * [decOctetFour]-><4> * [decOctetFour]-><5> */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser, - const URI_CHAR * first, const URI_CHAR * afterLast) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('0'): - case _UT('1'): - case _UT('2'): - case _UT('3'): - case _UT('4'): - case _UT('5'): - uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); - return first + 1; - - default: - return first; - } +static URI_INLINE const URI_CHAR * +URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser, const URI_CHAR * first, + const URI_CHAR * afterLast) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case _UT('0'): + case _UT('1'): + case _UT('2'): + case _UT('3'): + case _UT('4'): + case _UT('5'): + uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9'))); + return first + 1; + + default: + return first; + } } - - #endif diff --git a/ext/uri/uriparser/src/UriIp4Base.c b/ext/uri/uriparser/src/UriIp4Base.c index ded7c32c9940e..900234cd782d3 100644 --- a/ext/uri/uriparser/src/UriIp4Base.c +++ b/ext/uri/uriparser/src/UriIp4Base.c @@ -43,54 +43,45 @@ */ #ifndef URI_DOXYGEN -# include "UriIp4Base.h" +# include "UriIp4Base.h" #endif - - void uriStackToOctet(UriIp4Parser * parser, unsigned char * octet) { - switch (parser->stackCount) { - case 1: - *octet = parser->stackOne; - break; + switch (parser->stackCount) { + case 1: + *octet = parser->stackOne; + break; - case 2: - *octet = parser->stackOne * 10 - + parser->stackTwo; - break; + case 2: + *octet = parser->stackOne * 10 + parser->stackTwo; + break; - case 3: - *octet = parser->stackOne * 100 - + parser->stackTwo * 10 - + parser->stackThree; - break; + case 3: + *octet = parser->stackOne * 100 + parser->stackTwo * 10 + parser->stackThree; + break; - default: - ; - } - parser->stackCount = 0; + default:; + } + parser->stackCount = 0; } - - void uriPushToStack(UriIp4Parser * parser, unsigned char digit) { - switch (parser->stackCount) { - case 0: - parser->stackOne = digit; - parser->stackCount = 1; - break; + switch (parser->stackCount) { + case 0: + parser->stackOne = digit; + parser->stackCount = 1; + break; - case 1: - parser->stackTwo = digit; - parser->stackCount = 2; - break; + case 1: + parser->stackTwo = digit; + parser->stackCount = 2; + break; - case 2: - parser->stackThree = digit; - parser->stackCount = 3; - break; + case 2: + parser->stackThree = digit; + parser->stackCount = 3; + break; - default: - ; - } + default:; + } } diff --git a/ext/uri/uriparser/src/UriIp4Base.h b/ext/uri/uriparser/src/UriIp4Base.h index 4867850224033..1a2ff148b628b 100644 --- a/ext/uri/uriparser/src/UriIp4Base.h +++ b/ext/uri/uriparser/src/UriIp4Base.h @@ -38,22 +38,16 @@ */ #ifndef URI_IP4_BASE_H -#define URI_IP4_BASE_H 1 - - +# define URI_IP4_BASE_H 1 typedef struct UriIp4ParserStruct { - unsigned char stackCount; - unsigned char stackOne; - unsigned char stackTwo; - unsigned char stackThree; + unsigned char stackCount; + unsigned char stackOne; + unsigned char stackTwo; + unsigned char stackThree; } UriIp4Parser; - - void uriPushToStack(UriIp4Parser * parser, unsigned char digit); void uriStackToOctet(UriIp4Parser * parser, unsigned char * octet); - - #endif /* URI_IP4_BASE_H */ diff --git a/ext/uri/uriparser/src/UriMemory.c b/ext/uri/uriparser/src/UriMemory.c index 503b9f9787ff4..3caf8199dc45d 100644 --- a/ext/uri/uriparser/src/UriMemory.c +++ b/ext/uri/uriparser/src/UriMemory.c @@ -42,469 +42,423 @@ * Holds memory manager implementation. */ -#include "UriConfig.h" /* for HAVE_REALLOCARRAY */ +#include "UriConfig.h" /* for HAVE_REALLOCARRAY */ #ifdef HAVE_REALLOCARRAY -# ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -# endif -# ifdef __NetBSD__ -# define _OPENBSD_SOURCE 1 -# endif +# ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +# endif +# ifdef __NetBSD__ +# define _OPENBSD_SOURCE 1 +# endif #endif #include #include - - #ifndef URI_DOXYGEN -# include "UriMemory.h" +# include "UriMemory.h" #endif - - -#define URI_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define URI_MAX(a, b) (((a) > (b)) ? (a) : (b)) /* NOTE: This intends to mimic MALLOC_ALIGNMENT of glibc */ -#define URI_MALLOC_ALIGNMENT URI_MAX(2 * sizeof(size_t), sizeof(long double)) - -#define URI_MALLOC_PADDING (URI_MALLOC_ALIGNMENT - sizeof(size_t)) - +#define URI_MALLOC_ALIGNMENT URI_MAX(2 * sizeof(size_t), sizeof(long double)) +#define URI_MALLOC_PADDING (URI_MALLOC_ALIGNMENT - sizeof(size_t)) #define URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size) \ - do { \ - /* check for unsigned overflow */ \ - if ((nmemb != 0) && (total_size / nmemb != size)) { \ - errno = ENOMEM; \ - return NULL; \ - } \ - } while (0) - - - -static void * uriDefaultMalloc(UriMemoryManager * URI_UNUSED(memory), - size_t size) { - return malloc(size); + do { \ + /* check for unsigned overflow */ \ + if ((nmemb != 0) && (total_size / nmemb != size)) { \ + errno = ENOMEM; \ + return NULL; \ + } \ + } while (0) + +static void * uriDefaultMalloc(UriMemoryManager * URI_UNUSED(memory), size_t size) { + return malloc(size); } - - -static void * uriDefaultCalloc(UriMemoryManager * URI_UNUSED(memory), - size_t nmemb, size_t size) { - return calloc(nmemb, size); +static void * uriDefaultCalloc(UriMemoryManager * URI_UNUSED(memory), size_t nmemb, + size_t size) { + return calloc(nmemb, size); } - - -static void * uriDefaultRealloc(UriMemoryManager * URI_UNUSED(memory), - void * ptr, size_t size) { - return realloc(ptr, size); +static void * uriDefaultRealloc(UriMemoryManager * URI_UNUSED(memory), void * ptr, + size_t size) { + return realloc(ptr, size); } - - -static void * uriDefaultReallocarray(UriMemoryManager * URI_UNUSED(memory), - void * ptr, size_t nmemb, size_t size) { +static void * uriDefaultReallocarray(UriMemoryManager * URI_UNUSED(memory), void * ptr, + size_t nmemb, size_t size) { #ifdef HAVE_REALLOCARRAY - return reallocarray(ptr, nmemb, size); + return reallocarray(ptr, nmemb, size); #else - const size_t total_size = nmemb * size; + const size_t total_size = nmemb * size; - URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ + URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ - return realloc(ptr, total_size); + return realloc(ptr, total_size); #endif } - - -static void uriDefaultFree(UriMemoryManager * URI_UNUSED(memory), - void * ptr) { - free(ptr); +static void uriDefaultFree(UriMemoryManager * URI_UNUSED(memory), void * ptr) { + free(ptr); } - - UriBool uriMemoryManagerIsComplete(const UriMemoryManager * memory) { - return (memory - && memory->malloc - && memory->calloc - && memory->realloc - && memory->reallocarray - && memory->free) ? URI_TRUE : URI_FALSE; + return (memory && memory->malloc && memory->calloc && memory->realloc + && memory->reallocarray && memory->free) + ? URI_TRUE + : URI_FALSE; } - - void * uriEmulateCalloc(UriMemoryManager * memory, size_t nmemb, size_t size) { - void * buffer; - const size_t total_size = nmemb * size; - - if (memory == NULL) { - errno = EINVAL; - return NULL; - } - - URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ - - buffer = memory->malloc(memory, total_size); - if (buffer == NULL) { - /* errno set by malloc */ - return NULL; - } - memset(buffer, 0, total_size); - return buffer; + void * buffer; + const size_t total_size = nmemb * size; + + if (memory == NULL) { + errno = EINVAL; + return NULL; + } + + URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ + + buffer = memory->malloc(memory, total_size); + if (buffer == NULL) { + /* errno set by malloc */ + return NULL; + } + memset(buffer, 0, total_size); + return buffer; } +void * uriEmulateReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, + size_t size) { + const size_t total_size = nmemb * size; + if (memory == NULL) { + errno = EINVAL; + return NULL; + } -void * uriEmulateReallocarray(UriMemoryManager * memory, - void * ptr, size_t nmemb, size_t size) { - const size_t total_size = nmemb * size; - - if (memory == NULL) { - errno = EINVAL; - return NULL; - } + URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ - URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ - - return memory->realloc(memory, ptr, total_size); + return memory->realloc(memory, ptr, total_size); } +static void * uriDecorateMalloc(UriMemoryManager * memory, size_t size) { + UriMemoryManager * backend; + const size_t extraBytes = sizeof(size_t) + URI_MALLOC_PADDING; + void * buffer; + if (memory == NULL) { + errno = EINVAL; + return NULL; + } -static void * uriDecorateMalloc(UriMemoryManager * memory, - size_t size) { - UriMemoryManager * backend; - const size_t extraBytes = sizeof(size_t) + URI_MALLOC_PADDING; - void * buffer; - - if (memory == NULL) { - errno = EINVAL; - return NULL; - } + /* check for unsigned overflow */ + if (size > ((size_t)-1) - extraBytes) { + errno = ENOMEM; + return NULL; + } - /* check for unsigned overflow */ - if (size > ((size_t)-1) - extraBytes) { - errno = ENOMEM; - return NULL; - } + backend = (UriMemoryManager *)memory->userData; + if (backend == NULL) { + errno = EINVAL; + return NULL; + } - backend = (UriMemoryManager *)memory->userData; - if (backend == NULL) { - errno = EINVAL; - return NULL; - } + buffer = backend->malloc(backend, extraBytes + size); + if (buffer == NULL) { + return NULL; + } - buffer = backend->malloc(backend, extraBytes + size); - if (buffer == NULL) { - return NULL; - } + *(size_t *)buffer = size; - *(size_t *)buffer = size; - - return (char *)buffer + extraBytes; + return (char *)buffer + extraBytes; } +static void * uriDecorateRealloc(UriMemoryManager * memory, void * ptr, size_t size) { + void * newBuffer; + size_t prevSize; + if (memory == NULL) { + errno = EINVAL; + return NULL; + } -static void * uriDecorateRealloc(UriMemoryManager * memory, - void * ptr, size_t size) { - void * newBuffer; - size_t prevSize; - - if (memory == NULL) { - errno = EINVAL; - return NULL; - } + /* man realloc: "If ptr is NULL, then the call is equivalent to + * malloc(size), for *all* values of size" */ + if (ptr == NULL) { + return memory->malloc(memory, size); + } - /* man realloc: "If ptr is NULL, then the call is equivalent to - * malloc(size), for *all* values of size" */ - if (ptr == NULL) { - return memory->malloc(memory, size); - } + /* man realloc: "If size is equal to zero, and ptr is *not* NULL, + * then the call is equivalent to free(ptr)." */ + if (size == 0) { + memory->free(memory, ptr); + return NULL; + } - /* man realloc: "If size is equal to zero, and ptr is *not* NULL, - * then the call is equivalent to free(ptr)." */ - if (size == 0) { - memory->free(memory, ptr); - return NULL; - } + prevSize = *((size_t *)((char *)ptr - sizeof(size_t) - URI_MALLOC_PADDING)); - prevSize = *((size_t *)((char *)ptr - sizeof(size_t) - URI_MALLOC_PADDING)); + /* Anything to do? */ + /* mull-ignore-next cxx_le_to_lt */ + if (size <= prevSize) { + return ptr; + } - /* Anything to do? */ - if (size <= prevSize) { - return ptr; - } + newBuffer = memory->malloc(memory, size); + if (newBuffer == NULL) { + /* errno set by malloc */ + return NULL; + } - newBuffer = memory->malloc(memory, size); - if (newBuffer == NULL) { - /* errno set by malloc */ - return NULL; - } + memcpy(newBuffer, ptr, prevSize); - memcpy(newBuffer, ptr, prevSize); + memory->free(memory, ptr); - memory->free(memory, ptr); - - return newBuffer; + return newBuffer; } - - static void uriDecorateFree(UriMemoryManager * memory, void * ptr) { - UriMemoryManager * backend; + UriMemoryManager * backend; - if ((ptr == NULL) || (memory == NULL)) { - return; - } + if ((ptr == NULL) || (memory == NULL)) { + return; + } - backend = (UriMemoryManager *)memory->userData; - if (backend == NULL) { - return; - } + backend = (UriMemoryManager *)memory->userData; + if (backend == NULL) { + return; + } - backend->free(backend, (char *)ptr - sizeof(size_t) - URI_MALLOC_PADDING); + backend->free(backend, (char *)ptr - sizeof(size_t) - URI_MALLOC_PADDING); } +int uriCompleteMemoryManager(UriMemoryManager * memory, UriMemoryManager * backend) { + if ((memory == NULL) || (backend == NULL)) { + return URI_ERROR_NULL; + } + if ((backend->malloc == NULL) || (backend->free == NULL)) { + return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; + } -int uriCompleteMemoryManager(UriMemoryManager * memory, - UriMemoryManager * backend) { - if ((memory == NULL) || (backend == NULL)) { - return URI_ERROR_NULL; - } - - if ((backend->malloc == NULL) || (backend->free == NULL)) { - return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; - } - - memory->calloc = uriEmulateCalloc; - memory->reallocarray = uriEmulateReallocarray; + memory->calloc = uriEmulateCalloc; + memory->reallocarray = uriEmulateReallocarray; - memory->malloc = uriDecorateMalloc; - memory->realloc = uriDecorateRealloc; - memory->free = uriDecorateFree; + memory->malloc = uriDecorateMalloc; + memory->realloc = uriDecorateRealloc; + memory->free = uriDecorateFree; - memory->userData = backend; + memory->userData = backend; - return URI_SUCCESS; + return URI_SUCCESS; } - - +/* mull-off */ int uriTestMemoryManagerEx(UriMemoryManager * memory, UriBool challengeAlignment) { - const size_t mallocSize = 7; - const size_t callocNmemb = 3; - const size_t callocSize = 5; - const size_t callocTotalSize = callocNmemb * callocSize; - const size_t reallocSize = 11; - const size_t reallocarrayNmemb = 5; - const size_t reallocarraySize = 7; - const size_t reallocarrayTotal = reallocarrayNmemb * reallocarraySize; - size_t index; - char * buffer; - - if (memory == NULL) { - return URI_ERROR_NULL; - } - - if (uriMemoryManagerIsComplete(memory) != URI_TRUE) { - return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; - } - - /* malloc + free*/ - buffer = memory->malloc(memory, mallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - buffer[mallocSize - 1] = '\xF1'; - memory->free(memory, buffer); - buffer = NULL; - - /* calloc + free */ - buffer = memory->calloc(memory, callocNmemb, callocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - for (index = 0; index < callocTotalSize; index++) { /* all zeros? */ - if (buffer[index] != '\0') { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - } - buffer[callocTotalSize - 1] = '\xF2'; - memory->free(memory, buffer); - buffer = NULL; - - /* malloc + realloc + free */ - buffer = memory->malloc(memory, mallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - for (index = 0; index < mallocSize; index++) { - buffer[index] = '\xF3'; - } - buffer = memory->realloc(memory, buffer, reallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - for (index = 0; index < mallocSize; index++) { /* previous content? */ - if (buffer[index] != '\xF3') { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - } - buffer[reallocSize - 1] = '\xF4'; - memory->free(memory, buffer); - buffer = NULL; - - /* malloc + realloc ptr!=NULL size==0 (equals free) */ - buffer = memory->malloc(memory, mallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - buffer[mallocSize - 1] = '\xF5'; - memory->realloc(memory, buffer, 0); - buffer = NULL; - - /* realloc ptr==NULL size!=0 (equals malloc) + free */ - buffer = memory->realloc(memory, NULL, mallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - buffer[mallocSize - 1] = '\xF6'; - memory->free(memory, buffer); - buffer = NULL; - - /* realloc ptr==NULL size==0 (equals malloc) + free */ - buffer = memory->realloc(memory, NULL, 0); - if (buffer != NULL) { - memory->free(memory, buffer); - buffer = NULL; - } - - /* malloc + reallocarray + free */ - buffer = memory->malloc(memory, mallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - for (index = 0; index < mallocSize; index++) { - buffer[index] = '\xF7'; - } - buffer = memory->reallocarray(memory, buffer, reallocarrayNmemb, - reallocarraySize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - for (index = 0; index < mallocSize; index++) { /* previous content? */ - if (buffer[index] != '\xF7') { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - } - buffer[reallocarrayTotal - 1] = '\xF8'; - memory->free(memory, buffer); - buffer = NULL; - - /* malloc + reallocarray ptr!=NULL nmemb==0 size!=0 (equals free) */ - buffer = memory->malloc(memory, mallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - buffer[mallocSize - 1] = '\xF9'; - memory->reallocarray(memory, buffer, 0, reallocarraySize); - buffer = NULL; - - /* malloc + reallocarray ptr!=NULL nmemb!=0 size==0 (equals free) */ - buffer = memory->malloc(memory, mallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - buffer[mallocSize - 1] = '\xFA'; - memory->reallocarray(memory, buffer, reallocarrayNmemb, 0); - buffer = NULL; - - /* malloc + reallocarray ptr!=NULL nmemb==0 size==0 (equals free) */ - buffer = memory->malloc(memory, mallocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - buffer[mallocSize - 1] = '\xFB'; - memory->reallocarray(memory, buffer, 0, 0); - buffer = NULL; - - /* reallocarray ptr==NULL nmemb!=0 size!=0 (equals malloc) + free */ - buffer = memory->reallocarray(memory, NULL, callocNmemb, callocSize); - if (buffer == NULL) { - return URI_ERROR_MEMORY_MANAGER_FAULTY; - } - buffer[callocTotalSize - 1] = '\xFC'; - memory->free(memory, buffer); - buffer = NULL; - - /* reallocarray ptr==NULL nmemb==0 size!=0 (equals malloc) + free */ - buffer = memory->reallocarray(memory, NULL, 0, callocSize); - if (buffer != NULL) { - memory->free(memory, buffer); - buffer = NULL; - } - - /* reallocarray ptr==NULL nmemb!=0 size==0 (equals malloc) + free */ - buffer = memory->reallocarray(memory, NULL, callocNmemb, 0); - if (buffer != NULL) { - memory->free(memory, buffer); - buffer = NULL; - } - - /* reallocarray ptr==NULL nmemb==0 size==0 (equals malloc) + free */ - buffer = memory->reallocarray(memory, NULL, 0, 0); - if (buffer != NULL) { - memory->free(memory, buffer); - buffer = NULL; - } - - /* challenge pointer alignment */ - if (challengeAlignment == URI_TRUE) { - long double * ptr = memory->malloc(memory, 4 * sizeof(long double)); - if (ptr != NULL) { - ptr[0] = 0.0L; - ptr[1] = 1.1L; - ptr[2] = 2.2L; - ptr[3] = 3.3L; - - { - long double * const ptrNew = memory->realloc(memory, ptr, 8 * sizeof(long double)); - if (ptrNew != NULL) { - ptr = ptrNew; - ptr[4] = 4.4L; - ptr[5] = 5.5L; - ptr[6] = 6.6L; - ptr[7] = 7.7L; - } - } - - memory->free(memory, ptr); - } - } - - return URI_SUCCESS; + const size_t mallocSize = 7; + const size_t callocNmemb = 3; + const size_t callocSize = 5; + const size_t callocTotalSize = callocNmemb * callocSize; + const size_t reallocSize = 11; + const size_t reallocarrayNmemb = 5; + const size_t reallocarraySize = 7; + const size_t reallocarrayTotal = reallocarrayNmemb * reallocarraySize; + size_t index; + char * buffer; + + if (memory == NULL) { + return URI_ERROR_NULL; + } + + if (uriMemoryManagerIsComplete(memory) != URI_TRUE) { + return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; + } + + /* malloc + free*/ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xF1'; + memory->free(memory, buffer); + buffer = NULL; + + /* calloc + free */ + buffer = memory->calloc(memory, callocNmemb, callocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < callocTotalSize; index++) { /* all zeros? */ + if (buffer[index] != '\0') { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + } + buffer[callocTotalSize - 1] = '\xF2'; + memory->free(memory, buffer); + buffer = NULL; + + /* malloc + realloc + free */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < mallocSize; index++) { + buffer[index] = '\xF3'; + } + buffer = memory->realloc(memory, buffer, reallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < mallocSize; index++) { /* previous content? */ + if (buffer[index] != '\xF3') { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + } + buffer[reallocSize - 1] = '\xF4'; + memory->free(memory, buffer); + buffer = NULL; + + /* malloc + realloc ptr!=NULL size==0 (equals free) */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xF5'; + memory->realloc(memory, buffer, 0); + buffer = NULL; + + /* realloc ptr==NULL size!=0 (equals malloc) + free */ + buffer = memory->realloc(memory, NULL, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xF6'; + memory->free(memory, buffer); + buffer = NULL; + + /* realloc ptr==NULL size==0 (equals malloc) + free */ + buffer = memory->realloc(memory, NULL, 0); + if (buffer != NULL) { + memory->free(memory, buffer); + buffer = NULL; + } + + /* malloc + reallocarray + free */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < mallocSize; index++) { + buffer[index] = '\xF7'; + } + buffer = memory->reallocarray(memory, buffer, reallocarrayNmemb, reallocarraySize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < mallocSize; index++) { /* previous content? */ + if (buffer[index] != '\xF7') { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + } + buffer[reallocarrayTotal - 1] = '\xF8'; + memory->free(memory, buffer); + buffer = NULL; + + /* malloc + reallocarray ptr!=NULL nmemb==0 size!=0 (equals free) */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xF9'; + memory->reallocarray(memory, buffer, 0, reallocarraySize); + buffer = NULL; + + /* malloc + reallocarray ptr!=NULL nmemb!=0 size==0 (equals free) */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xFA'; + memory->reallocarray(memory, buffer, reallocarrayNmemb, 0); + buffer = NULL; + + /* malloc + reallocarray ptr!=NULL nmemb==0 size==0 (equals free) */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xFB'; + memory->reallocarray(memory, buffer, 0, 0); + buffer = NULL; + + /* reallocarray ptr==NULL nmemb!=0 size!=0 (equals malloc) + free */ + buffer = memory->reallocarray(memory, NULL, callocNmemb, callocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[callocTotalSize - 1] = '\xFC'; + memory->free(memory, buffer); + buffer = NULL; + + /* reallocarray ptr==NULL nmemb==0 size!=0 (equals malloc) + free */ + buffer = memory->reallocarray(memory, NULL, 0, callocSize); + if (buffer != NULL) { + memory->free(memory, buffer); + buffer = NULL; + } + + /* reallocarray ptr==NULL nmemb!=0 size==0 (equals malloc) + free */ + buffer = memory->reallocarray(memory, NULL, callocNmemb, 0); + if (buffer != NULL) { + memory->free(memory, buffer); + buffer = NULL; + } + + /* reallocarray ptr==NULL nmemb==0 size==0 (equals malloc) + free */ + buffer = memory->reallocarray(memory, NULL, 0, 0); + if (buffer != NULL) { + memory->free(memory, buffer); + buffer = NULL; + } + + /* challenge pointer alignment */ + if (challengeAlignment == URI_TRUE) { + long double * ptr = memory->malloc(memory, 4 * sizeof(long double)); + if (ptr != NULL) { + ptr[0] = 0.0L; + ptr[1] = 1.1L; + ptr[2] = 2.2L; + ptr[3] = 3.3L; + + long double * const ptrNew = + memory->realloc(memory, ptr, 8 * sizeof(long double)); + if (ptrNew != NULL) { + ptr = ptrNew; + ptr[4] = 4.4L; + ptr[5] = 5.5L; + ptr[6] = 6.6L; + ptr[7] = 7.7L; + } + + memory->free(memory, ptr); + } + } + + return URI_SUCCESS; } - - +/* mull-on */ int uriTestMemoryManager(UriMemoryManager * memory) { - return uriTestMemoryManagerEx(memory, /*challengeAlignment=*/ URI_FALSE); + return uriTestMemoryManagerEx(memory, /*challengeAlignment=*/URI_FALSE); } - - /*extern*/ UriMemoryManager defaultMemoryManager = { - uriDefaultMalloc, - uriDefaultCalloc, - uriDefaultRealloc, - uriDefaultReallocarray, - uriDefaultFree, - NULL /* userData */ + uriDefaultMalloc, uriDefaultCalloc, uriDefaultRealloc, + uriDefaultReallocarray, uriDefaultFree, NULL /* userData */ }; diff --git a/ext/uri/uriparser/src/UriMemory.h b/ext/uri/uriparser/src/UriMemory.h index a930f93ac3c35..b03ca4a093b05 100644 --- a/ext/uri/uriparser/src/UriMemory.h +++ b/ext/uri/uriparser/src/UriMemory.h @@ -38,41 +38,31 @@ */ #ifndef URI_MEMORY_H -#define URI_MEMORY_H 1 - - - -#ifndef URI_DOXYGEN -# include -#endif - - - -#define URI_CHECK_MEMORY_MANAGER(memory) \ - do { \ - if (memory == NULL) { \ - memory = &defaultMemoryManager; \ - } else if (uriMemoryManagerIsComplete(memory) != URI_TRUE) { \ - return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; \ - } \ - } while (0) - - - -#ifdef __cplusplus -# define URIPARSER_EXTERN extern "C" -#else -# define URIPARSER_EXTERN extern -#endif +# define URI_MEMORY_H 1 + +# ifndef URI_DOXYGEN +# include +# endif + +# define URI_CHECK_MEMORY_MANAGER(memory) \ + do { \ + if (memory == NULL) { \ + memory = &defaultMemoryManager; \ + } else if (uriMemoryManagerIsComplete(memory) != URI_TRUE) { \ + return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; \ + } \ + } while (0) + +# ifdef __cplusplus +# define URIPARSER_EXTERN extern "C" +# else +# define URIPARSER_EXTERN extern +# endif URIPARSER_EXTERN UriMemoryManager defaultMemoryManager; -#undef URIPARSER_EXTERN - - +# undef URIPARSER_EXTERN UriBool uriMemoryManagerIsComplete(const UriMemoryManager * memory); - - #endif /* URI_MEMORY_H */ diff --git a/ext/uri/uriparser/src/UriNormalize.c b/ext/uri/uriparser/src/UriNormalize.c index 631d9a05a4d95..8c812d37a0a7e 100644 --- a/ext/uri/uriparser/src/UriNormalize.c +++ b/ext/uri/uriparser/src/UriNormalize.c @@ -47,865 +47,818 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriNormalize.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriNormalize.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriNormalize.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriNormalize.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriNormalizeBase.h" -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - - -#include - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriNormalizeBase.h" +# include "UriCommon.h" +# include "UriMemory.h" +# endif + +# include static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask, - unsigned int * outMask, UriMemoryManager * memory); + unsigned int * outMask, + UriMemoryManager * memory); -static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask, - unsigned int maskTest, URI_TYPE(TextRange) * range, - UriMemoryManager * memory); -static UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri, - unsigned int * revertMask, UriMemoryManager * memory); +static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask, unsigned int maskTest, + URI_TYPE(TextRange) * range, + UriMemoryManager * memory); +static UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri, unsigned int * revertMask, + UriMemoryManager * memory); static void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first, - const URI_CHAR ** afterLast); + const URI_CHAR ** afterLast); static UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first, - const URI_CHAR ** afterLast, UriMemoryManager * memory); -static void URI_FUNC(FixPercentEncodingEngine)( - const URI_CHAR * inFirst, const URI_CHAR * inAfterLast, - const URI_CHAR * outFirst, const URI_CHAR ** outAfterLast); + const URI_CHAR ** afterLast, + UriMemoryManager * memory); +static void URI_FUNC(FixPercentEncodingEngine)(const URI_CHAR * inFirst, + const URI_CHAR * inAfterLast, + const URI_CHAR * outFirst, + const URI_CHAR ** outAfterLast); static UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first, - const URI_CHAR * afterLast); + const URI_CHAR * afterLast); static UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first, - const URI_CHAR * afterLast); + const URI_CHAR * afterLast); static void URI_FUNC(LowercaseInplace)(const URI_CHAR * first, - const URI_CHAR * afterLast); + const URI_CHAR * afterLast); static void URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first, - const URI_CHAR * afterLast); + const URI_CHAR * afterLast); static UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first, - const URI_CHAR ** afterLast, UriMemoryManager * memory); - - - -void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, - unsigned int revertMask, UriMemoryManager * memory) { - if (revertMask & URI_NORMALIZE_SCHEME) { - /* NOTE: A scheme cannot be the empty string - * so no need to compare .first with .afterLast, here. */ - memory->free(memory, (URI_CHAR *)uri->scheme.first); - uri->scheme.first = NULL; - uri->scheme.afterLast = NULL; - } - - if (revertMask & URI_NORMALIZE_USER_INFO) { - if (uri->userInfo.first != uri->userInfo.afterLast) { - memory->free(memory, (URI_CHAR *)uri->userInfo.first); - } - uri->userInfo.first = NULL; - uri->userInfo.afterLast = NULL; - } - - if (revertMask & URI_NORMALIZE_HOST) { - if (uri->hostData.ipFuture.first != NULL) { - /* IPvFuture */ - /* NOTE: An IPvFuture address cannot be the empty string - * so no need to compare .first with .afterLast, here. */ - memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first); - uri->hostData.ipFuture.first = NULL; - uri->hostData.ipFuture.afterLast = NULL; - uri->hostText.first = NULL; - uri->hostText.afterLast = NULL; - } else if (uri->hostText.first != NULL) { - /* Regname */ - if (uri->hostText.first != uri->hostText.afterLast) { - memory->free(memory, (URI_CHAR *)uri->hostText.first); - } - uri->hostText.first = NULL; - uri->hostText.afterLast = NULL; - } - } - - /* NOTE: Port cannot happen! */ - - if (revertMask & URI_NORMALIZE_PATH) { - URI_TYPE(PathSegment) * walker = uri->pathHead; - while (walker != NULL) { - URI_TYPE(PathSegment) * const next = walker->next; - if (walker->text.afterLast > walker->text.first) { - memory->free(memory, (URI_CHAR *)walker->text.first); - } - memory->free(memory, walker); - walker = next; - } - uri->pathHead = NULL; - uri->pathTail = NULL; - } - - if (revertMask & URI_NORMALIZE_QUERY) { - if (uri->query.first != uri->query.afterLast) { - memory->free(memory, (URI_CHAR *)uri->query.first); - } - uri->query.first = NULL; - uri->query.afterLast = NULL; - } - - if (revertMask & URI_NORMALIZE_FRAGMENT) { - if (uri->fragment.first != uri->fragment.afterLast) { - memory->free(memory, (URI_CHAR *)uri->fragment.first); - } - uri->fragment.first = NULL; - uri->fragment.afterLast = NULL; - } + const URI_CHAR ** afterLast, + UriMemoryManager * memory); + +void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, unsigned int revertMask, + UriMemoryManager * memory) { + if (revertMask & URI_NORMALIZE_SCHEME) { + /* NOTE: A scheme cannot be the empty string + * so no need to compare .first with .afterLast, here. */ + memory->free(memory, (URI_CHAR *)uri->scheme.first); + uri->scheme.first = NULL; + uri->scheme.afterLast = NULL; + } + + if (revertMask & URI_NORMALIZE_USER_INFO) { + if (uri->userInfo.first != uri->userInfo.afterLast) { + memory->free(memory, (URI_CHAR *)uri->userInfo.first); + } + uri->userInfo.first = NULL; + uri->userInfo.afterLast = NULL; + } + + if (revertMask & URI_NORMALIZE_HOST) { + if (uri->hostData.ipFuture.first != NULL) { + /* IPvFuture */ + /* NOTE: An IPvFuture address cannot be the empty string + * so no need to compare .first with .afterLast, here. */ + memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first); + uri->hostData.ipFuture.first = NULL; + uri->hostData.ipFuture.afterLast = NULL; + uri->hostText.first = NULL; + uri->hostText.afterLast = NULL; + } else if (uri->hostText.first != NULL) { + /* Regname */ + if (uri->hostText.first != uri->hostText.afterLast) { + memory->free(memory, (URI_CHAR *)uri->hostText.first); + } + uri->hostText.first = NULL; + uri->hostText.afterLast = NULL; + } + } + + /* NOTE: Port cannot happen! */ + + if (revertMask & URI_NORMALIZE_PATH) { + URI_TYPE(PathSegment) * walker = uri->pathHead; + while (walker != NULL) { + URI_TYPE(PathSegment) * const next = walker->next; + if (walker->text.afterLast > walker->text.first) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + memory->free(memory, walker); + walker = next; + } + uri->pathHead = NULL; + uri->pathTail = NULL; + } + + if (revertMask & URI_NORMALIZE_QUERY) { + if (uri->query.first != uri->query.afterLast) { + memory->free(memory, (URI_CHAR *)uri->query.first); + } + uri->query.first = NULL; + uri->query.afterLast = NULL; + } + + if (revertMask & URI_NORMALIZE_FRAGMENT) { + if (uri->fragment.first != uri->fragment.afterLast) { + memory->free(memory, (URI_CHAR *)uri->fragment.first); + } + uri->fragment.first = NULL; + uri->fragment.afterLast = NULL; + } } - - static URI_INLINE UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first, - const URI_CHAR * afterLast) { - if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { - const URI_CHAR * i = first; - for (; i < afterLast; i++) { - /* 6.2.2.1 Case Normalization: uppercase letters in scheme or host */ - if ((*i >= _UT('A')) && (*i <= _UT('Z'))) { - return URI_TRUE; - } - } - } - return URI_FALSE; + const URI_CHAR * afterLast) { + if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { + const URI_CHAR * i = first; + for (; i < afterLast; i++) { + /* 6.2.2.1 Case Normalization: uppercase letters in scheme or host */ + if ((*i >= _UT('A')) && (*i <= _UT('Z'))) { + return URI_TRUE; + } + } + } + return URI_FALSE; } - - -static URI_INLINE UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first, - const URI_CHAR * afterLast) { - if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { - const URI_CHAR * i = first; - for (; i + 2 < afterLast; i++) { - if (i[0] == _UT('%')) { - /* 6.2.2.1 Case Normalization: * - * lowercase percent-encodings */ - if (((i[1] >= _UT('a')) && (i[1] <= _UT('f'))) - || ((i[2] >= _UT('a')) && (i[2] <= _UT('f')))) { - return URI_TRUE; - } else { - /* 6.2.2.2 Percent-Encoding Normalization: * - * percent-encoded unreserved characters */ - const unsigned char left = URI_FUNC(HexdigToInt)(i[1]); - const unsigned char right = URI_FUNC(HexdigToInt)(i[2]); - const int code = 16 * left + right; - if (uriIsUnreserved(code)) { - return URI_TRUE; - } - } - } - } - } - return URI_FALSE; +static URI_INLINE UriBool URI_FUNC(ContainsUglyPercentEncoding)( + const URI_CHAR * first, const URI_CHAR * afterLast) { + if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { + const URI_CHAR * i = first; + for (; i + 2 < afterLast; i++) { + if (i[0] == _UT('%')) { + /* 6.2.2.1 Case Normalization: * + * lowercase percent-encodings */ + if (((i[1] >= _UT('a')) && (i[1] <= _UT('f'))) + || ((i[2] >= _UT('a')) && (i[2] <= _UT('f')))) { + return URI_TRUE; + } else { + /* 6.2.2.2 Percent-Encoding Normalization: * + * percent-encoded unreserved characters */ + const unsigned char left = URI_FUNC(HexdigToInt)(i[1]); + const unsigned char right = URI_FUNC(HexdigToInt)(i[2]); + const int code = 16 * left + right; + if (uriIsUnreserved(code)) { + return URI_TRUE; + } + } + } + } + } + return URI_FALSE; } - - static URI_INLINE void URI_FUNC(LowercaseInplace)(const URI_CHAR * first, - const URI_CHAR * afterLast) { - if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { - URI_CHAR * i = (URI_CHAR *)first; - const int lowerUpperDiff = (_UT('a') - _UT('A')); - for (; i < afterLast; i++) { - if ((*i >= _UT('A')) && (*i <=_UT('Z'))) { - *i = (URI_CHAR)(*i + lowerUpperDiff); - } - } - } + const URI_CHAR * afterLast) { + if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { + URI_CHAR * i = (URI_CHAR *)first; + const int lowerUpperDiff = (_UT('a') - _UT('A')); + for (; i < afterLast; i++) { + if ((*i >= _UT('A')) && (*i <= _UT('Z'))) { + *i = (URI_CHAR)(*i + lowerUpperDiff); + } + } + } } - - -static URI_INLINE void URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first, - const URI_CHAR * afterLast) { - if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { - URI_CHAR * i = (URI_CHAR *)first; - const int lowerUpperDiff = (_UT('a') - _UT('A')); - for (; i < afterLast; i++) { - if ((*i >= _UT('A')) && (*i <=_UT('Z'))) { - *i = (URI_CHAR)(*i + lowerUpperDiff); - } else if (*i == _UT('%')) { - if (i + 3 >= afterLast) { - return; - } - i += 2; - } - } - } +static URI_INLINE void +URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first, + const URI_CHAR * afterLast) { + if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) { + URI_CHAR * i = (URI_CHAR *)first; + const int lowerUpperDiff = (_UT('a') - _UT('A')); + for (; i < afterLast; i++) { + if ((*i >= _UT('A')) && (*i <= _UT('Z'))) { + *i = (URI_CHAR)(*i + lowerUpperDiff); + } else if (*i == _UT('%')) { + if (i + 3 >= afterLast) { + return; + } + i += 2; + } + } + } } - - static URI_INLINE UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first, - const URI_CHAR ** afterLast, UriMemoryManager * memory) { - int lenInChars; - const int lowerUpperDiff = (_UT('a') - _UT('A')); - URI_CHAR * buffer; - int i = 0; - - if ((first == NULL) || (afterLast == NULL) || (*first == NULL) - || (*afterLast == NULL)) { - return URI_FALSE; - } - - lenInChars = (int)(*afterLast - *first); - if (lenInChars == 0) { - return URI_TRUE; - } else if (lenInChars < 0) { - return URI_FALSE; - } - - buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR)); - if (buffer == NULL) { - return URI_FALSE; - } - - for (; i < lenInChars; i++) { - if (((*first)[i] >= _UT('A')) && ((*first)[i] <=_UT('Z'))) { - buffer[i] = (URI_CHAR)((*first)[i] + lowerUpperDiff); - } else { - buffer[i] = (*first)[i]; - } - } - - *first = buffer; - *afterLast = buffer + lenInChars; - return URI_TRUE; + const URI_CHAR ** afterLast, + UriMemoryManager * memory) { + int lenInChars; + const int lowerUpperDiff = (_UT('a') - _UT('A')); + URI_CHAR * buffer; + int i = 0; + + if ((first == NULL) || (afterLast == NULL) || (*first == NULL) + || (*afterLast == NULL)) { + return URI_FALSE; + } + + lenInChars = (int)(*afterLast - *first); + if (lenInChars == 0) { + return URI_TRUE; + } else if (lenInChars < 0) { + return URI_FALSE; + } + + buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR)); + if (buffer == NULL) { + return URI_FALSE; + } + + for (; i < lenInChars; i++) { + if (((*first)[i] >= _UT('A')) && ((*first)[i] <= _UT('Z'))) { + buffer[i] = (URI_CHAR)((*first)[i] + lowerUpperDiff); + } else { + buffer[i] = (*first)[i]; + } + } + + *first = buffer; + *afterLast = buffer + lenInChars; + return URI_TRUE; } - - /* NOTE: Implementation must stay inplace-compatible */ -static URI_INLINE void URI_FUNC(FixPercentEncodingEngine)( - const URI_CHAR * inFirst, const URI_CHAR * inAfterLast, - const URI_CHAR * outFirst, const URI_CHAR ** outAfterLast) { - URI_CHAR * write = (URI_CHAR *)outFirst; - const int lenInChars = (int)(inAfterLast - inFirst); - int i = 0; - - /* All but last two */ - for (; i + 2 < lenInChars; i++) { - if (inFirst[i] != _UT('%')) { - write[0] = inFirst[i]; - write++; - } else { - /* 6.2.2.2 Percent-Encoding Normalization: * - * percent-encoded unreserved characters */ - const URI_CHAR one = inFirst[i + 1]; - const URI_CHAR two = inFirst[i + 2]; - const unsigned char left = URI_FUNC(HexdigToInt)(one); - const unsigned char right = URI_FUNC(HexdigToInt)(two); - const int code = 16 * left + right; - if (uriIsUnreserved(code)) { - write[0] = (URI_CHAR)(code); - write++; - } else { - /* 6.2.2.1 Case Normalization: * - * uppercase percent-encodings */ - write[0] = _UT('%'); - write[1] = URI_FUNC(HexToLetterEx)(left, URI_TRUE); - write[2] = URI_FUNC(HexToLetterEx)(right, URI_TRUE); - write += 3; - } - - i += 2; /* For the two chars of the percent group we just ate */ - } - } - - /* Last two */ - for (; i < lenInChars; i++) { - write[0] = inFirst[i]; - write++; - } - - *outAfterLast = write; +static URI_INLINE void +URI_FUNC(FixPercentEncodingEngine)(const URI_CHAR * inFirst, const URI_CHAR * inAfterLast, + const URI_CHAR * outFirst, + const URI_CHAR ** outAfterLast) { + URI_CHAR * write = (URI_CHAR *)outFirst; + const int lenInChars = (int)(inAfterLast - inFirst); + int i = 0; + + /* All but last two */ + for (; i + 2 < lenInChars; i++) { + if (inFirst[i] != _UT('%')) { + write[0] = inFirst[i]; + write++; + } else { + /* 6.2.2.2 Percent-Encoding Normalization: * + * percent-encoded unreserved characters */ + const URI_CHAR one = inFirst[i + 1]; + const URI_CHAR two = inFirst[i + 2]; + const unsigned char left = URI_FUNC(HexdigToInt)(one); + const unsigned char right = URI_FUNC(HexdigToInt)(two); + const int code = 16 * left + right; + if (uriIsUnreserved(code)) { + write[0] = (URI_CHAR)(code); + write++; + } else { + /* 6.2.2.1 Case Normalization: * + * uppercase percent-encodings */ + write[0] = _UT('%'); + write[1] = URI_FUNC(HexToLetterEx)(left, URI_TRUE); + write[2] = URI_FUNC(HexToLetterEx)(right, URI_TRUE); + write += 3; + } + + i += 2; /* For the two chars of the percent group we just ate */ + } + } + + /* Last two */ + for (; i < lenInChars; i++) { + write[0] = inFirst[i]; + write++; + } + + *outAfterLast = write; } - - static URI_INLINE void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first, - const URI_CHAR ** afterLast) { - /* Death checks */ - if ((first == NULL) || (afterLast == NULL) || (*afterLast == NULL)) { - return; - } - - /* Fix inplace */ - URI_FUNC(FixPercentEncodingEngine)(first, *afterLast, first, afterLast); + const URI_CHAR ** afterLast) { + /* Death checks */ + if ((first == NULL) || (afterLast == NULL) || (*afterLast == NULL)) { + return; + } + + /* Fix inplace */ + URI_FUNC(FixPercentEncodingEngine)(first, *afterLast, first, afterLast); } - - static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first, - const URI_CHAR ** afterLast, UriMemoryManager * memory) { - int lenInChars; - URI_CHAR * buffer; - - /* Death checks */ - if ((first == NULL) || (afterLast == NULL) - || (*first == NULL) || (*afterLast == NULL)) { - return URI_FALSE; - } - - /* Old text length */ - lenInChars = (int)(*afterLast - *first); - if (lenInChars == 0) { - return URI_TRUE; - } else if (lenInChars < 0) { - return URI_FALSE; - } - - /* New buffer */ - buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR)); - if (buffer == NULL) { - return URI_FALSE; - } - - /* Fix on copy */ - URI_FUNC(FixPercentEncodingEngine)(*first, *afterLast, buffer, afterLast); - *first = buffer; - return URI_TRUE; + const URI_CHAR ** afterLast, + UriMemoryManager * memory) { + int lenInChars; + URI_CHAR * buffer; + + /* Death checks */ + if ((first == NULL) || (afterLast == NULL) || (*first == NULL) + || (*afterLast == NULL)) { + return URI_FALSE; + } + + /* Old text length */ + lenInChars = (int)(*afterLast - *first); + if (lenInChars == 0) { + return URI_TRUE; + } else if (lenInChars < 0) { + return URI_FALSE; + } + + /* New buffer */ + buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR)); + if (buffer == NULL) { + return URI_FALSE; + } + + /* Fix on copy */ + URI_FUNC(FixPercentEncodingEngine)(*first, *afterLast, buffer, afterLast); + *first = buffer; + return URI_TRUE; } - - static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask, - unsigned int maskTest, URI_TYPE(TextRange) * range, - UriMemoryManager * memory) { - if (((*revertMask & maskTest) == 0) - && (range->first != NULL) - && (range->afterLast != NULL) - && (range->afterLast > range->first)) { - if (URI_FUNC(CopyRange)(range, range, memory) == URI_FALSE) { - return URI_FALSE; - } - *revertMask |= maskTest; - } - return URI_TRUE; + unsigned int maskTest, + URI_TYPE(TextRange) * range, + UriMemoryManager * memory) { + if (((*revertMask & maskTest) == 0) && (range->first != NULL) + && (range->afterLast != NULL) && (range->afterLast > range->first)) { + if (URI_FUNC(CopyRange)(range, range, memory) == URI_FALSE) { + return URI_FALSE; + } + *revertMask |= maskTest; + } + return URI_TRUE; } - - static URI_INLINE UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri, - unsigned int * revertMask, UriMemoryManager * memory) { - URI_TYPE(PathSegment) * walker = uri->pathHead; - if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_SCHEME, - &(uri->scheme), memory) - || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_USER_INFO, - &(uri->userInfo), memory) - || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_QUERY, - &(uri->query), memory) - || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_FRAGMENT, - &(uri->fragment), memory)) { - return URI_FALSE; /* Raises malloc error */ - } - - /* Host */ - if ((*revertMask & URI_NORMALIZE_HOST) == 0) { - if (uri->hostData.ipFuture.first != NULL) { - /* IPvFuture */ - if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST, - &(uri->hostData.ipFuture), memory)) { - return URI_FALSE; /* Raises malloc error */ - } - uri->hostText.first = uri->hostData.ipFuture.first; - uri->hostText.afterLast = uri->hostData.ipFuture.afterLast; - } else if (uri->hostText.first != NULL) { - /* Regname */ - if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST, - &(uri->hostText), memory)) { - return URI_FALSE; /* Raises malloc error */ - } - } - } - - /* Path */ - if ((*revertMask & URI_NORMALIZE_PATH) == 0) { - while (walker != NULL) { - if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(walker->text), memory)) { - /* Free allocations done so far and kill path */ - - /* Kill path to one before walker (if any) */ - URI_TYPE(PathSegment) * ranger = uri->pathHead; - while (ranger != walker) { - URI_TYPE(PathSegment) * const next = ranger->next; - if ((ranger->text.first != NULL) - && (ranger->text.afterLast != NULL) - && (ranger->text.afterLast > ranger->text.first)) { - memory->free(memory, (URI_CHAR *)ranger->text.first); - } - memory->free(memory, ranger); - ranger = next; - } - - /* Kill path from walker */ - while (walker != NULL) { - URI_TYPE(PathSegment) * const next = walker->next; - memory->free(memory, walker); - walker = next; - } - - uri->pathHead = NULL; - uri->pathTail = NULL; - return URI_FALSE; /* Raises malloc error */ - } - walker = walker->next; - } - *revertMask |= URI_NORMALIZE_PATH; - } - - /* Port text, must come last so we don't have to undo that one if it fails. * - * Otherwise we would need and extra enum flag for it although the port * - * cannot go unnormalized... */ - if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(uri->portText), memory)) { - return URI_FALSE; /* Raises malloc error */ - } - - return URI_TRUE; + unsigned int * revertMask, + UriMemoryManager * memory) { + URI_TYPE(PathSegment) * walker = uri->pathHead; + if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_SCHEME, &(uri->scheme), + memory) + || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_USER_INFO, + &(uri->userInfo), memory) + || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_QUERY, &(uri->query), + memory) + || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_FRAGMENT, &(uri->fragment), + memory)) { + return URI_FALSE; /* Raises malloc error */ + } + + /* Host */ + if ((*revertMask & URI_NORMALIZE_HOST) == 0) { + if (uri->hostData.ipFuture.first != NULL) { + /* IPvFuture */ + if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST, + &(uri->hostData.ipFuture), memory)) { + return URI_FALSE; /* Raises malloc error */ + } + uri->hostText.first = uri->hostData.ipFuture.first; + uri->hostText.afterLast = uri->hostData.ipFuture.afterLast; + } else if (uri->hostText.first != NULL) { + /* Regname */ + if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST, + &(uri->hostText), memory)) { + return URI_FALSE; /* Raises malloc error */ + } + } + } + + /* Path */ + if ((*revertMask & URI_NORMALIZE_PATH) == 0) { + while (walker != NULL) { + if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(walker->text), memory)) { + /* Free allocations done so far and kill path */ + + /* Kill path to one before walker (if any) */ + URI_TYPE(PathSegment) * ranger = uri->pathHead; + while (ranger != walker) { + URI_TYPE(PathSegment) * const next = ranger->next; + if ((ranger->text.first != NULL) && (ranger->text.afterLast != NULL) + && (ranger->text.afterLast > ranger->text.first)) { + memory->free(memory, (URI_CHAR *)ranger->text.first); + } + memory->free(memory, ranger); + ranger = next; + } + + /* Kill path from walker */ + while (walker != NULL) { + URI_TYPE(PathSegment) * const next = walker->next; + memory->free(memory, walker); + walker = next; + } + + uri->pathHead = NULL; + uri->pathTail = NULL; + return URI_FALSE; /* Raises malloc error */ + } + walker = walker->next; + } + *revertMask |= URI_NORMALIZE_PATH; + } + + /* Port text, must come last so we don't have to undo that one if it fails. * + * Otherwise we would need and extra enum flag for it although the port * + * cannot go unnormalized... */ + if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(uri->portText), memory)) { + return URI_FALSE; /* Raises malloc error */ + } + + return URI_TRUE; } - - unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri) { - unsigned int outMask = URI_NORMALIZED; /* for NULL uri */ - URI_FUNC(NormalizeSyntaxMaskRequiredEx)(uri, &outMask); - return outMask; + unsigned int outMask = URI_NORMALIZED; /* for NULL uri */ + URI_FUNC(NormalizeSyntaxMaskRequiredEx)(uri, &outMask); + return outMask; } - - int URI_FUNC(NormalizeSyntaxMaskRequiredEx)(const URI_TYPE(Uri) * uri, - unsigned int * outMask) { - UriMemoryManager * const memory = NULL; /* no use of memory manager */ - -#if defined(__GNUC__) && ((__GNUC__ > 4) \ - || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2))) - /* Slower code that fixes a warning, not sure if this is a smart idea */ - URI_TYPE(Uri) writeableClone; -#endif - - if ((uri == NULL) || (outMask == NULL)) { - return URI_ERROR_NULL; - } - -#if defined(__GNUC__) && ((__GNUC__ > 4) \ - || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2))) - /* Slower code that fixes a warning, not sure if this is a smart idea */ - memcpy(&writeableClone, uri, 1 * sizeof(URI_TYPE(Uri))); - URI_FUNC(NormalizeSyntaxEngine)(&writeableClone, 0, outMask, memory); -#else - URI_FUNC(NormalizeSyntaxEngine)((URI_TYPE(Uri) *)uri, 0, outMask, memory); -#endif - return URI_SUCCESS; + unsigned int * outMask) { + UriMemoryManager * const memory = NULL; /* no use of memory manager */ + +# if defined(__GNUC__) \ + && ((__GNUC__ > 4) \ + || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2))) + /* Slower code that fixes a warning, not sure if this is a smart idea */ + URI_TYPE(Uri) writeableClone; +# endif + + if ((uri == NULL) || (outMask == NULL)) { + return URI_ERROR_NULL; + } + +# if defined(__GNUC__) \ + && ((__GNUC__ > 4) \ + || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2))) + /* Slower code that fixes a warning, not sure if this is a smart idea */ + memcpy(&writeableClone, uri, 1 * sizeof(URI_TYPE(Uri))); + URI_FUNC(NormalizeSyntaxEngine)(&writeableClone, 0, outMask, memory); +# else + URI_FUNC(NormalizeSyntaxEngine)((URI_TYPE(Uri) *)uri, 0, outMask, memory); +# endif + return URI_SUCCESS; } - - int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask) { - return URI_FUNC(NormalizeSyntaxExMm)(uri, mask, NULL); + return URI_FUNC(NormalizeSyntaxExMm)(uri, mask, NULL); } - - int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri, unsigned int mask, - UriMemoryManager * memory) { - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - return URI_FUNC(NormalizeSyntaxEngine)(uri, mask, NULL, memory); + UriMemoryManager * memory) { + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + return URI_FUNC(NormalizeSyntaxEngine)(uri, mask, NULL, memory); } - - int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri) { - return URI_FUNC(NormalizeSyntaxEx)(uri, (unsigned int)-1); + return URI_FUNC(NormalizeSyntaxEx)(uri, (unsigned int)-1); } - -static const URI_CHAR * URI_FUNC(PastLeadingZeros)(const URI_CHAR * first, const URI_CHAR * afterLast) { - assert(first != NULL); - assert(afterLast != NULL); - assert(first != afterLast); - - { - /* Find the first non-zero character */ - const URI_CHAR * remainderFirst = first; - while ((remainderFirst < afterLast) && (remainderFirst[0] == _UT('0'))) { - remainderFirst++; - } - - /* Is the string /all/ zeros? */ - if (remainderFirst == afterLast) { - /* Yes, and length is >=1 because we ruled out the empty string earlier; - * pull back onto rightmost zero */ - assert(remainderFirst > first); - remainderFirst--; - assert(remainderFirst[0] == _UT('0')); - } - - return remainderFirst; - } +static const URI_CHAR * URI_FUNC(PastLeadingZeros)(const URI_CHAR * first, + const URI_CHAR * afterLast) { + assert(first != NULL); + assert(afterLast != NULL); + assert(first != afterLast); + + /* Find the first non-zero character */ + const URI_CHAR * remainderFirst = first; + while ((remainderFirst < afterLast) && (remainderFirst[0] == _UT('0'))) { + remainderFirst++; + } + + /* Is the string /all/ zeros? */ + if (remainderFirst == afterLast) { + /* Yes, and length is >=1 because we ruled out the empty string earlier; + * pull back onto rightmost zero */ + assert(remainderFirst > first); + remainderFirst--; + assert(remainderFirst[0] == _UT('0')); + } + + return remainderFirst; } +static void URI_FUNC(DropLeadingZerosInplace)(URI_CHAR * first, + const URI_CHAR ** afterLast) { + assert(first != NULL); + assert(afterLast != NULL); + assert(*afterLast != NULL); + if (first == *afterLast) { + return; + } -static void URI_FUNC(DropLeadingZerosInplace)(URI_CHAR * first, const URI_CHAR ** afterLast) { - assert(first != NULL); - assert(afterLast != NULL); - assert(*afterLast != NULL); - - if (first == *afterLast) { - return; - } - - { - const URI_CHAR * const remainderFirst = URI_FUNC(PastLeadingZeros)(first, *afterLast); + const URI_CHAR * const remainderFirst = URI_FUNC(PastLeadingZeros)(first, *afterLast); - if (remainderFirst > first) { - const size_t remainderLen = *afterLast - remainderFirst; - memmove(first, remainderFirst, remainderLen * sizeof(URI_CHAR)); - first[remainderLen] = _UT('\0'); - *afterLast = first + remainderLen; - } - } + if (remainderFirst > first) { + const size_t remainderLen = *afterLast - remainderFirst; + memmove(first, remainderFirst, remainderLen * sizeof(URI_CHAR)); + first[remainderLen] = _UT('\0'); + *afterLast = first + remainderLen; + } } +static void URI_FUNC(AdvancePastLeadingZeros)(const URI_CHAR ** first, + const URI_CHAR * afterLast) { + assert(first != NULL); + assert(*first != NULL); + assert(afterLast != NULL); + if (*first == afterLast) { + return; + } -static void URI_FUNC(AdvancePastLeadingZeros)( - const URI_CHAR ** first, const URI_CHAR * afterLast) { - assert(first != NULL); - assert(*first != NULL); - assert(afterLast != NULL); + const URI_CHAR * const remainderFirst = URI_FUNC(PastLeadingZeros)(*first, afterLast); - if (*first == afterLast) { - return; - } - - { - const URI_CHAR * const remainderFirst = URI_FUNC(PastLeadingZeros)(*first, afterLast); - - /* Cut off leading zeros */ - *first = remainderFirst; - } + /* Cut off leading zeros */ + *first = remainderFirst; } - - static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, - unsigned int inMask, unsigned int * outMask, - UriMemoryManager * memory) { - unsigned int revertMask = URI_NORMALIZED; - - /* Not just doing inspection? -> memory manager required! */ - if (outMask == NULL) { - assert(memory != NULL); - } - - if (uri == NULL) { - if (outMask != NULL) { - *outMask = URI_NORMALIZED; - return URI_SUCCESS; - } else { - return URI_ERROR_NULL; - } - } - - if (outMask != NULL) { - /* Reset mask */ - *outMask = URI_NORMALIZED; - } else if (inMask == URI_NORMALIZED) { - /* Nothing to do */ - return URI_SUCCESS; - } - - /* Scheme, host */ - if (outMask != NULL) { - const UriBool normalizeScheme = URI_FUNC(ContainsUppercaseLetters)( - uri->scheme.first, uri->scheme.afterLast); - const UriBool normalizeHostCase = URI_FUNC(ContainsUppercaseLetters)( - uri->hostText.first, uri->hostText.afterLast); - if (normalizeScheme) { - *outMask |= URI_NORMALIZE_SCHEME; - } - - if (normalizeHostCase) { - *outMask |= URI_NORMALIZE_HOST; - } else { - const UriBool normalizeHostPrecent = URI_FUNC(ContainsUglyPercentEncoding)( - uri->hostText.first, uri->hostText.afterLast); - if (normalizeHostPrecent) { - *outMask |= URI_NORMALIZE_HOST; - } - } - } else { - /* Scheme */ - if ((inMask & URI_NORMALIZE_SCHEME) && (uri->scheme.first != NULL)) { - if (uri->owner) { - URI_FUNC(LowercaseInplace)(uri->scheme.first, uri->scheme.afterLast); - } else { - if (!URI_FUNC(LowercaseMalloc)(&(uri->scheme.first), &(uri->scheme.afterLast), memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - revertMask |= URI_NORMALIZE_SCHEME; - } - } - - /* Host */ - if (inMask & URI_NORMALIZE_HOST) { - if (uri->hostData.ipFuture.first != NULL) { - /* IPvFuture */ - if (uri->owner) { - URI_FUNC(LowercaseInplace)(uri->hostData.ipFuture.first, - uri->hostData.ipFuture.afterLast); - } else { - if (!URI_FUNC(LowercaseMalloc)(&(uri->hostData.ipFuture.first), - &(uri->hostData.ipFuture.afterLast), memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - revertMask |= URI_NORMALIZE_HOST; - } - uri->hostText.first = uri->hostData.ipFuture.first; - uri->hostText.afterLast = uri->hostData.ipFuture.afterLast; - } else if ((uri->hostText.first != NULL) - && (uri->hostData.ip4 == NULL)) { - /* Regname or IPv6 */ - if (uri->owner) { - URI_FUNC(FixPercentEncodingInplace)(uri->hostText.first, - &(uri->hostText.afterLast)); - } else { - if (!URI_FUNC(FixPercentEncodingMalloc)( - &(uri->hostText.first), - &(uri->hostText.afterLast), - memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - revertMask |= URI_NORMALIZE_HOST; - } - - URI_FUNC(LowercaseInplaceExceptPercentEncoding)(uri->hostText.first, - uri->hostText.afterLast); - } - } - } - - /* Port */ - if (outMask != NULL) { - /* Is there a port even? */ - if (uri->portText.first != NULL) { - /* Determine whether the port is already normalized, i.e. either "", "0" or no leading zeros */ - const size_t portLen = uri->portText.afterLast - uri->portText.first; - if ((portLen > 1) && (uri->portText.first[0] == _UT('0'))) { - *outMask |= URI_NORMALIZE_PORT; - } - } - } else { - /* Normalize the port, i.e. drop leading zeros (except for string "0") */ - if ((inMask & URI_NORMALIZE_PORT) && (uri->portText.first != NULL)) { - if (uri->owner) { - URI_FUNC(DropLeadingZerosInplace)((URI_CHAR *)uri->portText.first, &(uri->portText.afterLast)); - } else { - URI_FUNC(AdvancePastLeadingZeros)(&(uri->portText.first), uri->portText.afterLast); - } - } - } - - /* User info */ - if (outMask != NULL) { - const UriBool normalizeUserInfo = URI_FUNC(ContainsUglyPercentEncoding)( - uri->userInfo.first, uri->userInfo.afterLast); - if (normalizeUserInfo) { - *outMask |= URI_NORMALIZE_USER_INFO; - } - } else { - if ((inMask & URI_NORMALIZE_USER_INFO) && (uri->userInfo.first != NULL)) { - if (uri->owner) { - URI_FUNC(FixPercentEncodingInplace)(uri->userInfo.first, &(uri->userInfo.afterLast)); - } else { - if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->userInfo.first), - &(uri->userInfo.afterLast), memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - revertMask |= URI_NORMALIZE_USER_INFO; - } - } - } - - /* Path */ - if (outMask != NULL) { - const URI_TYPE(PathSegment) * walker = uri->pathHead; - while (walker != NULL) { - const URI_CHAR * const first = walker->text.first; - const URI_CHAR * const afterLast = walker->text.afterLast; - if ((first != NULL) - && (afterLast != NULL) - && (afterLast > first) - && ( - (((afterLast - first) == 1) - && (first[0] == _UT('.'))) - || - (((afterLast - first) == 2) - && (first[0] == _UT('.')) - && (first[1] == _UT('.'))) - || - URI_FUNC(ContainsUglyPercentEncoding)(first, afterLast) - )) { - *outMask |= URI_NORMALIZE_PATH; - break; - } - walker = walker->next; - } - } else if (inMask & URI_NORMALIZE_PATH) { - URI_TYPE(PathSegment) * walker; - const UriBool relative = ((uri->scheme.first == NULL) - && !uri->absolutePath) ? URI_TRUE : URI_FALSE; - - /* Fix percent-encoding for each segment */ - walker = uri->pathHead; - if (uri->owner) { - while (walker != NULL) { - URI_FUNC(FixPercentEncodingInplace)(walker->text.first, &(walker->text.afterLast)); - walker = walker->next; - } - } else { - while (walker != NULL) { - if (!URI_FUNC(FixPercentEncodingMalloc)(&(walker->text.first), - &(walker->text.afterLast), memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - walker = walker->next; - } - revertMask |= URI_NORMALIZE_PATH; - } - - /* 6.2.2.3 Path Segment Normalization */ - if (!URI_FUNC(RemoveDotSegmentsEx)(uri, relative, - (uri->owner == URI_TRUE) - || ((revertMask & URI_NORMALIZE_PATH) != 0), - memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - URI_FUNC(FixEmptyTrailSegment)(uri, memory); - } - - /* Query, fragment */ - if (outMask != NULL) { - const UriBool normalizeQuery = URI_FUNC(ContainsUglyPercentEncoding)( - uri->query.first, uri->query.afterLast); - const UriBool normalizeFragment = URI_FUNC(ContainsUglyPercentEncoding)( - uri->fragment.first, uri->fragment.afterLast); - if (normalizeQuery) { - *outMask |= URI_NORMALIZE_QUERY; - } - - if (normalizeFragment) { - *outMask |= URI_NORMALIZE_FRAGMENT; - } - } else { - /* Query */ - if ((inMask & URI_NORMALIZE_QUERY) && (uri->query.first != NULL)) { - if (uri->owner) { - URI_FUNC(FixPercentEncodingInplace)(uri->query.first, &(uri->query.afterLast)); - } else { - if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->query.first), - &(uri->query.afterLast), memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - revertMask |= URI_NORMALIZE_QUERY; - } - } - - /* Fragment */ - if ((inMask & URI_NORMALIZE_FRAGMENT) && (uri->fragment.first != NULL)) { - if (uri->owner) { - URI_FUNC(FixPercentEncodingInplace)(uri->fragment.first, &(uri->fragment.afterLast)); - } else { - if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->fragment.first), - &(uri->fragment.afterLast), memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - revertMask |= URI_NORMALIZE_FRAGMENT; - } - } - } - - /* Dup all not duped yet */ - if ((outMask == NULL) && !uri->owner) { - if (!URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } - uri->owner = URI_TRUE; - } - - return URI_SUCCESS; + unsigned int inMask, + unsigned int * outMask, + UriMemoryManager * memory) { + unsigned int revertMask = URI_NORMALIZED; + + /* Not just doing inspection? -> memory manager required! */ + if (outMask == NULL) { + assert(memory != NULL); + } + + if (uri == NULL) { + if (outMask != NULL) { + *outMask = URI_NORMALIZED; + return URI_SUCCESS; + } else { + return URI_ERROR_NULL; + } + } + + if (outMask != NULL) { + /* Reset mask */ + *outMask = URI_NORMALIZED; + } else if (inMask == URI_NORMALIZED) { + /* Nothing to do */ + return URI_SUCCESS; + } + + /* Scheme, host */ + if (outMask != NULL) { + const UriBool normalizeScheme = + URI_FUNC(ContainsUppercaseLetters)(uri->scheme.first, uri->scheme.afterLast); + const UriBool normalizeHostCase = URI_FUNC(ContainsUppercaseLetters)( + uri->hostText.first, uri->hostText.afterLast); + if (normalizeScheme) { + *outMask |= URI_NORMALIZE_SCHEME; + } + + if (normalizeHostCase) { + *outMask |= URI_NORMALIZE_HOST; + } else { + const UriBool normalizeHostPrecent = URI_FUNC(ContainsUglyPercentEncoding)( + uri->hostText.first, uri->hostText.afterLast); + if (normalizeHostPrecent) { + *outMask |= URI_NORMALIZE_HOST; + } + } + } else { + /* Scheme */ + if ((inMask & URI_NORMALIZE_SCHEME) && (uri->scheme.first != NULL)) { + if (uri->owner) { + URI_FUNC(LowercaseInplace)(uri->scheme.first, uri->scheme.afterLast); + } else { + if (!URI_FUNC(LowercaseMalloc)(&(uri->scheme.first), + &(uri->scheme.afterLast), memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + revertMask |= URI_NORMALIZE_SCHEME; + } + } + + /* Host */ + if (inMask & URI_NORMALIZE_HOST) { + if (uri->hostData.ipFuture.first != NULL) { + /* IPvFuture */ + if (uri->owner) { + URI_FUNC(LowercaseInplace)(uri->hostData.ipFuture.first, + uri->hostData.ipFuture.afterLast); + } else { + if (!URI_FUNC(LowercaseMalloc)(&(uri->hostData.ipFuture.first), + &(uri->hostData.ipFuture.afterLast), + memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + revertMask |= URI_NORMALIZE_HOST; + } + uri->hostText.first = uri->hostData.ipFuture.first; + uri->hostText.afterLast = uri->hostData.ipFuture.afterLast; + } else if ((uri->hostText.first != NULL) && (uri->hostData.ip4 == NULL)) { + /* Regname or IPv6 */ + if (uri->owner) { + URI_FUNC(FixPercentEncodingInplace)(uri->hostText.first, + &(uri->hostText.afterLast)); + } else { + if (!URI_FUNC(FixPercentEncodingMalloc)( + &(uri->hostText.first), &(uri->hostText.afterLast), memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + revertMask |= URI_NORMALIZE_HOST; + } + + URI_FUNC(LowercaseInplaceExceptPercentEncoding)(uri->hostText.first, + uri->hostText.afterLast); + } + } + } + + /* Port */ + if (outMask != NULL) { + /* Is there a port even? */ + if (uri->portText.first != NULL) { + /* Determine whether the port is already normalized, i.e. either "", "0" or no + * leading zeros */ + const size_t portLen = uri->portText.afterLast - uri->portText.first; + if ((portLen > 1) && (uri->portText.first[0] == _UT('0'))) { + *outMask |= URI_NORMALIZE_PORT; + } + } + } else { + /* Normalize the port, i.e. drop leading zeros (except for string "0") */ + if ((inMask & URI_NORMALIZE_PORT) && (uri->portText.first != NULL)) { + if (uri->owner) { + URI_FUNC(DropLeadingZerosInplace)((URI_CHAR *)uri->portText.first, + &(uri->portText.afterLast)); + } else { + URI_FUNC(AdvancePastLeadingZeros)(&(uri->portText.first), + uri->portText.afterLast); + } + } + } + + /* User info */ + if (outMask != NULL) { + const UriBool normalizeUserInfo = URI_FUNC(ContainsUglyPercentEncoding)( + uri->userInfo.first, uri->userInfo.afterLast); + if (normalizeUserInfo) { + *outMask |= URI_NORMALIZE_USER_INFO; + } + } else { + if ((inMask & URI_NORMALIZE_USER_INFO) && (uri->userInfo.first != NULL)) { + if (uri->owner) { + URI_FUNC(FixPercentEncodingInplace)(uri->userInfo.first, + &(uri->userInfo.afterLast)); + } else { + if (!URI_FUNC(FixPercentEncodingMalloc)( + &(uri->userInfo.first), &(uri->userInfo.afterLast), memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + revertMask |= URI_NORMALIZE_USER_INFO; + } + } + } + + /* Path */ + if (outMask != NULL) { + const URI_TYPE(PathSegment) * walker = uri->pathHead; + while (walker != NULL) { + const URI_CHAR * const first = walker->text.first; + const URI_CHAR * const afterLast = walker->text.afterLast; + if ((first != NULL) && (afterLast != NULL) && (afterLast > first) + && ((((afterLast - first) == 1) && (first[0] == _UT('.'))) + || (((afterLast - first) == 2) && (first[0] == _UT('.')) + && (first[1] == _UT('.'))) + || URI_FUNC(ContainsUglyPercentEncoding)(first, afterLast))) { + *outMask |= URI_NORMALIZE_PATH; + break; + } + walker = walker->next; + } + } else if (inMask & URI_NORMALIZE_PATH) { + URI_TYPE(PathSegment) * walker; + const UriBool relative = + ((uri->scheme.first == NULL) && !uri->absolutePath) ? URI_TRUE : URI_FALSE; + + /* Fix percent-encoding for each segment */ + walker = uri->pathHead; + if (uri->owner) { + while (walker != NULL) { + URI_FUNC(FixPercentEncodingInplace)(walker->text.first, + &(walker->text.afterLast)); + walker = walker->next; + } + } else { + while (walker != NULL) { + if (!URI_FUNC(FixPercentEncodingMalloc)( + &(walker->text.first), &(walker->text.afterLast), memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + walker = walker->next; + } + revertMask |= URI_NORMALIZE_PATH; + } + + /* 6.2.2.3 Path Segment Normalization */ + if (!URI_FUNC(RemoveDotSegmentsEx)( + uri, relative, + (uri->owner == URI_TRUE) || ((revertMask & URI_NORMALIZE_PATH) != 0), + memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + URI_FUNC(FixEmptyTrailSegment)(uri, memory); + } + + /* Query, fragment */ + if (outMask != NULL) { + const UriBool normalizeQuery = + URI_FUNC(ContainsUglyPercentEncoding)(uri->query.first, uri->query.afterLast); + const UriBool normalizeFragment = URI_FUNC(ContainsUglyPercentEncoding)( + uri->fragment.first, uri->fragment.afterLast); + if (normalizeQuery) { + *outMask |= URI_NORMALIZE_QUERY; + } + + if (normalizeFragment) { + *outMask |= URI_NORMALIZE_FRAGMENT; + } + } else { + /* Query */ + if ((inMask & URI_NORMALIZE_QUERY) && (uri->query.first != NULL)) { + if (uri->owner) { + URI_FUNC(FixPercentEncodingInplace)(uri->query.first, + &(uri->query.afterLast)); + } else { + if (!URI_FUNC(FixPercentEncodingMalloc)( + &(uri->query.first), &(uri->query.afterLast), memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + revertMask |= URI_NORMALIZE_QUERY; + } + } + + /* Fragment */ + if ((inMask & URI_NORMALIZE_FRAGMENT) && (uri->fragment.first != NULL)) { + if (uri->owner) { + URI_FUNC(FixPercentEncodingInplace)(uri->fragment.first, + &(uri->fragment.afterLast)); + } else { + if (!URI_FUNC(FixPercentEncodingMalloc)( + &(uri->fragment.first), &(uri->fragment.afterLast), memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + revertMask |= URI_NORMALIZE_FRAGMENT; + } + } + } + + /* Dup all not duped yet */ + if ((outMask == NULL) && !uri->owner) { + if (!URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } + uri->owner = URI_TRUE; + } + + return URI_SUCCESS; } - - int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { - unsigned int revertMask = URI_NORMALIZED; + unsigned int revertMask = URI_NORMALIZED; - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - if (uri == NULL) { - return URI_ERROR_NULL; - } + if (uri == NULL) { + return URI_ERROR_NULL; + } - if (uri->owner == URI_TRUE) { - return URI_SUCCESS; - } + if (uri->owner == URI_TRUE) { + return URI_SUCCESS; + } - if (! URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) { - URI_FUNC(PreventLeakage)(uri, revertMask, memory); - return URI_ERROR_MALLOC; - } + if (!URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) { + URI_FUNC(PreventLeakage)(uri, revertMask, memory); + return URI_ERROR_MALLOC; + } - uri->owner = URI_TRUE; + uri->owner = URI_TRUE; - return URI_SUCCESS; + return URI_SUCCESS; } - - int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri) { - return URI_FUNC(MakeOwnerMm)(uri, NULL); + return URI_FUNC(MakeOwnerMm)(uri, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriNormalize.h b/ext/uri/uriparser/src/UriNormalize.h index cb58085b7d318..41c87a382c369 100644 --- a/ext/uri/uriparser/src/UriNormalize.h +++ b/ext/uri/uriparser/src/UriNormalize.h @@ -39,38 +39,37 @@ */ #if (defined(URI_PASS_ANSI) && !defined(URI_NORMALIZE_H_ANSI)) \ - || (defined(URI_PASS_UNICODE) && !defined(URI_NORMALIZE_H_UNICODE)) \ - || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) + || (defined(URI_PASS_UNICODE) && !defined(URI_NORMALIZE_H_UNICODE)) \ + || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* What encodings are enabled? */ -#include -#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) +# include +# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriNormalize.h" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriNormalize.h" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriNormalize.h" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriNormalize.h" +# undef URI_PASS_UNICODE +# endif /* Only one pass for each encoding */ -#elif (defined(URI_PASS_ANSI) && !defined(URI_NORMALIZE_H_ANSI) \ - && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ - && !defined(URI_NORMALIZE_H_UNICODE) && defined(URI_ENABLE_UNICODE)) -# ifdef URI_PASS_ANSI -# define URI_NORMALIZE_H_ANSI 1 -# include -# else -# define URI_NORMALIZE_H_UNICODE 1 -# include -# endif +# elif (defined(URI_PASS_ANSI) && !defined(URI_NORMALIZE_H_ANSI) \ + && defined(URI_ENABLE_ANSI)) \ + || (defined(URI_PASS_UNICODE) && !defined(URI_NORMALIZE_H_UNICODE) \ + && defined(URI_ENABLE_UNICODE)) +# ifdef URI_PASS_ANSI +# define URI_NORMALIZE_H_ANSI 1 +# include +# else +# define URI_NORMALIZE_H_UNICODE 1 +# include +# endif +void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, unsigned int revertMask, + UriMemoryManager * memory); - -void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, - unsigned int revertMask, UriMemoryManager * memory); - -#endif +# endif #endif diff --git a/ext/uri/uriparser/src/UriNormalizeBase.c b/ext/uri/uriparser/src/UriNormalizeBase.c index a74fcd3f8bfbf..9c2acee1ee759 100644 --- a/ext/uri/uriparser/src/UriNormalizeBase.c +++ b/ext/uri/uriparser/src/UriNormalizeBase.c @@ -38,82 +38,80 @@ */ #ifndef URI_DOXYGEN -# include "UriNormalizeBase.h" +# include "UriNormalizeBase.h" #endif - - UriBool uriIsUnreserved(int code) { - switch (code) { - case L'a': /* ALPHA */ - case L'A': - case L'b': - case L'B': - case L'c': - case L'C': - case L'd': - case L'D': - case L'e': - case L'E': - case L'f': - case L'F': - case L'g': - case L'G': - case L'h': - case L'H': - case L'i': - case L'I': - case L'j': - case L'J': - case L'k': - case L'K': - case L'l': - case L'L': - case L'm': - case L'M': - case L'n': - case L'N': - case L'o': - case L'O': - case L'p': - case L'P': - case L'q': - case L'Q': - case L'r': - case L'R': - case L's': - case L'S': - case L't': - case L'T': - case L'u': - case L'U': - case L'v': - case L'V': - case L'w': - case L'W': - case L'x': - case L'X': - case L'y': - case L'Y': - case L'z': - case L'Z': - case L'0': /* DIGIT */ - case L'1': - case L'2': - case L'3': - case L'4': - case L'5': - case L'6': - case L'7': - case L'8': - case L'9': - case L'-': /* "-" / "." / "_" / "~" */ - case L'.': - case L'_': - case L'~': - return URI_TRUE; + switch (code) { + case L'a': /* ALPHA */ + case L'A': + case L'b': + case L'B': + case L'c': + case L'C': + case L'd': + case L'D': + case L'e': + case L'E': + case L'f': + case L'F': + case L'g': + case L'G': + case L'h': + case L'H': + case L'i': + case L'I': + case L'j': + case L'J': + case L'k': + case L'K': + case L'l': + case L'L': + case L'm': + case L'M': + case L'n': + case L'N': + case L'o': + case L'O': + case L'p': + case L'P': + case L'q': + case L'Q': + case L'r': + case L'R': + case L's': + case L'S': + case L't': + case L'T': + case L'u': + case L'U': + case L'v': + case L'V': + case L'w': + case L'W': + case L'x': + case L'X': + case L'y': + case L'Y': + case L'z': + case L'Z': + case L'0': /* DIGIT */ + case L'1': + case L'2': + case L'3': + case L'4': + case L'5': + case L'6': + case L'7': + case L'8': + case L'9': + case L'-': /* "-" / "." / "_" / "~" */ + case L'.': + case L'_': + case L'~': + return URI_TRUE; - default: - return URI_FALSE; - } + default: + return URI_FALSE; + } } diff --git a/ext/uri/uriparser/src/UriNormalizeBase.h b/ext/uri/uriparser/src/UriNormalizeBase.h index 8651c8616649f..3ff49112a82cc 100644 --- a/ext/uri/uriparser/src/UriNormalizeBase.h +++ b/ext/uri/uriparser/src/UriNormalizeBase.h @@ -38,16 +38,10 @@ */ #ifndef URI_NORMALIZE_BASE_H -#define URI_NORMALIZE_BASE_H 1 - - - -#include - +# define URI_NORMALIZE_BASE_H 1 +# include UriBool uriIsUnreserved(int code); - - #endif /* URI_NORMALIZE_BASE_H */ diff --git a/ext/uri/uriparser/src/UriParse.c b/ext/uri/uriparser/src/UriParse.c index 8bb18f65ac166..cada02301e00c 100644 --- a/ext/uri/uriparser/src/UriParse.c +++ b/ext/uri/uriparser/src/UriParse.c @@ -47,839 +47,757 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriParse.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriParse.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriParse.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriParse.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include -# include "UriCommon.h" -# include "UriMemory.h" -# include "UriParseBase.h" -#endif - - - -#define URI_SET_DIGIT \ - _UT('0'): \ - case _UT('1'): \ - case _UT('2'): \ - case _UT('3'): \ - case _UT('4'): \ - case _UT('5'): \ - case _UT('6'): \ - case _UT('7'): \ - case _UT('8'): \ - case _UT('9') - -#define URI_SET_HEX_LETTER_UPPER \ - _UT('A'): \ - case _UT('B'): \ - case _UT('C'): \ - case _UT('D'): \ - case _UT('E'): \ - case _UT('F') - -#define URI_SET_HEX_LETTER_LOWER \ - _UT('a'): \ - case _UT('b'): \ - case _UT('c'): \ - case _UT('d'): \ - case _UT('e'): \ - case _UT('f') - -#define URI_SET_HEXDIG \ - URI_SET_DIGIT: \ - case URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER - -#define URI_SET_ALPHA \ - URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER: \ - case _UT('g'): \ - case _UT('G'): \ - case _UT('h'): \ - case _UT('H'): \ - case _UT('i'): \ - case _UT('I'): \ - case _UT('j'): \ - case _UT('J'): \ - case _UT('k'): \ - case _UT('K'): \ - case _UT('l'): \ - case _UT('L'): \ - case _UT('m'): \ - case _UT('M'): \ - case _UT('n'): \ - case _UT('N'): \ - case _UT('o'): \ - case _UT('O'): \ - case _UT('p'): \ - case _UT('P'): \ - case _UT('q'): \ - case _UT('Q'): \ - case _UT('r'): \ - case _UT('R'): \ - case _UT('s'): \ - case _UT('S'): \ - case _UT('t'): \ - case _UT('T'): \ - case _UT('u'): \ - case _UT('U'): \ - case _UT('v'): \ - case _UT('V'): \ - case _UT('w'): \ - case _UT('W'): \ - case _UT('x'): \ - case _UT('X'): \ - case _UT('y'): \ - case _UT('Y'): \ - case _UT('z'): \ - case _UT('Z') - - - -static const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); -static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); -static const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast); -static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); -static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory); - -static UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory); -static UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory); -static UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory); -static UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory); +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriParseBase.h" +# include "UriSets.h" +# endif + +static const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast); +static const URI_CHAR * URI_FUNC(ParseHexZero)(const URI_CHAR * first, + const URI_CHAR * afterLast); +static const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParsePort)(const URI_CHAR * first, + const URI_CHAR * afterLast); +static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); + +static UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + UriMemoryManager * memory); +static UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + UriMemoryManager * memory); +static UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + UriMemoryManager * memory); +static UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + UriMemoryManager * memory); static void URI_FUNC(OnExitPartHelperTwo)(URI_TYPE(ParserState) * state); static void URI_FUNC(ResetParserStateExceptUri)(URI_TYPE(ParserState) * state); static UriBool URI_FUNC(PushPathSegment)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory); - -static void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state, const URI_CHAR * errorPos, UriMemoryManager * memory); -static void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state, UriMemoryManager * memory); - -static int URI_FUNC(ParseUriExMm)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory); + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory); +static void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state, const URI_CHAR * errorPos, + UriMemoryManager * memory); +static void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state, + UriMemoryManager * memory); +static int URI_FUNC(ParseUriExMm)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory); static URI_INLINE void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state, - const URI_CHAR * errorPos, UriMemoryManager * memory) { - URI_FUNC(FreeUriMembersMm)(state->uri, memory); - state->errorPos = errorPos; - state->errorCode = URI_ERROR_SYNTAX; + const URI_CHAR * errorPos, + UriMemoryManager * memory) { + URI_FUNC(FreeUriMembersMm)(state->uri, memory); + state->errorPos = errorPos; + state->errorCode = URI_ERROR_SYNTAX; } - - -static URI_INLINE void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state, UriMemoryManager * memory) { - URI_FUNC(FreeUriMembersMm)(state->uri, memory); - state->errorPos = NULL; - state->errorCode = URI_ERROR_MALLOC; +static URI_INLINE void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state, + UriMemoryManager * memory) { + URI_FUNC(FreeUriMembersMm)(state->uri, memory); + state->errorPos = NULL; + state->errorCode = URI_ERROR_MALLOC; } - - /* * [authority]-><[>[ipLit2][authorityTwo] * [authority]->[ownHostUserInfoNz] * [authority]-> */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthority)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - /* "" regname host */ - state->uri->hostText.first = URI_FUNC(SafeToPointTo); - state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo); - return afterLast; - } - - switch (*first) { - case _UT('['): - { - const URI_CHAR * const afterIpLit2 - = URI_FUNC(ParseIpLit2)(state, first + 1, afterLast, memory); - if (afterIpLit2 == NULL) { - return NULL; - } - state->uri->hostText.first = first + 1; /* HOST BEGIN */ - return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast); - } - - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(':'): - case _UT(';'): - case _UT('@'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - state->uri->userInfo.first = first; /* USERINFO BEGIN */ - return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast, memory); - - default: - /* "" regname host */ - state->uri->hostText.first = URI_FUNC(SafeToPointTo); - state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo); - return first; - } +static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + /* "" regname host */ + state->uri->hostText.first = URI_FUNC(SafeToPointTo); + state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo); + return afterLast; + } + + switch (*first) { + case _UT('['): { + const URI_CHAR * const afterIpLit2 = + URI_FUNC(ParseIpLit2)(state, first + 1, afterLast, memory); + if (afterIpLit2 == NULL) { + return NULL; + } + state->uri->hostText.first = first + 1; /* HOST BEGIN */ + return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast); + } + + case URI_SET_PCHAR(_UT): + state->uri->userInfo.first = first; /* USERINFO BEGIN */ + return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast, memory); + + default: + /* "" regname host */ + state->uri->hostText.first = URI_FUNC(SafeToPointTo); + state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo); + return first; + } } - - /* * [authorityTwo]-><:>[port] * [authorityTwo]-> */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT(':'): - { - const URI_CHAR * const afterPort = URI_FUNC(ParsePort)(state, first + 1, afterLast); - if (afterPort == NULL) { - return NULL; - } - state->uri->portText.first = first + 1; /* PORT BEGIN */ - state->uri->portText.afterLast = afterPort; /* PORT END */ - return afterPort; - } - - default: - return first; - } +static URI_INLINE const URI_CHAR * +URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case _UT(':'): { + const URI_CHAR * const afterPort = URI_FUNC(ParsePort)(first + 1, afterLast); + if (afterPort == NULL) { + return NULL; + } + state->uri->portText.first = first + 1; /* PORT BEGIN */ + state->uri->portText.afterLast = afterPort; /* PORT END */ + return afterPort; + } + + default: + return first; + } } - - /* * [hexZero]->[HEXDIG][hexZero] * [hexZero]-> */ -static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case URI_SET_HEXDIG: - return URI_FUNC(ParseHexZero)(state, first + 1, afterLast); - - default: - return first; - } +static const URI_CHAR * URI_FUNC(ParseHexZero)(const URI_CHAR * first, + const URI_CHAR * afterLast) { +tail_call: + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_HEXDIG(_UT): + first += 1; + goto tail_call; + + default: + return first; + } } - - /* * [hierPart]->[pathRootless] * [hierPart]->[partHelperTwo] * [hierPart]-> */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseHierPart)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(':'): - case _UT(';'): - case _UT('@'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - return URI_FUNC(ParsePathRootless)(state, first, afterLast, memory); - - case _UT('/'): - return URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast, memory); - - default: - return first; - } +static URI_INLINE const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_PCHAR(_UT): + return URI_FUNC(ParsePathRootless)(state, first, afterLast, memory); + + case _UT('/'): + return URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast, memory); + + default: + return first; + } } - - /* * [ipFutLoop]->[subDelims][ipFutStopGo] * [ipFutLoop]->[unreserved][ipFutStopGo] * [ipFutLoop]-><:>[ipFutStopGo] - */ -static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(':'): - case _UT(';'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - return URI_FUNC(ParseIpFutStopGo)(state, first + 1, afterLast, memory); - - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } -} - - - -/* + * * [ipFutStopGo]->[ipFutLoop] * [ipFutStopGo]-> */ -static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)( - URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(':'): - case _UT(';'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - return URI_FUNC(ParseIpFutLoop)(state, first, afterLast, memory); - - default: - return first; - } +static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + const URI_CHAR * const originalFirst = first; + + while (first < afterLast) { + switch (*first) { + case _UT(':'): + case URI_SET_SUB_DELIMS(_UT): + case URI_SET_UNRESERVED(_UT): + first += 1; + break; + + default: + goto done_looping; + break; + } + } + +done_looping: + if (first == originalFirst) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + + return first; } - - /* * [ipFuture]->[HEXDIG][hexZero]<.>[ipFutLoop] */ static const URI_CHAR * URI_FUNC(ParseIpFuture)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - /* - First character has already been - checked before entering this rule. - - switch (*first) { - case _UT('v'): - case _UT('V'): - */ - if (afterLast - first < 2) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (first[1]) { - case URI_SET_HEXDIG: - { - const URI_CHAR * afterIpFutLoop; - const URI_CHAR * const afterHexZero - = URI_FUNC(ParseHexZero)(state, first + 2, afterLast); - if (afterHexZero == NULL) { - return NULL; - } - if (afterHexZero >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - if (*afterHexZero != _UT('.')) { - URI_FUNC(StopSyntax)(state, afterHexZero, memory); - return NULL; - } - state->uri->hostText.first = first; /* HOST BEGIN */ - state->uri->hostData.ipFuture.first = first; /* IPFUTURE BEGIN */ - afterIpFutLoop = URI_FUNC(ParseIpFutLoop)(state, afterHexZero + 1, afterLast, memory); - if (afterIpFutLoop == NULL) { - return NULL; - } - state->uri->hostText.afterLast = afterIpFutLoop; /* HOST END */ - state->uri->hostData.ipFuture.afterLast = afterIpFutLoop; /* IPFUTURE END */ - return afterIpFutLoop; - } - - default: - URI_FUNC(StopSyntax)(state, first + 1, memory); - return NULL; - } - - /* - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - */ + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + /* + First character has already been + checked before entering this rule. + + switch (*first) { + case _UT('v'): + case _UT('V'): + */ + if (afterLast - first < 2) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + switch (first[1]) { + case URI_SET_HEXDIG(_UT): { + const URI_CHAR * afterIpFutLoop; + const URI_CHAR * const afterHexZero = + URI_FUNC(ParseHexZero)(first + 2, afterLast); + if (afterHexZero == NULL) { + return NULL; + } + if (afterHexZero >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + if (*afterHexZero != _UT('.')) { + URI_FUNC(StopSyntax)(state, afterHexZero, memory); + return NULL; + } + state->uri->hostText.first = first; /* HOST BEGIN */ + state->uri->hostData.ipFuture.first = first; /* IPFUTURE BEGIN */ + afterIpFutLoop = + URI_FUNC(ParseIpFutLoop)(state, afterHexZero + 1, afterLast, memory); + if (afterIpFutLoop == NULL) { + return NULL; + } + state->uri->hostText.afterLast = afterIpFutLoop; /* HOST END */ + state->uri->hostData.ipFuture.afterLast = afterIpFutLoop; /* IPFUTURE END */ + return afterIpFutLoop; + } + + default: + URI_FUNC(StopSyntax)(state, first + 1, memory); + return NULL; + } + + /* + default: + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + */ } - - /* * [ipLit2]->[ipFuture]<]> * [ipLit2]->[IPv6address2] */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseIpLit2)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (*first) { - /* The leading "v" of IPvFuture is case-insensitive. */ - case _UT('v'): - case _UT('V'): - { - const URI_CHAR * const afterIpFuture - = URI_FUNC(ParseIpFuture)(state, first, afterLast, memory); - if (afterIpFuture == NULL) { - return NULL; - } - if (afterIpFuture >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - if (*afterIpFuture != _UT(']')) { - URI_FUNC(StopSyntax)(state, afterIpFuture, memory); - return NULL; - } - return afterIpFuture + 1; - } - - case _UT(':'): - case _UT(']'): - case URI_SET_HEXDIG: - state->uri->hostData.ip6 = memory->malloc(memory, 1 * sizeof(UriIp6)); /* Freed when stopping on parse error */ - if (state->uri->hostData.ip6 == NULL) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return URI_FUNC(ParseIPv6address2)(state, first, afterLast, memory); - - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } +static URI_INLINE const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + switch (*first) { + /* The leading "v" of IPvFuture is case-insensitive. */ + case _UT('v'): + case _UT('V'): { + const URI_CHAR * const afterIpFuture = + URI_FUNC(ParseIpFuture)(state, first, afterLast, memory); + if (afterIpFuture == NULL) { + return NULL; + } + if (afterIpFuture >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + if (*afterIpFuture != _UT(']')) { + URI_FUNC(StopSyntax)(state, afterIpFuture, memory); + return NULL; + } + return afterIpFuture + 1; + } + + case _UT(':'): + case _UT(']'): + case URI_SET_HEXDIG(_UT): + state->uri->hostData.ip6 = memory->malloc( + memory, 1 * sizeof(UriIp6)); /* Freed when stopping on parse error */ + if (state->uri->hostData.ip6 == NULL) { + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + return URI_FUNC(ParseIPv6address2)(state, first, afterLast, memory); + + default: + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } } - - /* * [IPv6address2]->..<]> */ -static const URI_CHAR * URI_FUNC(ParseIPv6address2)( - URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - int zipperEver = 0; - int quadsDone = 0; - int digitCount = 0; - unsigned char digitHistory[4]; - int ip4OctetsDone = 0; - - unsigned char quadsAfterZipper[14]; - int quadsAfterZipperCount = 0; - - - for (;;) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - /* Inside IPv4 part? */ - if (ip4OctetsDone > 0) { - /* Eat rest of IPv4 address */ - for (;;) { - switch (*first) { - case URI_SET_DIGIT: - if (digitCount == 4) { - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - digitHistory[digitCount++] = (unsigned char)(9 + *first - _UT('9')); - break; - - case _UT('.'): - if ((ip4OctetsDone == 4) /* NOTE! */ - || (digitCount == 0) - || (digitCount == 4)) { - /* Invalid digit or octet count */ - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } else if ((digitCount > 1) - && (digitHistory[0] == 0)) { - /* Leading zero */ - URI_FUNC(StopSyntax)(state, first - digitCount, memory); - return NULL; - } else if ((digitCount == 3) - && (100 * digitHistory[0] - + 10 * digitHistory[1] - + digitHistory[2] > 255)) { - /* Octet value too large */ - if (digitHistory[0] > 2) { - URI_FUNC(StopSyntax)(state, first - 3, memory); - } else if (digitHistory[1] > 5) { - URI_FUNC(StopSyntax)(state, first - 2, memory); - } else { - URI_FUNC(StopSyntax)(state, first - 1, memory); - } - return NULL; - } - - /* Copy IPv4 octet */ - state->uri->hostData.ip6->data[16 - 4 + ip4OctetsDone] = uriGetOctetValue(digitHistory, digitCount); - digitCount = 0; - ip4OctetsDone++; - break; - - case _UT(']'): - if ((ip4OctetsDone != 3) /* NOTE! */ - || (digitCount == 0) - || (digitCount == 4)) { - /* Invalid digit or octet count */ - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } else if ((digitCount > 1) - && (digitHistory[0] == 0)) { - /* Leading zero */ - URI_FUNC(StopSyntax)(state, first - digitCount, memory); - return NULL; - } else if ((digitCount == 3) - && (100 * digitHistory[0] - + 10 * digitHistory[1] - + digitHistory[2] > 255)) { - /* Octet value too large */ - if (digitHistory[0] > 2) { - URI_FUNC(StopSyntax)(state, first - 3, memory); - } else if (digitHistory[1] > 5) { - URI_FUNC(StopSyntax)(state, first - 2, memory); - } else { - URI_FUNC(StopSyntax)(state, first - 1, memory); - } - return NULL; - } - - state->uri->hostText.afterLast = first; /* HOST END */ - - /* Copy missing quads right before IPv4 */ - memcpy(state->uri->hostData.ip6->data + 16 - 4 - 2 * quadsAfterZipperCount, - quadsAfterZipper, 2 * quadsAfterZipperCount); - - /* Copy last IPv4 octet */ - state->uri->hostData.ip6->data[16 - 4 + 3] = uriGetOctetValue(digitHistory, digitCount); - - return first + 1; - - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - first++; - - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - } - } else { - /* Eat while no dot in sight */ - int letterAmong = 0; - int walking = 1; - do { - switch (*first) { - case URI_SET_HEX_LETTER_LOWER: - letterAmong = 1; - if (digitCount == 4) { - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('f')); - digitCount++; - break; - - case URI_SET_HEX_LETTER_UPPER: - letterAmong = 1; - if (digitCount == 4) { - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('F')); - digitCount++; - break; - - case URI_SET_DIGIT: - if (digitCount == 4) { - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - digitHistory[digitCount] = (unsigned char)(9 + *first - _UT('9')); - digitCount++; - break; - - case _UT(':'): - { - int setZipper = 0; - - if (digitCount > 0) { - if (zipperEver) { - uriWriteQuadToDoubleByte(digitHistory, digitCount, quadsAfterZipper + 2 * quadsAfterZipperCount); - quadsAfterZipperCount++; - } else { - uriWriteQuadToDoubleByte(digitHistory, digitCount, state->uri->hostData.ip6->data + 2 * quadsDone); - } - quadsDone++; - digitCount = 0; - } - letterAmong = 0; - - /* Too many quads? */ - if (quadsDone >= 8 - zipperEver) { - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - - /* "::"? */ - if (afterLast - first < 2) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - if (first[1] == _UT(':')) { - const int resetOffset = 2 * (quadsDone + (digitCount > 0)); - - first++; - if (zipperEver) { - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; /* "::.+::" */ - } - - /* Zero everything after zipper */ - memset(state->uri->hostData.ip6->data + resetOffset, 0, 16 - resetOffset); - setZipper = 1; - - /* ":::+"? */ - if (afterLast - first < 2) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; /* No ']' yet */ - } - if (first[1] == _UT(':')) { - URI_FUNC(StopSyntax)(state, first + 1, memory); - return NULL; /* ":::+ "*/ - } - } else if (quadsDone == 0 || first[1] == _UT(']')) { - /* Single leading or trailing ":" */ - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - - if (setZipper) { - zipperEver = 1; - } - } - break; - - case _UT('.'): - if ((quadsDone + zipperEver > 6) /* NOTE */ - || (!zipperEver && (quadsDone < 6)) - || letterAmong - || (digitCount == 0) - || (digitCount == 4)) { - /* Invalid octet before */ - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } else if ((digitCount > 1) - && (digitHistory[0] == 0)) { - /* Leading zero */ - URI_FUNC(StopSyntax)(state, first - digitCount, memory); - return NULL; - } else if ((digitCount == 3) - && (100 * digitHistory[0] - + 10 * digitHistory[1] - + digitHistory[2] > 255)) { - /* Octet value too large */ - if (digitHistory[0] > 2) { - URI_FUNC(StopSyntax)(state, first - 3, memory); - } else if (digitHistory[1] > 5) { - URI_FUNC(StopSyntax)(state, first - 2, memory); - } else { - URI_FUNC(StopSyntax)(state, first - 1, memory); - } - return NULL; - } - - /* Copy first IPv4 octet */ - state->uri->hostData.ip6->data[16 - 4] = uriGetOctetValue(digitHistory, digitCount); - digitCount = 0; - - /* Switch over to IPv4 loop */ - ip4OctetsDone = 1; - walking = 0; - break; - - case _UT(']'): - /* Too little quads? */ - if (!zipperEver && !((quadsDone == 7) && (digitCount > 0))) { - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - - if (digitCount > 0) { - if (zipperEver) { - /* Too many quads? */ - if (quadsDone >= 7) { - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - uriWriteQuadToDoubleByte(digitHistory, digitCount, quadsAfterZipper + 2 * quadsAfterZipperCount); - quadsAfterZipperCount++; - } else { - uriWriteQuadToDoubleByte(digitHistory, digitCount, state->uri->hostData.ip6->data + 2 * quadsDone); - } - /* - quadsDone++; - digitCount = 0; - */ - } - - /* Copy missing quads to the end */ - memcpy(state->uri->hostData.ip6->data + 16 - 2 * quadsAfterZipperCount, - quadsAfterZipper, 2 * quadsAfterZipperCount); - - state->uri->hostText.afterLast = first; /* HOST END */ - return first + 1; /* Fine */ - - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - first++; - - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; /* No ']' yet */ - } - } while (walking); - } - } +static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + int zipperEver = 0; + int quadsDone = 0; + int digitCount = 0; + unsigned char digitHistory[4]; + int ip4OctetsDone = 0; + + unsigned char quadsAfterZipper[14]; + int quadsAfterZipperCount = 0; + + for (;;) { + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + /* Inside IPv4 part? */ + if (ip4OctetsDone > 0) { + /* Eat rest of IPv4 address */ + for (;;) { + switch (*first) { + case URI_SET_DIGIT(_UT): + if (digitCount == 4) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + digitHistory[digitCount++] = (unsigned char)(9 + *first - _UT('9')); + break; + + case _UT('.'): + if ((ip4OctetsDone == 4) /* NOTE! */ + || (digitCount == 0) || (digitCount == 4)) { + /* Invalid digit or octet count */ + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } else if ((digitCount > 1) && (digitHistory[0] == 0)) { + /* Leading zero */ + URI_FUNC(StopSyntax)(state, first - digitCount, memory); + return NULL; + } else if ((digitCount == 3) + && (100 * digitHistory[0] + 10 * digitHistory[1] + + digitHistory[2] + > 255)) { + /* Octet value too large */ + if (digitHistory[0] > 2) { + URI_FUNC(StopSyntax)(state, first - 3, memory); + } else if (digitHistory[1] > 5) { + URI_FUNC(StopSyntax)(state, first - 2, memory); + } else { + URI_FUNC(StopSyntax)(state, first - 1, memory); + } + return NULL; + } + + /* Copy IPv4 octet */ + state->uri->hostData.ip6->data[16 - 4 + ip4OctetsDone] = + uriGetOctetValue(digitHistory, digitCount); + digitCount = 0; + ip4OctetsDone++; + break; + + case _UT(']'): + if ((ip4OctetsDone != 3) /* NOTE! */ + || (digitCount == 0) || (digitCount == 4)) { + /* Invalid digit or octet count */ + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } else if ((digitCount > 1) && (digitHistory[0] == 0)) { + /* Leading zero */ + URI_FUNC(StopSyntax)(state, first - digitCount, memory); + return NULL; + } else if ((digitCount == 3) + && (100 * digitHistory[0] + 10 * digitHistory[1] + + digitHistory[2] + > 255)) { + /* Octet value too large */ + if (digitHistory[0] > 2) { + URI_FUNC(StopSyntax)(state, first - 3, memory); + } else if (digitHistory[1] > 5) { + URI_FUNC(StopSyntax)(state, first - 2, memory); + } else { + URI_FUNC(StopSyntax)(state, first - 1, memory); + } + return NULL; + } + + state->uri->hostText.afterLast = first; /* HOST END */ + + /* Copy missing quads right before IPv4 */ + memcpy(state->uri->hostData.ip6->data + 16 - 4 + - 2 * quadsAfterZipperCount, + quadsAfterZipper, 2 * quadsAfterZipperCount); + + /* Copy last IPv4 octet */ + state->uri->hostData.ip6->data[16 - 4 + 3] = + uriGetOctetValue(digitHistory, digitCount); + + return first + 1; + + default: + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + first++; + + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + } + } else { + /* Eat while no dot in sight */ + int letterAmong = 0; + int walking = 1; + do { + switch (*first) { + case URI_SET_HEX_LETTER_LOWER(_UT): + letterAmong = 1; + if (digitCount == 4) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('f')); + digitCount++; + break; + + case URI_SET_HEX_LETTER_UPPER(_UT): + letterAmong = 1; + if (digitCount == 4) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('F')); + digitCount++; + break; + + case URI_SET_DIGIT(_UT): + if (digitCount == 4) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + digitHistory[digitCount] = (unsigned char)(9 + *first - _UT('9')); + digitCount++; + break; + + case _UT(':'): { + int setZipper = 0; + + if (digitCount > 0) { + if (zipperEver) { + uriWriteQuadToDoubleByte(digitHistory, digitCount, + quadsAfterZipper + + 2 * quadsAfterZipperCount); + quadsAfterZipperCount++; + } else { + uriWriteQuadToDoubleByte(digitHistory, digitCount, + state->uri->hostData.ip6->data + + 2 * quadsDone); + } + quadsDone++; + digitCount = 0; + } + letterAmong = 0; + + /* Too many quads? */ + if (quadsDone >= 8 - zipperEver) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + + /* "::"? */ + if (afterLast - first < 2) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + if (first[1] == _UT(':')) { + const int resetOffset = 2 * (quadsDone + (digitCount > 0)); + + first++; + if (zipperEver) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; /* "::.+::" */ + } + + /* Zero everything after zipper */ + memset(state->uri->hostData.ip6->data + resetOffset, 0, + 16 - resetOffset); + setZipper = 1; + + /* ":::+"? */ + if (afterLast - first < 2) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; /* No ']' yet */ + } + if (first[1] == _UT(':')) { + URI_FUNC(StopSyntax)(state, first + 1, memory); + return NULL; /* ":::+ "*/ + } + } else if (quadsDone == 0 || first[1] == _UT(']')) { + /* Single leading or trailing ":" */ + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + + if (setZipper) { + zipperEver = 1; + } + } break; + + case _UT('.'): + if ((quadsDone + zipperEver > 6) /* NOTE */ + || (!zipperEver && (quadsDone < 6)) || letterAmong + || (digitCount == 0) || (digitCount == 4)) { + /* Invalid octet before */ + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } else if ((digitCount > 1) && (digitHistory[0] == 0)) { + /* Leading zero */ + URI_FUNC(StopSyntax)(state, first - digitCount, memory); + return NULL; + } else if ((digitCount == 3) + && (100 * digitHistory[0] + 10 * digitHistory[1] + + digitHistory[2] + > 255)) { + /* Octet value too large */ + if (digitHistory[0] > 2) { + URI_FUNC(StopSyntax)(state, first - 3, memory); + } else if (digitHistory[1] > 5) { + URI_FUNC(StopSyntax)(state, first - 2, memory); + } else { + URI_FUNC(StopSyntax)(state, first - 1, memory); + } + return NULL; + } + + /* Copy first IPv4 octet */ + state->uri->hostData.ip6->data[16 - 4] = + uriGetOctetValue(digitHistory, digitCount); + digitCount = 0; + + /* Switch over to IPv4 loop */ + ip4OctetsDone = 1; + walking = 0; + break; + + case _UT(']'): + /* Too little quads? */ + if (!zipperEver && !((quadsDone == 7) && (digitCount > 0))) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + + if (digitCount > 0) { + if (zipperEver) { + /* Too many quads? */ + if (quadsDone >= 7) { + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + uriWriteQuadToDoubleByte(digitHistory, digitCount, + quadsAfterZipper + + 2 * quadsAfterZipperCount); + quadsAfterZipperCount++; + } else { + uriWriteQuadToDoubleByte(digitHistory, digitCount, + state->uri->hostData.ip6->data + + 2 * quadsDone); + } + /* + quadsDone++; + digitCount = 0; + */ + } + + /* Copy missing quads to the end */ + memcpy(state->uri->hostData.ip6->data + 16 + - 2 * quadsAfterZipperCount, + quadsAfterZipper, 2 * quadsAfterZipperCount); + + state->uri->hostText.afterLast = first; /* HOST END */ + return first + 1; /* Fine */ + + default: + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + first++; + + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; /* No ']' yet */ + } + } while (walking); + } + } } - - /* * [mustBeSegmentNzNc]->[pctEncoded][mustBeSegmentNzNc] * [mustBeSegmentNzNc]->[subDelims][mustBeSegmentNzNc] @@ -888,346 +806,277 @@ static const URI_CHAR * URI_FUNC(ParseIPv6address2)( * [mustBeSegmentNzNc]->[segment][zeroMoreSlashSegs][uriTail] * [mustBeSegmentNzNc]-><@>[mustBeSegmentNzNc] */ -static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - state->uri->scheme.first = NULL; /* Not a scheme, reset */ - return afterLast; - } - - switch (*first) { - case _UT('%'): - { - const URI_CHAR * const afterPctEncoded - = URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); - if (afterPctEncoded == NULL) { - return NULL; - } - return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast, memory); - } - - case _UT('@'): - case _UT('!'): - case _UT('$'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('*'): - case _UT(','): - case _UT(';'): - case _UT('\''): - case _UT('+'): - case _UT('='): - case _UT('-'): - case _UT('.'): - case _UT('_'): - case _UT('~'): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory); - - case _UT('/'): - { - const URI_CHAR * afterZeroMoreSlashSegs; - const URI_CHAR * afterSegment; - if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - state->uri->scheme.first = NULL; /* Not a scheme, reset */ - afterSegment = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory); - if (afterSegment == NULL) { - return NULL; - } - if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - afterZeroMoreSlashSegs - = URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory); - if (afterZeroMoreSlashSegs == NULL) { - return NULL; - } - return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast, memory); - } - - default: - if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - state->uri->scheme.first = NULL; /* Not a scheme, reset */ - return URI_FUNC(ParseUriTail)(state, first, afterLast, memory); - } +static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + state->uri->scheme.first = NULL; /* Not a scheme, reset */ + return afterLast; + } + + switch (*first) { + case _UT('%'): { + const URI_CHAR * const afterPctEncoded = + URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); + if (afterPctEncoded == NULL) { + return NULL; + } + first = afterPctEncoded; + goto tail_call; + } + + case _UT('@'): + case URI_SET_SUB_DELIMS(_UT): + case URI_SET_UNRESERVED(_UT): + first += 1; + goto tail_call; + + case _UT('/'): { + const URI_CHAR * afterZeroMoreSlashSegs; + const URI_CHAR * afterSegment; + if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + state->uri->scheme.first = NULL; /* Not a scheme, reset */ + afterSegment = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory); + if (afterSegment == NULL) { + return NULL; + } + if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + afterZeroMoreSlashSegs = + URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory); + if (afterZeroMoreSlashSegs == NULL) { + return NULL; + } + return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast, memory); + } + + default: + if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + state->uri->scheme.first = NULL; /* Not a scheme, reset */ + return URI_FUNC(ParseUriTail)(state, first, afterLast, memory); + } } - - /* * [ownHost]-><[>[ipLit2][authorityTwo] * [ownHost]->[ownHost2] // can take */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHost)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - state->uri->hostText.afterLast = afterLast; /* HOST END */ - return afterLast; - } - - switch (*first) { - case _UT('['): - { - const URI_CHAR * const afterIpLit2 - = URI_FUNC(ParseIpLit2)(state, first + 1, afterLast, memory); - if (afterIpLit2 == NULL) { - return NULL; - } - state->uri->hostText.first = first + 1; /* HOST BEGIN */ - return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast); - } - - default: - return URI_FUNC(ParseOwnHost2)(state, first, afterLast, memory); - } +static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + state->uri->hostText.afterLast = afterLast; /* HOST END */ + return afterLast; + } + + switch (*first) { + case _UT('['): { + const URI_CHAR * const afterIpLit2 = + URI_FUNC(ParseIpLit2)(state, first + 1, afterLast, memory); + if (afterIpLit2 == NULL) { + return NULL; + } + state->uri->hostText.first = first + 1; /* HOST BEGIN */ + return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast); + } + + default: + return URI_FUNC(ParseOwnHost2)(state, first, afterLast, memory); + } } - - -static URI_INLINE UriBool URI_FUNC(OnExitOwnHost2)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - UriMemoryManager * memory) { - state->uri->hostText.afterLast = first; /* HOST END */ - - /* Valid IPv4 or just a regname? */ - state->uri->hostData.ip4 = memory->malloc(memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ - if (state->uri->hostData.ip4 == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, - state->uri->hostText.first, state->uri->hostText.afterLast)) { - /* Not IPv4 */ - memory->free(memory, state->uri->hostData.ip4); - state->uri->hostData.ip4 = NULL; - } - return URI_TRUE; /* Success */ +static URI_INLINE UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + UriMemoryManager * memory) { + state->uri->hostText.afterLast = first; /* HOST END */ + + /* Valid IPv4 or just a regname? */ + state->uri->hostData.ip4 = memory->malloc( + memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ + if (state->uri->hostData.ip4 == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, + state->uri->hostText.first, + state->uri->hostText.afterLast)) { + /* Not IPv4 */ + memory->free(memory, state->uri->hostData.ip4); + state->uri->hostData.ip4 = NULL; + } + return URI_TRUE; /* Success */ } - - /* * [ownHost2]->[authorityTwo] // can take * [ownHost2]->[pctSubUnres][ownHost2] */ -static const URI_CHAR * URI_FUNC(ParseOwnHost2)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - if (!URI_FUNC(OnExitOwnHost2)(state, first, memory)) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return afterLast; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(';'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - { - const URI_CHAR * const afterPctSubUnres - = URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory); - if (afterPctSubUnres == NULL) { - return NULL; - } - return URI_FUNC(ParseOwnHost2)(state, afterPctSubUnres, afterLast, memory); - } - - default: - if (!URI_FUNC(OnExitOwnHost2)(state, first, memory)) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return URI_FUNC(ParseAuthorityTwo)(state, first, afterLast); - } +static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + if (!URI_FUNC(OnExitOwnHost2)(state, first, memory)) { + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + return afterLast; + } + + switch (*first) { + case _UT('%'): + case URI_SET_SUB_DELIMS(_UT): + case URI_SET_UNRESERVED(_UT): { + const URI_CHAR * const afterPctSubUnres = + URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory); + if (afterPctSubUnres == NULL) { + return NULL; + } + first = afterPctSubUnres; + goto tail_call; + } + + default: + if (!URI_FUNC(OnExitOwnHost2)(state, first, memory)) { + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + return URI_FUNC(ParseAuthorityTwo)(state, first, afterLast); + } } - - -static URI_INLINE UriBool URI_FUNC(OnExitOwnHostUserInfo)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - UriMemoryManager * memory) { - state->uri->hostText.first = state->uri->userInfo.first; /* Host instead of userInfo, update */ - state->uri->userInfo.first = NULL; /* Not a userInfo, reset */ - state->uri->hostText.afterLast = first; /* HOST END */ - - /* Valid IPv4 or just a regname? */ - state->uri->hostData.ip4 = memory->malloc(memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ - if (state->uri->hostData.ip4 == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, - state->uri->hostText.first, state->uri->hostText.afterLast)) { - /* Not IPv4 */ - memory->free(memory, state->uri->hostData.ip4); - state->uri->hostData.ip4 = NULL; - } - return URI_TRUE; /* Success */ +static URI_INLINE UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + UriMemoryManager * memory) { + state->uri->hostText.first = + state->uri->userInfo.first; /* Host instead of userInfo, update */ + state->uri->userInfo.first = NULL; /* Not a userInfo, reset */ + state->uri->hostText.afterLast = first; /* HOST END */ + + /* Valid IPv4 or just a regname? */ + state->uri->hostData.ip4 = memory->malloc( + memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ + if (state->uri->hostData.ip4 == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, + state->uri->hostText.first, + state->uri->hostText.afterLast)) { + /* Not IPv4 */ + memory->free(memory, state->uri->hostData.ip4); + state->uri->hostData.ip4 = NULL; + } + return URI_TRUE; /* Success */ } - - -/* - * [ownHostUserInfo]->[ownHostUserInfoNz] - * [ownHostUserInfo]-> - */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first, memory)) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return afterLast; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(':'): - case _UT(';'): - case _UT('@'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast, memory); - - default: - if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first, memory)) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return first; - } -} - - - /* * [ownHostUserInfoNz]->[pctSubUnres][ownHostUserInfo] * [ownHostUserInfoNz]-><:>[ownPortUserInfo] * [ownHostUserInfoNz]-><@>[ownHost] + * + * [ownHostUserInfo]->[ownHostUserInfoNz] + * [ownHostUserInfo]-> */ -static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(';'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - { - const URI_CHAR * const afterPctSubUnres - = URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory); - if (afterPctSubUnres == NULL) { - return NULL; - } - return URI_FUNC(ParseOwnHostUserInfo)(state, afterPctSubUnres, afterLast, memory); - } - - case _UT(':'): - state->uri->hostText.afterLast = first; /* HOST END */ - state->uri->portText.first = first + 1; /* PORT BEGIN */ - return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast, memory); - - case _UT('@'): - state->uri->userInfo.afterLast = first; /* USERINFO END */ - state->uri->hostText.first = first + 1; /* HOST BEGIN */ - return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory); - - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } +static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + const URI_CHAR * const originalFirst = first; + + while (first < afterLast) { + switch (*first) { + case _UT('%'): + case URI_SET_SUB_DELIMS(_UT): + case URI_SET_UNRESERVED(_UT): { + const URI_CHAR * const afterPctSubUnres = + URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory); + if (afterPctSubUnres == NULL) { + return NULL; + } + first = afterPctSubUnres; + break; + } + + default: + goto done_looping; + break; + } + } + +done_looping: + if (first < afterLast) { + switch (*first) { + case _UT(':'): + state->uri->hostText.afterLast = first; /* HOST END */ + state->uri->portText.first = first + 1; /* PORT BEGIN */ + return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast, memory); + + case _UT('@'): + state->uri->userInfo.afterLast = first; /* USERINFO END */ + state->uri->hostText.first = first + 1; /* HOST BEGIN */ + return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory); + + default: + break; + } + } + + if (first == originalFirst) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first, memory)) { + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + + return first; } - - -static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - UriMemoryManager * memory) { - state->uri->hostText.first = state->uri->userInfo.first; /* Host instead of userInfo, update */ - state->uri->userInfo.first = NULL; /* Not a userInfo, reset */ - state->uri->portText.afterLast = first; /* PORT END */ - - /* Valid IPv4 or just a regname? */ - state->uri->hostData.ip4 = memory->malloc(memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ - if (state->uri->hostData.ip4 == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, - state->uri->hostText.first, state->uri->hostText.afterLast)) { - /* Not IPv4 */ - memory->free(memory, state->uri->hostData.ip4); - state->uri->hostData.ip4 = NULL; - } - return URI_TRUE; /* Success */ +static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + UriMemoryManager * memory) { + state->uri->hostText.first = + state->uri->userInfo.first; /* Host instead of userInfo, update */ + state->uri->userInfo.first = NULL; /* Not a userInfo, reset */ + state->uri->portText.afterLast = first; /* PORT END */ + + /* Valid IPv4 or just a regname? */ + state->uri->hostData.ip4 = memory->malloc( + memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */ + if (state->uri->hostData.ip4 == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data, + state->uri->hostText.first, + state->uri->hostText.afterLast)) { + /* Not IPv4 */ + memory->free(memory, state->uri->hostData.ip4); + state->uri->hostData.ip4 = NULL; + } + return URI_TRUE; /* Success */ } - - /* * [ownPortUserInfo]->[ALPHA][ownUserInfo] * [ownPortUserInfo]->[DIGIT][ownPortUserInfo] @@ -1241,281 +1090,229 @@ static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)( * [ownPortUserInfo]-><@>[ownHost] * [ownPortUserInfo]-> */ -static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first, memory)) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return afterLast; - } - - switch (*first) { - /* begin sub-delims */ - case _UT('!'): - case _UT('$'): - case _UT('&'): - case _UT('\''): - case _UT('('): - case _UT(')'): - case _UT('*'): - case _UT('+'): - case _UT(','): - case _UT(';'): - case _UT('='): - /* end sub-delims */ - /* begin unreserved (except alpha and digit) */ - case _UT('-'): - case _UT('.'): - case _UT('_'): - case _UT('~'): - /* end unreserved (except alpha and digit) */ - case _UT(':'): - case URI_SET_ALPHA: - state->uri->hostText.afterLast = NULL; /* Not a host, reset */ - state->uri->portText.first = NULL; /* Not a port, reset */ - return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast, memory); - - case URI_SET_DIGIT: - return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast, memory); - - case _UT('%'): - state->uri->portText.first = NULL; /* Not a port, reset */ - { - const URI_CHAR * const afterPct - = URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); - if (afterPct == NULL) { - return NULL; - } - return URI_FUNC(ParseOwnUserInfo)(state, afterPct, afterLast, memory); - } - - case _UT('@'): - state->uri->hostText.afterLast = NULL; /* Not a host, reset */ - state->uri->portText.first = NULL; /* Not a port, reset */ - state->uri->userInfo.afterLast = first; /* USERINFO END */ - state->uri->hostText.first = first + 1; /* HOST BEGIN */ - return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory); - - default: - if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first, memory)) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return first; - } +static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first, memory)) { + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + return afterLast; + } + + switch (*first) { + case URI_SET_SUB_DELIMS(_UT): + /* begin unreserved (except alpha and digit) */ + case _UT('-'): + case _UT('.'): + case _UT('_'): + case _UT('~'): + /* end unreserved (except alpha and digit) */ + case _UT(':'): + case URI_SET_ALPHA(_UT): + state->uri->hostText.afterLast = NULL; /* Not a host, reset */ + state->uri->portText.first = NULL; /* Not a port, reset */ + return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast, memory); + + case URI_SET_DIGIT(_UT): + first += 1; + goto tail_call; + + case _UT('%'): + state->uri->portText.first = NULL; /* Not a port, reset */ + const URI_CHAR * const afterPct = + URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); + if (afterPct == NULL) { + return NULL; + } + return URI_FUNC(ParseOwnUserInfo)(state, afterPct, afterLast, memory); + + case _UT('@'): + state->uri->hostText.afterLast = NULL; /* Not a host, reset */ + state->uri->portText.first = NULL; /* Not a port, reset */ + state->uri->userInfo.afterLast = first; /* USERINFO END */ + state->uri->hostText.first = first + 1; /* HOST BEGIN */ + return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory); + + default: + if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first, memory)) { + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + return first; + } } - - /* * [ownUserInfo]->[pctSubUnres][ownUserInfo] * [ownUserInfo]-><:>[ownUserInfo] * [ownUserInfo]-><@>[ownHost] */ -static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(';'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - { - const URI_CHAR * const afterPctSubUnres - = URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory); - if (afterPctSubUnres == NULL) { - return NULL; - } - return URI_FUNC(ParseOwnUserInfo)(state, afterPctSubUnres, afterLast, memory); - } - - case _UT(':'): - return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast, memory); - - case _UT('@'): - /* SURE */ - state->uri->userInfo.afterLast = first; /* USERINFO END */ - state->uri->hostText.first = first + 1; /* HOST BEGIN */ - return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory); - - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } +static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + switch (*first) { + case _UT('%'): + case URI_SET_SUB_DELIMS(_UT): + case URI_SET_UNRESERVED(_UT): { + const URI_CHAR * const afterPctSubUnres = + URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory); + if (afterPctSubUnres == NULL) { + return NULL; + } + first = afterPctSubUnres; + goto tail_call; + } + + case _UT(':'): + first += 1; + goto tail_call; + + case _UT('@'): + /* SURE */ + state->uri->userInfo.afterLast = first; /* USERINFO END */ + state->uri->hostText.first = first + 1; /* HOST BEGIN */ + return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory); + + default: + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } } - - static URI_INLINE void URI_FUNC(OnExitPartHelperTwo)(URI_TYPE(ParserState) * state) { - state->uri->absolutePath = URI_TRUE; + state->uri->absolutePath = URI_TRUE; } - - /* * [partHelperTwo]->[pathAbsNoLeadSlash] // can take * [partHelperTwo]->[authority][pathAbsEmpty] */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParsePartHelperTwo)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(OnExitPartHelperTwo)(state); - return afterLast; - } - - switch (*first) { - case _UT('/'): - { - const URI_CHAR * const afterAuthority - = URI_FUNC(ParseAuthority)(state, first + 1, afterLast, memory); - const URI_CHAR * afterPathAbsEmpty; - if (afterAuthority == NULL) { - return NULL; - } - afterPathAbsEmpty = URI_FUNC(ParsePathAbsEmpty)(state, afterAuthority, afterLast, memory); - - URI_FUNC(FixEmptyTrailSegment)(state->uri, memory); - - return afterPathAbsEmpty; - } - - default: - URI_FUNC(OnExitPartHelperTwo)(state); - return URI_FUNC(ParsePathAbsNoLeadSlash)(state, first, afterLast, memory); - } +static URI_INLINE const URI_CHAR * +URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + if (first >= afterLast) { + URI_FUNC(OnExitPartHelperTwo)(state); + return afterLast; + } + + switch (*first) { + case _UT('/'): { + const URI_CHAR * const afterAuthority = + URI_FUNC(ParseAuthority)(state, first + 1, afterLast, memory); + const URI_CHAR * afterPathAbsEmpty; + if (afterAuthority == NULL) { + return NULL; + } + afterPathAbsEmpty = + URI_FUNC(ParsePathAbsEmpty)(state, afterAuthority, afterLast, memory); + + URI_FUNC(FixEmptyTrailSegment)(state->uri, memory); + + return afterPathAbsEmpty; + } + + default: + URI_FUNC(OnExitPartHelperTwo)(state); + return URI_FUNC(ParsePathAbsNoLeadSlash)(state, first, afterLast, memory); + } } - - /* * [pathAbsEmpty]->[segment][pathAbsEmpty] * [pathAbsEmpty]-> */ -static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('/'): - { - const URI_CHAR * const afterSegment - = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory); - if (afterSegment == NULL) { - return NULL; - } - if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return URI_FUNC(ParsePathAbsEmpty)(state, afterSegment, afterLast, memory); - } - - default: - return first; - } +static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case _UT('/'): { + const URI_CHAR * const afterSegment = + URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory); + if (afterSegment == NULL) { + return NULL; + } + if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + first = afterSegment; + goto tail_call; + } + + default: + return first; + } } - - /* * [pathAbsNoLeadSlash]->[segmentNz][zeroMoreSlashSegs] * [pathAbsNoLeadSlash]-> */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(':'): - case _UT(';'): - case _UT('@'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - { - const URI_CHAR * const afterSegmentNz - = URI_FUNC(ParseSegmentNz)(state, first, afterLast, memory); - if (afterSegmentNz == NULL) { - return NULL; - } - if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast, memory); - } - - default: - return first; - } +static URI_INLINE const URI_CHAR * +URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_PCHAR(_UT): { + const URI_CHAR * const afterSegmentNz = + URI_FUNC(ParseSegmentNz)(state, first, afterLast, memory); + if (afterSegmentNz == NULL) { + return NULL; + } + if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast, memory); + } + + default: + return first; + } } - - /* * [pathRootless]->[segmentNz][zeroMoreSlashSegs] */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathRootless)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - const URI_CHAR * const afterSegmentNz - = URI_FUNC(ParseSegmentNz)(state, first, afterLast, memory); - if (afterSegmentNz == NULL) { - return NULL; - } else { - if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - } - return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast, memory); +static URI_INLINE const URI_CHAR * +URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + const URI_CHAR * const afterSegmentNz = + URI_FUNC(ParseSegmentNz)(state, first, afterLast, memory); + if (afterSegmentNz == NULL) { + return NULL; + } else { + if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + } + return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast, memory); } - - /* * [pchar]->[pctEncoded] * [pchar]->[subDelims] @@ -1524,166 +1321,129 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathRootless)( * [pchar]-><@> */ static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (*first) { - case _UT('%'): - return URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); - - case _UT(':'): - case _UT('@'): - case _UT('!'): - case _UT('$'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('*'): - case _UT(','): - case _UT(';'): - case _UT('\''): - case _UT('+'): - case _UT('='): - case _UT('-'): - case _UT('.'): - case _UT('_'): - case _UT('~'): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - return first + 1; - - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + switch (*first) { + case _UT('%'): + return URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); + + case URI_SET_PCHAR_WITHOUT_PERCENT(_UT): + return first + 1; + + default: + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } } - - /* * [pctEncoded]-><%>[HEXDIG][HEXDIG] */ -static const URI_CHAR * URI_FUNC(ParsePctEncoded)( - URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - /* - First character has already been - checked before entering this rule. - - switch (*first) { - case _UT('%'): - */ - if (afterLast - first < 2) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (first[1]) { - case URI_SET_HEXDIG: - if (afterLast - first < 3) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (first[2]) { - case URI_SET_HEXDIG: - return first + 3; - - default: - URI_FUNC(StopSyntax)(state, first + 2, memory); - return NULL; - } - - default: - URI_FUNC(StopSyntax)(state, first + 1, memory); - return NULL; - } - - /* - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } - */ +static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + /* + First character has already been + checked before entering this rule. + + switch (*first) { + case _UT('%'): + */ + if (afterLast - first < 2) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + switch (first[1]) { + case URI_SET_HEXDIG(_UT): + if (afterLast - first < 3) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + switch (first[2]) { + case URI_SET_HEXDIG(_UT): + return first + 3; + + default: + URI_FUNC(StopSyntax)(state, first + 2, memory); + return NULL; + } + + default: + URI_FUNC(StopSyntax)(state, first + 1, memory); + return NULL; + } + + /* + default: + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } + */ } - - /* * [pctSubUnres]->[pctEncoded] * [pctSubUnres]->[subDelims] * [pctSubUnres]->[unreserved] */ -static const URI_CHAR * URI_FUNC(ParsePctSubUnres)( - URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - URI_FUNC(StopSyntax)(state, afterLast, memory); - return NULL; - } - - switch (*first) { - case _UT('%'): - return URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); - - case _UT('!'): - case _UT('$'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('*'): - case _UT(','): - case _UT(';'): - case _UT('\''): - case _UT('+'): - case _UT('='): - case _UT('-'): - case _UT('.'): - case _UT('_'): - case _UT('~'): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - return first + 1; - - default: - URI_FUNC(StopSyntax)(state, first, memory); - return NULL; - } +static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + URI_FUNC(StopSyntax)(state, afterLast, memory); + return NULL; + } + + switch (*first) { + case _UT('%'): + return URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); + + case URI_SET_SUB_DELIMS(_UT): + case URI_SET_UNRESERVED(_UT): + return first + 1; + + default: + URI_FUNC(StopSyntax)(state, first, memory); + return NULL; + } } - - /* * [port]->[DIGIT][port] * [port]-> */ -static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case URI_SET_DIGIT: - return URI_FUNC(ParsePort)(state, first + 1, afterLast); - - default: - return first; - } +static const URI_CHAR * URI_FUNC(ParsePort)(const URI_CHAR * first, + const URI_CHAR * afterLast) { +tail_call: + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_DIGIT(_UT): + first += 1; + goto tail_call; + + default: + return first; + } } - - /* * [queryFrag]->[pchar][queryFrag] * [queryFrag]->[queryFrag] @@ -1691,130 +1451,89 @@ static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const * [queryFrag]-> */ static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(':'): - case _UT(';'): - case _UT('@'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - { - const URI_CHAR * const afterPchar - = URI_FUNC(ParsePchar)(state, first, afterLast, memory); - if (afterPchar == NULL) { - return NULL; - } - return URI_FUNC(ParseQueryFrag)(state, afterPchar, afterLast, memory); - } - - case _UT('/'): - case _UT('?'): - return URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory); - - default: - return first; - } + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_PCHAR(_UT): { + const URI_CHAR * const afterPchar = + URI_FUNC(ParsePchar)(state, first, afterLast, memory); + if (afterPchar == NULL) { + return NULL; + } + first = afterPchar; + goto tail_call; + } + + case _UT('/'): + case _UT('?'): + first += 1; + goto tail_call; + + default: + return first; + } } - - /* * [segment]->[pchar][segment] * [segment]-> */ static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('!'): - case _UT('$'): - case _UT('%'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('-'): - case _UT('*'): - case _UT(','): - case _UT('.'): - case _UT(':'): - case _UT(';'): - case _UT('@'): - case _UT('\''): - case _UT('_'): - case _UT('~'): - case _UT('+'): - case _UT('='): - case URI_SET_DIGIT: - case URI_SET_ALPHA: - { - const URI_CHAR * const afterPchar - = URI_FUNC(ParsePchar)(state, first, afterLast, memory); - if (afterPchar == NULL) { - return NULL; - } - return URI_FUNC(ParseSegment)(state, afterPchar, afterLast, memory); - } - - default: - return first; - } + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_PCHAR(_UT): { + const URI_CHAR * const afterPchar = + URI_FUNC(ParsePchar)(state, first, afterLast, memory); + if (afterPchar == NULL) { + return NULL; + } + first = afterPchar; + goto tail_call; + } + + default: + return first; + } } - - /* * [segmentNz]->[pchar][segment] */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseSegmentNz)( - URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - const URI_CHAR * const afterPchar - = URI_FUNC(ParsePchar)(state, first, afterLast, memory); - if (afterPchar == NULL) { - return NULL; - } - return URI_FUNC(ParseSegment)(state, afterPchar, afterLast, memory); +static URI_INLINE const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + const URI_CHAR * const afterPchar = + URI_FUNC(ParsePchar)(state, first, afterLast, memory); + if (afterPchar == NULL) { + return NULL; + } + return URI_FUNC(ParseSegment)(state, afterPchar, afterLast, memory); } - - static URI_INLINE UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - UriMemoryManager * memory) { - if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */ - return URI_FALSE; /* Raises malloc error*/ - } - state->uri->scheme.first = NULL; /* Not a scheme, reset */ - return URI_TRUE; /* Success */ + URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory) { + if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, + memory)) { /* SEGMENT BOTH */ + return URI_FALSE; /* Raises malloc error*/ + } + state->uri->scheme.first = NULL; /* Not a scheme, reset */ + return URI_TRUE; /* Success */ } - - /* * [segmentNzNcOrScheme2]->[ALPHA][segmentNzNcOrScheme2] * [segmentNzNcOrScheme2]->[DIGIT][segmentNzNcOrScheme2] @@ -1839,97 +1558,98 @@ static URI_INLINE UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)( * [segmentNzNcOrScheme2]-><'>[mustBeSegmentNzNc] * [segmentNzNcOrScheme2]-><->[segmentNzNcOrScheme2] */ -static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first, memory)) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return afterLast; - } - - switch (*first) { - case _UT('.'): - case _UT('+'): - case _UT('-'): - case URI_SET_ALPHA: - case URI_SET_DIGIT: - return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast, memory); - - case _UT('%'): - { - const URI_CHAR * const afterPctEncoded - = URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); - if (afterPctEncoded == NULL) { - return NULL; - } - return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast, memory); - } - - case _UT('!'): - case _UT('$'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('*'): - case _UT(','): - case _UT(';'): - case _UT('@'): - case _UT('_'): - case _UT('~'): - case _UT('='): - case _UT('\''): - return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory); - - case _UT('/'): - { - const URI_CHAR * afterZeroMoreSlashSegs; - const URI_CHAR * const afterSegment - = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory); - if (afterSegment == NULL) { - return NULL; - } - if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - state->uri->scheme.first = NULL; /* Not a scheme, reset */ - if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - afterZeroMoreSlashSegs - = URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory); - if (afterZeroMoreSlashSegs == NULL) { - return NULL; - } - return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast, memory); - } - - case _UT(':'): - { - const URI_CHAR * const afterHierPart - = URI_FUNC(ParseHierPart)(state, first + 1, afterLast, memory); - state->uri->scheme.afterLast = first; /* SCHEME END */ - if (afterHierPart == NULL) { - return NULL; - } - return URI_FUNC(ParseUriTail)(state, afterHierPart, afterLast, memory); - } - - default: - if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first, memory)) { - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return URI_FUNC(ParseUriTail)(state, first, afterLast, memory); - } +static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first, memory)) { + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + return afterLast; + } + + switch (*first) { + case _UT('.'): + case _UT('+'): + case _UT('-'): + case URI_SET_ALPHA(_UT): + case URI_SET_DIGIT(_UT): + first += 1; + goto tail_call; + + case _UT('%'): { + const URI_CHAR * const afterPctEncoded = + URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); + if (afterPctEncoded == NULL) { + return NULL; + } + return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast, + memory); + } + + case _UT('!'): + case _UT('$'): + case _UT('&'): + case _UT('('): + case _UT(')'): + case _UT('*'): + case _UT(','): + case _UT(';'): + case _UT('@'): + case _UT('_'): + case _UT('~'): + case _UT('='): + case _UT('\''): + return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory); + + case _UT('/'): { + const URI_CHAR * afterZeroMoreSlashSegs; + const URI_CHAR * const afterSegment = + URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory); + if (afterSegment == NULL) { + return NULL; + } + if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + state->uri->scheme.first = NULL; /* Not a scheme, reset */ + if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + afterZeroMoreSlashSegs = + URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory); + if (afterZeroMoreSlashSegs == NULL) { + return NULL; + } + return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast, memory); + } + + case _UT(':'): { + const URI_CHAR * const afterHierPart = + URI_FUNC(ParseHierPart)(state, first + 1, afterLast, memory); + state->uri->scheme.afterLast = first; /* SCHEME END */ + if (afterHierPart == NULL) { + return NULL; + } + return URI_FUNC(ParseUriTail)(state, afterHierPart, afterLast, memory); + } + + default: + if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first, memory)) { + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + return URI_FUNC(ParseUriTail)(state, first, afterLast, memory); + } } - - /* * [uriReference]->[ALPHA][segmentNzNcOrScheme2] * [uriReference]->[DIGIT][mustBeSegmentNzNc] @@ -1943,452 +1663,410 @@ static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)( * [uriReference]-><~>[mustBeSegmentNzNc] * [uriReference]-><->[mustBeSegmentNzNc] */ -static const URI_CHAR * URI_FUNC(ParseUriReference)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case URI_SET_ALPHA: - state->uri->scheme.first = first; /* SCHEME BEGIN */ - return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast, memory); - - case URI_SET_DIGIT: - case _UT('!'): - case _UT('$'): - case _UT('&'): - case _UT('('): - case _UT(')'): - case _UT('*'): - case _UT(','): - case _UT(';'): - case _UT('\''): - case _UT('+'): - case _UT('='): - case _UT('.'): - case _UT('_'): - case _UT('~'): - case _UT('-'): - case _UT('@'): - state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */ - return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory); - - case _UT('%'): - { - const URI_CHAR * const afterPctEncoded - = URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); - if (afterPctEncoded == NULL) { - return NULL; - } - state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */ - return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast, memory); - } - - case _UT('/'): - { - const URI_CHAR * const afterPartHelperTwo - = URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast, memory); - if (afterPartHelperTwo == NULL) { - return NULL; - } - return URI_FUNC(ParseUriTail)(state, afterPartHelperTwo, afterLast, memory); - } - - default: - return URI_FUNC(ParseUriTail)(state, first, afterLast, memory); - } +static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case URI_SET_ALPHA(_UT): + state->uri->scheme.first = first; /* SCHEME BEGIN */ + return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast, memory); + + case URI_SET_DIGIT(_UT): + case URI_SET_SUB_DELIMS(_UT): + case _UT('.'): + case _UT('_'): + case _UT('~'): + case _UT('-'): + case _UT('@'): + state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */ + return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory); + + case _UT('%'): { + const URI_CHAR * const afterPctEncoded = + URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory); + if (afterPctEncoded == NULL) { + return NULL; + } + state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */ + return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast, + memory); + } + + case _UT('/'): { + const URI_CHAR * const afterPartHelperTwo = + URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast, memory); + if (afterPartHelperTwo == NULL) { + return NULL; + } + return URI_FUNC(ParseUriTail)(state, afterPartHelperTwo, afterLast, memory); + } + + default: + return URI_FUNC(ParseUriTail)(state, first, afterLast, memory); + } } - - /* * [uriTail]-><#>[queryFrag] * [uriTail]->[queryFrag][uriTailTwo] * [uriTail]-> */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTail)( - URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('#'): - { - const URI_CHAR * const afterQueryFrag = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory); - if (afterQueryFrag == NULL) { - return NULL; - } - state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */ - state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */ - return afterQueryFrag; - } - - case _UT('?'): - { - const URI_CHAR * const afterQueryFrag - = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory); - if (afterQueryFrag == NULL) { - return NULL; - } - state->uri->query.first = first + 1; /* QUERY BEGIN */ - state->uri->query.afterLast = afterQueryFrag; /* QUERY END */ - return URI_FUNC(ParseUriTailTwo)(state, afterQueryFrag, afterLast, memory); - } - - default: - return first; - } +static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case _UT('#'): { + const URI_CHAR * const afterQueryFrag = + URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory); + if (afterQueryFrag == NULL) { + return NULL; + } + state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */ + state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */ + return afterQueryFrag; + } + + case _UT('?'): { + const URI_CHAR * const afterQueryFrag = + URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory); + if (afterQueryFrag == NULL) { + return NULL; + } + state->uri->query.first = first + 1; /* QUERY BEGIN */ + state->uri->query.afterLast = afterQueryFrag; /* QUERY END */ + return URI_FUNC(ParseUriTailTwo)(state, afterQueryFrag, afterLast, memory); + } + + default: + return first; + } } - - /* * [uriTailTwo]-><#>[queryFrag] * [uriTailTwo]-> */ -static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTailTwo)( - URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('#'): - { - const URI_CHAR * const afterQueryFrag = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory); - if (afterQueryFrag == NULL) { - return NULL; - } - state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */ - state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */ - return afterQueryFrag; - } - - default: - return first; - } +static URI_INLINE const URI_CHAR * +URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case _UT('#'): { + const URI_CHAR * const afterQueryFrag = + URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory); + if (afterQueryFrag == NULL) { + return NULL; + } + state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */ + state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */ + return afterQueryFrag; + } + + default: + return first; + } } - - /* * [zeroMoreSlashSegs]->[segment][zeroMoreSlashSegs] * [zeroMoreSlashSegs]-> */ -static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - if (first >= afterLast) { - return afterLast; - } - - switch (*first) { - case _UT('/'): - { - const URI_CHAR * const afterSegment - = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory); - if (afterSegment == NULL) { - return NULL; - } - if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, memory)) { /* SEGMENT BOTH */ - URI_FUNC(StopMalloc)(state, memory); - return NULL; - } - return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory); - } - - default: - return first; - } +static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { +tail_call: + if (first >= afterLast) { + return afterLast; + } + + switch (*first) { + case _UT('/'): { + const URI_CHAR * const afterSegment = + URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory); + if (afterSegment == NULL) { + return NULL; + } + if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, + memory)) { /* SEGMENT BOTH */ + URI_FUNC(StopMalloc)(state, memory); + return NULL; + } + first = afterSegment; + goto tail_call; + } + + default: + return first; + } } - - -static URI_INLINE void URI_FUNC(ResetParserStateExceptUri)(URI_TYPE(ParserState) * state) { - URI_TYPE(Uri) * const uriBackup = state->uri; - memset(state, 0, sizeof(URI_TYPE(ParserState))); - state->uri = uriBackup; +static URI_INLINE void URI_FUNC(ResetParserStateExceptUri)(URI_TYPE(ParserState) + * state) { + URI_TYPE(Uri) * const uriBackup = state->uri; + memset(state, 0, sizeof(URI_TYPE(ParserState))); + state->uri = uriBackup; } - - -static URI_INLINE UriBool URI_FUNC(PushPathSegment)( - URI_TYPE(ParserState) * state, const URI_CHAR * first, - const URI_CHAR * afterLast, UriMemoryManager * memory) { - URI_TYPE(PathSegment) * segment = memory->calloc(memory, 1, sizeof(URI_TYPE(PathSegment))); - if (segment == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - if (first == afterLast) { - segment->text.first = URI_FUNC(SafeToPointTo); - segment->text.afterLast = URI_FUNC(SafeToPointTo); - } else { - segment->text.first = first; - segment->text.afterLast = afterLast; - } - - /* First segment ever? */ - if (state->uri->pathHead == NULL) { - /* First segment ever, set head and tail */ - state->uri->pathHead = segment; - state->uri->pathTail = segment; - } else { - /* Append, update tail */ - state->uri->pathTail->next = segment; - state->uri->pathTail = segment; - } - - return URI_TRUE; /* Success */ +static URI_INLINE UriBool URI_FUNC(PushPathSegment)(URI_TYPE(ParserState) * state, + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + URI_TYPE(PathSegment) * segment = + memory->calloc(memory, 1, sizeof(URI_TYPE(PathSegment))); + if (segment == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + if (first == afterLast) { + segment->text.first = URI_FUNC(SafeToPointTo); + segment->text.afterLast = URI_FUNC(SafeToPointTo); + } else { + segment->text.first = first; + segment->text.afterLast = afterLast; + } + + /* First segment ever? */ + if (state->uri->pathHead == NULL) { + /* First segment ever, set head and tail */ + state->uri->pathHead = segment; + state->uri->pathTail = segment; + } else { + /* Append, update tail */ + state->uri->pathTail->next = segment; + state->uri->pathTail = segment; + } + + return URI_TRUE; /* Success */ } - - -int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast) { - return URI_FUNC(ParseUriExMm)(state, first, afterLast, NULL); +int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(ParseUriExMm)(state, first, afterLast, NULL); } - - -static int URI_FUNC(ParseUriExMm)(URI_TYPE(ParserState) * state, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - const URI_CHAR * afterUriReference; - URI_TYPE(Uri) * uri; - - /* Check params */ - if ((state == NULL) || (first == NULL) || (afterLast == NULL)) { - return URI_ERROR_NULL; - } - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - uri = state->uri; - - /* Init parser */ - URI_FUNC(ResetParserStateExceptUri)(state); - URI_FUNC(ResetUri)(uri); - - /* Parse */ - afterUriReference = URI_FUNC(ParseUriReference)(state, first, afterLast, memory); - if (afterUriReference == NULL) { - /* Waterproof errorPos <= afterLast */ - if (state->errorPos && (state->errorPos > afterLast)) { - state->errorPos = afterLast; - } - return state->errorCode; - } - if (afterUriReference != afterLast) { - if (afterUriReference < afterLast) { - URI_FUNC(StopSyntax)(state, afterUriReference, memory); - } else { - URI_FUNC(StopSyntax)(state, afterLast, memory); - } - return state->errorCode; - } - return URI_SUCCESS; +static int URI_FUNC(ParseUriExMm)(URI_TYPE(ParserState) * state, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + const URI_CHAR * afterUriReference; + URI_TYPE(Uri) * uri; + + /* Check params */ + if ((state == NULL) || (first == NULL) || (afterLast == NULL)) { + return URI_ERROR_NULL; + } + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + uri = state->uri; + + /* Init parser */ + URI_FUNC(ResetParserStateExceptUri)(state); + URI_FUNC(ResetUri)(uri); + + /* Parse */ + afterUriReference = URI_FUNC(ParseUriReference)(state, first, afterLast, memory); + if (afterUriReference == NULL) { + /* Waterproof errorPos <= afterLast */ + if (state->errorPos && (state->errorPos > afterLast)) { + state->errorPos = afterLast; + } + return state->errorCode; + } + if (afterUriReference != afterLast) { + if (afterUriReference < afterLast) { + URI_FUNC(StopSyntax)(state, afterUriReference, memory); + } else { + URI_FUNC(StopSyntax)(state, afterLast, memory); + } + return state->errorCode; + } + return URI_SUCCESS; } - - int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, const URI_CHAR * text) { - if ((state == NULL) || (text == NULL)) { - return URI_ERROR_NULL; - } - return URI_FUNC(ParseUriEx)(state, text, text + URI_STRLEN(text)); + if ((state == NULL) || (text == NULL)) { + return URI_ERROR_NULL; + } + return URI_FUNC(ParseUriEx)(state, text, text + URI_STRLEN(text)); } - - int URI_FUNC(ParseSingleUri)(URI_TYPE(Uri) * uri, const URI_CHAR * text, - const URI_CHAR ** errorPos) { - return URI_FUNC(ParseSingleUriEx)(uri, text, NULL, errorPos); + const URI_CHAR ** errorPos) { + return URI_FUNC(ParseSingleUriEx)(uri, text, NULL, errorPos); } - - -int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, const URI_CHAR * afterLast, - const URI_CHAR ** errorPos) { +int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, const URI_CHAR ** errorPos) { if ((afterLast == NULL) && (first != NULL)) { - afterLast = first + URI_STRLEN(first); - } - return URI_FUNC(ParseSingleUriExMm)(uri, first, afterLast, errorPos, NULL); + afterLast = first + URI_STRLEN(first); + } + return URI_FUNC(ParseSingleUriExMm)(uri, first, afterLast, errorPos, NULL); } +int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, const URI_CHAR ** errorPos, + UriMemoryManager * memory) { + URI_TYPE(ParserState) state; + int res; + /* Check params */ + if ((uri == NULL) || (first == NULL) || (afterLast == NULL)) { + return URI_ERROR_NULL; + } + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ -int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, const URI_CHAR * afterLast, - const URI_CHAR ** errorPos, UriMemoryManager * memory) { - URI_TYPE(ParserState) state; - int res; - - /* Check params */ - if ((uri == NULL) || (first == NULL) || (afterLast == NULL)) { - return URI_ERROR_NULL; - } - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - state.uri = uri; + state.uri = uri; - res = URI_FUNC(ParseUriExMm)(&state, first, afterLast, memory); + res = URI_FUNC(ParseUriExMm)(&state, first, afterLast, memory); - if (res != URI_SUCCESS) { - if (errorPos != NULL) { - *errorPos = state.errorPos; - } - URI_FUNC(FreeUriMembersMm)(uri, memory); - } + if (res != URI_SUCCESS) { + if (errorPos != NULL) { + *errorPos = state.errorPos; + } + URI_FUNC(FreeUriMembersMm)(uri, memory); + } - return res; + return res; } - - void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri) { - URI_FUNC(FreeUriMembersMm)(uri, NULL); + URI_FUNC(FreeUriMembersMm)(uri, NULL); } - - int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { - if (uri == NULL) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - if (uri->owner) { - /* Scheme */ - if (uri->scheme.first != NULL) { - if (uri->scheme.first != uri->scheme.afterLast) { - memory->free(memory, (URI_CHAR *)uri->scheme.first); - } - uri->scheme.first = NULL; - uri->scheme.afterLast = NULL; - } - - /* User info */ - if (uri->userInfo.first != NULL) { - if (uri->userInfo.first != uri->userInfo.afterLast) { - memory->free(memory, (URI_CHAR *)uri->userInfo.first); - } - uri->userInfo.first = NULL; - uri->userInfo.afterLast = NULL; - } - - /* Host data - IPvFuture (may affect host text) */ - if (uri->hostData.ipFuture.first != NULL) { - /* NOTE: .hostData.ipFuture holds the very same range pointers - * as .hostText; we must not free memory twice. */ - uri->hostText.first = NULL; - uri->hostText.afterLast = NULL; - - if (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast) { - memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first); - } - uri->hostData.ipFuture.first = NULL; - uri->hostData.ipFuture.afterLast = NULL; - } - - /* Host text (after IPvFuture, see above) */ - if (uri->hostText.first != NULL) { - if (uri->hostText.first != uri->hostText.afterLast) { - memory->free(memory, (URI_CHAR *)uri->hostText.first); - } - uri->hostText.first = NULL; - uri->hostText.afterLast = NULL; - } - } - - /* Host data - IPv4 */ - if (uri->hostData.ip4 != NULL) { - memory->free(memory, uri->hostData.ip4); - uri->hostData.ip4 = NULL; - } - - /* Host data - IPv6 */ - if (uri->hostData.ip6 != NULL) { - memory->free(memory, uri->hostData.ip6); - uri->hostData.ip6 = NULL; - } - - /* Port text */ - if (uri->owner && (uri->portText.first != NULL)) { - if (uri->portText.first != uri->portText.afterLast) { - memory->free(memory, (URI_CHAR *)uri->portText.first); - } - uri->portText.first = NULL; - uri->portText.afterLast = NULL; - } - - /* Path */ - URI_FUNC(FreeUriPath)(uri, memory); - - if (uri->owner) { - /* Query */ - if (uri->query.first != NULL) { - if (uri->query.first != uri->query.afterLast) { - memory->free(memory, (URI_CHAR *)uri->query.first); - } - uri->query.first = NULL; - uri->query.afterLast = NULL; - } - - /* Fragment */ - if (uri->fragment.first != NULL) { - if (uri->fragment.first != uri->fragment.afterLast) { - memory->free(memory, (URI_CHAR *)uri->fragment.first); - } - uri->fragment.first = NULL; - uri->fragment.afterLast = NULL; - } - } - - return URI_SUCCESS; + if (uri == NULL) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + if (uri->owner) { + /* Scheme */ + if (uri->scheme.first != NULL) { + if (uri->scheme.first != uri->scheme.afterLast) { + memory->free(memory, (URI_CHAR *)uri->scheme.first); + } + uri->scheme.first = NULL; + uri->scheme.afterLast = NULL; + } + + /* User info */ + if (uri->userInfo.first != NULL) { + if (uri->userInfo.first != uri->userInfo.afterLast) { + memory->free(memory, (URI_CHAR *)uri->userInfo.first); + } + uri->userInfo.first = NULL; + uri->userInfo.afterLast = NULL; + } + + /* Host data - IPvFuture (may affect host text) */ + if (uri->hostData.ipFuture.first != NULL) { + /* NOTE: .hostData.ipFuture holds the very same range pointers + * as .hostText; we must not free memory twice. */ + uri->hostText.first = NULL; + uri->hostText.afterLast = NULL; + + if (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast) { + memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first); + } + uri->hostData.ipFuture.first = NULL; + uri->hostData.ipFuture.afterLast = NULL; + } + + /* Host text (after IPvFuture, see above) */ + if (uri->hostText.first != NULL) { + if (uri->hostText.first != uri->hostText.afterLast) { + memory->free(memory, (URI_CHAR *)uri->hostText.first); + } + uri->hostText.first = NULL; + uri->hostText.afterLast = NULL; + } + } + + /* Host data - IPv4 */ + if (uri->hostData.ip4 != NULL) { + memory->free(memory, uri->hostData.ip4); + uri->hostData.ip4 = NULL; + } + + /* Host data - IPv6 */ + if (uri->hostData.ip6 != NULL) { + memory->free(memory, uri->hostData.ip6); + uri->hostData.ip6 = NULL; + } + + /* Port text */ + if (uri->owner && (uri->portText.first != NULL)) { + if (uri->portText.first != uri->portText.afterLast) { + memory->free(memory, (URI_CHAR *)uri->portText.first); + } + uri->portText.first = NULL; + uri->portText.afterLast = NULL; + } + + /* Path */ + URI_FUNC(FreeUriPath)(uri, memory); + + if (uri->owner) { + /* Query */ + if (uri->query.first != NULL) { + if (uri->query.first != uri->query.afterLast) { + memory->free(memory, (URI_CHAR *)uri->query.first); + } + uri->query.first = NULL; + uri->query.afterLast = NULL; + } + + /* Fragment */ + if (uri->fragment.first != NULL) { + if (uri->fragment.first != uri->fragment.afterLast) { + memory->free(memory, (URI_CHAR *)uri->fragment.first); + } + uri->fragment.first = NULL; + uri->fragment.afterLast = NULL; + } + } + + return URI_SUCCESS; } - - UriBool URI_FUNC(_TESTING_ONLY_ParseIpSix)(const URI_CHAR * text) { - UriMemoryManager * const memory = &defaultMemoryManager; - URI_TYPE(Uri) uri; - URI_TYPE(ParserState) parser; - const URI_CHAR * const afterIpSix = text + URI_STRLEN(text); - const URI_CHAR * res; - - URI_FUNC(ResetUri)(&uri); - parser.uri = &uri; - URI_FUNC(ResetParserStateExceptUri)(&parser); - parser.uri->hostData.ip6 = memory->malloc(memory, 1 * sizeof(UriIp6)); - res = URI_FUNC(ParseIPv6address2)(&parser, text, afterIpSix, memory); - URI_FUNC(FreeUriMembersMm)(&uri, memory); - return res == afterIpSix ? URI_TRUE : URI_FALSE; + UriMemoryManager * const memory = &defaultMemoryManager; + URI_TYPE(Uri) uri; + URI_TYPE(ParserState) parser; + const URI_CHAR * const afterIpSix = text + URI_STRLEN(text); + const URI_CHAR * res; + + URI_FUNC(ResetUri)(&uri); + parser.uri = &uri; + URI_FUNC(ResetParserStateExceptUri)(&parser); + parser.uri->hostData.ip6 = memory->malloc(memory, 1 * sizeof(UriIp6)); + res = URI_FUNC(ParseIPv6address2)(&parser, text, afterIpSix, memory); + URI_FUNC(FreeUriMembersMm)(&uri, memory); + return res == afterIpSix ? URI_TRUE : URI_FALSE; } - - UriBool URI_FUNC(_TESTING_ONLY_ParseIpFour)(const URI_CHAR * text) { - unsigned char octets[4]; - int res = URI_FUNC(ParseIpFourAddress)(octets, text, text + URI_STRLEN(text)); - return (res == URI_SUCCESS) ? URI_TRUE : URI_FALSE; + unsigned char octets[4]; + int res = URI_FUNC(ParseIpFourAddress)(octets, text, text + URI_STRLEN(text)); + return (res == URI_SUCCESS) ? URI_TRUE : URI_FALSE; } - - -#undef URI_SET_DIGIT -#undef URI_SET_HEX_LETTER_UPPER -#undef URI_SET_HEX_LETTER_LOWER -#undef URI_SET_HEXDIG -#undef URI_SET_ALPHA - - +# undef URI_SET_DIGIT +# undef URI_SET_HEX_LETTER_UPPER +# undef URI_SET_HEX_LETTER_LOWER +# undef URI_SET_HEXDIG +# undef URI_SET_ALPHA #endif diff --git a/ext/uri/uriparser/src/UriParseBase.c b/ext/uri/uriparser/src/UriParseBase.c index 3a4aa08f6b760..0ee66d4427e3b 100644 --- a/ext/uri/uriparser/src/UriParseBase.c +++ b/ext/uri/uriparser/src/UriParseBase.c @@ -38,53 +38,48 @@ */ #ifndef URI_DOXYGEN -# include "UriParseBase.h" +# include "UriParseBase.h" #endif +void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount, + unsigned char * output) { + switch (digitCount) { + case 1: + /* 0x___? -> \x00 \x0? */ + output[0] = 0; + output[1] = hexDigits[0]; + break; + case 2: + /* 0x__?? -> \0xx \x?? */ + output[0] = 0; + output[1] = 16 * hexDigits[0] + hexDigits[1]; + break; -void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount, unsigned char * output) { - switch (digitCount) { - case 1: - /* 0x___? -> \x00 \x0? */ - output[0] = 0; - output[1] = hexDigits[0]; - break; + case 3: + /* 0x_??? -> \0x? \x?? */ + output[0] = hexDigits[0]; + output[1] = 16 * hexDigits[1] + hexDigits[2]; + break; - case 2: - /* 0x__?? -> \0xx \x?? */ - output[0] = 0; - output[1] = 16 * hexDigits[0] + hexDigits[1]; - break; - - case 3: - /* 0x_??? -> \0x? \x?? */ - output[0] = hexDigits[0]; - output[1] = 16 * hexDigits[1] + hexDigits[2]; - break; - - case 4: - /* 0x???? -> \0?? \x?? */ - output[0] = 16 * hexDigits[0] + hexDigits[1]; - output[1] = 16 * hexDigits[2] + hexDigits[3]; - break; - - } + case 4: + /* 0x???? -> \0?? \x?? */ + output[0] = 16 * hexDigits[0] + hexDigits[1]; + output[1] = 16 * hexDigits[2] + hexDigits[3]; + break; + } } - - unsigned char uriGetOctetValue(const unsigned char * digits, int digitCount) { - switch (digitCount) { - case 1: - return digits[0]; - - case 2: - return 10 * digits[0] + digits[1]; + switch (digitCount) { + case 1: + return digits[0]; - case 3: - default: - return 100 * digits[0] + 10 * digits[1] + digits[2]; + case 2: + return 10 * digits[0] + digits[1]; - } + case 3: + default: + return 100 * digits[0] + 10 * digits[1] + digits[2]; + } } diff --git a/ext/uri/uriparser/src/UriParseBase.h b/ext/uri/uriparser/src/UriParseBase.h index 6d7379de1c0a9..cdb2c6f778790 100644 --- a/ext/uri/uriparser/src/UriParseBase.h +++ b/ext/uri/uriparser/src/UriParseBase.h @@ -38,18 +38,12 @@ */ #ifndef URI_PARSE_BASE_H -#define URI_PARSE_BASE_H 1 - - - -#include - +# define URI_PARSE_BASE_H 1 +# include void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount, - unsigned char * output); + unsigned char * output); unsigned char uriGetOctetValue(const unsigned char * digits, int digitCount); - - #endif /* URI_PARSE_BASE_H */ diff --git a/ext/uri/uriparser/src/UriQuery.c b/ext/uri/uriparser/src/UriQuery.c index bbc15488773c6..801a237a3a1b2 100644 --- a/ext/uri/uriparser/src/UriQuery.c +++ b/ext/uri/uriparser/src/UriQuery.c @@ -41,465 +41,427 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriQuery.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriQuery.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriQuery.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriQuery.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - - -#include -#include /* size_t */ - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# endif + +# include +# include /* size_t */ static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, - const URI_TYPE(QueryList) * queryList, - int maxChars, int * charsWritten, int * charsRequired, - UriBool spaceToPlus, UriBool normalizeBreaks); - -static UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, - int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, - const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, - UriBool plusToSpace, UriBreakConversion breakConversion, - UriMemoryManager * memory); - + const URI_TYPE(QueryList) * queryList, + int maxChars, int * charsWritten, + int * charsRequired, UriBool spaceToPlus, + UriBool normalizeBreaks); +static UriBool URI_FUNC(AppendQueryItem)( + URI_TYPE(QueryList) * *prevNext, int * itemCount, const URI_CHAR * keyFirst, + const URI_CHAR * keyAfter, const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, + UriBool plusToSpace, UriBreakConversion breakConversion, UriMemoryManager * memory); int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList, - int * charsRequired) { - const UriBool spaceToPlus = URI_TRUE; - const UriBool normalizeBreaks = URI_TRUE; + int * charsRequired) { + const UriBool spaceToPlus = URI_TRUE; + const UriBool normalizeBreaks = URI_TRUE; - return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired, - spaceToPlus, normalizeBreaks); + return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired, spaceToPlus, + normalizeBreaks); } - - int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList, - int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks) { - if ((queryList == NULL) || (charsRequired == NULL)) { - return URI_ERROR_NULL; - } - - return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL, - charsRequired, spaceToPlus, normalizeBreaks); + int * charsRequired, UriBool spaceToPlus, + UriBool normalizeBreaks) { + if ((queryList == NULL) || (charsRequired == NULL)) { + return URI_ERROR_NULL; + } + + return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL, charsRequired, + spaceToPlus, normalizeBreaks); } +int URI_FUNC(ComposeQuery)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList, + int maxChars, int * charsWritten) { + const UriBool spaceToPlus = URI_TRUE; + const UriBool normalizeBreaks = URI_TRUE; - -int URI_FUNC(ComposeQuery)(URI_CHAR * dest, - const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten) { - const UriBool spaceToPlus = URI_TRUE; - const UriBool normalizeBreaks = URI_TRUE; - - return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten, - spaceToPlus, normalizeBreaks); + return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten, spaceToPlus, + normalizeBreaks); } +int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList, + int maxChars, int * charsWritten, UriBool spaceToPlus, + UriBool normalizeBreaks) { + if ((dest == NULL) || (queryList == NULL)) { + return URI_ERROR_NULL; + } + if (maxChars < 1) { + return URI_ERROR_OUTPUT_TOO_LARGE; + } -int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, - const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, - UriBool spaceToPlus, UriBool normalizeBreaks) { - if ((dest == NULL) || (queryList == NULL)) { - return URI_ERROR_NULL; - } - - if (maxChars < 1) { - return URI_ERROR_OUTPUT_TOO_LARGE; - } - - return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars, - charsWritten, NULL, spaceToPlus, normalizeBreaks); + return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars, charsWritten, NULL, + spaceToPlus, normalizeBreaks); } - - int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, - const URI_TYPE(QueryList) * queryList) { - const UriBool spaceToPlus = URI_TRUE; - const UriBool normalizeBreaks = URI_TRUE; + const URI_TYPE(QueryList) * queryList) { + const UriBool spaceToPlus = URI_TRUE; + const UriBool normalizeBreaks = URI_TRUE; - return URI_FUNC(ComposeQueryMallocEx)(dest, queryList, - spaceToPlus, normalizeBreaks); + return URI_FUNC(ComposeQueryMallocEx)(dest, queryList, spaceToPlus, normalizeBreaks); } - - int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, - const URI_TYPE(QueryList) * queryList, - UriBool spaceToPlus, UriBool normalizeBreaks) { - return URI_FUNC(ComposeQueryMallocExMm)(dest, queryList, spaceToPlus, - normalizeBreaks, NULL); + const URI_TYPE(QueryList) * queryList, + UriBool spaceToPlus, UriBool normalizeBreaks) { + return URI_FUNC(ComposeQueryMallocExMm)(dest, queryList, spaceToPlus, normalizeBreaks, + NULL); } - - int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest, - const URI_TYPE(QueryList) * queryList, - UriBool spaceToPlus, UriBool normalizeBreaks, - UriMemoryManager * memory) { - int charsRequired; - int res; - URI_CHAR * queryString; - - if (dest == NULL) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - /* Calculate space */ - res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired, - spaceToPlus, normalizeBreaks); - if (res != URI_SUCCESS) { - return res; - } - if (charsRequired == INT_MAX) { - return URI_ERROR_MALLOC; - } - charsRequired++; - - /* Allocate space */ - queryString = memory->calloc(memory, charsRequired, sizeof(URI_CHAR)); - if (queryString == NULL) { - return URI_ERROR_MALLOC; - } - - /* Put query in */ - res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired, - NULL, spaceToPlus, normalizeBreaks); - if (res != URI_SUCCESS) { - memory->free(memory, queryString); - return res; - } - - *dest = queryString; - return URI_SUCCESS; + const URI_TYPE(QueryList) * queryList, + UriBool spaceToPlus, UriBool normalizeBreaks, + UriMemoryManager * memory) { + int charsRequired; + int res; + URI_CHAR * queryString; + + if (dest == NULL) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + /* Calculate space */ + res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired, spaceToPlus, + normalizeBreaks); + if (res != URI_SUCCESS) { + return res; + } + if (charsRequired == INT_MAX) { + return URI_ERROR_MALLOC; + } + charsRequired++; + + /* Allocate space */ + queryString = memory->calloc(memory, charsRequired, sizeof(URI_CHAR)); + if (queryString == NULL) { + return URI_ERROR_MALLOC; + } + + /* Put query in */ + res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired, NULL, + spaceToPlus, normalizeBreaks); + if (res != URI_SUCCESS) { + memory->free(memory, queryString); + return res; + } + + *dest = queryString; + return URI_SUCCESS; } - - -int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, - const URI_TYPE(QueryList) * queryList, - int maxChars, int * charsWritten, int * charsRequired, - UriBool spaceToPlus, UriBool normalizeBreaks) { - UriBool firstItem = URI_TRUE; - int ampersandLen = 0; /* increased to 1 from second item on */ - URI_CHAR * write = dest; - - /* Subtract terminator */ - if (dest == NULL) { - *charsRequired = 0; - } else { - maxChars--; - } - - while (queryList != NULL) { - const URI_CHAR * const key = queryList->key; - const URI_CHAR * const value = queryList->value; - const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3); - const size_t keyLen = (key == NULL) ? 0 : URI_STRLEN(key); - int keyRequiredChars; - const size_t valueLen = (value == NULL) ? 0 : URI_STRLEN(value); - int valueRequiredChars; - - if ((keyLen >= (size_t)INT_MAX / worstCase) || (valueLen >= (size_t)INT_MAX / worstCase)) { - return URI_ERROR_OUTPUT_TOO_LARGE; - } - keyRequiredChars = worstCase * (int)keyLen; - valueRequiredChars = worstCase * (int)valueLen; - - if (dest == NULL) { - (*charsRequired) += ampersandLen + keyRequiredChars + ((value == NULL) - ? 0 - : 1 + valueRequiredChars); - - if (firstItem == URI_TRUE) { - ampersandLen = 1; - firstItem = URI_FALSE; - } - } else { - if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) { - return URI_ERROR_OUTPUT_TOO_LARGE; - } - - /* Copy key */ - if (firstItem == URI_TRUE) { - ampersandLen = 1; - firstItem = URI_FALSE; - } else { - write[0] = _UT('&'); - write++; - } - write = URI_FUNC(EscapeEx)(key, key + keyLen, - write, spaceToPlus, normalizeBreaks); - - if (value != NULL) { - if ((write - dest) + 1 + valueRequiredChars > maxChars) { - return URI_ERROR_OUTPUT_TOO_LARGE; - } - - /* Copy value */ - write[0] = _UT('='); - write++; - write = URI_FUNC(EscapeEx)(value, value + valueLen, - write, spaceToPlus, normalizeBreaks); - } - } - - queryList = queryList->next; - } - - if (dest != NULL) { - write[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = (int)(write - dest) + 1; /* .. for terminator */ - } - } - - return URI_SUCCESS; +int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList, + int maxChars, int * charsWritten, int * charsRequired, + UriBool spaceToPlus, UriBool normalizeBreaks) { + UriBool firstItem = URI_TRUE; + int ampersandLen = 0; /* increased to 1 from second item on */ + URI_CHAR * write = dest; + + /* Subtract terminator */ + if (dest == NULL) { + *charsRequired = 0; + } else { + maxChars--; + } + + while (queryList != NULL) { + const URI_CHAR * const key = queryList->key; + const URI_CHAR * const value = queryList->value; + const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3); + const size_t keyLen = (key == NULL) ? 0 : URI_STRLEN(key); + int keyRequiredChars; + const size_t valueLen = (value == NULL) ? 0 : URI_STRLEN(value); + int valueRequiredChars; + + if ((keyLen >= (size_t)INT_MAX / worstCase) + || (valueLen >= (size_t)INT_MAX / worstCase)) { + return URI_ERROR_OUTPUT_TOO_LARGE; + } + keyRequiredChars = worstCase * (int)keyLen; + valueRequiredChars = worstCase * (int)valueLen; + + if (dest == NULL) { + (*charsRequired) += ampersandLen + keyRequiredChars + + ((value == NULL) ? 0 : 1 + valueRequiredChars); + + if (firstItem == URI_TRUE) { + ampersandLen = 1; + firstItem = URI_FALSE; + } + } else { + if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) { + return URI_ERROR_OUTPUT_TOO_LARGE; + } + + /* Copy key */ + if (firstItem == URI_TRUE) { + ampersandLen = 1; + firstItem = URI_FALSE; + } else { + write[0] = _UT('&'); + write++; + } + write = URI_FUNC(EscapeEx)(key, key + keyLen, write, spaceToPlus, + normalizeBreaks); + + if (value != NULL) { + if ((write - dest) + 1 + valueRequiredChars > maxChars) { + return URI_ERROR_OUTPUT_TOO_LARGE; + } + + /* Copy value */ + write[0] = _UT('='); + write++; + write = URI_FUNC(EscapeEx)(value, value + valueLen, write, spaceToPlus, + normalizeBreaks); + } + } + + queryList = queryList->next; + } + + if (dest != NULL) { + write[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = (int)(write - dest) + 1; /* .. for terminator */ + } + } + + return URI_SUCCESS; } - - -UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, - int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, - const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, - UriBool plusToSpace, UriBreakConversion breakConversion, - UriMemoryManager * memory) { - const int keyLen = (int)(keyAfter - keyFirst); - const int valueLen = (int)(valueAfter - valueFirst); - URI_CHAR * key; - URI_CHAR * value; - - if ((prevNext == NULL) || (itemCount == NULL) - || (keyFirst == NULL) || (keyAfter == NULL) - || (keyFirst > keyAfter) || (valueFirst > valueAfter) - || ((keyFirst == keyAfter) - && (valueFirst == NULL) && (valueAfter == NULL))) { - return URI_TRUE; - } - - /* Append new empty item */ - *prevNext = memory->malloc(memory, 1 * sizeof(URI_TYPE(QueryList))); - if (*prevNext == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - (*prevNext)->next = NULL; - - - /* Fill key */ - key = memory->malloc(memory, (keyLen + 1) * sizeof(URI_CHAR)); - if (key == NULL) { - memory->free(memory, *prevNext); - *prevNext = NULL; - return URI_FALSE; /* Raises malloc error */ - } - - key[keyLen] = _UT('\0'); - if (keyLen > 0) { - /* Copy 1:1 */ - memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR)); - - /* Unescape */ - URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion); - } - (*prevNext)->key = key; - - - /* Fill value */ - if (valueFirst != NULL) { - value = memory->malloc(memory, (valueLen + 1) * sizeof(URI_CHAR)); - if (value == NULL) { - memory->free(memory, key); - memory->free(memory, *prevNext); - *prevNext = NULL; - return URI_FALSE; /* Raises malloc error */ - } - - value[valueLen] = _UT('\0'); - if (valueLen > 0) { - /* Copy 1:1 */ - memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR)); - - /* Unescape */ - URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion); - } - (*prevNext)->value = value; - } else { - value = NULL; - } - (*prevNext)->value = value; - - (*itemCount)++; - return URI_TRUE; +UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) * *prevNext, int * itemCount, + const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, + const URI_CHAR * valueFirst, + const URI_CHAR * valueAfter, UriBool plusToSpace, + UriBreakConversion breakConversion, + UriMemoryManager * memory) { + const int keyLen = (int)(keyAfter - keyFirst); + const int valueLen = (int)(valueAfter - valueFirst); + URI_CHAR * key; + URI_CHAR * value; + + if ((prevNext == NULL) || (itemCount == NULL) || (keyFirst == NULL) + || (keyAfter == NULL) || (keyFirst > keyAfter) || (valueFirst > valueAfter) + || ((keyFirst == keyAfter) && (valueFirst == NULL) && (valueAfter == NULL))) { + return URI_TRUE; + } + + /* Append new empty item */ + *prevNext = memory->malloc(memory, 1 * sizeof(URI_TYPE(QueryList))); + if (*prevNext == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + (*prevNext)->next = NULL; + + /* Fill key */ + key = memory->malloc(memory, (keyLen + 1) * sizeof(URI_CHAR)); + if (key == NULL) { + memory->free(memory, *prevNext); + *prevNext = NULL; + return URI_FALSE; /* Raises malloc error */ + } + + key[keyLen] = _UT('\0'); + if (keyLen > 0) { + /* Copy 1:1 */ + memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR)); + + /* Unescape */ + URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion); + } + (*prevNext)->key = key; + + /* Fill value */ + if (valueFirst != NULL) { + value = memory->malloc(memory, (valueLen + 1) * sizeof(URI_CHAR)); + if (value == NULL) { + memory->free(memory, key); + memory->free(memory, *prevNext); + *prevNext = NULL; + return URI_FALSE; /* Raises malloc error */ + } + + value[valueLen] = _UT('\0'); + if (valueLen > 0) { + /* Copy 1:1 */ + memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR)); + + /* Unescape */ + URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion); + } + (*prevNext)->value = value; + } else { + value = NULL; + } + (*prevNext)->value = value; + + (*itemCount)++; + return URI_TRUE; } - - void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList) { - URI_FUNC(FreeQueryListMm)(queryList, NULL); + URI_FUNC(FreeQueryListMm)(queryList, NULL); } - - int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList, - UriMemoryManager * memory) { - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - while (queryList != NULL) { - URI_TYPE(QueryList) * nextBackup = queryList->next; - memory->free(memory, (URI_CHAR *)queryList->key); /* const cast */ - memory->free(memory, (URI_CHAR *)queryList->value); /* const cast */ - memory->free(memory, queryList); - queryList = nextBackup; - } - return URI_SUCCESS; + UriMemoryManager * memory) { + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + while (queryList != NULL) { + URI_TYPE(QueryList) * nextBackup = queryList->next; + memory->free(memory, (URI_CHAR *)queryList->key); /* const cast */ + memory->free(memory, (URI_CHAR *)queryList->value); /* const cast */ + memory->free(memory, queryList); + queryList = nextBackup; + } + return URI_SUCCESS; } +int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) * *dest, int * itemCount, + const URI_CHAR * first, const URI_CHAR * afterLast) { + const UriBool plusToSpace = URI_TRUE; + const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; - -int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount, - const URI_CHAR * first, const URI_CHAR * afterLast) { - const UriBool plusToSpace = URI_TRUE; - const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; - - return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast, - plusToSpace, breakConversion); + return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast, plusToSpace, + breakConversion); } - - -int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriBool plusToSpace, UriBreakConversion breakConversion) { - return URI_FUNC(DissectQueryMallocExMm)(dest, itemCount, first, afterLast, - plusToSpace, breakConversion, NULL); +int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) * *dest, int * itemCount, + const URI_CHAR * first, const URI_CHAR * afterLast, + UriBool plusToSpace, + UriBreakConversion breakConversion) { + return URI_FUNC(DissectQueryMallocExMm)(dest, itemCount, first, afterLast, + plusToSpace, breakConversion, NULL); } - - -int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, int * itemCount, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriBool plusToSpace, UriBreakConversion breakConversion, - UriMemoryManager * memory) { - const URI_CHAR * walk = first; - const URI_CHAR * keyFirst = first; - const URI_CHAR * keyAfter = NULL; - const URI_CHAR * valueFirst = NULL; - const URI_CHAR * valueAfter = NULL; - URI_TYPE(QueryList) ** prevNext = dest; - int nullCounter; - int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount; - - if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) { - return URI_ERROR_NULL; - } - - if (first > afterLast) { - return URI_ERROR_RANGE_INVALID; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - *dest = NULL; - *itemsAppended = 0; - - /* Parse query string */ - for (; walk < afterLast; walk++) { - switch (*walk) { - case _UT('&'): - if (valueFirst != NULL) { - valueAfter = walk; - } else { - keyAfter = walk; - } - - if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, - keyFirst, keyAfter, valueFirst, valueAfter, - plusToSpace, breakConversion, memory) - == URI_FALSE) { - /* Free list we built */ - *itemsAppended = 0; - URI_FUNC(FreeQueryListMm)(*dest, memory); - return URI_ERROR_MALLOC; - } - - /* Make future items children of the current */ - if ((prevNext != NULL) && (*prevNext != NULL)) { - prevNext = &((*prevNext)->next); - } - - if (walk + 1 < afterLast) { - keyFirst = walk + 1; - } else { - keyFirst = NULL; - } - keyAfter = NULL; - valueFirst = NULL; - valueAfter = NULL; - break; - - case _UT('='): - /* NOTE: WE treat the first '=' as a separator, */ - /* all following go into the value part */ - if (keyAfter == NULL) { - keyAfter = walk; - if (walk + 1 <= afterLast) { - valueFirst = walk + 1; - valueAfter = walk + 1; - } - } - break; - - default: - break; - } - } - - if (valueFirst != NULL) { - /* Must be key/value pair */ - valueAfter = walk; - } else { - /* Must be key only */ - keyAfter = walk; - } - - if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter, - valueFirst, valueAfter, plusToSpace, breakConversion, memory) - == URI_FALSE) { - /* Free list we built */ - *itemsAppended = 0; - URI_FUNC(FreeQueryListMm)(*dest, memory); - return URI_ERROR_MALLOC; - } - - return URI_SUCCESS; +int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) * *dest, int * itemCount, + const URI_CHAR * first, const URI_CHAR * afterLast, + UriBool plusToSpace, + UriBreakConversion breakConversion, + UriMemoryManager * memory) { + const URI_CHAR * walk = first; + const URI_CHAR * keyFirst = first; + const URI_CHAR * keyAfter = NULL; + const URI_CHAR * valueFirst = NULL; + const URI_CHAR * valueAfter = NULL; + URI_TYPE(QueryList) ** prevNext = dest; + int nullCounter; + int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount; + + if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) { + return URI_ERROR_NULL; + } + + if (first > afterLast) { + return URI_ERROR_RANGE_INVALID; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + *dest = NULL; + *itemsAppended = 0; + + /* Parse query string */ + for (; walk < afterLast; walk++) { + switch (*walk) { + case _UT('&'): + if (valueFirst != NULL) { + valueAfter = walk; + } else { + keyAfter = walk; + } + + if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter, + valueFirst, valueAfter, plusToSpace, + breakConversion, memory) + == URI_FALSE) { + /* Free list we built */ + *itemsAppended = 0; + URI_FUNC(FreeQueryListMm)(*dest, memory); + return URI_ERROR_MALLOC; + } + + /* Make future items children of the current */ + if ((prevNext != NULL) && (*prevNext != NULL)) { + prevNext = &((*prevNext)->next); + } + + if (walk + 1 < afterLast) { + keyFirst = walk + 1; + } else { + keyFirst = NULL; + } + keyAfter = NULL; + valueFirst = NULL; + valueAfter = NULL; + break; + + case _UT('='): + /* NOTE: WE treat the first '=' as a separator, */ + /* all following go into the value part */ + if (keyAfter == NULL) { + keyAfter = walk; + if (walk + 1 <= afterLast) { + valueFirst = walk + 1; + valueAfter = walk + 1; + } + } + break; + + default: + break; + } + } + + if (valueFirst != NULL) { + /* Must be key/value pair */ + valueAfter = walk; + } else { + /* Must be key only */ + keyAfter = walk; + } + + if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter, valueFirst, + valueAfter, plusToSpace, breakConversion, memory) + == URI_FALSE) { + /* Free list we built */ + *itemsAppended = 0; + URI_FUNC(FreeQueryListMm)(*dest, memory); + return URI_ERROR_MALLOC; + } + + return URI_SUCCESS; } - - #endif diff --git a/ext/uri/uriparser/src/UriRecompose.c b/ext/uri/uriparser/src/UriRecompose.c index 1567efc81dcbf..61ffee77248f1 100644 --- a/ext/uri/uriparser/src/UriRecompose.c +++ b/ext/uri/uriparser/src/UriRecompose.c @@ -41,537 +41,564 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriRecompose.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriRecompose.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriRecompose.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriRecompose.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -#endif - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# endif static int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, - int maxChars, int * charsWritten, int * charsRequired); - + int maxChars, int * charsWritten, + int * charsRequired); - -int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri, - int * charsRequired) { - const int MAX_CHARS = ((unsigned int)-1) >> 1; - return URI_FUNC(ToStringEngine)(NULL, uri, MAX_CHARS, NULL, charsRequired); +int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri, int * charsRequired) { + const int MAX_CHARS = ((unsigned int)-1) >> 1; + return URI_FUNC(ToStringEngine)(NULL, uri, MAX_CHARS, NULL, charsRequired); } - - -int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, - int maxChars, int * charsWritten) { - return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL); +int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, int maxChars, + int * charsWritten) { + return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL); } - - -static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest, - const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten, - int * charsRequired) { - int written = 0; - if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) { - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_NULL; - } - - if (maxChars < 1) { - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - maxChars--; /* So we don't have to subtract 1 for '\0' all the time */ - - /* [01/19] result = "" */ - if (dest != NULL) { - dest[0] = _UT('\0'); - } else { - (*charsRequired) = 0; - } - /* [02/19] if defined(scheme) then */ - if (uri->scheme.first != NULL) { - /* [03/19] append scheme to result; */ - const int charsToWrite - = (int)(uri->scheme.afterLast - uri->scheme.first); - if (dest != NULL) { - if (written + charsToWrite <= maxChars) { - memcpy(dest + written, uri->scheme.first, - charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += charsToWrite; - } - /* [04/19] append ":" to result; */ - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT(":"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1; - } - /* [05/19] endif; */ - } - /* [06/19] if defined(authority) then */ - if (URI_FUNC(HasHost)(uri)) { - /* [07/19] append "//" to result; */ - if (dest != NULL) { - if (written + 2 <= maxChars) { - memcpy(dest + written, _UT("//"), - 2 * sizeof(URI_CHAR)); - written += 2; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 2; - } - /* [08/19] append authority to result; */ - /* UserInfo */ - if (uri->userInfo.first != NULL) { - const int charsToWrite = (int)(uri->userInfo.afterLast - uri->userInfo.first); - if (dest != NULL) { - if (written + charsToWrite <= maxChars) { - memcpy(dest + written, uri->userInfo.first, - charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("@"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += charsToWrite + 1; - } - } - - /* Host */ - if (uri->hostData.ip4 != NULL) { - /* IPv4 */ - int i = 0; - for (; i < 4; i++) { - const unsigned char value = uri->hostData.ip4->data[i]; - const int charsToWrite = (value > 99) ? 3 : ((value > 9) ? 2 : 1); - if (dest != NULL) { - if (written + charsToWrite <= maxChars) { - URI_CHAR text[4]; - if (value > 99) { - text[0] = _UT('0') + (value / 100); - text[1] = _UT('0') + ((value % 100) / 10); - text[2] = _UT('0') + (value % 10); - } else if (value > 9) { - text[0] = _UT('0') + (value / 10); - text[1] = _UT('0') + (value % 10); - } else { - text[0] = _UT('0') + value; - } - text[charsToWrite] = _UT('\0'); - memcpy(dest + written, text, charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - if (i < 3) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("."), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } - } else { - (*charsRequired) += charsToWrite + ((i == 3) ? 0 : 1); - } - } - } else if (uri->hostData.ip6 != NULL) { - /* IPv6 */ - int i = 0; - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("["), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1; - } - - for (; i < 16; i++) { - const unsigned char value = uri->hostData.ip6->data[i]; - if (dest != NULL) { - if (written + 2 <= maxChars) { - URI_CHAR text[3]; - text[0] = URI_FUNC(HexToLetterEx)(value / 16, URI_FALSE); - text[1] = URI_FUNC(HexToLetterEx)(value % 16, URI_FALSE); - text[2] = _UT('\0'); - memcpy(dest + written, text, 2 * sizeof(URI_CHAR)); - written += 2; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 2; - } - if (((i & 1) == 1) && (i < 15)) { - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT(":"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1; - } - } - } - - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("]"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1; - } - } else if (uri->hostData.ipFuture.first != NULL) { - /* IPvFuture */ - const int charsToWrite = (int)(uri->hostData.ipFuture.afterLast - - uri->hostData.ipFuture.first); - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("["), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - - if (written + charsToWrite <= maxChars) { - memcpy(dest + written, uri->hostData.ipFuture.first, charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("]"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1 + charsToWrite + 1; - } - } else if (uri->hostText.first != NULL) { - /* Regname */ - const int charsToWrite = (int)(uri->hostText.afterLast - uri->hostText.first); - if (dest != NULL) { - if (written + charsToWrite <= maxChars) { - memcpy(dest + written, uri->hostText.first, - charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += charsToWrite; - } - } - - /* Port */ - if (uri->portText.first != NULL) { - const int charsToWrite = (int)(uri->portText.afterLast - uri->portText.first); - if (dest != NULL) { - /* Leading ':' */ - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT(":"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - - /* Port number */ - if (written + charsToWrite <= maxChars) { - memcpy(dest + written, uri->portText.first, - charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1 + charsToWrite; - } - } - /* [09/19] endif; */ - } - /* [10/19] append path to result; */ - /* Slash needed here? */ - if (uri->absolutePath || ((uri->pathHead != NULL) - && URI_FUNC(HasHost)(uri))) { - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("/"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1; - } - } - - if (uri->pathHead != NULL) { - URI_TYPE(PathSegment) * walker = uri->pathHead; - do { - const int charsToWrite = (int)(walker->text.afterLast - walker->text.first); - if (dest != NULL) { - if (written + charsToWrite <= maxChars) { - memcpy(dest + written, walker->text.first, - charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += charsToWrite; - } - - /* Not last segment -> append slash */ - if (walker->next != NULL) { - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("/"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1; - } - } - - walker = walker->next; - } while (walker != NULL); - } - /* [11/19] if defined(query) then */ - if (uri->query.first != NULL) { - /* [12/19] append "?" to result; */ - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("?"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1; - } - /* [13/19] append query to result; */ - { - const int charsToWrite - = (int)(uri->query.afterLast - uri->query.first); - if (dest != NULL) { - if (written + charsToWrite <= maxChars) { - memcpy(dest + written, uri->query.first, - charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += charsToWrite; - } - } - /* [14/19] endif; */ - } - /* [15/19] if defined(fragment) then */ - if (uri->fragment.first != NULL) { - /* [16/19] append "#" to result; */ - if (dest != NULL) { - if (written + 1 <= maxChars) { - memcpy(dest + written, _UT("#"), - 1 * sizeof(URI_CHAR)); - written += 1; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += 1; - } - /* [17/19] append fragment to result; */ - { - const int charsToWrite - = (int)(uri->fragment.afterLast - uri->fragment.first); - if (dest != NULL) { - if (written + charsToWrite <= maxChars) { - memcpy(dest + written, uri->fragment.first, - charsToWrite * sizeof(URI_CHAR)); - written += charsToWrite; - } else { - dest[0] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = 0; - } - return URI_ERROR_TOSTRING_TOO_LONG; - } - } else { - (*charsRequired) += charsToWrite; - } - } - /* [18/19] endif; */ - } - /* [19/19] return result; */ - if (dest != NULL) { - dest[written++] = _UT('\0'); - if (charsWritten != NULL) { - *charsWritten = written; - } - } - return URI_SUCCESS; +static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, + int maxChars, int * charsWritten, + int * charsRequired) { + int written = 0; + if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) { + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_NULL; + } + + if (maxChars < 1) { + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + maxChars--; /* So we don't have to subtract 1 for '\0' all the time */ + + /* NOTE: The curly brackets here force deeper indent (and that's all) */ + { + { + { + /* clang-format off */ + /* [01/19] result = "" */ + /* clang-format on */ + if (dest != NULL) { + dest[0] = _UT('\0'); + } else { + (*charsRequired) = 0; + } + /* clang-format off */ + /* [02/19] if defined(scheme) then */ + /* clang-format on */ + if (uri->scheme.first != NULL) { + /* clang-format off */ + /* [03/19] append scheme to result; */ + /* clang-format on */ + const int charsToWrite = + (int)(uri->scheme.afterLast - uri->scheme.first); + if (dest != NULL) { + if (written + charsToWrite <= maxChars) { + memcpy(dest + written, uri->scheme.first, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += charsToWrite; + } + /* clang-format off */ + /* [04/19] append ":" to result; */ + /* clang-format on */ + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1; + } + /* clang-format off */ + /* [05/19] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [06/19] if defined(authority) then */ + /* clang-format on */ + if (URI_FUNC(HasHost)(uri)) { + /* clang-format off */ + /* [07/19] append "//" to result; */ + /* clang-format on */ + if (dest != NULL) { + if (written + 2 <= maxChars) { + memcpy(dest + written, _UT("//"), 2 * sizeof(URI_CHAR)); + written += 2; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 2; + } + /* clang-format off */ + /* [08/19] append authority to result; */ + /* clang-format on */ + /* UserInfo */ + if (uri->userInfo.first != NULL) { + const int charsToWrite = + (int)(uri->userInfo.afterLast - uri->userInfo.first); + if (dest != NULL) { + if (written + charsToWrite <= maxChars) { + memcpy(dest + written, uri->userInfo.first, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("@"), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += charsToWrite + 1; + } + } + + /* Host */ + if (uri->hostData.ip4 != NULL) { + /* IPv4 */ + int i = 0; + for (; i < 4; i++) { + const unsigned char value = uri->hostData.ip4->data[i]; + const int charsToWrite = + (value > 99) ? 3 : ((value > 9) ? 2 : 1); + if (dest != NULL) { + if (written + charsToWrite <= maxChars) { + URI_CHAR text[4]; + if (value > 99) { + text[0] = _UT('0') + (value / 100); + text[1] = _UT('0') + ((value % 100) / 10); + text[2] = _UT('0') + (value % 10); + } else if (value > 9) { + text[0] = _UT('0') + (value / 10); + text[1] = _UT('0') + (value % 10); + } else { + text[0] = _UT('0') + value; + } + text[charsToWrite] = _UT('\0'); + memcpy(dest + written, text, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + if (i < 3) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("."), + 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } + } else { + (*charsRequired) += charsToWrite + ((i == 3) ? 0 : 1); + } + } + } else if (uri->hostData.ip6 != NULL) { + /* IPv6 */ + int i = 0; + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1; + } + + for (; i < 16; i++) { + const unsigned char value = uri->hostData.ip6->data[i]; + if (dest != NULL) { + if (written + 2 <= maxChars) { + URI_CHAR text[3]; + text[0] = + URI_FUNC(HexToLetterEx)(value / 16, URI_FALSE); + text[1] = + URI_FUNC(HexToLetterEx)(value % 16, URI_FALSE); + text[2] = _UT('\0'); + memcpy(dest + written, text, 2 * sizeof(URI_CHAR)); + written += 2; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 2; + } + if (((i & 1) == 1) && (i < 15)) { + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT(":"), + 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1; + } + } + } + + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1; + } + } else if (uri->hostData.ipFuture.first != NULL) { + /* IPvFuture */ + const int charsToWrite = (int)(uri->hostData.ipFuture.afterLast + - uri->hostData.ipFuture.first); + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + + if (written + charsToWrite <= maxChars) { + memcpy(dest + written, uri->hostData.ipFuture.first, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1 + charsToWrite + 1; + } + } else if (uri->hostText.first != NULL) { + /* Regname */ + const int charsToWrite = + (int)(uri->hostText.afterLast - uri->hostText.first); + if (dest != NULL) { + if (written + charsToWrite <= maxChars) { + memcpy(dest + written, uri->hostText.first, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += charsToWrite; + } + } + + /* Port */ + if (uri->portText.first != NULL) { + const int charsToWrite = + (int)(uri->portText.afterLast - uri->portText.first); + if (dest != NULL) { + /* Leading ':' */ + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + + /* Port number */ + if (written + charsToWrite <= maxChars) { + memcpy(dest + written, uri->portText.first, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1 + charsToWrite; + } + } + /* clang-format off */ + /* [09/19] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [10/19] append path to result; */ + /* clang-format on */ + /* Slash needed here? */ + if (uri->absolutePath + || ((uri->pathHead != NULL) && URI_FUNC(HasHost)(uri))) { + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("/"), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1; + } + } + + if (uri->pathHead != NULL) { + URI_TYPE(PathSegment) * walker = uri->pathHead; + do { + const int charsToWrite = + (int)(walker->text.afterLast - walker->text.first); + if (dest != NULL) { + if (written + charsToWrite <= maxChars) { + memcpy(dest + written, walker->text.first, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += charsToWrite; + } + + /* Not last segment -> append slash */ + if (walker->next != NULL) { + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("/"), + 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1; + } + } + + walker = walker->next; + } while (walker != NULL); + } + /* clang-format off */ + /* [11/19] if defined(query) then */ + /* clang-format on */ + if (uri->query.first != NULL) { + /* clang-format off */ + /* [12/19] append "?" to result; */ + /* clang-format on */ + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("?"), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1; + } + /* clang-format off */ + /* [13/19] append query to result; */ + /* clang-format on */ + const int charsToWrite = + (int)(uri->query.afterLast - uri->query.first); + if (dest != NULL) { + if (written + charsToWrite <= maxChars) { + memcpy(dest + written, uri->query.first, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += charsToWrite; + } + /* clang-format off */ + /* [14/19] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [15/19] if defined(fragment) then */ + /* clang-format on */ + if (uri->fragment.first != NULL) { + /* clang-format off */ + /* [16/19] append "#" to result; */ + /* clang-format on */ + if (dest != NULL) { + if (written + 1 <= maxChars) { + memcpy(dest + written, _UT("#"), 1 * sizeof(URI_CHAR)); + written += 1; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += 1; + } + /* clang-format off */ + /* [17/19] append fragment to result; */ + /* clang-format on */ + const int charsToWrite = + (int)(uri->fragment.afterLast - uri->fragment.first); + if (dest != NULL) { + if (written + charsToWrite <= maxChars) { + memcpy(dest + written, uri->fragment.first, + charsToWrite * sizeof(URI_CHAR)); + written += charsToWrite; + } else { + dest[0] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = 0; + } + return URI_ERROR_TOSTRING_TOO_LONG; + } + } else { + (*charsRequired) += charsToWrite; + } + /* clang-format off */ + /* [18/19] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [19/19] return result; */ + /* clang-format on */ + if (dest != NULL) { + dest[written++] = _UT('\0'); + if (charsWritten != NULL) { + *charsWritten = written; + } + } + return URI_SUCCESS; + } + } + } } - - #endif diff --git a/ext/uri/uriparser/src/UriResolve.c b/ext/uri/uriparser/src/UriResolve.c index 8e47e6af8c6f9..302665d21cd66 100644 --- a/ext/uri/uriparser/src/UriResolve.c +++ b/ext/uri/uriparser/src/UriResolve.c @@ -41,289 +41,358 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriResolve.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriResolve.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriResolve.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriResolve.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# endif /* Appends a relative URI to an absolute. The last path segment of * the absolute URI is replaced. */ static URI_INLINE UriBool URI_FUNC(MergePath)(URI_TYPE(Uri) * absWork, - const URI_TYPE(Uri) * relAppend, UriMemoryManager * memory) { - URI_TYPE(PathSegment) * sourceWalker; - URI_TYPE(PathSegment) * destPrev; - if (relAppend->pathHead == NULL) { - return URI_TRUE; - } - - /* Replace last segment ("" if trailing slash) with first of append chain */ - if (absWork->pathHead == NULL) { - URI_TYPE(PathSegment) * const dup = memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); - if (dup == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - dup->next = NULL; - absWork->pathHead = dup; - absWork->pathTail = dup; - } - absWork->pathTail->text.first = relAppend->pathHead->text.first; - absWork->pathTail->text.afterLast = relAppend->pathHead->text.afterLast; - - /* Append all the others */ - sourceWalker = relAppend->pathHead->next; - if (sourceWalker == NULL) { - return URI_TRUE; - } - destPrev = absWork->pathTail; - - for (;;) { - URI_TYPE(PathSegment) * const dup = memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); - if (dup == NULL) { - destPrev->next = NULL; - absWork->pathTail = destPrev; - return URI_FALSE; /* Raises malloc error */ - } - dup->text = sourceWalker->text; - destPrev->next = dup; - - if (sourceWalker->next == NULL) { - absWork->pathTail = dup; - absWork->pathTail->next = NULL; - break; - } - destPrev = dup; - sourceWalker = sourceWalker->next; - } - - return URI_TRUE; + const URI_TYPE(Uri) * relAppend, + UriMemoryManager * memory) { + URI_TYPE(PathSegment) * sourceWalker; + URI_TYPE(PathSegment) * destPrev; + if (relAppend->pathHead == NULL) { + return URI_TRUE; + } + + /* Replace last segment ("" if trailing slash) with first of append chain */ + if (absWork->pathHead == NULL) { + URI_TYPE(PathSegment) * const dup = + memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); + if (dup == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + dup->next = NULL; + absWork->pathHead = dup; + absWork->pathTail = dup; + } + absWork->pathTail->text.first = relAppend->pathHead->text.first; + absWork->pathTail->text.afterLast = relAppend->pathHead->text.afterLast; + + /* Append all the others */ + sourceWalker = relAppend->pathHead->next; + if (sourceWalker == NULL) { + return URI_TRUE; + } + destPrev = absWork->pathTail; + + for (;;) { + URI_TYPE(PathSegment) * const dup = + memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); + if (dup == NULL) { + destPrev->next = NULL; + absWork->pathTail = destPrev; + return URI_FALSE; /* Raises malloc error */ + } + dup->text = sourceWalker->text; + destPrev->next = dup; + + if (sourceWalker->next == NULL) { + absWork->pathTail = dup; + absWork->pathTail->next = NULL; + break; + } + destPrev = dup; + sourceWalker = sourceWalker->next; + } + + return URI_TRUE; } - static int URI_FUNC(ResolveAbsolutePathFlag)(URI_TYPE(Uri) * absWork, - UriMemoryManager * memory) { - if (absWork == NULL) { - return URI_ERROR_NULL; - } - - if (URI_FUNC(HasHost)(absWork) && absWork->absolutePath) { - /* Empty segment needed, instead? */ - if (absWork->pathHead == NULL) { - URI_TYPE(PathSegment) * const segment = memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); - if (segment == NULL) { - return URI_ERROR_MALLOC; - } - segment->text.first = URI_FUNC(SafeToPointTo); - segment->text.afterLast = URI_FUNC(SafeToPointTo); - segment->next = NULL; - - absWork->pathHead = segment; - absWork->pathTail = segment; - } - - absWork->absolutePath = URI_FALSE; - } - - return URI_SUCCESS; + UriMemoryManager * memory) { + if (absWork == NULL) { + return URI_ERROR_NULL; + } + + if (URI_FUNC(HasHost)(absWork) && absWork->absolutePath) { + /* Empty segment needed, instead? */ + if (absWork->pathHead == NULL) { + URI_TYPE(PathSegment) * const segment = + memory->malloc(memory, sizeof(URI_TYPE(PathSegment))); + if (segment == NULL) { + return URI_ERROR_MALLOC; + } + segment->text.first = URI_FUNC(SafeToPointTo); + segment->text.afterLast = URI_FUNC(SafeToPointTo); + segment->next = NULL; + + absWork->pathHead = segment; + absWork->pathTail = segment; + } + + absWork->absolutePath = URI_FALSE; + } + + return URI_SUCCESS; } - static int URI_FUNC(AddBaseUriImpl)(URI_TYPE(Uri) * absDest, - const URI_TYPE(Uri) * relSource, - const URI_TYPE(Uri) * absBase, - UriResolutionOptions options, UriMemoryManager * memory) { - UriBool relSourceHasScheme; - - if (absDest == NULL) { - return URI_ERROR_NULL; - } - URI_FUNC(ResetUri)(absDest); - - if ((relSource == NULL) || (absBase == NULL)) { - return URI_ERROR_NULL; - } - - /* absBase absolute? */ - if (absBase->scheme.first == NULL) { - return URI_ERROR_ADDBASE_REL_BASE; - } - - /* [00/32] -- A non-strict parser may ignore a scheme in the reference */ - /* [00/32] -- if it is identical to the base URI's scheme. */ - /* [00/32] if ((not strict) and (R.scheme == Base.scheme)) then */ - relSourceHasScheme = (relSource->scheme.first != NULL) ? URI_TRUE : URI_FALSE; - if ((options & URI_RESOLVE_IDENTICAL_SCHEME_COMPAT) - && (absBase->scheme.first != NULL) - && (relSource->scheme.first != NULL) - && (0 == URI_FUNC(CompareRange)(&(absBase->scheme), &(relSource->scheme)))) { - /* [00/32] undefine(R.scheme); */ - relSourceHasScheme = URI_FALSE; - /* [00/32] endif; */ - } - - /* [01/32] if defined(R.scheme) then */ - if (relSourceHasScheme) { - /* [02/32] T.scheme = R.scheme; */ - absDest->scheme = relSource->scheme; - /* [03/32] T.authority = R.authority; */ - if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) { - return URI_ERROR_MALLOC; - } - /* [04/32] T.path = remove_dot_segments(R.path); */ - if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) { - return URI_ERROR_MALLOC; - } - if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) { - return URI_ERROR_MALLOC; - } - /* [05/32] T.query = R.query; */ - absDest->query = relSource->query; - /* [06/32] else */ - } else { - /* [07/32] if defined(R.authority) then */ - if (URI_FUNC(HasHost)(relSource)) { - /* [08/32] T.authority = R.authority; */ - if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) { - return URI_ERROR_MALLOC; - } - /* [09/32] T.path = remove_dot_segments(R.path); */ - if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) { - return URI_ERROR_MALLOC; - } - if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) { - return URI_ERROR_MALLOC; - } - /* [10/32] T.query = R.query; */ - absDest->query = relSource->query; - /* [11/32] else */ - } else { - /* [28/32] T.authority = Base.authority; */ - if (!URI_FUNC(CopyAuthority)(absDest, absBase, memory)) { - return URI_ERROR_MALLOC; - } - /* [12/32] if (R.path == "") then */ - if (relSource->pathHead == NULL && !relSource->absolutePath) { - /* [13/32] T.path = Base.path; */ - if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) { - return URI_ERROR_MALLOC; - } - /* [14/32] if defined(R.query) then */ - if (relSource->query.first != NULL) { - /* [15/32] T.query = R.query; */ - absDest->query = relSource->query; - /* [16/32] else */ - } else { - /* [17/32] T.query = Base.query; */ - absDest->query = absBase->query; - /* [18/32] endif; */ - } - /* [19/32] else */ - } else { - /* [20/32] if (R.path starts-with "/") then */ - if (relSource->absolutePath) { - int res; - /* [21/32] T.path = remove_dot_segments(R.path); */ - if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) { - return URI_ERROR_MALLOC; - } - res = URI_FUNC(ResolveAbsolutePathFlag)(absDest, memory); - if (res != URI_SUCCESS) { - return res; - } - if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) { - return URI_ERROR_MALLOC; - } - /* [22/32] else */ - } else { - /* [23/32] T.path = merge(Base.path, R.path); */ - if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) { - return URI_ERROR_MALLOC; - } - if (!URI_FUNC(MergePath)(absDest, relSource, memory)) { - return URI_ERROR_MALLOC; - } - /* [24/32] T.path = remove_dot_segments(T.path); */ - if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) { - return URI_ERROR_MALLOC; - } - - if (!URI_FUNC(FixAmbiguity)(absDest, memory)) { - return URI_ERROR_MALLOC; - } - /* [25/32] endif; */ - } - /* [26/32] T.query = R.query; */ - absDest->query = relSource->query; - /* [27/32] endif; */ - } - URI_FUNC(FixEmptyTrailSegment)(absDest, memory); - /* [29/32] endif; */ - } - /* [30/32] T.scheme = Base.scheme; */ - absDest->scheme = absBase->scheme; - /* [31/32] endif; */ - } - /* [32/32] T.fragment = R.fragment; */ - absDest->fragment = relSource->fragment; - - return URI_SUCCESS; - + const URI_TYPE(Uri) * relSource, + const URI_TYPE(Uri) * absBase, + UriResolutionOptions options, + UriMemoryManager * memory) { + UriBool relSourceHasScheme; + + if (absDest == NULL) { + return URI_ERROR_NULL; + } + URI_FUNC(ResetUri)(absDest); + + if ((relSource == NULL) || (absBase == NULL)) { + return URI_ERROR_NULL; + } + + /* absBase absolute? */ + if (absBase->scheme.first == NULL) { + return URI_ERROR_ADDBASE_REL_BASE; + } + + /* NOTE: The curly brackets here force deeper indent (and that's all) */ + { + { + { + /* clang-format off */ + /* [00/32] -- A non-strict parser may ignore a scheme in the reference */ + /* [00/32] -- if it is identical to the base URI's scheme. */ + /* [00/32] if ((not strict) and (R.scheme == Base.scheme)) then */ + /* clang-format on */ + relSourceHasScheme = + (relSource->scheme.first != NULL) ? URI_TRUE : URI_FALSE; + if ((options & URI_RESOLVE_IDENTICAL_SCHEME_COMPAT) + && (absBase->scheme.first != NULL) + && (relSource->scheme.first != NULL) + && (0 + == URI_FUNC(CompareRange)(&(absBase->scheme), + &(relSource->scheme)))) { + /* clang-format off */ + /* [00/32] undefine(R.scheme); */ + /* clang-format on */ + relSourceHasScheme = URI_FALSE; + /* clang-format off */ + /* [00/32] endif; */ + /* clang-format on */ + } + + /* clang-format off */ + /* [01/32] if defined(R.scheme) then */ + /* clang-format on */ + if (relSourceHasScheme) { + /* clang-format off */ + /* [02/32] T.scheme = R.scheme; */ + /* clang-format on */ + absDest->scheme = relSource->scheme; + /* clang-format off */ + /* [03/32] T.authority = R.authority; */ + /* clang-format on */ + if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [04/32] T.path = remove_dot_segments(R.path); */ + /* clang-format on */ + if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) { + return URI_ERROR_MALLOC; + } + if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [05/32] T.query = R.query; */ + /* clang-format on */ + absDest->query = relSource->query; + /* clang-format off */ + /* [06/32] else */ + /* clang-format on */ + } else { + /* clang-format off */ + /* [07/32] if defined(R.authority) then */ + /* clang-format on */ + if (URI_FUNC(HasHost)(relSource)) { + /* clang-format off */ + /* [08/32] T.authority = R.authority; */ + /* clang-format on */ + if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [09/32] T.path = remove_dot_segments(R.path); */ + /* clang-format on */ + if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) { + return URI_ERROR_MALLOC; + } + if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [10/32] T.query = R.query; */ + /* clang-format on */ + absDest->query = relSource->query; + /* clang-format off */ + /* [11/32] else */ + /* clang-format on */ + } else { + /* clang-format off */ + /* [28/32] T.authority = Base.authority; */ + /* clang-format on */ + if (!URI_FUNC(CopyAuthority)(absDest, absBase, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [12/32] if (R.path == "") then */ + /* clang-format on */ + if (relSource->pathHead == NULL && !relSource->absolutePath) { + /* clang-format off */ + /* [13/32] T.path = Base.path; */ + /* clang-format on */ + if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [14/32] if defined(R.query) then */ + /* clang-format on */ + if (relSource->query.first != NULL) { + /* clang-format off */ + /* [15/32] T.query = R.query; */ + /* clang-format on */ + absDest->query = relSource->query; + /* clang-format off */ + /* [16/32] else */ + /* clang-format on */ + } else { + /* clang-format off */ + /* [17/32] T.query = Base.query; */ + /* clang-format on */ + absDest->query = absBase->query; + /* clang-format off */ + /* [18/32] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [19/32] else */ + /* clang-format on */ + } else { + /* clang-format off */ + /* [20/32] if (R.path starts-with "/") then */ + /* clang-format on */ + if (relSource->absolutePath) { + int res; + /* clang-format off */ + /* [21/32] T.path = remove_dot_segments(R.path); */ + /* clang-format on */ + if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) { + return URI_ERROR_MALLOC; + } + res = URI_FUNC(ResolveAbsolutePathFlag)(absDest, memory); + if (res != URI_SUCCESS) { + return res; + } + if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, + memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [22/32] else */ + /* clang-format on */ + } else { + /* clang-format off */ + /* [23/32] T.path = merge(Base.path, R.path); */ + /* clang-format on */ + if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) { + return URI_ERROR_MALLOC; + } + if (!URI_FUNC(MergePath)(absDest, relSource, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [24/32] T.path = remove_dot_segments(T.path); */ + /* clang-format on */ + if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, + memory)) { + return URI_ERROR_MALLOC; + } + + if (!URI_FUNC(FixAmbiguity)(absDest, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [25/32] endif; */ + } + /* clang-format off */ + /* [26/32] T.query = R.query; */ + /* clang-format on */ + absDest->query = relSource->query; + /* clang-format off */ + /* [27/32] endif; */ + /* clang-format on */ + } + URI_FUNC(FixEmptyTrailSegment)(absDest, memory); + /* clang-format off */ + /* [29/32] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [30/32] T.scheme = Base.scheme; */ + /* clang-format on */ + absDest->scheme = absBase->scheme; + /* clang-format off */ + /* [31/32] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [32/32] T.fragment = R.fragment; */ + /* clang-format on */ + absDest->fragment = relSource->fragment; + } + } + } + return URI_SUCCESS; } - - -int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absDest, - const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase) { - const UriResolutionOptions options = URI_RESOLVE_STRICTLY; - return URI_FUNC(AddBaseUriEx)(absDest, relSource, absBase, options); +int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absDest, const URI_TYPE(Uri) * relSource, + const URI_TYPE(Uri) * absBase) { + const UriResolutionOptions options = URI_RESOLVE_STRICTLY; + return URI_FUNC(AddBaseUriEx)(absDest, relSource, absBase, options); } - - -int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absDest, - const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase, - UriResolutionOptions options) { - return URI_FUNC(AddBaseUriExMm)(absDest, relSource, absBase, options, NULL); +int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absDest, const URI_TYPE(Uri) * relSource, + const URI_TYPE(Uri) * absBase, UriResolutionOptions options) { + return URI_FUNC(AddBaseUriExMm)(absDest, relSource, absBase, options, NULL); } +int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absDest, const URI_TYPE(Uri) * relSource, + const URI_TYPE(Uri) * absBase, UriResolutionOptions options, + UriMemoryManager * memory) { + int res; + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ -int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absDest, - const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase, - UriResolutionOptions options, UriMemoryManager * memory) { - int res; - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - res = URI_FUNC(AddBaseUriImpl)(absDest, relSource, absBase, options, memory); - if ((res != URI_SUCCESS) && (absDest != NULL)) { - URI_FUNC(FreeUriMembersMm)(absDest, memory); - } - return res; + res = URI_FUNC(AddBaseUriImpl)(absDest, relSource, absBase, options, memory); + if ((res != URI_SUCCESS) && (absDest != NULL)) { + URI_FUNC(FreeUriMembersMm)(absDest, memory); + } + return res; } - - #endif diff --git a/ext/uri/uriparser/src/UriSetFragment.c b/ext/uri/uriparser/src/UriSetFragment.c index f2327c1afa4d0..4479391d859dc 100644 --- a/ext/uri/uriparser/src/UriSetFragment.c +++ b/ext/uri/uriparser/src/UriSetFragment.c @@ -40,267 +40,135 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetFragment.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetFragment.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetFragment.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetFragment.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - - -#include - - - -#define URI_SET_DIGIT \ - _UT('0'): \ - case _UT('1'): \ - case _UT('2'): \ - case _UT('3'): \ - case _UT('4'): \ - case _UT('5'): \ - case _UT('6'): \ - case _UT('7'): \ - case _UT('8'): \ - case _UT('9') - - - -#define URI_SET_HEX_LETTER_UPPER \ - _UT('A'): \ - case _UT('B'): \ - case _UT('C'): \ - case _UT('D'): \ - case _UT('E'): \ - case _UT('F') - - - -#define URI_SET_HEX_LETTER_LOWER \ - _UT('a'): \ - case _UT('b'): \ - case _UT('c'): \ - case _UT('d'): \ - case _UT('e'): \ - case _UT('f') - - - -#define URI_SET_HEXDIG \ - URI_SET_DIGIT: \ - case URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER - - - -#define URI_SET_ALPHA \ - URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER: \ - case _UT('g'): \ - case _UT('G'): \ - case _UT('h'): \ - case _UT('H'): \ - case _UT('i'): \ - case _UT('I'): \ - case _UT('j'): \ - case _UT('J'): \ - case _UT('k'): \ - case _UT('K'): \ - case _UT('l'): \ - case _UT('L'): \ - case _UT('m'): \ - case _UT('M'): \ - case _UT('n'): \ - case _UT('N'): \ - case _UT('o'): \ - case _UT('O'): \ - case _UT('p'): \ - case _UT('P'): \ - case _UT('q'): \ - case _UT('Q'): \ - case _UT('r'): \ - case _UT('R'): \ - case _UT('s'): \ - case _UT('S'): \ - case _UT('t'): \ - case _UT('T'): \ - case _UT('u'): \ - case _UT('U'): \ - case _UT('v'): \ - case _UT('V'): \ - case _UT('w'): \ - case _UT('W'): \ - case _UT('x'): \ - case _UT('X'): \ - case _UT('y'): \ - case _UT('Y'): \ - case _UT('z'): \ - case _UT('Z') - - - -#define URI_SET_SUB_DELIMS \ - _UT('!'): \ - case _UT('$'): \ - case _UT('&'): \ - case _UT('\''): \ - case _UT('('): \ - case _UT(')'): \ - case _UT('*'): \ - case _UT('+'): \ - case _UT(','): \ - case _UT(';'): \ - case _UT('=') - - - -#define URI_SET_UNRESERVED \ - URI_SET_ALPHA: \ - case URI_SET_DIGIT: \ - case _UT('-'): \ - case _UT('.'): \ - case _UT('_'): \ - case _UT('~') - - - -UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first, const URI_CHAR * afterLast) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_FALSE; - } - - /* The related part of the grammar in RFC 3986 reads: - * - * fragment = *( pchar / "/" / "?" ) - * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - */ - while (first < afterLast) { - switch (first[0]) { - case URI_SET_UNRESERVED: - break; - - /* pct-encoded */ - case _UT('%'): - if (afterLast - first < 3) { - return URI_FALSE; - } - switch (first[1]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - switch (first[2]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - first += 2; - break; - - case URI_SET_SUB_DELIMS: - break; - - /* ":" / "@" and "/" / "?" */ - case _UT(':'): - case _UT('@'): - case _UT('/'): - case _UT('?'): - break; - - default: - return URI_FALSE; - } - - first++; - } - return URI_TRUE; +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriSets.h" +# endif + +# include + +UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first, + const URI_CHAR * afterLast) { + if ((first == NULL) || (afterLast == NULL)) { + return URI_FALSE; + } + + /* The related part of the grammar in RFC 3986 reads: + * + * fragment = *( pchar / "/" / "?" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + */ + while (first < afterLast) { + switch (first[0]) { + case URI_SET_PCHAR_WITHOUT_PERCENT(_UT): + break; + + /* pct-encoded */ + case _UT('%'): + if (afterLast - first < 3) { + return URI_FALSE; + } + switch (first[1]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + switch (first[2]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + first += 2; + break; + + case _UT('/'): + case _UT('?'): + break; + + default: + return URI_FALSE; + } + + first++; + } + return URI_TRUE; } - - -int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* Input validation (before making any changes) */ - if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - if ((first != NULL) && (URI_FUNC(IsWellFormedFragment)(first, afterLast) == URI_FALSE)) { - return URI_ERROR_SYNTAX; - } - - /* Clear old value */ - if ((uri->owner == URI_TRUE) && (uri->fragment.first != uri->fragment.afterLast)) { - memory->free(memory, (URI_CHAR *)uri->fragment.first); - } - uri->fragment.first = NULL; - uri->fragment.afterLast = NULL; - - /* Already done? */ - if (first == NULL) { - return URI_SUCCESS; - } - - assert(first != NULL); - - /* Ensure owned */ - if (uri->owner == URI_FALSE) { - const int res = URI_FUNC(MakeOwnerMm)(uri, memory); - if (res != URI_SUCCESS) { - return res; - } - } - - assert(uri->owner == URI_TRUE); - - /* Apply new value */ - { - URI_TYPE(TextRange) sourceRange; - sourceRange.first = first; - sourceRange.afterLast = afterLast; - - if (URI_FUNC(CopyRangeAsNeeded)(&uri->fragment, &sourceRange, memory) == URI_FALSE) { - return URI_ERROR_MALLOC; - } - } - - return URI_SUCCESS; +int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + /* Input validation (before making any changes) */ + if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + if ((first != NULL) + && (URI_FUNC(IsWellFormedFragment)(first, afterLast) == URI_FALSE)) { + return URI_ERROR_SYNTAX; + } + + /* Clear old value */ + if ((uri->owner == URI_TRUE) && (uri->fragment.first != uri->fragment.afterLast)) { + memory->free(memory, (URI_CHAR *)uri->fragment.first); + } + uri->fragment.first = NULL; + uri->fragment.afterLast = NULL; + + /* Already done? */ + if (first == NULL) { + return URI_SUCCESS; + } + + assert(first != NULL); + + /* Ensure owned */ + if (uri->owner == URI_FALSE) { + const int res = URI_FUNC(MakeOwnerMm)(uri, memory); + if (res != URI_SUCCESS) { + return res; + } + } + + assert(uri->owner == URI_TRUE); + + /* Apply new value */ + URI_TYPE(TextRange) sourceRange; + sourceRange.first = first; + sourceRange.afterLast = afterLast; + + if (URI_FUNC(CopyRangeAsNeeded)(&uri->fragment, &sourceRange, memory) == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + return URI_SUCCESS; } - - -int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetFragmentMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetFragmentMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetHostAuto.c b/ext/uri/uriparser/src/UriSetHostAuto.c index 66ade6a5365bb..df015880b33f6 100644 --- a/ext/uri/uriparser/src/UriSetHostAuto.c +++ b/ext/uri/uriparser/src/UriSetHostAuto.c @@ -40,100 +40,85 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetHostAuto.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetHostAuto.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetHostAuto.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetHostAuto.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriSetHostBase.h" -# include "UriSetHostCommon.h" -# include "UriMemory.h" -#endif - - - -#include - - - -int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - if ((first == NULL) || (first >= afterLast)) { - return URI_FUNC(SetHostRegNameMm)(uri, first, afterLast, memory); - } - - /* Auto-detect type and then apply */ - { - UriHostType hostType; - - /* IPv6 or IPvFuture? */ - if (first[0] == _UT('[')) { - if ((afterLast - first < 2) || (afterLast[-1] != _UT(']'))) { - return URI_ERROR_SYNTAX; - } - - /* Drop the bracket wrap (for InternalSetHostMm call below) */ - first++; - afterLast--; - - if (first >= afterLast) { - return URI_ERROR_SYNTAX; - } - - switch (first[0]) { - case _UT('v'): - case _UT('V'): - hostType = URI_HOST_TYPE_IPFUTURE; - break; - default: - hostType = URI_HOST_TYPE_IP6; - break; - } - /* IPv4? */ - } else if (URI_FUNC(IsWellFormedHostIp4)(first, afterLast)) { - hostType = URI_HOST_TYPE_IP4; - } else { - /* RegName! */ - hostType = URI_HOST_TYPE_REGNAME; - } - - return URI_FUNC(InternalSetHostMm)(uri, hostType, first, afterLast, memory); - } +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriSetHostBase.h" +# include "UriSetHostCommon.h" +# include "UriMemory.h" +# endif + +# include + +int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + if ((first == NULL) || (first >= afterLast)) { + return URI_FUNC(SetHostRegNameMm)(uri, first, afterLast, memory); + } + + /* Auto-detect type and then apply */ + UriHostType hostType; + + /* IPv6 or IPvFuture? */ + if (first[0] == _UT('[')) { + if ((afterLast - first < 2) || (afterLast[-1] != _UT(']'))) { + return URI_ERROR_SYNTAX; + } + + /* Drop the bracket wrap (for InternalSetHostMm call below) */ + first++; + afterLast--; + + if (first >= afterLast) { + return URI_ERROR_SYNTAX; + } + + switch (first[0]) { + case _UT('v'): + case _UT('V'): + hostType = URI_HOST_TYPE_IPFUTURE; + break; + default: + hostType = URI_HOST_TYPE_IP6; + break; + } + /* IPv4? */ + } else if (URI_FUNC(IsWellFormedHostIp4)(first, afterLast)) { + hostType = URI_HOST_TYPE_IP4; + } else { + /* RegName! */ + hostType = URI_HOST_TYPE_REGNAME; + } + + return URI_FUNC(InternalSetHostMm)(uri, hostType, first, afterLast, memory); } - - -int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetHostAutoMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetHostAutoMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetHostBase.h b/ext/uri/uriparser/src/UriSetHostBase.h index 79b643cc0c4b0..081db36f219de 100644 --- a/ext/uri/uriparser/src/UriSetHostBase.h +++ b/ext/uri/uriparser/src/UriSetHostBase.h @@ -37,9 +37,7 @@ */ #ifndef URI_SET_HOST_BASE_H -#define URI_SET_HOST_BASE_H 1 - - +# define URI_SET_HOST_BASE_H 1 typedef enum UriHostTypeEnum { URI_HOST_TYPE_IP4, @@ -48,6 +46,4 @@ typedef enum UriHostTypeEnum { URI_HOST_TYPE_REGNAME } UriHostType; - - #endif /* URI_SET_HOST_BASE_H */ diff --git a/ext/uri/uriparser/src/UriSetHostCommon.c b/ext/uri/uriparser/src/UriSetHostCommon.c index 343db849dfff2..bd8095aea3cfa 100644 --- a/ext/uri/uriparser/src/UriSetHostCommon.c +++ b/ext/uri/uriparser/src/UriSetHostCommon.c @@ -46,221 +46,203 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetHostCommon.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetHostCommon.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetHostCommon.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetHostCommon.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include -# include "UriCommon.h" -# include "UriMemory.h" -# include "UriSetHostBase.h" -# include "UriSetHostCommon.h" -#endif - - - -#include - - - -int URI_FUNC(InternalSetHostMm)(URI_TYPE(Uri) * uri, - UriHostType hostType, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* Superficial input validation (before making any changes) */ - if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - /* The RFC 3986 grammar reads: - * authority = [ userinfo "@" ] host [ ":" port ] - * So no user info or port without a host. */ - if (first == NULL) { - if (uri->userInfo.first != NULL) { - return URI_ERROR_SETHOST_USERINFO_SET; - } else if (uri->portText.first != NULL) { - return URI_ERROR_SETHOST_PORT_SET; - } - } - - /* Syntax-check the new value */ - if (first != NULL) { - switch (hostType) { - case URI_HOST_TYPE_IP4: - if (URI_FUNC(IsWellFormedHostIp4)(first, afterLast) == URI_FALSE) { - return URI_ERROR_SYNTAX; - } - break; - case URI_HOST_TYPE_IP6: - { - const int res = URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, memory); - assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC)); - if (res != URI_SUCCESS) { - return res; - } - } - break; - case URI_HOST_TYPE_IPFUTURE: - { - const int res = URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, memory); - assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC)); - if (res != URI_SUCCESS) { - return res; - } - } - break; - case URI_HOST_TYPE_REGNAME: - if (URI_FUNC(IsWellFormedHostRegName)(first, afterLast) == URI_FALSE) { - return URI_ERROR_SYNTAX; - } - break; - default: - assert(0 && "Unsupported URI host type"); - } - } - - { - /* Clear old value */ - const UriBool hadHostBefore = URI_FUNC(HasHost)(uri); - if (uri->hostData.ipFuture.first != NULL) { - /* NOTE: .hostData.ipFuture holds the very same range pointers - * as .hostText; we must not free memory twice. */ - uri->hostText.first = NULL; - uri->hostText.afterLast = NULL; - - if ((uri->owner == URI_TRUE) && (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast)) { - memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first); - } - uri->hostData.ipFuture.first = NULL; - uri->hostData.ipFuture.afterLast = NULL; - } else if (uri->hostText.first != NULL) { - if ((uri->owner == URI_TRUE) && (uri->hostText.first != uri->hostText.afterLast)) { - memory->free(memory, (URI_CHAR *)uri->hostText.first); - } - uri->hostText.first = NULL; - uri->hostText.afterLast = NULL; - } - - if (uri->hostData.ip4 != NULL) { - memory->free(memory, uri->hostData.ip4); - uri->hostData.ip4 = NULL; - } else if (uri->hostData.ip6 != NULL) { - memory->free(memory, uri->hostData.ip6); - uri->hostData.ip6 = NULL; - } - - /* Already done setting? */ - if (first == NULL) { - /* Yes, but disambiguate as needed */ - if (hadHostBefore == URI_TRUE) { - uri->absolutePath = URI_TRUE; - - { - const UriBool success = URI_FUNC(EnsureThatPathIsNotMistakenForHost)(uri, memory); - return (success == URI_TRUE) - ? URI_SUCCESS - : URI_ERROR_MALLOC; - } - } - - return URI_SUCCESS; - } - } - - assert(first != NULL); - - /* Ensure owned */ - if (uri->owner == URI_FALSE) { - const int res = URI_FUNC(MakeOwnerMm)(uri, memory); - if (res != URI_SUCCESS) { - return res; - } - } - - assert(uri->owner == URI_TRUE); - - /* Apply new value; NOTE that .hostText is set for all four host types */ - { - URI_TYPE(TextRange) sourceRange; - sourceRange.first = first; - sourceRange.afterLast = afterLast; - - if (URI_FUNC(CopyRangeAsNeeded)(&uri->hostText, &sourceRange, memory) == URI_FALSE) { - return URI_ERROR_MALLOC; - } - - uri->absolutePath = URI_FALSE; /* always URI_FALSE for URIs with host */ - - /* Fill .hostData as needed */ - switch (hostType) { - case URI_HOST_TYPE_IP4: - { - uri->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4)); - if (uri->hostData.ip4 == NULL) { - return URI_ERROR_MALLOC; - } - - { - const int res = URI_FUNC(ParseIpFourAddress)(uri->hostData.ip4->data, first, afterLast); -#if defined(NDEBUG) - (void)res; /* i.e. mark as unused */ -#else - assert(res == URI_SUCCESS); /* because checked for well-formedness earlier */ -#endif - } - } - break; - case URI_HOST_TYPE_IP6: - { - uri->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6)); - if (uri->hostData.ip6 == NULL) { - return URI_ERROR_MALLOC; - } - - { - const int res = URI_FUNC(ParseIpSixAddressMm)(uri->hostData.ip6, first, afterLast, memory); - assert((res == URI_SUCCESS) || (res == URI_ERROR_MALLOC)); /* because checked for well-formedness earlier */ - if (res != URI_SUCCESS) { - return res; - } - } - } - break; - case URI_HOST_TYPE_IPFUTURE: - uri->hostData.ipFuture.first = uri->hostText.first; - uri->hostData.ipFuture.afterLast = uri->hostText.afterLast; - break; - case URI_HOST_TYPE_REGNAME: - break; - default: - assert(0 && "Unsupported URI host type"); - } - } - - return URI_SUCCESS; +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriSetHostBase.h" +# include "UriSetHostCommon.h" +# endif + +# include + +int URI_FUNC(InternalSetHostMm)(URI_TYPE(Uri) * uri, UriHostType hostType, + const URI_CHAR * first, const URI_CHAR * afterLast, + UriMemoryManager * memory) { + /* Superficial input validation (before making any changes) */ + if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + /* The RFC 3986 grammar reads: + * authority = [ userinfo "@" ] host [ ":" port ] + * So no user info or port without a host. */ + if (first == NULL) { + if (uri->userInfo.first != NULL) { + return URI_ERROR_SETHOST_USERINFO_SET; + } else if (uri->portText.first != NULL) { + return URI_ERROR_SETHOST_PORT_SET; + } + } + + /* Syntax-check the new value */ + if (first != NULL) { + switch (hostType) { + case URI_HOST_TYPE_IP4: + if (URI_FUNC(IsWellFormedHostIp4)(first, afterLast) == URI_FALSE) { + return URI_ERROR_SYNTAX; + } + break; + case URI_HOST_TYPE_IP6: { + const int res = URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, memory); + assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) + || (res == URI_ERROR_MALLOC)); + if (res != URI_SUCCESS) { + return res; + } + } break; + case URI_HOST_TYPE_IPFUTURE: { + const int res = + URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, memory); + assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) + || (res == URI_ERROR_MALLOC)); + if (res != URI_SUCCESS) { + return res; + } + } break; + case URI_HOST_TYPE_REGNAME: + if (URI_FUNC(IsWellFormedHostRegName)(first, afterLast) == URI_FALSE) { + return URI_ERROR_SYNTAX; + } + break; + default: + assert(0 && "Unsupported URI host type"); + } + } + + /* Clear old value */ + const UriBool hadHostBefore = URI_FUNC(HasHost)(uri); + if (uri->hostData.ipFuture.first != NULL) { + /* NOTE: .hostData.ipFuture holds the very same range pointers + * as .hostText; we must not free memory twice. */ + uri->hostText.first = NULL; + uri->hostText.afterLast = NULL; + + if ((uri->owner == URI_TRUE) + && (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast)) { + memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first); + } + uri->hostData.ipFuture.first = NULL; + uri->hostData.ipFuture.afterLast = NULL; + } else if (uri->hostText.first != NULL) { + if ((uri->owner == URI_TRUE) + && (uri->hostText.first != uri->hostText.afterLast)) { + memory->free(memory, (URI_CHAR *)uri->hostText.first); + } + uri->hostText.first = NULL; + uri->hostText.afterLast = NULL; + } + + if (uri->hostData.ip4 != NULL) { + memory->free(memory, uri->hostData.ip4); + uri->hostData.ip4 = NULL; + } else if (uri->hostData.ip6 != NULL) { + memory->free(memory, uri->hostData.ip6); + uri->hostData.ip6 = NULL; + } + + /* Already done setting? */ + if (first == NULL) { + /* Yes, but disambiguate as needed */ + if (hadHostBefore == URI_TRUE) { + if (uri->pathHead != NULL) { + uri->absolutePath = URI_TRUE; + } + + const UriBool success = + URI_FUNC(EnsureThatPathIsNotMistakenForHost)(uri, memory); + return (success == URI_TRUE) ? URI_SUCCESS : URI_ERROR_MALLOC; + } + + return URI_SUCCESS; + } + + assert(first != NULL); + + /* Ensure owned */ + if (uri->owner == URI_FALSE) { + const int res = URI_FUNC(MakeOwnerMm)(uri, memory); + if (res != URI_SUCCESS) { + return res; + } + } + + assert(uri->owner == URI_TRUE); + + /* Apply new value; NOTE that .hostText is set for all four host types */ + URI_TYPE(TextRange) sourceRange; + sourceRange.first = first; + sourceRange.afterLast = afterLast; + + if (URI_FUNC(CopyRangeAsNeeded)(&uri->hostText, &sourceRange, memory) == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + uri->absolutePath = URI_FALSE; /* always URI_FALSE for URIs with host */ + + /* Fill .hostData as needed */ + switch (hostType) { + case URI_HOST_TYPE_IP4: { + uri->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4)); + if (uri->hostData.ip4 == NULL) { + return URI_ERROR_MALLOC; + } + + const int res = + URI_FUNC(ParseIpFourAddress)(uri->hostData.ip4->data, first, afterLast); +# if defined(NDEBUG) + (void)res; /* i.e. mark as unused */ +# else + assert(res == URI_SUCCESS); /* because checked for well-formedness earlier */ +# endif + } break; + case URI_HOST_TYPE_IP6: { + uri->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6)); + if (uri->hostData.ip6 == NULL) { + return URI_ERROR_MALLOC; + } + + const int res = + URI_FUNC(ParseIpSixAddressMm)(uri->hostData.ip6, first, afterLast, memory); + assert((res == URI_SUCCESS) + || (res == URI_ERROR_MALLOC)); /* because checked for + well-formedness earlier */ + if (res != URI_SUCCESS) { + return res; + } + } break; + case URI_HOST_TYPE_IPFUTURE: + uri->hostData.ipFuture.first = uri->hostText.first; + uri->hostData.ipFuture.afterLast = uri->hostText.afterLast; + break; + case URI_HOST_TYPE_REGNAME: + break; + default: + assert(0 && "Unsupported URI host type"); + } + + return URI_SUCCESS; } - - #endif diff --git a/ext/uri/uriparser/src/UriSetHostCommon.h b/ext/uri/uriparser/src/UriSetHostCommon.h index 1914d8480eb4a..6627767f2caf5 100644 --- a/ext/uri/uriparser/src/UriSetHostCommon.h +++ b/ext/uri/uriparser/src/UriSetHostCommon.h @@ -37,43 +37,38 @@ */ #if (defined(URI_PASS_ANSI) && !defined(URI_SET_HOST_COMMON_H_ANSI)) \ - || (defined(URI_PASS_UNICODE) && !defined(URI_SET_HOST_COMMON_H_UNICODE)) \ - || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) + || (defined(URI_PASS_UNICODE) && !defined(URI_SET_HOST_COMMON_H_UNICODE)) \ + || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* What encodings are enabled? */ -#include -#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) +# include +# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetHostCommon.h" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetHostCommon.h" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetHostCommon.h" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetHostCommon.h" +# undef URI_PASS_UNICODE +# endif /* Only one pass for each encoding */ -#elif (defined(URI_PASS_ANSI) && !defined(URI_SET_HOST_COMMON_H_ANSI) \ - && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \ - && !defined(URI_SET_HOST_COMMON_H_UNICODE) && defined(URI_ENABLE_UNICODE)) -# ifdef URI_PASS_ANSI -# define URI_SET_HOST_COMMON_H_ANSI 1 -# include -# else -# define URI_SET_HOST_COMMON_H_UNICODE 1 -# include -# endif +# elif (defined(URI_PASS_ANSI) && !defined(URI_SET_HOST_COMMON_H_ANSI) \ + && defined(URI_ENABLE_ANSI)) \ + || (defined(URI_PASS_UNICODE) && !defined(URI_SET_HOST_COMMON_H_UNICODE) \ + && defined(URI_ENABLE_UNICODE)) +# ifdef URI_PASS_ANSI +# define URI_SET_HOST_COMMON_H_ANSI 1 +# include +# else +# define URI_SET_HOST_COMMON_H_UNICODE 1 +# include +# endif +int URI_FUNC(InternalSetHostMm)(URI_TYPE(Uri) * uri, UriHostType hostType, + const URI_CHAR * first, const URI_CHAR * afterLast, + UriMemoryManager * memory); - -int URI_FUNC(InternalSetHostMm)(URI_TYPE(Uri) * uri, - UriHostType hostType, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory); - - - -#endif +# endif #endif diff --git a/ext/uri/uriparser/src/UriSetHostIp4.c b/ext/uri/uriparser/src/UriSetHostIp4.c index e07e249c23d2a..e52880be4c421 100644 --- a/ext/uri/uriparser/src/UriSetHostIp4.c +++ b/ext/uri/uriparser/src/UriSetHostIp4.c @@ -40,66 +40,52 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetHostIp4.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetHostIp4.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetHostIp4.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetHostIp4.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include -# include "UriMemory.h" -# include "UriSetHostBase.h" -# include "UriSetHostCommon.h" -#endif - - - -UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first, const URI_CHAR * afterLast) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_FALSE; - } - - { - unsigned char octetOutput[4]; - return (URI_FUNC(ParseIpFourAddress)(octetOutput, first, afterLast) == URI_SUCCESS) - ? URI_TRUE - : URI_FALSE; - } +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include +# include "UriMemory.h" +# include "UriSetHostBase.h" +# include "UriSetHostCommon.h" +# endif + +UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first, + const URI_CHAR * afterLast) { + if ((first == NULL) || (afterLast == NULL)) { + return URI_FALSE; + } + + unsigned char octetOutput[4]; + return (URI_FUNC(ParseIpFourAddress)(octetOutput, first, afterLast) == URI_SUCCESS) + ? URI_TRUE + : URI_FALSE; } - - -int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IP4, first, afterLast, memory); +int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IP4, first, afterLast, memory); } - - -int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetHostIp4Mm)(uri, first, afterLast, NULL); +int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetHostIp4Mm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetHostIp6.c b/ext/uri/uriparser/src/UriSetHostIp6.c index f99365558ff0b..9637a4384b232 100644 --- a/ext/uri/uriparser/src/UriSetHostIp6.c +++ b/ext/uri/uriparser/src/UriSetHostIp6.c @@ -40,143 +40,119 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetHostIp6.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetHostIp6.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetHostIp6.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetHostIp6.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriMemory.h" -# include "UriSetHostBase.h" -# include "UriSetHostCommon.h" -#endif - - - -#include -#include /* for memcpy */ - - - -#define URI_MAX_IP6_LEN (8 * 4 + 7 * 1) /* i.e. 8 full quads plus 7 colon separators */ - - - -int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* NOTE: output is allowed to be NULL */ - if ((first == NULL) || (afterLast == NULL)) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - /* Are we dealing with potential IPvFuture input? */ - if (first < afterLast) { - switch (first[0]) { - case _UT('v'): - case _UT('V'): - return URI_ERROR_SYNTAX; - default: - break; - } - } - - /* Are we dealing with IPv6 input? */ - { - /* Assemble "//[..]" input wrap for upcoming parse as a URI - * NOTE: If the input contains closing "]" on its own, the resulting - * string will not be valid URI syntax, and hence there is - * no risk of false positives from "bracket injection". */ - URI_CHAR candidate[3 + URI_MAX_IP6_LEN + 1 + 1] = _UT("//["); - const size_t inputLenChars = (afterLast - first); - - /* Detect overflow */ - if (inputLenChars > URI_MAX_IP6_LEN) { - return URI_ERROR_SYNTAX; - } - - memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR)); - memcpy(candidate + 3 + inputLenChars, _UT("]"), 2 * sizeof(URI_CHAR)); /* includes zero terminator */ - - /* Parse as an RFC 3986 URI */ - { - const size_t candidateLenChars = 3 + inputLenChars + 1; - URI_TYPE(Uri) uri; - const int res = URI_FUNC(ParseSingleUriExMm)(&uri, candidate, candidate + candidateLenChars, NULL, memory); - - assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC)); - - if (res == URI_SUCCESS) { - assert(uri.hostData.ip6 != NULL); - - if (output != NULL) { - memcpy(output->data, uri.hostData.ip6->data, sizeof(output->data)); - } - - URI_FUNC(FreeUriMembersMm)(&uri, memory); - } - - return res; - } - } +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriMemory.h" +# include "UriSetHostBase.h" +# include "UriSetHostCommon.h" +# endif + +# include +# include /* for memcpy */ + +# define URI_MAX_IP6_LEN \ + (8 * 4 + 7 * 1) /* i.e. 8 full quads plus 7 colon separators \ + */ + +int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + /* NOTE: output is allowed to be NULL */ + if ((first == NULL) || (afterLast == NULL)) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + /* Are we dealing with potential IPvFuture input? */ + if (first < afterLast) { + switch (first[0]) { + case _UT('v'): + case _UT('V'): + return URI_ERROR_SYNTAX; + default: + break; + } + } + + /* Are we dealing with IPv6 input? */ + /* Assemble "//[..]" input wrap for upcoming parse as a URI + * NOTE: If the input contains closing "]" on its own, the resulting + * string will not be valid URI syntax, and hence there is + * no risk of false positives from "bracket injection". */ + URI_CHAR candidate[3 + URI_MAX_IP6_LEN + 1 + 1] = _UT("//["); + const size_t inputLenChars = (afterLast - first); + + /* Detect overflow */ + if (inputLenChars > URI_MAX_IP6_LEN) { + return URI_ERROR_SYNTAX; + } + + memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR)); + memcpy(candidate + 3 + inputLenChars, _UT("]"), + 2 * sizeof(URI_CHAR)); /* includes zero terminator */ + + /* Parse as an RFC 3986 URI */ + const size_t candidateLenChars = 3 + inputLenChars + 1; + URI_TYPE(Uri) uri; + const int res = URI_FUNC(ParseSingleUriExMm)( + &uri, candidate, candidate + candidateLenChars, NULL, memory); + + assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) + || (res == URI_ERROR_MALLOC)); + + if (res == URI_SUCCESS) { + assert(uri.hostData.ip6 != NULL); + + if (output != NULL) { + memcpy(output->data, uri.hostData.ip6->data, sizeof(output->data)); + } + + URI_FUNC(FreeUriMembersMm)(&uri, memory); + } + + return res; } - - -int URI_FUNC(ParseIpSixAddress)(UriIp6 * output, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(ParseIpSixAddressMm)(output, first, afterLast, NULL); +int URI_FUNC(ParseIpSixAddress)(UriIp6 * output, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(ParseIpSixAddressMm)(output, first, afterLast, NULL); } - - -int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory) { +int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * afterLast, + UriMemoryManager * memory) { return URI_FUNC(ParseIpSixAddressMm)(NULL, first, afterLast, memory); } - - int URI_FUNC(IsWellFormedHostIp6)(const URI_CHAR * first, const URI_CHAR * afterLast) { - return URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, NULL); + return URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, NULL); } - - -int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IP6, first, afterLast, memory); +int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IP6, first, afterLast, memory); } - - -int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetHostIp6Mm)(uri, first, afterLast, NULL); +int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetHostIp6Mm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetHostIpFuture.c b/ext/uri/uriparser/src/UriSetHostIpFuture.c index aa84a82f4fe68..c5044c49c76fc 100644 --- a/ext/uri/uriparser/src/UriSetHostIpFuture.c +++ b/ext/uri/uriparser/src/UriSetHostIpFuture.c @@ -40,135 +40,118 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetHostIpFuture.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetHostIpFuture.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetHostIpFuture.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetHostIpFuture.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriMemory.h" -# include "UriSetHostBase.h" -# include "UriSetHostCommon.h" -#endif - - - -#include -#include /* for memcpy */ - - - -int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - /* Are we dealing with potential IPv6 input? */ - if (first < afterLast) { - switch (first[0]) { - case _UT('v'): - case _UT('V'): - break; - default: - return URI_ERROR_SYNTAX; - } - } - - /* Are we dealing with IPvFuture input? */ - { - /* Assemble "//[..]" input wrap for upcoming parse as a URI - * NOTE: If the input contains closing "]" on its own, the resulting - * string will not be valid URI syntax, and hence there is - * no risk of false positives from "bracket injection". */ - const size_t inputLenChars = (afterLast - first); - const size_t MAX_SIZE_T = (size_t)-1; - - /* Detect overflow */ - if (MAX_SIZE_T - inputLenChars < 3 + 1 + 1) { - return URI_ERROR_MALLOC; - } - - { - const size_t candidateLenChars = 3 + inputLenChars + 1; - - /* Detect overflow */ - if (MAX_SIZE_T / sizeof(URI_CHAR) < candidateLenChars + 1) { - return URI_ERROR_MALLOC; - } - - { - URI_CHAR * const candidate = memory->malloc(memory, (candidateLenChars + 1) * sizeof(URI_CHAR)); - - if (candidate == NULL) { - return URI_ERROR_MALLOC; - } - - memcpy(candidate, _UT("//["), 3 * sizeof(URI_CHAR)); - memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR)); - memcpy(candidate + 3 + inputLenChars, _UT("]"), 2 * sizeof(URI_CHAR)); /* includes zero terminator */ - - /* Parse as an RFC 3986 URI */ - { - URI_TYPE(Uri) uri; - const int res = URI_FUNC(ParseSingleUriExMm)(&uri, candidate, candidate + candidateLenChars, NULL, memory); - - assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC)); - - if (res == URI_SUCCESS) { - assert(uri.hostData.ipFuture.first != NULL); - URI_FUNC(FreeUriMembersMm)(&uri, memory); - } - - memory->free(memory, candidate); - - return res; - } - } - } - } +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriMemory.h" +# include "UriSetHostBase.h" +# include "UriSetHostCommon.h" +# endif + +# include +# include /* for memcpy */ + +int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + if ((first == NULL) || (afterLast == NULL)) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + /* Are we dealing with potential IPv6 input? */ + if (first < afterLast) { + switch (first[0]) { + case _UT('v'): + case _UT('V'): + break; + default: + return URI_ERROR_SYNTAX; + } + } + + /* Are we dealing with IPvFuture input? */ + /* Assemble "//[..]" input wrap for upcoming parse as a URI + * NOTE: If the input contains closing "]" on its own, the resulting + * string will not be valid URI syntax, and hence there is + * no risk of false positives from "bracket injection". */ + const size_t inputLenChars = (afterLast - first); + const size_t MAX_SIZE_T = (size_t)-1; + + /* Detect overflow */ + if (MAX_SIZE_T - inputLenChars < 3 + 1 + 1) { + return URI_ERROR_MALLOC; + } + + const size_t candidateLenChars = 3 + inputLenChars + 1; + + /* Detect overflow */ + if (MAX_SIZE_T / sizeof(URI_CHAR) < candidateLenChars + 1) { + return URI_ERROR_MALLOC; + } + + URI_CHAR * const candidate = + memory->malloc(memory, (candidateLenChars + 1) * sizeof(URI_CHAR)); + + if (candidate == NULL) { + return URI_ERROR_MALLOC; + } + + memcpy(candidate, _UT("//["), 3 * sizeof(URI_CHAR)); + memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR)); + memcpy(candidate + 3 + inputLenChars, _UT("]"), + 2 * sizeof(URI_CHAR)); /* includes zero terminator */ + + /* Parse as an RFC 3986 URI */ + URI_TYPE(Uri) uri; + const int res = URI_FUNC(ParseSingleUriExMm)( + &uri, candidate, candidate + candidateLenChars, NULL, memory); + + assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) + || (res == URI_ERROR_MALLOC)); + + if (res == URI_SUCCESS) { + assert(uri.hostData.ipFuture.first != NULL); + URI_FUNC(FreeUriMembersMm)(&uri, memory); + } + + memory->free(memory, candidate); + + return res; } - - -int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first, const URI_CHAR * afterLast) { - return URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, NULL); +int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, NULL); } - - -int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IPFUTURE, first, afterLast, memory); +int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IPFUTURE, first, afterLast, + memory); } - - -int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetHostIpFutureMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetHostIpFutureMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetHostRegName.c b/ext/uri/uriparser/src/UriSetHostRegName.c index d09e2e98e3616..01bc4e47f16ef 100644 --- a/ext/uri/uriparser/src/UriSetHostRegName.c +++ b/ext/uri/uriparser/src/UriSetHostRegName.c @@ -40,207 +40,85 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetHostRegName.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetHostRegName.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetHostRegName.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetHostRegName.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriMemory.h" -# include "UriSetHostBase.h" -# include "UriSetHostCommon.h" -#endif - - - -#define URI_SET_DIGIT \ - _UT('0'): \ - case _UT('1'): \ - case _UT('2'): \ - case _UT('3'): \ - case _UT('4'): \ - case _UT('5'): \ - case _UT('6'): \ - case _UT('7'): \ - case _UT('8'): \ - case _UT('9') - - - -#define URI_SET_HEX_LETTER_UPPER \ - _UT('A'): \ - case _UT('B'): \ - case _UT('C'): \ - case _UT('D'): \ - case _UT('E'): \ - case _UT('F') - - - -#define URI_SET_HEX_LETTER_LOWER \ - _UT('a'): \ - case _UT('b'): \ - case _UT('c'): \ - case _UT('d'): \ - case _UT('e'): \ - case _UT('f') - - - -#define URI_SET_HEXDIG \ - URI_SET_DIGIT: \ - case URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER - - - -#define URI_SET_ALPHA \ - URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER: \ - case _UT('g'): \ - case _UT('G'): \ - case _UT('h'): \ - case _UT('H'): \ - case _UT('i'): \ - case _UT('I'): \ - case _UT('j'): \ - case _UT('J'): \ - case _UT('k'): \ - case _UT('K'): \ - case _UT('l'): \ - case _UT('L'): \ - case _UT('m'): \ - case _UT('M'): \ - case _UT('n'): \ - case _UT('N'): \ - case _UT('o'): \ - case _UT('O'): \ - case _UT('p'): \ - case _UT('P'): \ - case _UT('q'): \ - case _UT('Q'): \ - case _UT('r'): \ - case _UT('R'): \ - case _UT('s'): \ - case _UT('S'): \ - case _UT('t'): \ - case _UT('T'): \ - case _UT('u'): \ - case _UT('U'): \ - case _UT('v'): \ - case _UT('V'): \ - case _UT('w'): \ - case _UT('W'): \ - case _UT('x'): \ - case _UT('X'): \ - case _UT('y'): \ - case _UT('Y'): \ - case _UT('z'): \ - case _UT('Z') - - - -#define URI_SET_SUB_DELIMS \ - _UT('!'): \ - case _UT('$'): \ - case _UT('&'): \ - case _UT('\''): \ - case _UT('('): \ - case _UT(')'): \ - case _UT('*'): \ - case _UT('+'): \ - case _UT(','): \ - case _UT(';'): \ - case _UT('=') - - - -#define URI_SET_UNRESERVED \ - URI_SET_ALPHA: \ - case URI_SET_DIGIT: \ - case _UT('-'): \ - case _UT('.'): \ - case _UT('_'): \ - case _UT('~') - - - -UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, const URI_CHAR * afterLast) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_FALSE; - } - - /* reg-name = *( unreserved / pct-encoded / sub-delims ) */ - while (first < afterLast) { - switch (first[0]) { - case URI_SET_UNRESERVED: - break; - - /* pct-encoded */ - case _UT('%'): - if (afterLast - first < 3) { - return URI_FALSE; - } - switch (first[1]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - switch (first[2]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - first += 2; - break; - - case URI_SET_SUB_DELIMS: - break; - - default: - return URI_FALSE; - } - - first++; - } - return URI_TRUE; +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriMemory.h" +# include "UriSetHostBase.h" +# include "UriSetHostCommon.h" +# include "UriSets.h" +# endif + +UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, + const URI_CHAR * afterLast) { + if ((first == NULL) || (afterLast == NULL)) { + return URI_FALSE; + } + + /* reg-name = *( unreserved / pct-encoded / sub-delims ) */ + while (first < afterLast) { + switch (first[0]) { + case URI_SET_UNRESERVED(_UT): + break; + + /* pct-encoded */ + case _UT('%'): + if (afterLast - first < 3) { + return URI_FALSE; + } + switch (first[1]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + switch (first[2]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + first += 2; + break; + + case URI_SET_SUB_DELIMS(_UT): + break; + + default: + return URI_FALSE; + } + + first++; + } + return URI_TRUE; } - - -int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_REGNAME, first, afterLast, memory); +int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_REGNAME, first, afterLast, + memory); } - - -int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetHostRegNameMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetHostRegNameMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetPath.c b/ext/uri/uriparser/src/UriSetPath.c index abd783b3c65ae..17aef0fca42d4 100644 --- a/ext/uri/uriparser/src/UriSetPath.c +++ b/ext/uri/uriparser/src/UriSetPath.c @@ -40,456 +40,304 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetPath.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetPath.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetPath.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetPath.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - - -#include - - - -#define URI_SET_DIGIT \ - _UT('0'): \ - case _UT('1'): \ - case _UT('2'): \ - case _UT('3'): \ - case _UT('4'): \ - case _UT('5'): \ - case _UT('6'): \ - case _UT('7'): \ - case _UT('8'): \ - case _UT('9') - - - -#define URI_SET_HEX_LETTER_UPPER \ - _UT('A'): \ - case _UT('B'): \ - case _UT('C'): \ - case _UT('D'): \ - case _UT('E'): \ - case _UT('F') - - - -#define URI_SET_HEX_LETTER_LOWER \ - _UT('a'): \ - case _UT('b'): \ - case _UT('c'): \ - case _UT('d'): \ - case _UT('e'): \ - case _UT('f') - - - -#define URI_SET_HEXDIG \ - URI_SET_DIGIT: \ - case URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER - - - -#define URI_SET_ALPHA \ - URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER: \ - case _UT('g'): \ - case _UT('G'): \ - case _UT('h'): \ - case _UT('H'): \ - case _UT('i'): \ - case _UT('I'): \ - case _UT('j'): \ - case _UT('J'): \ - case _UT('k'): \ - case _UT('K'): \ - case _UT('l'): \ - case _UT('L'): \ - case _UT('m'): \ - case _UT('M'): \ - case _UT('n'): \ - case _UT('N'): \ - case _UT('o'): \ - case _UT('O'): \ - case _UT('p'): \ - case _UT('P'): \ - case _UT('q'): \ - case _UT('Q'): \ - case _UT('r'): \ - case _UT('R'): \ - case _UT('s'): \ - case _UT('S'): \ - case _UT('t'): \ - case _UT('T'): \ - case _UT('u'): \ - case _UT('U'): \ - case _UT('v'): \ - case _UT('V'): \ - case _UT('w'): \ - case _UT('W'): \ - case _UT('x'): \ - case _UT('X'): \ - case _UT('y'): \ - case _UT('Y'): \ - case _UT('z'): \ - case _UT('Z') - - - -#define URI_SET_SUB_DELIMS \ - _UT('!'): \ - case _UT('$'): \ - case _UT('&'): \ - case _UT('\''): \ - case _UT('('): \ - case _UT(')'): \ - case _UT('*'): \ - case _UT('+'): \ - case _UT(','): \ - case _UT(';'): \ - case _UT('=') - - - -#define URI_SET_UNRESERVED \ - URI_SET_ALPHA: \ - case URI_SET_DIGIT: \ - case _UT('-'): \ - case _UT('.'): \ - case _UT('_'): \ - case _UT('~') - - - -UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, const URI_CHAR * afterLast, UriBool hasHost) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_FALSE; - } - - if ((hasHost == URI_TRUE) && ((first >= afterLast) || (first[0] != _UT('/')))) { - return URI_FALSE; - } - - /* The related part of the grammar in RFC 3986 (section 3.3) reads: - * - * path = path-abempty ; begins with "/" or is empty - * / path-absolute ; begins with "/" but not "//" - * / path-noscheme ; begins with a non-colon segment - * / path-rootless ; begins with a segment - * / path-empty ; zero characters - * - * path-abempty = *( "/" segment ) - * path-absolute = "/" [ segment-nz *( "/" segment ) ] - * path-noscheme = segment-nz-nc *( "/" segment ) - * path-rootless = segment-nz *( "/" segment ) - * path-empty = 0 - * - * segment = *pchar - * segment-nz = 1*pchar - * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) - * ; non-zero-length segment without any colon ":" - * - * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - * - * The check below simplifies this to .. - * - * path = *( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" ) - * - * .. and leaves the rest to pre-return removal of ambiguity - * from cases like "path1:/path2" and "//path1/path2" inside SetPath. - */ - while (first < afterLast) { - switch (first[0]) { - case URI_SET_UNRESERVED: - break; - - /* pct-encoded */ - case _UT('%'): - if (afterLast - first < 3) { - return URI_FALSE; - } - switch (first[1]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - switch (first[2]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - first += 2; - break; - - case URI_SET_SUB_DELIMS: - break; - - /* ":" / "@" and "/" */ - case _UT(':'): - case _UT('@'): - case _UT('/'): - break; - - default: - return URI_FALSE; - } - - first++; - } - return URI_TRUE; +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriSets.h" +# endif + +# include + +UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, const URI_CHAR * afterLast, + UriBool hasHost) { + if ((first == NULL) || (afterLast == NULL)) { + return URI_FALSE; + } + + if ((hasHost == URI_TRUE) && ((first >= afterLast) || (first[0] != _UT('/')))) { + return URI_FALSE; + } + + /* The related part of the grammar in RFC 3986 (section 3.3) reads: + * + * path = path-abempty ; begins with "/" or is empty + * / path-absolute ; begins with "/" but not "//" + * / path-noscheme ; begins with a non-colon segment + * / path-rootless ; begins with a segment + * / path-empty ; zero characters + * + * path-abempty = *( "/" segment ) + * path-absolute = "/" [ segment-nz *( "/" segment ) ] + * path-noscheme = segment-nz-nc *( "/" segment ) + * path-rootless = segment-nz *( "/" segment ) + * path-empty = 0 + * + * segment = *pchar + * segment-nz = 1*pchar + * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + * ; non-zero-length segment without any colon ":" + * + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * + * The check below simplifies this to .. + * + * path = *( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" ) + * + * .. and leaves the rest to pre-return removal of ambiguity + * from cases like "path1:/path2" and "//path1/path2" inside SetPath. + */ + while (first < afterLast) { + switch (first[0]) { + case URI_SET_PCHAR_WITHOUT_PERCENT(_UT): + break; + + /* pct-encoded */ + case _UT('%'): + if (afterLast - first < 3) { + return URI_FALSE; + } + switch (first[1]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + switch (first[2]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + first += 2; + break; + + case _UT('/'): + break; + + default: + return URI_FALSE; + } + + first++; + } + return URI_TRUE; } +static void URI_FUNC(DropEmptyFirstPathSegment)(URI_TYPE(Uri) * uri, + UriMemoryManager * memory) { + assert(uri != NULL); + assert(memory != NULL); + assert(uri->pathHead != NULL); + assert(uri->pathHead->text.first == uri->pathHead->text.afterLast); + URI_TYPE(PathSegment) * const originalHead = uri->pathHead; -static void URI_FUNC(DropEmptyFirstPathSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { - assert(uri != NULL); - assert(memory != NULL); - assert(uri->pathHead != NULL); - assert(uri->pathHead->text.first == uri->pathHead->text.afterLast); - - { - URI_TYPE(PathSegment) * const originalHead = uri->pathHead; + uri->pathHead = uri->pathHead->next; - uri->pathHead = uri->pathHead->next; - - originalHead->text.first = NULL; - originalHead->text.afterLast = NULL; - memory->free(memory, originalHead); - } + originalHead->text.first = NULL; + originalHead->text.afterLast = NULL; + memory->free(memory, originalHead); } - - /* URIs without a host encode a leading slash in the path as .absolutePath == URI_TRUE. - * This function checks for a leading empty path segment (that would have the "visual effect" - * of a leading slash during stringification) and transforms it into .absolutePath == URI_TRUE - * instead, if present. */ -static void URI_FUNC(TransformEmptyLeadPathSegments)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { - assert(uri != NULL); - assert(memory != NULL); + * This function checks for a leading empty path segment (that would have the "visual + * effect" of a leading slash during stringification) and transforms it into .absolutePath + * == URI_TRUE instead, if present. */ +static void URI_FUNC(TransformEmptyLeadPathSegments)(URI_TYPE(Uri) * uri, + UriMemoryManager * memory) { + assert(uri != NULL); + assert(memory != NULL); - if ((URI_FUNC(HasHost)(uri) == URI_TRUE) - || (uri->pathHead == NULL) - || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) { - return; /* i.e. nothing to do */ - } + if ((URI_FUNC(HasHost)(uri) == URI_TRUE) || (uri->pathHead == NULL) + || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) { + return; /* i.e. nothing to do */ + } - assert(uri->absolutePath == URI_FALSE); + assert(uri->absolutePath == URI_FALSE); - URI_FUNC(DropEmptyFirstPathSegment)(uri, memory); + URI_FUNC(DropEmptyFirstPathSegment)(uri, memory); - uri->absolutePath = URI_TRUE; + uri->absolutePath = URI_TRUE; } - - -static int URI_FUNC(InternalSetPath)(URI_TYPE(Uri) * destUri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - assert(destUri != NULL); - assert(first != NULL); - assert(afterLast != NULL); - assert(memory != NULL); - assert(destUri->pathHead == NULL); /* set by SetPathMm right before */ - assert(destUri->pathTail == NULL); /* set by SetPathMm right before */ - assert(destUri->absolutePath == URI_FALSE); /* set by SetPathMm right before */ - - /* Skip the leading slash from target URIs with a host (so that we can - * transfer the path 1:1 further down) */ - if (URI_FUNC(HasHost)(destUri) == URI_TRUE) { - /* NOTE: This is because SetPathMm called IsWellFormedPath earlier: */ - assert((afterLast - first >= 1) && (first[0] == _UT('/'))); - first++; - } else if (first == afterLast) { - /* This avoids (1) all the expensive but unnecessary work below - * and also (2) mis-encoding as single empty path segment - * that would need (detection and) repair further down otherwise */ - return URI_SUCCESS; - } - - /* Assemble "///.." input wrap for upcoming parse as a URI */ - { - const size_t inputLenChars = (afterLast - first); - const size_t MAX_SIZE_T = (size_t)-1; - - /* Detect overflow */ - if (MAX_SIZE_T - inputLenChars < 3 + 1) { - return URI_ERROR_MALLOC; - } - - { - const size_t candidateLenChars = 3 + inputLenChars; - - /* Detect overflow */ - if (MAX_SIZE_T / sizeof(URI_CHAR) < candidateLenChars + 1) { - return URI_ERROR_MALLOC; - } - - { - URI_CHAR * const candidate = memory->malloc(memory, (candidateLenChars + 1) * sizeof(URI_CHAR)); - - if (candidate == NULL) { - return URI_ERROR_MALLOC; - } - - memcpy(candidate, _UT("///"), 3 * sizeof(URI_CHAR)); - memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR)); - candidate[3 + inputLenChars] = _UT('\0'); - - /* Parse as an RFC 3986 URI */ - { - URI_TYPE(Uri) tempUri; - const int res = URI_FUNC(ParseSingleUriExMm)(&tempUri, - candidate, - candidate + candidateLenChars, - NULL, - memory); - assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC)); - if (res != URI_SUCCESS) { - memory->free(memory, candidate); - return res; - } - - /* Nothing but path and host is supposed to be set by the parse, in particular not: */ - assert(tempUri.query.first == NULL); - assert(tempUri.fragment.first == NULL); - - /* Ensure that the strings in the path segments are all owned by `tempUri` - * because we want to (1) rip out and keep the full path list further down - * and (2) be able to free the parsed string (`candidate`) also. */ - { - const int res = URI_FUNC(MakeOwnerMm)(&tempUri, memory); - assert((res == URI_SUCCESS) || (res == URI_ERROR_MALLOC)); - if (res != URI_SUCCESS) { - URI_FUNC(FreeUriMembersMm)(&tempUri, memory); - memory->free(memory, candidate); - return res; - } - assert(tempUri.owner == URI_TRUE); - } - - /* Move path to destination URI */ - assert(tempUri.absolutePath == URI_FALSE); /* always URI_FALSE for URIs with host */ - destUri->pathHead = tempUri.pathHead; - destUri->pathTail = tempUri.pathTail; - destUri->absolutePath = URI_FALSE; - - tempUri.pathHead = NULL; - tempUri.pathTail = NULL; - - /* Free the rest of the temp URI */ - URI_FUNC(FreeUriMembersMm)(&tempUri, memory); - memory->free(memory, candidate); - - /* Restore use of .absolutePath as needed */ - URI_FUNC(TransformEmptyLeadPathSegments)(destUri, memory); - - /* Disambiguate as needed */ - { - const UriBool success = URI_FUNC(FixPathNoScheme)(destUri, memory); - if (success == URI_FALSE) { - return URI_ERROR_MALLOC; - } - } - { - const UriBool success = URI_FUNC(EnsureThatPathIsNotMistakenForHost)(destUri, memory); - if (success == URI_FALSE) { - return URI_ERROR_MALLOC; - } - } - } - } - } - } - - return URI_SUCCESS; +static int URI_FUNC(InternalSetPath)(URI_TYPE(Uri) * destUri, const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + assert(destUri != NULL); + assert(first != NULL); + assert(afterLast != NULL); + assert(memory != NULL); + assert(destUri->pathHead == NULL); /* set by SetPathMm right before */ + assert(destUri->pathTail == NULL); /* set by SetPathMm right before */ + assert(destUri->absolutePath == URI_FALSE); /* set by SetPathMm right before */ + + /* Skip the leading slash from target URIs with a host (so that we can + * transfer the path 1:1 further down) */ + if (URI_FUNC(HasHost)(destUri) == URI_TRUE) { + /* NOTE: This is because SetPathMm called IsWellFormedPath earlier: */ + assert((afterLast - first >= 1) && (first[0] == _UT('/'))); + first++; + } else if (first == afterLast) { + /* This avoids (1) all the expensive but unnecessary work below + * and also (2) mis-encoding as single empty path segment + * that would need (detection and) repair further down otherwise */ + return URI_SUCCESS; + } + + /* Assemble "///.." input wrap for upcoming parse as a URI */ + const size_t inputLenChars = (afterLast - first); + const size_t MAX_SIZE_T = (size_t)-1; + + /* Detect overflow */ + if (MAX_SIZE_T - inputLenChars < 3 + 1) { + return URI_ERROR_MALLOC; + } + + const size_t candidateLenChars = 3 + inputLenChars; + + /* Detect overflow */ + if (MAX_SIZE_T / sizeof(URI_CHAR) < candidateLenChars + 1) { + return URI_ERROR_MALLOC; + } + + URI_CHAR * const candidate = + memory->malloc(memory, (candidateLenChars + 1) * sizeof(URI_CHAR)); + + if (candidate == NULL) { + return URI_ERROR_MALLOC; + } + + memcpy(candidate, _UT("///"), 3 * sizeof(URI_CHAR)); + memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR)); + candidate[3 + inputLenChars] = _UT('\0'); + + /* Parse as an RFC 3986 URI */ + URI_TYPE(Uri) tempUri; + int res = URI_FUNC(ParseSingleUriExMm)(&tempUri, candidate, + candidate + candidateLenChars, NULL, memory); + assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) + || (res == URI_ERROR_MALLOC)); + if (res != URI_SUCCESS) { + memory->free(memory, candidate); + return res; + } + + /* Nothing but path and host is supposed to be set by the parse, in + * particular not: */ + assert(tempUri.query.first == NULL); + assert(tempUri.fragment.first == NULL); + + /* Ensure that the strings in the path segments are all owned by + * `tempUri` because we want to (1) rip out and keep the full path + * list further down and (2) be able to free the parsed string + * (`candidate`) also. */ + res = URI_FUNC(MakeOwnerMm)(&tempUri, memory); + assert((res == URI_SUCCESS) || (res == URI_ERROR_MALLOC)); + if (res != URI_SUCCESS) { + URI_FUNC(FreeUriMembersMm)(&tempUri, memory); + memory->free(memory, candidate); + return res; + } + assert(tempUri.owner == URI_TRUE); + + /* Move path to destination URI */ + assert(tempUri.absolutePath == URI_FALSE); /* always URI_FALSE for URIs with host */ + destUri->pathHead = tempUri.pathHead; + destUri->pathTail = tempUri.pathTail; + destUri->absolutePath = URI_FALSE; + + tempUri.pathHead = NULL; + tempUri.pathTail = NULL; + + /* Free the rest of the temp URI */ + URI_FUNC(FreeUriMembersMm)(&tempUri, memory); + memory->free(memory, candidate); + + /* Restore use of .absolutePath as needed */ + URI_FUNC(TransformEmptyLeadPathSegments)(destUri, memory); + + /* Disambiguate as needed */ + UriBool success = URI_FUNC(FixPathNoScheme)(destUri, memory); + if (success == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + success = URI_FUNC(EnsureThatPathIsNotMistakenForHost)(destUri, memory); + if (success == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + return URI_SUCCESS; } - - -int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* Input validation (before making any changes) */ - if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - if ((first != NULL) && (URI_FUNC(IsWellFormedPath)(first, afterLast, URI_FUNC(HasHost)(uri)) == URI_FALSE)) { - return URI_ERROR_SYNTAX; - } - - /* Clear old value */ - { - const int res = URI_FUNC(FreeUriPath)(uri, memory); - if (res != URI_SUCCESS) { - return res; - } - uri->absolutePath = URI_FALSE; - } - - /* Already done? */ - if (first == NULL) { - return URI_SUCCESS; - } - - assert(first != NULL); - - /* Ensure owned */ - if (uri->owner == URI_FALSE) { - const int res = URI_FUNC(MakeOwnerMm)(uri, memory); - if (res != URI_SUCCESS) { - return res; - } - } - - assert(uri->owner == URI_TRUE); - - /* Apply new value */ - { - const int res = URI_FUNC(InternalSetPath)(uri, first, afterLast, memory); - assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC)); - return res; - } +int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + /* Input validation (before making any changes) */ + if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + if ((first != NULL) + && (URI_FUNC(IsWellFormedPath)(first, afterLast, URI_FUNC(HasHost)(uri)) + == URI_FALSE)) { + return URI_ERROR_SYNTAX; + } + + /* Clear old value */ + int res = URI_FUNC(FreeUriPath)(uri, memory); + if (res != URI_SUCCESS) { + return res; + } + uri->absolutePath = URI_FALSE; + + /* Already done? */ + if (first == NULL) { + return URI_SUCCESS; + } + + assert(first != NULL); + + /* Ensure owned */ + if (uri->owner == URI_FALSE) { + res = URI_FUNC(MakeOwnerMm)(uri, memory); + if (res != URI_SUCCESS) { + return res; + } + } + + assert(uri->owner == URI_TRUE); + + /* Apply new value */ + res = URI_FUNC(InternalSetPath)(uri, first, afterLast, memory); + assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) + || (res == URI_ERROR_MALLOC)); + return res; } - - -int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetPathMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetPathMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetPort.c b/ext/uri/uriparser/src/UriSetPort.c index 3331b717e21e7..5e2160e309765 100644 --- a/ext/uri/uriparser/src/UriSetPort.c +++ b/ext/uri/uriparser/src/UriSetPort.c @@ -40,140 +40,110 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetPort.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetPort.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetPort.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetPort.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - - -#include - - - -#define URI_SET_DIGIT \ - _UT('0'): \ - case _UT('1'): \ - case _UT('2'): \ - case _UT('3'): \ - case _UT('4'): \ - case _UT('5'): \ - case _UT('6'): \ - case _UT('7'): \ - case _UT('8'): \ - case _UT('9') - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriSets.h" +# endif + +# include UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first, const URI_CHAR * afterLast) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_FALSE; - } - - /* NOTE: Grammar reads "port = *DIGIT" which includes the empty string. */ - while (first < afterLast) { - switch (first[0]) { - case URI_SET_DIGIT: - break; - default: - return URI_FALSE; - } - first++; - } - return URI_TRUE; + if ((first == NULL) || (afterLast == NULL)) { + return URI_FALSE; + } + + /* NOTE: Grammar reads "port = *DIGIT" which includes the empty string. */ + while (first < afterLast) { + switch (first[0]) { + case URI_SET_DIGIT(_UT): + break; + default: + return URI_FALSE; + } + first++; + } + return URI_TRUE; } - - -int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* Input validation (before making any changes) */ - if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - /* The RFC 3986 grammar reads: - * authority = [ userinfo "@" ] host [ ":" port ] - * So no port without a host. */ - if ((first != NULL) && (URI_FUNC(HasHost)(uri) == URI_FALSE)) { - return URI_ERROR_SETPORT_HOST_NOT_SET; - } - - if ((first != NULL) && (URI_FUNC(IsWellFormedPort)(first, afterLast) == URI_FALSE)) { - return URI_ERROR_SYNTAX; - } - - /* Clear old value */ - if ((uri->owner == URI_TRUE) && (uri->portText.first != uri->portText.afterLast)) { - memory->free(memory, (URI_CHAR *)uri->portText.first); - } - uri->portText.first = NULL; - uri->portText.afterLast = NULL; - - /* Already done? */ - if (first == NULL) { - return URI_SUCCESS; - } - - assert(first != NULL); - - /* Ensure owned */ - if (uri->owner == URI_FALSE) { - const int res = URI_FUNC(MakeOwnerMm)(uri, memory); - if (res != URI_SUCCESS) { - return res; - } - } - - assert(uri->owner == URI_TRUE); - - /* Apply new value */ - { - URI_TYPE(TextRange) sourceRange; - sourceRange.first = first; - sourceRange.afterLast = afterLast; - - if (URI_FUNC(CopyRangeAsNeeded)(&uri->portText, &sourceRange, memory) == URI_FALSE) { - return URI_ERROR_MALLOC; - } - } - - return URI_SUCCESS; +int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + /* Input validation (before making any changes) */ + if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + /* The RFC 3986 grammar reads: + * authority = [ userinfo "@" ] host [ ":" port ] + * So no port without a host. */ + if ((first != NULL) && (URI_FUNC(HasHost)(uri) == URI_FALSE)) { + return URI_ERROR_SETPORT_HOST_NOT_SET; + } + + if ((first != NULL) && (URI_FUNC(IsWellFormedPort)(first, afterLast) == URI_FALSE)) { + return URI_ERROR_SYNTAX; + } + + /* Clear old value */ + if ((uri->owner == URI_TRUE) && (uri->portText.first != uri->portText.afterLast)) { + memory->free(memory, (URI_CHAR *)uri->portText.first); + } + uri->portText.first = NULL; + uri->portText.afterLast = NULL; + + /* Already done? */ + if (first == NULL) { + return URI_SUCCESS; + } + + assert(first != NULL); + + /* Ensure owned */ + if (uri->owner == URI_FALSE) { + const int res = URI_FUNC(MakeOwnerMm)(uri, memory); + if (res != URI_SUCCESS) { + return res; + } + } + + assert(uri->owner == URI_TRUE); + + /* Apply new value */ + URI_TYPE(TextRange) sourceRange; + sourceRange.first = first; + sourceRange.afterLast = afterLast; + + if (URI_FUNC(CopyRangeAsNeeded)(&uri->portText, &sourceRange, memory) == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + return URI_SUCCESS; } - - -int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetPortTextMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetPortTextMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetQuery.c b/ext/uri/uriparser/src/UriSetQuery.c index 567ff6d1d8aa7..4f58c8286ed70 100644 --- a/ext/uri/uriparser/src/UriSetQuery.c +++ b/ext/uri/uriparser/src/UriSetQuery.c @@ -40,267 +40,133 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetQuery.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetQuery.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetQuery.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetQuery.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - - -#include - - - -#define URI_SET_DIGIT \ - _UT('0'): \ - case _UT('1'): \ - case _UT('2'): \ - case _UT('3'): \ - case _UT('4'): \ - case _UT('5'): \ - case _UT('6'): \ - case _UT('7'): \ - case _UT('8'): \ - case _UT('9') - - - -#define URI_SET_HEX_LETTER_UPPER \ - _UT('A'): \ - case _UT('B'): \ - case _UT('C'): \ - case _UT('D'): \ - case _UT('E'): \ - case _UT('F') - - - -#define URI_SET_HEX_LETTER_LOWER \ - _UT('a'): \ - case _UT('b'): \ - case _UT('c'): \ - case _UT('d'): \ - case _UT('e'): \ - case _UT('f') - - - -#define URI_SET_HEXDIG \ - URI_SET_DIGIT: \ - case URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER - - - -#define URI_SET_ALPHA \ - URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER: \ - case _UT('g'): \ - case _UT('G'): \ - case _UT('h'): \ - case _UT('H'): \ - case _UT('i'): \ - case _UT('I'): \ - case _UT('j'): \ - case _UT('J'): \ - case _UT('k'): \ - case _UT('K'): \ - case _UT('l'): \ - case _UT('L'): \ - case _UT('m'): \ - case _UT('M'): \ - case _UT('n'): \ - case _UT('N'): \ - case _UT('o'): \ - case _UT('O'): \ - case _UT('p'): \ - case _UT('P'): \ - case _UT('q'): \ - case _UT('Q'): \ - case _UT('r'): \ - case _UT('R'): \ - case _UT('s'): \ - case _UT('S'): \ - case _UT('t'): \ - case _UT('T'): \ - case _UT('u'): \ - case _UT('U'): \ - case _UT('v'): \ - case _UT('V'): \ - case _UT('w'): \ - case _UT('W'): \ - case _UT('x'): \ - case _UT('X'): \ - case _UT('y'): \ - case _UT('Y'): \ - case _UT('z'): \ - case _UT('Z') - - - -#define URI_SET_SUB_DELIMS \ - _UT('!'): \ - case _UT('$'): \ - case _UT('&'): \ - case _UT('\''): \ - case _UT('('): \ - case _UT(')'): \ - case _UT('*'): \ - case _UT('+'): \ - case _UT(','): \ - case _UT(';'): \ - case _UT('=') - - - -#define URI_SET_UNRESERVED \ - URI_SET_ALPHA: \ - case URI_SET_DIGIT: \ - case _UT('-'): \ - case _UT('.'): \ - case _UT('_'): \ - case _UT('~') - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriSets.h" +# endif + +# include UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first, const URI_CHAR * afterLast) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_FALSE; - } - - /* The related part of the grammar in RFC 3986 reads: - * - * query = *( pchar / "/" / "?" ) - * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - */ - while (first < afterLast) { - switch (first[0]) { - case URI_SET_UNRESERVED: - break; - - /* pct-encoded */ - case _UT('%'): - if (afterLast - first < 3) { - return URI_FALSE; - } - switch (first[1]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - switch (first[2]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - first += 2; - break; - - case URI_SET_SUB_DELIMS: - break; - - /* ":" / "@" and "/" / "?" */ - case _UT(':'): - case _UT('@'): - case _UT('/'): - case _UT('?'): - break; - - default: - return URI_FALSE; - } - - first++; - } - return URI_TRUE; + if ((first == NULL) || (afterLast == NULL)) { + return URI_FALSE; + } + + /* The related part of the grammar in RFC 3986 reads: + * + * query = *( pchar / "/" / "?" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + */ + while (first < afterLast) { + switch (first[0]) { + case URI_SET_PCHAR_WITHOUT_PERCENT(_UT): + break; + + /* pct-encoded */ + case _UT('%'): + if (afterLast - first < 3) { + return URI_FALSE; + } + switch (first[1]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + switch (first[2]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + first += 2; + break; + + case _UT('/'): + case _UT('?'): + break; + + default: + return URI_FALSE; + } + + first++; + } + return URI_TRUE; } - - -int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* Input validation (before making any changes) */ - if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - if ((first != NULL) && (URI_FUNC(IsWellFormedQuery)(first, afterLast) == URI_FALSE)) { - return URI_ERROR_SYNTAX; - } - - /* Clear old value */ - if ((uri->owner == URI_TRUE) && (uri->query.first != uri->query.afterLast)) { - memory->free(memory, (URI_CHAR *)uri->query.first); - } - uri->query.first = NULL; - uri->query.afterLast = NULL; - - /* Already done? */ - if (first == NULL) { - return URI_SUCCESS; - } - - assert(first != NULL); - - /* Ensure owned */ - if (uri->owner == URI_FALSE) { - const int res = URI_FUNC(MakeOwnerMm)(uri, memory); - if (res != URI_SUCCESS) { - return res; - } - } - - assert(uri->owner == URI_TRUE); - - /* Apply new value */ - { - URI_TYPE(TextRange) sourceRange; - sourceRange.first = first; - sourceRange.afterLast = afterLast; - - if (URI_FUNC(CopyRangeAsNeeded)(&uri->query, &sourceRange, memory) == URI_FALSE) { - return URI_ERROR_MALLOC; - } - } - - return URI_SUCCESS; +int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + /* Input validation (before making any changes) */ + if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + if ((first != NULL) && (URI_FUNC(IsWellFormedQuery)(first, afterLast) == URI_FALSE)) { + return URI_ERROR_SYNTAX; + } + + /* Clear old value */ + if ((uri->owner == URI_TRUE) && (uri->query.first != uri->query.afterLast)) { + memory->free(memory, (URI_CHAR *)uri->query.first); + } + uri->query.first = NULL; + uri->query.afterLast = NULL; + + /* Already done? */ + if (first == NULL) { + return URI_SUCCESS; + } + + assert(first != NULL); + + /* Ensure owned */ + if (uri->owner == URI_FALSE) { + const int res = URI_FUNC(MakeOwnerMm)(uri, memory); + if (res != URI_SUCCESS) { + return res; + } + } + + assert(uri->owner == URI_TRUE); + + /* Apply new value */ + URI_TYPE(TextRange) sourceRange; + sourceRange.first = first; + sourceRange.afterLast = afterLast; + + if (URI_FUNC(CopyRangeAsNeeded)(&uri->query, &sourceRange, memory) == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + return URI_SUCCESS; } - - -int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetQueryMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetQueryMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetScheme.c b/ext/uri/uriparser/src/UriSetScheme.c index 73a75b82350fd..3dfaf1e9f151b 100644 --- a/ext/uri/uriparser/src/UriSetScheme.c +++ b/ext/uri/uriparser/src/UriSetScheme.c @@ -40,233 +40,129 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetScheme.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetScheme.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetScheme.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetScheme.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - - -#include - - - -#define URI_SET_DIGIT \ - _UT('0'): \ - case _UT('1'): \ - case _UT('2'): \ - case _UT('3'): \ - case _UT('4'): \ - case _UT('5'): \ - case _UT('6'): \ - case _UT('7'): \ - case _UT('8'): \ - case _UT('9') - - - -#define URI_SET_HEX_LETTER_UPPER \ - _UT('A'): \ - case _UT('B'): \ - case _UT('C'): \ - case _UT('D'): \ - case _UT('E'): \ - case _UT('F') - - - -#define URI_SET_HEX_LETTER_LOWER \ - _UT('a'): \ - case _UT('b'): \ - case _UT('c'): \ - case _UT('d'): \ - case _UT('e'): \ - case _UT('f') - - - -#define URI_SET_HEXDIG \ - URI_SET_DIGIT: \ - case URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER - - - -#define URI_SET_ALPHA \ - URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER: \ - case _UT('g'): \ - case _UT('G'): \ - case _UT('h'): \ - case _UT('H'): \ - case _UT('i'): \ - case _UT('I'): \ - case _UT('j'): \ - case _UT('J'): \ - case _UT('k'): \ - case _UT('K'): \ - case _UT('l'): \ - case _UT('L'): \ - case _UT('m'): \ - case _UT('M'): \ - case _UT('n'): \ - case _UT('N'): \ - case _UT('o'): \ - case _UT('O'): \ - case _UT('p'): \ - case _UT('P'): \ - case _UT('q'): \ - case _UT('Q'): \ - case _UT('r'): \ - case _UT('R'): \ - case _UT('s'): \ - case _UT('S'): \ - case _UT('t'): \ - case _UT('T'): \ - case _UT('u'): \ - case _UT('U'): \ - case _UT('v'): \ - case _UT('V'): \ - case _UT('w'): \ - case _UT('W'): \ - case _UT('x'): \ - case _UT('X'): \ - case _UT('y'): \ - case _UT('Y'): \ - case _UT('z'): \ - case _UT('Z') - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriSets.h" +# endif + +# include UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first, const URI_CHAR * afterLast) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_FALSE; - } - - /* The related part of the grammar in RFC 3986 reads: - * - * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - */ - if (first >= afterLast) { - return URI_FALSE; - } - - switch (first[0]) { - case URI_SET_ALPHA: - break; - - default: - return URI_FALSE; - } - - first++; - - while (first < afterLast) { - switch (first[0]) { - case URI_SET_ALPHA: - case URI_SET_DIGIT: - case _UT('+'): - case _UT('-'): - case _UT('.'): - break; - - default: - return URI_FALSE; - } - - first++; - } - return URI_TRUE; + if ((first == NULL) || (afterLast == NULL)) { + return URI_FALSE; + } + + /* The related part of the grammar in RFC 3986 reads: + * + * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + */ + if (first >= afterLast) { + return URI_FALSE; + } + + switch (first[0]) { + case URI_SET_ALPHA(_UT): + break; + + default: + return URI_FALSE; + } + + first++; + + while (first < afterLast) { + switch (first[0]) { + case URI_SET_ALPHA(_UT): + case URI_SET_DIGIT(_UT): + case _UT('+'): + case _UT('-'): + case _UT('.'): + break; + + default: + return URI_FALSE; + } + + first++; + } + return URI_TRUE; } - - -int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* Input validation (before making any changes) */ - if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - if ((first != NULL) && (URI_FUNC(IsWellFormedScheme)(first, afterLast) == URI_FALSE)) { - return URI_ERROR_SYNTAX; - } - - /* Clear old value */ - if ((uri->owner == URI_TRUE) && (uri->scheme.first != uri->scheme.afterLast)) { - memory->free(memory, (URI_CHAR *)uri->scheme.first); - } - uri->scheme.first = NULL; - uri->scheme.afterLast = NULL; - - /* Already done setting? */ - if (first == NULL) { - /* Yes, but disambiguate as needed */ - const UriBool success = URI_FUNC(FixPathNoScheme)(uri, memory); - return (success == URI_TRUE) - ? URI_SUCCESS - : URI_ERROR_MALLOC; - } - - assert(first != NULL); - - /* Ensure owned */ - if (uri->owner == URI_FALSE) { - const int res = URI_FUNC(MakeOwnerMm)(uri, memory); - if (res != URI_SUCCESS) { - return res; - } - } - - assert(uri->owner == URI_TRUE); - - /* Apply new value */ - { - URI_TYPE(TextRange) sourceRange; - sourceRange.first = first; - sourceRange.afterLast = afterLast; - - if (URI_FUNC(CopyRangeAsNeeded)(&uri->scheme, &sourceRange, memory) == URI_FALSE) { - return URI_ERROR_MALLOC; - } - } - - return URI_SUCCESS; +int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + /* Input validation (before making any changes) */ + if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + if ((first != NULL) + && (URI_FUNC(IsWellFormedScheme)(first, afterLast) == URI_FALSE)) { + return URI_ERROR_SYNTAX; + } + + /* Clear old value */ + if ((uri->owner == URI_TRUE) && (uri->scheme.first != uri->scheme.afterLast)) { + memory->free(memory, (URI_CHAR *)uri->scheme.first); + } + uri->scheme.first = NULL; + uri->scheme.afterLast = NULL; + + /* Already done setting? */ + if (first == NULL) { + /* Yes, but disambiguate as needed */ + const UriBool success = URI_FUNC(FixPathNoScheme)(uri, memory); + return (success == URI_TRUE) ? URI_SUCCESS : URI_ERROR_MALLOC; + } + + assert(first != NULL); + + /* Ensure owned */ + if (uri->owner == URI_FALSE) { + const int res = URI_FUNC(MakeOwnerMm)(uri, memory); + if (res != URI_SUCCESS) { + return res; + } + } + + assert(uri->owner == URI_TRUE); + + /* Apply new value */ + URI_TYPE(TextRange) sourceRange; + sourceRange.first = first; + sourceRange.afterLast = afterLast; + + if (URI_FUNC(CopyRangeAsNeeded)(&uri->scheme, &sourceRange, memory) == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + return URI_SUCCESS; } - - -int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetSchemeMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetSchemeMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSetUserInfo.c b/ext/uri/uriparser/src/UriSetUserInfo.c index d30f984395a24..7865e837deb66 100644 --- a/ext/uri/uriparser/src/UriSetUserInfo.c +++ b/ext/uri/uriparser/src/UriSetUserInfo.c @@ -40,267 +40,141 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriSetUserInfo.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriSetUserInfo.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriSetUserInfo.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriSetUserInfo.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - - -#include - - - -#define URI_SET_DIGIT \ - _UT('0'): \ - case _UT('1'): \ - case _UT('2'): \ - case _UT('3'): \ - case _UT('4'): \ - case _UT('5'): \ - case _UT('6'): \ - case _UT('7'): \ - case _UT('8'): \ - case _UT('9') - - - -#define URI_SET_HEX_LETTER_UPPER \ - _UT('A'): \ - case _UT('B'): \ - case _UT('C'): \ - case _UT('D'): \ - case _UT('E'): \ - case _UT('F') - - - -#define URI_SET_HEX_LETTER_LOWER \ - _UT('a'): \ - case _UT('b'): \ - case _UT('c'): \ - case _UT('d'): \ - case _UT('e'): \ - case _UT('f') - - - -#define URI_SET_HEXDIG \ - URI_SET_DIGIT: \ - case URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER - - - -#define URI_SET_ALPHA \ - URI_SET_HEX_LETTER_UPPER: \ - case URI_SET_HEX_LETTER_LOWER: \ - case _UT('g'): \ - case _UT('G'): \ - case _UT('h'): \ - case _UT('H'): \ - case _UT('i'): \ - case _UT('I'): \ - case _UT('j'): \ - case _UT('J'): \ - case _UT('k'): \ - case _UT('K'): \ - case _UT('l'): \ - case _UT('L'): \ - case _UT('m'): \ - case _UT('M'): \ - case _UT('n'): \ - case _UT('N'): \ - case _UT('o'): \ - case _UT('O'): \ - case _UT('p'): \ - case _UT('P'): \ - case _UT('q'): \ - case _UT('Q'): \ - case _UT('r'): \ - case _UT('R'): \ - case _UT('s'): \ - case _UT('S'): \ - case _UT('t'): \ - case _UT('T'): \ - case _UT('u'): \ - case _UT('U'): \ - case _UT('v'): \ - case _UT('V'): \ - case _UT('w'): \ - case _UT('W'): \ - case _UT('x'): \ - case _UT('X'): \ - case _UT('y'): \ - case _UT('Y'): \ - case _UT('z'): \ - case _UT('Z') - - - -#define URI_SET_SUB_DELIMS \ - _UT('!'): \ - case _UT('$'): \ - case _UT('&'): \ - case _UT('\''): \ - case _UT('('): \ - case _UT(')'): \ - case _UT('*'): \ - case _UT('+'): \ - case _UT(','): \ - case _UT(';'): \ - case _UT('=') - - - -#define URI_SET_UNRESERVED \ - URI_SET_ALPHA: \ - case URI_SET_DIGIT: \ - case _UT('-'): \ - case _UT('.'): \ - case _UT('_'): \ - case _UT('~') - - - -UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first, const URI_CHAR * afterLast) { - if ((first == NULL) || (afterLast == NULL)) { - return URI_FALSE; - } - - /* userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) */ - while (first < afterLast) { - switch (first[0]) { - case URI_SET_UNRESERVED: - break; - - /* pct-encoded */ - case _UT('%'): - if (afterLast - first < 3) { - return URI_FALSE; - } - switch (first[1]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - switch (first[2]) { - case URI_SET_HEXDIG: - break; - default: - return URI_FALSE; - } - first += 2; - break; - - case URI_SET_SUB_DELIMS: - break; - - /* ":" */ - case _UT(':'): - break; - - default: - return URI_FALSE; - } - - first++; - } - return URI_TRUE; +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# include "UriSets.h" +# endif + +# include + +UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first, + const URI_CHAR * afterLast) { + if ((first == NULL) || (afterLast == NULL)) { + return URI_FALSE; + } + + /* userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) */ + while (first < afterLast) { + switch (first[0]) { + case URI_SET_UNRESERVED(_UT): + break; + + /* pct-encoded */ + case _UT('%'): + if (afterLast - first < 3) { + return URI_FALSE; + } + switch (first[1]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + switch (first[2]) { + case URI_SET_HEXDIG(_UT): + break; + default: + return URI_FALSE; + } + first += 2; + break; + + case URI_SET_SUB_DELIMS(_UT): + break; + + /* ":" */ + case _UT(':'): + break; + + default: + return URI_FALSE; + } + + first++; + } + return URI_TRUE; } - - -int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* Input validation (before making any changes) */ - if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { - return URI_ERROR_NULL; - } - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - /* The RFC 3986 grammar reads: - * authority = [ userinfo "@" ] host [ ":" port ] - * So no user info without a host. */ - if ((first != NULL) && (URI_FUNC(HasHost)(uri) == URI_FALSE)) { - return URI_ERROR_SETUSERINFO_HOST_NOT_SET; - } - - if ((first != NULL) && (URI_FUNC(IsWellFormedUserInfo)(first, afterLast) == URI_FALSE)) { - return URI_ERROR_SYNTAX; - } - - /* Clear old value */ - if ((uri->owner == URI_TRUE) && (uri->userInfo.first != uri->userInfo.afterLast)) { - memory->free(memory, (URI_CHAR *)uri->userInfo.first); - } - uri->userInfo.first = NULL; - uri->userInfo.afterLast = NULL; - - /* Already done? */ - if (first == NULL) { - return URI_SUCCESS; - } - - assert(first != NULL); - - /* Ensure owned */ - if (uri->owner == URI_FALSE) { - const int res = URI_FUNC(MakeOwnerMm)(uri, memory); - if (res != URI_SUCCESS) { - return res; - } - } - - assert(uri->owner == URI_TRUE); - - /* Apply new value */ - { - URI_TYPE(TextRange) sourceRange; - sourceRange.first = first; - sourceRange.afterLast = afterLast; - - if (URI_FUNC(CopyRangeAsNeeded)(&uri->userInfo, &sourceRange, memory) == URI_FALSE) { - return URI_ERROR_MALLOC; - } - } - - return URI_SUCCESS; +int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast, UriMemoryManager * memory) { + /* Input validation (before making any changes) */ + if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) { + return URI_ERROR_NULL; + } + + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ + + /* The RFC 3986 grammar reads: + * authority = [ userinfo "@" ] host [ ":" port ] + * So no user info without a host. */ + if ((first != NULL) && (URI_FUNC(HasHost)(uri) == URI_FALSE)) { + return URI_ERROR_SETUSERINFO_HOST_NOT_SET; + } + + if ((first != NULL) + && (URI_FUNC(IsWellFormedUserInfo)(first, afterLast) == URI_FALSE)) { + return URI_ERROR_SYNTAX; + } + + /* Clear old value */ + if ((uri->owner == URI_TRUE) && (uri->userInfo.first != uri->userInfo.afterLast)) { + memory->free(memory, (URI_CHAR *)uri->userInfo.first); + } + uri->userInfo.first = NULL; + uri->userInfo.afterLast = NULL; + + /* Already done? */ + if (first == NULL) { + return URI_SUCCESS; + } + + assert(first != NULL); + + /* Ensure owned */ + if (uri->owner == URI_FALSE) { + const int res = URI_FUNC(MakeOwnerMm)(uri, memory); + if (res != URI_SUCCESS) { + return res; + } + } + + assert(uri->owner == URI_TRUE); + + /* Apply new value */ + URI_TYPE(TextRange) sourceRange; + sourceRange.first = first; + sourceRange.afterLast = afterLast; + + if (URI_FUNC(CopyRangeAsNeeded)(&uri->userInfo, &sourceRange, memory) == URI_FALSE) { + return URI_ERROR_MALLOC; + } + + return URI_SUCCESS; } - - -int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, - const URI_CHAR * afterLast) { - return URI_FUNC(SetUserInfoMm)(uri, first, afterLast, NULL); +int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri, const URI_CHAR * first, + const URI_CHAR * afterLast) { + return URI_FUNC(SetUserInfoMm)(uri, first, afterLast, NULL); } - - #endif diff --git a/ext/uri/uriparser/src/UriSets.h b/ext/uri/uriparser/src/UriSets.h new file mode 100644 index 0000000000000..a6a2c46a14d77 --- /dev/null +++ b/ext/uri/uriparser/src/UriSets.h @@ -0,0 +1,174 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2025, Sebastian Pipping + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file UriSets.h + * Holds character set definitions. + */ + +// NOTE: We cannot use a regular include-once guard here because the +// file must support being included twice, e.g. from file UriParse.c. +#if !defined(URI_SET_DIGIT) + +// clang-format off +# define URI_SET_DIGIT(ut) \ + ut('0'): \ + case ut('1'): \ + /* clang-format on */ \ + case ut('2'): \ + case ut('3'): \ + case ut('4'): \ + case ut('5'): \ + case ut('6'): \ + case ut('7'): \ + case ut('8'): \ + case ut('9') + +// clang-format off +# define URI_SET_HEX_LETTER_LOWER(ut) \ + ut('a'): \ + case ut('b'): \ + /* clang-format on */ \ + case ut('c'): \ + case ut('d'): \ + case ut('e'): \ + case ut('f') + +// clang-format off +# define URI_SET_HEX_LETTER_UPPER(ut) \ + ut('A'): \ + case ut('B'): \ + /* clang-format on */ \ + case ut('C'): \ + case ut('D'): \ + case ut('E'): \ + case ut('F') + +// clang-format off +# define URI_SET_HEXDIG(ut) \ + URI_SET_DIGIT(ut): \ + case URI_SET_HEX_LETTER_LOWER(ut): \ + /* clang-format on */ \ + case URI_SET_HEX_LETTER_UPPER(ut) + +// clang-format off +# define URI_SET_ALPHA(ut) \ + URI_SET_HEX_LETTER_UPPER(ut): \ + case URI_SET_HEX_LETTER_LOWER(ut): \ + /* clang-format on */ \ + case ut('g'): \ + case ut('G'): \ + case ut('h'): \ + case ut('H'): \ + case ut('i'): \ + case ut('I'): \ + case ut('j'): \ + case ut('J'): \ + case ut('k'): \ + case ut('K'): \ + case ut('l'): \ + case ut('L'): \ + case ut('m'): \ + case ut('M'): \ + case ut('n'): \ + case ut('N'): \ + case ut('o'): \ + case ut('O'): \ + case ut('p'): \ + case ut('P'): \ + case ut('q'): \ + case ut('Q'): \ + case ut('r'): \ + case ut('R'): \ + case ut('s'): \ + case ut('S'): \ + case ut('t'): \ + case ut('T'): \ + case ut('u'): \ + case ut('U'): \ + case ut('v'): \ + case ut('V'): \ + case ut('w'): \ + case ut('W'): \ + case ut('x'): \ + case ut('X'): \ + case ut('y'): \ + case ut('Y'): \ + case ut('z'): \ + case ut('Z') + +// clang-format off +# define URI_SET_SUB_DELIMS(ut) \ + ut('!'): \ + case ut('$'): \ + /* clang-format on */ \ + case ut('&'): \ + case ut('\''): \ + case ut('('): \ + case ut(')'): \ + case ut('*'): \ + case ut('+'): \ + case ut(','): \ + case ut(';'): \ + case ut('=') + +// clang-format off +# define URI_SET_UNRESERVED(ut) \ + URI_SET_ALPHA(ut): \ + case URI_SET_DIGIT(ut): \ + /* clang-format on */ \ + case ut('-'): \ + case ut('.'): \ + case ut('_'): \ + case ut('~') + +// clang-format off +# define URI_SET_PCHAR_WITHOUT_PERCENT(ut) \ + URI_SET_UNRESERVED(ut): \ + case URI_SET_SUB_DELIMS(ut): \ + /* clang-format on */ \ + case ut(':'): \ + case ut('@') + +// clang-format off +# define URI_SET_PCHAR(ut) \ + URI_SET_PCHAR_WITHOUT_PERCENT(ut): \ + case ut('%') +/* clang-format on */ + +#endif // ! defined(URI_SET_DIGIT) diff --git a/ext/uri/uriparser/src/UriShorten.c b/ext/uri/uriparser/src/UriShorten.c index d2f893592d9ce..548b0b4157dd0 100644 --- a/ext/uri/uriparser/src/UriShorten.c +++ b/ext/uri/uriparser/src/UriShorten.c @@ -41,284 +41,386 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriShorten.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriShorten.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriShorten.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriShorten.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -# include "UriCommon.h" -# include "UriMemory.h" -#endif - - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif + +# ifndef URI_DOXYGEN +# include +# include "UriCommon.h" +# include "UriMemory.h" +# endif static URI_INLINE UriBool URI_FUNC(AppendSegment)(URI_TYPE(Uri) * uri, - const URI_CHAR * first, const URI_CHAR * afterLast, - UriMemoryManager * memory) { - /* Create segment */ - URI_TYPE(PathSegment) * segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment))); - if (segment == NULL) { - return URI_FALSE; /* Raises malloc error */ - } - segment->next = NULL; - segment->text.first = first; - segment->text.afterLast = afterLast; - - /* Put into chain */ - if (uri->pathTail == NULL) { - uri->pathHead = segment; - } else { - uri->pathTail->next = segment; - } - uri->pathTail = segment; - - return URI_TRUE; + const URI_CHAR * first, + const URI_CHAR * afterLast, + UriMemoryManager * memory) { + /* Create segment */ + URI_TYPE(PathSegment) * segment = + memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment))); + if (segment == NULL) { + return URI_FALSE; /* Raises malloc error */ + } + segment->next = NULL; + segment->text.first = first; + segment->text.afterLast = afterLast; + + /* Put into chain */ + if (uri->pathTail == NULL) { + uri->pathHead = segment; + } else { + uri->pathTail->next = segment; + } + uri->pathTail = segment; + + return URI_TRUE; } - - static URI_INLINE UriBool URI_FUNC(EqualsAuthority)(const URI_TYPE(Uri) * first, - const URI_TYPE(Uri) * second) { - /* IPv4 */ - if (first->hostData.ip4 != NULL) { - return ((second->hostData.ip4 != NULL) - && !memcmp(first->hostData.ip4->data, - second->hostData.ip4->data, 4)) ? URI_TRUE : URI_FALSE; - } - - /* IPv6 */ - if (first->hostData.ip6 != NULL) { - return ((second->hostData.ip6 != NULL) - && !memcmp(first->hostData.ip6->data, - second->hostData.ip6->data, 16)) ? URI_TRUE : URI_FALSE; - } - - /* IPvFuture */ - if (first->hostData.ipFuture.first != NULL) { - return ((second->hostData.ipFuture.first != NULL) - && !URI_FUNC(CompareRange)(&first->hostData.ipFuture, - &second->hostData.ipFuture)) ? URI_TRUE : URI_FALSE; - } - - return !URI_FUNC(CompareRange)(&first->hostText, &second->hostText) - ? URI_TRUE : URI_FALSE; + const URI_TYPE(Uri) * second) { + /* IPv4 */ + if (first->hostData.ip4 != NULL) { + return ((second->hostData.ip4 != NULL) + && !memcmp(first->hostData.ip4->data, second->hostData.ip4->data, 4)) + ? URI_TRUE + : URI_FALSE; + } + + /* IPv6 */ + if (first->hostData.ip6 != NULL) { + return ((second->hostData.ip6 != NULL) + && !memcmp(first->hostData.ip6->data, second->hostData.ip6->data, 16)) + ? URI_TRUE + : URI_FALSE; + } + + /* IPvFuture */ + if (first->hostData.ipFuture.first != NULL) { + return ((second->hostData.ipFuture.first != NULL) + && !URI_FUNC(CompareRange)(&first->hostData.ipFuture, + &second->hostData.ipFuture)) + ? URI_TRUE + : URI_FALSE; + } + + return !URI_FUNC(CompareRange)(&first->hostText, &second->hostText) ? URI_TRUE + : URI_FALSE; } - - static int URI_FUNC(RemoveBaseUriImpl)(URI_TYPE(Uri) * dest, - const URI_TYPE(Uri) * absSource, - const URI_TYPE(Uri) * absBase, - UriBool domainRootMode, UriMemoryManager * memory) { - if (dest == NULL) { - return URI_ERROR_NULL; - } - URI_FUNC(ResetUri)(dest); - - if ((absSource == NULL) || (absBase == NULL)) { - return URI_ERROR_NULL; - } - - /* absBase absolute? */ - if (absBase->scheme.first == NULL) { - return URI_ERROR_REMOVEBASE_REL_BASE; - } - - /* absSource absolute? */ - if (absSource->scheme.first == NULL) { - return URI_ERROR_REMOVEBASE_REL_SOURCE; - } - - /* [01/50] if (A.scheme != Base.scheme) then */ - if (URI_FUNC(CompareRange)(&absSource->scheme, &absBase->scheme)) { - /* [02/50] T.scheme = A.scheme; */ - dest->scheme = absSource->scheme; - /* [03/50] T.authority = A.authority; */ - if (!URI_FUNC(CopyAuthority)(dest, absSource, memory)) { - return URI_ERROR_MALLOC; - } - /* [04/50] T.path = A.path; */ - if (!URI_FUNC(CopyPath)(dest, absSource, memory)) { - return URI_ERROR_MALLOC; - } - /* [05/50] else */ - } else { - /* [06/50] undef(T.scheme); */ - /* NOOP */ - /* [07/50] if (A.authority != Base.authority) then */ - if (!URI_FUNC(EqualsAuthority)(absSource, absBase)) { - /* [08/50] T.authority = A.authority; */ - if (!URI_FUNC(CopyAuthority)(dest, absSource, memory)) { - return URI_ERROR_MALLOC; - } - /* [09/50] T.path = A.path; */ - if (!URI_FUNC(CopyPath)(dest, absSource, memory)) { - return URI_ERROR_MALLOC; - } - /* [10/50] else */ - } else { - /* [11/50] if domainRootMode then */ - if (domainRootMode == URI_TRUE) { - /* [12/50] undef(T.authority); */ - /* NOOP */ - /* [13/50] if (first(A.path) == "") then */ - /* GROUPED */ - /* [14/50] T.path = "/." + A.path; */ - /* GROUPED */ - /* [15/50] else */ - /* GROUPED */ - /* [16/50] T.path = A.path; */ - /* GROUPED */ - /* [17/50] endif; */ - if (!URI_FUNC(CopyPath)(dest, absSource, memory)) { - return URI_ERROR_MALLOC; - } - dest->absolutePath = URI_TRUE; - - if (!URI_FUNC(FixAmbiguity)(dest, memory)) { - return URI_ERROR_MALLOC; - } - /* [18/50] else */ - } else { - const URI_TYPE(PathSegment) * sourceSeg = absSource->pathHead; - const URI_TYPE(PathSegment) * baseSeg = absBase->pathHead; - /* [19/50] bool pathNaked = true; */ - UriBool pathNaked = URI_TRUE; - /* [20/50] undef(last(Base.path)); */ - /* NOOP */ - /* [21/50] T.path = ""; */ - dest->absolutePath = URI_FALSE; - /* [22/50] while (first(A.path) == first(Base.path)) do */ - while ((sourceSeg != NULL) && (baseSeg != NULL) - && !URI_FUNC(CompareRange)(&sourceSeg->text, &baseSeg->text) - && !((sourceSeg->text.first == sourceSeg->text.afterLast) - && ((sourceSeg->next == NULL) != (baseSeg->next == NULL)))) { - /* [23/50] A.path++; */ - sourceSeg = sourceSeg->next; - /* [24/50] Base.path++; */ - baseSeg = baseSeg->next; - /* [25/50] endwhile; */ - } - /* [26/50] while defined(first(Base.path)) do */ - while ((baseSeg != NULL) && (baseSeg->next != NULL)) { - /* [27/50] Base.path++; */ - baseSeg = baseSeg->next; - /* [28/50] T.path += "../"; */ - if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstParent), - URI_FUNC(ConstParent) + 2, memory)) { - return URI_ERROR_MALLOC; - } - /* [29/50] pathNaked = false; */ - pathNaked = URI_FALSE; - /* [30/50] endwhile; */ - } - /* [31/50] while defined(first(A.path)) do */ - while (sourceSeg != NULL) { - /* [32/50] if pathNaked then */ - if (pathNaked == URI_TRUE) { - /* [33/50] if (first(A.path) contains ":") then */ - UriBool containsColon = URI_FALSE; - const URI_CHAR * ch = sourceSeg->text.first; - for (; ch < sourceSeg->text.afterLast; ch++) { - if (*ch == _UT(':')) { - containsColon = URI_TRUE; - break; - } - } - - if (containsColon) { - /* [34/50] T.path += "./"; */ - if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstPwd), - URI_FUNC(ConstPwd) + 1, memory)) { - return URI_ERROR_MALLOC; - } - /* [35/50] elseif (first(A.path) == "") then */ - } else if (sourceSeg->text.first == sourceSeg->text.afterLast) { - /* [36/50] T.path += "/."; */ - if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstPwd), - URI_FUNC(ConstPwd) + 1, memory)) { - return URI_ERROR_MALLOC; - } - /* [37/50] endif; */ - } - /* [38/50] endif; */ - } - /* [39/50] T.path += first(A.path); */ - if (!URI_FUNC(AppendSegment)(dest, sourceSeg->text.first, - sourceSeg->text.afterLast, memory)) { - return URI_ERROR_MALLOC; - } - /* [40/50] pathNaked = false; */ - pathNaked = URI_FALSE; - /* [41/50] A.path++; */ - sourceSeg = sourceSeg->next; - /* [42/50] if defined(first(A.path)) then */ - /* NOOP */ - /* [43/50] T.path += + "/"; */ - /* NOOP */ - /* [44/50] endif; */ - /* NOOP */ - /* [45/50] endwhile; */ - } - /* [46/50] endif; */ - } - /* [47/50] endif; */ - } - /* [48/50] endif; */ - } - /* [49/50] T.query = A.query; */ - dest->query = absSource->query; - /* [50/50] T.fragment = A.fragment; */ - dest->fragment = absSource->fragment; - - return URI_SUCCESS; + const URI_TYPE(Uri) * absSource, + const URI_TYPE(Uri) * absBase, + UriBool domainRootMode, + UriMemoryManager * memory) { + if (dest == NULL) { + return URI_ERROR_NULL; + } + URI_FUNC(ResetUri)(dest); + + if ((absSource == NULL) || (absBase == NULL)) { + return URI_ERROR_NULL; + } + + /* absBase absolute? */ + if (absBase->scheme.first == NULL) { + return URI_ERROR_REMOVEBASE_REL_BASE; + } + + /* absSource absolute? */ + if (absSource->scheme.first == NULL) { + return URI_ERROR_REMOVEBASE_REL_SOURCE; + } + + /* NOTE: The curly brackets here force deeper indent (and that's all) */ + { + { + { + /* clang-format off */ + /* [01/50] if (A.scheme != Base.scheme) then */ + /* clang-format on */ + if (URI_FUNC(CompareRange)(&absSource->scheme, &absBase->scheme)) { + /* clang-format off */ + /* [02/50] T.scheme = A.scheme; */ + /* clang-format on */ + dest->scheme = absSource->scheme; + /* clang-format off */ + /* [03/50] T.authority = A.authority; */ + /* clang-format on */ + if (!URI_FUNC(CopyAuthority)(dest, absSource, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [04/50] T.path = A.path; */ + /* clang-format on */ + if (!URI_FUNC(CopyPath)(dest, absSource, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [05/50] else */ + /* clang-format on */ + } else { + /* clang-format off */ + /* [06/50] undef(T.scheme); */ + /* clang-format on */ + /* NOOP */ + /* clang-format off */ + /* [07/50] if (A.authority != Base.authority) then */ + /* clang-format on */ + if (!URI_FUNC(EqualsAuthority)(absSource, absBase)) { + /* clang-format off */ + /* [08/50] T.authority = A.authority; */ + /* clang-format on */ + if (!URI_FUNC(CopyAuthority)(dest, absSource, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [09/50] T.path = A.path; */ + /* clang-format on */ + if (!URI_FUNC(CopyPath)(dest, absSource, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [10/50] else */ + /* clang-format on */ + } else { + /* clang-format off */ + /* [11/50] if domainRootMode then */ + /* clang-format on */ + if (domainRootMode == URI_TRUE) { + /* clang-format off */ + /* [12/50] undef(T.authority); */ + /* clang-format on */ + /* NOOP */ + /* clang-format off */ + /* [13/50] if (first(A.path) == "") then */ + /* clang-format on */ + /* GROUPED */ + /* clang-format off */ + /* [14/50] T.path = "/." + A.path; */ + /* clang-format on */ + /* GROUPED */ + /* clang-format off */ + /* [15/50] else */ + /* clang-format on */ + /* GROUPED */ + /* clang-format off */ + /* [16/50] T.path = A.path; */ + /* clang-format on */ + /* GROUPED */ + /* clang-format off */ + /* [17/50] endif; */ + /* clang-format on */ + if (!URI_FUNC(CopyPath)(dest, absSource, memory)) { + return URI_ERROR_MALLOC; + } + dest->absolutePath = URI_TRUE; + + if (!URI_FUNC(FixAmbiguity)(dest, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [18/50] else */ + /* clang-format on */ + } else { + const URI_TYPE(PathSegment) * sourceSeg = absSource->pathHead; + const URI_TYPE(PathSegment) * baseSeg = absBase->pathHead; + /* clang-format off */ + /* [19/50] bool pathNaked = true; */ + /* clang-format on */ + UriBool pathNaked = URI_TRUE; + /* clang-format off */ + /* [20/50] undef(last(Base.path)); */ + /* clang-format on */ + /* NOOP */ + /* clang-format off */ + /* [21/50] T.path = ""; */ + /* clang-format on */ + dest->absolutePath = URI_FALSE; + /* clang-format off */ + /* [22/50] while (first(A.path) == first(Base.path)) do */ + /* clang-format on */ + while ( + (sourceSeg != NULL) && (baseSeg != NULL) + && !URI_FUNC(CompareRange)(&sourceSeg->text, + &baseSeg->text) + && !((sourceSeg->text.first == sourceSeg->text.afterLast) + && ((sourceSeg->next == NULL) + != (baseSeg->next == NULL)))) { + /* clang-format off */ + /* [23/50] A.path++; */ + /* clang-format on */ + sourceSeg = sourceSeg->next; + /* clang-format off */ + /* [24/50] Base.path++; */ + /* clang-format on */ + baseSeg = baseSeg->next; + /* clang-format off */ + /* [25/50] endwhile; */ + /* clang-format on */ + } + /* clang-format off */ + /* [26/50] while defined(first(Base.path)) do */ + /* clang-format on */ + while ((baseSeg != NULL) && (baseSeg->next != NULL)) { + /* clang-format off */ + /* [27/50] Base.path++; */ + /* clang-format on */ + baseSeg = baseSeg->next; + /* clang-format off */ + /* [28/50] T.path += "../"; */ + /* clang-format on */ + if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstParent), + URI_FUNC(ConstParent) + 2, + memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [29/50] pathNaked = false; */ + /* clang-format on */ + pathNaked = URI_FALSE; + /* clang-format off */ + /* [30/50] endwhile; */ + /* clang-format on */ + } + /* clang-format off */ + /* [31/50] while defined(first(A.path)) do */ + /* clang-format on */ + while (sourceSeg != NULL) { + /* clang-format off */ + /* [32/50] if pathNaked then */ + /* clang-format on */ + if (pathNaked == URI_TRUE) { + /* clang-format off */ + /* [33/50] if (first(A.path) contains ":") then */ + /* clang-format on */ + UriBool containsColon = URI_FALSE; + const URI_CHAR * ch = sourceSeg->text.first; + for (; ch < sourceSeg->text.afterLast; ch++) { + if (*ch == _UT(':')) { + containsColon = URI_TRUE; + break; + } + } + + if (containsColon) { + /* clang-format off */ + /* [34/50] T.path += "./"; */ + /* clang-format on */ + if (!URI_FUNC(AppendSegment)( + dest, URI_FUNC(ConstPwd), + URI_FUNC(ConstPwd) + 1, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [35/50] elseif (first(A.path) == "") then */ + /* clang-format on */ + } else if (sourceSeg->text.first + == sourceSeg->text.afterLast) { + /* clang-format off */ + /* [36/50] T.path += "/."; */ + /* clang-format on */ + if (!URI_FUNC(AppendSegment)( + dest, URI_FUNC(ConstPwd), + URI_FUNC(ConstPwd) + 1, memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [37/50] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [38/50] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [39/50] T.path += first(A.path); */ + /* clang-format on */ + if (!URI_FUNC(AppendSegment)(dest, sourceSeg->text.first, + sourceSeg->text.afterLast, + memory)) { + return URI_ERROR_MALLOC; + } + /* clang-format off */ + /* [40/50] pathNaked = false; */ + /* clang-format on */ + pathNaked = URI_FALSE; + /* clang-format off */ + /* [41/50] A.path++; */ + /* clang-format on */ + sourceSeg = sourceSeg->next; + /* clang-format off */ + /* [42/50] if defined(first(A.path)) then */ + /* clang-format on */ + /* NOOP */ + /* clang-format off */ + /* [43/50] T.path += + "/"; */ + /* clang-format on */ + /* NOOP */ + /* clang-format off */ + /* [44/50] endif; */ + /* clang-format on */ + /* NOOP */ + /* clang-format off */ + /* [45/50] endwhile; */ + /* clang-format on */ + } + /* clang-format off */ + /* [46/50] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [47/50] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [48/50] endif; */ + /* clang-format on */ + } + /* clang-format off */ + /* [49/50] T.query = A.query; */ + /* clang-format on */ + dest->query = absSource->query; + /* clang-format off */ + /* [50/50] T.fragment = A.fragment; */ + /* clang-format on */ + dest->fragment = absSource->fragment; + } + } + } + return URI_SUCCESS; } - - -int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest, - const URI_TYPE(Uri) * absSource, - const URI_TYPE(Uri) * absBase, - UriBool domainRootMode) { - return URI_FUNC(RemoveBaseUriMm)(dest, absSource, absBase, - domainRootMode, NULL); +int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * absSource, + const URI_TYPE(Uri) * absBase, UriBool domainRootMode) { + return URI_FUNC(RemoveBaseUriMm)(dest, absSource, absBase, domainRootMode, NULL); } +int URI_FUNC(RemoveBaseUriMm)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * absSource, + const URI_TYPE(Uri) * absBase, UriBool domainRootMode, + UriMemoryManager * memory) { + int res; + URI_CHECK_MEMORY_MANAGER(memory); /* may return */ -int URI_FUNC(RemoveBaseUriMm)(URI_TYPE(Uri) * dest, - const URI_TYPE(Uri) * absSource, - const URI_TYPE(Uri) * absBase, - UriBool domainRootMode, UriMemoryManager * memory) { - int res; - - URI_CHECK_MEMORY_MANAGER(memory); /* may return */ - - res = URI_FUNC(RemoveBaseUriImpl)(dest, absSource, - absBase, domainRootMode, memory); - if ((res != URI_SUCCESS) && (dest != NULL)) { - URI_FUNC(FreeUriMembersMm)(dest, memory); - } - return res; + res = URI_FUNC(RemoveBaseUriImpl)(dest, absSource, absBase, domainRootMode, memory); + if ((res != URI_SUCCESS) && (dest != NULL)) { + URI_FUNC(FreeUriMembersMm)(dest, memory); + } + return res; } - - #endif diff --git a/ext/uri/uriparser/src/UriVersion.c b/ext/uri/uriparser/src/UriVersion.c index 81295ca942b31..5c9a3e3f4b0af 100644 --- a/ext/uri/uriparser/src/UriVersion.c +++ b/ext/uri/uriparser/src/UriVersion.c @@ -46,42 +46,36 @@ #include #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) /* Include SELF twice */ -# ifdef URI_ENABLE_ANSI -# define URI_PASS_ANSI 1 -# include "UriVersion.c" -# undef URI_PASS_ANSI -# endif -# ifdef URI_ENABLE_UNICODE -# define URI_PASS_UNICODE 1 -# include "UriVersion.c" -# undef URI_PASS_UNICODE -# endif +# ifdef URI_ENABLE_ANSI +# define URI_PASS_ANSI 1 +# include "UriVersion.c" +# undef URI_PASS_ANSI +# endif +# ifdef URI_ENABLE_UNICODE +# define URI_PASS_UNICODE 1 +# include "UriVersion.c" +# undef URI_PASS_UNICODE +# endif #else -# ifdef URI_PASS_ANSI -# include -# else -# include -# include -# endif - - - -#ifndef URI_DOXYGEN -# include -#endif - +# ifdef URI_PASS_ANSI +# include +# else +# include +# include +# endif +# ifndef URI_DOXYGEN +# include +# endif const URI_CHAR * URI_FUNC(BaseRuntimeVersion)(void) { -#if defined(URI_PASS_ANSI) - return URI_VER_ANSI; -#elif defined(URI_PASS_UNICODE) - return URI_VER_UNICODE; -#else -# error Either URI_PASS_ANSI or URI_PASS_UNICODE must be defined -#endif +# if defined(URI_PASS_ANSI) + return URI_VER_ANSI; +# elif defined(URI_PASS_UNICODE) + return URI_VER_UNICODE; +# else +# error Either URI_PASS_ANSI or URI_PASS_UNICODE must be defined +# endif } - - #endif diff --git a/ext/xml/compat.c b/ext/xml/compat.c index 6ce0809cd5b09..7e37bf1e412c3 100644 --- a/ext/xml/compat.c +++ b/ext/xml/compat.c @@ -37,36 +37,35 @@ qualify_namespace(XML_Parser parser, const xmlChar *name, const xmlChar *URI) } } +static void start_element_emit_default(XML_Parser parser) +{ + if (parser->h_default) { + /* Grammar does not allow embedded '<' and '>' in elements, so we can seek to the start and end positions. + * Since the parser in the current mode mode is non-progressive, it contains the entire input. */ + const xmlChar *cur = parser->parser->input->cur; + const xmlChar *end = cur; + for (const xmlChar *base = parser->parser->input->base; cur > base && *cur != '<'; cur--); + if (*end == '/') { + /* BC: Keep split between start & end element. + * TODO: In the future this could be aligned with expat and only emit a start event, or vice versa. + * See gh20439_2.phpt */ + xmlChar *tmp = BAD_CAST estrndup((const char *) cur, end - cur + 1); + tmp[end - cur] = '>'; + parser->h_default(parser->user, tmp, end - cur + 1); + efree(tmp); + } else { + parser->h_default(parser->user, cur, end - cur + 1); + } + } +} + static void start_element_handler(void *user, const xmlChar *name, const xmlChar **attributes) { XML_Parser parser = (XML_Parser) user; if (parser->h_start_element == NULL) { - if (parser->h_default) { - int attno = 0; - smart_string qualified_name = {0}; - - smart_string_appendc(&qualified_name, '<'); - smart_string_appends(&qualified_name, (const char *) name); - - if (attributes) { - while (attributes[attno] != NULL) { - const char *att_name = (const char *) attributes[attno++]; - const char *att_value = (const char *) attributes[attno++]; - - smart_string_appendc(&qualified_name, ' '); - smart_string_appends(&qualified_name, att_name); - smart_string_appends(&qualified_name, "=\""); - smart_string_appends(&qualified_name, att_value); - smart_string_appendc(&qualified_name, '"'); - } - } - smart_string_appendc(&qualified_name, '>'); - smart_string_0(&qualified_name); - parser->h_default(parser->user, (const XML_Char *) qualified_name.c, qualified_name.len); - smart_string_free(&qualified_name); - } + start_element_emit_default(parser); return; } @@ -92,66 +91,14 @@ start_element_handler_ns(void *user, const xmlChar *name, const xmlChar *prefix, } if (parser->h_start_element == NULL) { - if (parser->h_default) { - smart_string qualified_name = {0}; - smart_string_appendc(&qualified_name, '<'); - if (prefix) { - smart_string_appends(&qualified_name, (const char *) prefix); - smart_string_appendc(&qualified_name, ':'); - } - smart_string_appends(&qualified_name, (const char *) name); - - if (namespaces) { - int i, j; - for (i = 0,j = 0;j < nb_namespaces;j++) { - const char *ns_prefix = (const char *) namespaces[i++]; - const char *ns_url = (const char *) namespaces[i++]; - - if (ns_prefix) { - smart_string_appends(&qualified_name, " xmlns:"); - smart_string_appends(&qualified_name, ns_prefix); - smart_string_appends(&qualified_name, "=\""); - } else { - smart_string_appends(&qualified_name, " xmlns=\""); - } - - smart_string_appends(&qualified_name, ns_url); - smart_string_appendc(&qualified_name, '"'); - } - } - - if (attributes) { - for (i = 0; i < nb_attributes; i += 1) { - const char *att_name = (const char *) attributes[y++]; - const char *att_prefix = (const char *)attributes[y++]; - y++; - const char *att_value = (const char *)attributes[y++]; - const char *att_valueend = (const char *)attributes[y++]; - - smart_string_appendc(&qualified_name, ' '); - if (att_prefix) { - smart_string_appends(&qualified_name, att_prefix); - smart_string_appendc(&qualified_name, ':'); - } - smart_string_appends(&qualified_name, att_name); - smart_string_appends(&qualified_name, "=\""); - - smart_string_appendl(&qualified_name, att_value, att_valueend - att_value); - smart_string_appendc(&qualified_name, '"'); - } - - } - smart_string_appendc(&qualified_name, '>'); - parser->h_default(parser->user, (const XML_Char *) qualified_name.c, qualified_name.len); - smart_string_free(&qualified_name); - } + start_element_emit_default(parser); return; } qualified_name = qualify_namespace(parser, name, URI); if (attributes != NULL) { xmlChar *qualified_name_attr = NULL; - attrs = safe_emalloc((nb_attributes * 2) + 1, sizeof(int *), 0); + attrs = safe_emalloc(nb_attributes, 2 * sizeof(int *), sizeof(int *)); for (i = 0; i < nb_attributes; i += 1) { @@ -697,19 +644,6 @@ XML_GetCurrentByteIndex(XML_Parser parser) (parser->parser->input->cur - parser->parser->input->base); } -PHP_XML_API int -XML_GetCurrentByteCount(XML_Parser parser) -{ - /* TODO: this is identical to ByteIndex; it should probably - * be different */ - return (int) XML_GetCurrentByteIndex(parser); -} - -PHP_XML_API const XML_Char *XML_ExpatVersion(void) -{ - return (const XML_Char *) "1.0"; -} - PHP_XML_API void XML_ParserFree(XML_Parser parser) { diff --git a/ext/xml/expat_compat.h b/ext/xml/expat_compat.h index 94ca8aeb4c351..a7faffbac504f 100644 --- a/ext/xml/expat_compat.h +++ b/ext/xml/expat_compat.h @@ -147,8 +147,6 @@ PHP_XML_API const XML_Char *XML_ErrorString(int); PHP_XML_API int XML_GetCurrentLineNumber(XML_Parser); PHP_XML_API int XML_GetCurrentColumnNumber(XML_Parser); PHP_XML_API long XML_GetCurrentByteIndex(XML_Parser); -PHP_XML_API int XML_GetCurrentByteCount(XML_Parser); -PHP_XML_API const XML_Char *XML_ExpatVersion(void); PHP_XML_API void XML_ParserFree(XML_Parser); #elif defined(HAVE_LIBEXPAT) diff --git a/ext/xml/tests/gh20439_1.phpt b/ext/xml/tests/gh20439_1.phpt new file mode 100644 index 0000000000000..cda6803e9d078 --- /dev/null +++ b/ext/xml/tests/gh20439_1.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-20439 (xml_set_default_handler() does not properly handle special characters in attributes when passing data to callback) +--EXTENSIONS-- +xml +--FILE-- +"; +$inputs = str_split($input); + +// Test chunked parser wrt non-progressive parser +foreach ($inputs as $input) { + xml_parse($x, $input, false); +} +xml_parse($x, "", true); + +?> +--EXPECT-- +string(12) "" +string(71) "" +string(6) "" diff --git a/ext/xml/tests/gh20439_2.phpt b/ext/xml/tests/gh20439_2.phpt new file mode 100644 index 0000000000000..dce4f5976a140 --- /dev/null +++ b/ext/xml/tests/gh20439_2.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-20439 (xml_set_default_handler() does not properly handle special characters in attributes when passing data to callback) - closing solidus variant +--EXTENSIONS-- +xml +--SKIPIF-- + +--FILE-- +"; +xml_parse($x, $input, true); + +?> +--EXPECT-- +string(29) "" +string(10) "" diff --git a/ext/xml/xml.c b/ext/xml/xml.c index 813718bb8a229..7a9329bcc8041 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -64,11 +64,7 @@ typedef struct { XML_Parser parser; XML_Char *target_encoding; - /* Reference to the object itself, for convenience. - * It is not owned, do not release it. */ - zval index; - - zend_object *object; + zend_object *object; /* object with handlers */ zend_fcall_info_cache startElementHandler; zend_fcall_info_cache endElementHandler; zend_fcall_info_cache characterDataHandler; @@ -135,7 +131,7 @@ inline static char xml_decode_iso_8859_1(unsigned short); inline static unsigned short xml_encode_us_ascii(unsigned char); inline static char xml_decode_us_ascii(unsigned short); static void xml_xmlchar_zval(const XML_Char *, int, const XML_Char *, zval *); -static int xml_xmlcharlen(const XML_Char *); +static size_t xml_xmlcharlen(const XML_Char *); static void xml_add_to_info(xml_parser *parser, zend_string *name); inline static zend_string *xml_decode_tag(xml_parser *parser, const XML_Char *tag); @@ -540,15 +536,9 @@ static zend_string *xml_utf8_decode(const XML_Char *s, size_t len, const XML_Cha /* }}} */ /* {{{ xml_xmlcharlen() */ -static int xml_xmlcharlen(const XML_Char *s) +static size_t xml_xmlcharlen(const XML_Char *s) { - int len = 0; - - while (*s) { - len++; - s++; - } - return len; + return strlen((const char *) s); } /* }}} */ @@ -641,7 +631,7 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha if (ZEND_FCC_INITIALIZED(parser->startElementHandler)) { zval args[3]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); ZVAL_STR(&args[1], xml_stripped_tag(tag_name, parser->toffset)); array_init(&args[2]); @@ -652,7 +642,7 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha val = xml_utf8_decode(attributes[1], strlen((char *)attributes[1]), parser->target_encoding); ZVAL_STR(&tmp, val); - zend_symtable_update(Z_ARRVAL(args[2]), att, &tmp); + zend_hash_update(Z_ARRVAL(args[2]), att, &tmp); attributes += 2; @@ -660,7 +650,6 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha } zend_call_known_fcc(&parser->startElementHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); zval_ptr_dtor(&args[2]); } @@ -693,7 +682,7 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha val = xml_utf8_decode(attributes[1], strlen((char *)attributes[1]), parser->target_encoding); ZVAL_STR(&tmp, val); - zend_symtable_update(Z_ARRVAL(atr), att, &tmp); + zend_hash_update(Z_ARRVAL(atr), att, &tmp); atcnt++; attributes += 2; @@ -742,11 +731,10 @@ void xml_endElementHandler(void *userData, const XML_Char *name) if (ZEND_FCC_INITIALIZED(parser->endElementHandler)) { zval args[2]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); ZVAL_STR(&args[1], xml_stripped_tag(tag_name, parser->toffset)); zend_call_known_fcc(&parser->endElementHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); } @@ -803,11 +791,10 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len) if (ZEND_FCC_INITIALIZED(parser->characterDataHandler)) { zval args[2]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); xml_xmlchar_zval(s, len, parser->target_encoding, &args[1]); zend_call_known_fcc(&parser->characterDataHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); } @@ -911,12 +898,11 @@ void xml_processingInstructionHandler(void *userData, const XML_Char *target, co zval args[3]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); xml_xmlchar_zval(target, 0, parser->target_encoding, &args[1]); xml_xmlchar_zval(data, 0, parser->target_encoding, &args[2]); zend_call_known_fcc(&parser->processingInstructionHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); zval_ptr_dtor_str(&args[2]); } @@ -933,11 +919,10 @@ void xml_defaultHandler(void *userData, const XML_Char *s, int len) zval args[2]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); xml_xmlchar_zval(s, len, parser->target_encoding, &args[1]); zend_call_known_fcc(&parser->defaultHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); } /* }}} */ @@ -955,7 +940,7 @@ void xml_unparsedEntityDeclHandler(void *userData, zval args[6]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); xml_xmlchar_zval(entityName, 0, parser->target_encoding, &args[1]); xml_xmlchar_zval(base, 0, parser->target_encoding, &args[2]); xml_xmlchar_zval(systemId, 0, parser->target_encoding, &args[3]); @@ -963,7 +948,6 @@ void xml_unparsedEntityDeclHandler(void *userData, xml_xmlchar_zval(notationName, 0, parser->target_encoding, &args[5]); zend_call_known_fcc(&parser->unparsedEntityDeclHandler, /* retval */ NULL, /* param_count */ 6, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); zval_ptr_dtor_str(&args[2]); zval_ptr_dtor_str(&args[3]); @@ -984,14 +968,13 @@ void xml_notationDeclHandler(void *userData, const XML_Char *notationName, zval args[5]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); xml_xmlchar_zval(notationName, 0, parser->target_encoding, &args[1]); xml_xmlchar_zval(base, 0, parser->target_encoding, &args[2]); xml_xmlchar_zval(systemId, 0, parser->target_encoding, &args[3]); xml_xmlchar_zval(publicId, 0, parser->target_encoding, &args[4]); zend_call_known_fcc(&parser->notationDeclHandler, /* retval */ NULL, /* param_count */ 5, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); zval_ptr_dtor_str(&args[2]); zval_ptr_dtor_str(&args[3]); @@ -1013,14 +996,13 @@ int xml_externalEntityRefHandler(XML_Parser userData, const XML_Char *openEntity zval args[5]; zval retval; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); xml_xmlchar_zval(openEntityNames, 0, parser->target_encoding, &args[1]); xml_xmlchar_zval(base, 0, parser->target_encoding, &args[2]); xml_xmlchar_zval(systemId, 0, parser->target_encoding, &args[3]); xml_xmlchar_zval(publicId, 0, parser->target_encoding, &args[4]); zend_call_known_fcc(&parser->externalEntityRefHandler, /* retval */ &retval, /* param_count */ 5, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); zval_ptr_dtor_str(&args[2]); zval_ptr_dtor_str(&args[3]); @@ -1048,12 +1030,11 @@ void xml_startNamespaceDeclHandler(void *userData,const XML_Char *prefix, const zval args[3]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); xml_xmlchar_zval(prefix, 0, parser->target_encoding, &args[1]); xml_xmlchar_zval(uri, 0, parser->target_encoding, &args[2]); zend_call_known_fcc(&parser->startNamespaceDeclHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); zval_ptr_dtor_str(&args[2]); } @@ -1070,11 +1051,10 @@ void xml_endNamespaceDeclHandler(void *userData, const XML_Char *prefix) zval args[2]; - ZVAL_COPY(&args[0], &parser->index); + ZVAL_OBJ(&args[0], &parser->std); xml_xmlchar_zval(prefix, 0, parser->target_encoding, &args[1]); zend_call_known_fcc(&parser->endNamespaceDeclHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL); - zval_ptr_dtor(&args[0]); zval_ptr_dtor_str(&args[1]); } /* }}} */ @@ -1133,7 +1113,6 @@ static void php_xml_parser_create_impl(INTERNAL_FUNCTION_PARAMETERS, int ns_supp parser->parsehuge = false; /* It's the default for BC & DoS protection */ XML_SetUserData(parser->parser, parser); - ZVAL_COPY_VALUE(&parser->index, return_value); } /* }}} */ diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 4e06b2106ce59..fd1a51c5776c3 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -37,10 +37,12 @@ #include "Zend/Optimizer/zend_optimizer.h" #include "Zend/zend_alloc.h" #include "test_arginfo.h" +#include "tmp_methods_arginfo.h" #include "zend_call_stack.h" #include "zend_exceptions.h" #include "zend_mm_custom_handlers.h" #include "ext/uri/php_uri.h" +#include "zend_observer.h" #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) # include @@ -1030,16 +1032,38 @@ static ZEND_FUNCTION(zend_test_log_err_debug) php_log_err_with_severity(ZSTR_VAL(str), LOG_DEBUG); } +typedef struct _zend_test_object { + zend_internal_function *tmp_method; + zend_object std; +} zend_test_object; + static zend_object *zend_test_class_new(zend_class_entry *class_type) { - zend_object *obj = zend_objects_new(class_type); - object_properties_init(obj, class_type); - obj->handlers = &zend_test_class_handlers; - return obj; + zend_test_object *intern = zend_object_alloc(sizeof(zend_test_object), class_type); + zend_object_std_init(&intern->std, class_type); + object_properties_init(&intern->std, class_type); + return &intern->std; +} + +static void zend_test_class_free_obj(zend_object *object) +{ + zend_test_object *intern = (zend_test_object*)((char*)object - XtOffsetOf(zend_test_object, std)); + + if (intern->tmp_method) { + zend_internal_function *func = intern->tmp_method; + intern->tmp_method = NULL; + zend_string_release_ex(func->function_name, 0); + zend_free_internal_arg_info(func, false); + efree(func); + } + + zend_object_std_dtor(object); } static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key) { + zend_test_object *intern = (zend_test_object*)((char*)(*object) - XtOffsetOf(zend_test_object, std)); + if (zend_string_equals_literal_ci(name, "test")) { zend_internal_function *fptr; @@ -1058,6 +1082,41 @@ static zend_function *zend_test_class_method_get(zend_object **object, zend_stri fptr->handler = ZEND_FN(zend_test_func); fptr->doc_comment = NULL; + return (zend_function*)fptr; + } else if (zend_string_equals_literal_ci(name, "testTmpMethodWithArgInfo")) { + if (intern->tmp_method) { + return (zend_function*)intern->tmp_method; + } + + const zend_function_entry *entry = &class_ZendTestTmpMethods_methods[0]; + zend_internal_function *fptr = emalloc(sizeof(zend_internal_function)); + memset(fptr, 0, sizeof(zend_internal_function)); + fptr->type = ZEND_INTERNAL_FUNCTION; + fptr->handler = entry->handler; + fptr->function_name = zend_string_init(entry->fname, strlen(entry->fname), false); + fptr->scope = intern->std.ce; + fptr->prototype = NULL; + fptr->T = ZEND_OBSERVER_ENABLED; + fptr->fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_NEVER_CACHE; + + zend_internal_function_info *info = (zend_internal_function_info*)entry->arg_info; + + uint32_t num_arg_info = 1 + entry->num_args; + zend_arg_info *arg_info = safe_emalloc(num_arg_info, sizeof(zend_arg_info), 0); + for (uint32_t i = 0; i < num_arg_info; i++) { + zend_convert_internal_arg_info(&arg_info[i], &entry->arg_info[i], i == 0, false); + } + + fptr->arg_info = arg_info + 1; + fptr->num_args = entry->num_args; + if (info->required_num_args == (uint32_t)-1) { + fptr->required_num_args = entry->num_args; + } else { + fptr->required_num_args = info->required_num_args; + } + + intern->tmp_method = fptr; + return (zend_function*)fptr; } return zend_std_get_method(object, name, key); @@ -1145,6 +1204,18 @@ static ZEND_METHOD(_ZendTestClass, variadicTest) { object_init_ex(return_value, zend_get_called_scope(execute_data)); } +ZEND_METHOD(ZendTestTmpMethods, testTmpMethodWithArgInfo) +{ + zend_object *obj; + zend_string *str; + + ZEND_PARSE_PARAMETERS_START(0, 2); + Z_PARAM_OPTIONAL; + Z_PARAM_OBJ_OR_NULL(obj); + Z_PARAM_STR(str); + ZEND_PARSE_PARAMETERS_END(); +} + static ZEND_METHOD(_ZendTestChildClass, returnsThrowable) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1450,11 +1521,14 @@ PHP_MINIT_FUNCTION(zend_test) register_ZendTestClass_dnf_property(zend_test_class); zend_test_class->create_object = zend_test_class_new; zend_test_class->get_static_method = zend_test_class_static_method_get; + zend_test_class->default_object_handlers = &zend_test_class_handlers; zend_test_child_class = register_class__ZendTestChildClass(zend_test_class); memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers)); zend_test_class_handlers.get_method = zend_test_class_method_get; + zend_test_class_handlers.free_obj = zend_test_class_free_obj; + zend_test_class_handlers.offset = XtOffsetOf(zend_test_object, std); zend_test_gen_stub_flag_compatibility_test = register_class_ZendTestGenStubFlagCompatibilityTest(); diff --git a/ext/zend_test/tmp_methods.stub.php b/ext/zend_test/tmp_methods.stub.php new file mode 100644 index 0000000000000..af479c7d5422f --- /dev/null +++ b/ext/zend_test/tmp_methods.stub.php @@ -0,0 +1,11 @@ +comp_method = zval_get_long(option); + zend_long comp_method = zval_get_long(option); + if (comp_method < 0 || comp_method > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Option \"comp_method\" must be between 0 and %d", INT_MAX); + } + opts->comp_method = (zip_int32_t)comp_method; if ((option = zend_hash_str_find(options, "comp_flags", sizeof("comp_flags") - 1)) != NULL) { if (Z_TYPE_P(option) != IS_LONG) { php_error_docref(NULL, E_WARNING, "Option \"comp_flags\" must be of type int, %s given", zend_zval_value_name(option)); } - opts->comp_flags = zval_get_long(option); + zend_long comp_flags = zval_get_long(option); + if (comp_flags < 0 || comp_flags > USHRT_MAX) { + php_error_docref(NULL, E_WARNING, "Option \"comp_flags\" must be between 0 and %u", USHRT_MAX); + } + opts->comp_flags = (zip_uint32_t)comp_flags; } } @@ -909,17 +928,16 @@ static int php_zip_has_property(zend_object *object, zend_string *name, int type if (hnd != NULL) { zval tmp, *prop; - if (type == 2) { + if (type == ZEND_PROPERTY_EXISTS) { retval = true; } else if ((prop = php_zip_property_reader(obj, hnd, &tmp)) != NULL) { - if (type == 1) { + if (type == ZEND_PROPERTY_NOT_EMPTY) { retval = zend_is_true(&tmp); - } else if (type == 0) { + } else if (type == ZEND_PROPERTY_ISSET) { retval = (Z_TYPE(tmp) != IS_NULL); } + zval_ptr_dtor(&tmp); } - - zval_ptr_dtor(&tmp); } else { retval = zend_std_has_property(object, name, type, cache_slot); } @@ -1014,7 +1032,7 @@ static void php_zip_object_free_storage(zend_object *object) /* {{{ */ if (intern->buffers_cnt>0) { for (i=0; ibuffers_cnt; i++) { - efree(intern->buffers[i]); + zend_string_release(intern->buffers[i]); } efree(intern->buffers); } @@ -1285,7 +1303,6 @@ PHP_FUNCTION(zip_entry_read) zend_long len = 0; zip_read_rsrc * zr_rsrc; zend_string *buffer; - int n = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &zip_entry, &len) == FAILURE) { RETURN_THROWS(); @@ -1301,7 +1318,7 @@ PHP_FUNCTION(zip_entry_read) if (zr_rsrc->zf) { buffer = zend_string_safe_alloc(1, len, 0, false); - n = zip_fread(zr_rsrc->zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer)); + zip_int64_t n = zip_fread(zr_rsrc->zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer)); if (n > 0) { ZSTR_VAL(buffer)[n] = '\0'; ZSTR_LEN(buffer) = n; @@ -1752,12 +1769,7 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* } #ifdef HAVE_ENCRYPTION if (opts.enc_method >= 0) { - if (UNEXPECTED(zip_file_set_encryption(ze_obj->za, ze_obj->last_id, ZIP_EM_NONE, NULL) < 0)) { - zend_array_destroy(Z_ARR_P(return_value)); - php_error_docref(NULL, E_WARNING, "password reset failed"); - RETURN_FALSE; - } - if (zip_file_set_encryption(ze_obj->za, ze_obj->last_id, opts.enc_method, opts.enc_password)) { + if (!php_zip_file_set_encryption(ze_obj->za, ze_obj->last_id, opts.enc_method, opts.enc_password)) { zend_array_destroy(Z_ARR_P(return_value)); RETURN_FALSE; } @@ -1868,17 +1880,16 @@ PHP_METHOD(ZipArchive, addFromString) ze_obj = Z_ZIP_P(self); if (ze_obj->buffers_cnt) { - ze_obj->buffers = (char **)safe_erealloc(ze_obj->buffers, sizeof(char *), (ze_obj->buffers_cnt+1), 0); + ze_obj->buffers = safe_erealloc(ze_obj->buffers, sizeof(*ze_obj->buffers), (ze_obj->buffers_cnt + 1), 0); pos = ze_obj->buffers_cnt++; } else { - ze_obj->buffers = (char **)emalloc(sizeof(char *)); + ze_obj->buffers = emalloc(sizeof(*ze_obj->buffers)); ze_obj->buffers_cnt++; pos = 0; } - ze_obj->buffers[pos] = (char *)safe_emalloc(ZSTR_LEN(buffer), 1, 1); - memcpy(ze_obj->buffers[pos], ZSTR_VAL(buffer), ZSTR_LEN(buffer) + 1); + ze_obj->buffers[pos] = zend_string_copy(buffer); - zs = zip_source_buffer(intern, ze_obj->buffers[pos], ZSTR_LEN(buffer), 0); + zs = zip_source_buffer(intern, ZSTR_VAL(buffer), ZSTR_LEN(buffer), 0); if (zs == NULL) { RETURN_FALSE; @@ -2280,15 +2291,7 @@ PHP_METHOD(ZipArchive, setEncryptionName) RETURN_FALSE; } - if (UNEXPECTED(zip_file_set_encryption(intern, idx, ZIP_EM_NONE, NULL) < 0)) { - php_error_docref(NULL, E_WARNING, "password reset failed"); - RETURN_FALSE; - } - - if (zip_file_set_encryption(intern, idx, (zip_uint16_t)method, password)) { - RETURN_FALSE; - } - RETURN_TRUE; + RETURN_BOOL(php_zip_file_set_encryption(intern, idx, method, password)); } /* }}} */ @@ -2308,12 +2311,7 @@ PHP_METHOD(ZipArchive, setEncryptionIndex) ZIP_FROM_OBJECT(intern, self); - if (UNEXPECTED(zip_file_set_encryption(intern, index, ZIP_EM_NONE, NULL) < 0)) { - php_error_docref(NULL, E_WARNING, "password reset failed"); - RETURN_FALSE; - } - - RETURN_BOOL(zip_file_set_encryption(intern, index, (zip_uint16_t)method, password) == 0); + RETURN_BOOL(php_zip_file_set_encryption(intern, index, method, password)); } /* }}} */ #endif @@ -2391,13 +2389,23 @@ PHP_METHOD(ZipArchive, setCompressionName) RETURN_THROWS(); } - ZIP_FROM_OBJECT(intern, this); - if (name_len == 0) { zend_argument_must_not_be_empty_error(1); RETURN_THROWS(); } + if (comp_method < -1 || comp_method > INT_MAX) { + zend_argument_value_error(2, "must be between -1 and %d", INT_MAX); + RETURN_THROWS(); + } + + if (comp_flags < 0 || comp_flags > USHRT_MAX) { + // comp_flags is cast down accordingly in libzip, zip_entry_t compression_level is of zip_uint16_t + zend_argument_value_error(3, "must be between 0 and %u", USHRT_MAX); + RETURN_THROWS(); + } + + ZIP_FROM_OBJECT(intern, this); idx = zip_name_locate(intern, name, 0); if (idx < 0) { @@ -2422,6 +2430,21 @@ PHP_METHOD(ZipArchive, setCompressionIndex) RETURN_THROWS(); } + if (index < 0) { + RETURN_FALSE; + } + + if (comp_method < -1 || comp_method > INT_MAX) { + zend_argument_value_error(2, "must be between -1 and %d", INT_MAX); + RETURN_THROWS(); + } + + if (comp_flags < 0 || comp_flags > USHRT_MAX) { + // comp_flags is cast down accordingly in libzip, zip_entry_t compression_level is of zip_uint16_t + zend_argument_value_error(3, "must be between 0 and %u", USHRT_MAX); + RETURN_THROWS(); + } + ZIP_FROM_OBJECT(intern, this); RETURN_BOOL(zip_set_file_compression(intern, (zip_uint64_t)index, @@ -2444,13 +2467,13 @@ PHP_METHOD(ZipArchive, setMtimeName) RETURN_THROWS(); } - ZIP_FROM_OBJECT(intern, this); - if (name_len == 0) { zend_argument_must_not_be_empty_error(1); RETURN_THROWS(); } + ZIP_FROM_OBJECT(intern, this); + idx = zip_name_locate(intern, name, 0); if (idx < 0) { @@ -2516,17 +2539,15 @@ PHP_METHOD(ZipArchive, deleteName) RETURN_THROWS(); } - ZIP_FROM_OBJECT(intern, self); - if (name_len < 1) { RETURN_FALSE; } + ZIP_FROM_OBJECT(intern, self); + PHP_ZIP_STAT_PATH(intern, name, name_len, 0, sb); - if (zip_delete(intern, sb.index)) { - RETURN_FALSE; - } - RETURN_TRUE; + + RETURN_BOOL(zip_delete(intern, sb.index) == 0); } /* }}} */ @@ -2547,13 +2568,13 @@ PHP_METHOD(ZipArchive, renameIndex) RETURN_FALSE; } - ZIP_FROM_OBJECT(intern, self); - if (new_name_len == 0) { zend_argument_must_not_be_empty_error(2); RETURN_THROWS(); } + ZIP_FROM_OBJECT(intern, self); + RETURN_BOOL(zip_file_rename(intern, index, (const char *)new_name, 0) == 0); } /* }}} */ @@ -2595,12 +2616,12 @@ PHP_METHOD(ZipArchive, unchangeIndex) RETURN_THROWS(); } - ZIP_FROM_OBJECT(intern, self); - if (index < 0) { RETURN_FALSE; } + ZIP_FROM_OBJECT(intern, self); + RETURN_BOOL(zip_unchange(intern, index) == 0); } /* }}} */ @@ -2618,12 +2639,12 @@ PHP_METHOD(ZipArchive, unchangeName) RETURN_THROWS(); } - ZIP_FROM_OBJECT(intern, self); - if (name_len < 1) { RETURN_FALSE; } + ZIP_FROM_OBJECT(intern, self); + PHP_ZIP_STAT_PATH(intern, name, name_len, 0, sb); RETURN_BOOL(zip_unchange(intern, sb.index) == 0); @@ -2687,8 +2708,6 @@ PHP_METHOD(ZipArchive, extractTo) Z_PARAM_ARRAY_HT_OR_STR_OR_NULL(files_ht, files_str) ZEND_PARSE_PARAMETERS_END(); - ZIP_FROM_OBJECT(intern, self); - if (pathto_len < 1) { RETURN_FALSE; } @@ -2701,6 +2720,7 @@ PHP_METHOD(ZipArchive, extractTo) } uint32_t nelems, i; + ZIP_FROM_OBJECT(intern, self); if (files_str) { if (!php_zip_extract_file(intern, pathto, ZSTR_VAL(files_str), ZSTR_LEN(files_str), -1)) { @@ -2760,8 +2780,6 @@ static void php_zip_get_from(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */ zend_string *filename; zend_string *buffer; - int n = 0; - if (type == 1) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|ll", &filename, &len, &flags) == FAILURE) { RETURN_THROWS(); @@ -2797,8 +2815,8 @@ static void php_zip_get_from(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */ RETURN_FALSE; } - buffer = zend_string_safe_alloc(1, len, 0, 0); - n = zip_fread(zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer)); + buffer = zend_string_safe_alloc(1, len, 0, false); + zip_int64_t n = zip_fread(zf, ZSTR_VAL(buffer), ZSTR_LEN(buffer)); if (n < 1) { zend_string_efree(buffer); RETURN_EMPTY_STRING(); @@ -3006,6 +3024,10 @@ PHP_METHOD(ZipArchive, isCompressionMethodSupported) if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &method, &enc) == FAILURE) { return; } + if (method < -1 || method > INT_MAX) { + zend_argument_value_error(1, "must be between -1 and %d", INT_MAX); + RETURN_THROWS(); + } RETVAL_BOOL(zip_compression_method_supported((zip_int32_t)method, enc)); } /* }}} */ @@ -3019,7 +3041,11 @@ PHP_METHOD(ZipArchive, isEncryptionMethodSupported) if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &method, &enc) == FAILURE) { return; } - RETVAL_BOOL(zip_encryption_method_supported((zip_uint16_t)method, enc)); + if (method < 0 || method > USHRT_MAX) { + zend_argument_value_error(1, "must be between 0 and %u", USHRT_MAX); + RETURN_THROWS(); + } + RETURN_BOOL(zip_encryption_method_supported((zip_uint16_t)method, enc)); } /* }}} */ #endif diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h index 61e7fb8dad1ea..5dc7bab250042 100644 --- a/ext/zip/php_zip.h +++ b/ext/zip/php_zip.h @@ -68,7 +68,7 @@ typedef struct _ze_zip_read_rsrc { /* Extends zend object */ typedef struct _ze_zip_object { struct zip *za; - char **buffers; + zend_string **buffers; HashTable *prop_handler; char *filename; int filename_len; diff --git a/ext/zip/tests/oo_addglob2.phpt b/ext/zip/tests/oo_addglob2.phpt index 517c0b7fd7fda..a98a222712052 100644 --- a/ext/zip/tests/oo_addglob2.phpt +++ b/ext/zip/tests/oo_addglob2.phpt @@ -33,10 +33,26 @@ if (!$zip->addGlob($dirname . 'foo.*', GLOB_BRACE, $options)) { $options = [ 'remove_all_path' => true, 'comp_method' => ZipArchive::CM_STORE, - 'comp_flags' => 5, + 'comp_flags' => PHP_INT_MIN, 'enc_method' => ZipArchive::EM_AES_256, 'enc_password' => 'secret', ]; + +try { + $zip->addGlob($dirname. 'bar.*', GLOB_BRACE, $options); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +$options['comp_flags'] = 65536; + +try { + $zip->addGlob($dirname. 'bar.*', GLOB_BRACE, $options); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +$options['comp_flags'] = 5; if (!$zip->addGlob($dirname . 'bar.*', GLOB_BRACE, $options)) { echo "failed 2\n"; } @@ -61,6 +77,10 @@ $dirname = __DIR__ . '/'; include $dirname . 'utils.inc'; rmdir_rf(__DIR__ . '/__tmp_oo_addglob2/'); ?> ---EXPECT-- +--EXPECTF-- + +Warning: ZipArchive::addGlob(): Option "comp_flags" must be between 0 and 65535 in %s on line %d + +Warning: ZipArchive::addGlob(): Option "comp_flags" must be between 0 and 65535 in %s on line %d 0: foo.txt, comp=8, enc=0 1: bar.txt, comp=0, enc=259 diff --git a/ext/zip/tests/oo_setcompression.phpt b/ext/zip/tests/oo_setcompression.phpt index 6b3291463659b..1b7e817688dde 100644 --- a/ext/zip/tests/oo_setcompression.phpt +++ b/ext/zip/tests/oo_setcompression.phpt @@ -28,6 +28,18 @@ var_dump($zip->setCompressionName('entry2.txt', ZipArchive::CM_DEFAULT)); var_dump($zip->setCompressionName('dir/entry3.txt', ZipArchive::CM_STORE)); var_dump($zip->setCompressionName('entry4.txt', ZipArchive::CM_DEFLATE)); +try { + $zip->setCompressionName('entry5.txt', PHP_INT_MIN); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + $zip->setCompressionIndex(4, PHP_INT_MIN); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + var_dump($zip->setCompressionIndex(4, ZipArchive::CM_STORE)); var_dump($zip->setCompressionIndex(5, ZipArchive::CM_DEFLATE)); var_dump($zip->setCompressionIndex(6, ZipArchive::CM_DEFAULT)); @@ -57,6 +69,8 @@ unlink($tmpfile); bool(true) bool(true) bool(true) +ZipArchive::setCompressionName(): Argument #2 ($method) must be between -1 and %d +ZipArchive::setCompressionIndex(): Argument #2 ($method) must be between -1 and %d bool(true) bool(true) bool(true) diff --git a/ext/zip/tests/oo_setcompression_64bit.phpt b/ext/zip/tests/oo_setcompression_64bit.phpt new file mode 100644 index 0000000000000..cb093e8ccfc9d --- /dev/null +++ b/ext/zip/tests/oo_setcompression_64bit.phpt @@ -0,0 +1,29 @@ +--TEST-- +setCompressionName and setCompressionIndex methods +--EXTENSIONS-- +zip +--SKIPIF-- + +--FILE-- +setCompressionName('entry5.txt', PHP_INT_MAX); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + $zip->setCompressionIndex(4, PHP_INT_MAX); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +?> +--EXPECTF-- +ZipArchive::setCompressionName(): Argument #2 ($method) must be between -1 and %d +ZipArchive::setCompressionIndex(): Argument #2 ($method) must be between -1 and %d diff --git a/ext/zip/tests/property_existence_test.phpt b/ext/zip/tests/property_existence_test.phpt new file mode 100644 index 0000000000000..855bf73464ac1 --- /dev/null +++ b/ext/zip/tests/property_existence_test.phpt @@ -0,0 +1,20 @@ +--TEST-- +Property existence test can cause a crash +--EXTENSIONS-- +zip +--FILE-- + +--CLEAN-- + +--EXPECT-- +array(1) { + [0]=> + int(-1) +} diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c index 76e4588f249e5..50f097de3c876 100644 --- a/ext/zip/zip_stream.c +++ b/ext/zip/zip_stream.c @@ -150,7 +150,7 @@ static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ fragment++; if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) { - zend_string_release_ex(file_basename, 0); + zend_string_release_ex(file_basename, false); return -1; } @@ -159,7 +159,7 @@ static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ memset(ssb, 0, sizeof(php_stream_statbuf)); if (zip_stat(za, fragment, ZIP_FL_NOCASE, &sb) != 0) { zip_close(za); - zend_string_release_ex(file_basename, 0); + zend_string_release_ex(file_basename, false); return -1; } zip_close(za); @@ -183,7 +183,7 @@ static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ #endif ssb->sb.st_ino = -1; } - zend_string_release_ex(file_basename, 0); + zend_string_release_ex(file_basename, false); return 0; } /* }}} */ @@ -312,7 +312,7 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, fragment++; if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) { - zend_string_release_ex(file_basename, 0); + zend_string_release_ex(file_basename, false); return NULL; } @@ -344,14 +344,14 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, } if (opened_path) { - *opened_path = zend_string_init(path, strlen(path), 0); + *opened_path = zend_string_init(path, path_len, false); } } else { zip_close(za); } } - zend_string_release_ex(file_basename, 0); + zend_string_release_ex(file_basename, false); if (!stream) { return NULL; diff --git a/ext/zlib/tests/filter_broken_object_options.phpt b/ext/zlib/tests/filter_broken_object_options.phpt new file mode 100644 index 0000000000000..beb0fef9fb137 --- /dev/null +++ b/ext/zlib/tests/filter_broken_object_options.phpt @@ -0,0 +1,21 @@ +--TEST-- +zlib filter assertion failure with non-dynamic properties in filter param object +--EXTENSIONS-- +zlib +--FILE-- + +--EXPECT-- +Hello world, hopefully not broken diff --git a/ext/zlib/tests/gzseek_seek_oob.phpt b/ext/zlib/tests/gzseek_seek_oob.phpt new file mode 100644 index 0000000000000..e05ea4778b94b --- /dev/null +++ b/ext/zlib/tests/gzseek_seek_oob.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test function gzseek() by seeking out of bounds +--EXTENSIONS-- +zlib +--FILE-- + +--EXPECT-- +int(-1) +int(0) +int(0) diff --git a/ext/zlib/tests/inflate_init_error.phpt b/ext/zlib/tests/inflate_init_error.phpt index 8faed763be4e5..9854f7453909b 100644 --- a/ext/zlib/tests/inflate_init_error.phpt +++ b/ext/zlib/tests/inflate_init_error.phpt @@ -13,4 +13,4 @@ try { ?> --EXPECT-- -Encoding mode must be ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE +inflate_init(): Argument #1 ($encoding) must be one of ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP, or ZLIB_ENCODING_DEFLATE diff --git a/ext/zlib/tests/leak_invalid_encoding_with_dict.phpt b/ext/zlib/tests/leak_invalid_encoding_with_dict.phpt index da2a11849c0c2..507e6842cb587 100644 --- a/ext/zlib/tests/leak_invalid_encoding_with_dict.phpt +++ b/ext/zlib/tests/leak_invalid_encoding_with_dict.phpt @@ -16,5 +16,5 @@ try { } ?> --EXPECT-- -Encoding mode must be ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE +inflate_init(): Argument #1 ($encoding) must be one of ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP, or ZLIB_ENCODING_DEFLATE deflate_init(): Argument #1 ($encoding) must be one of ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP, or ZLIB_ENCODING_DEFLATE diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 0b08cea7d69ec..68c5572931b66 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -887,7 +887,7 @@ PHP_FUNCTION(inflate_init) case PHP_ZLIB_ENCODING_DEFLATE: break; default: - zend_value_error("Encoding mode must be ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE"); + zend_argument_value_error(1, "must be one of ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP, or ZLIB_ENCODING_DEFLATE"); RETURN_THROWS(); } diff --git a/ext/zlib/zlib_filter.c b/ext/zlib/zlib_filter.c index 6da5ff2a5959f..e42132fd0008c 100644 --- a/ext/zlib/zlib_filter.c +++ b/ext/zlib/zlib_filter.c @@ -323,7 +323,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f zval *tmpzval; if ((Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) && - (tmpzval = zend_hash_str_find(HASH_OF(filterparams), "window", sizeof("window") - 1))) { + (tmpzval = zend_hash_str_find_ind(HASH_OF(filterparams), "window", sizeof("window") - 1))) { /* log-2 base of history window (9 - 15) */ zend_long tmp = zval_get_long(tmpzval); if (tmp < -MAX_WBITS || tmp > MAX_WBITS + 32) { @@ -354,8 +354,10 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f switch (Z_TYPE_P(filterparams)) { case IS_ARRAY: - case IS_OBJECT: - if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "memory", sizeof("memory") -1))) { + case IS_OBJECT: { + HashTable *ht = HASH_OF(filterparams); + + if ((tmpzval = zend_hash_str_find_ind(ht, "memory", sizeof("memory") -1))) { /* Memory Level (1 - 9) */ tmp = zval_get_long(tmpzval); if (tmp < 1 || tmp > MAX_MEM_LEVEL) { @@ -365,7 +367,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f } } - if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "window", sizeof("window") - 1))) { + if ((tmpzval = zend_hash_str_find_ind(ht, "window", sizeof("window") - 1))) { /* log-2 base of history window (9 - 15) */ tmp = zval_get_long(tmpzval); if (tmp < -MAX_WBITS || tmp > MAX_WBITS + 16) { @@ -375,13 +377,14 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f } } - if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "level", sizeof("level") - 1))) { + if ((tmpzval = zend_hash_str_find_ind(ht, "level", sizeof("level") - 1))) { tmp = zval_get_long(tmpzval); /* Pseudo pass through to catch level validating code */ goto factory_setlevel; } break; + } case IS_STRING: case IS_DOUBLE: case IS_LONG: diff --git a/ext/zlib/zlib_fopen_wrapper.c b/ext/zlib/zlib_fopen_wrapper.c index bcf0e33c56ef1..7420c0cc6ff2e 100644 --- a/ext/zlib/zlib_fopen_wrapper.c +++ b/ext/zlib/zlib_fopen_wrapper.c @@ -108,9 +108,14 @@ static int php_gziop_seek(php_stream *stream, zend_off_t offset, int whence, zen php_error_docref(NULL, E_WARNING, "SEEK_END is not supported"); return -1; } - *newoffs = gzseek(self->gz_file, offset, whence); - return (*newoffs < 0) ? -1 : 0; + z_off_t new_offset = gzseek(self->gz_file, offset, whence); + if (new_offset < 0) { + return -1; + } + + *newoffs = new_offset; + return 0; } static int php_gziop_close(php_stream *stream, int close_handle) diff --git a/main/main.c b/main/main.c index 6d29d3462b517..f190eab3d094f 100644 --- a/main/main.c +++ b/main/main.c @@ -350,7 +350,8 @@ static PHP_INI_MH(OnChangeMemoryLimit) } zend_ini_entry *max_mem_limit_ini = zend_hash_str_find_ptr(EG(ini_directives), ZEND_STRL("max_memory_limit")); - entry->value = zend_string_copy(max_mem_limit_ini->value); + entry->value = zend_string_init(ZSTR_VAL(max_mem_limit_ini->value), ZSTR_LEN(max_mem_limit_ini->value), true); + GC_MAKE_PERSISTENT_LOCAL(entry->value); PG(memory_limit) = PG(max_memory_limit); return SUCCESS; diff --git a/main/network.c b/main/network.c index 6c43321cf2e8a..96953531c3761 100644 --- a/main/network.c +++ b/main/network.c @@ -317,6 +317,8 @@ static inline void php_network_set_limit_time(struct timeval *limit_time, struct timeval *timeout) { gettimeofday(limit_time, NULL); + const double timeoutmax = (double) PHP_TIMEOUT_ULL_MAX / 1000000.0; + ZEND_ASSERT(limit_time->tv_sec < (timeoutmax - timeout->tv_sec)); limit_time->tv_sec += timeout->tv_sec; limit_time->tv_usec += timeout->tv_usec; if (limit_time->tv_usec >= 1000000) { diff --git a/main/output.c b/main/output.c index c75b09e86c18b..c90e4426d6cde 100644 --- a/main/output.c +++ b/main/output.c @@ -187,8 +187,12 @@ PHPAPI void php_output_deactivate(void) /* release all output handlers */ if (OG(handlers).elements) { while ((handler = zend_stack_top(&OG(handlers)))) { - php_output_handler_free(handler); zend_stack_del_top(&OG(handlers)); + /* It's possible to start a new output handler and mark it as active, + * however this loop will destroy all active handlers. */ + OG(active) = NULL; + ZEND_ASSERT(OG(running) == NULL && "output is deactivated therefore running should stay NULL"); + php_output_handler_free(handler); } } zend_stack_destroy(&OG(handlers)); @@ -718,10 +722,11 @@ PHPAPI void php_output_handler_dtor(php_output_handler *handler) * Destroy and free an output handler */ PHPAPI void php_output_handler_free(php_output_handler **h) { - if (*h) { - php_output_handler_dtor(*h); - efree(*h); + php_output_handler *handler = *h; + if (handler) { *h = NULL; + php_output_handler_dtor(handler); + efree(handler); } } /* }}} */ @@ -956,7 +961,6 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl if (handler->flags & PHP_OUTPUT_HANDLER_USER) { zval ob_args[2]; zval retval; - ZVAL_UNDEF(&retval); /* ob_data */ ZVAL_STRINGL(&ob_args[0], handler->buffer.data, handler->buffer.used); @@ -969,17 +973,10 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl handler->func.user->fci.retval = &retval; if (SUCCESS == zend_call_function(&handler->func.user->fci, &handler->func.user->fcc) && Z_TYPE(retval) != IS_UNDEF) { - if (Z_TYPE(retval) != IS_STRING || handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { + if (handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { // Make sure that we don't get lost in the current output buffer // by disabling it handler->flags |= PHP_OUTPUT_HANDLER_DISABLED; - // Make sure we keep a reference to the handler name in - // case - // * The handler produced output *and* returned a non-string - // * The first deprecation message causes the handler to - // be removed - zend_string *handler_name = handler->name; - zend_string_addref(handler_name); if (handler->flags & PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT) { // The handler might not always produce output handler->flags &= ~PHP_OUTPUT_HANDLER_PRODUCED_OUTPUT; @@ -987,18 +984,9 @@ static inline php_output_handler_status_t php_output_handler_op(php_output_handl NULL, E_DEPRECATED, "Producing output from user output handler %s is deprecated", - ZSTR_VAL(handler_name) - ); - } - if (Z_TYPE(retval) != IS_STRING) { - php_error_docref( - NULL, - E_DEPRECATED, - "Returning a non-string result from user output handler %s is deprecated", - ZSTR_VAL(handler_name) + ZSTR_VAL(handler->name) ); } - zend_string_release(handler_name); // Check if the handler is still in the list of handlers to // determine if the PHP_OUTPUT_HANDLER_DISABLED flag can diff --git a/main/php.h b/main/php.h index 8bb47ed275825..32222cfca94e0 100644 --- a/main/php.h +++ b/main/php.h @@ -23,7 +23,6 @@ #endif #define PHP_API_VERSION 20250926 -#define PHP_HAVE_STREAMS #define YYDEBUG 0 #define PHP_DEFAULT_CHARSET "UTF-8" diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index da6732f06e72a..046e2174dc1d8 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -304,7 +304,7 @@ static int status_comp(const void *a, const void *b) /* {{{ */ static const char *get_status_string(int code) /* {{{ */ { - http_response_status_code_pair needle = {code, NULL}, + const http_response_status_code_pair needle = {code, NULL}, *result = NULL; result = bsearch(&needle, http_status_map, http_status_map_len, sizeof(needle), status_comp); @@ -395,13 +395,7 @@ static void append_essential_headers(smart_str* buffer, php_cli_server_client *c static const char *get_mime_type(const php_cli_server *server, const char *ext, size_t ext_len) /* {{{ */ { - char *ret; - ALLOCA_FLAG(use_heap) - char *ext_lower = do_alloca(ext_len + 1, use_heap); - zend_str_tolower_copy(ext_lower, ext, ext_len); - ret = zend_hash_str_find_ptr(&server->extension_mime_types, ext_lower, ext_len); - free_alloca(ext_lower, use_heap); - return (const char*)ret; + return zend_hash_str_find_ptr_lc(&server->extension_mime_types, ext, ext_len); } /* }}} */ PHP_FUNCTION(apache_request_headers) /* {{{ */ diff --git a/sapi/fpm/www.conf.in b/sapi/fpm/www.conf.in index 69df3e6630047..f39e371ea70fe 100644 --- a/sapi/fpm/www.conf.in +++ b/sapi/fpm/www.conf.in @@ -329,7 +329,7 @@ pm.max_spare_servers = 3 ; it must be associated with embraces to specify the name of the header: ; - %{Content-Type}o ; - %{X-Powered-By}o -; - %{Transfert-Encoding}o +; - %{Transfer-Encoding}o ; - .... ; %p: PID of the child that serviced the request ; %P: PID of the parent of the child that serviced the request diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index bc2bb08c70278..4ef83be1b9f47 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -493,7 +493,7 @@ PHP_FUNCTION(phpdbg_get_executable) HashTable *files = &PHPDBG_G(file_sources); HashTable files_tmp; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|h", &options) == FAILURE) { RETURN_THROWS(); } @@ -587,7 +587,7 @@ PHP_FUNCTION(phpdbg_end_oplog) bool by_function = false; bool by_opcode = false; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|h", &options) == FAILURE) { RETURN_THROWS(); } diff --git a/sapi/phpdbg/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c index a8f1bf01433b7..01b19de80a995 100644 --- a/sapi/phpdbg/phpdbg_frame.c +++ b/sapi/phpdbg/phpdbg_frame.c @@ -34,11 +34,7 @@ static inline void phpdbg_append_individual_arg(smart_str *s, uint32_t i, zend_f } if (i < func->common.num_args) { if (arginfo) { - if (func->type == ZEND_INTERNAL_FUNCTION) { - arg_name = (char *) ((zend_internal_arg_info *) &arginfo[i])->name; - } else { - arg_name = ZSTR_VAL(arginfo[i].name); - } + arg_name = ZSTR_VAL(arginfo[i].name); } smart_str_appends(s, arg_name ? arg_name : "?"); smart_str_appendc(s, '='); @@ -213,11 +209,7 @@ static void phpdbg_dump_prototype(zval *tmp) /* {{{ */ char *arg_name = NULL; if (arginfo) { - if (func->type == ZEND_INTERNAL_FUNCTION) { - arg_name = (char *)((zend_internal_arg_info *)&arginfo[j])->name; - } else { - arg_name = ZSTR_VAL(arginfo[j].name); - } + arg_name = ZSTR_VAL(arginfo[j].name); } if (!is_variadic) { diff --git a/tests/basic/gh17951_runtime_change_6.phpt b/tests/basic/gh17951_runtime_change_6.phpt new file mode 100644 index 0000000000000..0c62b0e837474 --- /dev/null +++ b/tests/basic/gh17951_runtime_change_6.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-17951 Runtime Change 6 +--INI-- +memory_limit=128M +max_memory_limit=512M +--FILE-- + +--EXPECTF-- +Warning: Failed to set memory_limit to 1073741824 bytes. Setting to max_memory_limit instead (currently: 536870912 bytes) in %s on line %d +512M +Warning: Failed to set memory_limit to 1073741824 bytes. Setting to max_memory_limit instead (currently: 536870912 bytes) in %s on line %d +512M +Warning: Failed to set memory_limit to 1073741824 bytes. Setting to max_memory_limit instead (currently: 536870912 bytes) in %s on line %d +512M diff --git a/tests/output/gh20352.phpt b/tests/output/gh20352.phpt new file mode 100644 index 0000000000000..16be0b920e80f --- /dev/null +++ b/tests/output/gh20352.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-20352 (UAF in php_output_handler_free via re-entrant ob_start() during error deactivation) +--FILE-- + +--EXPECTF-- +Fatal error: ob_start(): Cannot use output buffering in output buffering display handlers in %s on line %d diff --git a/tests/output/ob_start_basic_002.phpt b/tests/output/ob_start_basic_002.phpt index e9af2b5e1904c..700dab5d3c381 100644 --- a/tests/output/ob_start_basic_002.phpt +++ b/tests/output/ob_start_basic_002.phpt @@ -35,24 +35,19 @@ foreach ($callbacks as $callback) { } ?> ---EXPECTF-- +--EXPECT-- --> Use callback 'return_empty_string': --> Use callback 'return_false': - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d My output. --> Use callback 'return_null': -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d - --> Use callback 'return_string': I stole your output. --> Use callback 'return_zero': - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s on line %d 0 + diff --git a/tests/output/ob_start_callback_bad_return/exception_handler.phpt b/tests/output/ob_start_callback_bad_return/exception_handler.phpt deleted file mode 100644 index eef3fccc77ec0..0000000000000 --- a/tests/output/ob_start_callback_bad_return/exception_handler.phpt +++ /dev/null @@ -1,147 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation converted to exception [bad return] ---FILE-- -val; - } -} - -$log = []; - -set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) { - throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); - -function return_null($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return null; -} - -function return_false($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return false; -} - -function return_true($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return true; -} - -function return_zero($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return 0; -} - -function return_non_stringable($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return new NotStringable($string); -} - -function return_stringable($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return new IsStringable($string); -} - -$cases = [ - 'return_null', - 'return_false', - 'return_true', - 'return_zero', - 'return_non_stringable', - 'return_stringable', -]; -foreach ($cases as $case) { - $log = []; - echo "\n\nTesting: $case\n"; - ob_start($case); - echo "Inside of $case\n"; - try { - ob_end_flush(); - } catch (\ErrorException $e) { - echo $e . "\n"; - } - echo "\nEnd of $case, log was:\n"; - echo implode("\n", $log); -} - -?> ---EXPECTF-- -Testing: return_null -ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_null, log was: -return_null: <<>> - -Testing: return_false -Inside of return_false -ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_false, log was: -return_false: <<>> - -Testing: return_true -ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_true, log was: -return_true: <<>> - -Testing: return_zero -0ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_zero, log was: -return_zero: <<>> - -Testing: return_non_stringable -ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_non_stringable is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, 69) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_non_stringable, log was: -return_non_stringable: <<>> - -Testing: return_stringable -ErrorException: ob_end_flush(): Returning a non-string result from user output handler return_stringable is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, 69) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_stringable, log was: -return_stringable: <<>> diff --git a/tests/output/ob_start_callback_bad_return/exception_handler_nested.phpt b/tests/output/ob_start_callback_bad_return/exception_handler_nested.phpt deleted file mode 100644 index 64d7f805687b2..0000000000000 --- a/tests/output/ob_start_callback_bad_return/exception_handler_nested.phpt +++ /dev/null @@ -1,143 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with nested deprecation converted to exception [bad return] ---FILE-- -val; - } -} - -$log = []; - -set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) { - throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); - -function return_null($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return null; -} - -function return_false($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return false; -} - -function return_true($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return true; -} - -function return_zero($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return 0; -} - -function return_non_stringable($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return new NotStringable($string); -} - -function return_stringable($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return new IsStringable($string); -} - -ob_start('return_null'); -ob_start('return_false'); -ob_start('return_true'); -ob_start('return_zero'); -ob_start('return_non_stringable'); -ob_start('return_stringable'); - -echo "In all of them\n\n"; -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_stringable handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_non_stringable handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_zero handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_true handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_false handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_null handler\n\n"; - -echo "All handlers are over\n\n"; -echo implode("\n", $log); - -?> ---EXPECT-- -ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated -Ended return_null handler - -All handlers are over - -return_stringable: <<>> -return_non_stringable: <<>> -return_zero: <<>> -return_true: <<<0ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated -Ended return_zero handler - ->>> -return_false: <<>> -return_null: <<>> diff --git a/tests/output/ob_start_callback_bad_return/handler_false_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_false_removed.phpt deleted file mode 100644 index 32702a58fcc14..0000000000000 --- a/tests/output/ob_start_callback_bad_return/handler_false_removed.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns false) ---INI-- -memory_limit=2M ---FILE-- - ---EXPECTF-- -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_bad_return/handler_is_stringable_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_is_stringable_removed.phpt deleted file mode 100644 index 0d87358da1b9d..0000000000000 --- a/tests/output/ob_start_callback_bad_return/handler_is_stringable_removed.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns stringable object) ---INI-- -memory_limit=2M ---FILE-- -val; - } -} - -ob_start(function() { - // We are out of memory, now trigger a deprecation - return new IsStringable(""); -}); - -$a = []; -// trigger OOM in a resize operation -while (1) { - $a[] = 1; -} - -?> ---EXPECTF-- -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_bad_return/handler_non_stringable_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_non_stringable_removed.phpt deleted file mode 100644 index 65d8ccfbcba61..0000000000000 --- a/tests/output/ob_start_callback_bad_return/handler_non_stringable_removed.phpt +++ /dev/null @@ -1,32 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns non-stringable object) ---INI-- -memory_limit=2M ---FILE-- - ---EXPECTF-- -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d - -Fatal error: Uncaught Error: Object of class NotStringable could not be converted to string in %s:%d -Stack trace: -#0 {main} - thrown in %s on line %d diff --git a/tests/output/ob_start_callback_bad_return/handler_true_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_true_removed.phpt deleted file mode 100644 index 5ad19826c4ac7..0000000000000 --- a/tests/output/ob_start_callback_bad_return/handler_true_removed.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns true) ---INI-- -memory_limit=2M ---FILE-- - ---EXPECTF-- -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_bad_return/handler_zero_removed.phpt b/tests/output/ob_start_callback_bad_return/handler_zero_removed.phpt deleted file mode 100644 index 1bc7279c71d35..0000000000000 --- a/tests/output/ob_start_callback_bad_return/handler_zero_removed.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns zero) ---INI-- -memory_limit=2M ---FILE-- - ---EXPECTF-- -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt b/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt deleted file mode 100644 index 100abe7d79d18..0000000000000 --- a/tests/output/ob_start_callback_bad_return/multiple_handlers.phpt +++ /dev/null @@ -1,106 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with multiple nested handlers with bad return values ---FILE-- ->>"; - return $string; -} - -function return_empty_string($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return ""; -} - -function return_false($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return false; -} - -function return_true($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return true; -} - -function return_null($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return null; -} - -function return_string($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return "I stole your output."; -} - -function return_zero($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - return 0; -} - -ob_start('return_given_string'); -ob_start('return_empty_string'); -ob_start('return_false'); -ob_start('return_true'); -ob_start('return_null'); -ob_start('return_string'); -ob_start('return_zero'); - -echo "Testing..."; - -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); - -echo "\n\nLog:\n"; -echo implode("\n", $log); -?> ---EXPECTF-- -Deprecated: ob_end_flush(): Producing output from user output handler return_given_string is deprecated in %s on line %d3 - -Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d2 - - -Log: -return_zero: <<>> -return_string: <<< -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s on line %d -0>>> -return_null: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_string is deprecated in %s on line %d -I stole your output.>>> -return_true: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_null is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d ->>> -return_false: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d ->>> -return_empty_string: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_false is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d ->>> -return_given_string: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d2 ->>> diff --git a/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt b/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt deleted file mode 100644 index 2b018c792a52c..0000000000000 --- a/tests/output/ob_start_callback_output_and_bad_return/exception_handler.phpt +++ /dev/null @@ -1,153 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation converted to exception [bad return + produce output] ---FILE-- -val; - } -} - -$log = []; - -set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) { - throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); - -function return_null($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return null; -} - -function return_false($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return false; -} - -function return_true($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return true; -} - -function return_zero($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return 0; -} - -function return_non_stringable($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return new NotStringable($string); -} - -function return_stringable($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return new IsStringable($string); -} - -$cases = [ - 'return_null', - 'return_false', - 'return_true', - 'return_zero', - 'return_non_stringable', - 'return_stringable', -]; -foreach ($cases as $case) { - $log = []; - echo "\n\nTesting: $case\n"; - ob_start($case); - echo "Inside of $case\n"; - try { - ob_end_flush(); - } catch (\ErrorException $e) { - echo $e . "\n"; - } - echo "\nEnd of $case, log was:\n"; - echo implode("\n", $log); -} - -?> ---EXPECTF-- -Testing: return_null -ErrorException: ob_end_flush(): Producing output from user output handler return_null is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_null, log was: -return_null: <<>> - -Testing: return_false -Inside of return_false -return_falseErrorException: ob_end_flush(): Producing output from user output handler return_false is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_false, log was: -return_false: <<>> - -Testing: return_true -ErrorException: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_true, log was: -return_true: <<>> - -Testing: return_zero -0ErrorException: ob_end_flush(): Producing output from user output handler return_zero is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_zero, log was: -return_zero: <<>> - -Testing: return_non_stringable -ErrorException: ob_end_flush(): Producing output from user output handler return_non_stringable is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_non_stringable, log was: -return_non_stringable: <<>> - -Testing: return_stringable -ErrorException: ob_end_flush(): Producing output from user output handler return_stringable is deprecated in %s:%d -Stack trace: -#0 [internal function]: {closure:%s:%d}(8192, 'ob_end_flush():...', %s, %d) -#1 %s(%d): ob_end_flush() -#2 {main} - -End of return_stringable, log was: -return_stringable: <<>> diff --git a/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt b/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt deleted file mode 100644 index 7eb060acc2133..0000000000000 --- a/tests/output/ob_start_callback_output_and_bad_return/exception_handler_nested.phpt +++ /dev/null @@ -1,149 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with nested deprecation converted to exception [bad return + produce output] ---FILE-- -val; - } -} - -$log = []; - -set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) { - throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); - -function return_null($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return null; -} - -function return_false($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return false; -} - -function return_true($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return true; -} - -function return_zero($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return 0; -} - -function return_non_stringable($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return new NotStringable($string); -} - -function return_stringable($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return new IsStringable($string); -} - -ob_start('return_null'); -ob_start('return_false'); -ob_start('return_true'); -ob_start('return_zero'); -ob_start('return_non_stringable'); -ob_start('return_stringable'); - -echo "In all of them\n\n"; -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_stringable handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_non_stringable handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_zero handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_true handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_false handler\n\n"; - -try { - ob_end_flush(); -} catch (\ErrorException $e) { - echo $e->getMessage() . "\n"; -} -echo "Ended return_null handler\n\n"; - -echo "All handlers are over\n\n"; -echo implode("\n", $log); - -?> ---EXPECT-- -ob_end_flush(): Producing output from user output handler return_null is deprecated -Ended return_null handler - -All handlers are over - -return_stringable: <<>> -return_non_stringable: <<>> -return_zero: <<>> -return_true: <<<0ob_end_flush(): Producing output from user output handler return_zero is deprecated -Ended return_zero handler - ->>> -return_false: <<>> -return_null: <<>> diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt deleted file mode 100644 index 78c736b80cd14..0000000000000 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_false_removed.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns false + produces output) ---INI-- -memory_limit=2M ---FILE-- - ---EXPECTF-- -Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt deleted file mode 100644 index 9da82bc147e19..0000000000000 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_is_stringable_removed.phpt +++ /dev/null @@ -1,33 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns stringable object + produces output) ---INI-- -memory_limit=2M ---FILE-- -val; - } -} - -ob_start(function() { - // We are out of memory, now trigger a deprecation - echo "IN HANDLER\n"; - return new IsStringable(""); -}); - -$a = []; -// trigger OOM in a resize operation -while (1) { - $a[] = 1; -} - -?> ---EXPECTF-- -Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt deleted file mode 100644 index 476acaee9c3a3..0000000000000 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_non_stringable_removed.phpt +++ /dev/null @@ -1,35 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns non-stringable object + produces output) ---INI-- -memory_limit=2M ---FILE-- - ---EXPECTF-- -Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d - -Fatal error: Uncaught Error: Object of class NotStringable could not be converted to string in %s:%d -Stack trace: -#0 {main} - thrown in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt deleted file mode 100644 index 2b0218341c9b8..0000000000000 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_true_removed.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns true + produces output) ---INI-- -memory_limit=2M ---FILE-- - ---EXPECTF-- -Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt b/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt deleted file mode 100644 index 8681a846a3648..0000000000000 --- a/tests/output/ob_start_callback_output_and_bad_return/handler_zero_removed.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with deprecation when OOM triggers handler removal (handler returns zero + produces output) ---INI-- -memory_limit=2M ---FILE-- - ---EXPECTF-- -Deprecated: main(): Producing output from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Deprecated: main(): Returning a non-string result from user output handler {closure:%s:%d} is deprecated in %s on line %d - -Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt b/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt deleted file mode 100644 index 94d5d34c03830..0000000000000 --- a/tests/output/ob_start_callback_output_and_bad_return/multiple_handlers.phpt +++ /dev/null @@ -1,115 +0,0 @@ ---TEST-- -ob_start(): Check behaviour with multiple nested handlers with bad return values and output ---FILE-- ->>"; - echo __FUNCTION__; - return $string; -} - -function return_empty_string($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return ""; -} - -function return_false($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return false; -} - -function return_true($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return true; -} - -function return_null($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return null; -} - -function return_string($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return "I stole your output."; -} - -function return_zero($string) { - global $log; - $log[] = __FUNCTION__ . ": <<<" . $string . ">>>"; - echo __FUNCTION__; - return 0; -} - -ob_start('return_given_string'); -ob_start('return_empty_string'); -ob_start('return_false'); -ob_start('return_true'); -ob_start('return_null'); -ob_start('return_string'); -ob_start('return_zero'); - -echo "Testing..."; - -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); -ob_end_flush(); - -echo "\n\nLog:\n"; -echo implode("\n", $log); -?> ---EXPECTF-- -Deprecated: ob_end_flush(): Producing output from user output handler return_given_string is deprecated in %s on line %d0 - -Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d9 - - -Log: -return_zero: <<>> -return_string: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_zero is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_zero is deprecated in %s on line %d -0>>> -return_null: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_string is deprecated in %s on line %d5 -I stole your output.>>> -return_true: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_null is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_null is deprecated in %s on line %d ->>> -return_false: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d ->>> -return_empty_string: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_false is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_false is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Producing output from user output handler return_true is deprecated in %s on line %d - -Deprecated: ob_end_flush(): Returning a non-string result from user output handler return_true is deprecated in %s on line %d -return_false>>> -return_given_string: <<< -Deprecated: ob_end_flush(): Producing output from user output handler return_empty_string is deprecated in %s on line %d9 ->>> diff --git a/win32/sendmail.c b/win32/sendmail.c index 80dff3f390772..394676f30316d 100644 --- a/win32/sendmail.c +++ b/win32/sendmail.c @@ -32,6 +32,7 @@ #include "php_win32_globals.h" +#include "Zend/zend_smart_str.h" #include "ext/pcre/php_pcre.h" #include "ext/standard/php_string.h" #include "ext/date/php_date.h" @@ -63,7 +64,7 @@ char seps[] = " ,\t\n"; char *php_mailer = "PHP 7 WIN32"; /* Error messages */ -static char *ErrorMessages[] = +static const char *ErrorMessages[] = { "Success", /* 0 */ "Bad arguments from form", /* 1 */ @@ -111,11 +112,11 @@ static char *ErrorMessages[] = #define PHP_WIN32_MAIL_DOT_PATTERN "\n." #define PHP_WIN32_MAIL_DOT_REPLACE "\n.." -static int SendText(char *RPath, const char *Subject, const char *mailTo, char *mailCc, char *mailBcc, const char *data, - const char *headers, char *headers_lc, char **error_message); +static int SendText(char *RPath, const char *Subject, const char *mailTo, const char *data, + zend_string *headers, zend_string *headers_lc, char **error_message); static int MailConnect(); -static int PostHeader(char *RPath, const char *Subject, const char *mailTo, char *xheaders); -static int Post(LPCSTR msg); +static bool PostHeader(char *RPath, const char *Subject, const char *mailTo, zend_string *xheaders); +static bool Post(LPCSTR msg); static int Ack(char **server_response); static unsigned long GetAddr(LPSTR szHost); static int FormatEmailAddress(char* Buf, char* EmailAddress, char* FormatString); @@ -140,8 +141,8 @@ static zend_string *php_win32_mail_trim_header(const char *header) return NULL; } - replace = zend_string_init(PHP_WIN32_MAIL_UNIFY_REPLACE, strlen(PHP_WIN32_MAIL_UNIFY_REPLACE), 0); - regex = zend_string_init(PHP_WIN32_MAIL_UNIFY_PATTERN, sizeof(PHP_WIN32_MAIL_UNIFY_PATTERN)-1, 0); + replace = ZSTR_INIT_LITERAL(PHP_WIN32_MAIL_UNIFY_REPLACE, false); + regex = ZSTR_INIT_LITERAL(PHP_WIN32_MAIL_UNIFY_PATTERN, false); result = php_pcre_replace(regex, NULL, header, strlen(header), @@ -149,24 +150,24 @@ static zend_string *php_win32_mail_trim_header(const char *header) -1, NULL); - zend_string_release_ex(replace, 0); - zend_string_release_ex(regex, 0); + zend_string_release_ex(replace, false); + zend_string_release_ex(regex, false); if (NULL == result) { return NULL; } - replace = zend_string_init(PHP_WIN32_MAIL_RMVDBL_PATTERN, strlen(PHP_WIN32_MAIL_RMVDBL_PATTERN), 0); - regex = zend_string_init(PHP_WIN32_MAIL_RMVDBL_PATTERN, sizeof(PHP_WIN32_MAIL_RMVDBL_PATTERN)-1, 0); + replace = ZSTR_INIT_LITERAL(PHP_WIN32_MAIL_RMVDBL_PATTERN, false); + regex = ZSTR_INIT_LITERAL(PHP_WIN32_MAIL_RMVDBL_PATTERN, false); result2 = php_pcre_replace(regex, result, ZSTR_VAL(result), ZSTR_LEN(result), replace, -1, NULL); - zend_string_release_ex(replace, 0); - zend_string_release_ex(regex, 0); - zend_string_release_ex(result, 0); + zend_string_release_ex(replace, false); + zend_string_release_ex(regex, false); + zend_string_release_ex(result, false); return result2; } @@ -185,8 +186,7 @@ static zend_string *php_win32_mail_trim_header(const char *header) // See SendText() for additional args! //********************************************************************* PHPAPI int TSendMail(const char *host, int *error, char **error_message, - const char *headers, const char *Subject, const char *mailTo, const char *data, - char *mailCc, char *mailBcc, char *mailRPath) + const char *headers, const char *Subject, const char *mailTo, const char *data) { int ret; char *RPath = NULL; @@ -216,9 +216,7 @@ PHPAPI int TSendMail(const char *host, int *error, char **error_message, } /* Fall back to sendmail_from php.ini setting */ - if (mailRPath && *mailRPath) { - RPath = estrdup(mailRPath); - } else if (INI_STR("sendmail_from")) { + if (INI_STR("sendmail_from")) { RPath = estrdup(INI_STR("sendmail_from")); } else if (headers_lc) { int found = 0; @@ -281,7 +279,7 @@ PHPAPI int TSendMail(const char *host, int *error, char **error_message, PW32G(mail_host), !INI_INT("smtp_port") ? 25 : INI_INT("smtp_port")); return FAILURE; } else { - ret = SendText(RPath, Subject, mailTo, mailCc, mailBcc, data, headers ? ZSTR_VAL(headers_trim) : NULL, headers ? ZSTR_VAL(headers_lc) : NULL, error_message); + ret = SendText(RPath, Subject, mailTo, data, headers_trim, headers_lc, error_message); TSMClose(); if (RPath) { efree(RPath); @@ -328,7 +326,7 @@ PHPAPI void TSMClose(void) // Author/Date: jcar 20/9/96 // History: //********************************************************************* -PHPAPI char *GetSMErrorText(int index) +PHPAPI const char *GetSMErrorText(int index) { if (MIN_ERROR_INDEX <= index && index < MAX_ERROR_INDEX) { return (ErrorMessages[index]); @@ -389,15 +387,15 @@ static char *find_address(char *list, char **state) // Author/Date: jcar 20/9/96 // History: //********************************************************************* -static int SendText(char *RPath, const char *Subject, const char *mailTo, char *mailCc, char *mailBcc, const char *data, - const char *headers, char *headers_lc, char **error_message) +static int SendText(char *RPath, const char *Subject, const char *mailTo, const char *data, + zend_string *headers, zend_string *headers_lc, char **error_message) { int res; char *p; char *tempMailTo, *token, *token_state; const char *pos1, *pos2; char *server_response = NULL; - char *stripped_header = NULL; + zend_string *stripped_header = NULL; zend_string *data_cln; /* check for NULL parameters */ @@ -421,14 +419,14 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * /* in the beginning of the dialog */ /* attempt reconnect if the first Post fail */ - if ((res = Post(PW32G(mail_buffer))) != SUCCESS) { + if (!Post(PW32G(mail_buffer))) { int err = MailConnect(); if (0 != err) { return (FAILED_TO_SEND); } - if ((res = Post(PW32G(mail_buffer))) != SUCCESS) { - return (res); + if (!Post(PW32G(mail_buffer))) { + return (FAILED_TO_SEND); } } if ((res = Ack(&server_response)) != SUCCESS) { @@ -438,8 +436,8 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * SMTP_SKIP_SPACE(RPath); FormatEmailAddress(PW32G(mail_buffer), RPath, "MAIL FROM:<%s>\r\n"); - if ((res = Post(PW32G(mail_buffer))) != SUCCESS) { - return (res); + if (!Post(PW32G(mail_buffer))) { + return (FAILED_TO_SEND); } if ((res = Ack(&server_response)) != SUCCESS) { SMTP_ERROR_RESPONSE(server_response); @@ -453,9 +451,9 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * { SMTP_SKIP_SPACE(token); FormatEmailAddress(PW32G(mail_buffer), token, "RCPT TO:<%s>\r\n"); - if ((res = Post(PW32G(mail_buffer))) != SUCCESS) { + if (!Post(PW32G(mail_buffer))) { efree(tempMailTo); - return (res); + return (FAILED_TO_SEND); } if ((res = Ack(&server_response)) != SUCCESS) { SMTP_ERROR_RESPONSE(server_response); @@ -466,33 +464,12 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * } efree(tempMailTo); - if (mailCc && *mailCc) { - tempMailTo = estrdup(mailCc); - /* Send mail to all rcpt's */ - token = find_address(tempMailTo, &token_state); - while (token != NULL) - { - SMTP_SKIP_SPACE(token); - FormatEmailAddress(PW32G(mail_buffer), token, "RCPT TO:<%s>\r\n"); - if ((res = Post(PW32G(mail_buffer))) != SUCCESS) { - efree(tempMailTo); - return (res); - } - if ((res = Ack(&server_response)) != SUCCESS) { - SMTP_ERROR_RESPONSE(server_response); - efree(tempMailTo); - return (res); - } - token = find_address(NULL, &token_state); - } - efree(tempMailTo); - } /* Send mail to all Cc rcpt's */ - else if (headers && (pos1 = strstr(headers_lc, "cc:")) && ((pos1 == headers_lc) || (*(pos1-1) == '\n'))) { + if (headers && (pos1 = strstr(ZSTR_VAL(headers_lc), "cc:")) && ((pos1 == ZSTR_VAL(headers_lc)) || (*(pos1-1) == '\n'))) { /* Real offset is memaddress from the original headers + difference of * string found in the lowercase headers + 3 characters to jump over * the cc: */ - pos1 = headers + (pos1 - headers_lc) + 3; + pos1 = ZSTR_VAL(headers) + (pos1 - ZSTR_VAL(headers_lc)) + 3; if (NULL == (pos2 = strstr(pos1, "\r\n"))) { tempMailTo = estrndup(pos1, strlen(pos1)); } else { @@ -514,9 +491,9 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * { SMTP_SKIP_SPACE(token); FormatEmailAddress(PW32G(mail_buffer), token, "RCPT TO:<%s>\r\n"); - if ((res = Post(PW32G(mail_buffer))) != SUCCESS) { + if (!Post(PW32G(mail_buffer))) { efree(tempMailTo); - return (res); + return (FAILED_TO_SEND); } if ((res = Ack(&server_response)) != SUCCESS) { SMTP_ERROR_RESPONSE(server_response); @@ -528,36 +505,23 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * efree(tempMailTo); } + if (!Post("DATA\r\n")) { + return (FAILED_TO_SEND); + } + if ((res = Ack(&server_response)) != SUCCESS) { + SMTP_ERROR_RESPONSE(server_response); + return (res); + } + /* Send mail to all Bcc rcpt's This is basically a rip of the Cc code above. Just don't forget to remove the Bcc: from the header afterwards. */ - if (mailBcc && *mailBcc) { - tempMailTo = estrdup(mailBcc); - /* Send mail to all rcpt's */ - token = find_address(tempMailTo, &token_state); - while (token != NULL) - { - SMTP_SKIP_SPACE(token); - FormatEmailAddress(PW32G(mail_buffer), token, "RCPT TO:<%s>\r\n"); - if ((res = Post(PW32G(mail_buffer))) != SUCCESS) { - efree(tempMailTo); - return (res); - } - if ((res = Ack(&server_response)) != SUCCESS) { - SMTP_ERROR_RESPONSE(server_response); - efree(tempMailTo); - return (res); - } - token = find_address(NULL, &token_state); - } - efree(tempMailTo); - } - else if (headers) { - if ((pos1 = strstr(headers_lc, "bcc:")) && (pos1 == headers_lc || *(pos1-1) == '\n')) { + if (headers) { + if ((pos1 = strstr(ZSTR_VAL(headers_lc), "bcc:")) && (pos1 == ZSTR_VAL(headers_lc) || *(pos1-1) == '\n')) { /* Real offset is memaddress from the original headers + difference of * string found in the lowercase headers + 4 characters to jump over * the bcc: */ - pos1 = headers + (pos1 - headers_lc) + 4; + pos1 = ZSTR_VAL(headers) + (pos1 - ZSTR_VAL(headers_lc)) + 4; if (NULL == (pos2 = strstr(pos1, "\r\n"))) { tempMailTo = estrndup(pos1, strlen(pos1)); /* Later, when we remove the Bcc: out of the @@ -587,9 +551,9 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * { SMTP_SKIP_SPACE(token); FormatEmailAddress(PW32G(mail_buffer), token, "RCPT TO:<%s>\r\n"); - if ((res = Post(PW32G(mail_buffer))) != SUCCESS) { + if (!Post(PW32G(mail_buffer))) { efree(tempMailTo); - return (res); + return (FAILED_TO_SEND); } if ((res = Ack(&server_response)) != SUCCESS) { SMTP_ERROR_RESPONSE(server_response); @@ -602,54 +566,41 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * /* Now that we've identified that we've a Bcc list, remove it from the current header. */ - stripped_header = ecalloc(1, strlen(headers)); /* headers = point to string start of header pos1 = pointer IN headers where the Bcc starts '4' = Length of the characters 'bcc:' Because we've added +4 above for parsing the Emails we've to subtract them here. */ - memcpy(stripped_header, headers, pos1 - headers - 4); + size_t header_length_prior_to_bcc = pos1 - ZSTR_VAL(headers) - 4; if (pos1 != pos2) { /* if pos1 != pos2 , pos2 points to the rest of the headers. Since pos1 != pos2 if "\r\n" was found, we know those characters are there and so we jump over them (else we would generate a new header which would look like "\r\n\r\n". */ - memcpy(stripped_header + (pos1 - headers - 4), pos2 + 2, strlen(pos2) - 2); + stripped_header = zend_string_concat2(ZSTR_VAL(headers), header_length_prior_to_bcc, pos2 + 2, strlen(pos2) - 2); + } else { + stripped_header = zend_string_truncate(headers, header_length_prior_to_bcc, false); + ZSTR_VAL(stripped_header)[ZSTR_LEN(stripped_header)] = '\0'; } + } else { + /* Simplify the code that we create a copy of stripped_header no matter if + we actually strip something or not. So we've a single zend_string_release() later. */ + stripped_header = zend_string_copy(headers); } } - /* Simplify the code that we create a copy of stripped_header no matter if - we actually strip something or not. So we've a single efree() later. */ - if (headers && !stripped_header) { - stripped_header = estrndup(headers, strlen(headers)); - } - - if ((res = Post("DATA\r\n")) != SUCCESS) { - if (stripped_header) { - efree(stripped_header); - } - return (res); - } - if ((res = Ack(&server_response)) != SUCCESS) { - SMTP_ERROR_RESPONSE(server_response); - if (stripped_header) { - efree(stripped_header); - } - return (res); - } - /* send message header */ + bool PostHeaderIsSuccessful = false; if (Subject == NULL) { - res = PostHeader(RPath, "No Subject", mailTo, stripped_header); + PostHeaderIsSuccessful = PostHeader(RPath, "No Subject", mailTo, stripped_header); } else { - res = PostHeader(RPath, Subject, mailTo, stripped_header); + PostHeaderIsSuccessful = PostHeader(RPath, Subject, mailTo, stripped_header); } if (stripped_header) { - efree(stripped_header); + zend_string_release_ex(stripped_header, false); } - if (res != SUCCESS) { - return (res); + if (!PostHeaderIsSuccessful) { + return FAILED_TO_SEND; } /* Escape \n. sequences @@ -670,24 +621,24 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * e2 = p + 1024; c = *e2; *e2 = '\0'; - if ((res = Post(p)) != SUCCESS) { + if (!Post(p)) { zend_string_free(data_cln); - return(res); + return(FAILED_TO_SEND); } *e2 = c; p = e2; } - if ((res = Post(p)) != SUCCESS) { + if (!Post(p)) { zend_string_free(data_cln); - return(res); + return(FAILED_TO_SEND); } } zend_string_free(data_cln); /*send termination dot */ - if ((res = Post("\r\n.\r\n")) != SUCCESS) - return (res); + if (!Post("\r\n.\r\n")) + return (FAILED_TO_SEND); if ((res = Ack(&server_response)) != SUCCESS) { SMTP_ERROR_RESPONSE(server_response); return (res); @@ -696,15 +647,6 @@ static int SendText(char *RPath, const char *Subject, const char *mailTo, char * return (SUCCESS); } -static int addToHeader(char **header_buffer, const char *specifier, const char *string) -{ - size_t header_buffer_size = strlen(*header_buffer); - size_t total_size = header_buffer_size + strlen(specifier) + strlen(string) + 1; - *header_buffer = erealloc(*header_buffer, total_size); - snprintf(*header_buffer + header_buffer_size, total_size - header_buffer_size, specifier, string); - return 1; -} - //********************************************************************* // Name: PostHeader // Input: 1) return path @@ -716,78 +658,58 @@ static int addToHeader(char **header_buffer, const char *specifier, const char * // Author/Date: jcar 20/9/96 // History: //********************************************************************* -static int PostHeader(char *RPath, const char *Subject, const char *mailTo, char *xheaders) +static bool PostHeader(char *RPath, const char *Subject, const char *mailTo, zend_string *xheaders) { /* Print message header according to RFC 822 */ /* Return-path, Received, Date, From, Subject, Sender, To, cc */ - int res; - char *header_buffer; - char *headers_lc = NULL; - size_t i; + zend_string *headers_lc = NULL; + smart_str combined_headers = {0}; if (xheaders) { - size_t headers_lc_len; - - headers_lc = estrdup(xheaders); - headers_lc_len = strlen(headers_lc); - - for (i = 0; i < headers_lc_len; i++) { - headers_lc[i] = tolower(headers_lc[i]); - } + headers_lc = zend_string_tolower(xheaders); } - header_buffer = ecalloc(1, MAIL_BUFFER_SIZE); - - if (!xheaders || !strstr(headers_lc, "date:")) { + if (!xheaders || !strstr(ZSTR_VAL(headers_lc), "date:")) { time_t tNow = time(NULL); zend_string *dt = php_format_date("r", 1, tNow, 1); - snprintf(header_buffer, MAIL_BUFFER_SIZE, "Date: %s\r\n", ZSTR_VAL(dt)); + smart_str_appends(&combined_headers, "Date: "); + smart_str_append(&combined_headers, dt); + smart_str_appends(&combined_headers, "\r\n"); zend_string_free(dt); } - if (!headers_lc || !strstr(headers_lc, "from:")) { - if (!addToHeader(&header_buffer, "From: %s\r\n", RPath)) { - goto PostHeader_outofmem; - } - } - if (!addToHeader(&header_buffer, "Subject: %s\r\n", Subject)) { - goto PostHeader_outofmem; + if (!headers_lc || !strstr(ZSTR_VAL(headers_lc), "from:")) { + smart_str_appends(&combined_headers, "From: "); + smart_str_appends(&combined_headers, RPath); + smart_str_appends(&combined_headers, "\r\n"); } + smart_str_appends(&combined_headers, "Subject: "); + smart_str_appends(&combined_headers, Subject); + smart_str_appends(&combined_headers, "\r\n"); /* Only add the To: field from the $to parameter if isn't in the custom headers */ - if ((headers_lc && (!strstr(headers_lc, "\r\nto:") && (strncmp(headers_lc, "to:", 3) != 0))) || !headers_lc) { - if (!addToHeader(&header_buffer, "To: %s\r\n", mailTo)) { - goto PostHeader_outofmem; - } + if (!headers_lc || (!strstr(ZSTR_VAL(headers_lc), "\r\nto:") && (strncmp(ZSTR_VAL(headers_lc), "to:", 3) != 0))) { + smart_str_appends(&combined_headers, "To: "); + smart_str_appends(&combined_headers, mailTo); + smart_str_appends(&combined_headers, "\r\n"); } if (xheaders) { - if (!addToHeader(&header_buffer, "%s\r\n", xheaders)) { - goto PostHeader_outofmem; - } + smart_str_append(&combined_headers, xheaders); + smart_str_appends(&combined_headers, "\r\n"); } + /* End of headers */ + smart_str_appends(&combined_headers, "\r\n"); + zend_string *combined_headers_str = smart_str_extract(&combined_headers); if (headers_lc) { - efree(headers_lc); - } - if ((res = Post(header_buffer)) != SUCCESS) { - efree(header_buffer); - return (res); + zend_string_release_ex(headers_lc, false); } - efree(header_buffer); - if ((res = Post("\r\n")) != SUCCESS) { - return (res); - } - - return (SUCCESS); - -PostHeader_outofmem: - if (headers_lc) { - efree(headers_lc); - } - return OUT_OF_MEMORY; + bool header_post_status = Post(ZSTR_VAL(combined_headers_str)); + zend_string_efree(combined_headers_str); + return header_post_status; } @@ -896,7 +818,7 @@ return 0; // Author/Date: jcar 20/9/96 // History: //********************************************************************* -static int Post(LPCSTR msg) +static bool Post(LPCSTR msg) { int len = (int)strlen(msg); int slen; @@ -905,16 +827,16 @@ static int Post(LPCSTR msg) #if SENDMAIL_DEBUG if (msg) printf("POST: '%s'\n", msg); - return (SUCCESS); + return true; #endif while (len > 0) { if ((slen = send(PW32G(mail_socket), msg + index, len, 0)) < 1) - return (FAILED_TO_SEND); + return false; len -= slen; index += slen; } - return (SUCCESS); + return true; } diff --git a/win32/sendmail.h b/win32/sendmail.h index e6096f789eb78..9999f9a6dfa58 100644 --- a/win32/sendmail.h +++ b/win32/sendmail.h @@ -33,8 +33,7 @@ PHPAPI int TSendMail(const char *host, int *error, char **error_message, - const char *headers, const char *Subject, const char *mailTo, const char *data, - char *mailCc, char *mailBcc, char *mailRPath); + const char *headers, const char *Subject, const char *mailTo, const char *data); PHPAPI void TSMClose(void); -PHPAPI char *GetSMErrorText(int index); +PHPAPI const char *GetSMErrorText(int index); #endif /* sendmail_h */