diff --git a/.circleci/config.yml b/.circleci/config.yml index f5dddad093158..8c8f08f17543a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,7 +4,7 @@ jobs: arm: resource_class: arm.medium docker: - - image: cimg/base:current-22.04 + - image: cimg/base:current-24.04 - image: mysql:8.3 environment: MYSQL_ALLOW_EMPTY_PASSWORD: true @@ -60,7 +60,7 @@ jobs: libreadline-dev \ libldap2-dev \ libsodium-dev \ - libargon2-0-dev \ + libargon2-dev \ libmm-dev \ libsnmp-dev \ snmpd \ @@ -78,7 +78,7 @@ jobs: libqdbm-dev \ libjpeg-dev \ libpng-dev \ - libfreetype6-dev + libfreetype-dev - run: name: ./configure command: | diff --git a/.github/actions/setup-mssql/action.yml b/.github/actions/setup-mssql/action.yml index dd372a5637aac..cbd220d0b29e6 100644 --- a/.github/actions/setup-mssql/action.yml +++ b/.github/actions/setup-mssql/action.yml @@ -11,4 +11,4 @@ runs: -p 1433:1433 \ --name sql1 \ -h sql1 \ - -d mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04 + -d mcr.microsoft.com/mssql/server:2025-latest 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/workflows/docs.yml b/.github/workflows/docs.yml index 3e59990742cbe..ffb45c9a20cd3 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -10,14 +10,14 @@ on: - docs/** jobs: pages: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest permissions: pages: write id-token: write 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 48628896f4982..8d267c615c12f 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -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,7 +360,7 @@ 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 @@ -429,10 +429,10 @@ jobs: FIREBIRD_DATABASE: test.fdb FIREBIRD_USER: test FIREBIRD_PASSWORD: test - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.branch }} - name: Create MSSQL container @@ -480,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 @@ -679,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 @@ -737,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 @@ -823,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 @@ -862,44 +862,44 @@ jobs: uses: ./.github/actions/verify-generated-files PECL: if: inputs.branch == 'master' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: CC: ccache gcc 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 @@ -909,6 +909,8 @@ jobs: sudo apt-get install -y --no-install-recommends \ ccache \ libmemcached-dev \ + imagemagick \ + libmagickwand-dev \ bison \ re2c - name: ccache @@ -1004,7 +1006,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 @@ -1025,7 +1027,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 414969378dc70..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,7 @@ 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 @@ -287,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 @@ -301,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 @@ -363,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 }} @@ -394,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 @@ -406,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..3bb0218faebd7 100644 --- a/.github/workflows/real-time-benchmark.yml +++ b/.github/workflows/real-time-benchmark.yml @@ -24,24 +24,6 @@ on: options: - "0" - "1" - opcache: - description: 'Whether opcache is enabled for the benchmarked commit' - required: true - default: "1" - type: choice - options: - - "0" - - "1" - - "2" - baseline_opcache: - description: 'Whether opcache is enabled for the baseline commit' - required: true - default: "1" - type: choice - options: - - "0" - - "1" - - "2" run_micro_bench: description: 'Whether to run the micro_bench.php test' required: true @@ -60,17 +42,15 @@ jobs: REAL_TIME_BENCHMARK: name: REAL_TIME_BENCHMARK if: github.repository == 'php/php-src' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: REPOSITORY: ${{ github.repository }} BRANCH: "master" COMMIT: ${{ github.sha }} BASELINE_COMMIT: "d5f6e56610c729710073350af318c4ea1b292cfe" ID: "master" - OPCACHE: "1" - BASELINE_OPCACHE: "2" JIT: "1" - INSTRUCTION_COUNT: "1" + INSTRUCTION_COUNT: "0" RUN_MICRO_BENCH: "0" YEAR: "" steps: @@ -82,7 +62,7 @@ jobs: echo "YEAR=$YEAR" >> $GITHUB_ENV if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - PR_INFO=$(gh pr view ${{ inputs.pull_request }} --json headRepositoryOwner,headRepository,headRefName,headRefOid,baseRefOid --repo ${{ github.repository }} | jq -r '.headRepositoryOwner.login, .headRepository.name, .headRefName, .headRefOid, .baseRefOid') + PR_INFO=$(gh pr view ${{ inputs.pull_request }} --json headRepositoryOwner,headRepository,headRefName,headRefOid,baseRefName --repo ${{ github.repository }} | jq -r '.headRepositoryOwner.login, .headRepository.name, .headRefName, .headRefOid, .baseRefName') REPOSITORY="$(echo "$PR_INFO" | sed -n '1p')/$(echo "$PR_INFO" | sed -n '2p')" echo "REPOSITORY=$REPOSITORY" >> $GITHUB_ENV @@ -93,13 +73,13 @@ jobs: COMMIT=$(echo "$PR_INFO" | sed -n '4p') echo "COMMIT=$COMMIT" >> $GITHUB_ENV - BASELINE_COMMIT=$(echo "$PR_INFO" | sed -n '5p') + BASELINE_BRANCH=$(echo "$PR_INFO" | sed -n '5p') + + BASELINE_COMMIT=$(gh api /repos/${{ github.repository }}/compare/$BASELINE_BRANCH...$COMMIT --jq '.merge_base_commit.sha') echo "BASELINE_COMMIT=$BASELINE_COMMIT" >> $GITHUB_ENV echo "ID=benchmarked" >> $GITHUB_ENV - echo "OPCACHE=${{ inputs.opcache }}" >> $GITHUB_ENV - echo "BASELINE_OPCACHE=${{ inputs.baseline_opcache }}" >> $GITHUB_ENV echo "JIT=${{ inputs.jit }}" >> $GITHUB_ENV echo "INSTRUCTION_COUNT=${{ inputs.instruction_count }}" >> $GITHUB_ENV echo "RUN_MICRO_BENCH=${{ inputs.run_micro_bench }}" >> $GITHUB_ENV @@ -118,21 +98,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,23 +126,11 @@ 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 }} path: 'php-version-benchmarks/docs/results' - - name: Setup infra config - run: | - set -e - - cp ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini.dist ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini - ESCAPED_DOCKER_REGISTRY=$(printf '%s\n' "${{ secrets.PHP_VERSION_BENCHMARK_DOCKER_REGISTRY }}" | sed -e 's/[\/&]/\\&/g') - sed -i "s/INFRA_DOCKER_REGISTRY=public.ecr.aws\/abcdefgh/INFRA_DOCKER_REGISTRY=$ESCAPED_DOCKER_REGISTRY/g" ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini - sed -i "s/INFRA_MEASURE_INSTRUCTION_COUNT=0/INFRA_MEASURE_INSTRUCTION_COUNT=${{ env.INSTRUCTION_COUNT }}/g" ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini - cp ./php-version-benchmarks/build/infrastructure/config/aws.tfvars.dist ./php-version-benchmarks/build/infrastructure/config/aws.tfvars - sed -i 's/access_key = ""/access_key = "${{ secrets.PHP_VERSION_BENCHMARK_AWS_ACCESS_KEY }}"/g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars - sed -i 's/secret_key = ""/secret_key = "${{ secrets.PHP_VERSION_BENCHMARK_AWS_SECRET_KEY }}"/g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars - sed -i 's/github_token = ""/github_token = "${{ secrets.GITHUB_TOKEN }}"/g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars - name: Setup PHP config - baseline PHP version run: | set -e @@ -173,11 +141,10 @@ jobs: PHP_NAME="PHP - baseline@$BASELINE_SHORT_SHA" PHP_ID=php_baseline - PHP_REPO=https://github.com/${{ env.REPOSITORY }}.git + PHP_REPO=${{ github.server_url }}/${{ env.REPOSITORY }}.git PHP_BRANCH=${{ env.BRANCH }} PHP_COMMIT=${{ env.BASELINE_COMMIT }} - PHP_OPCACHE=${{ env.BASELINE_OPCACHE }} PHP_JIT=0 EOF - name: Setup PHP config - baseline PHP version with JIT @@ -191,11 +158,10 @@ jobs: PHP_NAME="PHP - baseline@$BASELINE_SHORT_SHA (JIT)" PHP_ID=php_baseline_jit - PHP_REPO=https://github.com/${{ env.REPOSITORY }}.git + PHP_REPO=${{ github.server_url }}/${{ env.REPOSITORY }}.git PHP_BRANCH=${{ env.BRANCH }} PHP_COMMIT=${{ env.BASELINE_COMMIT }} - PHP_OPCACHE=${{ env.BASELINE_OPCACHE }} PHP_JIT=${{ env.JIT }} EOF @@ -213,15 +179,16 @@ jobs: LAST_RESULT_SHA="$(cd ./php-version-benchmarks/tmp/php_${{ env.ID }}/ && git --no-pager log --until="$YESTERDAY" -n 1 --pretty='%H')" fi + echo "LAST_RESULT_SHA=$LAST_RESULT_SHA" >> $GITHUB_ENV + cat << EOF > ./php-version-benchmarks/config/php/previous.ini PHP_NAME="PHP - previous ${{ env.BRANCH }}" PHP_ID=php_previous - PHP_REPO=https://github.com/${{ env.REPOSITORY }}.git + PHP_REPO=${{ github.server_url }}/${{ env.REPOSITORY }}.git PHP_BRANCH=${{ env.BRANCH }} PHP_COMMIT=$LAST_RESULT_SHA - PHP_OPCACHE=1 PHP_JIT=0 EOF - name: Setup PHP config - benchmarked PHP version @@ -232,11 +199,10 @@ jobs: PHP_NAME="PHP - ${{ env.BRANCH }}" PHP_ID=php_${{ env.ID }} - PHP_REPO=https://github.com/${{ env.REPOSITORY }}.git + PHP_REPO=${{ github.server_url }}/${{ env.REPOSITORY }}.git PHP_BRANCH=${{ env.BRANCH }} PHP_COMMIT=${{ env.COMMIT }} - PHP_OPCACHE=${{ env.OPCACHE }} PHP_JIT=0 EOF - name: Setup PHP config - benchmarked PHP version with JIT @@ -248,11 +214,10 @@ jobs: PHP_NAME="PHP - ${{ env.BRANCH }} (JIT)" PHP_ID=php_${{ env.ID }}_jit - PHP_REPO=https://github.com/${{ env.REPOSITORY }}.git + PHP_REPO=${{ github.server_url }}/${{ env.REPOSITORY }}.git PHP_BRANCH=${{ env.BRANCH }} PHP_COMMIT=${{ env.COMMIT }} - PHP_OPCACHE=${{ env.OPCACHE }} PHP_JIT=${{ env.JIT }} EOF @@ -269,6 +234,37 @@ jobs: if [ "${{ env.RUN_MICRO_BENCH }}" -eq "1" ]; then cp ./php-version-benchmarks/config/test/6_micro_bench.php.ini.dist ./php-version-benchmarks/config/test/6_micro_bench.php.ini fi + - name: Setup infra config + run: | + set -e + + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + WORKSPACE="manual" + BASE_COMMIT="$(echo "${{ env.BASELINE_COMMIT }}" | cut -c 1-6)" + else + WORKSPACE="nightly" + BASE_COMMIT="$(echo "${{ env.LAST_RESULT_SHA }}" | cut -c 1-6)" + fi + COMPARE_COMMIT="$(echo "${{ env.COMMIT }}" | cut -c 1-6)" + + cp ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini.dist ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini + sed -i "s|INFRA_DOCKER_REGISTRY=public.ecr.aws/abcdefgh|INFRA_DOCKER_REGISTRY=${{ secrets.PHP_VERSION_BENCHMARK_DOCKER_REGISTRY }}|g" ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini + sed -i "s|INFRA_WORKSPACE=|INFRA_WORKSPACE=$WORKSPACE|g" ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini + sed -i "s/INFRA_MEASURE_INSTRUCTION_COUNT=0/INFRA_MEASURE_INSTRUCTION_COUNT=${{ env.INSTRUCTION_COUNT }}/g" ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini + + cp ./php-version-benchmarks/build/infrastructure/config/aws.tfvars.dist ./php-version-benchmarks/build/infrastructure/config/aws.tfvars + sed -i 's/access_key = ""/access_key = "${{ secrets.PHP_VERSION_BENCHMARK_AWS_ACCESS_KEY }}"/g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars + sed -i 's/secret_key = ""/secret_key = "${{ secrets.PHP_VERSION_BENCHMARK_AWS_SECRET_KEY }}"/g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars + sed -i 's/state_bucket = ""/state_bucket = "${{ secrets.PHP_VERSION_BENCHMARK_STATE_BUCKET }}"/g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars + sed -i 's/github_token = ""/github_token = "${{ secrets.GITHUB_TOKEN }}"/g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars + + WORKFLOW_RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + sed -i "s|log_url = \"\"|log_url = \"$WORKFLOW_RUN_URL\"|g" ./php-version-benchmarks/build/infrastructure/config/aws.tfvars + sed -i 's|artifact_url = ""|artifact_url = "#ARTIFACT_URL#"|g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars + + CHANGESET_URL="${{ github.server_url }}/${{ github.repository }}/compare/$BASE_COMMIT..$COMPARE_COMMIT" + sed -i 's|extra_title = ""|extra_title = "Changeset"|g' ./php-version-benchmarks/build/infrastructure/config/aws.tfvars + sed -i "s|extra_text = \"\"|extra_text = \"$CHANGESET_URL\"|g" ./php-version-benchmarks/build/infrastructure/config/aws.tfvars - name: Run benchmark run: ./php-version-benchmarks/benchmark.sh run aws - name: Store results @@ -288,12 +284,13 @@ jobs: fi git commit -m "Add result for ${{ github.repository }}@${{ github.sha }}" git push - - name: Upload artifact - if: github.event_name == 'workflow_dispatch' - uses: actions/upload-artifact@v4 + - name: Upload artifacts + id: upload + uses: actions/upload-artifact@v6 with: name: results - path: ./php-version-benchmarks/docs/results/${{ env.YEAR }} + path: | + ./php-version-benchmarks/tmp/results/${{ env.YEAR }}/**/* retention-days: 30 - name: Comment results if: github.event_name == 'workflow_dispatch' @@ -302,6 +299,7 @@ jobs: run: | cd ./php-version-benchmarks/tmp/php_${{ env.ID }} NEWEST_RESULT_DIRECTORY=$(ls -td ${{ github.workspace }}/php-version-benchmarks/docs/results/${{ env.YEAR }}/*/ | head -1) + sed -i "s|#ARTIFACT_URL#|${{ steps.upload.outputs.artifact-url }}|g" "${NEWEST_RESULT_DIRECTORY}result.md" gh pr comment ${{ inputs.pull_request }} --body-file "${NEWEST_RESULT_DIRECTORY}result.md" --repo ${{ github.repository }} - name: Cleanup if: always() diff --git a/.github/workflows/root.yml b/.github/workflows/root.yml index 778f722e4f2f1..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,9 +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 }} - symfony_version: ${{ (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9) && '8.1') - || ((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 2) && '7.4') - || '' }} + 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 index e15fcb36a0e7a..6cce1a14cf7f3 100644 --- a/.github/workflows/verify-bundled-files.yml +++ b/.github/workflows/verify-bundled-files.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: git checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Detect changed files uses: dorny/paths-filter@v3 diff --git a/NEWS b/NEWS index 9fa63137d8851..74816c94a2906 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,21 @@ PHP NEWS request. (ilutov) . It is now possible to use reference assign on WeakMap without the key needing to be present beforehand. (ndossche) + . Added `clamp()`. (kylekatarnls, thinkverse) + . Fix OSS-Fuzz #429429090 (Failed assertion on unset() with uninitialized + container). (ilutov) + . Fixed GH-20564 (Don't call autoloaders with pending exception). (ilutov) + +- Date: + . Update timelib to 2022.16. (Derick) + +- DOM: + . Removed LIBXML_XINCLUDE from valid options for XMLDocument, + as it was a no-op. (ndossche) + +- Fileinfo: + . Fixed bug GH-20679 (finfo_file() doesn't work on remote resources). + (ndossche) - Hash: . Upgrade xxHash to 0.8.2. (timwolla) @@ -18,25 +33,33 @@ PHP NEWS . 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) +- JSON: + . Enriched JSON last error / exception message with error location. + (Juan Morales) - Fibers: . Fixed bug GH-20483 (ASAN stack overflow with fiber.stack_size INI small value). (David Carlier) +- Mail: + . Fixed bug GH-20862 (null pointer dereference in + php_mail_detect_multiple_crlf via error_log (jordikroon) + - 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) + . Fixed bug GH-20836 (Stack overflow in mb_convert_variables with + recursive array references). (alexandre-daubois) - Opcache: . Fixed bug GH-20051 (apache2 shutdowns when restart is requested during preloading). (Arnaud, welcomycozyhom) +- OpenSSL: + . Implemented GH-20310 (No critical extension indication in + openssl_x509_parse() output). (StephenWall) + - PDO_PGSQL: . Clear session-local state disconnect-equivalent processing. (KentarouTakeda) @@ -47,6 +70,8 @@ PHP NEWS ignored. (ndossche) . Support overridden methods in SplFileInfo for getMTime() and getPathname() when building a phar. (ndossche) + . Mark Phar::buildFromIterator() base directory argument as a path. + (ndossche) - Reflection: . Fixed bug GH-20217 (ReflectionClass::isIterable() incorrectly returns true @@ -56,6 +81,12 @@ PHP NEWS . 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) + . Added AF_UNSPEC support for sock_addrinfo_lookup() as a sole umbrella for + AF_INET* family only. (David Carlier) + - SPL: . DirectoryIterator key can now work better with filesystem supporting larger directory indexing. (David Carlier) @@ -68,10 +99,13 @@ PHP NEWS while COW violation flag is still set). (alexandre-daubois) - Streams: + . Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream + socket context options. . 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) + . Allowed filtered streams to be casted as fd for select. (Jakub Zelenka) - Zip: . Fixed ZipArchive callback being called after executor has shut down. diff --git a/UPGRADING b/UPGRADING index 4e511d094797e..3d0a56756cdcc 100644 --- a/UPGRADING +++ b/UPGRADING @@ -31,12 +31,19 @@ PHP 8.6 UPGRADE NOTES . It is now possible to use reference assign on WeakMap without the key needing to be present beforehand. +- Fileinfo: + . finfo_file() now works with remote streams. + - Intl: . Added IntlNumberRangeFormatter class to format an interval of two numbers with a given skeleton, locale, IntlNumberRangeFormatter::COLLAPSE_AUTO, IntlNumberRangeFormatter::COLLAPSE_NONE, IntlNumberRangeFormatter::COLLAPSE_UNIT, IntlNumberRangeFormatter::COLLAPSE_ALL collapse and IntlNumberRangeFormatter::IDENTITY_FALLBACK_SINGLE_VALUE, IntlNumberRangeFormatter::IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE, IntlNumberRangeFormatter::IDENTITY_FALLBACK_APPROXIMATELY and IntlNumberRangeFormatter::IDENTITY_FALLBACK_RANGE identity fallbacks. It is supported from icu 63. +- JSON: + . Added extra info about error location to the JSON error messages returned + from json_last_error_msg() and JsonException message. + - Phar: . Overriding the getMTime() and getPathname() methods of SplFileInfo now influences the result of the phar buildFrom family of functions. @@ -46,6 +53,10 @@ PHP 8.6 UPGRADE NOTES . Added stream socket context option so_reuseaddr that allows disabling address reuse (SO_REUSEADDR) and explicitly uses SO_EXCLUSIVEADDRUSE on Windows. + . Added stream socket context options so_keepalive, tcp_keepidle, + tcp_keepintvl and tcp_keepcnt that allow setting socket keepalive + options. + . Allowed casting casting filtered streams as file descriptor for select. ======================================== 3. Changes in SAPI modules @@ -59,6 +70,10 @@ PHP 8.6 UPGRADE NOTES 5. Changed Functions ======================================== +- OpenSSL: + . Output of openssl_x509_parse() contains criticalExtensions listing all + critical certificate extensions. + - Phar: . Phar::mungServer() now supports reference values. @@ -71,6 +86,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 ======================================== @@ -90,6 +109,10 @@ PHP 8.6 UPGRADE NOTES 10. New Global Constants ======================================== +- Sockets: + . TCP_USER_TIMEOUT (Linux only). + . AF_UNSPEC. + ======================================== 11. Changes to INI File Handling ======================================== @@ -128,6 +151,11 @@ PHP 8.6 UPGRADE NOTES parsing the format string. . Arguments are now passed more efficiently to known constructors (e.g. when using new self()). + . array_map() using a first-class callable or partial function application + callback will be compiled into the equivalent foreach-loop, avoiding the + creation of intermediate Closures, the overhead of calling userland + callbacks from internal functions and providing for better insight for the + JIT. - DOM: . Made splitText() faster and consume less memory. diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 3ec54f49391b8..2132006540c40 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -52,6 +52,10 @@ PHP 8.6 INTERNALS UPGRADE NOTES . 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. + . Added zend_ast_call_get_args() to fetch the argument node from any call + node. + . The zend_exception_save() and zend_exception_restore() functions were + removed. ======================== 2. Build system changes @@ -70,6 +74,12 @@ PHP 8.6 INTERNALS UPGRADE NOTES - 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/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c index b1fd8e44222e5..79e95ed3fab43 100644 --- a/Zend/Optimizer/block_pass.c +++ b/Zend/Optimizer/block_pass.c @@ -1228,7 +1228,7 @@ static zend_always_inline zend_basic_block *get_next_block(const zend_cfg *cfg, } next_block++; } - while (next_block->len == 0 && !(next_block->flags & ZEND_BB_PROTECTED)) { + while (next_block->len == 0 && !(next_block->flags & (ZEND_BB_TARGET|ZEND_BB_PROTECTED))) { next_block = cfg->blocks + next_block->successors[0]; } return next_block; diff --git a/Zend/Optimizer/compact_literals.c b/Zend/Optimizer/compact_literals.c index 447a034530e1b..c534a5ecd8a45 100644 --- a/Zend/Optimizer/compact_literals.c +++ b/Zend/Optimizer/compact_literals.c @@ -735,6 +735,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx case ZEND_SEND_VAR_NO_REF_EX: case ZEND_SEND_REF: case ZEND_SEND_FUNC_ARG: + case ZEND_SEND_PLACEHOLDER: case ZEND_CHECK_FUNC_ARG: if (opline->op2_type == IS_CONST) { opline->result.num = cache_size; @@ -747,6 +748,10 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx cache_size += sizeof(void *); } break; + case ZEND_CALLABLE_CONVERT_PARTIAL: + opline->op1.num = cache_size; + cache_size += 2 * sizeof(void *); + break; } opline++; } diff --git a/Zend/Optimizer/optimize_func_calls.c b/Zend/Optimizer/optimize_func_calls.c index 62b50464e87ba..522a8927acc7f 100644 --- a/Zend/Optimizer/optimize_func_calls.c +++ b/Zend/Optimizer/optimize_func_calls.c @@ -193,6 +193,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: call--; if (call_stack[call].func && call_stack[call].opline) { zend_op *fcall = call_stack[call].opline; @@ -225,13 +226,14 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) * At this point we also know whether or not the result of * the DO opcode is used, allowing to optimize calls to * ZEND_ACC_NODISCARD functions. */ - if (opline->opcode != ZEND_CALLABLE_CONVERT) { + if (opline->opcode != ZEND_CALLABLE_CONVERT && opline->opcode != ZEND_CALLABLE_CONVERT_PARTIAL) { opline->opcode = zend_get_call_op(fcall, call_stack[call].func, !RESULT_UNUSED(opline)); } if ((ZEND_OPTIMIZER_PASS_16 & ctx->optimization_level) && call_stack[call].try_inline - && opline->opcode != ZEND_CALLABLE_CONVERT) { + && opline->opcode != ZEND_CALLABLE_CONVERT + && opline->opcode != ZEND_CALLABLE_CONVERT_PARTIAL) { zend_try_inline_call(op_array, fcall, opline, call_stack[call].func); } } diff --git a/Zend/Optimizer/zend_call_graph.c b/Zend/Optimizer/zend_call_graph.c index 645edd2f99914..845b3d5813ee0 100644 --- a/Zend/Optimizer/zend_call_graph.c +++ b/Zend/Optimizer/zend_call_graph.c @@ -128,6 +128,7 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32 case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: func_info->flags |= ZEND_FUNC_HAS_CALLS; if (call_info) { call_info->caller_call_opline = opline; @@ -144,6 +145,7 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32 case ZEND_SEND_VAR_NO_REF: case ZEND_SEND_VAR_NO_REF_EX: case ZEND_SEND_USER: + case ZEND_SEND_PLACEHOLDER: if (call_info) { if (opline->op2_type == IS_CONST) { call_info->named_args = true; diff --git a/Zend/Optimizer/zend_dump.c b/Zend/Optimizer/zend_dump.c index 9c51ad223e060..16cb751882427 100644 --- a/Zend/Optimizer/zend_dump.c +++ b/Zend/Optimizer/zend_dump.c @@ -136,6 +136,10 @@ static void zend_dump_unused_op(const zend_op *opline, znode_op op, uint32_t fla if (op.num != (uint32_t)-1) { fprintf(stderr, " try-catch(%u)", op.num); } + } else if (ZEND_VM_OP_LOOP_END == (flags & ZEND_VM_OP_MASK)) { + if (opline->extended_value & ZEND_FREE_ON_RETURN) { + fprintf(stderr, " loop-end(+%u)", op.num); + } } else if (ZEND_VM_OP_THIS == (flags & ZEND_VM_OP_MASK)) { fprintf(stderr, " THIS"); } else if (ZEND_VM_OP_NEXT == (flags & ZEND_VM_OP_MASK)) { diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 54670c804d006..c476961166c96 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -3840,7 +3840,7 @@ static zend_always_inline zend_result _zend_update_type_info( tmp &= ~MAY_BE_RC1; } if (opline->opcode == ZEND_FETCH_STATIC_PROP_IS) { - tmp |= MAY_BE_UNDEF; + tmp |= MAY_BE_NULL; } } UPDATE_SSA_TYPE(tmp, ssa_op->result_def); @@ -3906,6 +3906,7 @@ static zend_always_inline zend_result _zend_update_type_info( } break; case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: UPDATE_SSA_TYPE(MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN, ssa_op->result_def); UPDATE_SSA_OBJ_TYPE(zend_ce_closure, /* is_instanceof */ false, ssa_op->result_def); break; diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 33009e9909f5a..0e45bdb8af90f 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -487,7 +487,7 @@ uint64_t key = UINT64_C(0x9d7f71d2bd296364); uintptr_t _a = 0; uintptr_t _b = 0; -uintptr_t __attribute__((preserve_none)) fun(uintptr_t a, uintptr_t b) { +uintptr_t __attribute__((preserve_none,noinline,used)) fun(uintptr_t a, uintptr_t b) { _a = a; _b = b; return (uintptr_t)const3; diff --git a/Zend/tests/enum/comparison-internal.phpt b/Zend/tests/enum/comparison-internal.phpt new file mode 100644 index 0000000000000..b07c0e1dba8d9 --- /dev/null +++ b/Zend/tests/enum/comparison-internal.phpt @@ -0,0 +1,54 @@ +--TEST-- +Enum comparison (internal enum) +--EXTENSIONS-- +zend_test +--FILE-- + $foo); +var_dump($foo < $foo); +var_dump($foo >= $foo); +var_dump($foo <= $foo); + +var_dump($foo > $bar); +var_dump($foo < $bar); +var_dump($foo >= $bar); +var_dump($foo <= $bar); + +var_dump($foo > true); +var_dump($foo < true); +var_dump($foo >= true); +var_dump($foo <= true); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) diff --git a/Zend/tests/enum/implements-internal.phpt b/Zend/tests/enum/implements-internal.phpt new file mode 100644 index 0000000000000..518602af97e19 --- /dev/null +++ b/Zend/tests/enum/implements-internal.phpt @@ -0,0 +1,14 @@ +--TEST-- +Enum implements (internal enum) +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECT-- +bool(false) +bool(true) diff --git a/Zend/tests/enum/instanceof-backed-enum.phpt b/Zend/tests/enum/instanceof-backed-enum.phpt index 4716835d1169c..7087cfec74b40 100644 --- a/Zend/tests/enum/instanceof-backed-enum.phpt +++ b/Zend/tests/enum/instanceof-backed-enum.phpt @@ -1,5 +1,7 @@ --TEST-- Auto implement BackedEnum interface +--EXTENSIONS-- +zend_test --FILE-- --EXPECT-- bool(false) bool(true) +bool(false) +bool(true) diff --git a/Zend/tests/enum/instanceof-unitenum.phpt b/Zend/tests/enum/instanceof-unitenum.phpt index 5523796325398..89b04b5046624 100644 --- a/Zend/tests/enum/instanceof-unitenum.phpt +++ b/Zend/tests/enum/instanceof-unitenum.phpt @@ -1,5 +1,7 @@ --TEST-- Auto implement UnitEnum interface +--EXTENSIONS-- +zend_test --FILE-- --EXPECT-- bool(true) bool(false) +bool(true) diff --git a/Zend/tests/enum/no-clone-internal.phpt b/Zend/tests/enum/no-clone-internal.phpt new file mode 100644 index 0000000000000..84b7ee2634d26 --- /dev/null +++ b/Zend/tests/enum/no-clone-internal.phpt @@ -0,0 +1,16 @@ +--TEST-- +Enum disallows cloning (internal enum) +--EXTENSIONS-- +zend_test +--FILE-- +getMessage() . "\n"; +} + +?> +--EXPECT-- +Trying to clone an uncloneable object of class ZendTestIntEnum diff --git a/Zend/tests/enum/no-dynamic-properties-internal.phpt b/Zend/tests/enum/no-dynamic-properties-internal.phpt new file mode 100644 index 0000000000000..8d821a5f62925 --- /dev/null +++ b/Zend/tests/enum/no-dynamic-properties-internal.phpt @@ -0,0 +1,18 @@ +--TEST-- +Enum case disallows dynamic properties (internal enum) +--EXTENSIONS-- +zend_test +--FILE-- +baz = 'Baz'; +} catch (\Error $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Cannot create dynamic property ZendTestUnitEnum::$baz diff --git a/Zend/tests/fibers/oss-fuzz-471533782-001.phpt b/Zend/tests/fibers/oss-fuzz-471533782-001.phpt new file mode 100644 index 0000000000000..755f18449b007 --- /dev/null +++ b/Zend/tests/fibers/oss-fuzz-471533782-001.phpt @@ -0,0 +1,33 @@ +--TEST-- +OSS-Fuzz #471533782: Infinite loop in GC destructor fiber +--FILE-- +self = $this; + } + public function __destruct() { + try { + Fiber::suspend(); + } finally { + throw new Exception(); + } + } +} + +$f = new Fiber(function () { + new Cycle(); + gc_collect_cycles(); +}); +$f->start(); + +?> +--EXPECTF-- +Fatal error: Uncaught Exception in %s:%d +Stack trace: +#0 [internal function]: Cycle->__destruct() +#1 [internal function]: gc_destructor_fiber() +#2 {main} + thrown in %s on line %d diff --git a/Zend/tests/fibers/oss-fuzz-471533782-002.phpt b/Zend/tests/fibers/oss-fuzz-471533782-002.phpt new file mode 100644 index 0000000000000..3dbac0aac75fb --- /dev/null +++ b/Zend/tests/fibers/oss-fuzz-471533782-002.phpt @@ -0,0 +1,34 @@ +--TEST-- +OSS-Fuzz #471533782: Infinite loop in GC destructor fiber +--FILE-- +self = $this; + } + public function __destruct() { + try { + Fiber::suspend(); + } finally { + Fiber::suspend(); + } + } +} + +$f = new Fiber(function () { + new Cycle(); + gc_collect_cycles(); +}); +$f->start(); + +?> +--EXPECTF-- +Fatal error: Uncaught FiberError: Cannot suspend in a force-closed fiber in %s:%d +Stack trace: +#0 %s(%d): Fiber::suspend() +#1 [internal function]: Cycle->__destruct() +#2 [internal function]: gc_destructor_fiber() +#3 {main} + thrown in %s on line %d diff --git a/Zend/tests/functions/zend_call_function_deprecated_frame.phpt b/Zend/tests/functions/zend_call_function_deprecated_frame.phpt index ce2943a876e2b..83d05144c0bdf 100644 --- a/Zend/tests/functions/zend_call_function_deprecated_frame.phpt +++ b/Zend/tests/functions/zend_call_function_deprecated_frame.phpt @@ -19,7 +19,6 @@ var_dump($a); --EXPECTF-- Fatal error: Uncaught Exception: Function foo() is deprecated in %s:%d Stack trace: -#0 [internal function]: {closure:%s:%d}(16384, 'Function foo() ...', '%s', %d) -#1 %s(%d): array_map(Object(Closure), Array) -#2 {main} +#0 %s(%d): {closure:%s:%d}(16384, 'Function foo() ...', '%s', %d) +#1 {main} thrown in %s on line %d diff --git a/Zend/tests/gc/gc_050.phpt b/Zend/tests/gc/gc_050.phpt index 858be7cbebd5f..0bedc7220fd43 100644 --- a/Zend/tests/gc/gc_050.phpt +++ b/Zend/tests/gc/gc_050.phpt @@ -1,37 +1,40 @@ --TEST-- -GC 050: Destructor are never called twice +GC 050: Try/finally in foreach should create separate live ranges --FILE-- v = 1; + } + return new stdClass; } -class WithDestructor -{ - public function __destruct() - { - echo "d\n"; +for ($i = 0; $i < 100000; $i++) { + // Create cyclic garbage to trigger GC + $a = new stdClass; + $b = new stdClass; + $a->r = $b; + $b->r = $a; - G::$v = $this; - } + $r = f($i % 2 + 1); } - -$o = new WithDestructor(); -$weakO = \WeakReference::create($o); -echo "---\n"; -unset($o); -echo "---\n"; -var_dump($weakO->get() !== null); // verify if kept allocated -G::$v = null; -echo "---\n"; -var_dump($weakO->get() !== null); // verify if released +echo "OK\n"; ?> --EXPECT-- ---- -d ---- -bool(true) ---- -bool(false) +OK diff --git a/Zend/tests/gc_051.phpt b/Zend/tests/gc_051.phpt new file mode 100644 index 0000000000000..575a25a108a15 --- /dev/null +++ b/Zend/tests/gc_051.phpt @@ -0,0 +1,29 @@ +--TEST-- +GC 048: FE_FREE should mark variable as UNDEF to prevent use-after-free during GC +--FILE-- +ref = $b; + $b->ref = $a; + + $result = test_foreach_early_return("x"); +} + +echo "OK\n"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/gc_052.phpt b/Zend/tests/gc_052.phpt new file mode 100644 index 0000000000000..dd15c56bcbf54 --- /dev/null +++ b/Zend/tests/gc_052.phpt @@ -0,0 +1,36 @@ +--TEST-- +GC 049: Multiple early returns from foreach should create separate live ranges +--FILE-- +r = $b; + $b->r = $a; + + $r = f($i % 3 + 1); +} +echo "OK\n"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/gc_053.phpt b/Zend/tests/gc_053.phpt new file mode 100644 index 0000000000000..858be7cbebd5f --- /dev/null +++ b/Zend/tests/gc_053.phpt @@ -0,0 +1,37 @@ +--TEST-- +GC 050: Destructor are never called twice +--FILE-- +get() !== null); // verify if kept allocated +G::$v = null; +echo "---\n"; +var_dump($weakO->get() !== null); // verify if released +?> +--EXPECT-- +--- +d +--- +bool(true) +--- +bool(false) diff --git a/Zend/tests/gh14003.phpt b/Zend/tests/gh14003.phpt index 92a6c5919ab5b..8d25cad863c14 100644 --- a/Zend/tests/gh14003.phpt +++ b/Zend/tests/gh14003.phpt @@ -18,7 +18,6 @@ array_filter( --EXPECTF-- Fatal error: Uncaught Exception: Test in %s:%d Stack trace: -#0 [internal function]: foo('a') -#1 %s(%d): array_map(Object(Closure), Array) -#2 {main} +#0 %s(%d): foo('a') +#1 {main} thrown in %s on line %d diff --git a/Zend/tests/gh20564.phpt b/Zend/tests/gh20564.phpt new file mode 100644 index 0000000000000..53311d952de71 --- /dev/null +++ b/Zend/tests/gh20564.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-20564: Don't call autoloaders with pending exception +--CREDITS-- +Viet Hoang Luu (@vi3tL0u1s) +--FILE-- +test(); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +array_map(): Argument #1 ($callback) must be a valid callback or null, class "B" not found 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-471486164-001.phpt b/Zend/tests/oss-fuzz-471486164-001.phpt new file mode 100644 index 0000000000000..a48a56398c1e1 --- /dev/null +++ b/Zend/tests/oss-fuzz-471486164-001.phpt @@ -0,0 +1,22 @@ +--TEST-- +OSS-Fuzz #471486164: get_property_ptr_ptr() on uninitialized hooked property +--FILE-- + $this->a; + set { $this->a = &$value; } + } + public $x = 1; +} + +$proxy = (new ReflectionClass(C::class))->newLazyProxy(function ($proxy) { + $proxy->a = 1; + return new C; +}); +var_dump($proxy->x); + +?> +--EXPECT-- +int(1) diff --git a/Zend/tests/oss-fuzz-471486164-002.phpt b/Zend/tests/oss-fuzz-471486164-002.phpt new file mode 100644 index 0000000000000..688dd76122018 --- /dev/null +++ b/Zend/tests/oss-fuzz-471486164-002.phpt @@ -0,0 +1,26 @@ +--TEST-- +OSS-Fuzz #471486164: get_property_ptr_ptr() on uninitialized hooked property +--FILE-- + $this->a; + set { + global $ref; + $this->a = &$ref; + } + } +} + +$ref = 1; +$proxy = new C; +$proxy->a = 1; +var_dump($proxy->a); +$ref++; +var_dump($proxy->a); + +?> +--EXPECT-- +int(1) +int(2) diff --git a/Zend/tests/oss-fuzz-474613951.phpt b/Zend/tests/oss-fuzz-474613951.phpt new file mode 100644 index 0000000000000..552be2e0116a9 --- /dev/null +++ b/Zend/tests/oss-fuzz-474613951.phpt @@ -0,0 +1,17 @@ +--TEST-- +OSS-Fuzz #474613951: Leaked parent property default value +--FILE-- + $this->prop; } +} + +class B extends A { + public $prop { get => 42; } +} + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/oss_fuzz_429429090.phpt b/Zend/tests/oss_fuzz_429429090.phpt new file mode 100644 index 0000000000000..d5279c2806ac6 --- /dev/null +++ b/Zend/tests/oss_fuzz_429429090.phpt @@ -0,0 +1,20 @@ +--TEST-- +OSS-Fuzz #429429090: FETCH_OBJ_UNSET IS_UNDEF result +--FILE-- +x[0]->prop); +unset($c->x[0]->prop); +isset(C::$y[0]->prop); +unset(C::$y[0]->prop); + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/oss_fuzz_438780145.phpt b/Zend/tests/oss_fuzz_438780145.phpt new file mode 100644 index 0000000000000..4c6936a69a019 --- /dev/null +++ b/Zend/tests/oss_fuzz_438780145.phpt @@ -0,0 +1,27 @@ +--TEST-- +OSS-Fuzz #438780145: Nested finally with repeated return type check may uaf +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught TypeError: test(): Return value must be of type int, string returned in %s:%d +Stack trace: +#0 %s(%d): test() +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/partial_application/assert.phpt b/Zend/tests/partial_application/assert.phpt new file mode 100644 index 0000000000000..fe36e687f8d58 --- /dev/null +++ b/Zend/tests/partial_application/assert.phpt @@ -0,0 +1,35 @@ +--TEST-- +PFA of assert() behaves like a dynamic call to assert() +--FILE-- +getMessage(), "\n"; +} + +try { + echo "# Dynamic call:\n"; + (function ($f) { $f(false); })('assert'); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage() ?: '(no message)', "\n"; +} + +try { + echo "# PFA call:\n"; + $f = assert(?); + $f(false); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage() ?: '(no message)', "\n"; +} + +?> +--EXPECT-- +# Static call: +AssertionError: assert(false) +# Dynamic call: +AssertionError: (no message) +# PFA call: +AssertionError: (no message) diff --git a/Zend/tests/partial_application/attributes_001.phpt b/Zend/tests/partial_application/attributes_001.phpt new file mode 100644 index 0000000000000..827ad41321ec6 --- /dev/null +++ b/Zend/tests/partial_application/attributes_001.phpt @@ -0,0 +1,88 @@ +--TEST-- +PFA inherits NoDiscard and SensitiveParameter attributes +--FILE-- +getAttributes()); + + foreach ($r->getParameters() as $i => $p) { + echo "Parameter $i:\n"; + var_dump($p->getAttributes()); + } +} + +echo "# Orig attributes:\n"; + +dump_attributes('f'); + +$f = f(1, ?, ?, ...); + +echo "# PFA attributes:\n"; + +dump_attributes($f); + +?> +--EXPECTF-- +# Orig attributes: +array(2) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(9) "NoDiscard" + } + [1]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(4) "Test" + } +} +Parameter 0: +array(0) { +} +Parameter 1: +array(1) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(18) "SensitiveParameter" + } +} +Parameter 2: +array(1) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(4) "Test" + } +} +# PFA attributes: +array(1) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(9) "NoDiscard" + } +} +Parameter 0: +array(1) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(18) "SensitiveParameter" + } +} +Parameter 1: +array(0) { +} +Parameter 2: +array(0) { +} diff --git a/Zend/tests/partial_application/attributes_002.phpt b/Zend/tests/partial_application/attributes_002.phpt new file mode 100644 index 0000000000000..be1f1612f9389 --- /dev/null +++ b/Zend/tests/partial_application/attributes_002.phpt @@ -0,0 +1,19 @@ +--TEST-- +PFA preserves #[SensitiveParameter] +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Exception in %s:%d +Stack trace: +#0 %s(%d): f(1, Object(SensitiveParameterValue), 3, Object(SensitiveParameterValue), Object(SensitiveParameterValue)) +#1 %s(%d): {closure:pfa:%s:7}(Object(SensitiveParameterValue), 3, Object(SensitiveParameterValue), Object(SensitiveParameterValue)) +#2 {main} + thrown in %s on line %d diff --git a/Zend/tests/partial_application/attributes_003.phpt b/Zend/tests/partial_application/attributes_003.phpt new file mode 100644 index 0000000000000..d113d02eb8f79 --- /dev/null +++ b/Zend/tests/partial_application/attributes_003.phpt @@ -0,0 +1,16 @@ +--TEST-- +PFA preserves #[NoDiscard] +--FILE-- + +--EXPECTF-- +Warning: The return value of function {closure:%s}() should either be used or intentionally ignored by casting it as (void) in %s on line 7 diff --git a/Zend/tests/partial_application/clone.phpt b/Zend/tests/partial_application/clone.phpt new file mode 100644 index 0000000000000..f778d776b7173 --- /dev/null +++ b/Zend/tests/partial_application/clone.phpt @@ -0,0 +1,50 @@ +--TEST-- +clone() can be partially applied +--FILE-- + 7])); + +$clone = clone(?, ['a' => 8]); +var_dump($clone(new C(9, 10))); + +?> +--EXPECTF-- +object(C)#%d (2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} +object(C)#%d (2) { + ["a"]=> + int(3) + ["b"]=> + int(4) +} +object(C)#%d (2) { + ["a"]=> + int(7) + ["b"]=> + int(6) +} +object(C)#%d (2) { + ["a"]=> + int(8) + ["b"]=> + int(10) +} diff --git a/Zend/tests/partial_application/compile_errors_001.phpt b/Zend/tests/partial_application/compile_errors_001.phpt new file mode 100644 index 0000000000000..f08495a1f1e56 --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_001.phpt @@ -0,0 +1,8 @@ +--TEST-- +PFA compile errors: multiple variadic placeholders +--FILE-- + +--EXPECTF-- +Fatal error: Variadic placeholder may only appear once in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_002.phpt b/Zend/tests/partial_application/compile_errors_002.phpt new file mode 100644 index 0000000000000..b6a2073a83638 --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_002.phpt @@ -0,0 +1,8 @@ +--TEST-- +PFA compile errors: variadic placeholder must be last +--FILE-- + +--EXPECTF-- +Fatal error: Variadic placeholder must be last in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_003.phpt b/Zend/tests/partial_application/compile_errors_003.phpt new file mode 100644 index 0000000000000..26ff8435111b6 --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_003.phpt @@ -0,0 +1,8 @@ +--TEST-- +PFA compile errors: placeholders can not appear after named args +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use positional argument after named argument in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_004.phpt b/Zend/tests/partial_application/compile_errors_004.phpt new file mode 100644 index 0000000000000..ac7ec163c5dae --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_004.phpt @@ -0,0 +1,8 @@ +--TEST-- +PFA compile errors: variadic placeholder must be last, including after named args +--FILE-- + +--EXPECTF-- +Fatal error: Variadic placeholder must be last in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_005.phpt b/Zend/tests/partial_application/compile_errors_005.phpt new file mode 100644 index 0000000000000..30e4aa12b488f --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_005.phpt @@ -0,0 +1,8 @@ +--TEST-- +PFA compile errors: variadic placeholder must be last, including after positional args +--FILE-- + +--EXPECTF-- +Fatal error: Variadic placeholder must be last in %s on line %d diff --git a/Zend/tests/partial_application/compile_errors_006.phpt b/Zend/tests/partial_application/compile_errors_006.phpt new file mode 100644 index 0000000000000..90210be6acae7 --- /dev/null +++ b/Zend/tests/partial_application/compile_errors_006.phpt @@ -0,0 +1,8 @@ +--TEST-- +PFA compile errors: can not use unpacking in PFA, including with variadic placeholdres +--FILE-- + "bar"], ...); +?> +--EXPECTF-- +Fatal error: Cannot combine partial application and unpacking in %s on line %d diff --git a/Zend/tests/partial_application/errors_001.phpt b/Zend/tests/partial_application/errors_001.phpt new file mode 100644 index 0000000000000..2d5348cb28af3 --- /dev/null +++ b/Zend/tests/partial_application/errors_001.phpt @@ -0,0 +1,62 @@ +--TEST-- +PFA errors: PFA instantiation follows the usual argument count validation +--FILE-- +getMessage()); +} + +try { + foo(?, ?, ?, ?); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +try { + $c = new C(); + $c->f(?); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +try { + property_exists(?); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +try { + usleep(?, ?); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +try { + foo(?, ?, ?, ?, ...); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +/* It is allowed to specify less than the number of required params, when there + * is a variadic placeholder */ +foo(?, ...); + +?> +--EXPECT-- +ArgumentCountError: Partial application of foo() expects exactly 3 arguments, 1 given +ArgumentCountError: Partial application of foo() expects at most 3 arguments, 4 given +ArgumentCountError: Partial application of C::f() expects exactly 3 arguments, 1 given +ArgumentCountError: Partial application of property_exists() expects exactly 2 arguments, 1 given +ArgumentCountError: Partial application of usleep() expects at most 1 arguments, 2 given +ArgumentCountError: Partial application of foo() expects at most 3 arguments, 4 given diff --git a/Zend/tests/partial_application/errors_002.phpt b/Zend/tests/partial_application/errors_002.phpt new file mode 100644 index 0000000000000..0132d8873e2ab --- /dev/null +++ b/Zend/tests/partial_application/errors_002.phpt @@ -0,0 +1,15 @@ +--TEST-- +PFA errors: named parameter that resolve to the position of a placeholder is an error +--FILE-- +getMessage()); +} +?> +--EXPECT-- +Error: Named parameter $a overwrites previous placeholder diff --git a/Zend/tests/partial_application/errors_003.phpt b/Zend/tests/partial_application/errors_003.phpt new file mode 100644 index 0000000000000..bc1c16e64f9b8 --- /dev/null +++ b/Zend/tests/partial_application/errors_003.phpt @@ -0,0 +1,77 @@ +--TEST-- +PFA errors: PFA call follows the usual argument count validation +--FILE-- +getMessage()); +} + +$foo = foo(?, ?); + +try { + $foo(1); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +$bar = bar(?, ?, ...); + +try { + $bar(1); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +class Foo { + public function bar($a, ...$b) {} +} + +$foo = new Foo; + +$bar = $foo->bar(?); + +try { + $bar(); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +$repeat = str_repeat('a', ...); + +try { + $repeat(); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +$usleep = usleep(?); + +try { + $usleep(); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +try { + $usleep(1, 2); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} +?> +--EXPECTF-- +ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected +ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 1 passed in %s on line %d and exactly 2 expected +ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 1 passed in %s on line %d and exactly 3 expected +ArgumentCountError: Too few arguments to function Foo::{closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected +ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected +ArgumentCountError: Too few arguments to function {closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected diff --git a/Zend/tests/partial_application/errors_004.phpt b/Zend/tests/partial_application/errors_004.phpt new file mode 100644 index 0000000000000..e5e1432753b27 --- /dev/null +++ b/Zend/tests/partial_application/errors_004.phpt @@ -0,0 +1,16 @@ +--TEST-- +PFA errors: not specifying a required param is an error +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught ArgumentCountError: f(): Argument #2 ($b) not passed in %s:6 +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/partial_application/errors_005.phpt b/Zend/tests/partial_application/errors_005.phpt new file mode 100644 index 0000000000000..2c28f0565e2d8 --- /dev/null +++ b/Zend/tests/partial_application/errors_005.phpt @@ -0,0 +1,15 @@ +--TEST-- +PFA errors: Can not fetch default parameter value for Closure::__invoke() +--FILE-- +__invoke(0, 0, ?); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +ArgumentCountError: Closure::__invoke(): Argument #3 ($c) must be passed explicitly, because the default value is not known diff --git a/Zend/tests/partial_application/errors_006.phpt b/Zend/tests/partial_application/errors_006.phpt new file mode 100644 index 0000000000000..aec2fc5dc0734 --- /dev/null +++ b/Zend/tests/partial_application/errors_006.phpt @@ -0,0 +1,23 @@ +--TEST-- +PFA errors: Some internal function parameters have UNKNOWN default value +--FILE-- + array_keys($array, ???, true) + $f = array_keys(?, strict: true); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +try { + // fn (array $array, mixed $filter_value = ???) => array_keys($array, $filter_value, true) + $f = array_keys(?, strict: true, ...); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +ArgumentCountError: array_keys(): Argument #2 ($filter_value) must be passed explicitly, because the default value is not known +ArgumentCountError: array_keys(): Argument #2 ($filter_value) must be passed explicitly, because the default value is not known diff --git a/Zend/tests/partial_application/export_001.phpt b/Zend/tests/partial_application/export_001.phpt new file mode 100644 index 0000000000000..b48146bcc65a8 --- /dev/null +++ b/Zend/tests/partial_application/export_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +PFA AST export +--INI-- +assert.exception=1 +--FILE-- +getMessage()); +} +?> +--EXPECT-- +AssertionError: assert(0 && foo(?) && foo(new stdClass(), bar: 1, ...)) diff --git a/Zend/tests/partial_application/extra_named.phpt b/Zend/tests/partial_application/extra_named.phpt new file mode 100644 index 0000000000000..4dd80cfa0127f --- /dev/null +++ b/Zend/tests/partial_application/extra_named.phpt @@ -0,0 +1,49 @@ +--TEST-- +PFA extra named parameters are forwarded to the actual function +--FILE-- + +--EXPECT-- +array(3) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" + ["baz"]=> + string(3) "baz" +} +array(2) { + ["bar"]=> + string(3) "bar" + ["baz"]=> + string(3) "baz" +} +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} diff --git a/Zend/tests/partial_application/function_name.phpt b/Zend/tests/partial_application/function_name.phpt new file mode 100644 index 0000000000000..5ed0c58696408 --- /dev/null +++ b/Zend/tests/partial_application/function_name.phpt @@ -0,0 +1,19 @@ +--TEST-- +Partial application function name +--FILE-- +getName()); +} + +f(); + +var_dump((new ReflectionFunction(g(?)))->getName()); + +?> +--EXPECTF-- +string(%d) "{closure:pfa:f():6}" +string(%d) "{closure:pfa:%sfunction_name.php:11}" diff --git a/Zend/tests/partial_application/fuzz_001.phpt b/Zend/tests/partial_application/fuzz_001.phpt new file mode 100644 index 0000000000000..f6544105a435b --- /dev/null +++ b/Zend/tests/partial_application/fuzz_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +Closure application fuzz 001 +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %s 4 - 4 + + - Bound Variables [2] { + Variable #0 [ $fn ] + Variable #1 [ $a ] + } + + - Parameters [1] { + Parameter #0 [ $b ] + } +} diff --git a/Zend/tests/partial_application/fuzz_002.phpt b/Zend/tests/partial_application/fuzz_002.phpt new file mode 100644 index 0000000000000..685cb706e69bb --- /dev/null +++ b/Zend/tests/partial_application/fuzz_002.phpt @@ -0,0 +1,13 @@ +--TEST-- +Closure application fuzz 002 +--FILE-- + +--EXPECTF-- +OK diff --git a/Zend/tests/partial_application/fuzz_003.phpt b/Zend/tests/partial_application/fuzz_003.phpt new file mode 100644 index 0000000000000..6e9d583fda99b --- /dev/null +++ b/Zend/tests/partial_application/fuzz_003.phpt @@ -0,0 +1,20 @@ +--TEST-- +Closure application fuzz 003 +--FILE-- +method(1, ...); +$bar(2); +?> +--EXPECT-- +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} diff --git a/Zend/tests/partial_application/fuzz_004.phpt b/Zend/tests/partial_application/fuzz_004.phpt new file mode 100644 index 0000000000000..ea005304a3afb --- /dev/null +++ b/Zend/tests/partial_application/fuzz_004.phpt @@ -0,0 +1,19 @@ +--TEST-- +Closure application fuzz 004 +--FILE-- +__invoke(UNDEFINED); +} catch (\Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Error: Undefined constant "UNDEFINED" diff --git a/Zend/tests/partial_application/fuzz_005.phpt b/Zend/tests/partial_application/fuzz_005.phpt new file mode 100644 index 0000000000000..ea04862d83998 --- /dev/null +++ b/Zend/tests/partial_application/fuzz_005.phpt @@ -0,0 +1,16 @@ +--TEST-- +PFA fuzz 005 +--FILE-- + +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/partial_application/fuzz_006.phpt b/Zend/tests/partial_application/fuzz_006.phpt new file mode 100644 index 0000000000000..26ec6e3e4dd1f --- /dev/null +++ b/Zend/tests/partial_application/fuzz_006.phpt @@ -0,0 +1,16 @@ +--TEST-- +PFA fuzz 006 +--FILE-- + +--EXPECT-- +int(1) diff --git a/Zend/tests/partial_application/fuzz_007.phpt b/Zend/tests/partial_application/fuzz_007.phpt new file mode 100644 index 0000000000000..123ce29d8b180 --- /dev/null +++ b/Zend/tests/partial_application/fuzz_007.phpt @@ -0,0 +1,19 @@ +--TEST-- +PFA fuzz 007 +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Undefined constant "UNDEFINED" diff --git a/Zend/tests/partial_application/hook.phpt b/Zend/tests/partial_application/hook.phpt new file mode 100644 index 0000000000000..6402c5d01e747 --- /dev/null +++ b/Zend/tests/partial_application/hook.phpt @@ -0,0 +1,25 @@ +--TEST-- +Parent property hook call can not be partially applied +--FILE-- +a = 1; + +?> +--EXPECTF-- +Fatal error: Cannot create Closure for parent property hook call in %s on line %d diff --git a/Zend/tests/partial_application/invokable.phpt b/Zend/tests/partial_application/invokable.phpt new file mode 100644 index 0000000000000..c21030e7733a8 --- /dev/null +++ b/Zend/tests/partial_application/invokable.phpt @@ -0,0 +1,51 @@ +--TEST-- +__invoke() can be partially applied +--FILE-- + +--EXPECTF-- +Closure [ public method {closure:%s:%d} ] { + @@ %s.php 11 - 11 + + - Parameters [2] { + Parameter #0 [ int $a ] + Parameter #1 [ object $b ] + } + - Return [ C ] +} + +Closure [ public method {closure:%s:%d} ] { + @@ %s.php 15 - 15 + + - Bound Variables [1] { + Variable #0 [ $b ] + } + + - Parameters [1] { + Parameter #0 [ int $a ] + } + - Return [ C ] +} + +int(1) +object(stdClass)#%d (0) { +} diff --git a/Zend/tests/partial_application/jit_001.phpt b/Zend/tests/partial_application/jit_001.phpt new file mode 100644 index 0000000000000..84aefa05ab282 --- /dev/null +++ b/Zend/tests/partial_application/jit_001.phpt @@ -0,0 +1,9 @@ +--TEST-- +PFA JIT 001 +--FILE-- + +--EXPECT-- +int(1) +int(2) diff --git a/Zend/tests/partial_application/magic_001.phpt b/Zend/tests/partial_application/magic_001.phpt new file mode 100644 index 0000000000000..e1d5248fdee41 --- /dev/null +++ b/Zend/tests/partial_application/magic_001.phpt @@ -0,0 +1,82 @@ +--TEST-- +__call() can be partially applied +--FILE-- +method(?); + +echo (string) new ReflectionFunction($bar); + +try { + $bar(); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +try { + $bar(1, 2); +} catch (Error $ex) { + printf("%s: %s\n", $ex::class, $ex->getMessage()); +} + +$bar(1); + +$bar = $foo->method(?, ...); + +echo (string) new ReflectionFunction($bar); + +$bar(10); + +$bar = $foo->method(new Foo, ...); + +echo (string) new ReflectionFunction($bar); + +$bar(100); +?> +--EXPECTF-- +Closure [ public method {closure:%s:%d} ] { + @@ %s 12 - 12 + + - Parameters [1] { + Parameter #0 [ mixed $arguments0 ] + } +} +ArgumentCountError: Too few arguments to function Foo::{closure:%s:%d}(), 0 passed in %s on line %d and exactly 1 expected +Foo::method +int(1) +Foo::method +int(1) +Closure [ public method {closure:%s:%d} ] { + @@ %s 30 - 30 + + - Parameters [2] { + Parameter #0 [ mixed $arguments0 ] + Parameter #1 [ mixed ...$arguments ] + } +} +Foo::method +int(10) +Closure [ public method {closure:%s:%d} ] { + @@ %s 36 - 36 + + - Bound Variables [1] { + Variable #0 [ $arguments0 ] + } + + - Parameters [1] { + Parameter #0 [ mixed ...$arguments ] + } +} +Foo::method +object(Foo)#%d (0) { +} +int(100) diff --git a/Zend/tests/partial_application/magic_002.phpt b/Zend/tests/partial_application/magic_002.phpt new file mode 100644 index 0000000000000..ff4e26623a9ed --- /dev/null +++ b/Zend/tests/partial_application/magic_002.phpt @@ -0,0 +1,65 @@ +--TEST-- +__callStatic() can be partially applied +--FILE-- + +--EXPECTF-- +Closure [ static public method {closure:%s:%d} ] { + @@ %s 10 - 10 + + - Parameters [1] { + Parameter #0 [ mixed $arguments0 ] + } +} +Foo::method +int(1) +Closure [ static public method {closure:%s:%d} ] { + @@ %s 16 - 16 + + - Parameters [2] { + Parameter #0 [ mixed $arguments0 ] + Parameter #1 [ mixed ...$arguments ] + } +} +Foo::method +int(10) +Closure [ static public method {closure:%s:%d} ] { + @@ %s 22 - 22 + + - Bound Variables [1] { + Variable #0 [ $arguments0 ] + } + + - Parameters [1] { + Parameter #0 [ mixed ...$arguments ] + } +} +Foo::method +object(Foo)#%d (0) { +} +int(100) diff --git a/Zend/tests/partial_application/magic_003.phpt b/Zend/tests/partial_application/magic_003.phpt new file mode 100644 index 0000000000000..242403ea38fc8 --- /dev/null +++ b/Zend/tests/partial_application/magic_003.phpt @@ -0,0 +1,13 @@ +--TEST-- +PFA magic trampoline release (result unused) +--FILE-- + +--EXPECT-- +OK diff --git a/Zend/tests/partial_application/magic_004.phpt b/Zend/tests/partial_application/magic_004.phpt new file mode 100644 index 0000000000000..8ef93a91ce838 --- /dev/null +++ b/Zend/tests/partial_application/magic_004.phpt @@ -0,0 +1,14 @@ +--TEST-- +PFA magic trampoline release (result used) +--FILE-- + +--EXPECT-- +OK diff --git a/Zend/tests/partial_application/magic_005.phpt b/Zend/tests/partial_application/magic_005.phpt new file mode 100644 index 0000000000000..e70ed90b17672 --- /dev/null +++ b/Zend/tests/partial_application/magic_005.phpt @@ -0,0 +1,29 @@ +--TEST-- +PFA magic null ptr deref in arginfo +--FILE-- +method(?); +var_dump($bar); +?> +--EXPECTF-- +object(Closure)#%d (%d) { + ["name"]=> + string(%d) "{closure:%s}" + ["file"]=> + string(%d) "%smagic_005.php" + ["line"]=> + int(7) + ["this"]=> + object(Foo)#%d (0) { + } + ["parameter"]=> + array(1) { + ["$arguments0"]=> + string(10) "" + } +} diff --git a/Zend/tests/partial_application/magic_006.phpt b/Zend/tests/partial_application/magic_006.phpt new file mode 100644 index 0000000000000..29564d8b615a7 --- /dev/null +++ b/Zend/tests/partial_application/magic_006.phpt @@ -0,0 +1,20 @@ +--TEST-- +PFA magic varargs +--FILE-- +method(1,...); +$bar(2); +?> +--EXPECT-- +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} diff --git a/Zend/tests/partial_application/named_placeholders.phpt b/Zend/tests/partial_application/named_placeholders.phpt new file mode 100644 index 0000000000000..6517a8946d36b --- /dev/null +++ b/Zend/tests/partial_application/named_placeholders.phpt @@ -0,0 +1,117 @@ +--TEST-- +PFA supports named placeholders +--FILE-- +getMessage(), "\n"; +} + +try { + $bar = bar(c: ?, ...); +} catch (\Throwable $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %snamed_placeholders.php 11 - 11 + + - Parameters [1] { + Parameter #0 [ $b = 2 ] + } +} +int(1) +object(B)#%d (0) { +} +int(3) +Closure [ static function {closure:%s:%d} ] { + @@ %snamed_placeholders.php 17 - 17 + + - Bound Variables [1] { + Variable #0 [ $fn ] + } + + - Parameters [1] { + Parameter #0 [ $b = 2 ] + } +} +int(1) +object(B)#%d (0) { +} +int(3) +Closure [ static function {closure:%s:%d} ] { + @@ %snamed_placeholders.php 24 - 24 + + - Bound Variables [1] { + Variable #0 [ $fn ] + } + + - Parameters [1] { + Parameter #0 [ $b = 2 ] + } +} +int(1) +object(B)#%d (0) { +} +int(3) +Closure [ static function {closure:%s:%d} ] { + @@ %snamed_placeholders.php 34 - 34 + + - Parameters [3] { + Parameter #0 [ $b = 2 ] + Parameter #1 [ $a = 1 ] + Parameter #2 [ ...$c ] + } +} +object(A)#%d (0) { +} +object(B)#%d (0) { +} +array(1) { + [0]=> + object(C)#%d (0) { + } +} +Named parameter $a overwrites previous placeholder +Cannot use named placeholder for unknown or variadic parameter $c diff --git a/Zend/tests/partial_application/non_dynamic_call_funcs.phpt b/Zend/tests/partial_application/non_dynamic_call_funcs.phpt new file mode 100644 index 0000000000000..db25ef3dcc93b --- /dev/null +++ b/Zend/tests/partial_application/non_dynamic_call_funcs.phpt @@ -0,0 +1,46 @@ +--TEST-- +Functions that can not be called dynamically, can not be partially applied +--FILE-- +getMessage(), "\n"; + } +} + +?> +--EXPECT-- +Error: Cannot call func_get_arg() dynamically +Error: Cannot call compact() dynamically +Error: Cannot call extract() dynamically +Error: Cannot call func_get_args() dynamically +Error: Cannot call func_num_args() dynamically +Error: Cannot call get_defined_vars() dynamically diff --git a/Zend/tests/partial_application/observers.phpt b/Zend/tests/partial_application/observers.phpt new file mode 100644 index 0000000000000..8717b38ca326d --- /dev/null +++ b/Zend/tests/partial_application/observers.phpt @@ -0,0 +1,34 @@ +--TEST-- +PFA support observers +--EXTENSIONS-- +zend_test +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.show_output=1 +zend_test.observer.observe_all=1 +--FILE-- + +--EXPECTF-- + + + + <{closure:%s}> + + + + +int(1) +int(2) + + + + diff --git a/Zend/tests/partial_application/param_reorder.phpt b/Zend/tests/partial_application/param_reorder.phpt new file mode 100644 index 0000000000000..3ade1beb0af73 --- /dev/null +++ b/Zend/tests/partial_application/param_reorder.phpt @@ -0,0 +1,202 @@ +--TEST-- +Named parameters define the order of parameters in a PFA +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECTF-- +# All named +Closure [ static function {closure:%s:%d} ] { + @@ %sparam_reorder.php 13 - 13 + + - Parameters [4] { + Parameter #0 [ $d ] + Parameter #1 [ $c ] + Parameter #2 [ $b ] + Parameter #3 [ $a ] + } +} + +array(4) { + [0]=> + int(4) + [1]=> + int(3) + [2]=> + int(2) + [3]=> + int(1) +} +# Some named: Positional first, then named in specified order +Closure [ static function {closure:%s:%d} ] { + @@ %sparam_reorder.php 19 - 19 + + - Parameters [4] { + Parameter #0 [ $a ] + Parameter #1 [ $b ] + Parameter #2 [ $d ] + Parameter #3 [ $c ] + } +} + +array(4) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(4) + [3]=> + int(3) +} +# Some named, one unspecified +Closure [ static function {closure:%s:%d} ] { + @@ %sparam_reorder.php 25 - 25 + + - Parameters [3] { + Parameter #0 [ $a ] + Parameter #1 [ $c ] + Parameter #2 [ $b ] + } +} + +array(4) { + [0]=> + int(1) + [1]=> + int(3) + [2]=> + int(2) + [3]=> + NULL +} +# Some named, some implicit added by '...' +Closure [ static function {closure:%s:%d} ] { + @@ %sparam_reorder.php 31 - 31 + + - Parameters [4] { + Parameter #0 [ $c ] + Parameter #1 [ $b ] + Parameter #2 [ $a ] + Parameter #3 [ $d = NULL ] + } +} + +array(4) { + [0]=> + int(3) + [1]=> + int(2) + [2]=> + int(1) + [3]=> + int(4) +} +# Some named, some implicit added by '...' on variadic function +Closure [ static function {closure:%s:%d} ] { + @@ %sparam_reorder.php 37 - 37 + + - Parameters [4] { + Parameter #0 [ $c ] + Parameter #1 [ $b ] + Parameter #2 [ $a ] + Parameter #3 [ ...$d ] + } +} + +array(4) { + [0]=> + int(3) + [1]=> + int(2) + [2]=> + int(1) + [3]=> + array(3) { + [0]=> + int(4) + [1]=> + int(5) + [2]=> + int(6) + } +} +# Some prebound, some named +Closure [ static function {closure:%s:%d} ] { + @@ %sparam_reorder.php 43 - 43 + + - Bound Variables [2] { + Variable #0 [ $a ] + Variable #1 [ $d ] + } + + - Parameters [2] { + Parameter #0 [ $c ] + Parameter #1 [ $b ] + } +} + +array(4) { + [0]=> + int(-1) + [1]=> + int(2) + [2]=> + int(1) + [3]=> + int(-2) +} +# Some named, some required missing +ArgumentCountError: f(): Argument #1 ($a) not passed diff --git a/Zend/tests/partial_application/pipe_optimization_001.phpt b/Zend/tests/partial_application/pipe_optimization_001.phpt new file mode 100644 index 0000000000000..71bfee5dba44e --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_001.phpt @@ -0,0 +1,47 @@ +--TEST-- +PFA optimization: PFA with single placeholder arg can be optimized +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a) { + var_dump($a); + } +} + +1 |> foo(?); + +?> +--EXPECTF-- +$_main: + ; (lines=9, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %spipe_optimization_001.php:1-12 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 1 string("foo") +0006 SEND_VAL_EX int(1) 1 +0007 DO_FCALL_BY_NAME +0008 RETURN int(1) + +foo: + ; (lines=5, args=1, vars=1, tmps=0) + ; (after optimizer) + ; %spipe_optimization_001.php:4-6 +0000 CV0($a) = RECV 1 +0001 INIT_FCALL 1 %d string("var_dump") +0002 SEND_VAR CV0($a) 1 +0003 DO_ICALL +0004 RETURN null +int(1) diff --git a/Zend/tests/partial_application/pipe_optimization_002.phpt b/Zend/tests/partial_application/pipe_optimization_002.phpt new file mode 100644 index 0000000000000..ae5992e405a05 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_002.phpt @@ -0,0 +1,51 @@ +--TEST-- +PFA pipe optimization: PFA with only one placeholder can be optimized +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b) { + var_dump($a, $b); + } +} + +2 |> foo(1, ?); + +?> +--EXPECTF-- +$_main: + ; (lines=10, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %spipe_optimization_002.php:1-12 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 2 string("foo") +0006 SEND_VAL_EX int(1) 1 +0007 SEND_VAL_EX int(2) 2 +0008 DO_FCALL_BY_NAME +0009 RETURN int(1) + +foo: + ; (lines=7, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %spipe_optimization_002.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 RETURN null +int(1) +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_003.phpt b/Zend/tests/partial_application/pipe_optimization_003.phpt new file mode 100644 index 0000000000000..f6c547d19dae0 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_003.phpt @@ -0,0 +1,51 @@ +--TEST-- +PFA pipe optimization: PFA with only one placeholder can be optimized (placeholder first) +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b) { + var_dump($a, $b); + } +} + +2 |> foo(?, 1); + +?> +--EXPECTF-- +$_main: + ; (lines=10, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %spipe_optimization_003.php:1-12 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 2 string("foo") +0006 SEND_VAL_EX int(2) 1 +0007 SEND_VAL_EX int(1) 2 +0008 DO_FCALL_BY_NAME +0009 RETURN int(1) + +foo: + ; (lines=7, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %spipe_optimization_003.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 RETURN null +int(2) +int(1) diff --git a/Zend/tests/partial_application/pipe_optimization_004.phpt b/Zend/tests/partial_application/pipe_optimization_004.phpt new file mode 100644 index 0000000000000..edf0d9f775cd5 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_004.phpt @@ -0,0 +1,88 @@ +--TEST-- +PFA pipe optimization: PFA with multiple placeholders can not be optimized +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b) { + var_dump($a, $b); + } +} + +try { + 2 |> foo(?, ?); +} catch (\Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +$_main: + ; (lines=22, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %spipe_optimization_004.php:1-16 +0000 INIT_FCALL 0 %d string("time") +0001 V2 = DO_ICALL +0002 T1 = IS_SMALLER int(0) V2 +0003 JMPZ T1 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 2 string("foo") +0006 SEND_PLACEHOLDER +0007 SEND_PLACEHOLDER +0008 T1 = CALLABLE_CONVERT_PARTIAL %d +0009 INIT_DYNAMIC_CALL 1 T1 +0010 SEND_VAL_EX int(2) 1 +0011 DO_FCALL +0012 RETURN int(1) +0013 CV0($e) = CATCH string("Throwable") +0014 T1 = FETCH_CLASS_NAME CV0($e) +0015 ECHO T1 +0016 ECHO string(": ") +0017 INIT_METHOD_CALL 0 CV0($e) string("getMessage") +0018 V1 = DO_FCALL +0019 ECHO V1 +0020 ECHO string("\n") +0021 RETURN int(1) +EXCEPTION TABLE: + 0005, 0013, -, - + +foo: + ; (lines=7, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %spipe_optimization_004.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 RETURN null + +$_main: + ; (lines=3, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:1-10 +0000 T0 = DECLARE_LAMBDA_FUNCTION 0 +0001 FREE T0 +0002 RETURN int(1) + +{closure:%s:%d}: + ; (lines=7, args=2, vars=2, tmps=1) + ; (after optimizer) + ; %s:10-10 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("foo") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 V2 = DO_UCALL +0006 RETURN V2 +ArgumentCountError: Too few arguments to function {closure:pfa:%s:%d}(), 1 passed in %s on line %d and exactly 2 expected diff --git a/Zend/tests/partial_application/pipe_optimization_005.phpt b/Zend/tests/partial_application/pipe_optimization_005.phpt new file mode 100644 index 0000000000000..5a0c6de43bbc2 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_005.phpt @@ -0,0 +1,51 @@ +--TEST-- +PFA pipe optimization: PFA with only one placeholder can be optimized (variadic) +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b) { + var_dump($a, $b); + } +} + +2 |> foo(1, ...); + +?> +--EXPECTF-- +$_main: + ; (lines=10, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %spipe_optimization_005.php:1-12 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 2 string("foo") +0006 SEND_VAL_EX int(1) 1 +0007 SEND_VAL_EX int(2) 2 +0008 DO_FCALL_BY_NAME +0009 RETURN int(1) + +foo: + ; (lines=7, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %spipe_optimization_005.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 RETURN null +int(1) +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_006.phpt b/Zend/tests/partial_application/pipe_optimization_006.phpt new file mode 100644 index 0000000000000..2a83f2b83fe9a --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_006.phpt @@ -0,0 +1,55 @@ +--TEST-- +PFA pipe optimization: PFA with only one placeholder can be optimized (named) +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b = null, $c = null) { + var_dump($a, $b, $c); + } +} + +2 |> foo(1, c: ?); + +?> +--EXPECTF-- +$_main: + ; (lines=11, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %spipe_optimization_006.php:1-12 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 1 string("foo") +0006 SEND_VAL_EX int(1) 1 +0007 SEND_VAL_EX int(2) string("c") +0008 CHECK_UNDEF_ARGS +0009 DO_FCALL_BY_NAME +0010 RETURN int(1) + +foo: + ; (lines=9, args=3, vars=3, tmps=0) + ; (after optimizer) + ; %spipe_optimization_006.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV_INIT 2 null +0002 CV2($c) = RECV_INIT 3 null +0003 INIT_FCALL 3 %d string("var_dump") +0004 SEND_VAR CV0($a) 1 +0005 SEND_VAR CV1($b) 2 +0006 SEND_VAR CV2($c) 3 +0007 DO_ICALL +0008 RETURN null +int(1) +NULL +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_007.phpt b/Zend/tests/partial_application/pipe_optimization_007.phpt new file mode 100644 index 0000000000000..77e0c7cbfa0ee --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_007.phpt @@ -0,0 +1,88 @@ +--TEST-- +PFA pipe optimization: PFA with multiple placeholders can not be optimized (named) +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b) { + var_dump($a, $b); + } +} + +try { + 2 |> foo(a: ?, b: ?); +} catch (\Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +$_main: + ; (lines=22, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %spipe_optimization_007.php:1-16 +0000 INIT_FCALL 0 %d string("time") +0001 V2 = DO_ICALL +0002 T1 = IS_SMALLER int(0) V2 +0003 JMPZ T1 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 0 string("foo") +0006 SEND_PLACEHOLDER string("a") +0007 SEND_PLACEHOLDER string("b") +0008 T1 = CALLABLE_CONVERT_PARTIAL %d array(...) +0009 INIT_DYNAMIC_CALL 1 T1 +0010 SEND_VAL_EX int(2) 1 +0011 DO_FCALL +0012 RETURN int(1) +0013 CV0($e) = CATCH string("Throwable") +0014 T1 = FETCH_CLASS_NAME CV0($e) +0015 ECHO T1 +0016 ECHO string(": ") +0017 INIT_METHOD_CALL 0 CV0($e) string("getMessage") +0018 V1 = DO_FCALL +0019 ECHO V1 +0020 ECHO string("\n") +0021 RETURN int(1) +EXCEPTION TABLE: + 0005, 0013, -, - + +foo: + ; (lines=7, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %spipe_optimization_007.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 RETURN null + +$_main: + ; (lines=3, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s:1-10 +0000 T0 = DECLARE_LAMBDA_FUNCTION 0 +0001 FREE T0 +0002 RETURN int(1) + +{closure:%s:%d}: + ; (lines=7, args=2, vars=2, tmps=1) + ; (after optimizer) + ; %s:10-10 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("foo") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 V2 = DO_UCALL +0006 RETURN V2 +ArgumentCountError: Too few arguments to function {closure:pfa:%s:%d}(), 1 passed in %s on line %d and exactly 2 expected diff --git a/Zend/tests/partial_application/pipe_optimization_008.phpt b/Zend/tests/partial_application/pipe_optimization_008.phpt new file mode 100644 index 0000000000000..6293f782d4d44 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_008.phpt @@ -0,0 +1,99 @@ +--TEST-- +PFA pipe optimization: PFA with both a variadic placeholder and named arg can not be optimized +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b) { + var_dump($a, $b); + } +} + +try { + 2 |> foo(a: 1, ...); +} catch (\Throwable $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +$_main: + ; (lines=18, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %spipe_optimization_008.php:1-16 +0000 INIT_FCALL 0 %d string("time") +0001 V2 = DO_ICALL +0002 T1 = IS_SMALLER int(0) V2 +0003 JMPZ T1 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 0 string("foo") +0006 SEND_VAL_EX int(1) string("a") +0007 T1 = CALLABLE_CONVERT_PARTIAL %d +0008 INIT_DYNAMIC_CALL 1 T1 +0009 SEND_VAL_EX int(2) 1 +0010 DO_FCALL +0011 RETURN int(1) +0012 CV0($e) = CATCH string("Throwable") +0013 INIT_METHOD_CALL 0 CV0($e) string("getMessage") +0014 V1 = DO_FCALL +0015 ECHO V1 +0016 ECHO string("\n") +0017 RETURN int(1) +EXCEPTION TABLE: + 0005, 0012, -, - + +foo: + ; (lines=7, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %spipe_optimization_008.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 RETURN null + +$_main: + ; (lines=4, args=0, vars=1, tmps=1) + ; (after optimizer) + ; %s:1-10 +0000 T1 = DECLARE_LAMBDA_FUNCTION 0 +0001 BIND_LEXICAL T1 CV0($a) +0002 FREE T1 +0003 RETURN int(1) +LIVE RANGES: + 1: 0001 - 0002 (tmp/var) + +{closure:%s:%d}: + ; (lines=18, args=1, vars=2, tmps=2) + ; (after optimizer) + ; %s:10-10 +0000 CV0($b) = RECV 1 +0001 BIND_STATIC CV1($a) +0002 T3 = FUNC_NUM_ARGS +0003 T2 = IS_SMALLER_OR_EQUAL T3 int(1) +0004 JMPZ T2 0010 +0005 INIT_FCALL 2 %d string("foo") +0006 SEND_VAR CV1($a) 1 +0007 SEND_VAR CV0($b) 2 +0008 V2 = DO_UCALL +0009 RETURN V2 +0010 INIT_FCALL 2 %d string("foo") +0011 SEND_VAR CV1($a) 1 +0012 SEND_VAR CV0($b) 2 +0013 T2 = FUNC_GET_ARGS int(1) +0014 SEND_UNPACK T2 +0015 CHECK_UNDEF_ARGS +0016 V2 = DO_UCALL +0017 RETURN V2 +int(1) +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_009.phpt b/Zend/tests/partial_application/pipe_optimization_009.phpt new file mode 100644 index 0000000000000..0902786616373 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_009.phpt @@ -0,0 +1,103 @@ +--TEST-- +PFA pipe optimization: Evaluation order +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b, $c) { + var_dump($a, $b, $c); + } + function lhs() { + echo __FUNCTION__, "\n"; + return 0; + } + function arg1() { + echo __FUNCTION__, "\n"; + return 1; + } + function arg2() { + echo __FUNCTION__, "\n"; + return 2; + } +} + +lhs() |> foo(arg1(), ?, arg2()); + +?> +--EXPECTF-- +$_main: + ; (lines=21, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %spipe_optimization_009.php:1-24 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0008 +0004 DECLARE_FUNCTION string("foo") 0 +0005 DECLARE_FUNCTION string("lhs") 1 +0006 DECLARE_FUNCTION string("arg1") 2 +0007 DECLARE_FUNCTION string("arg2") 3 +0008 INIT_FCALL_BY_NAME 0 string("lhs") +0009 V1 = DO_FCALL_BY_NAME +0010 T0 = QM_ASSIGN V1 +0011 INIT_FCALL_BY_NAME 3 string("foo") +0012 INIT_FCALL_BY_NAME 0 string("arg1") +0013 V1 = DO_FCALL_BY_NAME +0014 SEND_VAR_NO_REF_EX V1 1 +0015 SEND_VAL_EX T0 2 +0016 INIT_FCALL_BY_NAME 0 string("arg2") +0017 V0 = DO_FCALL_BY_NAME +0018 SEND_VAR_NO_REF_EX V0 3 +0019 DO_FCALL_BY_NAME +0020 RETURN int(1) +LIVE RANGES: + 0: 0011 - 0015 (tmp/var) + +foo: + ; (lines=9, args=3, vars=3, tmps=0) + ; (after optimizer) + ; %spipe_optimization_009.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 CV2($c) = RECV 3 +0003 INIT_FCALL 3 %d string("var_dump") +0004 SEND_VAR CV0($a) 1 +0005 SEND_VAR CV1($b) 2 +0006 SEND_VAR CV2($c) 3 +0007 DO_ICALL +0008 RETURN null + +lhs: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %spipe_optimization_009.php:7-10 +0000 ECHO string("lhs\n") +0001 RETURN int(0) + +arg1: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %spipe_optimization_009.php:11-14 +0000 ECHO string("arg1\n") +0001 RETURN int(1) + +arg2: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %spipe_optimization_009.php:15-18 +0000 ECHO string("arg2\n") +0001 RETURN int(2) +lhs +arg1 +arg2 +int(1) +int(0) +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_010.phpt b/Zend/tests/partial_application/pipe_optimization_010.phpt new file mode 100644 index 0000000000000..60202e72cfd1d --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_010.phpt @@ -0,0 +1,58 @@ +--TEST-- +PFA pipe optimization: References +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo(&$a, $b) { + var_dump($a, $b); + $a = 2; + } +} + +1 |> foo($a, ?); +var_dump($a); + +?> +--EXPECTF-- +$_main: + ; (lines=13, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %spipe_optimization_010.php:1-14 +0000 INIT_FCALL 0 %d string("time") +0001 V2 = DO_ICALL +0002 T1 = IS_SMALLER int(0) V2 +0003 JMPZ T1 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 2 string("foo") +0006 SEND_VAR_EX CV0($a) 1 +0007 SEND_VAL_EX int(1) 2 +0008 DO_FCALL_BY_NAME +0009 INIT_FCALL 1 %d string("var_dump") +0010 SEND_VAR CV0($a) 1 +0011 DO_ICALL +0012 RETURN int(1) + +foo: + ; (lines=8, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %spipe_optimization_010.php:4-7 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 ASSIGN CV0($a) int(2) +0007 RETURN null +NULL +int(1) +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_011.phpt b/Zend/tests/partial_application/pipe_optimization_011.phpt new file mode 100644 index 0000000000000..1a39e4ff2f0d6 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_011.phpt @@ -0,0 +1,110 @@ +--TEST-- +PFA pipe optimization: Evaluation order +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b, $c) { + var_dump($a, $b, $c); + } + function lhs() { + echo __FUNCTION__, "\n"; + return 0; + } + function arg1() { + global $a; + $a = 2; + echo __FUNCTION__, "\n"; + return 1; + } + function arg2() { + global $a; + $a = 3; + echo __FUNCTION__, "\n"; + return 2; + } +} + +$a = 0; +$a |> foo(arg1(), ?, arg2()); + +?> +--EXPECTF-- +$_main: + ; (lines=20, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %spipe_optimization_011.php:1-29 +0000 INIT_FCALL 0 %d string("time") +0001 V2 = DO_ICALL +0002 T1 = IS_SMALLER int(0) V2 +0003 JMPZ T1 0008 +0004 DECLARE_FUNCTION string("foo") 0 +0005 DECLARE_FUNCTION string("lhs") 1 +0006 DECLARE_FUNCTION string("arg1") 2 +0007 DECLARE_FUNCTION string("arg2") 3 +0008 ASSIGN CV0($a) int(0) +0009 T1 = QM_ASSIGN CV0($a) +0010 INIT_FCALL_BY_NAME 3 string("foo") +0011 INIT_FCALL_BY_NAME 0 string("arg1") +0012 V2 = DO_FCALL_BY_NAME +0013 SEND_VAR_NO_REF_EX V2 1 +0014 SEND_VAL_EX T1 2 +0015 INIT_FCALL_BY_NAME 0 string("arg2") +0016 V1 = DO_FCALL_BY_NAME +0017 SEND_VAR_NO_REF_EX V1 3 +0018 DO_FCALL_BY_NAME +0019 RETURN int(1) +LIVE RANGES: + 1: 0010 - 0014 (tmp/var) + +foo: + ; (lines=9, args=3, vars=3, tmps=0) + ; (after optimizer) + ; %spipe_optimization_011.php:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 CV2($c) = RECV 3 +0003 INIT_FCALL 3 %d string("var_dump") +0004 SEND_VAR CV0($a) 1 +0005 SEND_VAR CV1($b) 2 +0006 SEND_VAR CV2($c) 3 +0007 DO_ICALL +0008 RETURN null + +lhs: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %spipe_optimization_011.php:7-10 +0000 ECHO string("lhs\n") +0001 RETURN int(0) + +arg1: + ; (lines=4, args=0, vars=1, tmps=0) + ; (after optimizer) + ; %spipe_optimization_011.php:11-16 +0000 BIND_GLOBAL CV0($a) string("a") +0001 ASSIGN CV0($a) int(2) +0002 ECHO string("arg1\n") +0003 RETURN int(1) + +arg2: + ; (lines=4, args=0, vars=1, tmps=0) + ; (after optimizer) + ; %spipe_optimization_011.php:17-22 +0000 BIND_GLOBAL CV0($a) string("a") +0001 ASSIGN CV0($a) int(3) +0002 ECHO string("arg2\n") +0003 RETURN int(2) +arg1 +arg2 +int(1) +int(0) +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_012.phpt b/Zend/tests/partial_application/pipe_optimization_012.phpt new file mode 100644 index 0000000000000..fef48ba1cd3f9 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_012.phpt @@ -0,0 +1,52 @@ +--TEST-- +PFA optimization: PFA with named args and placeholders can be optimized +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b) { + var_dump($a, $b); + } +} + +1 |> foo(?, b: 2); + +?> +--EXPECTF-- +$_main: + ; (lines=11, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %s:1-12 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 1 string("foo") +0006 SEND_VAL_EX int(1) 1 +0007 SEND_VAL_EX int(2) string("b") +0008 CHECK_UNDEF_ARGS +0009 DO_FCALL_BY_NAME +0010 RETURN int(1) + +foo: + ; (lines=7, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %s:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 RETURN null +int(1) +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_013.phpt b/Zend/tests/partial_application/pipe_optimization_013.phpt new file mode 100644 index 0000000000000..164562fdd0b40 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_013.phpt @@ -0,0 +1,87 @@ +--TEST-- +PFA optimization: PFA with named args and a variadic placeholder can not be optimized +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b) { + var_dump($a, $b); + } +} + +1 |> foo(b: 2, ...); + +?> +--EXPECTF-- +$_main: + ; (lines=12, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %s:1-12 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 0 string("foo") +0006 SEND_VAL_EX int(2) string("b") +0007 T0 = CALLABLE_CONVERT_PARTIAL 3 +0008 INIT_DYNAMIC_CALL 1 T0 +0009 SEND_VAL_EX int(1) 1 +0010 DO_FCALL +0011 RETURN int(1) + +foo: + ; (lines=7, args=2, vars=2, tmps=0) + ; (after optimizer) + ; %s:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV 2 +0002 INIT_FCALL 2 %d string("var_dump") +0003 SEND_VAR CV0($a) 1 +0004 SEND_VAR CV1($b) 2 +0005 DO_ICALL +0006 RETURN null + +$_main: + ; (lines=4, args=0, vars=1, tmps=1) + ; (after optimizer) + ; %s:1-9 +0000 T1 = DECLARE_LAMBDA_FUNCTION 0 +0001 BIND_LEXICAL T1 CV0($b) +0002 FREE T1 +0003 RETURN int(1) +LIVE RANGES: + 1: 0001 - 0002 (tmp/var) + +{closure:pfa:%s:9}: + ; (lines=18, args=1, vars=2, tmps=2) + ; (after optimizer) + ; %s:9-9 +0000 CV0($a) = RECV 1 +0001 BIND_STATIC CV1($b) +0002 T3 = FUNC_NUM_ARGS +0003 T2 = IS_SMALLER_OR_EQUAL T3 int(1) +0004 JMPZ T2 0010 +0005 INIT_FCALL 2 %d string("foo") +0006 SEND_VAR CV0($a) 1 +0007 SEND_VAR CV1($b) 2 +0008 V2 = DO_UCALL +0009 RETURN V2 +0010 INIT_FCALL 2 %d string("foo") +0011 SEND_VAR CV0($a) 1 +0012 SEND_VAR CV1($b) 2 +0013 T2 = FUNC_GET_ARGS int(1) +0014 SEND_UNPACK T2 +0015 CHECK_UNDEF_ARGS +0016 V2 = DO_UCALL +0017 RETURN V2 +int(1) +int(2) diff --git a/Zend/tests/partial_application/pipe_optimization_014.phpt b/Zend/tests/partial_application/pipe_optimization_014.phpt new file mode 100644 index 0000000000000..a1390bc551032 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_014.phpt @@ -0,0 +1,68 @@ +--TEST-- +PFA pipe optimization: PFA with unknown named parameter can be optimized +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b = null, $c = null) { + var_dump($a, $b, $c); + } +} + +try { + 2 |> foo(1, unknown: ?); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +$_main: + ; (lines=20, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %s:1-16 +0000 INIT_FCALL 0 %d string("time") +0001 V2 = DO_ICALL +0002 T1 = IS_SMALLER int(0) V2 +0003 JMPZ T1 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 1 string("foo") +0006 SEND_VAL_EX int(1) 1 +0007 SEND_VAL_EX int(2) string("unknown") +0008 CHECK_UNDEF_ARGS +0009 DO_FCALL_BY_NAME +0010 RETURN int(1) +0011 CV0($e) = CATCH string("Error") +0012 T1 = FETCH_CLASS_NAME CV0($e) +0013 ECHO T1 +0014 ECHO string(": ") +0015 INIT_METHOD_CALL 0 CV0($e) string("getMessage") +0016 V1 = DO_FCALL +0017 ECHO V1 +0018 ECHO string("\n") +0019 RETURN int(1) +EXCEPTION TABLE: + 0005, 0011, -, - + +foo: + ; (lines=9, args=3, vars=3, tmps=0) + ; (after optimizer) + ; %s:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV_INIT 2 null +0002 CV2($c) = RECV_INIT 3 null +0003 INIT_FCALL 3 %d string("var_dump") +0004 SEND_VAR CV0($a) 1 +0005 SEND_VAR CV1($b) 2 +0006 SEND_VAR CV2($c) 3 +0007 DO_ICALL +0008 RETURN null +Error: Unknown named parameter $unknown diff --git a/Zend/tests/partial_application/pipe_optimization_015.phpt b/Zend/tests/partial_application/pipe_optimization_015.phpt new file mode 100644 index 0000000000000..66507bfa955a7 --- /dev/null +++ b/Zend/tests/partial_application/pipe_optimization_015.phpt @@ -0,0 +1,55 @@ +--TEST-- +PFA pipe optimization: PFA with skipped optional parameter can be optimized +--EXTENSIONS-- +opcache +--INI-- +opcache.opt_debug_level=0x20000 +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_cache= +opcache.file_cache_only=0 +--FILE-- + 0) { + function foo($a, $b = null, $c = null) { + var_dump($a, $b, $c); + } +} + +3 |> foo(1, c: ?); + +?> +--EXPECTF-- +$_main: + ; (lines=11, args=0, vars=0, tmps=2) + ; (after optimizer) + ; %s:1-12 +0000 INIT_FCALL 0 %d string("time") +0001 V1 = DO_ICALL +0002 T0 = IS_SMALLER int(0) V1 +0003 JMPZ T0 0005 +0004 DECLARE_FUNCTION string("foo") 0 +0005 INIT_FCALL_BY_NAME 1 string("foo") +0006 SEND_VAL_EX int(1) 1 +0007 SEND_VAL_EX int(3) string("c") +0008 CHECK_UNDEF_ARGS +0009 DO_FCALL_BY_NAME +0010 RETURN int(1) + +foo: + ; (lines=9, args=3, vars=3, tmps=0) + ; (after optimizer) + ; %s:4-6 +0000 CV0($a) = RECV 1 +0001 CV1($b) = RECV_INIT 2 null +0002 CV2($c) = RECV_INIT 3 null +0003 INIT_FCALL 3 %d string("var_dump") +0004 SEND_VAR CV0($a) 1 +0005 SEND_VAR CV1($b) 2 +0006 SEND_VAR CV2($c) 3 +0007 DO_ICALL +0008 RETURN null +int(1) +NULL +int(3) diff --git a/Zend/tests/partial_application/preloading.inc b/Zend/tests/partial_application/preloading.inc new file mode 100644 index 0000000000000..885ed0c5b0f18 --- /dev/null +++ b/Zend/tests/partial_application/preloading.inc @@ -0,0 +1,13 @@ + diff --git a/Zend/tests/partial_application/preloading.phpt b/Zend/tests/partial_application/preloading.phpt new file mode 100644 index 0000000000000..23ad6edf2c4cb --- /dev/null +++ b/Zend/tests/partial_application/preloading.phpt @@ -0,0 +1,19 @@ +--TEST-- +PFA preloading +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.preload={PWD}/preloading.inc +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(2) +int(2) diff --git a/Zend/tests/partial_application/rebinding_001.phpt b/Zend/tests/partial_application/rebinding_001.phpt new file mode 100644 index 0000000000000..d1913957a8c90 --- /dev/null +++ b/Zend/tests/partial_application/rebinding_001.phpt @@ -0,0 +1,59 @@ +--TEST-- +PFA can only be rebound to an instanceof $this +--FILE-- +f(?); +$g = $c->g(?); + +echo "# Can be rebound to \$this of the same class:\n"; +$f->bindTo(new C)(1); + +echo "# Can be rebound to \$this of a sub-class:\n"; +$f->bindTo(new SubClass)(1); + +echo "# Cannot be rebound to an unrelated class:\n"; +try { + $f->bindTo(new Unrelated)(1); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +echo "# Cannot unbind \$this on instance method:\n"; +try { + $f->bindTo(null)(1); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +echo "# Can unbind \$this on static method:\n"; +$g->bindTo(null)(1); + +?> +--EXPECTF-- +# Can be rebound to $this of the same class: +object(C)#%d (0) { +} +# Can be rebound to $this of a sub-class: +object(SubClass)#%d (0) { +} +# Cannot be rebound to an unrelated class: + +Warning: Cannot bind method C::{closure:%s:%d}() to object of class Unrelated, this will be an error in PHP 9 in %s on line %d +Error: Value of type null is not callable +# Cannot unbind $this on instance method: + +Warning: Cannot unbind $this of method, this will be an error in PHP 9 in %s on line %d +Error: Value of type null is not callable +# Can unbind $this on static method: +string(1) "C" diff --git a/Zend/tests/partial_application/rebinding_002.phpt b/Zend/tests/partial_application/rebinding_002.phpt new file mode 100644 index 0000000000000..fca6db08500f2 --- /dev/null +++ b/Zend/tests/partial_application/rebinding_002.phpt @@ -0,0 +1,45 @@ +--TEST-- +PFA scope cannot be rebound +--FILE-- +f(?); +$g = g(?); + +echo "# Can be rebound to the same scope:\n"; +$f->bindTo($c, C::class)(1); + +echo "# Method cannot be rebound to a different scope:\n"; +try { + $f->bindTo($c, SubClass::class)(1); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +echo "# Function cannot be refound to a different scope:\n"; +try { + $g->bindTo($c, SubClass::class)(1); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECTF-- +# Can be rebound to the same scope: +string(1) "C" +# Method cannot be rebound to a different scope: + +Warning: Cannot rebind scope of closure created from method, this will be an error in PHP 9 in %s on line %d +Value of type null is not callable +# Function cannot be refound to a different scope: + +Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in %s on line %d +Value of type null is not callable diff --git a/Zend/tests/partial_application/rebinding_003.phpt b/Zend/tests/partial_application/rebinding_003.phpt new file mode 100644 index 0000000000000..7b8a29231c32c --- /dev/null +++ b/Zend/tests/partial_application/rebinding_003.phpt @@ -0,0 +1,65 @@ +--TEST-- +Rebinding PFA of Closure rebinds inner Closure +--FILE-- +f(?); +$g = $c->g(?); + +echo "# Can be rebound to \$this of the same class:\n"; +$f->bindTo(new C)($c); + +echo "# Can be rebound to \$this of a sub-class:\n"; +$f->bindTo(new SubClass)($c); + +echo "# Cannot be rebound to an unrelated class:\n"; +try { + $f->bindTo(new Unrelated)($c); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +echo "# Cannot unbind \$this on instance method:\n"; +try { + $f->bindTo(null)($c); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +echo "# Can unbind \$this on static method:\n"; +try { + $g->bindTo(null)($c); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +# Can be rebound to $this of the same class: +object(C)#%d (0) { +} +bool(false) +# Can be rebound to $this of a sub-class: +object(SubClass)#%d (0) { +} +bool(false) +# Cannot be rebound to an unrelated class: + +Warning: Cannot bind method C::{closure:%s:%d}() to object of class Unrelated, this will be an error in PHP 9 in %s on line %d +Value of type null is not callable +# Cannot unbind $this on instance method: + +Warning: Cannot unbind $this of method, this will be an error in PHP 9 in %s on line %d +Value of type null is not callable +# Can unbind $this on static method: +string(1) "C" diff --git a/Zend/tests/partial_application/recorded_warnings.phpt b/Zend/tests/partial_application/recorded_warnings.phpt new file mode 100644 index 0000000000000..f25be826f5250 --- /dev/null +++ b/Zend/tests/partial_application/recorded_warnings.phpt @@ -0,0 +1,14 @@ +--TEST-- +PFA compilation warnings are recorded and replayed +--FILE-- + +--EXPECTF-- +Deprecated: Using "_" as a type name is deprecated since 8.4 in %s on line 3 + +Deprecated: Using "_" as a type name is deprecated since 8.4 in %s on line 5 diff --git a/Zend/tests/partial_application/references_001.phpt b/Zend/tests/partial_application/references_001.phpt new file mode 100644 index 0000000000000..080b3085acc07 --- /dev/null +++ b/Zend/tests/partial_application/references_001.phpt @@ -0,0 +1,24 @@ +--TEST-- +PFA receives by val if the actual function does +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + &string(49) "unchanged because foo() doesn't take by reference" +} +string(49) "unchanged because foo() doesn't take by reference" diff --git a/Zend/tests/partial_application/references_002.phpt b/Zend/tests/partial_application/references_002.phpt new file mode 100644 index 0000000000000..42a90648c1ae8 --- /dev/null +++ b/Zend/tests/partial_application/references_002.phpt @@ -0,0 +1,24 @@ +--TEST-- +PFA receives by ref if the actual function does +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + &int(2) +} +int(2) diff --git a/Zend/tests/partial_application/references_003.phpt b/Zend/tests/partial_application/references_003.phpt new file mode 100644 index 0000000000000..be116b06c79f5 --- /dev/null +++ b/Zend/tests/partial_application/references_003.phpt @@ -0,0 +1,20 @@ +--TEST-- +PFA receives by ref if the actual function does +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECTF-- +{closure:%s}(): Argument #1 ($b) could not be passed by reference diff --git a/Zend/tests/partial_application/references_004.phpt b/Zend/tests/partial_application/references_004.phpt new file mode 100644 index 0000000000000..8ef3ff002ce7d --- /dev/null +++ b/Zend/tests/partial_application/references_004.phpt @@ -0,0 +1,42 @@ +--TEST-- +PFA receives variadic param by ref if the actual function does +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %sreferences_004.php 13 - 13 + + - Bound Variables [2] { + Variable #0 [ $a ] + Variable #1 [ $args1 ] + } + + - Parameters [2] { + Parameter #0 [ &$args0 ] + Parameter #1 [ &...$args ] + } +} + +int(-2) +int(-3) +int(-4) diff --git a/Zend/tests/partial_application/references_005.phpt b/Zend/tests/partial_application/references_005.phpt new file mode 100644 index 0000000000000..e8c7c27a07be6 --- /dev/null +++ b/Zend/tests/partial_application/references_005.phpt @@ -0,0 +1,26 @@ +--TEST-- +PFA inherits return by ref +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + int(1) +} +array(1) { + [0]=> + int(1) +} diff --git a/Zend/tests/partial_application/reflection_001.phpt b/Zend/tests/partial_application/reflection_001.phpt new file mode 100644 index 0000000000000..4ee997f562db1 --- /dev/null +++ b/Zend/tests/partial_application/reflection_001.phpt @@ -0,0 +1,48 @@ +--TEST-- +PFA reflection: required parameters +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %sreflection_001.php 6 - 6 + + - Parameters [3] { + Parameter #0 [ $a = 1 ] + Parameter #1 [ $b = 5 ] + Parameter #2 [ $c = 10 ] + } +} +Closure [ static function {closure:%s:%d} ] { + @@ %sreflection_001.php 10 - 10 + + - Parameters [3] { + Parameter #0 [ $a = 1 ] + Parameter #1 [ $b = 5 ] + Parameter #2 [ $c = 10 ] + } +} +Closure [ static function {closure:%s:%d} ] { + @@ %sreflection_001.php 14 - 14 + + - Parameters [3] { + Parameter #0 [ $a = 1 ] + Parameter #1 [ $b = 5 ] + Parameter #2 [ $c = 10 ] + } +} diff --git a/Zend/tests/partial_application/reflection_002.phpt b/Zend/tests/partial_application/reflection_002.phpt new file mode 100644 index 0000000000000..da91a7af50cfe --- /dev/null +++ b/Zend/tests/partial_application/reflection_002.phpt @@ -0,0 +1,57 @@ +--TEST-- +PFA reflection: variadics +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %s 6 - 6 + + - Parameters [1] { + Parameter #0 [ $a ] + } +} +Closure [ static function {closure:%s:%d} ] { + @@ %s 10 - 10 + + - Parameters [2] { + Parameter #0 [ $a ] + Parameter #1 [ ...$b ] + } +} +Closure [ static function {closure:%s:%d} ] { + @@ %s 14 - 14 + + - Parameters [2] { + Parameter #0 [ $a ] + Parameter #1 [ $b0 ] + } +} +Closure [ static function {closure:%s:%d} ] { + @@ %s 18 - 18 + + - Parameters [3] { + Parameter #0 [ $a ] + Parameter #1 [ $b0 ] + Parameter #2 [ $b1 ] + } +} diff --git a/Zend/tests/partial_application/reflection_003.phpt b/Zend/tests/partial_application/reflection_003.phpt new file mode 100644 index 0000000000000..90506d38a778a --- /dev/null +++ b/Zend/tests/partial_application/reflection_003.phpt @@ -0,0 +1,43 @@ +--TEST-- +PFA reflection: internal with variadics +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %sreflection_003.php 2 - 2 + + - Parameters [1] { + Parameter #0 [ string $format ] + } + - Return [ string ] +} +Closure [ static function {closure:%s:%d} ] { + @@ %sreflection_003.php 6 - 6 + + - Parameters [2] { + Parameter #0 [ string $format ] + Parameter #1 [ mixed ...$values ] + } + - Return [ string ] +} +Closure [ static function {closure:%s:%d} ] { + @@ %sreflection_003.php 10 - 10 + + - Parameters [2] { + Parameter #0 [ string $format ] + Parameter #1 [ mixed $values0 ] + } + - Return [ string ] +} diff --git a/Zend/tests/partial_application/reflection_004.phpt b/Zend/tests/partial_application/reflection_004.phpt new file mode 100644 index 0000000000000..7226383f5afa0 --- /dev/null +++ b/Zend/tests/partial_application/reflection_004.phpt @@ -0,0 +1,16 @@ +--TEST-- +PFA reflection: ReflectionFunction::isAnonymous() is true for partials +--FILE-- +isAnonymous()); + +var_dump((new ReflectionFunction(function () {}))->isAnonymous()); + +var_dump((new ReflectionFunction(sprintf(?)))->isAnonymous()); + +?> +--EXPECT-- +bool(false) +bool(true) +bool(true) diff --git a/Zend/tests/partial_application/reflection_005.phpt b/Zend/tests/partial_application/reflection_005.phpt new file mode 100644 index 0000000000000..be86270c004c9 --- /dev/null +++ b/Zend/tests/partial_application/reflection_005.phpt @@ -0,0 +1,16 @@ +--TEST-- +PFA reflection: ReflectionFunction::isClosure() is true for partials +--FILE-- +isClosure()); + +var_dump((new ReflectionFunction(function () {}))->isClosure()); + +var_dump((new ReflectionFunction(sprintf(?)))->isClosure()); + +?> +--EXPECT-- +bool(false) +bool(true) +bool(true) diff --git a/Zend/tests/partial_application/relative_return_types.phpt b/Zend/tests/partial_application/relative_return_types.phpt new file mode 100644 index 0000000000000..f34e1889d394e --- /dev/null +++ b/Zend/tests/partial_application/relative_return_types.phpt @@ -0,0 +1,133 @@ +--TEST-- +PFA supports relative return types +--FILE-- + 0) { + trait T { + public function getSelf(object $o): self { + return $o; + } + public function getStatic(object $o): static { + return $o; + } + } +} + +class C { + use T; +} + +class D extends C { +} + +$c = new C; + +$self = $c->getSelf(?); + +echo (string) new ReflectionFunction($self), "\n"; + +var_dump($self($c)); +var_dump($self(new D)); +try { + $self(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$static = $c->getStatic(?); + +echo (string) new ReflectionFunction($static), "\n"; + +var_dump($static($c)); +var_dump($static(new D)); +try { + $static(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$d = new D; + +$self = $d->getSelf(?); + +echo (string) new ReflectionFunction($self), "\n"; + +var_dump($self($d)); +var_dump($self(new D)); +try { + $self(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$static = $d->getStatic(?); + +echo (string) new ReflectionFunction($static), "\n"; + +var_dump($static($d)); +var_dump($static(new D)); +try { + $static(new stdClass); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +Closure [ public method {closure:%s:%d} ] { + @@ %s.php 23 - 23 + + - Parameters [1] { + Parameter #0 [ object $o ] + } + - Return [ self ] +} + +object(C)#%d (0) { +} +object(D)#%d (0) { +} +C::getSelf(): Return value must be of type C, stdClass returned +Closure [ public method {closure:%s:%d} ] { + @@ %s.php 35 - 35 + + - Parameters [1] { + Parameter #0 [ object $o ] + } + - Return [ static ] +} + +object(C)#%d (0) { +} +object(D)#%d (0) { +} +C::getStatic(): Return value must be of type C, stdClass returned +Closure [ public method {closure:%s:%d} ] { + @@ %s.php 49 - 49 + + - Parameters [1] { + Parameter #0 [ object $o ] + } + - Return [ self ] +} + +object(D)#%d (0) { +} +object(D)#%d (0) { +} +C::getSelf(): Return value must be of type C, stdClass returned +Closure [ public method {closure:%s:%d} ] { + @@ %s.php 61 - 61 + + - Parameters [1] { + Parameter #0 [ object $o ] + } + - Return [ static ] +} + +object(D)#%d (0) { +} +object(D)#%d (0) { +} +C::getStatic(): Return value must be of type D, stdClass returned diff --git a/Zend/tests/partial_application/return_type.phpt b/Zend/tests/partial_application/return_type.phpt new file mode 100644 index 0000000000000..ae3738e2c660c --- /dev/null +++ b/Zend/tests/partial_application/return_type.phpt @@ -0,0 +1,20 @@ +--TEST-- +PFA inherits return type +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %s 4 - 4 + + - Bound Variables [1] { + Variable #0 [ $a ] + } + + - Parameters [0] { + } + - Return [ array ] +} diff --git a/Zend/tests/partial_application/rfc_examples.inc b/Zend/tests/partial_application/rfc_examples.inc new file mode 100644 index 0000000000000..53babc07888b6 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples.inc @@ -0,0 +1,76 @@ + [$pfa, $closure]) { + echo "# ", $test, ": "; + $pfaReflector = new ReflectionFunction($pfa); + $closureReflector = new ReflectionFunction($closure); + + try { + if (count($pfaReflector->getParameters()) !== count($closureReflector->getParameters())) { + throw new Exception(sprintf( + "Arity does not match: expected %d, got %d", + count($closureReflector->getParameters()), + count($pfaReflector->getParameters()), + )); + } + + $it = new MultipleIterator(); + $it->attachIterator(new ArrayIterator($pfaReflector->getParameters())); + $it->attachIterator(new ArrayIterator($closureReflector->getParameters())); + foreach ($it as $i => [$pfaParam, $closureParam]) { + [$i] = $i; + if ($pfaParam->getName() !== $closureParam->getName()) { + throw new Exception(sprintf("Name of param %d does not match: %s vs %s", + $i, + $pfaParam->getName(), + $closureParam->getName(), + )); + } + if ((string)$pfaParam->getType() !== (string)$closureParam->getType()) { + throw new Exception(sprintf("Type of param %d does not match: %s vs %s", + $i, + $pfaParam->getType(), + $closureParam->getType(), + )); + } + if ($pfaParam->isOptional() !== $closureParam->isOptional()) { + throw new Exception(sprintf("Optionalness of param %d does not match: %d vs %d", + $i, + $pfaParam->isOptional(), + $closureParam->isOptional(), + )); + } + } + + $args = []; + foreach ($pfaReflector->getParameters() as $i => $p) { + $args[] = match ((string) $p->getType()) { + 'int' => 100 + $i, + 'float' => 100.5 + $i, + '?float' => 100.5 + $i, + 'string' => (string) (100 + $i), + 'Point' => new Point, + 'mixed' => "mixed($i)", + '' => "mixed($i)", + }; + } + + if ($pfaReflector->getClosureThis() !== $closureReflector->getClosureThis()) { + throw new Exception("\$this differs"); + } + + if ($pfa(...$args) !== $closure(...$args)) { + throw new Exception("PFA is not equivalent to closure"); + } + } catch (Exception $e) { + echo $e->getMessage(), "\n"; + echo $pfaReflector; + echo $closureReflector; + return; + } + + echo "Ok\n"; + } +} diff --git a/Zend/tests/partial_application/rfc_examples_const_expr.phpt b/Zend/tests/partial_application/rfc_examples_const_expr.phpt new file mode 100644 index 0000000000000..e2fc574402565 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_const_expr.phpt @@ -0,0 +1,25 @@ +--TEST-- +PFA RFC examples: "Constant expressions" section +--XFAIL-- +PFA in constant expressions not implemented yet +--FILE-- + +==DONE== +--EXPECTF-- +==DONE== diff --git a/Zend/tests/partial_application/rfc_examples_debug.phpt b/Zend/tests/partial_application/rfc_examples_debug.phpt new file mode 100644 index 0000000000000..9c5501090d4e0 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_debug.phpt @@ -0,0 +1,25 @@ +--TEST-- +PFA RFC examples: "Debug output" section +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Exception in %s:%d +Stack trace: +#0 %s(%d): g() +#1 %s(%d): f(1, Object(SensitiveParameterValue), 3) +#2 %s(%d): {closure:pfa:%s}(1, Object(SensitiveParameterValue)) +#3 {main} + thrown in %s on line %d diff --git a/Zend/tests/partial_application/rfc_examples_errors.phpt b/Zend/tests/partial_application/rfc_examples_errors.phpt new file mode 100644 index 0000000000000..21818d7446e33 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_errors.phpt @@ -0,0 +1,34 @@ +--TEST-- +PFA RFC examples: "Error examples" section +--FILE-- +getMessage(), "\n"; +} + +try { + stuff(?, ?, ?, ?, ?, ?); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +try { + stuff(?, ?, 3.5, $point, i: 5); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +ArgumentCountError: Partial application of stuff() expects at least 4 arguments, 1 given +ArgumentCountError: Partial application of stuff() expects at most 5 arguments, 6 given +Error: Named parameter $i overwrites previous placeholder diff --git a/Zend/tests/partial_application/rfc_examples_eval_order.phpt b/Zend/tests/partial_application/rfc_examples_eval_order.phpt new file mode 100644 index 0000000000000..b54ce0ce15e42 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_eval_order.phpt @@ -0,0 +1,30 @@ +--TEST-- +PFA RFC examples: "Evaluation order" section +--FILE-- + speak($who, getArg()); +print "Arnaud\n"; +$arrow('Larry'); + +$partial = speak(?, getArg()); +print "Arnaud\n"; +$partial('Larry'); + +?> +--EXPECT-- +Arnaud +getArg +Larry: hi +getArg +Arnaud +Larry: hi diff --git a/Zend/tests/partial_application/rfc_examples_extra_args.phpt b/Zend/tests/partial_application/rfc_examples_extra_args.phpt new file mode 100644 index 0000000000000..f6a24df8cc713 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_extra_args.phpt @@ -0,0 +1,54 @@ +--TEST-- +PFA RFC examples: "Variadics, func_get_args(), and extraneous arguments" section +--FILE-- + [ + foo(1, ?), + static function (int $j) { return foo(1, $j); }, + ], + 'If a PFA call has a ... placeholder, then any extraneous arguments will be passed through to the underlying function' => [ + foo(1, ?, ...), + static function (int $j) { return foo(1, $j, ...array_slice(func_get_args(), 1)); }, + ], + 'If a PFA call has a ... placeholder and the underlying function is variadic, then the trailing arguments will be forwarded directly but will get “collected†by the variadic parameter as normal' => [ + foo2(1, ?, ...), + static function (int $j, ...$extra) { return foo2(1, $j, ...$extra); }, + ], +]; + +check_equivalence($tests); + +echo "# The extra parameter here will be passed to the closure object, which will simply ignore it:\n"; +var_dump(foo(1, ?)(4, 'ignore me')); + +echo "# The extra parameter here will be passed to the closure object, which will forward it directly to the underlying function. It will be accessible only via ''func_get_args()'' et al:\n"; +var_dump(foo(1, ?, ...)(4, 'ignore me')); + +echo "# The extra parameter here will be passed to the closure object, which will forward it directly to the underlying function. It will show up as part of the \$extra array:\n"; +var_dump(foo2(1, ?, ...)(4, 'ignore me')); + +?> +==DONE== +--EXPECT-- +# If a PFA call has no ... placeholder, then any extraneous arguments to the resulting closure will be ignored. That is consistent with how manually writing the equivalent closure would behave, and is the same regardless of whether the underlying function is variadic: Ok +# If a PFA call has a ... placeholder, then any extraneous arguments will be passed through to the underlying function: Ok +# If a PFA call has a ... placeholder and the underlying function is variadic, then the trailing arguments will be forwarded directly but will get “collected†by the variadic parameter as normal: Ok +# The extra parameter here will be passed to the closure object, which will simply ignore it: +int(2) +# The extra parameter here will be passed to the closure object, which will forward it directly to the underlying function. It will be accessible only via ''func_get_args()'' et al: +int(3) +# The extra parameter here will be passed to the closure object, which will forward it directly to the underlying function. It will show up as part of the $extra array: +int(3) +==DONE== diff --git a/Zend/tests/partial_application/rfc_examples_incompatible_functions.phpt b/Zend/tests/partial_application/rfc_examples_incompatible_functions.phpt new file mode 100644 index 0000000000000..dd99cb229ae8a --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_incompatible_functions.phpt @@ -0,0 +1,14 @@ +--TEST-- +PFA RFC examples: "Incompatible functions" section +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Error: Cannot call func_get_arg() dynamically diff --git a/Zend/tests/partial_application/rfc_examples_magic_methods.phpt b/Zend/tests/partial_application/rfc_examples_magic_methods.phpt new file mode 100644 index 0000000000000..7162a790c57cc --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_magic_methods.phpt @@ -0,0 +1,47 @@ +--TEST-- +PFA RFC examples: "Magic methods" section +--FILE-- + [ + $f->method(?, ?), + (function ($f) { + return fn(mixed $arguments0, mixed $arguments1) => $f->method($arguments0, $arguments1); + })($f)->bindTo($f), + ], +]); + +try { + $f->method(?, ?)(a: 1, b: 2); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +# Test 1: Foo::method +Array +( + [0] => mixed(0) + [1] => mixed(1) +) +Foo::method +Array +( + [0] => mixed(0) + [1] => mixed(1) +) +Ok +Error: Unknown named parameter $a diff --git a/Zend/tests/partial_application/rfc_examples_overview.phpt b/Zend/tests/partial_application/rfc_examples_overview.phpt new file mode 100644 index 0000000000000..b6fc8c0586c2f --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_overview.phpt @@ -0,0 +1,44 @@ +--TEST-- +PFA RFC examples: "Overview" section +--FILE-- + [ + foo(1, ?, 3, 4), + static fn(int $b): int => foo(1, $b, 3, 4), + ], + 'Test 2' => [ + foo(1, ?, 3, ?), + static fn(int $b, int $d): int => foo(1, $b, 3, $d), + ], + 'Test 3' => [ + foo(1, ...), + static fn(int $b, int $c, int $d): int => foo(1, $b, $c, $d), + ], + 'Test 4' => [ + foo(1, 2, ...), + static fn(int $c, int $d): int => foo(1, 2, $c, $d), + ], + 'Test 5' => [ + foo(1, ?, 3, ...), + static fn(int $b, int $d): int => foo(1, $b, 3, $d), + ], +]; + +check_equivalence($tests); + +?> +--EXPECT-- +# Test 1: Ok +# Test 2: Ok +# Test 3: Ok +# Test 4: Ok +# Test 5: Ok diff --git a/Zend/tests/partial_application/rfc_examples_scoping.phpt b/Zend/tests/partial_application/rfc_examples_scoping.phpt new file mode 100644 index 0000000000000..071b4a5a5a398 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_scoping.phpt @@ -0,0 +1,113 @@ +--TEST-- +PFA RFC examples: "Scoping" section +--FILE-- + [ + foo(?, ?), + static fn(int $i, int $j = 0): string => foo($i, $j), + ], + 'Static closure 2' => [ + Foo::bar(?, ?), + static fn(int $i, int $j): string => Foo::bar($i, $j), + ], + 'Static closure 3' => [ + foo(?, ?)(1, ?), + static fn(int $j = 0): string => foo(1, $j), + ], + 'Static closure 4' => [ + foo(...)(?), + static fn(int $i): string => foo($i, 0), + ], +]; + +check_equivalence($tests); + +$c = new C(); +$f = $c->f(?); + +echo "# Cannot unbind \$this:\n"; +var_dump($f->bindTo(null, C::class)); // Warning: Cannot unbind $this of method, this will be an error in PHP 9 (returns null) + +echo "# Cannot rebind scope:\n"; +var_dump($f->bindTo($c, CSubClass::class)); // Warning: Cannot rebind scope of closure created from method, this will be an error in PHP 9 (returns null) + +echo "# Can rebind \$this with subclass:\n"; +var_dump($f->bindTo(new CSubClass, C::class)); // Allowed + +echo "# Cannot rebind \$this with unrelated class:\n"; +$f = $f->bindTo(new Unrelated, C::class); // Warning: Cannot bind method C::{closure:/path/to/test.php:11}() to object of class Unrelated, this will be an error in PHP 9 (returns null) + +echo "# self resolution:\n"; +$c = new CSubClass(); +var_dump($c->f(?)(1)); // string(1) "C" +var_dump($c->g(?)(1)); // string(9) "CSubClass" +var_dump($c->h(1)(1)); // string(1) "C" + +?> +--EXPECTF-- +# Static closure 1: Ok +# Static closure 2: Ok +# Static closure 3: Ok +# Static closure 4: Ok +# Cannot unbind $this: + +Warning: Cannot unbind $this of method, this will be an error in PHP 9 in %s on line %d +NULL +# Cannot rebind scope: + +Warning: Cannot rebind scope of closure created from method, this will be an error in PHP 9 in %s on line %d +NULL +# Can rebind $this with subclass: +object(Closure)#%d (5) { + ["name"]=> + string(%d) "{closure:pfa:%s}" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(53) + ["this"]=> + object(CSubClass)#%d (0) { + } + ["parameter"]=> + array(1) { + ["$a"]=> + string(10) "" + } +} +# Cannot rebind $this with unrelated class: + +Warning: Cannot bind method C::{closure:pfa:%s}() to object of class Unrelated, this will be an error in PHP 9 in %s on line %d +# self resolution: +string(1) "C" +string(9) "CSubClass" +string(1) "C" diff --git a/Zend/tests/partial_application/rfc_examples_semantics.phpt b/Zend/tests/partial_application/rfc_examples_semantics.phpt new file mode 100644 index 0000000000000..a3ea25c30d6d5 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_semantics.phpt @@ -0,0 +1,30 @@ +--TEST-- +PFA RFC examples: "Placeholder Semantics" section +--FILE-- + [ + foo(?, ?, ?, ?), + static fn(int $a, int $b, string $c0, string $c1) => foo($a, $b, $c0, $c1), + ], + 'Test 2' => [ + stuff(1, ?, p: ?, f: 3.14, ...), + static fn(string $s, Point $p, int $m = 0) => stuff(1, $s, 3.14, $p, $m), + ], +]; + +check_equivalence($tests); + +?> +--EXPECT-- +# Test 1: Ok +# Test 2: Ok diff --git a/Zend/tests/partial_application/rfc_examples_semantics_examples.phpt b/Zend/tests/partial_application/rfc_examples_semantics_examples.phpt new file mode 100644 index 0000000000000..9ee52d2786897 --- /dev/null +++ b/Zend/tests/partial_application/rfc_examples_semantics_examples.phpt @@ -0,0 +1,217 @@ +--TEST-- +PFA RFC examples: "Placeholder Semantics: Examples" section +--FILE-- + [ + stuff(?, ?, ...), + static fn(int $i1, string $s2, float $f3, Point $p4, int $m5 = 0): array + => stuff($i1, $s2, $f3, $p4, $m5), + ], + 'The degenerate "first class callables" case. (Supported since 8.1)' => [ + stuff(...), + static fn(int $i1, string $s2, float $f3, Point $p4, int $m5 = 0): array + => stuff($i1, $s2, $f3, $p4, $m5), + ], + 'Provide some values, require the rest to be provided later (1)' => [ + stuff(1, 'hi', ?, ?, ?), + static fn(float $f3, Point $p4, int $m5 = 0): array => stuff(1, 'hi', $f3, $p4, $m5), + ], + 'Provide some values, require the rest to be provided later (2)' => [ + stuff(1, 'hi', ...), + static fn(float $f3, Point $p4, int $m5 = 0): array => stuff(1, 'hi', $f3, $p4, $m5), + ], + 'Provide some values, but not just from the left (1)' => [ + stuff(1, ?, 3.5, ?, ?), + static fn(string $s2, Point $p4, int $m5 = 0): array => stuff(1, $s2, 3.5, $p4, $m5), + ], + 'Provide some values, but not just from the left (2)' => [ + stuff(1, ?, 3.5, ...), + static fn(string $s2, Point $p4, int $m5 = 0): array => stuff(1, $s2, 3.5, $p4, $m5), + ], + 'Provide just the last value' => [ + stuff(?, ?, ?, ?, 5), + static fn(int $i1, string $s2, float $f3, Point $p4): array + => stuff($i1, $s2, $f3, $p4, 5), + ], + 'Not accounting for an optional argument means it will always get its default value' => [ + stuff(?, ?, ?, ?), + static fn(int $i1, string $s2, float $f3, Point $p4): array + => stuff($i1, $s2, $f3, $p4), + ], + 'Named arguments can be pulled "out of order", and still work (1)' => [ + stuff(?, ?, f3: 3.5, p4: $point), + static fn(int $i1, string $s2): array => stuff($i1, $s2, 3.5, $point), + ], + 'Named arguments can be pulled "out of order", and still work (2)' => [ + stuff(?, ?, p4: $point, f3: 3.5), + static fn(int $i1, string $s2): array => stuff($i1, $s2, 3.5, $point), + ], + + 'But named placeholders adopt the order listed' => [ + stuff(s2: ?, i1: ?, p4: ?, f3: 3.5), + static fn(string $s2, int $i1, Point $p4): array => stuff($i1, $s2, 3.5, $p4), + ], + 'The ... "everything else" placeholder respects named arguments' => [ + stuff(?, ?, f3: 3.5, p4: $point, ...), + static fn(int $i1, string $s2, int $m5 = 0): array => stuff($i1, $s2, 3.5, $point, $m5), + ], + 'Prefill all parameters, making a "delayed call" or "thunk"' => [ + stuff(1, 'hi', 3.4, $point, 5, ...), + static fn(): array => stuff(1, 'hi', 3.4, $point, 5), + ], + + // Variadics + + 'FCC equivalent. The signature is unchanged' => [ + things(...), + static fn(int $i1, ?float $f3 = null, Point ...$points): array => things(...[$i1, $f3, ...$points]), + ], + 'Provide some values, but allow the variadic to remain variadic' => [ + things(1, 3.14, ...), + static fn(Point ...$points): array => things(1, 3.14, ...$points), + ], + 'In this version, the partial requires precisely four arguments, the last two of which will get received by things() in the variadic parameter. Note too that $f becomes required in this case' => [ + things(?, ?, ?, ?), + static fn(int $i1, ?float $f3, Point $points0, Point $points1): array => things($i1, $f3, $points0, $points1), + ], + + // Esoteric examples + + 'Esoteric 1' => [ + four(...), + static fn(int $a, int $b, int $c, int $d): string => four($a, $b, $c, $d), + ], + 'Esoteric 2' => [ + four(1, 2, ...), + static fn(int $c, int $d): string => four(1, 2, $c, $d), + ], + 'Esoteric 3' => [ + four(1, 2, 3, ?), + static fn(int $d): string => four(1, 2, 3, $d), + ], + 'Esoteric 4' => [ + four(1, ?, ?, 4), + static fn(int $b, int $c): string => four(1, $b, $c, 4), + ], + 'Esoteric 5' => [ + four(1, 2, 3, 4, ...), + static fn(): string => four(1, 2, 3, 4, ...array_slice(func_get_args(), 4)), + ], + 'Esoteric 6' => [ + four(d: 4, a: 1, ...), + static fn(int $b, int $c): string => four(1, $b, $c, 4, ...array_slice(func_get_args(), 4)), + ], + 'Esoteric 7' => [ + four(c: ?, d: 4, b: ?, a: 1), + static fn(int $c, int $b): string => four(1, $b, $c, 4, ...array_slice(func_get_args(), 4)), + ], + + // Other callable styles + + 'This is allowed. Note the method is static, thus the partial closure is static' => [ + E::make(1, ?), + static fn(int $y): E => E::make(1, $y), + ], + 'Note the method is non-static, so the partial closure is non-static' => (function () { + $eMaker = E::make(1, ?); + $e = $eMaker(2); + return [ + $e->foo(?, ?, 3), + (function ($e) { + return fn(int $a, int $b): array => $e->foo($a, $b, 3); + })($e)->bindTo($e), + ]; + })(), + '$c can then be further refined' => (function () { + $eMaker = E::make(1, ?); + $e = $eMaker(2); + $c = $e->foo(?, ?, 3); + return [ + $c(1, ?), + (function ($e) { + return fn(int $b): array => $e->foo(1, $b, 3); + })($e)->bindTo($e), + ]; + })(), + 'RunMe' => (function () { + $r = new RunMe(); + return [ + $r(?, 3), + (function ($r) { + return fn(int $a): string => $r($a, 3); + })($r)->bindTo($r), + ]; + })(), +]; + +check_equivalence($tests); + +?> +--EXPECT-- +# Manually specify the first two values, and pull the rest "as is": Ok +# The degenerate "first class callables" case. (Supported since 8.1): Ok +# Provide some values, require the rest to be provided later (1): Ok +# Provide some values, require the rest to be provided later (2): Ok +# Provide some values, but not just from the left (1): Ok +# Provide some values, but not just from the left (2): Ok +# Provide just the last value: Ok +# Not accounting for an optional argument means it will always get its default value: Ok +# Named arguments can be pulled "out of order", and still work (1): Ok +# Named arguments can be pulled "out of order", and still work (2): Ok +# But named placeholders adopt the order listed: Ok +# The ... "everything else" placeholder respects named arguments: Ok +# Prefill all parameters, making a "delayed call" or "thunk": Ok +# FCC equivalent. The signature is unchanged: Ok +# Provide some values, but allow the variadic to remain variadic: Ok +# In this version, the partial requires precisely four arguments, the last two of which will get received by things() in the variadic parameter. Note too that $f becomes required in this case: Ok +# Esoteric 1: Ok +# Esoteric 2: Ok +# Esoteric 3: Ok +# Esoteric 4: Ok +# Esoteric 5: Ok +# Esoteric 6: Ok +# Esoteric 7: Ok +# This is allowed. Note the method is static, thus the partial closure is static: Ok +# Note the method is non-static, so the partial closure is non-static: Ok +# $c can then be further refined: Ok +# RunMe: Ok diff --git a/Zend/tests/partial_application/static_method_001.phpt b/Zend/tests/partial_application/static_method_001.phpt new file mode 100644 index 0000000000000..ce4151441c336 --- /dev/null +++ b/Zend/tests/partial_application/static_method_001.phpt @@ -0,0 +1,18 @@ +--TEST-- +PFA supports static methods +--FILE-- + +--EXPECTF-- +Foo::method diff --git a/Zend/tests/partial_application/statics_001.phpt b/Zend/tests/partial_application/statics_001.phpt new file mode 100644 index 0000000000000..610cddf37b547 --- /dev/null +++ b/Zend/tests/partial_application/statics_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +PFA static variables are shared (001) +--FILE-- + +--EXPECT-- +int(1) +int(2) diff --git a/Zend/tests/partial_application/statics_002.phpt b/Zend/tests/partial_application/statics_002.phpt new file mode 100644 index 0000000000000..4e6cc82b720db --- /dev/null +++ b/Zend/tests/partial_application/statics_002.phpt @@ -0,0 +1,22 @@ +--TEST-- +PFA static variables are shared (002) +--FILE-- + +--EXPECT-- +int(1) +int(2) diff --git a/Zend/tests/partial_application/statics_003.phpt b/Zend/tests/partial_application/statics_003.phpt new file mode 100644 index 0000000000000..04328bf717b8a --- /dev/null +++ b/Zend/tests/partial_application/statics_003.phpt @@ -0,0 +1,25 @@ +--TEST-- +PFA static variables are shared (003) +--FILE-- + +--EXPECT-- +int(1) +int(2) diff --git a/Zend/tests/partial_application/superfluous_args_are_forwarded.phpt b/Zend/tests/partial_application/superfluous_args_are_forwarded.phpt new file mode 100644 index 0000000000000..506092655217e --- /dev/null +++ b/Zend/tests/partial_application/superfluous_args_are_forwarded.phpt @@ -0,0 +1,44 @@ +--TEST-- +PFAs forwards superfluous args iff a variadic placeholder is specified +--FILE-- + +--EXPECT-- +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(1) { + [0]=> + int(1) +} +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} diff --git a/Zend/tests/partial_application/this.phpt b/Zend/tests/partial_application/this.phpt new file mode 100644 index 0000000000000..bda6900bae398 --- /dev/null +++ b/Zend/tests/partial_application/this.phpt @@ -0,0 +1,20 @@ +--TEST-- +PFA $this +--FILE-- +method(new stdClass, ...); + +$baz = $bar(new stdClass, ...); + +var_dump($foo === $baz()); +?> +--EXPECT-- +bool(true) diff --git a/Zend/tests/partial_application/variation_call_001.phpt b/Zend/tests/partial_application/variation_call_001.phpt new file mode 100644 index 0000000000000..b9c1c19ec9c67 --- /dev/null +++ b/Zend/tests/partial_application/variation_call_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +PFA variation: call +--FILE-- +method(?, new Param); + +$closure(1); + +$closure->call(/* newThis: */ new Foo(), 10); +?> +--EXPECT-- +Bar: 1, Param +Foo: 10, Param diff --git a/Zend/tests/partial_application/variation_closure_001.phpt b/Zend/tests/partial_application/variation_closure_001.phpt new file mode 100644 index 0000000000000..d8e463b14c640 --- /dev/null +++ b/Zend/tests/partial_application/variation_closure_001.phpt @@ -0,0 +1,40 @@ +--TEST-- +PFA variation: Closure +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %s 5 - 5 + + - Bound Variables [2] { + Variable #0 [ $fn ] + Variable #1 [ $a ] + } + + - Parameters [1] { + Parameter #0 [ $b ] + } +} +Closure [ static function {closure:pfa:%s:%d} ] { + @@ %s 10 - 10 + + - Bound Variables [2] { + Variable #0 [ $fn2 ] + Variable #1 [ $a ] + } + + - Parameters [1] { + Parameter #0 [ $fn ] + } +} diff --git a/Zend/tests/partial_application/variation_closure_002.phpt b/Zend/tests/partial_application/variation_closure_002.phpt new file mode 100644 index 0000000000000..41abe0aaab0eb --- /dev/null +++ b/Zend/tests/partial_application/variation_closure_002.phpt @@ -0,0 +1,28 @@ +--TEST-- +PFA variation: Closure::__invoke() +--FILE-- +__invoke(1, ?); + +echo (string) new ReflectionFunction($function); + +$function(10); +?> +--EXPECTF-- +Closure [ public method {closure:%s:%d} ] { + @@ %svariation_closure_002.php 6 - 6 + + - Bound Variables [1] { + Variable #0 [ $a ] + } + + - Parameters [1] { + Parameter #0 [ $b ] + } +} +int(1) +int(10) diff --git a/Zend/tests/partial_application/variation_closure_003.phpt b/Zend/tests/partial_application/variation_closure_003.phpt new file mode 100644 index 0000000000000..da567e179853c --- /dev/null +++ b/Zend/tests/partial_application/variation_closure_003.phpt @@ -0,0 +1,46 @@ +--TEST-- +PFA variation: Closure::__invoke() with $this +--FILE-- +bar(); + +$function = $closure->__invoke(1, ?); + +echo (string) new ReflectionFunction($function); + +var_dump($function(10)); +?> +--EXPECTF-- +Closure [ public method {closure:%s:%d} ] { + @@ %svariation_closure_003.php 14 - 14 + + - Bound Variables [1] { + Variable #0 [ $a ] + } + + - Parameters [1] { + Parameter #0 [ $b ] + } +} +array(2) { + [0]=> + object(Foo)#1 (0) { + } + [1]=> + array(2) { + [0]=> + int(1) + [1]=> + int(10) + } +} diff --git a/Zend/tests/partial_application/variation_debug_001.phpt b/Zend/tests/partial_application/variation_debug_001.phpt new file mode 100644 index 0000000000000..d2f6458634e90 --- /dev/null +++ b/Zend/tests/partial_application/variation_debug_001.phpt @@ -0,0 +1,40 @@ +--TEST-- +PFA variation: var_dump(), user function +--FILE-- + +--EXPECTF-- +object(Closure)#%d (5) { + ["name"]=> + string(%d) "{closure:%s}" + ["file"]=> + string(%d) "%svariation_debug_001.php" + ["line"]=> + int(6) + ["static"]=> + array(4) { + ["b"]=> + object(stdClass)#%d (0) { + } + ["c"]=> + int(20) + ["c0"]=> + object(stdClass)#%d (0) { + } + ["extra_named_params"]=> + array(1) { + ["four"]=> + int(4) + } + } + ["parameter"]=> + array(1) { + ["$a"]=> + string(10) "" + } +} diff --git a/Zend/tests/partial_application/variation_debug_002.phpt b/Zend/tests/partial_application/variation_debug_002.phpt new file mode 100644 index 0000000000000..9a1121ed7918f --- /dev/null +++ b/Zend/tests/partial_application/variation_debug_002.phpt @@ -0,0 +1,49 @@ +--TEST-- +PFA variation: var_dump(), internal function +--FILE-- + +--EXPECTF-- +object(Closure)#%d (5) { + ["name"]=> + string(%d) "{closure:%s}" + ["file"]=> + string(%d) "%svariation_debug_002.php" + ["line"]=> + int(2) + ["static"]=> + array(3) { + ["array"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["arrays0"]=> + array(3) { + [0]=> + int(4) + [1]=> + int(5) + [2]=> + int(6) + } + ["extra_named_params"]=> + array(1) { + ["four"]=> + object(stdClass)#%d (0) { + } + } + } + ["parameter"]=> + array(2) { + ["$callback"]=> + string(10) "" + ["$arrays"]=> + string(10) "" + } +} diff --git a/Zend/tests/partial_application/variation_ex_001.phpt b/Zend/tests/partial_application/variation_ex_001.phpt new file mode 100644 index 0000000000000..0f36e90f616d2 --- /dev/null +++ b/Zend/tests/partial_application/variation_ex_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +PFA variation: UAF in cleanup unfinished calls +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +ArgumentCountError: Partial application of {closure:%s:%d}() expects at most 0 arguments, 1 given diff --git a/Zend/tests/partial_application/variation_gc_001.phpt b/Zend/tests/partial_application/variation_gc_001.phpt new file mode 100644 index 0000000000000..887156afc7e1e --- /dev/null +++ b/Zend/tests/partial_application/variation_gc_001.phpt @@ -0,0 +1,19 @@ +--TEST-- +PFA variation: GC (001) +--FILE-- +method = self::__construct(new stdClass, ...); + } +} + +$foo = new Foo(new stdClass); +$foo->bar = $foo; + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/partial_application/variation_gc_002.phpt b/Zend/tests/partial_application/variation_gc_002.phpt new file mode 100644 index 0000000000000..31c721e8e6819 --- /dev/null +++ b/Zend/tests/partial_application/variation_gc_002.phpt @@ -0,0 +1,11 @@ +--TEST-- +PFA variation: GC (002) +--FILE-- +prop = var_dump($obj, ?); + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/partial_application/variation_gc_003.phpt b/Zend/tests/partial_application/variation_gc_003.phpt new file mode 100644 index 0000000000000..23cdaa1c666ff --- /dev/null +++ b/Zend/tests/partial_application/variation_gc_003.phpt @@ -0,0 +1,15 @@ +--TEST-- +PFA variation: GC (003) +--FILE-- +prop = test(?, x: $obj); + +echo "OK"; +?> +--EXPECT-- +OK diff --git a/Zend/tests/partial_application/variation_invoke_001.phpt b/Zend/tests/partial_application/variation_invoke_001.phpt new file mode 100644 index 0000000000000..9285c08da19b9 --- /dev/null +++ b/Zend/tests/partial_application/variation_invoke_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +PFA variation: __invoke() +--FILE-- +__invoke(32)); + +try { + $foo->nothing(); +} catch (Error $ex) { + echo $ex::class, ": ", $ex->getMessage(), "\n"; +} +?> +--EXPECT-- +int(42) +Error: Call to undefined method Closure::nothing() diff --git a/Zend/tests/partial_application/variation_nocall_001.phpt b/Zend/tests/partial_application/variation_nocall_001.phpt new file mode 100644 index 0000000000000..3fbb3ec8d8c32 --- /dev/null +++ b/Zend/tests/partial_application/variation_nocall_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +PFA variation: no call args leak +--FILE-- + +--EXPECT-- +OK diff --git a/Zend/tests/partial_application/variation_nocall_002.phpt b/Zend/tests/partial_application/variation_nocall_002.phpt new file mode 100644 index 0000000000000..cd4823f1bd056 --- /dev/null +++ b/Zend/tests/partial_application/variation_nocall_002.phpt @@ -0,0 +1,30 @@ +--TEST-- +PFA variation: no call, order of destruction +--FILE-- +id, "\n"; + } +} +$foo = new Foo; +$f = $foo->method(?); +$g = $f(?); + +$map = new WeakMap(); +$map[$f] = new Dtor(1); +$map[$g] = new Dtor(2); + +unset($f); +unset($g); + +echo "OK"; +?> +--EXPECT-- +Dtor::__destruct 2 +Dtor::__destruct 1 +OK diff --git a/Zend/tests/partial_application/variation_parent_001.phpt b/Zend/tests/partial_application/variation_parent_001.phpt new file mode 100644 index 0000000000000..6b7545daf2d02 --- /dev/null +++ b/Zend/tests/partial_application/variation_parent_001.phpt @@ -0,0 +1,75 @@ +--TEST-- +PFA variation: parent +--FILE-- +method(10, ...); +$baz = $bar(20, ...); + +var_dump($baz, $baz()); +?> +--EXPECTF-- +object(Closure)#%d (6) { + ["name"]=> + string(%d) "{closure:%s}" + ["file"]=> + string(%d) "%svariation_parent_001.php" + ["line"]=> + int(12) + ["static"]=> + array(2) { + ["fn"]=> + object(Closure)#%d (6) { + ["name"]=> + string(%d) "{closure:%s:%d}" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(11) + ["static"]=> + array(1) { + ["a"]=> + int(10) + } + ["this"]=> + object(Foo)#%d (0) { + } + ["parameter"]=> + array(2) { + ["$b"]=> + string(10) "" + ["$c"]=> + string(10) "" + } + } + ["b"]=> + int(20) + } + ["this"]=> + object(Foo)#%d (0) { + } + ["parameter"]=> + array(1) { + ["$c"]=> + string(10) "" + } +} +object(Closure)#%d (4) { + ["name"]=> + string(25) "{closure:Foo::method():4}" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(4) + ["this"]=> + object(Foo)#%d (0) { + } +} diff --git a/Zend/tests/partial_application/variation_scope_001.phpt b/Zend/tests/partial_application/variation_scope_001.phpt new file mode 100644 index 0000000000000..0dcea0921c436 --- /dev/null +++ b/Zend/tests/partial_application/variation_scope_001.phpt @@ -0,0 +1,18 @@ +--TEST-- +PFA variation: called scope +--FILE-- +method(new stdClass, ...); + +$bar(); +?> +--EXPECT-- +Foo::method diff --git a/Zend/tests/partial_application/variation_strict_001.phpt b/Zend/tests/partial_application/variation_strict_001.phpt new file mode 100644 index 0000000000000..835f6e1380557 --- /dev/null +++ b/Zend/tests/partial_application/variation_strict_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +PFA variation: strict_types declared +--FILE-- +getMessage()); +} +?> +--EXPECTF-- +TypeError: {closure:%s:%d}(): Argument #1 ($int) must be of type int, string given, called in %s on line %d diff --git a/Zend/tests/partial_application/variation_variadics_001.phpt b/Zend/tests/partial_application/variation_variadics_001.phpt new file mode 100644 index 0000000000000..4710ca4d3b993 --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +PFA variation: variadics, user function +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %s 6 - 6 + + - Bound Variables [2] { + Variable #0 [ $a ] + Variable #1 [ $b0 ] + } + + - Parameters [1] { + Parameter #0 [ ...$b ] + } +} +int(10) +int(100) +int(1000) +int(10000) diff --git a/Zend/tests/partial_application/variation_variadics_002.phpt b/Zend/tests/partial_application/variation_variadics_002.phpt new file mode 100644 index 0000000000000..4269dd0e66f0b --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_002.phpt @@ -0,0 +1,25 @@ +--TEST-- +PFA variation: variadics, internal function +--FILE-- + +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %svariation_variadics_002.php 2 - 2 + + - Bound Variables [2] { + Variable #0 [ $format ] + Variable #1 [ $values0 ] + } + + - Parameters [1] { + Parameter #0 [ mixed ...$values ] + } + - Return [ string ] +} +100 1000 10000 diff --git a/Zend/tests/partial_application/variation_variadics_004.phpt b/Zend/tests/partial_application/variation_variadics_004.phpt new file mode 100644 index 0000000000000..228404dc82723 --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_004.phpt @@ -0,0 +1,45 @@ +--TEST-- +PFA variation: variadics and optional args +--FILE-- + +--EXPECT-- +# Bound year, pass day: +2006-01-02 +# Bound month, pass day: +2005-12-02 +# Bound month, bound year, pass day: +2016-12-02 +# Bound month, no args: +2005-12-01 +# Bound month, bound year, no args: +2016-12-01 diff --git a/Zend/tests/partial_application/variation_variadics_006.phpt b/Zend/tests/partial_application/variation_variadics_006.phpt new file mode 100644 index 0000000000000..cda62a2f3bfb6 --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_006.phpt @@ -0,0 +1,17 @@ +--TEST-- +PFA variation: named may overwrite variadic placeholder +--FILE-- + +--EXPECTF-- +array(1) { + [0]=> + string(1) "a" +} diff --git a/Zend/tests/partial_application/variation_variadics_007.phpt b/Zend/tests/partial_application/variation_variadics_007.phpt new file mode 100644 index 0000000000000..9624e05b449b6 --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_007.phpt @@ -0,0 +1,14 @@ +--TEST-- +PFA variation: extra through variadic +--FILE-- + $a + $b)); +?> +--EXPECT-- +int(3) diff --git a/Zend/tests/partial_application/variation_variadics_008.phpt b/Zend/tests/partial_application/variation_variadics_008.phpt new file mode 100644 index 0000000000000..4190bb759e68f --- /dev/null +++ b/Zend/tests/partial_application/variation_variadics_008.phpt @@ -0,0 +1,16 @@ +--TEST-- +PFA variation: variadics wrong signature checked +--FILE-- +getMessage() . PHP_EOL; +} +?> +--EXPECTF-- +Partial application of {closure:%s:%d}() expects at most 1 arguments, 2 given diff --git a/Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn.phpt b/Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn.phpt index 4ef1215461885..d62f8cd158e11 100644 --- a/Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn.phpt +++ b/Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn.phpt @@ -40,10 +40,6 @@ Warning: The float NAN is not representable as an int, cast occurred in %s on li int(0) int(3) int(3) - -Warning: The float-string "1.0E+121" is not representable as an int, cast occurred in %s on line %d int(9223372036854775807) - -Warning: The float-string "1.0E+301" is not representable as an int, cast occurred in %s on line %d int(9223372036854775807) int(0) diff --git a/Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn_32bit.phpt b/Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn_32bit.phpt index 3165d653d0478..23cd2854ba453 100644 --- a/Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn_32bit.phpt +++ b/Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn_32bit.phpt @@ -40,10 +40,6 @@ Warning: The float NAN is not representable as an int, cast occurred in %s on li int(0) int(3) int(3) - -Warning: The float-string "1.0E+121" is not representable as an int, cast occurred in %s on line %d int(2147483647) - -Warning: The float-string "1.0E+301" is not representable as an int, cast occurred in %s on line %d int(2147483647) int(0) diff --git a/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra1.phpt b/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra1.phpt index aacf0dc855190..42b91f4a656dc 100644 --- a/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra1.phpt +++ b/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra1.phpt @@ -14,6 +14,5 @@ var_dump($b | 1); ?> --EXPECTF-- -The float-string "1.0E+4%d" is not representable as an int, cast occurred Implicit conversion from float-string "1.0E+4%d" to int loses precision int(%d) diff --git a/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_arrays.phpt b/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_arrays.phpt index 779e103e6f821..13834e61c7416 100644 --- a/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_arrays.phpt +++ b/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_arrays.phpt @@ -25,8 +25,6 @@ var_dump($array[$string_float]); --EXPECTF-- Warning: The float 1.0E+121 is not representable as an int, cast occurred in %s on line %d int(0) - -Warning: The float-string "1.0E+121" is not representable as an int, cast occurred in %s on line %d bool(true) Warning: The float 1.0E+121 is not representable as an int, cast occurred in %s on line %d diff --git a/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_strings.phpt b/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_strings.phpt index b4651d28ac4b3..284b96eb9233a 100644 --- a/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_strings.phpt +++ b/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_strings.phpt @@ -77,8 +77,6 @@ var_dump($string); --EXPECTF-- Warning: The float 1.0E+121 is not representable as an int, cast occurred in %s on line %d int(0) - -Warning: The float-string "1.0E+121" is not representable as an int, cast occurred in %s on line %d int(9223372036854775807) Attempt to read Float diff --git a/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_strings_32bit.phpt b/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_strings_32bit.phpt index 3ec2c62cacdd4..720614d626931 100644 --- a/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_strings_32bit.phpt +++ b/Zend/tests/type_coercion/float_to_int/warning_float_does_not_fit_zend_long_strings_32bit.phpt @@ -77,8 +77,6 @@ var_dump($string); --EXPECTF-- Warning: The float 1.0E+121 is not representable as an int, cast occurred in %s on line %d int(0) - -Warning: The float-string "1.0E+121" is not representable as an int, cast occurred in %s on line %d int(2147483647) Attempt to read Float diff --git a/Zend/zend.c b/Zend/zend.c index c46c8e9ada86c..d2be69a757690 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1082,7 +1082,6 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ #endif zend_enum_startup(); - zend_closure_startup(); } /* }}} */ @@ -1979,7 +1978,6 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl zend_result ret = SUCCESS; if (op_array) { zend_execute(op_array, retval); - zend_exception_restore(); if (UNEXPECTED(EG(exception))) { if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { zend_user_exception_handler(); diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 0881a169dfa7d..c4d73bf481e88 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -374,7 +374,9 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_unexpected_extra_named_error(void) class_name, space, get_active_function_name()); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic_ex( + const zend_function *function, uint32_t arg_num, + zend_class_entry *error_ce, const char *format, va_list va) { zend_string *func_name; const char *arg_name; @@ -383,8 +385,8 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_en return; } - func_name = get_active_function_or_method_name(); - arg_name = get_active_function_arg_name(arg_num); + func_name = get_function_or_method_name(function); + arg_name = get_function_arg_name(function, arg_num); zend_vspprintf(&message, 0, format, va); zend_throw_error(error_ce, "%s(): Argument #%d%s%s%s %s", @@ -394,8 +396,27 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_en efree(message); zend_string_release(func_name); } + +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va) /* {{{ */ +{ + ZEND_ASSERT(zend_is_executing()); + + const zend_function *function = zend_active_function(); + + zend_argument_error_variadic_ex(function, arg_num, error_ce, format, va); +} /* }}} */ +ZEND_API ZEND_COLD void zend_argument_error_ex(const zend_function *function, + uint32_t arg_num, zend_class_entry *error_ce, const char *format, ...) +{ + va_list va; + + va_start(va, format); + zend_argument_error_variadic_ex(function, arg_num, error_ce, format, va); + va_end(va); +} + ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t arg_num, const char *format, ...) /* {{{ */ { va_list va; @@ -406,6 +427,18 @@ ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t } /* }}} */ +ZEND_API ZEND_COLD void zend_argument_type_error_ex( + const zend_function *function, uint32_t arg_num, + const char *format, ...) +{ + va_list va; + + va_start(va, format); + zend_argument_error_variadic_ex(function, arg_num, + zend_ce_type_error, format, va); + va_end(va); +} + ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format, ...) /* {{{ */ { va_list va; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index c1ccbf13666a5..233e4be6a04a1 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1560,8 +1560,16 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(uint32_t num, ch ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_or_null_error(uint32_t num, char *error); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_unexpected_extra_named_error(void); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va); +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic_ex( + const zend_function *function, uint32_t arg_num, + zend_class_entry *error_ce, const char *format, va_list va); ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t arg_num, const char *format, ...); +ZEND_API ZEND_COLD void zend_argument_error_ex(const zend_function *function, + uint32_t arg_num, zend_class_entry *error_ce, const char *format, ...); ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format, ...); +ZEND_API ZEND_COLD void zend_argument_type_error_ex( + const zend_function *function, uint32_t arg_num, + const char *format, ...); ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format, ...); ZEND_API ZEND_COLD void zend_argument_must_not_be_empty_error(uint32_t arg_num); ZEND_API ZEND_COLD void zend_class_redeclaration_error(int type, const zend_class_entry *old_ce); diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 9774cce39db2b..eb1e1effe0f99 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -54,13 +54,14 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_znode(const znode *node) { return (zend_ast *) ast; } -ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(void) { +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(zend_ast *args) { zend_ast_fcc *ast; ast = zend_ast_alloc(sizeof(zend_ast_fcc)); ast->kind = ZEND_AST_CALLABLE_CONVERT; ast->attr = 0; ast->lineno = CG(zend_lineno); + ast->args = args; ZEND_MAP_PTR_INIT(ast->fptr, NULL); return (zend_ast *) ast; @@ -157,6 +158,12 @@ ZEND_API zend_ast *zend_ast_create_decl( return (zend_ast *) ast; } +static bool zend_ast_is_placeholder_arg(zend_ast *arg) { + return arg->kind == ZEND_AST_PLACEHOLDER_ARG + || (arg->kind == ZEND_AST_NAMED_ARG + && arg->child[1]->kind == ZEND_AST_PLACEHOLDER_ARG); +} + #if ZEND_AST_SPEC ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_0(zend_ast_kind kind) { zend_ast *ast; @@ -400,6 +407,30 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_2(zend_ast_kind kind, zen return ast; } + +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_0(zend_ast_kind kind) { + return zend_ast_create_list(0, kind); +} + +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_1(zend_ast_kind kind, zend_ast *arg) { + zend_ast *list = zend_ast_create_list(1, kind, arg); + + if (zend_ast_is_placeholder_arg(arg)) { + return zend_ast_create_fcc(list); + } + + return list; +} + +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_2(zend_ast_kind kind, zend_ast *arg1, zend_ast *arg2) { + zend_ast *list = zend_ast_create_list(2, kind, arg1, arg2); + + if (zend_ast_is_placeholder_arg(arg1) || zend_ast_is_placeholder_arg(arg2)) { + return zend_ast_create_fcc(list); + } + + return list; +} #else static zend_ast *zend_ast_create_from_va_list(zend_ast_kind kind, zend_ast_attr attr, va_list va) { uint32_t i, children = kind >> ZEND_AST_NUM_CHILDREN_SHIFT; @@ -479,6 +510,41 @@ ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind ki return ast; } + +ZEND_API zend_ast *zend_ast_create_arg_list(uint32_t init_children, zend_ast_kind kind, ...) { + zend_ast *ast; + zend_ast_list *list; + bool has_placeholders = false; + + ast = zend_ast_alloc(zend_ast_list_size(4)); + list = (zend_ast_list *) ast; + list->kind = kind; + list->attr = 0; + list->lineno = CG(zend_lineno); + list->children = 0; + + { + va_list va; + uint32_t i; + va_start(va, kind); + for (i = 0; i < init_children; ++i) { + zend_ast *child = va_arg(va, zend_ast *); + ast = zend_ast_list_add(ast, child); + uint32_t lineno = zend_ast_get_lineno(child); + if (lineno < ast->lineno) { + ast->lineno = lineno; + } + has_placeholders = has_placeholders || zend_ast_is_placeholder_arg(child); + } + va_end(va); + } + + if (has_placeholders) { + return zend_ast_create_fcc(list); + } + + return ast; +} #endif zend_ast *zend_ast_create_concat_op(zend_ast *op0, zend_ast *op1) { @@ -508,6 +574,23 @@ ZEND_ATTRIBUTE_NODISCARD ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zen return (zend_ast *) list; } +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_arg_list_add(zend_ast *list, zend_ast *arg) +{ + if (list->kind == ZEND_AST_CALLABLE_CONVERT) { + zend_ast_fcc *fcc_ast = (zend_ast_fcc*)list; + fcc_ast->args = zend_ast_list_add(fcc_ast->args, arg); + return (zend_ast*)fcc_ast; + } + + ZEND_ASSERT(list->kind == ZEND_AST_ARG_LIST); + + if (zend_ast_is_placeholder_arg(arg)) { + return zend_ast_create_fcc(zend_ast_list_add(list, arg)); + } + + return zend_ast_list_add(list, arg); +} + static zend_result zend_ast_add_array_element(const zval *result, zval *offset, zval *expr) { if (Z_TYPE_P(offset) == IS_UNDEF) { @@ -1056,10 +1139,22 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( { zend_function *fptr; zend_class_entry *called_scope = NULL; + + zend_ast *args_ast = zend_ast_call_get_args(ast); + ZEND_ASSERT(args_ast->kind == ZEND_AST_CALLABLE_CONVERT); + + zend_ast_fcc *fcc_ast = (zend_ast_fcc*)args_ast; + + zend_ast_list *args = zend_ast_get_list(fcc_ast->args); + ZEND_ASSERT(args->children > 0); + if (args->children != 1 || args->child[0]->attr != ZEND_PLACEHOLDER_VARIADIC) { + /* TODO: PFAs */ + zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations"); + return FAILURE; + } + switch (ast->kind) { case ZEND_AST_CALL: { - ZEND_ASSERT(ast->child[1]->kind == ZEND_AST_CALLABLE_CONVERT); - zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast->child[1]; fptr = ZEND_MAP_PTR_GET(fcc_ast->fptr); if (!fptr) { @@ -1084,9 +1179,6 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( break; } case ZEND_AST_STATIC_CALL: { - ZEND_ASSERT(ast->child[2]->kind == ZEND_AST_CALLABLE_CONVERT); - zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast->child[2]; - zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope); if (!ce) { return FAILURE; @@ -1124,12 +1216,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, @@ -1146,6 +1238,7 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( break; } + EMPTY_SWITCH_DEFAULT_CASE() } zend_create_fake_closure(result, fptr, fptr->common.scope, called_scope, NULL); @@ -1243,7 +1336,8 @@ static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast) } else if (ast->kind == ZEND_AST_OP_ARRAY) { size = sizeof(zend_ast_op_array); } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { - size = sizeof(zend_ast_fcc); + zend_ast *args_ast = ((zend_ast_fcc*)ast)->args; + size = sizeof(zend_ast_fcc) + zend_ast_tree_size(args_ast); } else if (zend_ast_is_list(ast)) { uint32_t i; const zend_ast_list *list = zend_ast_get_list(ast); @@ -1320,6 +1414,8 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf) new->lineno = old->lineno; ZEND_MAP_PTR_INIT(new->fptr, ZEND_MAP_PTR(old->fptr)); buf = (void*)((char*)buf + sizeof(zend_ast_fcc)); + new->args = buf; + buf = zend_ast_tree_copy(old->args, buf); } else if (zend_ast_is_decl(ast)) { /* Not implemented. */ ZEND_UNREACHABLE(); @@ -1356,6 +1452,16 @@ ZEND_API zend_ast_ref * ZEND_FASTCALL zend_ast_copy(zend_ast *ast) return ref; } +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_dup(zend_ast *ast) +{ + ZEND_ASSERT(ast != NULL); + + zend_ast *buf = zend_ast_alloc(zend_ast_tree_size(ast)); + zend_ast_tree_copy(ast, buf); + + return buf; +} + ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast) { tail_call: @@ -1403,6 +1509,11 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast) zend_ast_destroy(decl->child[3]); ast = decl->child[4]; goto tail_call; + } else if (EXPECTED(ast->kind == ZEND_AST_CALLABLE_CONVERT)) { + zend_ast_fcc *fcc_ast = (zend_ast_fcc*) ast; + + ast = fcc_ast->args; + goto tail_call; } } @@ -2299,6 +2410,13 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio EMPTY_SWITCH_DEFAULT_CASE(); } break; + case ZEND_AST_PLACEHOLDER_ARG: + if (ast->attr == ZEND_PLACEHOLDER_VARIADIC) { + APPEND_STR("..."); + } else { + APPEND_STR("?"); + } + break; /* 1 child node */ case ZEND_AST_VAR: @@ -2445,9 +2563,11 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio zend_ast_export_ex(str, ast->child[1], 0, indent); smart_str_appendc(str, ')'); break; - case ZEND_AST_CALLABLE_CONVERT: - smart_str_appends(str, "..."); - break; + case ZEND_AST_CALLABLE_CONVERT: { + zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast; + ast = fcc_ast->args; + goto simple_list; + } case ZEND_AST_CLASS_CONST: zend_ast_export_ns_name(str, ast->child[0], 0, indent); smart_str_appends(str, "::"); @@ -2966,3 +3086,15 @@ zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr) return ast; } + +zend_ast * ZEND_FASTCALL zend_ast_call_get_args(zend_ast *ast) +{ + if (ast->kind == ZEND_AST_CALL) { + return ast->child[1]; + } else if (ast->kind == ZEND_AST_STATIC_CALL || ast->kind == ZEND_AST_METHOD_CALL) { + return ast->child[2]; + } + + ZEND_UNREACHABLE(); + return NULL; +} diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index fb48b187252b3..33a43f536821a 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -76,6 +76,7 @@ enum _zend_ast_kind { ZEND_AST_TYPE, ZEND_AST_CONSTANT_CLASS, ZEND_AST_CALLABLE_CONVERT, + ZEND_AST_PLACEHOLDER_ARG, /* 1 child node */ ZEND_AST_VAR = 1 << ZEND_AST_NUM_CHILDREN_SHIFT, @@ -229,10 +230,12 @@ typedef struct _zend_ast_decl { zend_ast *child[5]; } zend_ast_decl; +// TODO: rename typedef struct _zend_ast_fcc { zend_ast_kind kind; /* Type of the node (ZEND_AST_* enum constant) */ zend_ast_attr attr; /* Additional attribute, use depending on node type */ uint32_t lineno; /* Line number */ + zend_ast *args; ZEND_MAP_PTR_DEF(zend_function *, fptr); } zend_ast_fcc; @@ -307,27 +310,39 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_0(zend_ast_kind kind); ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_1(zend_ast_kind kind, zend_ast *child); ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2); +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_0(zend_ast_kind kind); +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_1(zend_ast_kind kind, zend_ast *child); +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2); + # define zend_ast_create(...) \ ZEND_AST_SPEC_CALL(zend_ast_create, __VA_ARGS__) # define zend_ast_create_ex(...) \ ZEND_AST_SPEC_CALL_EX(zend_ast_create_ex, __VA_ARGS__) # define zend_ast_create_list(init_children, ...) \ ZEND_AST_SPEC_CALL(zend_ast_create_list, __VA_ARGS__) +# define zend_ast_create_arg_list(init_children, ...) \ + ZEND_AST_SPEC_CALL(zend_ast_create_arg_list, __VA_ARGS__) #else ZEND_API zend_ast *zend_ast_create(zend_ast_kind kind, ...); ZEND_API zend_ast *zend_ast_create_ex(zend_ast_kind kind, zend_ast_attr attr, ...); ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind kind, ...); +ZEND_API zend_ast *zend_ast_create_arg_list(uint32_t init_children, zend_ast_kind kind, ...); #endif ZEND_ATTRIBUTE_NODISCARD ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zend_ast *list, zend_ast *op); +/* Like zend_ast_list_add(), but wraps the list into a ZEND_AST_CALLABLE_CONVERT + * if any arg is a ZEND_AST_PLACEHOLDER_ARG. list can be a zend_ast_list, or a + * zend_ast_fcc. */ +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_arg_list_add(zend_ast *list, zend_ast *arg); + ZEND_API zend_ast *zend_ast_create_decl( zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment, zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4 ); -ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(void); +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(zend_ast *args); typedef struct { bool had_side_effects; @@ -338,6 +353,7 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex(zval *result, zend_ast * ZEND_API zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix); ZEND_API zend_ast_ref * ZEND_FASTCALL zend_ast_copy(zend_ast *ast); +ZEND_API zend_ast * ZEND_FASTCALL zend_ast_dup(zend_ast *ast); ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast); ZEND_API void ZEND_FASTCALL zend_ast_ref_destroy(zend_ast_ref *ast); @@ -425,4 +441,6 @@ static zend_always_inline zend_ast *zend_ast_list_rtrim(zend_ast *ast) { zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr); +zend_ast * ZEND_FASTCALL zend_ast_call_get_args(zend_ast *ast); + #endif diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 05b6862044816..1fdebb06db183 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -28,6 +28,14 @@ #include "zend_globals.h" #include "zend_closures_arginfo.h" +/* Closure is a PFA */ +#define ZEND_PARTIAL OBJ_EXTRA_FLAG_PRIV_1 +/* Closure is a PFA of a Closure. Rebinding the PFA requires rebinding the inner Closure. */ +#define ZEND_PARTIAL_OF_CLOSURE OBJ_EXTRA_FLAG_PRIV_2 + +#define ZEND_CLOSURE_FLAGS(closure) ((closure)->std.extra_flags & (ZEND_PARTIAL|ZEND_PARTIAL_OF_CLOSURE)) +#define ZEND_CLOSURE_IS_FAKE(closure) ((closure)->func.common.fn_flags & ZEND_ACC_FAKE_CLOSURE) + typedef struct _zend_closure { zend_object std; zend_function func; @@ -41,6 +49,7 @@ ZEND_API zend_class_entry *zend_ce_closure; static zend_object_handlers closure_handlers; static zend_result zend_closure_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only); +static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool is_fake, uint32_t flags); ZEND_METHOD(Closure, __invoke) /* {{{ */ { @@ -78,7 +87,9 @@ static bool zend_valid_closure_binding( zend_closure *closure, zval *newthis, zend_class_entry *scope) /* {{{ */ { zend_function *func = &closure->func; - bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0; + // TODO: rename variable + bool is_fake_closure = (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0 + || (closure->std.extra_flags & ZEND_PARTIAL); if (newthis) { if (func->common.fn_flags & ZEND_ACC_STATIC) { zend_error(E_WARNING, "Cannot bind an instance to a static closure, this will be an error in PHP 9"); @@ -161,7 +172,9 @@ ZEND_METHOD(Closure, call) if (closure->func.common.fn_flags & ZEND_ACC_GENERATOR) { zval new_closure; - zend_create_closure(&new_closure, &closure->func, newclass, closure->called_scope, newthis); + zend_create_closure_ex(&new_closure, &closure->func, newclass, + closure->called_scope, newthis, + ZEND_CLOSURE_IS_FAKE(closure), ZEND_CLOSURE_FLAGS(closure)); closure = (zend_closure *) Z_OBJ(new_closure); fci_cache.function_handler = &closure->func; @@ -177,6 +190,7 @@ ZEND_METHOD(Closure, call) memset(&fake_closure->std, 0, sizeof(fake_closure->std)); fake_closure->std.gc.refcount = 1; fake_closure->std.gc.u.type_info = GC_NULL; + fake_closure->std.extra_flags = ZEND_CLOSURE_FLAGS(closure); ZVAL_UNDEF(&fake_closure->this_ptr); fake_closure->called_scope = NULL; my_function = &fake_closure->func; @@ -223,7 +237,7 @@ ZEND_METHOD(Closure, call) } /* }}} */ -static void do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, zend_object *scope_obj, zend_string *scope_str) +static zend_result do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, zend_object *scope_obj, zend_string *scope_str) { zend_class_entry *ce, *called_scope; zend_closure *closure = (zend_closure *) Z_OBJ_P(zclosure); @@ -235,14 +249,15 @@ static void do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, z ce = closure->func.common.scope; } else if ((ce = zend_lookup_class(scope_str)) == NULL) { zend_error(E_WARNING, "Class \"%s\" not found", ZSTR_VAL(scope_str)); - RETURN_NULL(); + RETVAL_NULL(); + return FAILURE; } } else { ce = NULL; } if (!zend_valid_closure_binding(closure, newthis, ce)) { - return; + return FAILURE; } if (newthis) { @@ -251,7 +266,31 @@ static void do_closure_bind(zval *return_value, zval *zclosure, zval *newthis, z called_scope = ce; } - zend_create_closure(return_value, &closure->func, ce, called_scope, newthis); + zend_create_closure_ex(return_value, &closure->func, ce, called_scope, newthis, + ZEND_CLOSURE_IS_FAKE(closure), ZEND_CLOSURE_FLAGS(closure)); + + if (ZEND_CLOSURE_FLAGS(closure) & ZEND_PARTIAL_OF_CLOSURE) { + /* Re-bind the inner closure */ + + HashTable *static_variables = ZEND_MAP_PTR_GET(closure->func.op_array.static_variables_ptr); + ZEND_ASSERT(static_variables->nNumOfElements > 0); + zval *inner = &static_variables->arData[0].val; + ZEND_ASSERT(Z_TYPE_P(inner) == IS_OBJECT && Z_OBJCE_P(inner) == zend_ce_closure); + + zval new_inner; + if (do_closure_bind(&new_inner, inner, newthis, scope_obj, scope_str) != SUCCESS) { + ZEND_UNREACHABLE(); + zval_ptr_dtor(return_value); + ZVAL_NULL(return_value); + return FAILURE; + } + + zend_object *garbage = Z_OBJ_P(inner); + ZVAL_COPY_VALUE(inner, &new_inner); + zend_object_release(garbage); + } + + return SUCCESS; } /* {{{ Create a closure from another one and bind to another object and scope */ @@ -588,8 +627,9 @@ static zend_object *zend_closure_clone(zend_object *zobject) /* {{{ */ zend_closure *closure = (zend_closure *)zobject; zval result; - zend_create_closure(&result, &closure->func, - closure->func.common.scope, closure->called_scope, &closure->this_ptr); + zend_create_closure_ex(&result, &closure->func, + closure->func.common.scope, closure->called_scope, &closure->this_ptr, + ZEND_CLOSURE_IS_FAKE(closure), ZEND_CLOSURE_FLAGS(closure)); return Z_OBJ(result); } /* }}} */ @@ -756,7 +796,7 @@ static ZEND_NAMED_FUNCTION(zend_closure_internal_handler) /* {{{ */ } /* }}} */ -static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool is_fake) /* {{{ */ +static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool is_fake, uint32_t flags) /* {{{ */ { zend_closure *closure; void *ptr; @@ -764,6 +804,7 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en object_init_ex(res, zend_ce_closure); closure = (zend_closure *)Z_OBJ_P(res); + closure->std.extra_flags = flags; if ((scope == NULL) && this_ptr && (Z_TYPE_P(this_ptr) != IS_UNDEF)) { /* use dummy scope if we're binding an object without specifying a scope */ @@ -861,14 +902,14 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) { zend_create_closure_ex(res, func, scope, called_scope, this_ptr, - /* is_fake */ (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0); + /* is_fake */ (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) != 0, 0); } ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) /* {{{ */ { zend_closure *closure; - zend_create_closure_ex(res, func, scope, called_scope, this_ptr, /* is_fake */ true); + zend_create_closure_ex(res, func, scope, called_scope, this_ptr, /* is_fake */ true, 0); closure = (zend_closure *)Z_OBJ_P(res); closure->func.common.fn_flags |= ZEND_ACC_FAKE_CLOSURE; @@ -878,7 +919,15 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas } /* }}} */ -static zend_arg_info trampoline_arg_info[1]; +ZEND_API void zend_create_partial_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool partial_of_closure) +{ + int flags = ZEND_PARTIAL; + if (partial_of_closure) { + flags |= ZEND_PARTIAL_OF_CLOSURE; + } + zend_create_closure_ex(res, func, scope, called_scope, this_ptr, + /* is_fake */ false, flags); +} void zend_closure_from_frame(zval *return_value, const zend_execute_data *call) { /* {{{ */ zval instance; @@ -904,9 +953,7 @@ void zend_closure_from_frame(zval *return_value, const zend_execute_data *call) trampoline.function_name = mptr->common.function_name; trampoline.scope = mptr->common.scope; trampoline.doc_comment = NULL; - if (trampoline.fn_flags & ZEND_ACC_VARIADIC) { - trampoline.arg_info = trampoline_arg_info; - } + trampoline.arg_info = mptr->common.arg_info; trampoline.attributes = mptr->common.attributes; zend_free_trampoline(mptr); @@ -943,11 +990,3 @@ 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 a118044c6e248..3c8d2f83c32ec 100644 --- a/Zend/zend_closures.h +++ b/Zend/zend_closures.h @@ -28,7 +28,6 @@ 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); @@ -38,6 +37,7 @@ extern ZEND_API zend_class_entry *zend_ce_closure; ZEND_API void zend_create_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr); ZEND_API void zend_create_fake_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr); +ZEND_API void zend_create_partial_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr, bool partial_of_closure); ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *obj); ZEND_API const zend_function *zend_get_closure_method_def(zend_object *obj); ZEND_API zval* zend_get_closure_this_ptr(zval *obj); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5eba2ec1366fa..dd3ba8bbeaba1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -29,6 +29,8 @@ #include "zend_exceptions.h" #include "zend_interfaces.h" #include "zend_types.h" +#include "zend_portability.h" +#include "zend_string.h" #include "zend_virtual_cwd.h" #include "zend_multibyte.h" #include "zend_language_scanner.h" @@ -103,6 +105,8 @@ static void zend_compile_expr(znode *result, zend_ast *ast); static void zend_compile_stmt(zend_ast *ast); static void zend_compile_assign(znode *result, zend_ast *ast); +static zend_ast *zend_partial_apply(zend_ast *callable_ast, zend_ast *pipe_arg); + #ifdef ZEND_CHECK_STACK_LIMIT zend_never_inline static void zend_stack_limit_error(void) { @@ -816,8 +820,6 @@ static void zend_do_free(znode *op1) /* {{{ */ } else { /* Frameless calls usually use the return value, so always emit a free. This should be * faster than checking RETURN_VALUE_USED inside the handler. */ - // FIXME: We may actually look at the function signature to determine whether a free - // is necessary. zend_emit_op(NULL, ZEND_FREE, op1, NULL); } } else { @@ -3699,12 +3701,16 @@ static uint32_t zend_get_arg_num(const zend_function *fn, const zend_string *arg return (uint32_t) -1; } -static uint32_t zend_compile_args( - zend_ast *ast, const zend_function *fbc, bool *may_have_extra_named_args) /* {{{ */ +static uint32_t zend_compile_args_ex( + zend_ast *ast, const zend_function *fbc, + bool *may_have_extra_named_args, + bool is_call_partial, bool *uses_variadic_placeholder_p, + zval *named_positions) /* {{{ */ { const zend_ast_list *args = zend_ast_get_list(ast); uint32_t i; bool uses_arg_unpack = false; + bool uses_variadic_placeholder = false; uint32_t arg_count = 0; /* number of arguments not including unpacks */ /* Whether named arguments are used syntactically, to enforce language level limitations. @@ -3730,6 +3736,11 @@ static uint32_t zend_compile_args( "Cannot use argument unpacking after named arguments"); } + if (is_call_partial) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot combine partial application and unpacking"); + } + /* Unpack may contain named arguments. */ may_have_undef = true; if (!fbc || (fbc->common.fn_flags & ZEND_ACC_VARIADIC)) { @@ -3770,18 +3781,75 @@ static uint32_t zend_compile_args( may_have_undef = true; *may_have_extra_named_args = true; } + + if (uses_variadic_placeholder) { + zend_error_noreturn(E_COMPILE_ERROR, + "Variadic placeholder must be last"); + } } else { if (uses_arg_unpack) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use positional argument after argument unpacking"); } - if (uses_named_args) { + bool is_variadic_placeholder = arg->kind == ZEND_AST_PLACEHOLDER_ARG + && arg->attr == ZEND_PLACEHOLDER_VARIADIC; + + if (uses_named_args && !is_variadic_placeholder) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use positional argument after named argument"); } - arg_count++; + if (uses_variadic_placeholder) { + if (is_variadic_placeholder) { + zend_error_noreturn(E_COMPILE_ERROR, + "Variadic placeholder may only appear once"); + } else { + zend_error_noreturn(E_COMPILE_ERROR, + "Variadic placeholder must be last"); + } + } + + if (!is_variadic_placeholder) { + arg_count++; + } + } + + if (arg->kind == ZEND_AST_PLACEHOLDER_ARG) { + if (uses_arg_unpack) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot combine partial application and unpacking"); + } + + if (arg->attr == ZEND_PLACEHOLDER_VARIADIC) { + uses_variadic_placeholder = true; + /* Do not emit ZEND_SEND_PLACEHOLDER: We represent the variadic + * placeholder with a flag on the ZEND_CONVERT_CALLABLE_PARTIAL + * op instead. */ + continue; + } + + if (arg_name) { + if (Z_ISUNDEF_P(named_positions)) { + array_init(named_positions); + } + zval tmp; + ZVAL_LONG(&tmp, zend_hash_num_elements(Z_ARRVAL_P(named_positions))); + zend_hash_add(Z_ARRVAL_P(named_positions), arg_name, &tmp); + } + + opline = zend_emit_op(NULL, ZEND_SEND_PLACEHOLDER, NULL, NULL); + if (arg_name) { + opline->op2_type = IS_CONST; + zend_string_addref(arg_name); + opline->op2.constant = zend_add_literal_string(&arg_name); + opline->result.num = zend_alloc_cache_slots(2); + } else if (arg->attr != ZEND_PLACEHOLDER_VARIADIC) { + opline->op2.opline_num = arg_num; + opline->result.var = EX_NUM_TO_VAR(arg_num - 1); + } + + continue; } /* Treat passing of $GLOBALS the same as passing a call. @@ -3894,14 +3962,24 @@ static uint32_t zend_compile_args( } } - if (may_have_undef) { - zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL); + if (!is_call_partial) { + if (may_have_undef) { + zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL); + } + } else { + *uses_variadic_placeholder_p = uses_variadic_placeholder; } return arg_count; } /* }}} */ +static uint32_t zend_compile_args(zend_ast *ast, const zend_function *fbc, + bool *may_have_extra_named_args) /* {{{ */ +{ + return zend_compile_args_ex(ast, fbc, may_have_extra_named_args, false, NULL, NULL); +} + ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, const zend_function *fbc, bool result_used) /* {{{ */ { uint32_t no_discard = result_used ? 0 : ZEND_ACC_NODISCARD; @@ -3935,6 +4013,38 @@ ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, const zend_function *f } /* }}} */ +static void zend_compile_call_partial(znode *result, uint32_t arg_count, + bool may_have_extra_named_args, bool uses_variadic_placeholder, + zval *named_positions, uint32_t opnum_init, const zend_function *fbc) { + + zend_op *init_opline = &CG(active_op_array)->opcodes[opnum_init]; + + init_opline->extended_value = arg_count; + + ZEND_ASSERT(init_opline->opcode != ZEND_NEW); + + if (init_opline->opcode == ZEND_INIT_FCALL) { + init_opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc); + } + + zend_op *opline = zend_emit_op_tmp(result, ZEND_CALLABLE_CONVERT_PARTIAL, + NULL, NULL); + + opline->op1.num = zend_alloc_cache_slots(2); + + if (may_have_extra_named_args) { + opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS; + } + if (uses_variadic_placeholder) { + opline->extended_value |= ZEND_FCALL_USES_VARIADIC_PLACEHOLDER; + } + + if (!Z_ISUNDEF_P(named_positions)) { + opline->op2.constant = zend_add_literal(named_positions); + opline->op2_type = IS_CONST; + } +} + static bool zend_compile_call_common(znode *result, zend_ast *args_ast, const zend_function *fbc, uint32_t lineno) /* {{{ */ { zend_op *opline; @@ -3950,18 +4060,43 @@ static bool zend_compile_call_common(znode *result, zend_ast *args_ast, const ze zend_error_noreturn(E_COMPILE_ERROR, "Cannot create Closure for new expression"); } - if (opcode == ZEND_INIT_FCALL) { - opline->op1.num = zend_vm_calc_used_stack(0, fbc); - } + zend_ast_list *fcc_args = zend_ast_get_list(((zend_ast_fcc*)args_ast)->args); - zend_op *callable_convert_op = zend_emit_op_tmp(result, ZEND_CALLABLE_CONVERT, NULL, NULL); - if (opcode == ZEND_INIT_FCALL - || opcode == ZEND_INIT_FCALL_BY_NAME - || opcode == ZEND_INIT_NS_FCALL_BY_NAME) { - callable_convert_op->extended_value = zend_alloc_cache_slot(); - } else { - callable_convert_op->extended_value = (uint32_t)-1; + /* FCCs are a special case of PFAs with a single variadic placeholder */ + if (fcc_args->children == 1 && fcc_args->child[0]->attr == ZEND_PLACEHOLDER_VARIADIC) { + + if (opline->opcode == ZEND_INIT_FCALL) { + opline->op1.num = zend_vm_calc_used_stack(0, fbc); + } + + zend_op *callable_convert_op = zend_emit_op_tmp(result, ZEND_CALLABLE_CONVERT, NULL, NULL); + if (opcode == ZEND_INIT_FCALL + || opcode == ZEND_INIT_FCALL_BY_NAME + || opcode == ZEND_INIT_NS_FCALL_BY_NAME) { + callable_convert_op->extended_value = zend_alloc_cache_slot(); + } else { + callable_convert_op->extended_value = (uint32_t)-1; + } + + return true; } + + args_ast = ((zend_ast_fcc*)args_ast)->args; + + bool may_have_extra_named_args; + bool uses_variadic_placeholder; + + zval named_positions; + ZVAL_UNDEF(&named_positions); + + uint32_t arg_count = zend_compile_args_ex(args_ast, fbc, + &may_have_extra_named_args, true, &uses_variadic_placeholder, + &named_positions); + + zend_compile_call_partial(result, arg_count, + may_have_extra_named_args, uses_variadic_placeholder, + &named_positions, opnum_init, fbc); + return true; } @@ -5024,7 +5159,92 @@ static zend_result zend_compile_func_clone(znode *result, const zend_ast_list *a return SUCCESS; } -static zend_result zend_try_compile_special_func_ex(znode *result, zend_string *lcname, zend_ast_list *args, uint32_t type) /* {{{ */ +static zend_result zend_compile_func_array_map(znode *result, zend_ast_list *args, zend_string *lcname, uint32_t lineno) /* {{{ */ +{ + /* Bail out if we do not have exactly two parameters. */ + if (args->children != 2) { + return FAILURE; + } + + zend_ast *callback = args->child[0]; + if (callback->kind != ZEND_AST_CALL && callback->kind != ZEND_AST_STATIC_CALL) { + return FAILURE; + } + + znode value; + value.op_type = IS_TMP_VAR; + value.u.op.var = get_temporary_variable(); + + zend_ast *call_args = zend_partial_apply(callback, + zend_ast_create_znode(&value)); + if (!call_args) { + CG(active_op_array)->T--; + /* The callback is not a FCC/PFA, or is not optimizable */ + return FAILURE; + } + + zend_op *opline; + + znode array; + zend_compile_expr(&array, args->child[1]); + /* array is an argument to both ZEND_TYPE_ASSERT and to ZEND_FE_RESET_R. */ + if (array.op_type == IS_CONST) { + Z_TRY_ADDREF(array.u.constant); + } + + /* Verify that the input array actually is an array. */ + znode name; + name.op_type = IS_CONST; + ZVAL_STR_COPY(&name.u.constant, lcname); + opline = zend_emit_op(NULL, ZEND_TYPE_ASSERT, &name, &array); + opline->lineno = lineno; + opline->extended_value = (2 << 16) | IS_ARRAY; + const zval *fbc_zv = zend_hash_find(CG(function_table), lcname); + const Bucket *fbc_bucket = (const Bucket*)((uintptr_t)fbc_zv - XtOffsetOf(Bucket, val)); + Z_EXTRA_P(CT_CONSTANT(opline->op1)) = fbc_bucket - CG(function_table)->arData; + + /* Initialize the result array. */ + zend_emit_op_tmp(result, ZEND_INIT_ARRAY, NULL, NULL); + + /* foreach loop starts here. */ + znode key; + + uint32_t opnum_reset = get_next_op_number(); + znode reset_node; + zend_emit_op(&reset_node, ZEND_FE_RESET_R, &array, NULL); + zend_begin_loop(ZEND_FE_FREE, &reset_node, false); + uint32_t opnum_fetch = get_next_op_number(); + zend_emit_op_tmp(&key, ZEND_FE_FETCH_R, &reset_node, &value); + + /* loop body */ + znode call_result; + switch (callback->kind) { + case ZEND_AST_CALL: + zend_compile_expr(&call_result, zend_ast_create(ZEND_AST_CALL, callback->child[0], call_args)); + break; + case ZEND_AST_STATIC_CALL: + zend_compile_expr(&call_result, zend_ast_create(ZEND_AST_STATIC_CALL, callback->child[0], callback->child[1], call_args)); + break; + } + opline = zend_emit_op(NULL, ZEND_ADD_ARRAY_ELEMENT, &call_result, &key); + SET_NODE(opline->result, result); + /* end loop body */ + + zend_emit_jump(opnum_fetch); + + uint32_t opnum_loop_end = get_next_op_number(); + opline = &CG(active_op_array)->opcodes[opnum_reset]; + opline->op2.opline_num = opnum_loop_end; + opline = &CG(active_op_array)->opcodes[opnum_fetch]; + opline->extended_value = opnum_loop_end; + + zend_end_loop(opnum_fetch, &reset_node); + zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL); + + return SUCCESS; +} + +static zend_result zend_try_compile_special_func_ex(znode *result, zend_string *lcname, zend_ast_list *args, uint32_t type, uint32_t lineno) /* {{{ */ { if (zend_string_equals_literal(lcname, "strlen")) { return zend_compile_func_strlen(result, args); @@ -5096,12 +5316,14 @@ static zend_result zend_try_compile_special_func_ex(znode *result, zend_string * return zend_compile_func_printf(result, args); } else if (zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_CLONE))) { return zend_compile_func_clone(result, args); + } else if (zend_string_equals_literal(lcname, "array_map")) { + return zend_compile_func_array_map(result, args, lcname, lineno); } else { return FAILURE; } } -static zend_result zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args, const zend_function *fbc, uint32_t type) /* {{{ */ +static zend_result zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args, const zend_function *fbc, uint32_t type, uint32_t lineno) /* {{{ */ { if (CG(compiler_options) & ZEND_COMPILE_NO_BUILTINS) { return FAILURE; @@ -5117,7 +5339,7 @@ static zend_result zend_try_compile_special_func(znode *result, zend_string *lcn return FAILURE; } - if (zend_try_compile_special_func_ex(result, lcname, args, type) == SUCCESS) { + if (zend_try_compile_special_func_ex(result, lcname, args, type, lineno) == SUCCESS) { return SUCCESS; } @@ -5260,7 +5482,7 @@ static void zend_compile_call(znode *result, const zend_ast *ast, uint32_t type) if (!is_callable_convert && zend_try_compile_special_func(result, lcname, - zend_ast_get_list(args_ast), fbc, type) == SUCCESS + zend_ast_get_list(args_ast), fbc, type, ast->lineno) == SUCCESS ) { zend_string_release_ex(lcname, 0); zval_ptr_dtor(&name_node.u.constant); @@ -6568,6 +6790,76 @@ static bool zend_is_pipe_optimizable_callable_name(zend_ast *ast) return true; } +static zend_ast *zend_partial_apply(zend_ast *callable_ast, zend_ast *pipe_arg) +{ + if (callable_ast->kind != ZEND_AST_CALL + && callable_ast->kind != ZEND_AST_STATIC_CALL + && callable_ast->kind != ZEND_AST_METHOD_CALL) { + return NULL; + } + + zend_ast *args_ast = zend_ast_call_get_args(callable_ast); + if (!args_ast || args_ast->kind != ZEND_AST_CALLABLE_CONVERT) { + return NULL; + } + + if (callable_ast->kind == ZEND_AST_CALL && + !zend_is_pipe_optimizable_callable_name(callable_ast->child[0])) { + return NULL; + } + + zend_ast_list *arg_list = zend_ast_get_list(((zend_ast_fcc*)args_ast)->args); + + zend_ast *first_placeholder = NULL; + bool uses_named_args = false; + + for (uint32_t i = 0; i < arg_list->children; i++) { + zend_ast *arg = arg_list->child[i]; + if (arg->kind == ZEND_AST_NAMED_ARG) { + uses_named_args = true; + arg = arg->child[1]; + } + + if (arg->kind == ZEND_AST_PLACEHOLDER_ARG) { + if (first_placeholder == NULL) { + first_placeholder = arg; + } else { + /* A PFA with multiple placeholders is unexpected in is this + * context, and will usually error due to a missing argument, + * so we don't optimize those. */ + return NULL; + } + if (arg->attr == ZEND_PLACEHOLDER_VARIADIC && uses_named_args) { + /* A PFA with both a variadic placeholder and named args can not + * be optimized because this would result in a positional arg + * after a named arg: f(name: $v, ...) -> f(name: $v, pipe_arg). + * Arg placeholders ('?') are safe since they are not allowed + * after named args. */ + return NULL; + } + } + } + + ZEND_ASSERT(first_placeholder); + + zend_ast *new_arg_list = zend_ast_create_list(0, arg_list->kind); + for (uint32_t i = 0; i < arg_list->children; i++) { + zend_ast *arg = arg_list->child[i]; + if (arg == first_placeholder) { + new_arg_list = zend_ast_list_add(new_arg_list, pipe_arg); + } else if (arg->kind == ZEND_AST_NAMED_ARG + && arg->child[1] == first_placeholder) { + zend_ast *name = arg->child[0]; + new_arg_list = zend_ast_list_add(new_arg_list, + zend_ast_create(ZEND_AST_NAMED_ARG, name, pipe_arg)); + } else { + new_arg_list = zend_ast_list_add(new_arg_list, arg); + } + } + + return new_arg_list; +} + static void zend_compile_pipe(znode *result, zend_ast *ast) { zend_ast *operand_ast = ast->child[0]; @@ -6592,29 +6884,34 @@ static void zend_compile_pipe(znode *result, zend_ast *ast) } /* Turn the operand into a function parameter list. */ - zend_ast *arg_list_ast = zend_ast_create_list(1, ZEND_AST_ARG_LIST, zend_ast_create_znode(&wrapped_operand_result)); + zend_ast *arg = zend_ast_create_znode(&wrapped_operand_result); zend_ast *fcall_ast; znode callable_result; + zend_ast *pfa_arg_list_ast = NULL; - /* Turn $foo |> bar(...) into bar($foo). */ - if (callable_ast->kind == ZEND_AST_CALL - && callable_ast->child[1]->kind == ZEND_AST_CALLABLE_CONVERT - && zend_is_pipe_optimizable_callable_name(callable_ast->child[0])) { - fcall_ast = zend_ast_create(ZEND_AST_CALL, - callable_ast->child[0], arg_list_ast); - /* Turn $foo |> bar::baz(...) into bar::baz($foo). */ - } else if (callable_ast->kind == ZEND_AST_STATIC_CALL - && callable_ast->child[2]->kind == ZEND_AST_CALLABLE_CONVERT) { - fcall_ast = zend_ast_create(ZEND_AST_STATIC_CALL, - callable_ast->child[0], callable_ast->child[1], arg_list_ast); - /* Turn $foo |> $bar->baz(...) into $bar->baz($foo). */ - } else if (callable_ast->kind == ZEND_AST_METHOD_CALL - && callable_ast->child[2]->kind == ZEND_AST_CALLABLE_CONVERT) { - fcall_ast = zend_ast_create(ZEND_AST_METHOD_CALL, - callable_ast->child[0], callable_ast->child[1], arg_list_ast); + /* Turn $foo |> PFA into plain function call if possible */ + if ((pfa_arg_list_ast = zend_partial_apply(callable_ast, arg))) { + switch (callable_ast->kind) { + case ZEND_AST_CALL: + fcall_ast = zend_ast_create(ZEND_AST_CALL, + callable_ast->child[0], pfa_arg_list_ast); + break; + case ZEND_AST_STATIC_CALL: + fcall_ast = zend_ast_create(ZEND_AST_STATIC_CALL, + callable_ast->child[0], callable_ast->child[1], + pfa_arg_list_ast); + break; + case ZEND_AST_METHOD_CALL: + fcall_ast = zend_ast_create(ZEND_AST_METHOD_CALL, + callable_ast->child[0], callable_ast->child[1], + pfa_arg_list_ast); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } /* Turn $foo |> $expr into ($expr)($foo) */ } else { + zend_ast *arg_list_ast = zend_ast_create_list(1, ZEND_AST_ARG_LIST, arg); zend_compile_expr(&callable_result, callable_ast); callable_ast = zend_ast_create_znode(&callable_result); fcall_ast = zend_ast_create(ZEND_AST_CALL, @@ -11603,6 +11900,13 @@ static void zend_compile_const_expr_fcc(zend_ast **ast_ptr) if ((*args_ast)->kind != ZEND_AST_CALLABLE_CONVERT) { zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations"); } + + zend_ast_list *args = zend_ast_get_list(((zend_ast_fcc*)*args_ast)->args); + if (args->children != 1 || args->child[0]->attr != ZEND_PLACEHOLDER_VARIADIC) { + // TODO: PFAs + zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations"); + } + ZEND_MAP_PTR_NEW(((zend_ast_fcc *)*args_ast)->fptr); switch ((*ast_ptr)->kind) { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index d2a3b47bf92f4..b95cdf3eab6fa 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -951,6 +951,7 @@ struct _zend_arena; ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type); ZEND_API zend_op_array *compile_string(zend_string *source_string, const char *filename, zend_compile_position position); ZEND_API zend_op_array *compile_filename(int type, zend_string *filename); +ZEND_API zend_op_array *zend_compile_ast(zend_ast *ast, int type, zend_string *filename); ZEND_API zend_ast *zend_compile_string_to_ast( zend_string *code, struct _zend_arena **ast_arena, zend_string *filename); ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count, ...); @@ -1125,7 +1126,8 @@ ZEND_API zend_string *zend_type_to_string(zend_type type); #define ZEND_THROW_IS_EXPR 1u -#define ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS 1 +#define ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS (1<<0) +#define ZEND_FCALL_USES_VARIADIC_PLACEHOLDER (1<<1) /* The send mode, the is_variadic, the is_promoted, and the is_tentative flags are stored as part of zend_type */ #define _ZEND_SEND_MODE_SHIFT _ZEND_TYPE_EXTRA_FLAGS_SHIFT @@ -1236,6 +1238,9 @@ static zend_always_inline bool zend_check_arg_send_type(const zend_function *zf, #define ZEND_IS_BINARY_ASSIGN_OP_OPCODE(opcode) \ (((opcode) >= ZEND_ADD) && ((opcode) <= ZEND_POW)) +/* PFAs/FCCs */ +#define ZEND_PLACEHOLDER_VARIADIC (1<<0) + /* Pseudo-opcodes that are used only temporarily during compilation */ #define ZEND_GOTO 253 #define ZEND_BRK 254 diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c index 00fbab22a056e..7c62c8a96d0e3 100644 --- a/Zend/zend_enum.c +++ b/Zend/zend_enum.c @@ -533,6 +533,8 @@ ZEND_API zend_class_entry *zend_register_internal_enum( zend_class_implements(ce, 1, zend_ce_backed_enum); } + ce->default_object_handlers = &zend_enum_object_handlers; + return ce; } diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 191d8f7fe6aec..52e3ab0092540 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -145,31 +145,6 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo } /* }}} */ -void zend_exception_save(void) /* {{{ */ -{ - if (EG(prev_exception)) { - zend_exception_set_previous(EG(exception), EG(prev_exception)); - } - if (EG(exception)) { - EG(prev_exception) = EG(exception); - } - EG(exception) = NULL; -} -/* }}} */ - -void zend_exception_restore(void) /* {{{ */ -{ - if (EG(prev_exception)) { - if (EG(exception)) { - zend_exception_set_previous(EG(exception), EG(prev_exception)); - } else { - EG(exception) = EG(prev_exception); - } - EG(prev_exception) = NULL; - } -} -/* }}} */ - static zend_always_inline bool is_handle_exception_set(void) { zend_execute_data *execute_data = EG(current_execute_data); return !execute_data @@ -241,10 +216,6 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* ZEND_API void zend_clear_exception(void) /* {{{ */ { zend_object *exception; - if (EG(prev_exception)) { - OBJ_RELEASE(EG(prev_exception)); - EG(prev_exception) = NULL; - } if (!EG(exception)) { return; } diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 24d9f4efd80a3..e5a6be2f32feb 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -41,8 +41,6 @@ extern ZEND_API zend_class_entry *zend_ce_unhandled_match_error; extern ZEND_API zend_class_entry *zend_ce_request_parse_body_exception; ZEND_API void zend_exception_set_previous(zend_object *exception, zend_object *add_previous); -ZEND_API void zend_exception_save(void); -ZEND_API void zend_exception_restore(void); ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 518cbb98fc0f8..765095fca36f5 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1213,8 +1213,7 @@ static zend_always_inline bool zend_check_type_slow( } static zend_always_inline bool zend_check_type( - const zend_type *type, zval *arg, zend_class_entry *scope, - bool is_return_type, bool is_internal) + const zend_type *type, zval *arg, bool is_return_type, bool is_internal) { const zend_reference *ref = NULL; ZEND_ASSERT(ZEND_TYPE_IS_SET(*type)); @@ -1231,6 +1230,12 @@ static zend_always_inline bool zend_check_type( return zend_check_type_slow(type, arg, ref, is_return_type, is_internal); } +ZEND_API bool zend_check_type_ex( + const zend_type *type, zval *arg, bool is_return_type, bool is_internal) +{ + return zend_check_type(type, arg, is_return_type, is_internal); +} + ZEND_API bool zend_check_user_type_slow( const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type) { @@ -1246,7 +1251,7 @@ static zend_always_inline bool zend_verify_recv_arg_type(const zend_function *zf cur_arg_info = &zf->common.arg_info[arg_num-1]; if (ZEND_TYPE_IS_SET(cur_arg_info->type) - && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, zf->common.scope, false, false))) { + && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, false, false))) { zend_verify_arg_error(zf, cur_arg_info, arg_num, arg); return 0; } @@ -1258,7 +1263,7 @@ static zend_always_inline bool zend_verify_variadic_arg_type( const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, zval *arg) { ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type)); - if (UNEXPECTED(!zend_check_type(&arg_info->type, arg, zf->common.scope, false, false))) { + if (UNEXPECTED(!zend_check_type(&arg_info->type, arg, false, false))) { zend_verify_arg_error(zf, arg_info, arg_num, arg); return 0; } @@ -1283,7 +1288,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ } if (ZEND_TYPE_IS_SET(cur_arg_info->type) - && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, fbc->common.scope, false, /* is_internal */ true))) { + && UNEXPECTED(!zend_check_type(&cur_arg_info->type, arg, false, /* is_internal */ true))) { return 0; } arg++; @@ -1316,6 +1321,7 @@ ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_exe if ((fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) && !zend_verify_internal_arg_types(fbc, call)) { + zend_clear_exception(); return 1; } @@ -1489,7 +1495,7 @@ ZEND_API bool zend_verify_internal_return_type(const zend_function *zf, zval *re return 1; } - if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, NULL, true, /* is_internal */ true))) { + if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, true, /* is_internal */ true))) { zend_verify_internal_return_error(zf, ret); return 0; } @@ -3627,6 +3633,9 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } else if (UNEXPECTED(Z_ISERROR_P(ptr))) { ZVAL_ERROR(result); goto end; + } else if (type == BP_VAR_UNSET && UNEXPECTED(Z_TYPE_P(ptr) == IS_UNDEF)) { + ZVAL_NULL(result); + goto end; } ZVAL_INDIRECT(result, ptr); @@ -3778,6 +3787,11 @@ static zend_never_inline zval* zend_fetch_static_property_address_ex(zend_proper return NULL; } + if (UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF) + && (fetch_type == BP_VAR_IS || fetch_type == BP_VAR_UNSET)) { + return NULL; + } + *prop_info = property_info; if (EXPECTED(op1_type == IS_CONST) @@ -4644,6 +4658,7 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: level++; break; case ZEND_INIT_FCALL: @@ -4700,6 +4715,7 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: level++; break; case ZEND_INIT_FCALL: @@ -4780,6 +4796,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: level++; break; case ZEND_INIT_FCALL: @@ -4837,6 +4854,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: level++; break; case ZEND_INIT_FCALL: @@ -4881,20 +4899,6 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o } /* }}} */ -static const zend_live_range *find_live_range(const zend_op_array *op_array, uint32_t op_num, uint32_t var_num) /* {{{ */ -{ - int i; - for (i = 0; i < op_array->last_live_range; i++) { - const zend_live_range *range = &op_array->live_range[i]; - if (op_num >= range->start && op_num < range->end - && var_num == (range->var & ~ZEND_LIVE_MASK)) { - return range; - } - } - return NULL; -} -/* }}} */ - static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */ { int i; @@ -4910,6 +4914,16 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t var_num = range->var & ~ZEND_LIVE_MASK; zval *var = EX_VAR(var_num); + /* Handle the split range for loop vars */ + if (catch_op_num) { + zend_op *final_op = EX(func)->op_array.opcodes + range->end; + if (final_op->extended_value & ZEND_FREE_ON_RETURN && (final_op->opcode == ZEND_FE_FREE || final_op->opcode == ZEND_FREE)) { + if (catch_op_num < range->end + final_op->op2.num) { + continue; + } + } + } + if (kind == ZEND_LIVE_TMPVAR) { zval_ptr_dtor_nogc(var); } else if (kind == ZEND_LIVE_NEW) { @@ -5552,9 +5566,10 @@ zval * ZEND_FASTCALL zend_handle_named_arg( } } else { arg = ZEND_CALL_VAR_NUM(call, arg_offset); + if (UNEXPECTED(!Z_ISUNDEF_P(arg))) { - zend_throw_error(NULL, "Named parameter $%s overwrites previous argument", - ZSTR_VAL(arg_name)); + zend_throw_error(NULL, "Named parameter $%s overwrites previous %s", + ZSTR_VAL(arg_name), Z_TYPE_P(arg) == _IS_PLACEHOLDER ? "placeholder" : "argument"); return NULL; } } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 8858f9fce96ae..104b9c49abe20 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -110,6 +110,8 @@ ZEND_API ZEND_COLD void zend_verify_never_error( ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref); ZEND_API bool zend_check_user_type_slow( const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type); +ZEND_API bool zend_check_type_ex( + const zend_type *type, zval *arg, bool is_return_type, bool is_internal); #if ZEND_DEBUG ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index e134d3d496b6d..393adfc8839fb 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -39,6 +39,7 @@ #include "zend_observer.h" #include "zend_call_stack.h" #include "zend_frameless_function.h" +#include "zend_partial.h" #ifdef HAVE_SYS_TIME_H #include #endif @@ -176,7 +177,6 @@ void init_executor(void) /* {{{ */ ZEND_ATOMIC_BOOL_INIT(&EG(timed_out), false); EG(exception) = NULL; - EG(prev_exception) = NULL; EG(fake_scope) = NULL; EG(trampoline).common.function_name = NULL; @@ -204,6 +204,7 @@ void init_executor(void) /* {{{ */ zend_weakrefs_init(); zend_hash_init(&EG(callable_convert_cache), 8, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(&EG(partial_function_application_cache), 8, NULL, zend_partial_op_array_dtor, 0); EG(active) = 1; } @@ -421,6 +422,7 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); zend_hash_clean(&EG(callable_convert_cache)); + zend_hash_clean(&EG(partial_function_application_cache)); #if ZEND_DEBUG if (!CG(unclean_shutdown)) { @@ -520,6 +522,7 @@ void shutdown_executor(void) /* {{{ */ } zend_hash_destroy(&EG(callable_convert_cache)); + zend_hash_destroy(&EG(partial_function_application_cache)); } #if ZEND_DEBUG @@ -1268,9 +1271,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * zend_long previous_lineno = EG(lineno_override); EG(filename_override) = NULL; EG(lineno_override) = -1; - zend_exception_save(); ce = zend_autoload(autoload_name, lc_name); - zend_exception_restore(); EG(filename_override) = previous_filename; EG(lineno_override) = previous_lineno; diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 527ddd4b1931e..f2fe29802a06f 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -76,6 +76,7 @@ #include "zend_types.h" #include "zend_weakrefs.h" #include "zend_string.h" +#include "zend_exceptions.h" #ifndef GC_BENCH # define GC_BENCH 0 @@ -1932,6 +1933,17 @@ static zend_fiber *gc_create_destructor_fiber(void) return fiber; } +static void remember_prev_exception(zend_object **prev_exception) +{ + if (EG(exception)) { + if (*prev_exception) { + zend_exception_set_previous(EG(exception), *prev_exception); + } + *prev_exception = EG(exception); + EG(exception) = NULL; + } +} + static zend_never_inline void gc_call_destructors_in_fiber(uint32_t end) { ZEND_ASSERT(!GC_G(dtor_fiber_running)); @@ -1947,6 +1959,9 @@ static zend_never_inline void gc_call_destructors_in_fiber(uint32_t end) zend_fiber_resume(fiber, NULL, NULL); } + zend_object *exception = NULL; + remember_prev_exception(&exception); + for (;;) { /* At this point, fiber has executed until suspension */ GC_TRACE("resumed from destructor fiber"); @@ -1960,7 +1975,9 @@ static zend_never_inline void gc_call_destructors_in_fiber(uint32_t end) /* We do not own the fiber anymore. It may be collected if the * application does not reference it. */ zend_object_release(&fiber->std); + remember_prev_exception(&exception); fiber = gc_create_destructor_fiber(); + remember_prev_exception(&exception); continue; } else { /* Fiber suspended itself after calling all destructors */ @@ -1968,6 +1985,8 @@ static zend_never_inline void gc_call_destructors_in_fiber(uint32_t end) break; } } + + EG(exception) = exception; } /* Perform a garbage collection run. The default implementation of gc_collect_cycles. */ 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_globals.h b/Zend/zend_globals.h index ef81ae5faaf25..0d15e35a9e3eb 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -255,7 +255,7 @@ struct _zend_executor_globals { zend_objects_store objects_store; zend_lazy_objects_store lazy_objects_store; - zend_object *exception, *prev_exception; + zend_object *exception; const zend_op *opline_before_exception; zend_op exception_op[3]; @@ -320,6 +320,7 @@ struct _zend_executor_globals { zend_strtod_state strtod_state; HashTable callable_convert_cache; + HashTable partial_function_application_cache; void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 3c3931cdca164..ce576def24ddd 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1515,10 +1515,9 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke } int parent_num = OBJ_PROP_TO_NUM(parent_info->offset); + /* Don't keep default properties in GC (they may be freed by opcache) */ + zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num])); if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) { - /* Don't keep default properties in GC (they may be freed by opcache) */ - zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num])); - if (use_child_prop) { ZVAL_UNDEF(&ce->default_properties_table[parent_num]); } else { diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index e4d61006fe12f..e2686c7e1c5a8 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -379,7 +379,7 @@ attribute_group: ; attribute: - T_ATTRIBUTE attribute_group possible_comma ']' { $$ = $2; } + T_ATTRIBUTE backup_doc_comment attribute_group possible_comma ']' { $$ = $3; CG(doc_comment) = $2; } ; attributes: @@ -901,16 +901,15 @@ return_type: ; argument_list: - '(' ')' { $$ = zend_ast_create_list(0, ZEND_AST_ARG_LIST); } + '(' ')' { $$ = zend_ast_create_arg_list(0, ZEND_AST_ARG_LIST); } | '(' non_empty_argument_list possible_comma ')' { $$ = $2; } - | '(' T_ELLIPSIS ')' { $$ = zend_ast_create_fcc(); } ; non_empty_argument_list: argument - { $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $1); } + { $$ = zend_ast_create_arg_list(1, ZEND_AST_ARG_LIST, $1); } | non_empty_argument_list ',' argument - { $$ = zend_ast_list_add($1, $3); } + { $$ = zend_ast_arg_list_add($1, $3); } ; /* `clone_argument_list` is necessary to resolve a parser ambiguity (shift-reduce conflict) @@ -923,25 +922,31 @@ non_empty_argument_list: * syntax. */ clone_argument_list: - '(' ')' { $$ = zend_ast_create_list(0, ZEND_AST_ARG_LIST); } + '(' ')' { $$ = zend_ast_create_arg_list(0, ZEND_AST_ARG_LIST); } | '(' non_empty_clone_argument_list possible_comma ')' { $$ = $2; } - | '(' expr ',' ')' { $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $2); } - | '(' T_ELLIPSIS ')' { $$ = zend_ast_create_fcc(); } + | '(' expr ',' ')' { $$ = zend_ast_create_arg_list(1, ZEND_AST_ARG_LIST, $2); } ; non_empty_clone_argument_list: expr ',' argument - { $$ = zend_ast_create_list(2, ZEND_AST_ARG_LIST, $1, $3); } + { $$ = zend_ast_create_arg_list(2, ZEND_AST_ARG_LIST, $1, $3); } | argument_no_expr - { $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $1); } + { $$ = zend_ast_create_arg_list(1, ZEND_AST_ARG_LIST, $1); } | non_empty_clone_argument_list ',' argument - { $$ = zend_ast_list_add($1, $3); } + { $$ = zend_ast_arg_list_add($1, $3); } ; argument_no_expr: identifier ':' expr { $$ = zend_ast_create(ZEND_AST_NAMED_ARG, $1, $3); } - | T_ELLIPSIS expr { $$ = zend_ast_create(ZEND_AST_UNPACK, $2); } + | T_ELLIPSIS + { $$ = zend_ast_create_ex(ZEND_AST_PLACEHOLDER_ARG, ZEND_PLACEHOLDER_VARIADIC); } + | '?' + { $$ = zend_ast_create(ZEND_AST_PLACEHOLDER_ARG); } + | identifier ':' '?' + { $$ = zend_ast_create(ZEND_AST_NAMED_ARG, $1, zend_ast_create(ZEND_AST_PLACEHOLDER_ARG)); } + | T_ELLIPSIS expr + { $$ = zend_ast_create(ZEND_AST_UNPACK, $2); } ; argument: diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 1e26ddbd99199..86ae6dc06a53b 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -591,6 +591,43 @@ ZEND_API zend_result open_file_for_scanning(zend_file_handle *file_handle) return SUCCESS; } +static zend_op_array *zend_compile_ast_internal(int type) +{ + ZEND_ASSERT(CG(in_compilation)); + ZEND_ASSERT(CG(ast)); + + 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); + + zend_op_array *op_array = emalloc(sizeof(zend_op_array)); + init_op_array(op_array, type, INITIAL_OP_ARRAY_SIZE); + CG(active_op_array) = op_array; + + /* Use heap to not waste arena memory */ + op_array->fn_flags |= ZEND_ACC_HEAP_RT_CACHE; + + if (zend_ast_process) { + zend_ast_process(CG(ast)); + } + + zend_file_context_begin(&original_file_context); + zend_oparray_context_begin(&original_oparray_context, op_array); + zend_compile_top_stmt(CG(ast)); + CG(zend_lineno) = last_lineno; + zend_emit_final_return(type == ZEND_USER_FUNCTION); + op_array->line_start = 1; + op_array->line_end = last_lineno; + pass_two(op_array); + zend_oparray_context_end(&original_oparray_context); + zend_file_context_end(&original_file_context); + + CG(active_op_array) = original_active_op_array; + + return op_array; +} + static zend_op_array *zend_compile(int type) { zend_op_array *op_array = NULL; @@ -601,34 +638,7 @@ static zend_op_array *zend_compile(int type) CG(ast_arena) = zend_arena_create(1024 * 32); if (!zendparse()) { - 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); - - op_array = emalloc(sizeof(zend_op_array)); - init_op_array(op_array, type, INITIAL_OP_ARRAY_SIZE); - CG(active_op_array) = op_array; - - /* Use heap to not waste arena memory */ - op_array->fn_flags |= ZEND_ACC_HEAP_RT_CACHE; - - if (zend_ast_process) { - zend_ast_process(CG(ast)); - } - - zend_file_context_begin(&original_file_context); - zend_oparray_context_begin(&original_oparray_context, op_array); - zend_compile_top_stmt(CG(ast)); - CG(zend_lineno) = last_lineno; - zend_emit_final_return(type == ZEND_USER_FUNCTION); - op_array->line_start = 1; - op_array->line_end = last_lineno; - pass_two(op_array); - zend_oparray_context_end(&original_oparray_context); - zend_file_context_end(&original_file_context); - - CG(active_op_array) = original_active_op_array; + op_array = zend_compile_ast_internal(type); } zend_ast_destroy(CG(ast)); @@ -671,6 +681,23 @@ ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type) return op_array; } +ZEND_API zend_op_array *zend_compile_ast( + zend_ast *ast, int type, zend_string *filename) +{ + zend_string *original_compiled_filename = CG(compiled_filename); + bool original_in_compilation = CG(in_compilation); + CG(in_compilation) = 1; + CG(ast) = ast; + + zend_set_compiled_filename(filename); + zend_op_array *op_array = zend_compile_ast_internal(type); + + CG(in_compilation) = original_in_compilation; + zend_restore_compiled_filename(original_compiled_filename); + + return op_array; +} + ZEND_API zend_ast *zend_compile_string_to_ast( zend_string *code, zend_arena **ast_arena, zend_string *filename) { zval code_zv; @@ -2765,7 +2792,8 @@ skip_escape_conversion: zend_ptr_stack_reverse_apply(¤t_state.heredoc_label_stack, copy_heredoc_label_stack); - zend_exception_save(); + zend_object *prev_exception = EG(exception); + EG(exception) = NULL; while (heredoc_nesting_level) { zval zv; int retval; @@ -2794,7 +2822,7 @@ skip_escape_conversion: heredoc_nesting_level = 0; } } - zend_exception_restore(); + EG(exception) = prev_exception; if ( (first_token == T_VARIABLE diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 88b7b1112d7b1..07ff4de9244a4 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1398,6 +1398,7 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__get != NULL), cache_slot, &prop_info); if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) { +try_again: retval = OBJ_PROP(zobj, property_offset); if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) { if (EXPECTED(!zobj->ce->__get) || @@ -1477,7 +1478,15 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam } retval = zend_hash_add(zobj->properties, name, &EG(uninitialized_zval)); } - } else if (!IS_HOOKED_PROPERTY_OFFSET(property_offset) && zobj->ce->__get == NULL) { + } else if (IS_HOOKED_PROPERTY_OFFSET(property_offset)) { + if (!(prop_info->flags & ZEND_ACC_VIRTUAL) && !zend_should_call_hook(prop_info, zobj)) { + property_offset = prop_info->offset; + if (!ZEND_TYPE_IS_SET(prop_info->type)) { + prop_info = NULL; + } + goto try_again; + } + } else if (zobj->ce->__get == NULL) { retval = &EG(error_zval); } @@ -1685,7 +1694,6 @@ ZEND_API ZEND_ATTRIBUTE_NONNULL zend_function *zend_get_call_trampoline_func( * The low bit must be zero, to not be interpreted as a MAP_PTR offset. */ static const void *dummy = (void*)(intptr_t)2; - static const zend_arg_info arg_info[1] = {{0}}; if (EXPECTED(EG(trampoline).common.function_name == NULL)) { func = &EG(trampoline).op_array; @@ -1732,7 +1740,7 @@ ZEND_API ZEND_ATTRIBUTE_NONNULL zend_function *zend_get_call_trampoline_func( func->prop_info = NULL; func->num_args = 0; func->required_num_args = 0; - func->arg_info = (zend_arg_info *) arg_info; + func->arg_info = zend_call_trampoline_arginfo; return (zend_function*)func; } @@ -2576,6 +2584,7 @@ ZEND_API const zend_object_handlers std_object_handlers = { }; void zend_object_handlers_startup(void) { - zend_call_trampoline_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_ARGS); + zend_call_trampoline_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_ARGUMENTS); + zend_call_trampoline_arginfo[0].type = (zend_type)ZEND_TYPE_INIT_CODE(IS_MIXED, false, _ZEND_ARG_INFO_FLAGS(false, 1, 0)); zend_property_hook_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_VALUE); } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 5e9e7b20d869b..d874f566dc87d 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -994,6 +994,35 @@ static void zend_calc_live_ranges( /* OP_DATA is really part of the previous opcode. */ last_use[var_num] = opnum - (opline->opcode == ZEND_OP_DATA); } + } else if ((opline->opcode == ZEND_FREE || opline->opcode == ZEND_FE_FREE) && opline->extended_value & ZEND_FREE_ON_RETURN) { + int jump_offset = 1; + while (((opline + jump_offset)->opcode == ZEND_FREE || (opline + jump_offset)->opcode == ZEND_FE_FREE) + && (opline + jump_offset)->extended_value & ZEND_FREE_ON_RETURN) { + ++jump_offset; + } + // loop var frees directly precede the jump (or return) operand, except that ZEND_VERIFY_RETURN_TYPE may happen first. + if ((opline + jump_offset)->opcode == ZEND_VERIFY_RETURN_TYPE) { + ++jump_offset; + } + /* FREE with ZEND_FREE_ON_RETURN immediately followed by RETURN frees + * the loop variable on early return. We need to split the live range + * so GC doesn't access the freed variable after this FREE. */ + uint32_t opnum_last_use = last_use[var_num]; + zend_op *opline_last_use = op_array->opcodes + opnum_last_use; + ZEND_ASSERT(opline_last_use->opcode == opline->opcode); // any ZEND_FREE_ON_RETURN must be followed by a FREE without + if (opnum + jump_offset + 1 != opnum_last_use) { + emit_live_range_raw(op_array, var_num, opline->opcode == ZEND_FE_FREE ? ZEND_LIVE_LOOP : ZEND_LIVE_TMPVAR, + opnum + jump_offset + 1, opnum_last_use); + } + + /* Update last_use so next range includes this FREE */ + last_use[var_num] = opnum; + + /* Store opline offset to loop end */ + opline->op2.opline_num = opnum_last_use - opnum; + if (opline_last_use->extended_value & ZEND_FREE_ON_RETURN) { + opline->op2.opline_num += opline_last_use->op2.opline_num; + } } } if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) { diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index ff31c84c41e5e..2f226a76ccaf8 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -149,10 +149,8 @@ static zend_always_inline zend_long zend_dval_to_lval_silent(double d) static zend_always_inline zend_long zend_dval_to_lval_cap(double d, const zend_string *s) { if (UNEXPECTED(!zend_finite(d))) { - zend_oob_string_to_long_error(s); return 0; } else if (!ZEND_DOUBLE_FITS_LONG(d)) { - zend_oob_string_to_long_error(s); return (d > 0 ? ZEND_LONG_MAX : ZEND_LONG_MIN); } return (zend_long)d; diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c new file mode 100644 index 0000000000000..60ae63b46bfc7 --- /dev/null +++ b/Zend/zend_partial.c @@ -0,0 +1,1135 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +/** + * Partial Function Application: + * + * A partial application is compiled to the usual sequence of function call + * opcodes (INIT_FCALL, SEND_VAR, etc), but the sequence ends with a + * CALLABLE_CONVERT_PARTIAL opcode instead of DO_FCALL, similarly to + * first class callables. Placeholders are compiled to SEND_PLACEHOLDER opcodes: + * + * $f = f($a, ?) + * + * 0001 INIT_FCALL f + * 0002 SEND_VAR CV($a) + * 0003 SEND_PLACEHOLDER + * 0004 CV($f) = CALLABLE_CONVERT_PARTIAL + * + * SEND_PLACEHOLDER sets the argument slot type to _IS_PLACEHOLDER. + * + * CALLABLE_CONVERT_PARTIAL uses the information available on the stack to + * create a Closure and return it, consuming the stack frame in the process + * like an internal function call. + * + * We create the Closure by generating the relevant AST and compiling it to an + * op_array. The op_array is cached in the Opcache SHM and inline caches. + * + * This file implements the Closure generation logic + * (see zend_partial_create(), zp_compile()). + */ + +#include "zend.h" +#include "zend_API.h" +#include "zend_arena.h" +#include "zend_ast.h" +#include "zend_compile.h" +#include "zend_closures.h" +#include "zend_attributes.h" +#include "zend_exceptions.h" +#include "ext/opcache/ZendAccelerator.h" + +#define Z_IS_PLACEHOLDER_P(p) (Z_TYPE_P(p) == _IS_PLACEHOLDER) + +static zend_always_inline bool zp_is_static_closure(const zend_function *function) { + return ((function->common.fn_flags & (ZEND_ACC_STATIC|ZEND_ACC_CLOSURE)) == (ZEND_ACC_STATIC|ZEND_ACC_CLOSURE)); +} + +static zend_never_inline ZEND_COLD void zp_args_underflow( + const zend_function *function, uint32_t args, uint32_t expected) +{ + zend_string *symbol = get_function_or_method_name(function); + const char *limit = function->common.num_args <= function->common.required_num_args ? + "exactly" : "at least"; + + zend_argument_count_error( + "Partial application of %s() expects %s %d arguments, %d given", + ZSTR_VAL(symbol), limit, expected, args); + + zend_string_release(symbol); +} + +static zend_never_inline ZEND_COLD void zp_args_overflow( + const zend_function *function, uint32_t args, uint32_t expected) +{ + zend_string *symbol = get_function_or_method_name(function); + + zend_argument_count_error( + "Partial application of %s() expects at most %d arguments, %d given", + ZSTR_VAL(symbol), expected, args); + + zend_string_release(symbol); +} + +static zend_result zp_args_check(const zend_function *function, + uint32_t argc, const zval *argv, + const zend_array *extra_named_args, + bool uses_variadic_placeholder) { + + if (extra_named_args) { + zval *arg; + zend_string *key; + ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(extra_named_args, key, arg) { + if (UNEXPECTED(Z_IS_PLACEHOLDER_P(arg))) { + zend_throw_error(NULL, + "Cannot use named placeholder for unknown or variadic parameter $%s", + ZSTR_VAL(key)); + return FAILURE; + } + } ZEND_HASH_FOREACH_END(); + } + + if (argc < function->common.required_num_args) { + if (uses_variadic_placeholder) { + /* Missing args will be turned into placeholders */ + return SUCCESS; + } + + zp_args_underflow( + function, argc, function->common.required_num_args); + return FAILURE; + } else if (argc > function->common.num_args && + !(function->common.fn_flags & ZEND_ACC_VARIADIC)) { + zp_args_overflow(function, argc, function->common.num_args); + return FAILURE; + } + + return SUCCESS; +} + +static bool zp_name_exists(zend_string **names, uint32_t num_names, const zend_string *name) +{ + for (uint32_t i = 0; i < num_names; i++) { + if (names[i] && zend_string_equals(names[i], name)) { + return true; + } + } + return false; +} + +static zend_string *zp_get_param_name(zend_function *function, uint32_t arg_offset) +{ + return zend_string_copy(function->common.arg_info[arg_offset].name); +} + +/* Assign a name for every variable that will be used in the generated closure, + * including params and used vars. */ +static void zp_assign_names(zend_string **names, uint32_t num_names, + uint32_t argc, zval *argv, + zend_function *function, bool variadic_partial, + zend_array *extra_named_params) +{ + /* Assign names for params. We never rename those. */ + for (uint32_t offset = 0; offset < MIN(argc, function->common.num_args); offset++) { + if (Z_IS_PLACEHOLDER_P(&argv[offset])) { + names[offset] = zp_get_param_name(function, offset); + } + } + + /* Assign name for the variadic param. Never renamed. */ + if (variadic_partial && (function->common.fn_flags & ZEND_ACC_VARIADIC)) { + names[argc] = zp_get_param_name(function, function->common.num_args); + } + + /* Assign names for placeholders that bind to the variadic param: + * + * function f($a, ...$args) {} + * f(?, ?, ...); // The second placeholder binds into the variadic param. + * + * By default these are named $origNameN with N the offset from the + * variadic param. In case of clash we increment N until a free name is + * found. */ + for (uint32_t offset = function->common.num_args; offset < argc; offset++) { + ZEND_ASSERT(function->common.fn_flags & ZEND_ACC_VARIADIC); + if (!Z_IS_PLACEHOLDER_P(&argv[offset])) { + continue; + } + zend_string *orig_name = zp_get_param_name(function, function->common.num_args); + zend_string *new_name; + for (uint32_t n = 0;; n++) { + new_name = zend_strpprintf_unchecked(0, "%S%" PRIu32, orig_name, n); + if (!zp_name_exists(names, num_names, new_name)) { + break; + } + zend_string_release(new_name); + } + names[offset] = new_name; + zend_string_release(orig_name); + } + + /* Assign names for pre-bound params (lexical vars). + * There may be clashes, we ensure to generate unique names. */ + for (uint32_t offset = 0; offset < argc; offset++) { + if (Z_IS_PLACEHOLDER_P(&argv[offset]) || Z_ISUNDEF(argv[offset])) { + continue; + } + uint32_t n = 0; + zend_string *orig_name = zp_get_param_name(function, MIN(offset, function->common.num_args)); + zend_string *new_name = zend_string_copy(orig_name); + while (zp_name_exists(names, num_names, new_name)) { + zend_string_release(new_name); + new_name = zend_strpprintf_unchecked(0, "%S%" PRIu32, orig_name, n); + n++; + } + names[offset] = new_name; + zend_string_release(orig_name); + } + + /* Assign name for $extra_named_params */ + if (extra_named_params) { + uint32_t n = 1; + zend_string *new_name = ZSTR_INIT_LITERAL("extra_named_params", 0); + while (zp_name_exists(names, num_names, new_name)) { + zend_string_release(new_name); + n++; + new_name = zend_strpprintf(0, "%s%" PRIu32, "extra_named_params", n); + } + names[argc + variadic_partial] = new_name; + } + + /* Assign name for $fn */ + if (function->common.fn_flags & ZEND_ACC_CLOSURE) { + uint32_t n = 1; + zend_string *new_name = ZSTR_INIT_LITERAL("fn", 0); + while (zp_name_exists(names, num_names, new_name)) { + zend_string_release(new_name); + n++; + new_name = zend_strpprintf(0, "%s%" PRIu32, "fn", n); + } + names[argc + variadic_partial + (extra_named_params != NULL)] = new_name; + } +} + +static inline bool zp_is_power_of_two(uint32_t x) +{ + return (x > 0) && !(x & (x - 1)); +} + +static bool zp_is_simple_type(uint32_t type_mask) +{ + ZEND_ASSERT(!(type_mask & ~_ZEND_TYPE_MAY_BE_MASK)); + + return zp_is_power_of_two(type_mask) + || type_mask == MAY_BE_BOOL + || type_mask == MAY_BE_ANY; +} + +static zend_ast *zp_simple_type_to_ast(uint32_t type) +{ + zend_string *name; + + switch (type) { + case MAY_BE_NULL: + name = ZSTR_KNOWN(ZEND_STR_NULL_LOWERCASE); + break; + case MAY_BE_TRUE: + name = ZSTR_KNOWN(ZEND_STR_TRUE); + break; + case MAY_BE_FALSE: + name = ZSTR_KNOWN(ZEND_STR_FALSE); + break; + case MAY_BE_LONG: + name = ZSTR_KNOWN(ZEND_STR_INT); + break; + case MAY_BE_DOUBLE: + name = ZSTR_KNOWN(ZEND_STR_FLOAT); + break; + case MAY_BE_STRING: + name = ZSTR_KNOWN(ZEND_STR_STRING); + break; + case MAY_BE_BOOL: + name = ZSTR_KNOWN(ZEND_STR_BOOL); + break; + case MAY_BE_VOID: + name = ZSTR_KNOWN(ZEND_STR_VOID); + break; + case MAY_BE_NEVER: + name = ZSTR_KNOWN(ZEND_STR_NEVER); + break; + case MAY_BE_OBJECT: + name = ZSTR_KNOWN(ZEND_STR_OBJECT); + break; + case MAY_BE_ANY: + name = ZSTR_KNOWN(ZEND_STR_MIXED); + break; + case MAY_BE_CALLABLE: + return zend_ast_create_ex(ZEND_AST_TYPE, IS_CALLABLE); + case MAY_BE_ARRAY: + return zend_ast_create_ex(ZEND_AST_TYPE, IS_ARRAY); + case MAY_BE_STATIC: + return zend_ast_create_ex(ZEND_AST_TYPE, IS_STATIC); + EMPTY_SWITCH_DEFAULT_CASE() + } + + zend_ast *ast = zend_ast_create_zval_from_str(name); + ast->attr = ZEND_NAME_NOT_FQ; + + return ast; +} + +static zend_ast *zp_type_name_to_ast(zend_string *name) +{ + zend_ast *ast = zend_ast_create_zval_from_str(name); + + if (zend_get_class_fetch_type(name) != ZEND_FETCH_CLASS_DEFAULT) { + ast->attr = ZEND_NAME_NOT_FQ; + } else { + ast->attr = ZEND_NAME_FQ; + } + + return ast; +} + +static zend_ast *zp_type_to_ast(const zend_type type) +{ + if (!ZEND_TYPE_IS_SET(type)) { + return NULL; + } + + if (ZEND_TYPE_IS_UNION(type) + || (ZEND_TYPE_IS_COMPLEX(type) && ZEND_TYPE_PURE_MASK(type)) + || (ZEND_TYPE_PURE_MASK(type) && !zp_is_simple_type(ZEND_TYPE_PURE_MASK(type)))) { + zend_ast *type_ast = zend_ast_create_list(0, ZEND_AST_TYPE_UNION); + if (ZEND_TYPE_HAS_LIST(type)) { + const zend_type *type_ptr; + ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), type_ptr) { + type_ast = zend_ast_list_add(type_ast, zp_type_to_ast(*type_ptr)); + } ZEND_TYPE_LIST_FOREACH_END(); + } else if (ZEND_TYPE_HAS_NAME(type)) { + zend_ast *name_ast = zp_type_name_to_ast( + zend_string_copy(ZEND_TYPE_NAME(type))); + type_ast = zend_ast_list_add(type_ast, name_ast); + } else { + ZEND_ASSERT(!ZEND_TYPE_IS_COMPLEX(type)); + } + uint32_t type_mask = ZEND_TYPE_PURE_MASK(type); + if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) { + type_ast = zend_ast_list_add(type_ast, zp_simple_type_to_ast(MAY_BE_BOOL)); + type_mask &= ~MAY_BE_BOOL; + } + for (uint32_t may_be_type = 1; may_be_type < _ZEND_TYPE_MAY_BE_MASK; may_be_type <<= 1) { + if (type_mask & may_be_type) { + type_ast = zend_ast_list_add(type_ast, zp_simple_type_to_ast(may_be_type)); + } + } + return type_ast; + } + + if (ZEND_TYPE_IS_INTERSECTION(type)) { + ZEND_ASSERT(!ZEND_TYPE_PURE_MASK(type)); + zend_ast *type_ast = zend_ast_create_list(0, ZEND_AST_TYPE_INTERSECTION); + const zend_type *type_ptr; + ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), type_ptr) { + type_ast = zend_ast_list_add(type_ast, zp_type_to_ast(*type_ptr)); + } ZEND_TYPE_LIST_FOREACH_END(); + return type_ast; + } + + if (ZEND_TYPE_HAS_NAME(type)) { + ZEND_ASSERT(!ZEND_TYPE_PURE_MASK(type)); + zend_ast *type_ast = zp_type_name_to_ast( + zend_string_copy(ZEND_TYPE_NAME(type))); + return type_ast; + } + + ZEND_ASSERT(!ZEND_TYPE_IS_COMPLEX(type)); + + uint32_t type_mask = ZEND_TYPE_PURE_MASK(type); + ZEND_ASSERT(zp_is_simple_type(type_mask)); + + return zp_simple_type_to_ast(type_mask); +} + +static zend_result zp_get_param_default_value(zval *result, zend_function *function, uint32_t arg_offset) +{ + ZEND_ASSERT(arg_offset < function->common.num_args); + + if (function->type == ZEND_USER_FUNCTION) { + zend_op *opline = &function->op_array.opcodes[arg_offset]; + if (EXPECTED(opline->opcode == ZEND_RECV_INIT)) { + ZVAL_COPY(result, RT_CONSTANT(opline, opline->op2)); + return SUCCESS; + } else { + ZEND_ASSERT(opline->opcode == ZEND_RECV); + } + } else { + if (function->common.fn_flags & ZEND_ACC_USER_ARG_INFO) { + goto error; + } + + const zend_arg_info *arg_info = &function->internal_function.arg_info[arg_offset]; + + if (zend_get_default_from_internal_arg_info(result, arg_info) == SUCCESS) { + return SUCCESS; + } + } + +error: + zend_argument_error_ex(function, arg_offset + 1, + zend_ce_argument_count_error, + "must be passed explicitly, because the default value is not known"); + + return FAILURE; +} + +static bool zp_arg_must_be_sent_by_ref(zend_function *function, uint32_t arg_num) +{ + if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_MUST_BE_SENT_BY_REF(function, arg_num)) { + return true; + } + } else if (ARG_MUST_BE_SENT_BY_REF(function, arg_num)) { + return true; + } + return false; +} + +static zend_ast *zp_attribute_to_ast(zend_attribute *attribute) +{ + zend_ast *args_ast; + if (attribute->argc) { + args_ast = zend_ast_create_arg_list(0, ZEND_AST_ARG_LIST); + for (uint32_t i = 0; i < attribute->argc; i++) { + zend_ast *arg_ast = zend_ast_create_zval(&attribute->args[i].value); + if (attribute->args[i].name) { + arg_ast = zend_ast_create(ZEND_AST_NAMED_ARG, + zend_ast_create_zval_from_str( + zend_string_copy(attribute->args[i].name)), + arg_ast); + } + args_ast = zend_ast_list_add(args_ast, arg_ast); + } + } else { + args_ast = NULL; + } + return zend_ast_create(ZEND_AST_ATTRIBUTE, + zend_ast_create_zval_from_str(zend_string_copy(attribute->name)), + args_ast); +} + +static zend_ast *zp_param_attributes_to_ast(zend_function *function, + uint32_t offset) +{ + zend_ast *attributes_ast = NULL; + if (!function->common.attributes) { + return NULL; + } + + /* Inherit the SensitiveParameter attribute */ + zend_attribute *attr = zend_get_parameter_attribute_str( + function->common.attributes, + "sensitiveparameter", strlen("sensitiveparameter"), offset); + if (attr) { + attributes_ast = zend_ast_create_list(1, ZEND_AST_ATTRIBUTE_GROUP, + zp_attribute_to_ast(attr)); + attributes_ast = zend_ast_create_list(1, ZEND_AST_ATTRIBUTE_LIST, + attributes_ast); + } + + return attributes_ast; +} + +static zend_string *zp_pfa_name(const zend_op_array *declaring_op_array, + const zend_op *declaring_opline) +{ + zend_string *filename = declaring_op_array->filename; + uint32_t start_lineno = declaring_opline->lineno; + + zend_string *class = zend_empty_string; + zend_string *separator = zend_empty_string; + zend_string *function = filename; + const char *parens = ""; + + if (declaring_op_array->function_name) { + if (declaring_op_array->fn_flags & ZEND_ACC_CLOSURE) { + /* If the parent function is a closure, don't redundantly + * add the classname and parentheses. + */ + function = declaring_op_array->function_name; + } else { + function = declaring_op_array->function_name; + parens = "()"; + + if (declaring_op_array->scope && declaring_op_array->scope->name) { + class = declaring_op_array->scope->name; + separator = ZSTR_KNOWN(ZEND_STR_PAAMAYIM_NEKUDOTAYIM); + } + } + } + + zend_string *name = zend_strpprintf_unchecked( + 0, + "{closure:pfa:%S%S%S%s:%" PRIu32 "}", + class, + separator, + function, + parens, + start_lineno + ); + + return name; +} + +/* Generate the AST for calling the actual function */ +static zend_ast *zp_compile_forwarding_call( + zval *this_ptr, zend_function *function, + uint32_t argc, zval *argv, zend_array *extra_named_params, + zend_string **param_names, bool variadic_partial, uint32_t num_args, + zend_class_entry *called_scope, zend_type return_type, + bool forward_superfluous_args, + zend_ast *stmts_ast) +{ + bool is_assert = zend_string_equals(function->common.function_name, + ZSTR_KNOWN(ZEND_STR_ASSERT)); + + zend_ast *args_ast = zend_ast_create_list(0, ZEND_AST_ARG_LIST); + zend_ast *call_ast = NULL; + + if (is_assert) { + /* We are going to call assert() dynamically (via call_user_func), + * otherwise assert() would print the generated AST on failure, which is + * irrelevant. */ + args_ast = zend_ast_list_add(args_ast, + zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_ASSERT))); + } + + for (uint32_t offset = 0; offset < argc; offset++) { + if (Z_ISUNDEF(argv[offset])) { + /* Argument was not passed. Pass its default value. */ + if (offset < function->common.required_num_args) { + /* Required param was not passed. This can happen due to named + * args. Using the same exception CE and message as + * zend_handle_undef_args(). */ + zend_argument_error_ex(function, offset + 1, + zend_ce_argument_count_error, "not passed"); + goto error; + } + zval default_value; + if (zp_get_param_default_value(&default_value, function, offset) == FAILURE) { + ZEND_ASSERT(EG(exception)); + goto error; + } + zend_ast *default_value_ast; + if (Z_TYPE(default_value) == IS_CONSTANT_AST) { + /* Must dup AST because we are doing to destroy it */ + default_value_ast = zend_ast_dup(Z_ASTVAL(default_value)); + } else { + default_value_ast = zend_ast_create_zval(&default_value); + } + args_ast = zend_ast_list_add(args_ast, default_value_ast); + } else { + args_ast = zend_ast_list_add(args_ast, zend_ast_create(ZEND_AST_VAR, + zend_ast_create_zval_from_str(zend_string_copy(param_names[offset])))); + } + } + if (extra_named_params) { + args_ast = zend_ast_list_add(args_ast, zend_ast_create(ZEND_AST_UNPACK, + zend_ast_create(ZEND_AST_VAR, + zend_ast_create_zval_from_str(zend_string_copy(param_names[argc + variadic_partial]))))); + } + if (variadic_partial) { + if (function->common.fn_flags & ZEND_ACC_VARIADIC) { + args_ast = zend_ast_list_add(args_ast, zend_ast_create(ZEND_AST_UNPACK, + zend_ast_create(ZEND_AST_VAR, + zend_ast_create_zval_from_str(zend_string_copy(param_names[argc]))))); + } else if (forward_superfluous_args) { + /* When a '...' placeholder is used, and the underlying function is + * not variadic, superfluous arguments are forwarded. + * Add a ...array_slice(func_get_args(), n) argument, which should + * be compiled as ZEND_AST_UNPACK + ZEND_FUNC_GET_ARGS. */ + + zend_ast *func_get_args_name_ast = zend_ast_create_zval_from_str( + zend_string_copy(ZSTR_KNOWN(ZEND_STR_FUNC_GET_ARGS))); + func_get_args_name_ast->attr = ZEND_NAME_FQ; + + zend_ast *array_slice_name_ast = zend_ast_create_zval_from_str( + zend_string_copy(ZSTR_KNOWN(ZEND_STR_ARRAY_SLICE))); + array_slice_name_ast->attr = ZEND_NAME_FQ; + + args_ast = zend_ast_list_add(args_ast, + zend_ast_create(ZEND_AST_UNPACK, + zend_ast_create(ZEND_AST_CALL, + array_slice_name_ast, + zend_ast_create_list(2, ZEND_AST_ARG_LIST, + zend_ast_create(ZEND_AST_CALL, + func_get_args_name_ast, + zend_ast_create_list(0, ZEND_AST_ARG_LIST)), + zend_ast_create_zval_from_long(num_args))))); + } + } + + if (is_assert) { + zend_ast *func_name_ast = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CALL_USER_FUNC)); + func_name_ast->attr = ZEND_NAME_FQ; + call_ast = zend_ast_create(ZEND_AST_CALL, func_name_ast, args_ast); + } else if (function->common.fn_flags & ZEND_ACC_CLOSURE) { + zend_ast *fn_ast = zend_ast_create(ZEND_AST_VAR, + zend_ast_create_zval_from_str(zend_string_copy(param_names[argc + variadic_partial + (extra_named_params != NULL)]))); + call_ast = zend_ast_create(ZEND_AST_CALL, fn_ast, args_ast); + } else if (Z_TYPE_P(this_ptr) == IS_OBJECT) { + zend_ast *this_ast = zend_ast_create(ZEND_AST_VAR, + zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_THIS))); + zend_ast *method_name_ast = zend_ast_create_zval_from_str( + zend_string_copy(function->common.function_name)); + call_ast = zend_ast_create(ZEND_AST_METHOD_CALL, this_ast, + method_name_ast, args_ast); + } else if (called_scope) { + zend_ast *class_name_ast = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_STATIC)); + class_name_ast->attr = ZEND_NAME_NOT_FQ; + zend_ast *method_name_ast = zend_ast_create_zval_from_str( + zend_string_copy(function->common.function_name)); + call_ast = zend_ast_create(ZEND_AST_STATIC_CALL, class_name_ast, + method_name_ast, args_ast); + } else { + zend_ast *func_name_ast = zend_ast_create_zval_from_str(zend_string_copy(function->common.function_name)); + func_name_ast->attr = ZEND_NAME_FQ; + call_ast = zend_ast_create(ZEND_AST_CALL, func_name_ast, args_ast); + } + + /* Void functions can not 'return $expr' */ + if (ZEND_TYPE_FULL_MASK(return_type) & MAY_BE_VOID) { + stmts_ast = zend_ast_list_add(stmts_ast, call_ast); + } else { + zend_ast *return_ast = zend_ast_create(ZEND_AST_RETURN, call_ast); + stmts_ast = zend_ast_list_add(stmts_ast, return_ast); + } + + return stmts_ast; + +error: + zend_ast_destroy(args_ast); + zend_ast_destroy(call_ast); + return NULL; +} + +static uint32_t zp_compute_num_required(zend_function *function, + uint32_t orig_offset, uint32_t new_offset, uint32_t num_required) { + if (orig_offset < function->common.num_args) { + if (orig_offset < function->common.required_num_args) { + num_required = MAX(num_required, new_offset + 1); + } + } else { + ZEND_ASSERT(function->common.fn_flags & ZEND_ACC_VARIADIC); + /* Placeholders that run into the variadic portion become + * required and make all params before them required */ + ZEND_ASSERT(orig_offset >= num_required); + num_required = new_offset + 1; + } + + return num_required; +} + +/* Functions that do not allow to be called dynamically */ +static const zend_known_string_id zp_non_dynamic_call_funcs[] = { + ZEND_STR_COMPACT, + ZEND_STR_EXTRACT, + ZEND_STR_FUNC_GET_ARG, + ZEND_STR_FUNC_GET_ARGS, + ZEND_STR_FUNC_NUM_ARGS, + ZEND_STR_GET_DEFINED_VARS, +}; + +static bool zp_is_non_dynamic_call_func(zend_function *function) +{ + for (size_t i = 0; i < sizeof(zp_non_dynamic_call_funcs) / sizeof(zp_non_dynamic_call_funcs[0]); i++) { + if (zend_string_equals(function->common.function_name, ZSTR_KNOWN(zp_non_dynamic_call_funcs[i]))) { + return true; + } + } + + return false; +} + +/* Compile PFA to an op_array */ +static zend_op_array *zp_compile(zval *this_ptr, zend_function *function, + uint32_t argc, zval *argv, zend_array *extra_named_params, + const zend_array *named_positions, + const zend_op_array *declaring_op_array, + const zend_op *declaring_opline, void **cache_slot, + bool uses_variadic_placeholder) { + + zend_op_array *op_array = NULL; + + if (UNEXPECTED(zp_is_non_dynamic_call_func(function))) { + zend_throw_error(NULL, "Cannot call %.*s() dynamically", + (int) ZSTR_LEN(function->common.function_name), ZSTR_VAL(function->common.function_name)); + return NULL; + } + + if (UNEXPECTED(zp_args_check(function, argc, argv, extra_named_params, uses_variadic_placeholder) != SUCCESS)) { + ZEND_ASSERT(EG(exception)); + return NULL; + } + + zend_class_entry *called_scope; + if (Z_TYPE_P(this_ptr) == IS_OBJECT) { + called_scope = Z_OBJCE_P(this_ptr); + } else { + called_scope = Z_CE_P(this_ptr); + } + + /* CG(ast_arena) is usually NULL, so we can't just make a snapshot */ + zend_arena *orig_ast_arena = CG(ast_arena); + CG(ast_arena) = zend_arena_create(1024 * 4); + + uint32_t orig_lineno = CG(zend_lineno); + CG(zend_lineno) = zend_get_executed_lineno(); + + uint32_t new_argc = argc; + + if (uses_variadic_placeholder) { + new_argc = MAX(new_argc, function->common.num_args); + } + + zval *tmp = zend_arena_alloc(&CG(ast_arena), new_argc * sizeof(zval)); + memcpy(tmp, argv, argc * sizeof(zval)); + argv = tmp; + + /* Compute param positions and number of required args, add implicit + * placeholders. + * + * Parameters are placed in the following order: + * - Positional placeholders + * - Then named placeholders in their syntax order + * - Then implicit placeholders added by '...' + */ + uint32_t num_params = 0; + uint32_t num_required = 0; + uint32_t *arg_to_param_offset_map = zend_arena_alloc(&CG(ast_arena), sizeof(uint32_t*) * new_argc); + { + uint32_t num_positional = 0; + + /* First, we handle explicit placeholders */ + for (uint32_t arg_offset = 0; arg_offset < argc; arg_offset++) { + if (!Z_IS_PLACEHOLDER_P(&argv[arg_offset])) { + continue; + } + + num_params++; + + zend_arg_info *arg_info = &function->common.arg_info[MIN(arg_offset, function->common.num_args)]; + zval *named_pos = named_positions ? zend_hash_find(named_positions, arg_info->name) : NULL; + uint32_t param_offset; + if (named_pos) { + /* Placeholder is sent as named arg. 'num_positional' can not + * change at this point. */ + param_offset = num_positional + Z_LVAL_P(named_pos); + } else { + /* Placeholder is sent as positional */ + param_offset = num_positional++; + } + + arg_to_param_offset_map[arg_offset] = param_offset; + + num_required = zp_compute_num_required(function, + arg_offset, param_offset, num_required); + } + + /* Handle implicit placeholders added by '...' */ + if (uses_variadic_placeholder) { + for (uint32_t arg_offset = 0; arg_offset < new_argc; arg_offset++) { + if (arg_offset < argc && !Z_ISUNDEF(argv[arg_offset])) { + continue; + } + + /* Unspecified parameters become placeholders */ + Z_TYPE_INFO(argv[arg_offset]) = _IS_PLACEHOLDER; + + num_params++; + + uint32_t param_offset = num_params - 1; + + arg_to_param_offset_map[arg_offset] = param_offset; + + num_required = zp_compute_num_required(function, + arg_offset, param_offset, num_required); + } + } + } + + argc = new_argc; + + /* Assign variable names */ + + uint32_t num_names = argc + uses_variadic_placeholder + (extra_named_params != NULL) + + ((function->common.fn_flags & ZEND_ACC_CLOSURE) != 0); + zend_string **param_names = zend_arena_calloc(&CG(ast_arena), + num_names, sizeof(zend_string*)); + zp_assign_names(param_names, num_names, argc, argv, function, + uses_variadic_placeholder, extra_named_params); + + /* Generate AST */ + + zend_ast *lexical_vars_ast = zend_ast_create_list(0, ZEND_AST_CLOSURE_USES); + zend_ast *params_ast = zend_ast_create_list(0, ZEND_AST_ARG_LIST); + zend_ast *return_type_ast = NULL; + zend_ast *stmts_ast = zend_ast_create_list(0, ZEND_AST_STMT_LIST); + zend_ast *attributes_ast = NULL; + + /* Generate AST for params and lexical vars */ + { + /* The inner Closure, if any, is assumed to be the first lexical var by + * do_closure_bind(). */ + if (function->common.fn_flags & ZEND_ACC_CLOSURE) { + zend_ast *lexical_var_ast = zend_ast_create_zval_from_str( + zend_string_copy(param_names[argc + uses_variadic_placeholder + (extra_named_params != NULL)])); + lexical_vars_ast = zend_ast_list_add(lexical_vars_ast, lexical_var_ast); + } + + zend_ast **params = zend_arena_calloc(&CG(ast_arena), num_params, sizeof(zend_ast*)); + for (uint32_t offset = 0; offset < argc; offset++) { + if (Z_IS_PLACEHOLDER_P(&argv[offset])) { + zend_arg_info *arg_info = &function->common.arg_info[MIN(offset, function->common.num_args)]; + + int param_flags = 0; + if (zp_arg_must_be_sent_by_ref(function, offset+1)) { + param_flags |= ZEND_PARAM_REF; + } + + uint32_t param_offset = arg_to_param_offset_map[offset]; + zend_ast *param_type_ast = zp_type_to_ast(arg_info->type); + zend_ast *default_value_ast = NULL; + if (param_offset >= num_required) { + zval default_value; + if (zp_get_param_default_value(&default_value, function, offset) == FAILURE) { + for (uint32_t i = 0; i < num_params; i++) { + zend_ast_destroy(params[i]); + } + goto error; + } + default_value_ast = zend_ast_create_zval(&default_value); + } + + ZEND_ASSERT(offset < function->common.num_args || (function->common.fn_flags & ZEND_ACC_VARIADIC)); + + zend_ast *attributes_ast = zp_param_attributes_to_ast(function, MIN(offset, function->common.num_args)); + params[param_offset] = zend_ast_create_ex(ZEND_AST_PARAM, + param_flags, param_type_ast, + zend_ast_create_zval_from_str( + zend_string_copy(param_names[offset])), + default_value_ast, attributes_ast, NULL, NULL); + + } else if (!Z_ISUNDEF(argv[offset])) { + // TODO: If the pre-bound parameter is a literal, it can be a + // literal in the function body instead of a lexical var. + zend_ast *lexical_var_ast = zend_ast_create_zval_from_str( + zend_string_copy(param_names[offset])); + if (zp_arg_must_be_sent_by_ref(function, offset+1)) { + lexical_var_ast->attr = ZEND_BIND_REF; + } + lexical_vars_ast = zend_ast_list_add( + lexical_vars_ast, lexical_var_ast); + } + } + + for (uint32_t i = 0; i < num_params; i++) { + params_ast = zend_ast_list_add(params_ast, params[i]); + } + } + + if (extra_named_params) { + zend_ast *lexical_var_ast = zend_ast_create_zval_from_str( + zend_string_copy(param_names[argc + uses_variadic_placeholder])); + lexical_vars_ast = zend_ast_list_add(lexical_vars_ast, lexical_var_ast); + } + + /* If we have a variadic placeholder and the underlying function is + * variadic, add a variadic param. */ + if (uses_variadic_placeholder + && (function->common.fn_flags & ZEND_ACC_VARIADIC)) { + zend_arg_info *arg_info = &function->common.arg_info[function->common.num_args]; + int param_flags = ZEND_PARAM_VARIADIC; + if (zp_arg_must_be_sent_by_ref(function, function->common.num_args+1)) { + param_flags |= ZEND_PARAM_REF; + } + zend_ast *param_type_ast = zp_type_to_ast(arg_info->type); + zend_ast *attributes_ast = zp_param_attributes_to_ast(function, function->common.num_args); + params_ast = zend_ast_list_add(params_ast, zend_ast_create_ex(ZEND_AST_PARAM, + param_flags, param_type_ast, + zend_ast_create_zval_from_str( + zend_string_copy(param_names[argc])), + NULL, attributes_ast, NULL, NULL)); + } + + zend_type return_type = {0}; + if (function->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { + return_type = (function->common.arg_info-1)->type; + return_type_ast = zp_type_to_ast(return_type); + } + + /** + * Generate function body. + * + * If we may need to forward superflous arguments, do that conditionally, as + * it's faster: + * + * if (func_num_args() <= n) { + * // normal call + * } else { + * // call with superflous arg forwarding + * } + * + * The func_num_args() call should be compiled to a single FUNC_NUM_ARGS op. + */ + + if (uses_variadic_placeholder && !(function->common.fn_flags & ZEND_ACC_VARIADIC)) { + zend_ast *no_forwarding_ast = zend_ast_create_list(0, ZEND_AST_STMT_LIST); + zend_ast *forwarding_ast = zend_ast_create_list(0, ZEND_AST_STMT_LIST); + + no_forwarding_ast = zp_compile_forwarding_call(this_ptr, function, + argc, argv, extra_named_params, + param_names, uses_variadic_placeholder, num_params, + called_scope, return_type, false, no_forwarding_ast); + + if (!no_forwarding_ast) { + ZEND_ASSERT(EG(exception)); + goto error; + } + + forwarding_ast = zp_compile_forwarding_call(this_ptr, function, + argc, argv, extra_named_params, + param_names, uses_variadic_placeholder, num_params, + called_scope, return_type, true, forwarding_ast); + + if (!forwarding_ast) { + ZEND_ASSERT(EG(exception)); + zend_ast_destroy(no_forwarding_ast); + goto error; + } + + zend_ast *func_num_args_name_ast = zend_ast_create_zval_from_str( + zend_string_copy(ZSTR_KNOWN(ZEND_STR_FUNC_NUM_ARGS))); + func_num_args_name_ast->attr = ZEND_NAME_FQ; + + stmts_ast = zend_ast_list_add(stmts_ast, + zend_ast_create_list(2, ZEND_AST_IF, + zend_ast_create(ZEND_AST_IF_ELEM, + zend_ast_create_binary_op(ZEND_IS_SMALLER_OR_EQUAL, + zend_ast_create(ZEND_AST_CALL, func_num_args_name_ast, + zend_ast_create_list(0, ZEND_AST_ARG_LIST)), + zend_ast_create_zval_from_long(num_params)), + no_forwarding_ast), + zend_ast_create(ZEND_AST_IF_ELEM, + NULL, + forwarding_ast))); + } else { + stmts_ast = zp_compile_forwarding_call(this_ptr, function, + argc, argv, extra_named_params, + param_names, uses_variadic_placeholder, num_params, + called_scope, return_type, false, stmts_ast); + + if (!stmts_ast) { + ZEND_ASSERT(EG(exception)); + goto error; + } + } + + /* Inherit the NoDiscard attribute */ + if (function->common.attributes) { + zend_attribute *attr = zend_get_attribute_str( + function->common.attributes, "nodiscard", strlen("nodiscard")); + if (attr) { + attributes_ast = zend_ast_create_list(1, ZEND_AST_ATTRIBUTE_GROUP, + zp_attribute_to_ast(attr)); + attributes_ast = zend_ast_create_list(1, ZEND_AST_ATTRIBUTE_LIST, + attributes_ast); + } + } + + int closure_flags = function->common.fn_flags & ZEND_ACC_RETURN_REFERENCE; + zend_ast *closure_ast = zend_ast_create_decl(ZEND_AST_CLOSURE, + closure_flags, CG(zend_lineno), NULL, + NULL, params_ast, lexical_vars_ast, stmts_ast, + return_type_ast, attributes_ast); + + if (Z_TYPE_P(this_ptr) != IS_OBJECT || zp_is_static_closure(function)) { + ((zend_ast_decl*)closure_ast)->flags |= ZEND_ACC_STATIC; + } + +#if ZEND_DEBUG + { + const char *tmp = getenv("DUMP_PFA_AST"); + if (tmp && ZEND_ATOL(tmp)) { + zend_string *str = zend_ast_export("", closure_ast, ""); + fprintf(stderr, "PFA AST: %s\n", ZSTR_VAL(str)); + zend_string_release(str); + } + } +#endif + + zend_string *pfa_name = zp_pfa_name(declaring_op_array, declaring_opline); + + op_array = zend_accel_compile_pfa(closure_ast, declaring_op_array, + declaring_opline, function, pfa_name); + + zend_ast_destroy(closure_ast); + +clean: + for (uint32_t i = 0; i < num_names; i++) { + if (param_names[i]) { + zend_string_release(param_names[i]); + } + } + + zend_arena_destroy(CG(ast_arena)); + CG(ast_arena) = orig_ast_arena; + CG(zend_lineno) = orig_lineno; + + return op_array; + +error: + zend_ast_destroy(lexical_vars_ast); + zend_ast_destroy(params_ast); + zend_ast_destroy(return_type_ast); + zend_ast_destroy(stmts_ast); + zend_ast_destroy(attributes_ast); + goto clean; +} + +static const zend_op_array *zp_get_op_array(zval *this_ptr, zend_function *function, + uint32_t argc, zval *argv, zend_array *extra_named_params, + const zend_array *named_positions, + const zend_op_array *declaring_op_array, + const zend_op *declaring_opline, void **cache_slot, + bool uses_variadic_placeholder) { + + if (EXPECTED(function->type == ZEND_INTERNAL_FUNCTION + ? cache_slot[0] == function + : cache_slot[0] == function->op_array.opcodes)) { + return cache_slot[1]; + } + + const zend_op_array *op_array = zend_accel_pfa_cache_get(declaring_op_array, + declaring_opline, function); + + if (UNEXPECTED(!op_array)) { + op_array = zp_compile(this_ptr, function, argc, argv, + extra_named_params, named_positions, declaring_op_array, declaring_opline, + cache_slot, uses_variadic_placeholder); + } + + if (EXPECTED(op_array) && !(function->common.fn_flags & ZEND_ACC_NEVER_CACHE)) { + cache_slot[0] = function->type == ZEND_INTERNAL_FUNCTION + ? (void*)function + : (void*)function->op_array.opcodes; + cache_slot[1] = (zend_op_array*)op_array; + } + + return op_array; +} + +/* Bind pre-bound arguments as lexical vars */ +static void zp_bind(zval *result, zend_function *function, uint32_t argc, zval *argv, + zend_array *extra_named_params) { + + zend_arg_info *arg_infos = function->common.arg_info; + uint32_t bind_offset = 0; + + if (function->common.fn_flags & ZEND_ACC_CLOSURE) { + zval var; + ZVAL_OBJ(&var, ZEND_CLOSURE_OBJECT(function)); + Z_ADDREF(var); + zend_closure_bind_var_ex(result, bind_offset, &var); + bind_offset += sizeof(Bucket); + } + + for (uint32_t offset = 0; offset < argc; offset++) { + zval *var = &argv[offset]; + if (Z_IS_PLACEHOLDER_P(var) || Z_ISUNDEF_P(var)) { + continue; + } + zend_arg_info *arg_info; + if (offset < function->common.num_args) { + arg_info = &arg_infos[offset]; + } else if (function->common.fn_flags & ZEND_ACC_VARIADIC) { + arg_info = &arg_infos[function->common.num_args]; + } else { + arg_info = NULL; + } + if (arg_info && ZEND_TYPE_IS_SET(arg_info->type) + && UNEXPECTED(!zend_check_type_ex(&arg_info->type, var, 0, 0))) { + zend_verify_arg_error(function, arg_info, offset+1, var); + zval_ptr_dtor(result); + ZVAL_NULL(result); + return; + } + ZEND_ASSERT(zp_arg_must_be_sent_by_ref(function, offset+1) ? Z_ISREF_P(var) : !Z_ISREF_P(var)); + zend_closure_bind_var_ex(result, bind_offset, var); + bind_offset += sizeof(Bucket); + } + + if (extra_named_params) { + zval var; + ZVAL_ARR(&var, extra_named_params); + Z_ADDREF(var); + zend_closure_bind_var_ex(result, bind_offset, &var); + } +} + +void zend_partial_create(zval *result, zval *this_ptr, zend_function *function, + uint32_t argc, zval *argv, zend_array *extra_named_params, + const zend_array *named_positions, + const zend_op_array *declaring_op_array, + const zend_op *declaring_opline, void **cache_slot, + bool uses_variadic_placeholder) { + + const zend_op_array *op_array = zp_get_op_array(this_ptr, function, argc, argv, + extra_named_params, named_positions, + declaring_op_array, declaring_opline, + cache_slot, uses_variadic_placeholder); + + if (UNEXPECTED(!op_array)) { + ZEND_ASSERT(EG(exception)); + ZVAL_NULL(result); + return; + } + + zend_class_entry *called_scope; + zval object; + + if (Z_TYPE_P(this_ptr) == IS_OBJECT) { + called_scope = Z_OBJCE_P(this_ptr); + } else { + called_scope = Z_CE_P(this_ptr); + } + + if (Z_TYPE_P(this_ptr) == IS_OBJECT && !zp_is_static_closure(function)) { + ZVAL_COPY_VALUE(&object, this_ptr); + } else { + ZVAL_UNDEF(&object); + } + + zend_create_partial_closure(result, (zend_function*)op_array, + function->common.scope, called_scope, &object, + (function->common.fn_flags & ZEND_ACC_CLOSURE) != 0); + + zp_bind(result, function, argc, argv, extra_named_params); +} + +void zend_partial_op_array_dtor(zval *pDest) +{ + destroy_op_array(Z_PTR_P(pDest)); +} diff --git a/Zend/zend_partial.h b/Zend/zend_partial.h new file mode 100644 index 0000000000000..7999dc99019c1 --- /dev/null +++ b/Zend/zend_partial.h @@ -0,0 +1,34 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ +#ifndef ZEND_PARTIAL_H +#define ZEND_PARTIAL_H + +#include "zend_compile.h" + +BEGIN_EXTERN_C() + +void zend_partial_create(zval *result, zval *this_ptr, zend_function *function, + uint32_t argc, zval *argv, zend_array *extra_named_params, + const zend_array *named_positions, + const zend_op_array *declaring_op_array, + const zend_op *declaring_opline, void **cache_slot, + bool uses_variadic_placeholder); + +void zend_partial_op_array_dtor(zval *pDest); + +END_EXTERN_C() + +#endif diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index c7e12d58c1f53..6546ebfb5b790 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -336,9 +336,12 @@ char *alloca(); # define ZEND_PRESERVE_NONE __attribute__((preserve_none)) #endif -#if __has_attribute(musttail) -# define HAVE_MUSTTAIL -# define ZEND_MUSTTAIL __attribute__((musttail)) + +#if !defined(__apple_build_version__) || (defined(__apple_build_version__) && __apple_build_version__ >= 17000404) +# if __has_attribute(musttail) +# define HAVE_MUSTTAIL +# define ZEND_MUSTTAIL __attribute__((musttail)) +# endif #endif #if (defined(__GNUC__) && __GNUC__ >= 3 && !defined(__INTEL_COMPILER) && !defined(__APPLE__) && !defined(__hpux) && !defined(_AIX) && !defined(__osf__)) || __has_attribute(noreturn) diff --git a/Zend/zend_string.h b/Zend/zend_string.h index fc7705ff78650..b88481fa6bddc 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -563,6 +563,7 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_OBJECT_OPERATOR, "->") \ _(ZEND_STR_PAAMAYIM_NEKUDOTAYIM, "::") \ _(ZEND_STR_ARGS, "args") \ + _(ZEND_STR_ARGUMENTS, "arguments") \ _(ZEND_STR_UNKNOWN, "unknown") \ _(ZEND_STR_UNKNOWN_CAPITALIZED, "Unknown") \ _(ZEND_STR_EXIT, "exit") \ @@ -630,6 +631,15 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_AUTOGLOBAL_ENV, "_ENV") \ _(ZEND_STR_AUTOGLOBAL_REQUEST, "_REQUEST") \ _(ZEND_STR_COUNT, "count") \ + _(ZEND_STR_FUNC_NUM_ARGS, "func_num_args") \ + _(ZEND_STR_FUNC_GET_ARGS, "func_get_args") \ + _(ZEND_STR_FUNC_GET_ARG, "func_get_arg") \ + _(ZEND_STR_COMPACT, "compact") \ + _(ZEND_STR_EXTRACT, "extract") \ + _(ZEND_STR_ASSERT, "assert") \ + _(ZEND_STR_CALL_USER_FUNC, "call_user_func") \ + _(ZEND_STR_ARRAY_SLICE, "array_slice") \ + _(ZEND_STR_GET_DEFINED_VARS, "get_defined_vars") \ _(ZEND_STR_SENSITIVEPARAMETER, "SensitiveParameter") \ _(ZEND_STR_CONST_EXPR_PLACEHOLDER, "[constant expression]") \ _(ZEND_STR_DEPRECATED_CAPITALIZED, "Deprecated") \ diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 43aa2aa86a00e..6a17ed9a69e1d 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -638,6 +638,9 @@ struct _zend_ast_ref { #define _IS_BOOL 18 #define _IS_NUMBER 19 +/* used for PFAs/FCCs */ +#define _IS_PLACEHOLDER 20 + /* guard flags */ #define ZEND_GUARD_PROPERTY_GET (1<<0) #define ZEND_GUARD_PROPERTY_SET (1<<1) @@ -855,6 +858,8 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define IS_OBJ_LAZY_UNINITIALIZED (1U<<31) /* Virtual proxy or uninitialized Ghost */ #define IS_OBJ_LAZY_PROXY (1U<<30) /* Virtual proxy (may be initialized) */ +#define OBJ_EXTRA_FLAG_PRIV_1 (1U<<29) /* Reserved for private use by the object itself */ +#define OBJ_EXTRA_FLAG_PRIV_2 (1U<<28) /* Reserved for private use by the object itself */ #define OBJ_EXTRA_FLAGS(obj) ((obj)->extra_flags) diff --git a/Zend/zend_verify_type_inference.h b/Zend/zend_verify_type_inference.h index 0add01933495f..8e9cbcbc181f1 100644 --- a/Zend/zend_verify_type_inference.h +++ b/Zend/zend_verify_type_inference.h @@ -156,7 +156,7 @@ static void zend_verify_inference_def(zend_execute_data *execute_data, const zen } if (opline->op1_def_type && (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) - // array is actually changed by the the following instruction(s) + // array is actually changed by the following instruction(s) && opline->opcode != ZEND_FETCH_DIM_W && opline->opcode != ZEND_FETCH_DIM_RW && opline->opcode != ZEND_FETCH_DIM_FUNC_ARG diff --git a/Zend/zend_virtual_cwd.c b/Zend/zend_virtual_cwd.c index a9fbd5667cb8d..94183e3724c47 100644 --- a/Zend/zend_virtual_cwd.c +++ b/Zend/zend_virtual_cwd.c @@ -1418,7 +1418,7 @@ CWD_API int virtual_chown(const char *filename, uid_t owner, gid_t group, int li int ret; CWD_STATE_COPY(&new_state, &CWDG(cwd)); - if (virtual_file_ex(&new_state, filename, NULL, CWD_REALPATH)) { + if (virtual_file_ex(&new_state, filename, NULL, link ? CWD_EXPAND : CWD_REALPATH)) { CWD_STATE_FREE_ERR(&new_state); return -1; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1b91f11662c7a..d23645c819346 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1866,7 +1866,7 @@ ZEND_VM_INLINE_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type) &prop_info, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC); if (UNEXPECTED(!prop)) { - ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); + ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS) || (type == BP_VAR_UNSET)); prop = &EG(uninitialized_zval); } else if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) @@ -3246,7 +3246,7 @@ ZEND_VM_COLD_CONST_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, JMP_ADDR) ZEND_VM_JMP(opline); } -ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY) +ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, LOOP_END) { USE_OPLINE @@ -3255,7 +3255,7 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HOT_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY) +ZEND_VM_HOT_HANDLER(127, ZEND_FE_FREE, TMPVAR, LOOP_END) { zval *var; USE_OPLINE @@ -4797,10 +4797,8 @@ ZEND_VM_COLD_CONST_HANDLER(108, ZEND_THROW, CONST|TMPVAR|CV, ANY) } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); FREE_OP1(); HANDLE_EXCEPTION(); } @@ -4813,7 +4811,6 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, JMP_ADDR, LAST_CATCH|CACHE_SLOT) SAVE_OPLINE(); /* Check whether an exception has been thrown, if not, jump over code */ - zend_exception_restore(); if (EG(exception) == NULL) { ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0); } @@ -5684,6 +5681,30 @@ ZEND_VM_HELPER(zend_verify_recv_arg_type_helper, ANY, ANY, zval *op_1) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(213, ZEND_SEND_PLACEHOLDER, UNUSED, CONST|UNUSED) +{ + zval *arg; + + if (OP2_TYPE == IS_CONST) { + /* Named placeholder */ + USE_OPLINE + SAVE_OPLINE(); + zend_string *arg_name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); + uint32_t arg_num; + arg = zend_handle_named_arg(&EX(call), arg_name, &arg_num, CACHE_ADDR(opline->result.num)); + if (UNEXPECTED(!arg)) { + HANDLE_EXCEPTION(); + } + } else { + /* Positional placeholder */ + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + } + + Z_TYPE_INFO_P(arg) = _IS_PLACEHOLDER; + + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED) { USE_OPLINE @@ -8185,24 +8206,11 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) && throw_op->extended_value & ZEND_FREE_ON_RETURN) { /* exceptions thrown because of loop var destruction on return/break/... * are logically thrown at the end of the foreach loop, so adjust the - * throw_op_num. + * throw_op_num to the final loop variable FREE. */ - const zend_live_range *range = find_live_range( - &EX(func)->op_array, throw_op_num, throw_op->op1.var); - /* free op1 of the corresponding RETURN */ - for (uint32_t i = throw_op_num; i < range->end; i++) { - if (EX(func)->op_array.opcodes[i].opcode == ZEND_FREE - || EX(func)->op_array.opcodes[i].opcode == ZEND_FE_FREE) { - /* pass */ - } else { - if (EX(func)->op_array.opcodes[i].opcode == ZEND_RETURN - && (EX(func)->op_array.opcodes[i].op1_type & (IS_VAR|IS_TMP_VAR))) { - zval_ptr_dtor(EX_VAR(EX(func)->op_array.opcodes[i].op1.var)); - } - break; - } - } - throw_op_num = range->end; + uint32_t new_throw_op_num = throw_op_num + throw_op->op2.opline_num; + cleanup_live_vars(execute_data, throw_op_num, new_throw_op_num); + throw_op_num = new_throw_op_num; } /* Find the innermost try/catch/finally the exception was thrown in */ @@ -8637,6 +8645,10 @@ ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY) zval *return_value = EX_VAR(EX(func)->op_array.opcodes[Z_OPLINE_NUM_P(fast_call)].op2.var); zval_ptr_dtor(return_value); + /* Clear return value in case we hit both DISCARD_EXCEPTION and + * zend_dispatch_try_catch_finally_helper, which will free the return + * value again. See OSS-Fuzz #438780145. */ + ZVAL_NULL(return_value); } /* cleanup delayed exception */ @@ -8858,6 +8870,39 @@ ZEND_VM_C_LABEL(type_check_resource): } } +ZEND_VM_HOT_HANDLER(211, ZEND_TYPE_ASSERT, CONST, ANY, NUM) +{ + USE_OPLINE + SAVE_OPLINE(); + + zval *value = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + + uint8_t actual_type = Z_TYPE_P(value); + uint8_t expected_type = opline->extended_value & 0xff; + /* Simple types can be checked directly. */ + if (UNEXPECTED(actual_type != expected_type)) { + zend_function *fbc; + { + zval *fname = (zval*)RT_CONSTANT(opline, opline->op1); + ZEND_ASSERT(Z_EXTRA_P(fname) != 0); + fbc = Z_FUNC(EG(function_table)->arData[Z_EXTRA_P(fname)].val); + ZEND_ASSERT(fbc->type != ZEND_USER_FUNCTION); + } + uint16_t argno = opline->extended_value >> 16; + zend_arg_info *arginfo = &fbc->common.arg_info[argno - 1]; + + if (!zend_check_type(&arginfo->type, value, /* is_return_type */ false, /* is_internal */ true)) { + zend_string *expected = zend_type_to_string(arginfo->type); + zend_argument_type_error_ex(fbc, argno, + "must be of type %s, %s given", + ZSTR_VAL(expected), zend_zval_value_name(value)); + zend_string_release(expected); + } + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + ZEND_VM_HOT_HANDLER(122, ZEND_DEFINED, CONST, ANY, CACHE_SLOT) { USE_OPLINE @@ -9762,6 +9807,45 @@ ZEND_VM_HANDLER(202, ZEND_CALLABLE_CONVERT, UNUSED, UNUSED, NUM|CACHE_SLOT) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(212, ZEND_CALLABLE_CONVERT_PARTIAL, CACHE_SLOT, CONST|UNUSED, NUM) +{ + USE_OPLINE + SAVE_OPLINE(); + + zend_execute_data *call = EX(call); + void **cache_slot = CACHE_ADDR(opline->op1.num); + zval *named_positions = GET_OP2_ZVAL_PTR(); + + zend_partial_create(EX_VAR(opline->result.var), + &call->This, call->func, + ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), + ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? + call->extra_named_params : NULL, + OP2_TYPE == IS_CONST ? Z_ARRVAL_P(named_positions) : NULL, + &EX(func)->op_array, opline, cache_slot, + opline->extended_value & ZEND_FCALL_USES_VARIADIC_PLACEHOLDER); + + if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_array_release(call->extra_named_params); + } + + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + zend_free_trampoline(call->func); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { + OBJ_RELEASE(Z_OBJ(call->This)); + } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); + } + + EX(call) = call->prev_execute_data; + + zend_vm_stack_free_call_frame(call); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + ZEND_VM_HANDLER(208, ZEND_JMP_FRAMELESS, CONST, JMP_ADDR, NUM|CACHE_SLOT) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 801bf0ee69e0d..64e8a807e61c8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -307,6 +307,7 @@ static uint8_t zend_user_opcodes[256] = {0, }; #include "Zend/zend_vm_opcodes.h" +#include "Zend/zend_partial.h" #define SPEC_START_MASK 0x0000ffff #define SPEC_EXTRA_MASK 0xfffc0000 @@ -895,7 +896,7 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_static_prop_helper_ &prop_info, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC); if (UNEXPECTED(!prop)) { - ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); + ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS) || (type == BP_VAR_UNSET)); prop = &EG(uninitialized_zval); } else if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) @@ -3398,24 +3399,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_HANDLE_EXCEPT && throw_op->extended_value & ZEND_FREE_ON_RETURN) { /* exceptions thrown because of loop var destruction on return/break/... * are logically thrown at the end of the foreach loop, so adjust the - * throw_op_num. + * throw_op_num to the final loop variable FREE. */ - const zend_live_range *range = find_live_range( - &EX(func)->op_array, throw_op_num, throw_op->op1.var); - /* free op1 of the corresponding RETURN */ - for (uint32_t i = throw_op_num; i < range->end; i++) { - if (EX(func)->op_array.opcodes[i].opcode == ZEND_FREE - || EX(func)->op_array.opcodes[i].opcode == ZEND_FE_FREE) { - /* pass */ - } else { - if (EX(func)->op_array.opcodes[i].opcode == ZEND_RETURN - && (EX(func)->op_array.opcodes[i].op1_type & (IS_VAR|IS_TMP_VAR))) { - zval_ptr_dtor(EX_VAR(EX(func)->op_array.opcodes[i].op1.var)); - } - break; - } - } - throw_op_num = range->end; + uint32_t new_throw_op_num = throw_op_num + throw_op->op2.opline_num; + cleanup_live_vars(execute_data, throw_op_num, new_throw_op_num); + throw_op_num = new_throw_op_num; } /* Find the innermost try/catch/finally the exception was thrown in */ @@ -3511,6 +3499,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_DISCARD_EXCEP zval *return_value = EX_VAR(EX(func)->op_array.opcodes[Z_OPLINE_NUM_P(fast_call)].op2.var); zval_ptr_dtor(return_value); + /* Clear return value in case we hit both DISCARD_EXCEPTION and + * zend_dispatch_try_catch_finally_helper, which will free the return + * value again. See OSS-Fuzz #438780145. */ + ZVAL_NULL(return_value); } /* cleanup delayed exception */ @@ -4255,6 +4247,45 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_R ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + SAVE_OPLINE(); + + zend_execute_data *call = EX(call); + void **cache_slot = CACHE_ADDR(opline->op1.num); + zval *named_positions = RT_CONSTANT(opline, opline->op2); + + zend_partial_create(EX_VAR(opline->result.var), + &call->This, call->func, + ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), + ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? + call->extra_named_params : NULL, + IS_CONST == IS_CONST ? Z_ARRVAL_P(named_positions) : NULL, + &EX(func)->op_array, opline, cache_slot, + opline->extended_value & ZEND_FCALL_USES_VARIADIC_PLACEHOLDER); + + if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_array_release(call->extra_named_params); + } + + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + zend_free_trampoline(call->func); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { + OBJ_RELEASE(Z_OBJ(call->This)); + } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); + } + + EX(call) = call->prev_execute_data; + + zend_vm_stack_free_call_frame(call); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -4399,6 +4430,45 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_RECV_VARIADIC ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + SAVE_OPLINE(); + + zend_execute_data *call = EX(call); + void **cache_slot = CACHE_ADDR(opline->op1.num); + zval *named_positions = NULL; + + zend_partial_create(EX_VAR(opline->result.var), + &call->This, call->func, + ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), + ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? + call->extra_named_params : NULL, + IS_UNUSED == IS_CONST ? Z_ARRVAL_P(named_positions) : NULL, + &EX(func)->op_array, opline, cache_slot, + opline->extended_value & ZEND_FCALL_USES_VARIADIC_PLACEHOLDER); + + if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_array_release(call->extra_named_params); + } + + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + zend_free_trampoline(call->func); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { + OBJ_RELEASE(Z_OBJ(call->This)); + } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); + } + + EX(call) = call->prev_execute_data; + + zend_vm_stack_free_call_frame(call); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5134,10 +5204,8 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); HANDLE_EXCEPTION(); @@ -5151,7 +5219,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_CATCH_SPEC_CO SAVE_OPLINE(); /* Check whether an exception has been thrown, if not, jump over code */ - zend_exception_restore(); if (EG(exception) == NULL) { ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0); } @@ -6129,6 +6196,39 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ } } +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_TYPE_ASSERT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + SAVE_OPLINE(); + + zval *value = get_zval_ptr_undef(opline->op2_type, opline->op2, BP_VAR_R); + + uint8_t actual_type = Z_TYPE_P(value); + uint8_t expected_type = opline->extended_value & 0xff; + /* Simple types can be checked directly. */ + if (UNEXPECTED(actual_type != expected_type)) { + zend_function *fbc; + { + zval *fname = (zval*)RT_CONSTANT(opline, opline->op1); + ZEND_ASSERT(Z_EXTRA_P(fname) != 0); + fbc = Z_FUNC(EG(function_table)->arData[Z_EXTRA_P(fname)].val); + ZEND_ASSERT(fbc->type != ZEND_USER_FUNCTION); + } + uint16_t argno = opline->extended_value >> 16; + zend_arg_info *arginfo = &fbc->common.arg_info[argno - 1]; + + if (!zend_check_type(&arginfo->type, value, /* is_return_type */ false, /* is_internal */ true)) { + zend_string *expected = zend_type_to_string(arginfo->type); + zend_argument_type_error_ex(fbc, argno, + "must be of type %s, %s given", + ZSTR_VAL(expected), zend_zval_value_name(value)); + zend_string_release(expected); + } + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_DEFINED_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -15729,10 +15829,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_THROW_SPEC_TM } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); HANDLE_EXCEPTION(); } @@ -36091,6 +36189,30 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_CHECK_FUNC_AR ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zval *arg; + + if (IS_CONST == IS_CONST) { + /* Named placeholder */ + USE_OPLINE + SAVE_OPLINE(); + zend_string *arg_name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); + uint32_t arg_num; + arg = zend_handle_named_arg(&EX(call), arg_name, &arg_num, CACHE_ADDR(opline->result.num)); + if (UNEXPECTED(!arg)) { + HANDLE_EXCEPTION(); + } + } else { + /* Positional placeholder */ + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + } + + Z_TYPE_INFO_P(arg) = _IS_PLACEHOLDER; + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -38856,6 +38978,30 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_C ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zval *arg; + + if (IS_UNUSED == IS_CONST) { + /* Named placeholder */ + USE_OPLINE + SAVE_OPLINE(); + zend_string *arg_name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); + uint32_t arg_num; + arg = zend_handle_named_arg(&EX(call), arg_name, &arg_num, CACHE_ADDR(opline->result.num)); + if (UNEXPECTED(!arg)) { + HANDLE_EXCEPTION(); + } + } else { + /* Positional placeholder */ + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + } + + Z_TYPE_INFO_P(arg) = _IS_PLACEHOLDER; + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -41910,10 +42056,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_THROW_SPEC_CV } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); HANDLE_EXCEPTION(); @@ -59066,24 +59210,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_HANDLE_EXCEPTION_S && throw_op->extended_value & ZEND_FREE_ON_RETURN) { /* exceptions thrown because of loop var destruction on return/break/... * are logically thrown at the end of the foreach loop, so adjust the - * throw_op_num. + * throw_op_num to the final loop variable FREE. */ - const zend_live_range *range = find_live_range( - &EX(func)->op_array, throw_op_num, throw_op->op1.var); - /* free op1 of the corresponding RETURN */ - for (uint32_t i = throw_op_num; i < range->end; i++) { - if (EX(func)->op_array.opcodes[i].opcode == ZEND_FREE - || EX(func)->op_array.opcodes[i].opcode == ZEND_FE_FREE) { - /* pass */ - } else { - if (EX(func)->op_array.opcodes[i].opcode == ZEND_RETURN - && (EX(func)->op_array.opcodes[i].op1_type & (IS_VAR|IS_TMP_VAR))) { - zval_ptr_dtor(EX_VAR(EX(func)->op_array.opcodes[i].op1.var)); - } - break; - } - } - throw_op_num = range->end; + uint32_t new_throw_op_num = throw_op_num + throw_op->op2.opline_num; + cleanup_live_vars(execute_data, throw_op_num, new_throw_op_num); + throw_op_num = new_throw_op_num; } /* Find the innermost try/catch/finally the exception was thrown in */ @@ -59179,6 +59310,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DISCARD_EXCEPTION_ zval *return_value = EX_VAR(EX(func)->op_array.opcodes[Z_OPLINE_NUM_P(fast_call)].op2.var); zval_ptr_dtor(return_value); + /* Clear return value in case we hit both DISCARD_EXCEPTION and + * zend_dispatch_try_catch_finally_helper, which will free the return + * value again. See OSS-Fuzz #438780145. */ + ZVAL_NULL(return_value); } /* cleanup delayed exception */ @@ -59923,6 +60058,45 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_RECV_I ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + SAVE_OPLINE(); + + zend_execute_data *call = EX(call); + void **cache_slot = CACHE_ADDR(opline->op1.num); + zval *named_positions = RT_CONSTANT(opline, opline->op2); + + zend_partial_create(EX_VAR(opline->result.var), + &call->This, call->func, + ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), + ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? + call->extra_named_params : NULL, + IS_CONST == IS_CONST ? Z_ARRVAL_P(named_positions) : NULL, + &EX(func)->op_array, opline, cache_slot, + opline->extended_value & ZEND_FCALL_USES_VARIADIC_PLACEHOLDER); + + if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_array_release(call->extra_named_params); + } + + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + zend_free_trampoline(call->func); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { + OBJ_RELEASE(Z_OBJ(call->This)); + } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); + } + + EX(call) = call->prev_execute_data; + + zend_vm_stack_free_call_frame(call); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -60067,6 +60241,45 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_RECV_VARIADIC_SPEC ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + SAVE_OPLINE(); + + zend_execute_data *call = EX(call); + void **cache_slot = CACHE_ADDR(opline->op1.num); + zval *named_positions = NULL; + + zend_partial_create(EX_VAR(opline->result.var), + &call->This, call->func, + ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1), + ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS ? + call->extra_named_params : NULL, + IS_UNUSED == IS_CONST ? Z_ARRVAL_P(named_positions) : NULL, + &EX(func)->op_array, opline, cache_slot, + opline->extended_value & ZEND_FCALL_USES_VARIADIC_PLACEHOLDER); + + if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_array_release(call->extra_named_params); + } + + if ((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + zend_free_trampoline(call->func); + } + + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { + OBJ_RELEASE(Z_OBJ(call->This)); + } else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func)); + } + + EX(call) = call->prev_execute_data; + + zend_vm_stack_free_call_frame(call); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -60802,10 +61015,8 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_THROW } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); HANDLE_EXCEPTION(); @@ -60819,7 +61030,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CATCH_SPEC_CONST_T SAVE_OPLINE(); /* Check whether an exception has been thrown, if not, jump over code */ - zend_exception_restore(); if (EG(exception) == NULL) { ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0); } @@ -61797,6 +62007,39 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_TYPE_ } } +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_TYPE_ASSERT_SPEC_CONST_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + SAVE_OPLINE(); + + zval *value = get_zval_ptr_undef(opline->op2_type, opline->op2, BP_VAR_R); + + uint8_t actual_type = Z_TYPE_P(value); + uint8_t expected_type = opline->extended_value & 0xff; + /* Simple types can be checked directly. */ + if (UNEXPECTED(actual_type != expected_type)) { + zend_function *fbc; + { + zval *fname = (zval*)RT_CONSTANT(opline, opline->op1); + ZEND_ASSERT(Z_EXTRA_P(fname) != 0); + fbc = Z_FUNC(EG(function_table)->arData[Z_EXTRA_P(fname)].val); + ZEND_ASSERT(fbc->type != ZEND_USER_FUNCTION); + } + uint16_t argno = opline->extended_value >> 16; + zend_arg_info *arginfo = &fbc->common.arg_info[argno - 1]; + + if (!zend_check_type(&arginfo->type, value, /* is_return_type */ false, /* is_internal */ true)) { + zend_string *expected = zend_type_to_string(arginfo->type); + zend_argument_type_error_ex(fbc, argno, + "must be of type %s, %s given", + ZSTR_VAL(expected), zend_zval_value_name(value)); + zend_string_release(expected); + } + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_DEFINED_SPEC_CONST_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -71295,10 +71538,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_THROW_SPEC_TMPVAR_ } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); HANDLE_EXCEPTION(); } @@ -91557,6 +91798,30 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CHECK_FUNC_ARG_SPE ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zval *arg; + + if (IS_CONST == IS_CONST) { + /* Named placeholder */ + USE_OPLINE + SAVE_OPLINE(); + zend_string *arg_name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); + uint32_t arg_num; + arg = zend_handle_named_arg(&EX(call), arg_name, &arg_num, CACHE_ADDR(opline->result.num)); + if (UNEXPECTED(!arg)) { + HANDLE_EXCEPTION(); + } + } else { + /* Positional placeholder */ + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + } + + Z_TYPE_INFO_P(arg) = _IS_PLACEHOLDER; + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -94322,6 +94587,30 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_CHECK_ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zval *arg; + + if (IS_UNUSED == IS_CONST) { + /* Named placeholder */ + USE_OPLINE + SAVE_OPLINE(); + zend_string *arg_name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); + uint32_t arg_num; + arg = zend_handle_named_arg(&EX(call), arg_name, &arg_num, CACHE_ADDR(opline->result.num)); + if (UNEXPECTED(!arg)) { + HANDLE_EXCEPTION(); + } + } else { + /* Positional placeholder */ + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + } + + Z_TYPE_INFO_P(arg) = _IS_PLACEHOLDER; + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_UNUSED_UNUSED_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -97376,10 +97665,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_THROW_SPEC_CV_TAIL } } while (0); - zend_exception_save(); Z_TRY_ADDREF_P(value); zend_throw_exception_object(value); - zend_exception_restore(); HANDLE_EXCEPTION(); @@ -112181,7 +112468,7 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_static_prop_helper_ &prop_info, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC); if (UNEXPECTED(!prop)) { - ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); + ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS) || (type == BP_VAR_UNSET)); prop = &EG(uninitialized_zval); } else if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) @@ -115257,6 +115544,17 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_JMP_FRAMELESS_SPEC_CONST_LABEL, (void*)&&ZEND_INIT_PARENT_PROPERTY_HOOK_CALL_SPEC_CONST_UNUSED_LABEL, (void*)&&ZEND_DECLARE_ATTRIBUTED_CONST_SPEC_CONST_CONST_LABEL, + (void*)&&ZEND_TYPE_ASSERT_SPEC_CONST_LABEL, + (void*)&&ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_LABEL, + (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_INIT_FCALL_OFFSET_SPEC_CONST_LABEL, (void*)&&ZEND_RECV_NOTYPE_SPEC_LABEL, (void*)&&ZEND_NULL_LABEL, @@ -116666,6 +116964,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_RECV_INIT_SPEC_CONST) HYBRID_BREAK(); + HYBRID_CASE(ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST): + VM_TRACE(ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST) + ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST) + HYBRID_BREAK(); HYBRID_CASE(ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR): VM_TRACE(ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR) ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -116681,6 +116984,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_RECV_VARIADIC_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_RECV_VARIADIC_SPEC_UNUSED) HYBRID_BREAK(); + HYBRID_CASE(ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED): + VM_TRACE(ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED) + ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED) + HYBRID_BREAK(); HYBRID_CASE(ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED): VM_TRACE(ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED) ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -117010,6 +117318,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_TYPE_CHECK_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_TYPE_CHECK_SPEC_CONST) HYBRID_BREAK(); + HYBRID_CASE(ZEND_TYPE_ASSERT_SPEC_CONST): + VM_TRACE(ZEND_TYPE_ASSERT_SPEC_CONST) + ZEND_TYPE_ASSERT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_TYPE_ASSERT_SPEC_CONST) + HYBRID_BREAK(); HYBRID_CASE(ZEND_DEFINED_SPEC_CONST): VM_TRACE(ZEND_DEFINED_SPEC_CONST) ZEND_DEFINED_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -120128,6 +120441,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_CHECK_FUNC_ARG_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_CHECK_FUNC_ARG_SPEC_UNUSED_CONST) HYBRID_BREAK(); + HYBRID_CASE(ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST): + VM_TRACE(ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST) + ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST) + HYBRID_BREAK(); HYBRID_CASE(ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST): VM_TRACE(ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST) ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -120313,6 +120631,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_CHECK_UNDEF_ARGS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); VM_TRACE_OP_END(ZEND_CHECK_UNDEF_ARGS_SPEC_UNUSED_UNUSED) HYBRID_BREAK(); + HYBRID_CASE(ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED): + VM_TRACE(ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED) + ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + VM_TRACE_OP_END(ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED) + HYBRID_BREAK(); HYBRID_CASE(ZEND_NEW_SPEC_UNUSED_UNUSED): VM_TRACE(ZEND_NEW_SPEC_UNUSED_UNUSED) ZEND_NEW_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -124508,6 +124831,17 @@ void zend_vm_init(void) ZEND_JMP_FRAMELESS_SPEC_CONST_HANDLER, ZEND_INIT_PARENT_PROPERTY_HOOK_CALL_SPEC_CONST_UNUSED_HANDLER, ZEND_DECLARE_ATTRIBUTED_CONST_SPEC_CONST_CONST_HANDLER, + ZEND_TYPE_ASSERT_SPEC_CONST_HANDLER, + ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_HANDLER, + ZEND_NULL_HANDLER, ZEND_INIT_FCALL_OFFSET_SPEC_CONST_HANDLER, ZEND_RECV_NOTYPE_SPEC_HANDLER, ZEND_NULL_HANDLER, @@ -128005,6 +128339,17 @@ void zend_vm_init(void) ZEND_JMP_FRAMELESS_SPEC_CONST_TAILCALL_HANDLER, ZEND_INIT_PARENT_PROPERTY_HOOK_CALL_SPEC_CONST_UNUSED_TAILCALL_HANDLER, ZEND_DECLARE_ATTRIBUTED_CONST_SPEC_CONST_CONST_TAILCALL_HANDLER, + ZEND_TYPE_ASSERT_SPEC_CONST_TAILCALL_HANDLER, + ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST_TAILCALL_HANDLER, + ZEND_NULL_TAILCALL_HANDLER, + ZEND_NULL_TAILCALL_HANDLER, + ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED_TAILCALL_HANDLER, + ZEND_NULL_TAILCALL_HANDLER, + ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST_TAILCALL_HANDLER, + ZEND_NULL_TAILCALL_HANDLER, + ZEND_NULL_TAILCALL_HANDLER, + ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED_TAILCALL_HANDLER, + ZEND_NULL_TAILCALL_HANDLER, ZEND_INIT_FCALL_OFFSET_SPEC_CONST_TAILCALL_HANDLER, ZEND_RECV_NOTYPE_SPEC_TAILCALL_HANDLER, ZEND_NULL_TAILCALL_HANDLER, @@ -128973,7 +129318,7 @@ void zend_vm_init(void) 1255, 1256 | SPEC_RULE_OP1, 1261 | SPEC_RULE_OP1, - 3493, + 3504, 1266 | SPEC_RULE_OP1, 1271 | SPEC_RULE_OP1, 1276 | SPEC_RULE_OP2, @@ -129007,7 +129352,7 @@ void zend_vm_init(void) 1559 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 1584 | SPEC_RULE_OP1, 1589, - 3493, + 3504, 1590 | SPEC_RULE_OP1, 1595 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 1620 | SPEC_RULE_OP1 | SPEC_RULE_OP2, @@ -129139,51 +129484,51 @@ void zend_vm_init(void) 2575, 2576, 2577, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, - 3493, + 2578, + 2579 | SPEC_RULE_OP2, + 2584 | SPEC_RULE_OP2, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, + 3504, }; #if 0 #elif (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) @@ -129360,7 +129705,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2586 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2597 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -129368,7 +129713,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2611 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2622 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -129376,7 +129721,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2636 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2647 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; if (op->op1_type < op->op2_type) { zend_swap_operands(op); } @@ -129387,17 +129732,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2661 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2672 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2686 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2697 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2711 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 2722 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_MUL: @@ -129408,17 +129753,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2736 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2747 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2761 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2772 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2786 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 2797 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_IDENTICAL: @@ -129429,16 +129774,16 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2811 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2822 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2886 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2897 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op->op2_type == IS_CONST && (Z_TYPE_P(RT_CONSTANT(op, op->op2)) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(RT_CONSTANT(op, op->op2))) == 0)) { - spec = 3111 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 3122 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) { - spec = 3117 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 3128 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_NOT_IDENTICAL: @@ -129449,16 +129794,16 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2961 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2972 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3036 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 3047 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op->op2_type == IS_CONST && (Z_TYPE_P(RT_CONSTANT(op, op->op2)) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(RT_CONSTANT(op, op->op2))) == 0)) { - spec = 3114 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 3125 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) { - spec = 3122 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + spec = 3133 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_EQUAL: @@ -129469,12 +129814,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2811 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2822 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2886 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2897 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_NOT_EQUAL: @@ -129485,12 +129830,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 2961 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 2972 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3036 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + spec = 3047 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } break; case ZEND_IS_SMALLER: @@ -129498,12 +129843,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3127 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3138 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3202 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3213 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_IS_SMALLER_OR_EQUAL: @@ -129511,79 +129856,79 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3277 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3288 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3352 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3363 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_QM_ASSIGN: if (op1_info == MAY_BE_LONG) { - spec = 3439 | SPEC_RULE_OP1; + spec = 3450 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_DOUBLE) { - spec = 3444 | SPEC_RULE_OP1; + spec = 3455 | SPEC_RULE_OP1; } else if ((op->op1_type == IS_CONST) ? !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1)) : (!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))))) { - spec = 3449 | SPEC_RULE_OP1; + spec = 3460 | SPEC_RULE_OP1; } break; case ZEND_PRE_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3427 | SPEC_RULE_RETVAL; + spec = 3438 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 3429 | SPEC_RULE_RETVAL; + spec = 3440 | SPEC_RULE_RETVAL; } break; case ZEND_PRE_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3431 | SPEC_RULE_RETVAL; + spec = 3442 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 3433 | SPEC_RULE_RETVAL; + spec = 3444 | SPEC_RULE_RETVAL; } break; case ZEND_POST_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3435; + spec = 3446; } else if (op1_info == MAY_BE_LONG) { - spec = 3436; + spec = 3447; } break; case ZEND_POST_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 3437; + spec = 3448; } else if (op1_info == MAY_BE_LONG) { - spec = 3438; + spec = 3449; } break; case ZEND_JMP: if (OP_JMP_ADDR(op, op->op1) > op) { - spec = 2585; + spec = 2596; } break; case ZEND_INIT_FCALL: if (Z_EXTRA_P(RT_CONSTANT(op, op->op2)) != 0) { - spec = 2578; + spec = 2589; } break; case ZEND_RECV: if (op->op2.num == MAY_BE_ANY) { - spec = 2579; + spec = 2590; } break; case ZEND_SEND_VAL: if (op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3489; + spec = 3500; } break; case ZEND_SEND_VAR_EX: if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3484 | SPEC_RULE_OP1; + spec = 3495 | SPEC_RULE_OP1; } break; case ZEND_FE_FETCH_R: if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) { - spec = 3491 | SPEC_RULE_RETVAL; + spec = 3502 | SPEC_RULE_RETVAL; } break; case ZEND_FETCH_DIM_R: @@ -129591,22 +129936,22 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3454 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3465 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_SEND_VAL_EX: if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && op->op1_type == IS_CONST && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3490; + spec = 3501; } break; case ZEND_SEND_VAR: if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3479 | SPEC_RULE_OP1; + spec = 3490 | SPEC_RULE_OP1; } break; case ZEND_COUNT: if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_ARRAY) { - spec = 2580 | SPEC_RULE_OP1; + spec = 2591 | SPEC_RULE_OP1; } break; case ZEND_BW_OR: diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 53b1ac6baf0a3..d664d17be6074 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -1,4 +1,5 @@ #include "Zend/zend_vm_opcodes.h" +#include "Zend/zend_partial.h" {%DEFINES%} diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 4ecc44237500a..38c20b24da2e9 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -64,7 +64,7 @@ "ZEND_VM_OP_NUM" => 0x10, "ZEND_VM_OP_JMP_ADDR" => 0x20, "ZEND_VM_OP_TRY_CATCH" => 0x30, - // unused 0x40 + "ZEND_VM_OP_LOOP_END" => 0x40, "ZEND_VM_OP_THIS" => 0x50, "ZEND_VM_OP_NEXT" => 0x60, "ZEND_VM_OP_CLASS_FETCH" => 0x70, @@ -112,6 +112,7 @@ "NUM" => ZEND_VM_OP_NUM, "JMP_ADDR" => ZEND_VM_OP_JMP_ADDR, "TRY_CATCH" => ZEND_VM_OP_TRY_CATCH, + "LOOP_END" => ZEND_VM_OP_LOOP_END, "THIS" => ZEND_VM_OP_THIS, "NEXT" => ZEND_VM_OP_NEXT, "CLASS_FETCH" => ZEND_VM_OP_CLASS_FETCH, diff --git a/Zend/zend_vm_handlers.h b/Zend/zend_vm_handlers.h index 33d951141550e..30ab98fcb7ee2 100644 --- a/Zend/zend_vm_handlers.h +++ b/Zend/zend_vm_handlers.h @@ -1373,508 +1373,513 @@ _(2575, ZEND_JMP_FRAMELESS_SPEC_CONST) \ _(2576, ZEND_INIT_PARENT_PROPERTY_HOOK_CALL_SPEC_CONST_UNUSED) \ _(2577, ZEND_DECLARE_ATTRIBUTED_CONST_SPEC_CONST_CONST) \ - _(2578, ZEND_INIT_FCALL_OFFSET_SPEC_CONST) \ - _(2579, ZEND_RECV_NOTYPE_SPEC) \ - _(2581, ZEND_COUNT_ARRAY_SPEC_TMPVAR_UNUSED) \ - _(2582, ZEND_COUNT_ARRAY_SPEC_TMPVAR_UNUSED) \ - _(2584, ZEND_COUNT_ARRAY_SPEC_CV_UNUSED) \ - _(2585, ZEND_JMP_FORWARD_SPEC) \ - _(2591, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2592, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2593, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2595, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2596, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2597, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2598, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2600, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2606, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2607, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2578, ZEND_TYPE_ASSERT_SPEC_CONST) \ + _(2579, ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_CONST) \ + _(2582, ZEND_CALLABLE_CONVERT_PARTIAL_SPEC_UNUSED) \ + _(2584, ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_CONST) \ + _(2587, ZEND_SEND_PLACEHOLDER_SPEC_UNUSED_UNUSED) \ + _(2589, ZEND_INIT_FCALL_OFFSET_SPEC_CONST) \ + _(2590, ZEND_RECV_NOTYPE_SPEC) \ + _(2592, ZEND_COUNT_ARRAY_SPEC_TMPVAR_UNUSED) \ + _(2593, ZEND_COUNT_ARRAY_SPEC_TMPVAR_UNUSED) \ + _(2595, ZEND_COUNT_ARRAY_SPEC_CV_UNUSED) \ + _(2596, ZEND_JMP_FORWARD_SPEC) \ + _(2602, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2603, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2604, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2606, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2607, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2608, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2610, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2616, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2617, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2618, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2620, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2621, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2622, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2623, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2625, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2631, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ - _(2632, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2609, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2611, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2617, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2618, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2619, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2621, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2627, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ + _(2628, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2629, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2631, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2632, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ _(2633, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2635, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2641, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2642, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2643, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2645, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2646, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2647, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2648, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2650, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2656, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2657, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2634, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2636, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2642, ZEND_ADD_LONG_SPEC_TMPVARCV_CONST) \ + _(2643, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2644, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2646, ZEND_ADD_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2652, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2653, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2654, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2656, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2657, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2658, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2660, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2662, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ - _(2663, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ - _(2665, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ - _(2666, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2667, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2668, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2670, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2671, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2672, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2673, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2675, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2681, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2682, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2659, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2661, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2667, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2668, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2669, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2671, ZEND_ADD_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2673, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2674, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2676, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV) \ + _(2677, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2678, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2679, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2681, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2682, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2683, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2685, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2687, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ - _(2688, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ - _(2690, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ - _(2691, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2692, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2693, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2695, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2696, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2697, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2698, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2700, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2706, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ - _(2707, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2684, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2686, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2692, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2693, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2694, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2696, ZEND_SUB_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2698, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2699, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2701, ZEND_SUB_LONG_SPEC_CONST_TMPVARCV) \ + _(2702, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ + _(2703, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2704, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2706, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2707, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ _(2708, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2710, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2712, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(2713, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(2715, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(2716, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2717, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2718, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2720, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2721, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2722, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2723, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2725, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2731, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2732, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2709, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2711, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2717, ZEND_SUB_LONG_SPEC_TMPVARCV_CONST) \ + _(2718, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2719, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2721, ZEND_SUB_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2723, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2724, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2726, ZEND_SUB_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(2727, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2728, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2729, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2731, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2732, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2733, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2735, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2741, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2742, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2743, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2745, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2746, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2747, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2748, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2750, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2756, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ - _(2757, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2734, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2736, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2742, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2743, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2744, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2746, ZEND_SUB_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2752, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2753, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2754, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2756, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2757, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ _(2758, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2760, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ - _(2766, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2767, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2768, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2770, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2771, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2772, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2773, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2775, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2781, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ - _(2782, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2759, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2761, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2767, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_CONST) \ + _(2768, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2769, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2771, ZEND_MUL_LONG_NO_OVERFLOW_SPEC_TMPVARCV_TMPVARCV) \ + _(2777, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ + _(2778, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2779, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2781, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2782, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ _(2783, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2785, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2791, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2792, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2793, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2795, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2796, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2797, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2798, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2800, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2806, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2807, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2784, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2786, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2792, ZEND_MUL_LONG_SPEC_TMPVARCV_CONST) \ + _(2793, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2794, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2796, ZEND_MUL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2802, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2803, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2804, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2806, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2807, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ _(2808, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2810, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2826, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2827, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2828, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2829, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2830, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2831, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2832, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2833, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2834, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2838, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2839, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2840, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2841, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2842, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2843, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2844, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2845, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2846, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2847, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2848, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2849, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2853, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2854, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2855, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2871, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2872, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2873, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2874, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2875, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2876, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2877, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2878, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2879, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2883, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2884, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2885, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2901, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2902, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2903, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2904, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2905, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2906, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2907, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2908, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2909, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2913, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2914, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2915, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2916, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2917, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2918, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2919, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2920, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2921, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2922, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2923, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2924, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2928, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2929, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2930, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2946, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(2947, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2948, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2949, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2950, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2951, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2952, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2953, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2954, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2958, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(2959, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2960, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2976, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2977, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2978, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2979, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2980, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2981, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2982, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2983, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2984, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2988, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2989, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2990, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2991, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(2992, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(2993, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(2994, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2995, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2996, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(2997, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(2998, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(2999, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3003, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3004, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3005, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3021, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3022, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3023, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3024, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3025, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3026, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3027, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3028, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3029, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3033, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3034, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3035, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3051, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3052, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3053, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3054, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3055, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3056, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3057, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3058, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3059, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3063, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3064, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3065, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3066, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3067, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3068, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3069, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3070, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3071, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3072, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3073, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3074, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3078, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3079, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3080, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3096, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3097, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3098, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3099, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3100, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3101, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3102, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3103, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3104, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3108, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3109, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3110, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3111, ZEND_IS_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST) \ - _(3112, ZEND_IS_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3113, ZEND_IS_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3114, ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST) \ - _(3115, ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3116, ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3117, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ - _(3121, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CV) \ - _(3122, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ - _(3126, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CV) \ - _(3130, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ - _(3131, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3132, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3133, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ - _(3134, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3135, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3139, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ - _(3140, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3141, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3142, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3143, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3144, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3145, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3146, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3147, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3148, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3149, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3150, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3154, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3155, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3156, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3157, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3158, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3159, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3160, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3161, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3162, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3163, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3164, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3165, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3169, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3170, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3171, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3187, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ - _(3188, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3189, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3190, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3191, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3192, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3193, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3194, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3195, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3199, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3200, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3201, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3205, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3206, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3207, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3208, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3209, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3210, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3214, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3215, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3216, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3217, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3218, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3219, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3220, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3221, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3222, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3223, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3224, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3225, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3229, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3230, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3231, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3232, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3233, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3234, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3235, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3236, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3237, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3238, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3239, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3240, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3244, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3245, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3246, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3262, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3263, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3264, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3265, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3266, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3267, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3268, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3269, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3270, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3274, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3275, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3276, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3280, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ - _(3281, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3282, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3283, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ - _(3284, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3285, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3289, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ - _(3290, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3291, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3292, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3293, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3294, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3295, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3296, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3297, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3298, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3299, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3300, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3304, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3305, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3306, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3307, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3308, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3309, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3310, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3311, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3312, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3313, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3314, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3315, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3319, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3320, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3321, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3337, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ - _(3338, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3339, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3340, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3341, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3342, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3343, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3344, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3345, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3349, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ - _(3350, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3351, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3355, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3356, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3357, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3358, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3359, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3360, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3364, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ - _(3365, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ - _(3366, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ - _(3367, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3368, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3369, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3370, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3371, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3372, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3373, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3374, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3375, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3379, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3380, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3381, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3382, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3383, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3384, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3385, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3386, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3387, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3388, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3389, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3390, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3394, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3395, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3396, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3412, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ - _(3413, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ - _(3414, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ - _(3415, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3416, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3417, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3418, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3419, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3420, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3424, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ - _(3425, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ - _(3426, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ - _(3427, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ - _(3428, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ - _(3429, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_UNUSED) \ - _(3430, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_USED) \ - _(3431, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ - _(3432, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ - _(3433, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_UNUSED) \ - _(3434, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_USED) \ - _(3435, ZEND_POST_INC_LONG_NO_OVERFLOW_SPEC_CV) \ - _(3436, ZEND_POST_INC_LONG_SPEC_CV) \ - _(3437, ZEND_POST_DEC_LONG_NO_OVERFLOW_SPEC_CV) \ - _(3438, ZEND_POST_DEC_LONG_SPEC_CV) \ - _(3439, ZEND_QM_ASSIGN_LONG_SPEC_CONST) \ - _(3440, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ - _(3441, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ - _(3443, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ - _(3444, ZEND_QM_ASSIGN_DOUBLE_SPEC_CONST) \ - _(3445, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ - _(3446, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ - _(3448, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ - _(3449, ZEND_QM_ASSIGN_NOREF_SPEC_CONST) \ - _(3450, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3451, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3453, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ - _(3455, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3456, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3458, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ - _(3459, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ - _(3460, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3461, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3463, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3464, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ - _(3465, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3466, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3468, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ - _(3474, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) \ - _(3475, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3476, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3478, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ - _(3481, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ - _(3483, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ - _(3486, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ - _(3488, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ - _(3489, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ - _(3490, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ - _(3491, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ - _(3492, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ - _(3492+1, ZEND_NULL) + _(2809, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2811, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2817, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2818, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2819, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2821, ZEND_MUL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2837, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2838, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2839, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2840, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2841, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2842, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2843, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2844, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2845, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2849, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2850, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2851, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2852, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2853, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2854, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2855, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2856, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2857, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2858, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2859, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2860, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2864, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2865, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2866, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2882, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2883, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2884, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2885, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2886, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2887, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2888, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2889, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2890, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2894, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2895, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2896, ZEND_IS_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2912, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2913, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2914, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2915, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2916, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2917, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2918, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2919, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2920, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2924, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2925, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2926, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2927, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2928, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2929, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2930, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2931, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2932, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2933, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2934, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2935, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2939, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2940, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2941, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2957, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(2958, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2959, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2960, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2961, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2962, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2963, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2964, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2965, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2969, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(2970, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2971, ZEND_IS_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2987, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(2988, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(2989, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(2990, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2991, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2992, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2993, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(2994, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(2995, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(2999, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3000, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3001, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3002, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3003, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3004, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3005, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3006, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3007, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3008, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3009, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3010, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3014, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3015, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3016, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3032, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3033, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3034, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3035, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3036, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3037, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3038, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3039, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3040, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3044, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3045, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3046, ZEND_IS_NOT_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3062, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3063, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3064, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3065, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3066, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3067, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3068, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3069, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3070, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3074, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3075, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3076, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3077, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3078, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3079, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3080, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3081, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3082, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3083, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3084, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3085, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3089, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3090, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3091, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3107, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3108, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3109, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3110, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3111, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3112, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3113, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3114, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3115, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3119, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3120, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3121, ZEND_IS_NOT_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3122, ZEND_IS_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST) \ + _(3123, ZEND_IS_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3124, ZEND_IS_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3125, ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST) \ + _(3126, ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3127, ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3128, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ + _(3132, ZEND_IS_IDENTICAL_NOTHROW_SPEC_CV_CV) \ + _(3133, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CONST) \ + _(3137, ZEND_IS_NOT_IDENTICAL_NOTHROW_SPEC_CV_CV) \ + _(3141, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ + _(3142, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3143, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3144, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ + _(3145, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3146, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3150, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV) \ + _(3151, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3152, ZEND_IS_SMALLER_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3153, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3154, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3155, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3156, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3157, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3158, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3159, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3160, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3161, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3165, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3166, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3167, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3168, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3169, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3170, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3171, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3172, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3173, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3174, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3175, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3176, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3180, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3181, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3182, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3198, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST) \ + _(3199, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3200, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3201, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3202, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3203, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3204, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3205, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3206, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3210, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3211, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3212, ZEND_IS_SMALLER_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3216, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3217, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3218, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3219, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3220, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3221, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3225, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3226, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3227, ZEND_IS_SMALLER_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3228, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3229, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3230, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3231, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3232, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3233, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3234, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3235, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3236, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3240, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3241, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3242, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3243, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3244, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3245, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3246, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3247, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3248, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3249, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3250, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3251, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3255, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3256, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3257, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3273, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3274, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3275, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3276, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3277, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3278, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3279, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3280, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3281, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3285, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3286, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3287, ZEND_IS_SMALLER_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3291, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ + _(3292, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3293, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3294, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ + _(3295, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3296, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3300, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV) \ + _(3301, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3302, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3303, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3304, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3305, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3306, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3307, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3308, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3309, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3310, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3311, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3315, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3316, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3317, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3318, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3319, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3320, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3321, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3322, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3323, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3324, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3325, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3326, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3330, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3331, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3332, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3348, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST) \ + _(3349, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3350, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3351, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3352, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3353, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3354, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3355, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3356, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3360, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV) \ + _(3361, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3362, ZEND_IS_SMALLER_OR_EQUAL_LONG_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3366, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3367, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3368, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3369, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3370, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3371, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3375, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV) \ + _(3376, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPZ) \ + _(3377, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_CONST_TMPVARCV_JMPNZ) \ + _(3378, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3379, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3380, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3381, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3382, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3383, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3384, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3385, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3386, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3390, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3391, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3392, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3393, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3394, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3395, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3396, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3397, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3398, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3399, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3400, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3401, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3405, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3406, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3407, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3423, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST) \ + _(3424, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPZ) \ + _(3425, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_CONST_JMPNZ) \ + _(3426, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3427, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3428, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3429, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3430, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3431, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3435, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV) \ + _(3436, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPZ) \ + _(3437, ZEND_IS_SMALLER_OR_EQUAL_DOUBLE_SPEC_TMPVARCV_TMPVARCV_JMPNZ) \ + _(3438, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ + _(3439, ZEND_PRE_INC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ + _(3440, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_UNUSED) \ + _(3441, ZEND_PRE_INC_LONG_SPEC_CV_RETVAL_USED) \ + _(3442, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_UNUSED) \ + _(3443, ZEND_PRE_DEC_LONG_NO_OVERFLOW_SPEC_CV_RETVAL_USED) \ + _(3444, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_UNUSED) \ + _(3445, ZEND_PRE_DEC_LONG_SPEC_CV_RETVAL_USED) \ + _(3446, ZEND_POST_INC_LONG_NO_OVERFLOW_SPEC_CV) \ + _(3447, ZEND_POST_INC_LONG_SPEC_CV) \ + _(3448, ZEND_POST_DEC_LONG_NO_OVERFLOW_SPEC_CV) \ + _(3449, ZEND_POST_DEC_LONG_SPEC_CV) \ + _(3450, ZEND_QM_ASSIGN_LONG_SPEC_CONST) \ + _(3451, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3452, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3454, ZEND_QM_ASSIGN_LONG_SPEC_TMPVARCV) \ + _(3455, ZEND_QM_ASSIGN_DOUBLE_SPEC_CONST) \ + _(3456, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3457, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3459, ZEND_QM_ASSIGN_DOUBLE_SPEC_TMPVARCV) \ + _(3460, ZEND_QM_ASSIGN_NOREF_SPEC_CONST) \ + _(3461, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ + _(3462, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ + _(3464, ZEND_QM_ASSIGN_NOREF_SPEC_TMPVARCV) \ + _(3466, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3467, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3469, ZEND_FETCH_DIM_R_INDEX_SPEC_CONST_TMPVARCV) \ + _(3470, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ + _(3471, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3472, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3474, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3475, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_CONST) \ + _(3476, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3477, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3479, ZEND_FETCH_DIM_R_INDEX_SPEC_TMPVAR_TMPVARCV) \ + _(3485, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_CONST) \ + _(3486, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3487, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3489, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ + _(3492, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ + _(3494, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ + _(3497, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ + _(3499, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ + _(3500, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ + _(3501, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ + _(3502, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ + _(3503, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ + _(3503+1, ZEND_NULL) diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 936a96e55e41f..b695b707d9a71 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -22,7 +22,7 @@ #include #include -static const char *zend_vm_opcodes_names[211] = { +static const char *zend_vm_opcodes_names[214] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -234,9 +234,12 @@ static const char *zend_vm_opcodes_names[211] = { "ZEND_JMP_FRAMELESS", "ZEND_INIT_PARENT_PROPERTY_HOOK_CALL", "ZEND_DECLARE_ATTRIBUTED_CONST", + "ZEND_TYPE_ASSERT", + "ZEND_CALLABLE_CONVERT_PARTIAL", + "ZEND_SEND_PLACEHOLDER", }; -static uint32_t zend_vm_opcodes_flags[211] = { +static uint32_t zend_vm_opcodes_flags[214] = { 0x00000000, 0x00000b0b, 0x00000b0b, @@ -307,7 +310,7 @@ static uint32_t zend_vm_opcodes_flags[211] = { 0x00001301, 0x0100a173, 0x01040300, - 0x00000005, + 0x00004005, 0x00186703, 0x00106703, 0x08000007, @@ -364,7 +367,7 @@ static uint32_t zend_vm_opcodes_flags[211] = { 0x00000103, 0x00002003, 0x03000001, - 0x00000005, + 0x00004005, 0x01000700, 0x00000000, 0x00000000, @@ -448,6 +451,9 @@ static uint32_t zend_vm_opcodes_flags[211] = { 0x01042003, 0x01001103, 0x00000303, + 0x01000003, + 0x010003a0, + 0x00000301, }; ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 287dec375f3a9..7a86c396bd864 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -86,6 +86,7 @@ typedef const void* zend_vm_opcode_handler_t; #define ZEND_VM_OP_NUM 0x00000010 #define ZEND_VM_OP_JMP_ADDR 0x00000020 #define ZEND_VM_OP_TRY_CATCH 0x00000030 +#define ZEND_VM_OP_LOOP_END 0x00000040 #define ZEND_VM_OP_THIS 0x00000050 #define ZEND_VM_OP_NEXT 0x00000060 #define ZEND_VM_OP_CLASS_FETCH 0x00000070 @@ -330,7 +331,10 @@ END_EXTERN_C() #define ZEND_JMP_FRAMELESS 208 #define ZEND_INIT_PARENT_PROPERTY_HOOK_CALL 209 #define ZEND_DECLARE_ATTRIBUTED_CONST 210 +#define ZEND_TYPE_ASSERT 211 +#define ZEND_CALLABLE_CONVERT_PARTIAL 212 +#define ZEND_SEND_PLACEHOLDER 213 -#define ZEND_VM_LAST_OPCODE 210 +#define ZEND_VM_LAST_OPCODE 213 #endif diff --git a/build/gen_stub.php b/build/gen_stub.php index acee1e6ca0981..9b1e829a50cb3 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2184,7 +2184,7 @@ public function getMethodSynopsisElement(DOMDocument $doc): ?DOMElement { $defaultValue = $arg->getDefaultValueAsMethodSynopsisString(); if ($defaultValue !== null) { $initializer = $doc->createElement('initializer'); - if (preg_match('/^[a-zA-Z_][a-zA-Z_0-9]*$/', $defaultValue)) { + if (preg_match('/^[a-zA-Z_][a-zA-Z_0-9\:\\\\]*$/', $defaultValue)) { $constant = $doc->createElement('constant', $defaultValue); $initializer->appendChild($constant); } else { @@ -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/configure.ac b/configure.ac index 77fc8c89cdf40..40bd29ae99a78 100644 --- a/configure.ac +++ b/configure.ac @@ -1779,6 +1779,7 @@ PHP_ADD_SOURCES([Zend], m4_normalize([ zend_observer.c zend_opcode.c zend_operators.c + zend_partial.c zend_property_hooks.c zend_ptr_stack.c zend_signal.c diff --git a/docs/source/miscellaneous/writing-tests.rst b/docs/source/miscellaneous/writing-tests.rst index 4c46dad638b6c..8c4e0535763cc 100644 --- a/docs/source/miscellaneous/writing-tests.rst +++ b/docs/source/miscellaneous/writing-tests.rst @@ -1389,7 +1389,7 @@ Example 1 (full): :ref:`sample002.phpt` ``--EXPECT_EXTERNAL--`` ----------------------- -**Description:** Similar to to ``--EXPECT--`` section, but just stating a filename where to load the +**Description:** Similar to ``--EXPECT--`` section, but just stating a filename where to load the expected output from. **Required:** One of the ``EXPECT`` type sections is required. @@ -1526,7 +1526,7 @@ Example 2 (full): :ref:`sample020.phpt` ``--EXPECTF_EXTERNAL--`` ------------------------ -**Description:** Similar to to ``--EXPECTF--`` section, but like the ``--EXPECT_EXTERNAL--`` section +**Description:** Similar to ``--EXPECTF--`` section, but like the ``--EXPECT_EXTERNAL--`` section just stating a filename where to load the expected output from. **Required:** One of the ``EXPECT`` type sections is required. @@ -1607,7 +1607,7 @@ Example 3 (snippet): ``--EXPECTREGEX_EXTERNAL--`` ---------------------------- -**Description:** Similar to to ``--EXPECTREGEX--`` section, but like the ``--EXPECT_EXTERNAL--`` +**Description:** Similar to ``--EXPECTREGEX--`` section, but like the ``--EXPECT_EXTERNAL--`` section just stating a filename where to load the expected output from. **Required:** One of the ``EXPECT`` type sections is required. diff --git a/ext/curl/curl.stub.php b/ext/curl/curl.stub.php index c9cda9c0d4b0c..aadab8cb0b0d3 100644 --- a/ext/curl/curl.stub.php +++ b/ext/curl/curl.stub.php @@ -3133,7 +3133,7 @@ */ const CURLOPT_TLS13_CIPHERS = UNKNOWN; -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ /** * @var int * @cvalue CURLOPT_DOH_URL @@ -3769,7 +3769,7 @@ function curl_getinfo(CurlHandle $handle, ?int $option = null): mixed {} /** @refcount 1 */ function curl_init(?string $url = null): CurlHandle|false {} -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ function curl_upkeep(CurlHandle $handle): bool {} #endif diff --git a/ext/curl/curl_arginfo.h b/ext/curl/curl_arginfo.h index 7e4a5789d599a..25fac2948bf2e 100644 --- a/ext/curl/curl_arginfo.h +++ b/ext/curl/curl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 2a2772e99deea07c0bc148e9715e6a960230cf4d */ + * Stub hash: 10ebdc94560ed19ecd6b61a11b3dab5d32989d66 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_close, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, handle, CurlHandle, 0) @@ -49,7 +49,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_curl_init, 0, 0, CurlHandle, ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, url, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_upkeep, 0, 1, _IS_BOOL, 0) ZEND_ARG_OBJ_INFO(0, handle, CurlHandle, 0) ZEND_END_ARG_INFO() @@ -157,7 +157,7 @@ ZEND_FUNCTION(curl_exec); ZEND_FUNCTION(curl_file_create); ZEND_FUNCTION(curl_getinfo); ZEND_FUNCTION(curl_init); -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ ZEND_FUNCTION(curl_upkeep); #endif ZEND_FUNCTION(curl_multi_add_handle); @@ -196,7 +196,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(curl_file_create, arginfo_curl_file_create) ZEND_FE(curl_getinfo, arginfo_curl_getinfo) ZEND_FE(curl_init, arginfo_curl_init) -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ ZEND_FE(curl_upkeep, arginfo_curl_upkeep) #endif ZEND_FE(curl_multi_add_handle, arginfo_curl_multi_add_handle) @@ -834,7 +834,7 @@ static void register_curl_symbols(int module_number) REGISTER_LONG_CONSTANT("CURLOPT_DISALLOW_USERNAME_IN_URL", CURLOPT_DISALLOW_USERNAME_IN_URL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_PROXY_TLS13_CIPHERS", CURLOPT_PROXY_TLS13_CIPHERS, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_TLS13_CIPHERS", CURLOPT_TLS13_CIPHERS, CONST_PERSISTENT); -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ REGISTER_LONG_CONSTANT("CURLOPT_DOH_URL", CURLOPT_DOH_URL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_UPKEEP_INTERVAL_MS", CURLOPT_UPKEEP_INTERVAL_MS, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLOPT_UPLOAD_BUFFERSIZE", CURLOPT_UPLOAD_BUFFERSIZE, CONST_PERSISTENT); diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 5f69beac8e936..62a55b4df5287 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -221,6 +221,54 @@ static zend_object *curl_clone_obj(zend_object *object); php_curl *init_curl_handle_into_zval(zval *curl); static inline zend_result build_mime_structure_from_hash(php_curl *ch, zval *zpostfields); +struct php_curl_feature { + const char *name; + int bitmask; +}; + +/* To update on each new cURL release using src/main.c in cURL sources */ +static const struct php_curl_feature php_curl_features[] = { + { "AsynchDNS", CURL_VERSION_ASYNCHDNS }, + { "CharConv", CURL_VERSION_CONV }, + { "Debug", CURL_VERSION_DEBUG }, + { "GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE }, + { "IDN", CURL_VERSION_IDN }, + { "IPv6", CURL_VERSION_IPV6 }, + { "krb4", CURL_VERSION_KERBEROS4 }, + { "Largefile", CURL_VERSION_LARGEFILE }, + { "libz", CURL_VERSION_LIBZ }, + { "NTLM", CURL_VERSION_NTLM }, + { "NTLMWB", CURL_VERSION_NTLM_WB }, + { "SPNEGO", CURL_VERSION_SPNEGO }, + { "SSL", CURL_VERSION_SSL }, + { "SSPI", CURL_VERSION_SSPI }, + { "TLS-SRP", CURL_VERSION_TLSAUTH_SRP }, + { "HTTP2", CURL_VERSION_HTTP2 }, + { "GSSAPI", CURL_VERSION_GSSAPI }, + { "KERBEROS5", CURL_VERSION_KERBEROS5 }, + { "UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS }, + { "PSL", CURL_VERSION_PSL }, + { "HTTPS_PROXY", CURL_VERSION_HTTPS_PROXY }, + { "MULTI_SSL", CURL_VERSION_MULTI_SSL }, + { "BROTLI", CURL_VERSION_BROTLI }, +#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ + { "ALTSVC", CURL_VERSION_ALTSVC }, +#endif +#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */ + { "HTTP3", CURL_VERSION_HTTP3 }, +#endif +#if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */ + { "UNICODE", CURL_VERSION_UNICODE }, + { "ZSTD", CURL_VERSION_ZSTD }, +#endif +#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ + { "HSTS", CURL_VERSION_HSTS }, +#endif +#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ + { "GSASL", CURL_VERSION_GSASL }, +#endif +}; + /* {{{ PHP_INI_BEGIN */ PHP_INI_BEGIN() PHP_INI_ENTRY("curl.cainfo", "", PHP_INI_SYSTEM, NULL) @@ -237,69 +285,17 @@ PHP_MINFO_FUNCTION(curl) d = curl_version_info(CURLVERSION_NOW); php_info_print_table_start(); - php_info_print_table_row(2, "cURL support", "enabled"); + php_info_print_table_row(2, "cURL support", "enabled"); php_info_print_table_row(2, "cURL Information", d->version); snprintf(str, sizeof(str), "%d", d->age); php_info_print_table_row(2, "Age", str); - /* To update on each new cURL release using src/main.c in cURL sources */ - /* make sure to sync this list with curl_version as well */ if (d->features) { - struct feat { - const char *name; - int bitmask; - }; - unsigned int i; - static const struct feat feats[] = { - {"AsynchDNS", CURL_VERSION_ASYNCHDNS}, - {"CharConv", CURL_VERSION_CONV}, - {"Debug", CURL_VERSION_DEBUG}, - {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE}, - {"IDN", CURL_VERSION_IDN}, - {"IPv6", CURL_VERSION_IPV6}, - {"krb4", CURL_VERSION_KERBEROS4}, - {"Largefile", CURL_VERSION_LARGEFILE}, - {"libz", CURL_VERSION_LIBZ}, - {"NTLM", CURL_VERSION_NTLM}, - {"NTLMWB", CURL_VERSION_NTLM_WB}, - {"SPNEGO", CURL_VERSION_SPNEGO}, - {"SSL", CURL_VERSION_SSL}, - {"SSPI", CURL_VERSION_SSPI}, - {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}, - {"HTTP2", CURL_VERSION_HTTP2}, - {"GSSAPI", CURL_VERSION_GSSAPI}, - {"KERBEROS5", CURL_VERSION_KERBEROS5}, - {"UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS}, - {"PSL", CURL_VERSION_PSL}, - {"HTTPS_PROXY", CURL_VERSION_HTTPS_PROXY}, - {"MULTI_SSL", CURL_VERSION_MULTI_SSL}, - {"BROTLI", CURL_VERSION_BROTLI}, -#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ - {"ALTSVC", CURL_VERSION_ALTSVC}, -#endif -#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */ - {"HTTP3", CURL_VERSION_HTTP3}, -#endif -#if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */ - {"UNICODE", CURL_VERSION_UNICODE}, - {"ZSTD", CURL_VERSION_ZSTD}, -#endif -#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ - {"HSTS", CURL_VERSION_HSTS}, -#endif -#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ - {"GSASL", CURL_VERSION_GSASL}, -#endif - {NULL, 0} - }; - php_info_print_table_row(1, "Features"); - for(i=0; ifeatures & feats[i].bitmask ? "Yes" : "No"); - } + for (i = 0; i < sizeof(php_curl_features) / sizeof(php_curl_features[0]); i++) { + php_info_print_table_row(2, php_curl_features[i].name, d->features & php_curl_features[i].bitmask ? "Yes" : "No"); } } @@ -483,6 +479,7 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n) zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.prereq); } #endif + #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ if (ZEND_FCC_INITIALIZED(curl->handlers.sshhostkey)) { zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.sshhostkey); @@ -685,8 +682,8 @@ static int curl_prereqfunction(void *clientp, char *conn_primary_ip, char *conn_ // gets called. Return CURL_PREREQFUNC_OK immediately in this case to avoid // zend_call_known_fcc() with an uninitialized FCC. if (!ZEND_FCC_INITIALIZED(ch->handlers.prereq)) { - return rval; - } + return rval; + } #if PHP_CURL_DEBUG fprintf(stderr, "curl_prereqfunction() called\n"); @@ -881,42 +878,42 @@ static int curl_debug(CURL *handle, curl_infotype type, char *data, size_t size, { php_curl *ch = (php_curl *)clientp; - #if PHP_CURL_DEBUG - fprintf(stderr, "curl_debug() called\n"); - fprintf(stderr, "type = %d, data = %s\n", type, data); - #endif +#if PHP_CURL_DEBUG + fprintf(stderr, "curl_debug() called\n"); + fprintf(stderr, "type = %d, data = %s\n", type, data); +#endif // Implicitly store the headers for compatibility with CURLINFO_HEADER_OUT // used as a Curl option. Previously, setting CURLINFO_HEADER_OUT set curl_debug // as the CURLOPT_DEBUGFUNCTION and stored the debug data when type is set to // CURLINFO_HEADER_OUT. For backward compatibility, we now store the headers // but also call the user-callback function if available. - if (type == CURLINFO_HEADER_OUT) { - if (ch->header.str) { - zend_string_release_ex(ch->header.str, 0); - } - ch->header.str = zend_string_init(data, size, 0); - } + if (type == CURLINFO_HEADER_OUT) { + if (ch->header.str) { + zend_string_release_ex(ch->header.str, 0); + } + ch->header.str = zend_string_init(data, size, 0); + } - if (!ZEND_FCC_INITIALIZED(ch->handlers.debug)) { - return 0; - } + if (!ZEND_FCC_INITIALIZED(ch->handlers.debug)) { + return 0; + } - zval args[3]; + zval args[3]; - GC_ADDREF(&ch->std); - ZVAL_OBJ(&args[0], &ch->std); - ZVAL_LONG(&args[1], type); - ZVAL_STRINGL(&args[2], data, size); + GC_ADDREF(&ch->std); + ZVAL_OBJ(&args[0], &ch->std); + ZVAL_LONG(&args[1], type); + ZVAL_STRINGL(&args[2], data, size); - ch->in_callback = true; - zend_call_known_fcc(&ch->handlers.debug, NULL, /* param_count */ 3, args, /* named_params */ NULL); - ch->in_callback = false; + ch->in_callback = true; + zend_call_known_fcc(&ch->handlers.debug, NULL, /* param_count */ 3, args, /* named_params */ NULL); + ch->in_callback = false; - zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&args[2]); + zval_ptr_dtor(&args[0]); + zval_ptr_dtor(&args[2]); - return 0; + return 0; } /* }}} */ @@ -969,62 +966,12 @@ PHP_FUNCTION(curl_version) CAAL("features", d->features); /* Add an array of features */ { - struct feat { - const char *name; - int bitmask; - }; - unsigned int i; zval feature_list; - array_init(&feature_list); - - /* Sync this list with PHP_MINFO_FUNCTION(curl) as well */ - static const struct feat feats[] = { - {"AsynchDNS", CURL_VERSION_ASYNCHDNS}, - {"CharConv", CURL_VERSION_CONV}, - {"Debug", CURL_VERSION_DEBUG}, - {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE}, - {"IDN", CURL_VERSION_IDN}, - {"IPv6", CURL_VERSION_IPV6}, - {"krb4", CURL_VERSION_KERBEROS4}, - {"Largefile", CURL_VERSION_LARGEFILE}, - {"libz", CURL_VERSION_LIBZ}, - {"NTLM", CURL_VERSION_NTLM}, - {"NTLMWB", CURL_VERSION_NTLM_WB}, - {"SPNEGO", CURL_VERSION_SPNEGO}, - {"SSL", CURL_VERSION_SSL}, - {"SSPI", CURL_VERSION_SSPI}, - {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}, - {"HTTP2", CURL_VERSION_HTTP2}, - {"GSSAPI", CURL_VERSION_GSSAPI}, - {"KERBEROS5", CURL_VERSION_KERBEROS5}, - {"UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS}, - {"PSL", CURL_VERSION_PSL}, - {"HTTPS_PROXY", CURL_VERSION_HTTPS_PROXY}, - {"MULTI_SSL", CURL_VERSION_MULTI_SSL}, - {"BROTLI", CURL_VERSION_BROTLI}, -#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ - {"ALTSVC", CURL_VERSION_ALTSVC}, -#endif -#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */ - {"HTTP3", CURL_VERSION_HTTP3}, -#endif -#if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */ - {"UNICODE", CURL_VERSION_UNICODE}, - {"ZSTD", CURL_VERSION_ZSTD}, -#endif -#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ - {"HSTS", CURL_VERSION_HSTS}, -#endif -#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ - {"GSASL", CURL_VERSION_GSASL}, -#endif - }; - for(i = 0; i < sizeof(feats) / sizeof(feats[0]); i++) { - if (feats[i].name) { - add_assoc_bool(&feature_list, feats[i].name, d->features & feats[i].bitmask ? true : false); - } + array_init_size(&feature_list, sizeof(php_curl_features) / sizeof(php_curl_features[0])); + for (i = 0; i < sizeof(php_curl_features) / sizeof(php_curl_features[0]); i++) { + add_assoc_bool(&feature_list, php_curl_features[i].name, d->features & php_curl_features[i].bitmask ? true : false); } CAAZ("feature_list", &feature_list); @@ -1753,7 +1700,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue case CURLOPT_DNS_SHUFFLE_ADDRESSES: case CURLOPT_HAPROXYPROTOCOL: case CURLOPT_DISALLOW_USERNAME_IN_URL: -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ case CURLOPT_UPKEEP_INTERVAL_MS: case CURLOPT_UPLOAD_BUFFERSIZE: #endif @@ -1917,7 +1864,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue case CURLOPT_DNS_LOCAL_IP6: case CURLOPT_XOAUTH2_BEARER: case CURLOPT_UNIX_SOCKET_PATH: -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ case CURLOPT_DOH_URL: #endif #if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ @@ -2222,9 +2169,9 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue case CURLINFO_HEADER_OUT: if (ZEND_FCC_INITIALIZED(ch->handlers.debug)) { - zend_value_error("CURLINFO_HEADER_OUT option must not be set when the CURLOPT_DEBUGFUNCTION option is set"); - return FAILURE; - } + zend_value_error("CURLINFO_HEADER_OUT option must not be set when the CURLOPT_DEBUGFUNCTION option is set"); + return FAILURE; + } if (zend_is_true(zvalue)) { curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, curl_debug); @@ -2931,11 +2878,13 @@ static void _php_curl_reset_handlers(php_curl *ch) if (ZEND_FCC_INITIALIZED(ch->handlers.debug)) { zend_fcc_dtor(&ch->handlers.debug); } + #if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */ if (ZEND_FCC_INITIALIZED(ch->handlers.prereq)) { zend_fcc_dtor(&ch->handlers.prereq); } #endif + #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ if (ZEND_FCC_INITIALIZED(ch->handlers.sshhostkey)) { zend_fcc_dtor(&ch->handlers.sshhostkey); @@ -3042,7 +2991,7 @@ PHP_FUNCTION(curl_pause) } /* }}} */ -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ +#if LIBCURL_VERSION_NUM >= 0x073e00 /* Available since 7.62.0 */ /* {{{ perform connection upkeep checks */ PHP_FUNCTION(curl_upkeep) { @@ -3061,5 +3010,5 @@ PHP_FUNCTION(curl_upkeep) RETURN_BOOL(error == CURLE_OK); } -/*}}} */ +/* }}} */ #endif diff --git a/ext/curl/multi.c b/ext/curl/multi.c index a16155759aed4..3e6142466e98d 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -398,7 +398,6 @@ PHP_FUNCTION(curl_multi_strerror) } /* }}} */ - static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_headers, struct curl_pushheaders *push_headers, void *userp) /* {{{ */ { php_curl *ch; diff --git a/ext/date/lib/parse_date.c b/ext/date/lib/parse_date.c index 1fb7fb15ec01a..65d99806642db 100644 --- a/ext/date/lib/parse_date.c +++ b/ext/date/lib/parse_date.c @@ -1,4 +1,4 @@ -/* Generated by re2c 1.0.3 on Mon Sep 15 10:40:13 2025 */ +/* Generated by re2c 1.0.3 on Wed Jan 14 14:21:53 2026 */ #line 1 "ext/date/lib/parse_date.re" /* * The MIT License (MIT) @@ -171,7 +171,14 @@ static const timelib_tz_lookup_table timelib_timezone_utc[] = { }; #if defined(_POSIX_TZNAME_MAX) -# define MAX_ABBR_LEN _POSIX_TZNAME_MAX +/* Solaris exposes _POSIX_TZNAME_MAX = 3 unless _XPG6 is defined. + * That is too small for real-world timezone abbreviations ("EDT", "CEST", ...). + */ +# if defined(__sun__) && _POSIX_TZNAME_MAX < 6 +# define MAX_ABBR_LEN 6 +# else +# define MAX_ABBR_LEN _POSIX_TZNAME_MAX +# endif #elif defined(TZNAME_MAX) # define MAX_ABBR_LEN TZNAME_MAX #else @@ -1021,11 +1028,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) std: s->tok = cursor; s->len = 0; -#line 1154 "ext/date/lib/parse_date.re" +#line 1161 "ext/date/lib/parse_date.re" -#line 1029 "ext/date/lib/parse_date.c" +#line 1036 "ext/date/lib/parse_date.c" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -1206,23 +1213,23 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(2, *YYCURSOR); ++YYCURSOR; YYDEBUG(3, *YYCURSOR); -#line 1987 "ext/date/lib/parse_date.re" +#line 1994 "ext/date/lib/parse_date.re" { s->pos = cursor; s->line++; goto std; } -#line 1215 "ext/date/lib/parse_date.c" +#line 1222 "ext/date/lib/parse_date.c" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; yy5: YYDEBUG(5, *YYCURSOR); -#line 1993 "ext/date/lib/parse_date.re" +#line 2000 "ext/date/lib/parse_date.re" { add_error(s, TIMELIB_ERR_UNEXPECTED_CHARACTER, "Unexpected character"); goto std; } -#line 1226 "ext/date/lib/parse_date.c" +#line 1233 "ext/date/lib/parse_date.c" yy6: YYDEBUG(6, *YYCURSOR); yyaccept = 0; @@ -1237,11 +1244,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy58; yy8: YYDEBUG(8, *YYCURSOR); -#line 1982 "ext/date/lib/parse_date.re" +#line 1989 "ext/date/lib/parse_date.re" { goto std; } -#line 1245 "ext/date/lib/parse_date.c" +#line 1252 "ext/date/lib/parse_date.c" yy9: YYDEBUG(9, *YYCURSOR); yych = *++YYCURSOR; @@ -1275,11 +1282,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(11, *YYCURSOR); ++YYCURSOR; YYDEBUG(12, *YYCURSOR); -#line 1977 "ext/date/lib/parse_date.re" +#line 1984 "ext/date/lib/parse_date.re" { goto std; } -#line 1283 "ext/date/lib/parse_date.c" +#line 1290 "ext/date/lib/parse_date.c" yy13: YYDEBUG(13, *YYCURSOR); yyaccept = 1; @@ -1780,7 +1787,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy20: YYDEBUG(20, *YYCURSOR); -#line 1892 "ext/date/lib/parse_date.re" +#line 1899 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("tzcorrection | tz"); @@ -1794,7 +1801,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIMEZONE; } -#line 1798 "ext/date/lib/parse_date.c" +#line 1805 "ext/date/lib/parse_date.c" yy21: YYDEBUG(21, *YYCURSOR); yych = *++YYCURSOR; @@ -3599,7 +3606,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy81: YYDEBUG(81, *YYCURSOR); -#line 1639 "ext/date/lib/parse_date.re" +#line 1646 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenoyearrev"); TIMELIB_INIT; @@ -3610,7 +3617,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 3614 "ext/date/lib/parse_date.c" +#line 3621 "ext/date/lib/parse_date.c" yy82: YYDEBUG(82, *YYCURSOR); yych = *++YYCURSOR; @@ -4125,7 +4132,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } if (yych == '.') goto yy289; YYDEBUG(114, *YYCURSOR); -#line 1214 "ext/date/lib/parse_date.re" +#line 1221 "ext/date/lib/parse_date.re" { timelib_ull i; @@ -4150,7 +4157,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 4154 "ext/date/lib/parse_date.c" +#line 4161 "ext/date/lib/parse_date.c" yy115: YYDEBUG(115, *YYCURSOR); ++YYCURSOR; @@ -5876,7 +5883,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy177: YYDEBUG(177, *YYCURSOR); -#line 1380 "ext/date/lib/parse_date.re" +#line 1387 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("timetiny24 | timeshort24 | timelong24 | iso8601long"); @@ -5903,7 +5910,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 5907 "ext/date/lib/parse_date.c" +#line 5914 "ext/date/lib/parse_date.c" yy178: YYDEBUG(178, *YYCURSOR); yyaccept = 4; @@ -6932,7 +6939,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy224: YYDEBUG(224, *YYCURSOR); -#line 1474 "ext/date/lib/parse_date.re" +#line 1481 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("americanshort | american"); @@ -6947,7 +6954,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AMERICAN; } -#line 6951 "ext/date/lib/parse_date.c" +#line 6958 "ext/date/lib/parse_date.c" yy225: YYDEBUG(225, *YYCURSOR); yyaccept = 5; @@ -7190,7 +7197,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy431; yy251: YYDEBUG(251, *YYCURSOR); -#line 1556 "ext/date/lib/parse_date.re" +#line 1563 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datefull"); @@ -7204,7 +7211,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL; } -#line 7208 "ext/date/lib/parse_date.c" +#line 7215 "ext/date/lib/parse_date.c" yy252: YYDEBUG(252, *YYCURSOR); yyaccept = 3; @@ -7318,7 +7325,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy440; yy260: YYDEBUG(260, *YYCURSOR); -#line 1961 "ext/date/lib/parse_date.re" +#line 1968 "ext/date/lib/parse_date.re" { timelib_ull i; DEBUG_OUTPUT("relative"); @@ -7333,7 +7340,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7337 "ext/date/lib/parse_date.c" +#line 7344 "ext/date/lib/parse_date.c" yy261: YYDEBUG(261, *YYCURSOR); yych = *++YYCURSOR; @@ -7779,7 +7786,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy471; yy290: YYDEBUG(290, *YYCURSOR); -#line 1240 "ext/date/lib/parse_date.re" +#line 1247 "ext/date/lib/parse_date.re" { timelib_sll i; timelib_ull us; @@ -7818,7 +7825,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7822 "ext/date/lib/parse_date.c" +#line 7829 "ext/date/lib/parse_date.c" yy291: YYDEBUG(291, *YYCURSOR); yych = *++YYCURSOR; @@ -7843,7 +7850,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy293: YYDEBUG(293, *YYCURSOR); -#line 1802 "ext/date/lib/parse_date.re" +#line 1809 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("ago"); TIMELIB_INIT; @@ -7863,7 +7870,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AGO; } -#line 7867 "ext/date/lib/parse_date.c" +#line 7874 "ext/date/lib/parse_date.c" yy294: YYDEBUG(294, *YYCURSOR); yyaccept = 7; @@ -7902,7 +7909,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy295: YYDEBUG(295, *YYCURSOR); -#line 1882 "ext/date/lib/parse_date.re" +#line 1889 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("monthtext"); TIMELIB_INIT; @@ -7911,7 +7918,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 7915 "ext/date/lib/parse_date.c" +#line 7922 "ext/date/lib/parse_date.c" yy296: YYDEBUG(296, *YYCURSOR); yyaccept = 7; @@ -8486,7 +8493,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy315: YYDEBUG(315, *YYCURSOR); -#line 1823 "ext/date/lib/parse_date.re" +#line 1830 "ext/date/lib/parse_date.re" { const timelib_relunit* relunit; DEBUG_OUTPUT("daytext"); @@ -8503,7 +8510,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEKDAY; } -#line 8507 "ext/date/lib/parse_date.c" +#line 8514 "ext/date/lib/parse_date.c" yy316: YYDEBUG(316, *YYCURSOR); yych = *++YYCURSOR; @@ -8771,7 +8778,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy325: YYDEBUG(325, *YYCURSOR); -#line 1625 "ext/date/lib/parse_date.re" +#line 1632 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datetextual | datenoyear"); @@ -8784,7 +8791,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 8788 "ext/date/lib/parse_date.c" +#line 8795 "ext/date/lib/parse_date.c" yy326: YYDEBUG(326, *YYCURSOR); yyaccept = 10; @@ -9478,7 +9485,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy351: YYDEBUG(351, *YYCURSOR); -#line 1171 "ext/date/lib/parse_date.re" +#line 1178 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("now"); TIMELIB_INIT; @@ -9486,7 +9493,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 9490 "ext/date/lib/parse_date.c" +#line 9497 "ext/date/lib/parse_date.c" yy352: YYDEBUG(352, *YYCURSOR); yyaccept = 2; @@ -10989,7 +10996,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy420: YYDEBUG(420, *YYCURSOR); -#line 1408 "ext/date/lib/parse_date.re" +#line 1415 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnunocolon"); TIMELIB_INIT; @@ -11011,7 +11018,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_GNU_NOCOLON; } -#line 11015 "ext/date/lib/parse_date.c" +#line 11022 "ext/date/lib/parse_date.c" yy421: YYDEBUG(421, *YYCURSOR); yyaccept = 13; @@ -11092,7 +11099,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy422: YYDEBUG(422, *YYCURSOR); -#line 1793 "ext/date/lib/parse_date.re" +#line 1800 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("year4"); TIMELIB_INIT; @@ -11100,7 +11107,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 11104 "ext/date/lib/parse_date.c" +#line 11111 "ext/date/lib/parse_date.c" yy423: YYDEBUG(423, *YYCURSOR); yyaccept = 3; @@ -11707,7 +11714,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(456, *YYCURSOR); ++YYCURSOR; YYDEBUG(457, *YYCURSOR); -#line 1342 "ext/date/lib/parse_date.re" +#line 1349 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12"); TIMELIB_INIT; @@ -11724,7 +11731,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME12; } -#line 11728 "ext/date/lib/parse_date.c" +#line 11735 "ext/date/lib/parse_date.c" yy458: YYDEBUG(458, *YYCURSOR); yych = *++YYCURSOR; @@ -13051,7 +13058,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy526: YYDEBUG(526, *YYCURSOR); -#line 1180 "ext/date/lib/parse_date.re" +#line 1187 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("noon"); TIMELIB_INIT; @@ -13062,7 +13069,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 13066 "ext/date/lib/parse_date.c" +#line 13073 "ext/date/lib/parse_date.c" yy527: YYDEBUG(527, *YYCURSOR); yyaccept = 2; @@ -14108,7 +14115,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy567: YYDEBUG(567, *YYCURSOR); -#line 1542 "ext/date/lib/parse_date.re" +#line 1549 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshort"); @@ -14121,7 +14128,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 14125 "ext/date/lib/parse_date.c" +#line 14132 "ext/date/lib/parse_date.c" yy568: YYDEBUG(568, *YYCURSOR); yyaccept = 15; @@ -14572,7 +14579,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy600: YYDEBUG(600, *YYCURSOR); -#line 1611 "ext/date/lib/parse_date.re" +#line 1618 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenodayrev"); @@ -14585,7 +14592,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 14589 "ext/date/lib/parse_date.c" +#line 14596 "ext/date/lib/parse_date.c" yy601: YYDEBUG(601, *YYCURSOR); yych = *++YYCURSOR; @@ -15960,7 +15967,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(696, *YYCURSOR); ++YYCURSOR; YYDEBUG(697, *YYCURSOR); -#line 1597 "ext/date/lib/parse_date.re" +#line 1604 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenoday"); @@ -15973,7 +15980,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 15977 "ext/date/lib/parse_date.c" +#line 15984 "ext/date/lib/parse_date.c" yy698: YYDEBUG(698, *YYCURSOR); yych = *++YYCURSOR; @@ -16534,7 +16541,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy722: YYDEBUG(722, *YYCURSOR); -#line 1192 "ext/date/lib/parse_date.re" +#line 1199 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("midnight | today"); TIMELIB_INIT; @@ -16543,7 +16550,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 16547 "ext/date/lib/parse_date.c" +#line 16554 "ext/date/lib/parse_date.c" yy723: YYDEBUG(723, *YYCURSOR); yych = *++YYCURSOR; @@ -16853,7 +16860,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy897; yy739: YYDEBUG(739, *YYCURSOR); -#line 1583 "ext/date/lib/parse_date.re" +#line 1590 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pointed date YY"); @@ -16866,7 +16873,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 16870 "ext/date/lib/parse_date.c" +#line 16877 "ext/date/lib/parse_date.c" yy740: YYDEBUG(740, *YYCURSOR); yyaccept = 15; @@ -16978,7 +16985,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy752: YYDEBUG(752, *YYCURSOR); -#line 1528 "ext/date/lib/parse_date.re" +#line 1535 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshorter"); @@ -16991,7 +16998,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 16995 "ext/date/lib/parse_date.c" +#line 17002 "ext/date/lib/parse_date.c" yy753: YYDEBUG(753, *YYCURSOR); yyaccept = 18; @@ -17240,7 +17247,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy777: YYDEBUG(777, *YYCURSOR); -#line 1454 "ext/date/lib/parse_date.re" +#line 1461 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("iso8601nocolon"); @@ -17259,7 +17266,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_NOCOLON; } -#line 17263 "ext/date/lib/parse_date.c" +#line 17270 "ext/date/lib/parse_date.c" yy778: YYDEBUG(778, *YYCURSOR); yyaccept = 19; @@ -18487,7 +18494,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy849: YYDEBUG(849, *YYCURSOR); -#line 1931 "ext/date/lib/parse_date.re" +#line 1938 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz"); @@ -18516,7 +18523,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 18520 "ext/date/lib/parse_date.c" +#line 18527 "ext/date/lib/parse_date.c" yy850: YYDEBUG(850, *YYCURSOR); yyaccept = 20; @@ -19560,7 +19567,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy926: YYDEBUG(926, *YYCURSOR); -#line 1689 "ext/date/lib/parse_date.re" +#line 1696 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgydotd"); @@ -19573,7 +19580,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_YEARDAY; } -#line 19577 "ext/date/lib/parse_date.c" +#line 19584 "ext/date/lib/parse_date.c" yy927: YYDEBUG(927, *YYCURSOR); yyaccept = 21; @@ -19827,7 +19834,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '7') goto yy1059; yy942: YYDEBUG(942, *YYCURSOR); -#line 1722 "ext/date/lib/parse_date.re" +#line 1729 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweek"); @@ -19845,7 +19852,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 19849 "ext/date/lib/parse_date.c" +#line 19856 "ext/date/lib/parse_date.c" yy943: YYDEBUG(943, *YYCURSOR); yych = *++YYCURSOR; @@ -20321,7 +20328,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy1094; yy982: YYDEBUG(982, *YYCURSOR); -#line 1865 "ext/date/lib/parse_date.re" +#line 1872 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -20337,7 +20344,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 20341 "ext/date/lib/parse_date.c" +#line 20348 "ext/date/lib/parse_date.c" yy983: YYDEBUG(983, *YYCURSOR); yych = *++YYCURSOR; @@ -20684,7 +20691,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1020, *YYCURSOR); ++YYCURSOR; YYDEBUG(1021, *YYCURSOR); -#line 1571 "ext/date/lib/parse_date.re" +#line 1578 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pointed date YYYY"); TIMELIB_INIT; @@ -20695,7 +20702,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 20699 "ext/date/lib/parse_date.c" +#line 20706 "ext/date/lib/parse_date.c" yy1022: YYDEBUG(1022, *YYCURSOR); ++YYCURSOR; @@ -20724,7 +20731,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1025: YYDEBUG(1025, *YYCURSOR); -#line 1502 "ext/date/lib/parse_date.re" +#line 1509 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("iso8601date2"); @@ -20737,7 +20744,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20741 "ext/date/lib/parse_date.c" +#line 20748 "ext/date/lib/parse_date.c" yy1026: YYDEBUG(1026, *YYCURSOR); yyaccept = 15; @@ -20957,7 +20964,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1043: YYDEBUG(1043, *YYCURSOR); -#line 1490 "ext/date/lib/parse_date.re" +#line 1497 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash"); TIMELIB_INIT; @@ -20968,7 +20975,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20972 "ext/date/lib/parse_date.c" +#line 20979 "ext/date/lib/parse_date.c" yy1044: YYDEBUG(1044, *YYCURSOR); yyaccept = 26; @@ -21083,7 +21090,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1048: YYDEBUG(1048, *YYCURSOR); -#line 1651 "ext/date/lib/parse_date.re" +#line 1658 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenocolon"); TIMELIB_INIT; @@ -21094,7 +21101,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NOCOLON; } -#line 21098 "ext/date/lib/parse_date.c" +#line 21105 "ext/date/lib/parse_date.c" yy1049: YYDEBUG(1049, *YYCURSOR); yych = *++YYCURSOR; @@ -21164,7 +21171,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1059, *YYCURSOR); ++YYCURSOR; YYDEBUG(1060, *YYCURSOR); -#line 1703 "ext/date/lib/parse_date.re" +#line 1710 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweekday"); @@ -21182,7 +21189,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 21186 "ext/date/lib/parse_date.c" +#line 21193 "ext/date/lib/parse_date.c" yy1061: YYDEBUG(1061, *YYCURSOR); yych = *++YYCURSOR; @@ -21245,7 +21252,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1143; yy1070: YYDEBUG(1070, *YYCURSOR); -#line 1741 "ext/date/lib/parse_date.re" +#line 1748 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextshort"); @@ -21258,7 +21265,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 21262 "ext/date/lib/parse_date.c" +#line 21269 "ext/date/lib/parse_date.c" yy1071: YYDEBUG(1071, *YYCURSOR); yych = *++YYCURSOR; @@ -21731,7 +21738,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1107: YYDEBUG(1107, *YYCURSOR); -#line 1202 "ext/date/lib/parse_date.re" +#line 1209 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("tomorrow"); TIMELIB_INIT; @@ -21742,7 +21749,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 21746 "ext/date/lib/parse_date.c" +#line 21753 "ext/date/lib/parse_date.c" yy1108: YYDEBUG(1108, *YYCURSOR); yyaccept = 28; @@ -22079,7 +22086,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1140, *YYCURSOR); ++YYCURSOR; YYDEBUG(1141, *YYCURSOR); -#line 1755 "ext/date/lib/parse_date.re" +#line 1762 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextreverse"); @@ -22092,7 +22099,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 22096 "ext/date/lib/parse_date.c" +#line 22103 "ext/date/lib/parse_date.c" yy1142: YYDEBUG(1142, *YYCURSOR); ++YYCURSOR; @@ -22136,7 +22143,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1145: YYDEBUG(1145, *YYCURSOR); -#line 1297 "ext/date/lib/parse_date.re" +#line 1304 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("backof | frontof"); TIMELIB_INIT; @@ -22158,7 +22165,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 22162 "ext/date/lib/parse_date.c" +#line 22169 "ext/date/lib/parse_date.c" yy1146: YYDEBUG(1146, *YYCURSOR); yyaccept = 29; @@ -22482,7 +22489,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1172: YYDEBUG(1172, *YYCURSOR); -#line 1841 "ext/date/lib/parse_date.re" +#line 1848 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -22505,7 +22512,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22509 "ext/date/lib/parse_date.c" +#line 22516 "ext/date/lib/parse_date.c" yy1173: YYDEBUG(1173, *YYCURSOR); yych = *++YYCURSOR; @@ -22517,7 +22524,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1175: YYDEBUG(1175, *YYCURSOR); -#line 1159 "ext/date/lib/parse_date.re" +#line 1166 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("yesterday"); TIMELIB_INIT; @@ -22528,7 +22535,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22532 "ext/date/lib/parse_date.c" +#line 22539 "ext/date/lib/parse_date.c" yy1176: YYDEBUG(1176, *YYCURSOR); yyaccept = 31; @@ -23021,7 +23028,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1222, *YYCURSOR); ++YYCURSOR; YYDEBUG(1223, *YYCURSOR); -#line 1907 "ext/date/lib/parse_date.re" +#line 1914 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12"); TIMELIB_INIT; @@ -23044,7 +23051,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 23048 "ext/date/lib/parse_date.c" +#line 23055 "ext/date/lib/parse_date.c" yy1224: YYDEBUG(1224, *YYCURSOR); yych = *++YYCURSOR; @@ -23546,7 +23553,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1268, *YYCURSOR); ++YYCURSOR; YYDEBUG(1269, *YYCURSOR); -#line 1320 "ext/date/lib/parse_date.re" +#line 1327 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -23567,7 +23574,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEK_DAY_OF_MONTH; } -#line 23571 "ext/date/lib/parse_date.c" +#line 23578 "ext/date/lib/parse_date.c" yy1270: YYDEBUG(1270, *YYCURSOR); yyaccept = 24; @@ -23614,7 +23621,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1273, *YYCURSOR); ++YYCURSOR; YYDEBUG(1274, *YYCURSOR); -#line 1280 "ext/date/lib/parse_date.re" +#line 1287 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("firstdayof | lastdayof"); TIMELIB_INIT; @@ -23630,12 +23637,12 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 23634 "ext/date/lib/parse_date.c" +#line 23641 "ext/date/lib/parse_date.c" yy1275: YYDEBUG(1275, *YYCURSOR); ++YYCURSOR; YYDEBUG(1276, *YYCURSOR); -#line 1516 "ext/date/lib/parse_date.re" +#line 1523 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601datex"); TIMELIB_INIT; @@ -23646,7 +23653,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 23650 "ext/date/lib/parse_date.c" +#line 23657 "ext/date/lib/parse_date.c" yy1277: YYDEBUG(1277, *YYCURSOR); yych = *++YYCURSOR; @@ -23749,7 +23756,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1290, *YYCURSOR); ++YYCURSOR; YYDEBUG(1291, *YYCURSOR); -#line 1360 "ext/date/lib/parse_date.re" +#line 1367 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("mssqltime"); TIMELIB_INIT; @@ -23768,7 +23775,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 23772 "ext/date/lib/parse_date.c" +#line 23779 "ext/date/lib/parse_date.c" yy1292: YYDEBUG(1292, *YYCURSOR); yych = *++YYCURSOR; @@ -24192,7 +24199,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1331; yy1329: YYDEBUG(1329, *YYCURSOR); -#line 1663 "ext/date/lib/parse_date.re" +#line 1670 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif"); @@ -24217,7 +24224,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_XMLRPC_SOAP; } -#line 24221 "ext/date/lib/parse_date.c" +#line 24228 "ext/date/lib/parse_date.c" yy1330: YYDEBUG(1330, *YYCURSOR); yych = *++YYCURSOR; @@ -24587,7 +24594,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= ':') goto yy1383; yy1375: YYDEBUG(1375, *YYCURSOR); -#line 1769 "ext/date/lib/parse_date.re" +#line 1776 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("clf"); @@ -24610,7 +24617,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 24614 "ext/date/lib/parse_date.c" +#line 24621 "ext/date/lib/parse_date.c" yy1376: YYDEBUG(1376, *YYCURSOR); yyaccept = 33; @@ -24842,7 +24849,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == ':') goto yy1286; goto yy1329; } -#line 1997 "ext/date/lib/parse_date.re" +#line 2004 "ext/date/lib/parse_date.re" } @@ -24863,10 +24870,10 @@ timelib_time *timelib_strtotime(const char *s, size_t len, timelib_error_contain in.errors->error_messages = NULL; if (len > 0) { - while (isspace(*s) && s < e) { + while (isspace((unsigned char)*s) && s < e) { s++; } - while (isspace(*e) && e > s) { + while (isspace((unsigned char)*e) && e > s) { e--; } } diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index c40a5c07c9aa1..ffb3e8e359137 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -169,7 +169,14 @@ static const timelib_tz_lookup_table timelib_timezone_utc[] = { }; #if defined(_POSIX_TZNAME_MAX) -# define MAX_ABBR_LEN _POSIX_TZNAME_MAX +/* Solaris exposes _POSIX_TZNAME_MAX = 3 unless _XPG6 is defined. + * That is too small for real-world timezone abbreviations ("EDT", "CEST", ...). + */ +# if defined(__sun__) && _POSIX_TZNAME_MAX < 6 +# define MAX_ABBR_LEN 6 +# else +# define MAX_ABBR_LEN _POSIX_TZNAME_MAX +# endif #elif defined(TZNAME_MAX) # define MAX_ABBR_LEN TZNAME_MAX #else @@ -2013,10 +2020,10 @@ timelib_time *timelib_strtotime(const char *s, size_t len, timelib_error_contain in.errors->error_messages = NULL; if (len > 0) { - while (isspace(*s) && s < e) { + while (isspace((unsigned char)*s) && s < e) { s++; } - while (isspace(*e) && e > s) { + while (isspace((unsigned char)*e) && e > s) { e--; } } diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index ef57a7ee783f0..acae8e32533db 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2025 Derick Rethans + * Copyright (c) 2015-2026 Derick Rethans * Copyright (c) 2018,2021 MongoDB, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -30,9 +30,9 @@ # include "timelib_config.h" #endif -#define TIMELIB_VERSION 202214 -#define TIMELIB_EXTENDED_VERSION 20221401 -#define TIMELIB_ASCII_VERSION "2022.14" +#define TIMELIB_VERSION 202215 +#define TIMELIB_EXTENDED_VERSION 20221501 +#define TIMELIB_ASCII_VERSION "2022.15" #include #include diff --git a/ext/date/lib/timezonedb.h b/ext/date/lib/timezonedb.h index a4cbb618799c8..1ad6aa2870c8a 100644 --- a/ext/date/lib/timezonedb.h +++ b/ext/date/lib/timezonedb.h @@ -118,495 +118,495 @@ const timelib_tzdb_index_entry timezonedb_idx_builtin[598] = { { (char*) "America/Eirunepe" , 0x00D1FE }, { (char*) "America/El_Salvador" , 0x00D3CD }, { (char*) "America/Ensenada" , 0x00D489 }, - { (char*) "America/Fort_Nelson" , 0x00D8CC }, - { (char*) "America/Fort_Wayne" , 0x00DE94 }, - { (char*) "America/Fortaleza" , 0x00E0B3 }, - { (char*) "America/Glace_Bay" , 0x00E2C9 }, - { (char*) "America/Godthab" , 0x00E660 }, - { (char*) "America/Goose_Bay" , 0x00EA31 }, - { (char*) "America/Grand_Turk" , 0x00F089 }, - { (char*) "America/Grenada" , 0x00F3EA }, - { (char*) "America/Guadeloupe" , 0x00F478 }, - { (char*) "America/Guatemala" , 0x00F506 }, - { (char*) "America/Guayaquil" , 0x00F5E6 }, - { (char*) "America/Guyana" , 0x00F6B7 }, - { (char*) "America/Halifax" , 0x00F778 }, - { (char*) "America/Havana" , 0x00FE2A }, - { (char*) "America/Hermosillo" , 0x010293 }, - { (char*) "America/Indiana/Indianapolis" , 0x0103A7 }, - { (char*) "America/Indiana/Knox" , 0x0105DF }, - { (char*) "America/Indiana/Marengo" , 0x0109F8 }, - { (char*) "America/Indiana/Petersburg" , 0x010C52 }, - { (char*) "America/Indiana/Tell_City" , 0x010F1C }, - { (char*) "America/Indiana/Vevay" , 0x011146 }, - { (char*) "America/Indiana/Vincennes" , 0x0112DD }, - { (char*) "America/Indiana/Winamac" , 0x011533 }, - { (char*) "America/Indianapolis" , 0x0117B0 }, - { (char*) "America/Inuvik" , 0x0119CF }, - { (char*) "America/Iqaluit" , 0x011D20 }, - { (char*) "America/Jamaica" , 0x01209C }, - { (char*) "America/Jujuy" , 0x0121FB }, - { (char*) "America/Juneau" , 0x0124B9 }, - { (char*) "America/Kentucky/Louisville" , 0x01289F }, - { (char*) "America/Kentucky/Monticello" , 0x012DA3 }, - { (char*) "America/Knox_IN" , 0x01318F }, - { (char*) "America/Kralendijk" , 0x013593 }, - { (char*) "America/La_Paz" , 0x013650 }, - { (char*) "America/Lima" , 0x013706 }, - { (char*) "America/Los_Angeles" , 0x01382D }, - { (char*) "America/Louisville" , 0x013D4E }, - { (char*) "America/Lower_Princes" , 0x014234 }, - { (char*) "America/Maceio" , 0x0142F1 }, - { (char*) "America/Managua" , 0x014503 }, - { (char*) "America/Manaus" , 0x014636 }, - { (char*) "America/Marigot" , 0x0147ED }, - { (char*) "America/Martinique" , 0x0148AA }, - { (char*) "America/Matamoros" , 0x014968 }, - { (char*) "America/Mazatlan" , 0x014B55 }, - { (char*) "America/Mendoza" , 0x014E45 }, - { (char*) "America/Menominee" , 0x015115 }, - { (char*) "America/Merida" , 0x0154D5 }, - { (char*) "America/Metlakatla" , 0x015780 }, - { (char*) "America/Mexico_City" , 0x0159ED }, - { (char*) "America/Miquelon" , 0x015D0C }, - { (char*) "America/Moncton" , 0x015F3E }, - { (char*) "America/Monterrey" , 0x016537 }, - { (char*) "America/Montevideo" , 0x01683E }, - { (char*) "America/Montreal" , 0x016C13 }, - { (char*) "America/Montserrat" , 0x0172D4 }, - { (char*) "America/Nassau" , 0x017362 }, - { (char*) "America/New_York" , 0x01775C }, - { (char*) "America/Nipigon" , 0x017E4C }, - { (char*) "America/Nome" , 0x01850D }, - { (char*) "America/Noronha" , 0x0188F5 }, - { (char*) "America/North_Dakota/Beulah" , 0x018AF5 }, - { (char*) "America/North_Dakota/Center" , 0x018F29 }, - { (char*) "America/North_Dakota/New_Salem" , 0x019328 }, - { (char*) "America/Nuuk" , 0x01972D }, - { (char*) "America/Ojinaga" , 0x019B0F }, - { (char*) "America/Panama" , 0x019E05 }, - { (char*) "America/Pangnirtung" , 0x019EA6 }, - { (char*) "America/Paramaribo" , 0x01A209 }, - { (char*) "America/Phoenix" , 0x01A2D0 }, - { (char*) "America/Port-au-Prince" , 0x01A3E4 }, - { (char*) "America/Port_of_Spain" , 0x01A625 }, - { (char*) "America/Porto_Acre" , 0x01A6B3 }, - { (char*) "America/Porto_Velho" , 0x01A861 }, - { (char*) "America/Puerto_Rico" , 0x01A9FF }, - { (char*) "America/Punta_Arenas" , 0x01AABC }, - { (char*) "America/Rainy_River" , 0x01AF9B }, - { (char*) "America/Rankin_Inlet" , 0x01B4B5 }, - { (char*) "America/Recife" , 0x01B7FE }, - { (char*) "America/Regina" , 0x01B9F8 }, - { (char*) "America/Resolute" , 0x01BC97 }, - { (char*) "America/Rio_Branco" , 0x01BFE1 }, - { (char*) "America/Rosario" , 0x01C193 }, - { (char*) "America/Santa_Isabel" , 0x01C463 }, - { (char*) "America/Santarem" , 0x01C8A6 }, - { (char*) "America/Santiago" , 0x01CA56 }, - { (char*) "America/Santo_Domingo" , 0x01CFB9 }, - { (char*) "America/Sao_Paulo" , 0x01D102 }, - { (char*) "America/Scoresbysund" , 0x01D4FC }, - { (char*) "America/Shiprock" , 0x01D8FD }, - { (char*) "America/Sitka" , 0x01DD1B }, - { (char*) "America/St_Barthelemy" , 0x01E0F6 }, - { (char*) "America/St_Johns" , 0x01E1B3 }, - { (char*) "America/St_Kitts" , 0x01E930 }, - { (char*) "America/St_Lucia" , 0x01E9BE }, - { (char*) "America/St_Thomas" , 0x01EA5F }, - { (char*) "America/St_Vincent" , 0x01EAED }, - { (char*) "America/Swift_Current" , 0x01EB8E }, - { (char*) "America/Tegucigalpa" , 0x01ED1C }, - { (char*) "America/Thule" , 0x01EDEA }, - { (char*) "America/Thunder_Bay" , 0x01EFCB }, - { (char*) "America/Tijuana" , 0x01F68C }, - { (char*) "America/Toronto" , 0x01FADE }, - { (char*) "America/Tortola" , 0x0201BD }, - { (char*) "America/Vancouver" , 0x02024B }, - { (char*) "America/Virgin" , 0x0207A2 }, - { (char*) "America/Whitehorse" , 0x02085F }, - { (char*) "America/Winnipeg" , 0x020C82 }, - { (char*) "America/Yakutat" , 0x0211B9 }, - { (char*) "America/Yellowknife" , 0x021587 }, - { (char*) "Antarctica/Casey" , 0x02195D }, - { (char*) "Antarctica/Davis" , 0x021A8D }, - { (char*) "Antarctica/DumontDUrville" , 0x021B63 }, - { (char*) "Antarctica/Macquarie" , 0x021C17 }, - { (char*) "Antarctica/Mawson" , 0x022003 }, - { (char*) "Antarctica/McMurdo" , 0x0220AD }, - { (char*) "Antarctica/Palmer" , 0x0223DF }, - { (char*) "Antarctica/Rothera" , 0x022768 }, - { (char*) "Antarctica/South_Pole" , 0x0227FF }, - { (char*) "Antarctica/Syowa" , 0x022C1E }, - { (char*) "Antarctica/Troll" , 0x022CB4 }, - { (char*) "Antarctica/Vostok" , 0x022D63 }, - { (char*) "Arctic/Longyearbyen" , 0x022E1F }, - { (char*) "Asia/Aden" , 0x0230EC }, - { (char*) "Asia/Almaty" , 0x02317D }, - { (char*) "Asia/Amman" , 0x023405 }, - { (char*) "Asia/Anadyr" , 0x0237B1 }, - { (char*) "Asia/Aqtau" , 0x023AB7 }, - { (char*) "Asia/Aqtobe" , 0x023D36 }, - { (char*) "Asia/Ashgabat" , 0x023FB6 }, - { (char*) "Asia/Ashkhabad" , 0x024139 }, - { (char*) "Asia/Atyrau" , 0x0242BC }, - { (char*) "Asia/Baghdad" , 0x024545 }, - { (char*) "Asia/Bahrain" , 0x0247C7 }, - { (char*) "Asia/Baku" , 0x024880 }, - { (char*) "Asia/Bangkok" , 0x024B74 }, - { (char*) "Asia/Barnaul" , 0x024C18 }, - { (char*) "Asia/Beirut" , 0x024F23 }, - { (char*) "Asia/Bishkek" , 0x02520B }, - { (char*) "Asia/Brunei" , 0x025481 }, - { (char*) "Asia/Calcutta" , 0x025527 }, - { (char*) "Asia/Chita" , 0x02560F }, - { (char*) "Asia/Choibalsan" , 0x02591D }, - { (char*) "Asia/Chongqing" , 0x025B7B }, - { (char*) "Asia/Chungking" , 0x025D10 }, - { (char*) "Asia/Colombo" , 0x025EA5 }, - { (char*) "Asia/Dacca" , 0x025FA8 }, - { (char*) "Asia/Damascus" , 0x02609B }, - { (char*) "Asia/Dhaka" , 0x026579 }, - { (char*) "Asia/Dili" , 0x02666C }, - { (char*) "Asia/Dubai" , 0x026722 }, - { (char*) "Asia/Dushanbe" , 0x0267B3 }, - { (char*) "Asia/Famagusta" , 0x02692D }, - { (char*) "Asia/Gaza" , 0x026CF4 }, - { (char*) "Asia/Harbin" , 0x027890 }, - { (char*) "Asia/Hebron" , 0x027A25 }, - { (char*) "Asia/Ho_Chi_Minh" , 0x0285D2 }, - { (char*) "Asia/Hong_Kong" , 0x0286CA }, - { (char*) "Asia/Hovd" , 0x0289DD }, - { (char*) "Asia/Irkutsk" , 0x028C51 }, - { (char*) "Asia/Istanbul" , 0x028F6F }, - { (char*) "Asia/Jakarta" , 0x02942B }, - { (char*) "Asia/Jayapura" , 0x02953C }, - { (char*) "Asia/Jerusalem" , 0x029629 }, - { (char*) "Asia/Kabul" , 0x029A67 }, - { (char*) "Asia/Kamchatka" , 0x029B12 }, - { (char*) "Asia/Karachi" , 0x029E07 }, - { (char*) "Asia/Kashgar" , 0x029F1D }, - { (char*) "Asia/Kathmandu" , 0x029FAE }, - { (char*) "Asia/Katmandu" , 0x02A05B }, - { (char*) "Asia/Khandyga" , 0x02A108 }, - { (char*) "Asia/Kolkata" , 0x02A439 }, - { (char*) "Asia/Krasnoyarsk" , 0x02A521 }, - { (char*) "Asia/Kuala_Lumpur" , 0x02A82B }, - { (char*) "Asia/Kuching" , 0x02A94B }, - { (char*) "Asia/Kuwait" , 0x02AAA5 }, - { (char*) "Asia/Macao" , 0x02AB36 }, - { (char*) "Asia/Macau" , 0x02AE59 }, - { (char*) "Asia/Magadan" , 0x02B17C }, - { (char*) "Asia/Makassar" , 0x02B487 }, - { (char*) "Asia/Manila" , 0x02B59A }, - { (char*) "Asia/Muscat" , 0x02B6B8 }, - { (char*) "Asia/Nicosia" , 0x02B749 }, - { (char*) "Asia/Novokuznetsk" , 0x02B9B8 }, - { (char*) "Asia/Novosibirsk" , 0x02BCAB }, - { (char*) "Asia/Omsk" , 0x02BFBC }, - { (char*) "Asia/Oral" , 0x02C2BA }, - { (char*) "Asia/Phnom_Penh" , 0x02C546 }, - { (char*) "Asia/Pontianak" , 0x02C61A }, - { (char*) "Asia/Pyongyang" , 0x02C733 }, - { (char*) "Asia/Qatar" , 0x02C7F6 }, - { (char*) "Asia/Qostanay" , 0x02C89A }, - { (char*) "Asia/Qyzylorda" , 0x02CB30 }, - { (char*) "Asia/Rangoon" , 0x02CDC9 }, - { (char*) "Asia/Riyadh" , 0x02CE90 }, - { (char*) "Asia/Saigon" , 0x02CF21 }, - { (char*) "Asia/Sakhalin" , 0x02D019 }, - { (char*) "Asia/Samarkand" , 0x02D330 }, - { (char*) "Asia/Seoul" , 0x02D4BB }, - { (char*) "Asia/Shanghai" , 0x02D666 }, - { (char*) "Asia/Singapore" , 0x02D807 }, - { (char*) "Asia/Srednekolymsk" , 0x02D913 }, - { (char*) "Asia/Taipei" , 0x02DC23 }, - { (char*) "Asia/Tashkent" , 0x02DE2E }, - { (char*) "Asia/Tbilisi" , 0x02DFB9 }, - { (char*) "Asia/Tehran" , 0x02E23A }, - { (char*) "Asia/Tel_Aviv" , 0x02E572 }, - { (char*) "Asia/Thimbu" , 0x02E9B0 }, - { (char*) "Asia/Thimphu" , 0x02EA56 }, - { (char*) "Asia/Tokyo" , 0x02EAFC }, - { (char*) "Asia/Tomsk" , 0x02EBDD }, - { (char*) "Asia/Ujung_Pandang" , 0x02EEE8 }, - { (char*) "Asia/Ulaanbaatar" , 0x02EFB2 }, - { (char*) "Asia/Ulan_Bator" , 0x02F220 }, - { (char*) "Asia/Urumqi" , 0x02F47E }, - { (char*) "Asia/Ust-Nera" , 0x02F51C }, - { (char*) "Asia/Vientiane" , 0x02F83F }, - { (char*) "Asia/Vladivostok" , 0x02F925 }, - { (char*) "Asia/Yakutsk" , 0x02FC2A }, - { (char*) "Asia/Yangon" , 0x02FF2E }, - { (char*) "Asia/Yekaterinburg" , 0x02FFF5 }, - { (char*) "Asia/Yerevan" , 0x030307 }, - { (char*) "Atlantic/Azores" , 0x0305D7 }, - { (char*) "Atlantic/Bermuda" , 0x030B62 }, - { (char*) "Atlantic/Canary" , 0x030F6E }, - { (char*) "Atlantic/Cape_Verde" , 0x031166 }, - { (char*) "Atlantic/Faeroe" , 0x031221 }, - { (char*) "Atlantic/Faroe" , 0x0313E6 }, - { (char*) "Atlantic/Jan_Mayen" , 0x0315AB }, - { (char*) "Atlantic/Madeira" , 0x031878 }, - { (char*) "Atlantic/Reykjavik" , 0x031DEF }, - { (char*) "Atlantic/South_Georgia" , 0x0320EC }, - { (char*) "Atlantic/St_Helena" , 0x03217C }, - { (char*) "Atlantic/Stanley" , 0x03221D }, - { (char*) "Australia/ACT" , 0x03253E }, - { (char*) "Australia/Adelaide" , 0x0328D2 }, - { (char*) "Australia/Brisbane" , 0x032C86 }, - { (char*) "Australia/Broken_Hill" , 0x032DCA }, - { (char*) "Australia/Canberra" , 0x03319F }, - { (char*) "Australia/Currie" , 0x033533 }, - { (char*) "Australia/Darwin" , 0x03392A }, - { (char*) "Australia/Eucla" , 0x033A32 }, - { (char*) "Australia/Hobart" , 0x033B91 }, - { (char*) "Australia/LHI" , 0x033F90 }, - { (char*) "Australia/Lindeman" , 0x034250 }, - { (char*) "Australia/Lord_Howe" , 0x0343C0 }, - { (char*) "Australia/Melbourne" , 0x034690 }, - { (char*) "Australia/North" , 0x034A2C }, - { (char*) "Australia/NSW" , 0x034B22 }, - { (char*) "Australia/Perth" , 0x034EB6 }, - { (char*) "Australia/Queensland" , 0x035012 }, - { (char*) "Australia/South" , 0x03513F }, - { (char*) "Australia/Sydney" , 0x0354E4 }, - { (char*) "Australia/Tasmania" , 0x035894 }, - { (char*) "Australia/Victoria" , 0x035C8B }, - { (char*) "Australia/West" , 0x03601F }, - { (char*) "Australia/Yancowinna" , 0x03615D }, - { (char*) "Brazil/Acre" , 0x036516 }, - { (char*) "Brazil/DeNoronha" , 0x0366C4 }, - { (char*) "Brazil/East" , 0x0368B4 }, - { (char*) "Brazil/West" , 0x036C78 }, - { (char*) "Canada/Atlantic" , 0x036E20 }, - { (char*) "Canada/Central" , 0x0374B4 }, - { (char*) "Canada/Eastern" , 0x0379CE }, - { (char*) "Canada/Mountain" , 0x03808F }, - { (char*) "Canada/Newfoundland" , 0x038465 }, - { (char*) "Canada/Pacific" , 0x038BC7 }, - { (char*) "Canada/Saskatchewan" , 0x039105 }, - { (char*) "Canada/Yukon" , 0x03938F }, - { (char*) "CET" , 0x0397A0 }, - { (char*) "Chile/Continental" , 0x039BFB }, - { (char*) "Chile/EasterIsland" , 0x03A151 }, - { (char*) "CST6CDT" , 0x03A5F3 }, - { (char*) "Cuba" , 0x03ACD9 }, - { (char*) "EET" , 0x03B142 }, - { (char*) "Egypt" , 0x03B3F8 }, - { (char*) "Eire" , 0x03B921 }, - { (char*) "EST" , 0x03BF05 }, - { (char*) "EST5EDT" , 0x03BFA6 }, - { (char*) "Etc/GMT" , 0x03C682 }, - { (char*) "Etc/GMT+0" , 0x03C6FD }, - { (char*) "Etc/GMT+1" , 0x03C778 }, - { (char*) "Etc/GMT+10" , 0x03C7F5 }, - { (char*) "Etc/GMT+11" , 0x03C873 }, - { (char*) "Etc/GMT+12" , 0x03C8F1 }, - { (char*) "Etc/GMT+2" , 0x03C96F }, - { (char*) "Etc/GMT+3" , 0x03C9EC }, - { (char*) "Etc/GMT+4" , 0x03CA69 }, - { (char*) "Etc/GMT+5" , 0x03CAE6 }, - { (char*) "Etc/GMT+6" , 0x03CB63 }, - { (char*) "Etc/GMT+7" , 0x03CBE0 }, - { (char*) "Etc/GMT+8" , 0x03CC5D }, - { (char*) "Etc/GMT+9" , 0x03CCDA }, - { (char*) "Etc/GMT-0" , 0x03CD57 }, - { (char*) "Etc/GMT-1" , 0x03CDD2 }, - { (char*) "Etc/GMT-10" , 0x03CE50 }, - { (char*) "Etc/GMT-11" , 0x03CECF }, - { (char*) "Etc/GMT-12" , 0x03CF4E }, - { (char*) "Etc/GMT-13" , 0x03CFCD }, - { (char*) "Etc/GMT-14" , 0x03D04C }, - { (char*) "Etc/GMT-2" , 0x03D0CB }, - { (char*) "Etc/GMT-3" , 0x03D149 }, - { (char*) "Etc/GMT-4" , 0x03D1C7 }, - { (char*) "Etc/GMT-5" , 0x03D245 }, - { (char*) "Etc/GMT-6" , 0x03D2C3 }, - { (char*) "Etc/GMT-7" , 0x03D341 }, - { (char*) "Etc/GMT-8" , 0x03D3BF }, - { (char*) "Etc/GMT-9" , 0x03D43D }, - { (char*) "Etc/GMT0" , 0x03D4BB }, - { (char*) "Etc/Greenwich" , 0x03D536 }, - { (char*) "Etc/UCT" , 0x03D5B1 }, - { (char*) "Etc/Universal" , 0x03D62C }, - { (char*) "Etc/UTC" , 0x03D6A7 }, - { (char*) "Etc/Zulu" , 0x03D722 }, - { (char*) "Europe/Amsterdam" , 0x03D79D }, - { (char*) "Europe/Andorra" , 0x03DBD8 }, - { (char*) "Europe/Astrakhan" , 0x03DD69 }, - { (char*) "Europe/Athens" , 0x03E05D }, - { (char*) "Europe/Belfast" , 0x03E313 }, - { (char*) "Europe/Belgrade" , 0x03E95E }, - { (char*) "Europe/Berlin" , 0x03EB48 }, - { (char*) "Europe/Bratislava" , 0x03EE24 }, - { (char*) "Europe/Brussels" , 0x03F103 }, - { (char*) "Europe/Bucharest" , 0x03F55E }, - { (char*) "Europe/Budapest" , 0x03F7FF }, - { (char*) "Europe/Busingen" , 0x03FB09 }, - { (char*) "Europe/Chisinau" , 0x03FD0E }, - { (char*) "Europe/Copenhagen" , 0x04000D }, - { (char*) "Europe/Dublin" , 0x040288 }, - { (char*) "Europe/Gibraltar" , 0x04086C }, - { (char*) "Europe/Guernsey" , 0x040D3C }, - { (char*) "Europe/Helsinki" , 0x041393 }, - { (char*) "Europe/Isle_of_Man" , 0x041580 }, - { (char*) "Europe/Istanbul" , 0x041BCB }, - { (char*) "Europe/Jersey" , 0x042087 }, - { (char*) "Europe/Kaliningrad" , 0x0426DE }, - { (char*) "Europe/Kiev" , 0x042A86 }, - { (char*) "Europe/Kirov" , 0x042CC0 }, - { (char*) "Europe/Kyiv" , 0x042FB9 }, - { (char*) "Europe/Lisbon" , 0x043202 }, - { (char*) "Europe/Ljubljana" , 0x0437D8 }, - { (char*) "Europe/London" , 0x0439C2 }, - { (char*) "Europe/Luxembourg" , 0x04400D }, - { (char*) "Europe/Madrid" , 0x044458 }, - { (char*) "Europe/Malta" , 0x0447F5 }, - { (char*) "Europe/Mariehamn" , 0x044BA1 }, - { (char*) "Europe/Minsk" , 0x044D8E }, - { (char*) "Europe/Monaco" , 0x0450C2 }, - { (char*) "Europe/Moscow" , 0x045528 }, - { (char*) "Europe/Nicosia" , 0x0458D4 }, - { (char*) "Europe/Oslo" , 0x045B35 }, - { (char*) "Europe/Paris" , 0x045DE5 }, - { (char*) "Europe/Podgorica" , 0x046242 }, - { (char*) "Europe/Prague" , 0x04642C }, - { (char*) "Europe/Riga" , 0x04670B }, - { (char*) "Europe/Rome" , 0x0469CD }, - { (char*) "Europe/Samara" , 0x046D8C }, - { (char*) "Europe/San_Marino" , 0x04708D }, - { (char*) "Europe/Sarajevo" , 0x04744C }, - { (char*) "Europe/Saratov" , 0x047636 }, - { (char*) "Europe/Simferopol" , 0x047928 }, - { (char*) "Europe/Skopje" , 0x047C9B }, - { (char*) "Europe/Sofia" , 0x047E85 }, - { (char*) "Europe/Stockholm" , 0x0480E1 }, - { (char*) "Europe/Tallinn" , 0x0482DE }, - { (char*) "Europe/Tirane" , 0x04858D }, - { (char*) "Europe/Tiraspol" , 0x0487F5 }, - { (char*) "Europe/Ulyanovsk" , 0x048AF4 }, - { (char*) "Europe/Uzhgorod" , 0x048E0A }, - { (char*) "Europe/Vaduz" , 0x049044 }, - { (char*) "Europe/Vatican" , 0x04922E }, - { (char*) "Europe/Vienna" , 0x0495ED }, - { (char*) "Europe/Vilnius" , 0x04988B }, - { (char*) "Europe/Volgograd" , 0x049B3B }, - { (char*) "Europe/Warsaw" , 0x049E4A }, - { (char*) "Europe/Zagreb" , 0x04A1F1 }, - { (char*) "Europe/Zaporozhye" , 0x04A3DB }, - { (char*) "Europe/Zurich" , 0x04A615 }, - { (char*) "Factory" , 0x04A812 }, - { (char*) "GB" , 0x04A88F }, - { (char*) "GB-Eire" , 0x04AEDA }, - { (char*) "GMT" , 0x04B525 }, - { (char*) "GMT+0" , 0x04B5A0 }, - { (char*) "GMT-0" , 0x04B61B }, - { (char*) "GMT0" , 0x04B696 }, - { (char*) "Greenwich" , 0x04B711 }, - { (char*) "Hongkong" , 0x04B78C }, - { (char*) "HST" , 0x04BA9F }, - { (char*) "Iceland" , 0x04BB88 }, - { (char*) "Indian/Antananarivo" , 0x04BC16 }, - { (char*) "Indian/Chagos" , 0x04BCC2 }, - { (char*) "Indian/Christmas" , 0x04BD66 }, - { (char*) "Indian/Cocos" , 0x04BDF7 }, - { (char*) "Indian/Comoro" , 0x04BE8F }, - { (char*) "Indian/Kerguelen" , 0x04BF1E }, - { (char*) "Indian/Mahe" , 0x04BFAF }, - { (char*) "Indian/Maldives" , 0x04C040 }, - { (char*) "Indian/Mauritius" , 0x04C0E4 }, - { (char*) "Indian/Mayotte" , 0x04C1A3 }, - { (char*) "Indian/Reunion" , 0x04C232 }, - { (char*) "Iran" , 0x04C2C3 }, - { (char*) "Israel" , 0x04C5FB }, - { (char*) "Jamaica" , 0x04CA39 }, - { (char*) "Japan" , 0x04CB98 }, - { (char*) "Kwajalein" , 0x04CC79 }, - { (char*) "Libya" , 0x04CD60 }, - { (char*) "MET" , 0x04CF1B }, - { (char*) "Mexico/BajaNorte" , 0x04D376 }, - { (char*) "Mexico/BajaSur" , 0x04D7B9 }, - { (char*) "Mexico/General" , 0x04DA77 }, - { (char*) "MST" , 0x04DD88 }, - { (char*) "MST7MDT" , 0x04DE84 }, - { (char*) "Navajo" , 0x04E2A2 }, - { (char*) "NZ" , 0x04E6C0 }, - { (char*) "NZ-CHAT" , 0x04EADF }, - { (char*) "Pacific/Apia" , 0x04EE13 }, - { (char*) "Pacific/Auckland" , 0x04EFB6 }, - { (char*) "Pacific/Bougainville" , 0x04F3E8 }, - { (char*) "Pacific/Chatham" , 0x04F4C9 }, - { (char*) "Pacific/Chuuk" , 0x04F80C }, - { (char*) "Pacific/Easter" , 0x04F8EA }, - { (char*) "Pacific/Efate" , 0x04FD99 }, - { (char*) "Pacific/Enderbury" , 0x04FEFB }, - { (char*) "Pacific/Fakaofo" , 0x04FFB3 }, - { (char*) "Pacific/Fiji" , 0x050058 }, - { (char*) "Pacific/Funafuti" , 0x0501F0 }, - { (char*) "Pacific/Galapagos" , 0x050282 }, - { (char*) "Pacific/Gambier" , 0x05034E }, - { (char*) "Pacific/Guadalcanal" , 0x0503ED }, - { (char*) "Pacific/Guam" , 0x05047F }, - { (char*) "Pacific/Honolulu" , 0x0505E9 }, - { (char*) "Pacific/Johnston" , 0x0506D8 }, - { (char*) "Pacific/Kanton" , 0x0507C1 }, - { (char*) "Pacific/Kiritimati" , 0x050888 }, - { (char*) "Pacific/Kosrae" , 0x05094E }, - { (char*) "Pacific/Kwajalein" , 0x050A52 }, - { (char*) "Pacific/Majuro" , 0x050B42 }, - { (char*) "Pacific/Marquesas" , 0x050C40 }, - { (char*) "Pacific/Midway" , 0x050CE8 }, - { (char*) "Pacific/Nauru" , 0x050DAB }, - { (char*) "Pacific/Niue" , 0x050E6E }, - { (char*) "Pacific/Norfolk" , 0x050F14 }, - { (char*) "Pacific/Noumea" , 0x05100D }, - { (char*) "Pacific/Pago_Pago" , 0x0510DF }, - { (char*) "Pacific/Palau" , 0x05117D }, - { (char*) "Pacific/Pitcairn" , 0x05121D }, - { (char*) "Pacific/Pohnpei" , 0x0512C2 }, - { (char*) "Pacific/Ponape" , 0x0513B2 }, - { (char*) "Pacific/Port_Moresby" , 0x051444 }, - { (char*) "Pacific/Rarotonga" , 0x051502 }, - { (char*) "Pacific/Saipan" , 0x0516A4 }, - { (char*) "Pacific/Samoa" , 0x051805 }, - { (char*) "Pacific/Tahiti" , 0x0518A3 }, - { (char*) "Pacific/Tarawa" , 0x051943 }, - { (char*) "Pacific/Tongatapu" , 0x0519E4 }, - { (char*) "Pacific/Truk" , 0x051ADD }, - { (char*) "Pacific/Wake" , 0x051B83 }, - { (char*) "Pacific/Wallis" , 0x051C20 }, - { (char*) "Pacific/Yap" , 0x051CB2 }, - { (char*) "Poland" , 0x051D58 }, - { (char*) "Portugal" , 0x0520FF }, - { (char*) "PRC" , 0x0526C2 }, - { (char*) "PST8PDT" , 0x052857 }, - { (char*) "ROC" , 0x052D71 }, - { (char*) "ROK" , 0x052F7C }, - { (char*) "Singapore" , 0x053127 }, - { (char*) "Turkey" , 0x053233 }, - { (char*) "UCT" , 0x0536EF }, - { (char*) "Universal" , 0x05376A }, - { (char*) "US/Alaska" , 0x0537E5 }, - { (char*) "US/Aleutian" , 0x053BC2 }, - { (char*) "US/Arizona" , 0x053F97 }, - { (char*) "US/Central" , 0x054093 }, - { (char*) "US/East-Indiana" , 0x054779 }, - { (char*) "US/Eastern" , 0x054998 }, - { (char*) "US/Hawaii" , 0x055074 }, - { (char*) "US/Indiana-Starke" , 0x05515D }, - { (char*) "US/Michigan" , 0x055561 }, - { (char*) "US/Mountain" , 0x0558F0 }, - { (char*) "US/Pacific" , 0x055D0E }, - { (char*) "US/Samoa" , 0x056228 }, - { (char*) "UTC" , 0x0562C6 }, - { (char*) "W-SU" , 0x056341 }, - { (char*) "WET" , 0x0566D9 }, - { (char*) "Zulu" , 0x056C9C }, + { (char*) "America/Fort_Nelson" , 0x00D9EC }, + { (char*) "America/Fort_Wayne" , 0x00DFB4 }, + { (char*) "America/Fortaleza" , 0x00E1D3 }, + { (char*) "America/Glace_Bay" , 0x00E3E9 }, + { (char*) "America/Godthab" , 0x00E780 }, + { (char*) "America/Goose_Bay" , 0x00EB51 }, + { (char*) "America/Grand_Turk" , 0x00F1A9 }, + { (char*) "America/Grenada" , 0x00F50A }, + { (char*) "America/Guadeloupe" , 0x00F598 }, + { (char*) "America/Guatemala" , 0x00F626 }, + { (char*) "America/Guayaquil" , 0x00F706 }, + { (char*) "America/Guyana" , 0x00F7D7 }, + { (char*) "America/Halifax" , 0x00F898 }, + { (char*) "America/Havana" , 0x00FF4A }, + { (char*) "America/Hermosillo" , 0x0103B3 }, + { (char*) "America/Indiana/Indianapolis" , 0x0104C7 }, + { (char*) "America/Indiana/Knox" , 0x0106FF }, + { (char*) "America/Indiana/Marengo" , 0x010B18 }, + { (char*) "America/Indiana/Petersburg" , 0x010D72 }, + { (char*) "America/Indiana/Tell_City" , 0x01103C }, + { (char*) "America/Indiana/Vevay" , 0x011266 }, + { (char*) "America/Indiana/Vincennes" , 0x0113FD }, + { (char*) "America/Indiana/Winamac" , 0x011653 }, + { (char*) "America/Indianapolis" , 0x0118D0 }, + { (char*) "America/Inuvik" , 0x011AEF }, + { (char*) "America/Iqaluit" , 0x011E40 }, + { (char*) "America/Jamaica" , 0x0121BC }, + { (char*) "America/Jujuy" , 0x01231B }, + { (char*) "America/Juneau" , 0x0125D9 }, + { (char*) "America/Kentucky/Louisville" , 0x0129BF }, + { (char*) "America/Kentucky/Monticello" , 0x012EC3 }, + { (char*) "America/Knox_IN" , 0x0132AF }, + { (char*) "America/Kralendijk" , 0x0136B3 }, + { (char*) "America/La_Paz" , 0x013770 }, + { (char*) "America/Lima" , 0x013826 }, + { (char*) "America/Los_Angeles" , 0x01394D }, + { (char*) "America/Louisville" , 0x013E6E }, + { (char*) "America/Lower_Princes" , 0x014354 }, + { (char*) "America/Maceio" , 0x014411 }, + { (char*) "America/Managua" , 0x014623 }, + { (char*) "America/Manaus" , 0x014756 }, + { (char*) "America/Marigot" , 0x01490D }, + { (char*) "America/Martinique" , 0x0149CA }, + { (char*) "America/Matamoros" , 0x014A88 }, + { (char*) "America/Mazatlan" , 0x014C75 }, + { (char*) "America/Mendoza" , 0x014F65 }, + { (char*) "America/Menominee" , 0x015235 }, + { (char*) "America/Merida" , 0x0155F5 }, + { (char*) "America/Metlakatla" , 0x0158A0 }, + { (char*) "America/Mexico_City" , 0x015B0D }, + { (char*) "America/Miquelon" , 0x015E2C }, + { (char*) "America/Moncton" , 0x01605E }, + { (char*) "America/Monterrey" , 0x016657 }, + { (char*) "America/Montevideo" , 0x01695E }, + { (char*) "America/Montreal" , 0x016D33 }, + { (char*) "America/Montserrat" , 0x0173F4 }, + { (char*) "America/Nassau" , 0x017482 }, + { (char*) "America/New_York" , 0x01787C }, + { (char*) "America/Nipigon" , 0x017F6C }, + { (char*) "America/Nome" , 0x01862D }, + { (char*) "America/Noronha" , 0x018A15 }, + { (char*) "America/North_Dakota/Beulah" , 0x018C15 }, + { (char*) "America/North_Dakota/Center" , 0x019049 }, + { (char*) "America/North_Dakota/New_Salem" , 0x019448 }, + { (char*) "America/Nuuk" , 0x01984D }, + { (char*) "America/Ojinaga" , 0x019C2F }, + { (char*) "America/Panama" , 0x019F25 }, + { (char*) "America/Pangnirtung" , 0x019FC6 }, + { (char*) "America/Paramaribo" , 0x01A329 }, + { (char*) "America/Phoenix" , 0x01A3F0 }, + { (char*) "America/Port-au-Prince" , 0x01A504 }, + { (char*) "America/Port_of_Spain" , 0x01A745 }, + { (char*) "America/Porto_Acre" , 0x01A7D3 }, + { (char*) "America/Porto_Velho" , 0x01A981 }, + { (char*) "America/Puerto_Rico" , 0x01AB1F }, + { (char*) "America/Punta_Arenas" , 0x01ABDC }, + { (char*) "America/Rainy_River" , 0x01B0BB }, + { (char*) "America/Rankin_Inlet" , 0x01B5D5 }, + { (char*) "America/Recife" , 0x01B91E }, + { (char*) "America/Regina" , 0x01BB18 }, + { (char*) "America/Resolute" , 0x01BDB7 }, + { (char*) "America/Rio_Branco" , 0x01C101 }, + { (char*) "America/Rosario" , 0x01C2B3 }, + { (char*) "America/Santa_Isabel" , 0x01C583 }, + { (char*) "America/Santarem" , 0x01CAE6 }, + { (char*) "America/Santiago" , 0x01CC96 }, + { (char*) "America/Santo_Domingo" , 0x01D1F9 }, + { (char*) "America/Sao_Paulo" , 0x01D342 }, + { (char*) "America/Scoresbysund" , 0x01D73C }, + { (char*) "America/Shiprock" , 0x01DB3D }, + { (char*) "America/Sitka" , 0x01DF5B }, + { (char*) "America/St_Barthelemy" , 0x01E336 }, + { (char*) "America/St_Johns" , 0x01E3F3 }, + { (char*) "America/St_Kitts" , 0x01EB70 }, + { (char*) "America/St_Lucia" , 0x01EBFE }, + { (char*) "America/St_Thomas" , 0x01EC9F }, + { (char*) "America/St_Vincent" , 0x01ED2D }, + { (char*) "America/Swift_Current" , 0x01EDCE }, + { (char*) "America/Tegucigalpa" , 0x01EF5C }, + { (char*) "America/Thule" , 0x01F02A }, + { (char*) "America/Thunder_Bay" , 0x01F20B }, + { (char*) "America/Tijuana" , 0x01F8CC }, + { (char*) "America/Toronto" , 0x01FE3E }, + { (char*) "America/Tortola" , 0x02051D }, + { (char*) "America/Vancouver" , 0x0205AB }, + { (char*) "America/Virgin" , 0x020B02 }, + { (char*) "America/Whitehorse" , 0x020BBF }, + { (char*) "America/Winnipeg" , 0x020FE2 }, + { (char*) "America/Yakutat" , 0x021519 }, + { (char*) "America/Yellowknife" , 0x0218E7 }, + { (char*) "Antarctica/Casey" , 0x021CBD }, + { (char*) "Antarctica/Davis" , 0x021DED }, + { (char*) "Antarctica/DumontDUrville" , 0x021EC3 }, + { (char*) "Antarctica/Macquarie" , 0x021F77 }, + { (char*) "Antarctica/Mawson" , 0x022363 }, + { (char*) "Antarctica/McMurdo" , 0x02240D }, + { (char*) "Antarctica/Palmer" , 0x02273F }, + { (char*) "Antarctica/Rothera" , 0x022AC8 }, + { (char*) "Antarctica/South_Pole" , 0x022B5F }, + { (char*) "Antarctica/Syowa" , 0x022F7E }, + { (char*) "Antarctica/Troll" , 0x023014 }, + { (char*) "Antarctica/Vostok" , 0x0230C3 }, + { (char*) "Arctic/Longyearbyen" , 0x02317F }, + { (char*) "Asia/Aden" , 0x02344C }, + { (char*) "Asia/Almaty" , 0x0234DD }, + { (char*) "Asia/Amman" , 0x023765 }, + { (char*) "Asia/Anadyr" , 0x023B11 }, + { (char*) "Asia/Aqtau" , 0x023E17 }, + { (char*) "Asia/Aqtobe" , 0x024096 }, + { (char*) "Asia/Ashgabat" , 0x024316 }, + { (char*) "Asia/Ashkhabad" , 0x024499 }, + { (char*) "Asia/Atyrau" , 0x02461C }, + { (char*) "Asia/Baghdad" , 0x0248A5 }, + { (char*) "Asia/Bahrain" , 0x024B27 }, + { (char*) "Asia/Baku" , 0x024BE0 }, + { (char*) "Asia/Bangkok" , 0x024ED4 }, + { (char*) "Asia/Barnaul" , 0x024F78 }, + { (char*) "Asia/Beirut" , 0x025283 }, + { (char*) "Asia/Bishkek" , 0x02556B }, + { (char*) "Asia/Brunei" , 0x0257E1 }, + { (char*) "Asia/Calcutta" , 0x025887 }, + { (char*) "Asia/Chita" , 0x02596F }, + { (char*) "Asia/Choibalsan" , 0x025C7D }, + { (char*) "Asia/Chongqing" , 0x025EDB }, + { (char*) "Asia/Chungking" , 0x026070 }, + { (char*) "Asia/Colombo" , 0x026205 }, + { (char*) "Asia/Dacca" , 0x026308 }, + { (char*) "Asia/Damascus" , 0x0263FB }, + { (char*) "Asia/Dhaka" , 0x0268D9 }, + { (char*) "Asia/Dili" , 0x0269CC }, + { (char*) "Asia/Dubai" , 0x026A82 }, + { (char*) "Asia/Dushanbe" , 0x026B13 }, + { (char*) "Asia/Famagusta" , 0x026C8D }, + { (char*) "Asia/Gaza" , 0x027054 }, + { (char*) "Asia/Harbin" , 0x027BF0 }, + { (char*) "Asia/Hebron" , 0x027D85 }, + { (char*) "Asia/Ho_Chi_Minh" , 0x028932 }, + { (char*) "Asia/Hong_Kong" , 0x028A2A }, + { (char*) "Asia/Hovd" , 0x028D3D }, + { (char*) "Asia/Irkutsk" , 0x028FB1 }, + { (char*) "Asia/Istanbul" , 0x0292CF }, + { (char*) "Asia/Jakarta" , 0x02978B }, + { (char*) "Asia/Jayapura" , 0x02989C }, + { (char*) "Asia/Jerusalem" , 0x029989 }, + { (char*) "Asia/Kabul" , 0x029DC7 }, + { (char*) "Asia/Kamchatka" , 0x029E72 }, + { (char*) "Asia/Karachi" , 0x02A167 }, + { (char*) "Asia/Kashgar" , 0x02A27D }, + { (char*) "Asia/Kathmandu" , 0x02A30E }, + { (char*) "Asia/Katmandu" , 0x02A3BB }, + { (char*) "Asia/Khandyga" , 0x02A468 }, + { (char*) "Asia/Kolkata" , 0x02A799 }, + { (char*) "Asia/Krasnoyarsk" , 0x02A881 }, + { (char*) "Asia/Kuala_Lumpur" , 0x02AB8B }, + { (char*) "Asia/Kuching" , 0x02ACAB }, + { (char*) "Asia/Kuwait" , 0x02AE05 }, + { (char*) "Asia/Macao" , 0x02AE96 }, + { (char*) "Asia/Macau" , 0x02B1B9 }, + { (char*) "Asia/Magadan" , 0x02B4DC }, + { (char*) "Asia/Makassar" , 0x02B7E7 }, + { (char*) "Asia/Manila" , 0x02B8FA }, + { (char*) "Asia/Muscat" , 0x02BA18 }, + { (char*) "Asia/Nicosia" , 0x02BAA9 }, + { (char*) "Asia/Novokuznetsk" , 0x02BD18 }, + { (char*) "Asia/Novosibirsk" , 0x02C00B }, + { (char*) "Asia/Omsk" , 0x02C31C }, + { (char*) "Asia/Oral" , 0x02C61A }, + { (char*) "Asia/Phnom_Penh" , 0x02C8A6 }, + { (char*) "Asia/Pontianak" , 0x02C97A }, + { (char*) "Asia/Pyongyang" , 0x02CA93 }, + { (char*) "Asia/Qatar" , 0x02CB56 }, + { (char*) "Asia/Qostanay" , 0x02CBFA }, + { (char*) "Asia/Qyzylorda" , 0x02CE90 }, + { (char*) "Asia/Rangoon" , 0x02D129 }, + { (char*) "Asia/Riyadh" , 0x02D1F0 }, + { (char*) "Asia/Saigon" , 0x02D281 }, + { (char*) "Asia/Sakhalin" , 0x02D379 }, + { (char*) "Asia/Samarkand" , 0x02D690 }, + { (char*) "Asia/Seoul" , 0x02D81B }, + { (char*) "Asia/Shanghai" , 0x02D9C6 }, + { (char*) "Asia/Singapore" , 0x02DB67 }, + { (char*) "Asia/Srednekolymsk" , 0x02DC73 }, + { (char*) "Asia/Taipei" , 0x02DF83 }, + { (char*) "Asia/Tashkent" , 0x02E18E }, + { (char*) "Asia/Tbilisi" , 0x02E319 }, + { (char*) "Asia/Tehran" , 0x02E59A }, + { (char*) "Asia/Tel_Aviv" , 0x02E8D2 }, + { (char*) "Asia/Thimbu" , 0x02ED10 }, + { (char*) "Asia/Thimphu" , 0x02EDB6 }, + { (char*) "Asia/Tokyo" , 0x02EE5C }, + { (char*) "Asia/Tomsk" , 0x02EF3D }, + { (char*) "Asia/Ujung_Pandang" , 0x02F248 }, + { (char*) "Asia/Ulaanbaatar" , 0x02F312 }, + { (char*) "Asia/Ulan_Bator" , 0x02F580 }, + { (char*) "Asia/Urumqi" , 0x02F7DE }, + { (char*) "Asia/Ust-Nera" , 0x02F87C }, + { (char*) "Asia/Vientiane" , 0x02FB9F }, + { (char*) "Asia/Vladivostok" , 0x02FC85 }, + { (char*) "Asia/Yakutsk" , 0x02FF8A }, + { (char*) "Asia/Yangon" , 0x03028E }, + { (char*) "Asia/Yekaterinburg" , 0x030355 }, + { (char*) "Asia/Yerevan" , 0x030667 }, + { (char*) "Atlantic/Azores" , 0x030937 }, + { (char*) "Atlantic/Bermuda" , 0x030EC2 }, + { (char*) "Atlantic/Canary" , 0x0312CE }, + { (char*) "Atlantic/Cape_Verde" , 0x0314C6 }, + { (char*) "Atlantic/Faeroe" , 0x031581 }, + { (char*) "Atlantic/Faroe" , 0x031746 }, + { (char*) "Atlantic/Jan_Mayen" , 0x03190B }, + { (char*) "Atlantic/Madeira" , 0x031BD8 }, + { (char*) "Atlantic/Reykjavik" , 0x03214F }, + { (char*) "Atlantic/South_Georgia" , 0x03244C }, + { (char*) "Atlantic/St_Helena" , 0x0324DC }, + { (char*) "Atlantic/Stanley" , 0x03257D }, + { (char*) "Australia/ACT" , 0x03289E }, + { (char*) "Australia/Adelaide" , 0x032C32 }, + { (char*) "Australia/Brisbane" , 0x032FE6 }, + { (char*) "Australia/Broken_Hill" , 0x03312A }, + { (char*) "Australia/Canberra" , 0x0334FF }, + { (char*) "Australia/Currie" , 0x033893 }, + { (char*) "Australia/Darwin" , 0x033C8A }, + { (char*) "Australia/Eucla" , 0x033D92 }, + { (char*) "Australia/Hobart" , 0x033EF1 }, + { (char*) "Australia/LHI" , 0x0342F0 }, + { (char*) "Australia/Lindeman" , 0x0345B0 }, + { (char*) "Australia/Lord_Howe" , 0x034720 }, + { (char*) "Australia/Melbourne" , 0x0349F0 }, + { (char*) "Australia/North" , 0x034D8C }, + { (char*) "Australia/NSW" , 0x034E82 }, + { (char*) "Australia/Perth" , 0x035216 }, + { (char*) "Australia/Queensland" , 0x035372 }, + { (char*) "Australia/South" , 0x03549F }, + { (char*) "Australia/Sydney" , 0x035844 }, + { (char*) "Australia/Tasmania" , 0x035BF4 }, + { (char*) "Australia/Victoria" , 0x035FEB }, + { (char*) "Australia/West" , 0x03637F }, + { (char*) "Australia/Yancowinna" , 0x0364BD }, + { (char*) "Brazil/Acre" , 0x036876 }, + { (char*) "Brazil/DeNoronha" , 0x036A24 }, + { (char*) "Brazil/East" , 0x036C14 }, + { (char*) "Brazil/West" , 0x036FD8 }, + { (char*) "Canada/Atlantic" , 0x037180 }, + { (char*) "Canada/Central" , 0x037814 }, + { (char*) "Canada/Eastern" , 0x037D2E }, + { (char*) "Canada/Mountain" , 0x0383EF }, + { (char*) "Canada/Newfoundland" , 0x0387C5 }, + { (char*) "Canada/Pacific" , 0x038F27 }, + { (char*) "Canada/Saskatchewan" , 0x039465 }, + { (char*) "Canada/Yukon" , 0x0396EF }, + { (char*) "CET" , 0x039B00 }, + { (char*) "Chile/Continental" , 0x039F5B }, + { (char*) "Chile/EasterIsland" , 0x03A4B1 }, + { (char*) "CST6CDT" , 0x03A953 }, + { (char*) "Cuba" , 0x03B039 }, + { (char*) "EET" , 0x03B4A2 }, + { (char*) "Egypt" , 0x03B758 }, + { (char*) "Eire" , 0x03BC81 }, + { (char*) "EST" , 0x03C265 }, + { (char*) "EST5EDT" , 0x03C306 }, + { (char*) "Etc/GMT" , 0x03C9E2 }, + { (char*) "Etc/GMT+0" , 0x03CA5D }, + { (char*) "Etc/GMT+1" , 0x03CAD8 }, + { (char*) "Etc/GMT+10" , 0x03CB55 }, + { (char*) "Etc/GMT+11" , 0x03CBD3 }, + { (char*) "Etc/GMT+12" , 0x03CC51 }, + { (char*) "Etc/GMT+2" , 0x03CCCF }, + { (char*) "Etc/GMT+3" , 0x03CD4C }, + { (char*) "Etc/GMT+4" , 0x03CDC9 }, + { (char*) "Etc/GMT+5" , 0x03CE46 }, + { (char*) "Etc/GMT+6" , 0x03CEC3 }, + { (char*) "Etc/GMT+7" , 0x03CF40 }, + { (char*) "Etc/GMT+8" , 0x03CFBD }, + { (char*) "Etc/GMT+9" , 0x03D03A }, + { (char*) "Etc/GMT-0" , 0x03D0B7 }, + { (char*) "Etc/GMT-1" , 0x03D132 }, + { (char*) "Etc/GMT-10" , 0x03D1B0 }, + { (char*) "Etc/GMT-11" , 0x03D22F }, + { (char*) "Etc/GMT-12" , 0x03D2AE }, + { (char*) "Etc/GMT-13" , 0x03D32D }, + { (char*) "Etc/GMT-14" , 0x03D3AC }, + { (char*) "Etc/GMT-2" , 0x03D42B }, + { (char*) "Etc/GMT-3" , 0x03D4A9 }, + { (char*) "Etc/GMT-4" , 0x03D527 }, + { (char*) "Etc/GMT-5" , 0x03D5A5 }, + { (char*) "Etc/GMT-6" , 0x03D623 }, + { (char*) "Etc/GMT-7" , 0x03D6A1 }, + { (char*) "Etc/GMT-8" , 0x03D71F }, + { (char*) "Etc/GMT-9" , 0x03D79D }, + { (char*) "Etc/GMT0" , 0x03D81B }, + { (char*) "Etc/Greenwich" , 0x03D896 }, + { (char*) "Etc/UCT" , 0x03D911 }, + { (char*) "Etc/Universal" , 0x03D98C }, + { (char*) "Etc/UTC" , 0x03DA07 }, + { (char*) "Etc/Zulu" , 0x03DA82 }, + { (char*) "Europe/Amsterdam" , 0x03DAFD }, + { (char*) "Europe/Andorra" , 0x03DF38 }, + { (char*) "Europe/Astrakhan" , 0x03E0C9 }, + { (char*) "Europe/Athens" , 0x03E3BD }, + { (char*) "Europe/Belfast" , 0x03E673 }, + { (char*) "Europe/Belgrade" , 0x03ECBE }, + { (char*) "Europe/Berlin" , 0x03EEA8 }, + { (char*) "Europe/Bratislava" , 0x03F184 }, + { (char*) "Europe/Brussels" , 0x03F463 }, + { (char*) "Europe/Bucharest" , 0x03F8BE }, + { (char*) "Europe/Budapest" , 0x03FB5F }, + { (char*) "Europe/Busingen" , 0x03FE69 }, + { (char*) "Europe/Chisinau" , 0x04006E }, + { (char*) "Europe/Copenhagen" , 0x04036D }, + { (char*) "Europe/Dublin" , 0x0405E8 }, + { (char*) "Europe/Gibraltar" , 0x040BCC }, + { (char*) "Europe/Guernsey" , 0x04109C }, + { (char*) "Europe/Helsinki" , 0x0416F3 }, + { (char*) "Europe/Isle_of_Man" , 0x0418E0 }, + { (char*) "Europe/Istanbul" , 0x041F2B }, + { (char*) "Europe/Jersey" , 0x0423E7 }, + { (char*) "Europe/Kaliningrad" , 0x042A3E }, + { (char*) "Europe/Kiev" , 0x042DE6 }, + { (char*) "Europe/Kirov" , 0x043020 }, + { (char*) "Europe/Kyiv" , 0x043319 }, + { (char*) "Europe/Lisbon" , 0x043562 }, + { (char*) "Europe/Ljubljana" , 0x043B38 }, + { (char*) "Europe/London" , 0x043D22 }, + { (char*) "Europe/Luxembourg" , 0x04436D }, + { (char*) "Europe/Madrid" , 0x0447B8 }, + { (char*) "Europe/Malta" , 0x044B55 }, + { (char*) "Europe/Mariehamn" , 0x044F01 }, + { (char*) "Europe/Minsk" , 0x0450EE }, + { (char*) "Europe/Monaco" , 0x045422 }, + { (char*) "Europe/Moscow" , 0x045888 }, + { (char*) "Europe/Nicosia" , 0x045C34 }, + { (char*) "Europe/Oslo" , 0x045E95 }, + { (char*) "Europe/Paris" , 0x046145 }, + { (char*) "Europe/Podgorica" , 0x0465A2 }, + { (char*) "Europe/Prague" , 0x04678C }, + { (char*) "Europe/Riga" , 0x046A6B }, + { (char*) "Europe/Rome" , 0x046D2D }, + { (char*) "Europe/Samara" , 0x0470EC }, + { (char*) "Europe/San_Marino" , 0x0473ED }, + { (char*) "Europe/Sarajevo" , 0x0477AC }, + { (char*) "Europe/Saratov" , 0x047996 }, + { (char*) "Europe/Simferopol" , 0x047C88 }, + { (char*) "Europe/Skopje" , 0x047FFB }, + { (char*) "Europe/Sofia" , 0x0481E5 }, + { (char*) "Europe/Stockholm" , 0x048441 }, + { (char*) "Europe/Tallinn" , 0x04863E }, + { (char*) "Europe/Tirane" , 0x0488ED }, + { (char*) "Europe/Tiraspol" , 0x048B55 }, + { (char*) "Europe/Ulyanovsk" , 0x048E54 }, + { (char*) "Europe/Uzhgorod" , 0x04916A }, + { (char*) "Europe/Vaduz" , 0x0493A4 }, + { (char*) "Europe/Vatican" , 0x04958E }, + { (char*) "Europe/Vienna" , 0x04994D }, + { (char*) "Europe/Vilnius" , 0x049BEB }, + { (char*) "Europe/Volgograd" , 0x049E9B }, + { (char*) "Europe/Warsaw" , 0x04A1AA }, + { (char*) "Europe/Zagreb" , 0x04A551 }, + { (char*) "Europe/Zaporozhye" , 0x04A73B }, + { (char*) "Europe/Zurich" , 0x04A975 }, + { (char*) "Factory" , 0x04AB72 }, + { (char*) "GB" , 0x04ABEF }, + { (char*) "GB-Eire" , 0x04B23A }, + { (char*) "GMT" , 0x04B885 }, + { (char*) "GMT+0" , 0x04B900 }, + { (char*) "GMT-0" , 0x04B97B }, + { (char*) "GMT0" , 0x04B9F6 }, + { (char*) "Greenwich" , 0x04BA71 }, + { (char*) "Hongkong" , 0x04BAEC }, + { (char*) "HST" , 0x04BDFF }, + { (char*) "Iceland" , 0x04BEE8 }, + { (char*) "Indian/Antananarivo" , 0x04BF76 }, + { (char*) "Indian/Chagos" , 0x04C022 }, + { (char*) "Indian/Christmas" , 0x04C0C6 }, + { (char*) "Indian/Cocos" , 0x04C157 }, + { (char*) "Indian/Comoro" , 0x04C1EF }, + { (char*) "Indian/Kerguelen" , 0x04C27E }, + { (char*) "Indian/Mahe" , 0x04C30F }, + { (char*) "Indian/Maldives" , 0x04C3A0 }, + { (char*) "Indian/Mauritius" , 0x04C444 }, + { (char*) "Indian/Mayotte" , 0x04C503 }, + { (char*) "Indian/Reunion" , 0x04C592 }, + { (char*) "Iran" , 0x04C623 }, + { (char*) "Israel" , 0x04C95B }, + { (char*) "Jamaica" , 0x04CD99 }, + { (char*) "Japan" , 0x04CEF8 }, + { (char*) "Kwajalein" , 0x04CFD9 }, + { (char*) "Libya" , 0x04D0C0 }, + { (char*) "MET" , 0x04D27B }, + { (char*) "Mexico/BajaNorte" , 0x04D6D6 }, + { (char*) "Mexico/BajaSur" , 0x04DC39 }, + { (char*) "Mexico/General" , 0x04DEF7 }, + { (char*) "MST" , 0x04E208 }, + { (char*) "MST7MDT" , 0x04E304 }, + { (char*) "Navajo" , 0x04E722 }, + { (char*) "NZ" , 0x04EB40 }, + { (char*) "NZ-CHAT" , 0x04EF5F }, + { (char*) "Pacific/Apia" , 0x04F293 }, + { (char*) "Pacific/Auckland" , 0x04F436 }, + { (char*) "Pacific/Bougainville" , 0x04F868 }, + { (char*) "Pacific/Chatham" , 0x04F949 }, + { (char*) "Pacific/Chuuk" , 0x04FC8C }, + { (char*) "Pacific/Easter" , 0x04FD6A }, + { (char*) "Pacific/Efate" , 0x050219 }, + { (char*) "Pacific/Enderbury" , 0x05037B }, + { (char*) "Pacific/Fakaofo" , 0x050433 }, + { (char*) "Pacific/Fiji" , 0x0504D8 }, + { (char*) "Pacific/Funafuti" , 0x050670 }, + { (char*) "Pacific/Galapagos" , 0x050702 }, + { (char*) "Pacific/Gambier" , 0x0507CE }, + { (char*) "Pacific/Guadalcanal" , 0x05086D }, + { (char*) "Pacific/Guam" , 0x0508FF }, + { (char*) "Pacific/Honolulu" , 0x050A69 }, + { (char*) "Pacific/Johnston" , 0x050B58 }, + { (char*) "Pacific/Kanton" , 0x050C41 }, + { (char*) "Pacific/Kiritimati" , 0x050D08 }, + { (char*) "Pacific/Kosrae" , 0x050DCE }, + { (char*) "Pacific/Kwajalein" , 0x050ED2 }, + { (char*) "Pacific/Majuro" , 0x050FC2 }, + { (char*) "Pacific/Marquesas" , 0x0510C0 }, + { (char*) "Pacific/Midway" , 0x051168 }, + { (char*) "Pacific/Nauru" , 0x05122B }, + { (char*) "Pacific/Niue" , 0x0512EE }, + { (char*) "Pacific/Norfolk" , 0x051394 }, + { (char*) "Pacific/Noumea" , 0x05148D }, + { (char*) "Pacific/Pago_Pago" , 0x05155F }, + { (char*) "Pacific/Palau" , 0x0515FD }, + { (char*) "Pacific/Pitcairn" , 0x05169D }, + { (char*) "Pacific/Pohnpei" , 0x051742 }, + { (char*) "Pacific/Ponape" , 0x051832 }, + { (char*) "Pacific/Port_Moresby" , 0x0518C4 }, + { (char*) "Pacific/Rarotonga" , 0x051982 }, + { (char*) "Pacific/Saipan" , 0x051B24 }, + { (char*) "Pacific/Samoa" , 0x051C85 }, + { (char*) "Pacific/Tahiti" , 0x051D23 }, + { (char*) "Pacific/Tarawa" , 0x051DC3 }, + { (char*) "Pacific/Tongatapu" , 0x051E64 }, + { (char*) "Pacific/Truk" , 0x051F5D }, + { (char*) "Pacific/Wake" , 0x052003 }, + { (char*) "Pacific/Wallis" , 0x0520A0 }, + { (char*) "Pacific/Yap" , 0x052132 }, + { (char*) "Poland" , 0x0521D8 }, + { (char*) "Portugal" , 0x05257F }, + { (char*) "PRC" , 0x052B42 }, + { (char*) "PST8PDT" , 0x052CD7 }, + { (char*) "ROC" , 0x0531F1 }, + { (char*) "ROK" , 0x0533FC }, + { (char*) "Singapore" , 0x0535A7 }, + { (char*) "Turkey" , 0x0536B3 }, + { (char*) "UCT" , 0x053B6F }, + { (char*) "Universal" , 0x053BEA }, + { (char*) "US/Alaska" , 0x053C65 }, + { (char*) "US/Aleutian" , 0x054042 }, + { (char*) "US/Arizona" , 0x054417 }, + { (char*) "US/Central" , 0x054513 }, + { (char*) "US/East-Indiana" , 0x054BF9 }, + { (char*) "US/Eastern" , 0x054E18 }, + { (char*) "US/Hawaii" , 0x0554F4 }, + { (char*) "US/Indiana-Starke" , 0x0555DD }, + { (char*) "US/Michigan" , 0x0559E1 }, + { (char*) "US/Mountain" , 0x055D70 }, + { (char*) "US/Pacific" , 0x05618E }, + { (char*) "US/Samoa" , 0x0566A8 }, + { (char*) "UTC" , 0x056746 }, + { (char*) "W-SU" , 0x0567C1 }, + { (char*) "WET" , 0x056B59 }, + { (char*) "Zulu" , 0x05711C }, }; -const unsigned char timelib_timezone_db_data_builtin[355607] = { +const unsigned char timelib_timezone_db_data_builtin[356759] = { /* Africa/Abidjan */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -4297,7 +4297,7 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0xB6, 0xE8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xA9, 0x79, 0x4F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF1, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x66, 0x64, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1B, 0x10, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xB8, 0x0A, 0xF2, 0xF0, 0xFF, @@ -4306,14 +4306,30 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0xFF, 0xFF, 0xFF, 0xD8, 0x91, 0xB4, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xC0, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0xDE, 0xB3, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xA9, 0xAC, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xBE, 0x95, 0xA0, 0xFF, -0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x9E, 0x69, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xE1, 0x69, 0x70, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x49, 0x52, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x5E, 0x2D, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE5, 0x29, 0x34, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE6, 0x47, 0x4A, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x12, 0x51, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x27, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF2, 0x33, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x07, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD2, 0x15, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xE6, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB1, 0xF7, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, -0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, +0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xAF, 0xEE, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF0, 0x71, 0xBB, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8F, 0xD0, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF2, 0x7F, 0xC1, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x6F, 0xB2, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF4, 0x5F, 0xA3, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x4F, 0x94, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF6, 0x3F, 0x85, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x2F, 0x76, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF8, 0x28, 0xA2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x0F, 0x58, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xFA, 0x08, 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xF8, 0x83, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFB, 0xE8, 0x66, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xD8, 0x65, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFD, 0xC8, 0x48, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xB8, 0x47, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x2A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, +0x00, 0x00, 0x00, 0x01, 0x88, 0x0C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0B, 0x20, 0x00, +0x00, 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, 0x27, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x05, 0x51, 0x0A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x06, 0x41, 0x09, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x07, 0x30, 0xEC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8D, 0x43, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x09, 0x10, 0xCE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xAD, 0xBF, 0x20, 0x00, +0x00, 0x00, 0x00, 0x0A, 0xF0, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xCD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xAF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xAE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, @@ -4354,6 +4370,8 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x14, 0x4C, 0x4D, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, 0x50, @@ -8348,7 +8366,7 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0xB6, 0xE8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xA9, 0x79, 0x4F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF1, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x66, 0x64, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1B, 0x10, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xB8, 0x0A, 0xF2, 0xF0, 0xFF, @@ -8357,14 +8375,30 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0xFF, 0xFF, 0xFF, 0xD8, 0x91, 0xB4, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xC0, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0xDE, 0xB3, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xA9, 0xAC, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xBE, 0x95, 0xA0, 0xFF, -0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x9E, 0x69, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xE1, 0x69, 0x70, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x49, 0x52, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x5E, 0x2D, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE5, 0x29, 0x34, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE6, 0x47, 0x4A, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x12, 0x51, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x27, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF2, 0x33, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x07, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD2, 0x15, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xE6, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB1, 0xF7, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, -0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, +0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xAF, 0xEE, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF0, 0x71, 0xBB, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8F, 0xD0, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF2, 0x7F, 0xC1, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x6F, 0xB2, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF4, 0x5F, 0xA3, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x4F, 0x94, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF6, 0x3F, 0x85, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x2F, 0x76, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF8, 0x28, 0xA2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x0F, 0x58, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xFA, 0x08, 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xF8, 0x83, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFB, 0xE8, 0x66, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xD8, 0x65, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFD, 0xC8, 0x48, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xB8, 0x47, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x2A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, +0x00, 0x00, 0x00, 0x01, 0x88, 0x0C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0B, 0x20, 0x00, +0x00, 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, 0x27, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x05, 0x51, 0x0A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x06, 0x41, 0x09, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x07, 0x30, 0xEC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8D, 0x43, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x09, 0x10, 0xCE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xAD, 0xBF, 0x20, 0x00, +0x00, 0x00, 0x00, 0x0A, 0xF0, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xCD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xAF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xAE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, @@ -8405,6 +8439,8 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x14, 0x4C, 0x4D, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, 0x50, @@ -9196,7 +9232,7 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0xB6, 0xE8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xA9, 0x79, 0x4F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF1, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x66, 0x64, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1B, 0x10, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xB8, 0x0A, 0xF2, 0xF0, 0xFF, @@ -9205,14 +9241,30 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0xFF, 0xFF, 0xFF, 0xD8, 0x91, 0xB4, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xC0, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0xDE, 0xB3, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xA9, 0xAC, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xBE, 0x95, 0xA0, 0xFF, -0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x9E, 0x69, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xE1, 0x69, 0x70, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x49, 0x52, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x5E, 0x2D, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE5, 0x29, 0x34, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE6, 0x47, 0x4A, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x12, 0x51, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x27, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF2, 0x33, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x07, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD2, 0x15, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xE6, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB1, 0xF7, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, -0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, +0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xAF, 0xEE, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF0, 0x71, 0xBB, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8F, 0xD0, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF2, 0x7F, 0xC1, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x6F, 0xB2, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF4, 0x5F, 0xA3, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x4F, 0x94, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF6, 0x3F, 0x85, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x2F, 0x76, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF8, 0x28, 0xA2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x0F, 0x58, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xFA, 0x08, 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xF8, 0x83, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFB, 0xE8, 0x66, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xD8, 0x65, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFD, 0xC8, 0x48, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xB8, 0x47, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x2A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, +0x00, 0x00, 0x00, 0x01, 0x88, 0x0C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0B, 0x20, 0x00, +0x00, 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, 0x27, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x05, 0x51, 0x0A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x06, 0x41, 0x09, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x07, 0x30, 0xEC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8D, 0x43, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x09, 0x10, 0xCE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xAD, 0xBF, 0x20, 0x00, +0x00, 0x00, 0x00, 0x0A, 0xF0, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xCD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xAF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xAE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, @@ -9253,6 +9305,8 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x14, 0x4C, 0x4D, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, 0x50, @@ -21680,7 +21734,7 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0xFF, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0xB6, 0xE8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xA9, 0x79, 0x4F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF1, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x66, 0x64, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1B, 0x10, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xB8, 0x0A, 0xF2, 0xF0, 0xFF, @@ -21689,14 +21743,30 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0xFF, 0xFF, 0xFF, 0xD8, 0x91, 0xB4, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xC0, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0xDE, 0xB3, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xA9, 0xAC, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xBE, 0x95, 0xA0, 0xFF, -0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x9E, 0x69, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xE1, 0x69, 0x70, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x49, 0x52, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x5E, 0x2D, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE5, 0x29, 0x34, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE6, 0x47, 0x4A, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x12, 0x51, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x27, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF2, 0x33, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x07, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD2, 0x15, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xE6, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB1, 0xF7, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, -0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, +0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xAF, 0xEE, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF0, 0x71, 0xBB, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8F, 0xD0, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF2, 0x7F, 0xC1, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x6F, 0xB2, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF4, 0x5F, 0xA3, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x4F, 0x94, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF6, 0x3F, 0x85, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x2F, 0x76, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF8, 0x28, 0xA2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x0F, 0x58, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xFA, 0x08, 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xF8, 0x83, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFB, 0xE8, 0x66, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xD8, 0x65, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFD, 0xC8, 0x48, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xB8, 0x47, 0x20, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x2A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, +0x00, 0x00, 0x00, 0x01, 0x88, 0x0C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0B, 0x20, 0x00, +0x00, 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, 0x27, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x05, 0x51, 0x0A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x06, 0x41, 0x09, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x07, 0x30, 0xEC, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8D, 0x43, 0xA0, 0x00, +0x00, 0x00, 0x00, 0x09, 0x10, 0xCE, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xAD, 0xBF, 0x20, 0x00, +0x00, 0x00, 0x00, 0x0A, 0xF0, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xCD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xAF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xAE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, @@ -21737,6 +21807,8 @@ const unsigned char timelib_timezone_db_data_builtin[355607] = { 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, +0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x14, 0x4C, 0x4D, 0x54, 0x00, 0x4D, 0x53, 0x54, 0x00, 0x50, @@ -24443,495 +24515,495 @@ const timelib_tzdb_index_entry timezonedb_idx_builtin[598] = { { (char*) "America/Eirunepe" , 0x0154AA }, { (char*) "America/El_Salvador" , 0x015747 }, { (char*) "America/Ensenada" , 0x015833 }, - { (char*) "America/Fort_Nelson" , 0x0161D9 }, - { (char*) "America/Fort_Wayne" , 0x016AB9 }, - { (char*) "America/Fortaleza" , 0x017157 }, - { (char*) "America/Glace_Bay" , 0x017447 }, - { (char*) "America/Godthab" , 0x017CFE }, - { (char*) "America/Goose_Bay" , 0x01846B }, - { (char*) "America/Grand_Turk" , 0x019121 }, - { (char*) "America/Grenada" , 0x019857 }, - { (char*) "America/Guadeloupe" , 0x0198F7 }, - { (char*) "America/Guatemala" , 0x019997 }, - { (char*) "America/Guayaquil" , 0x019ABB }, - { (char*) "America/Guyana" , 0x019BC1 }, - { (char*) "America/Halifax" , 0x019CC5 }, - { (char*) "America/Havana" , 0x01AA4F }, - { (char*) "America/Hermosillo" , 0x01B3CB }, - { (char*) "America/Indiana/Indianapolis" , 0x01B561 }, - { (char*) "America/Indiana/Knox" , 0x01BC18 }, - { (char*) "America/Indiana/Marengo" , 0x01C5C5 }, - { (char*) "America/Indiana/Petersburg" , 0x01CCB2 }, - { (char*) "America/Indiana/Tell_City" , 0x01D451 }, - { (char*) "America/Indiana/Vevay" , 0x01DB15 }, - { (char*) "America/Indiana/Vincennes" , 0x01E0D1 }, - { (char*) "America/Indiana/Winamac" , 0x01E7A7 }, - { (char*) "America/Indianapolis" , 0x01EECB }, - { (char*) "America/Inuvik" , 0x01F569 }, - { (char*) "America/Iqaluit" , 0x01FDA3 }, - { (char*) "America/Jamaica" , 0x020662 }, - { (char*) "America/Jujuy" , 0x020850 }, - { (char*) "America/Juneau" , 0x020C66 }, - { (char*) "America/Kentucky/Louisville" , 0x0215B7 }, - { (char*) "America/Kentucky/Monticello" , 0x0220C5 }, - { (char*) "America/Knox_IN" , 0x022A25 }, - { (char*) "America/Kralendijk" , 0x0233BD }, - { (char*) "America/La_Paz" , 0x0234BF }, - { (char*) "America/Lima" , 0x0235A5 }, - { (char*) "America/Los_Angeles" , 0x023739 }, - { (char*) "America/Louisville" , 0x024270 }, - { (char*) "America/Lower_Princes" , 0x024D60 }, - { (char*) "America/Maceio" , 0x024E62 }, - { (char*) "America/Managua" , 0x025158 }, - { (char*) "America/Manaus" , 0x025312 }, - { (char*) "America/Marigot" , 0x02557B }, - { (char*) "America/Martinique" , 0x02567D }, - { (char*) "America/Matamoros" , 0x025771 }, - { (char*) "America/Mazatlan" , 0x025D33 }, - { (char*) "America/Mendoza" , 0x026195 }, - { (char*) "America/Menominee" , 0x0265C7 }, - { (char*) "America/Merida" , 0x026ED4 }, - { (char*) "America/Metlakatla" , 0x0272DD }, - { (char*) "America/Mexico_City" , 0x02788F }, - { (char*) "America/Miquelon" , 0x027D6F }, - { (char*) "America/Moncton" , 0x0283EF }, - { (char*) "America/Monterrey" , 0x029065 }, - { (char*) "America/Montevideo" , 0x029501 }, - { (char*) "America/Montreal" , 0x029AE5 }, - { (char*) "America/Montserrat" , 0x02A897 }, - { (char*) "America/Nassau" , 0x02A937 }, - { (char*) "America/New_York" , 0x02B297 }, - { (char*) "America/Nipigon" , 0x02C097 }, - { (char*) "America/Nome" , 0x02CE49 }, - { (char*) "America/Noronha" , 0x02D7A1 }, - { (char*) "America/North_Dakota/Beulah" , 0x02DA7B }, - { (char*) "America/North_Dakota/Center" , 0x02E3F8 }, - { (char*) "America/North_Dakota/New_Salem" , 0x02ED75 }, - { (char*) "America/Nuuk" , 0x02F6F8 }, - { (char*) "America/Ojinaga" , 0x02FE76 }, - { (char*) "America/Panama" , 0x030492 }, - { (char*) "America/Pangnirtung" , 0x030554 }, - { (char*) "America/Paramaribo" , 0x030DFA }, - { (char*) "America/Phoenix" , 0x030EFE }, - { (char*) "America/Port-au-Prince" , 0x03108A }, - { (char*) "America/Port_of_Spain" , 0x031630 }, - { (char*) "America/Porto_Acre" , 0x0316D0 }, - { (char*) "America/Porto_Velho" , 0x031942 }, - { (char*) "America/Puerto_Rico" , 0x031B88 }, - { (char*) "America/Punta_Arenas" , 0x031C8A }, - { (char*) "America/Rainy_River" , 0x032415 }, - { (char*) "America/Rankin_Inlet" , 0x032F55 }, - { (char*) "America/Recife" , 0x033789 }, - { (char*) "America/Regina" , 0x033A5D }, - { (char*) "America/Resolute" , 0x033E52 }, - { (char*) "America/Rio_Branco" , 0x034687 }, - { (char*) "America/Rosario" , 0x0348FD }, - { (char*) "America/Santa_Isabel" , 0x034D2F }, - { (char*) "America/Santarem" , 0x0356D5 }, - { (char*) "America/Santiago" , 0x035938 }, - { (char*) "America/Santo_Domingo" , 0x036324 }, - { (char*) "America/Sao_Paulo" , 0x0364FA }, - { (char*) "America/Scoresbysund" , 0x036AD2 }, - { (char*) "America/Shiprock" , 0x03728A }, - { (char*) "America/Sitka" , 0x037C32 }, - { (char*) "America/St_Barthelemy" , 0x03856A }, - { (char*) "America/St_Johns" , 0x03866C }, - { (char*) "America/St_Kitts" , 0x0394DA }, - { (char*) "America/St_Lucia" , 0x03957A }, - { (char*) "America/St_Thomas" , 0x03963C }, - { (char*) "America/St_Vincent" , 0x0396DC }, - { (char*) "America/Swift_Current" , 0x03979E }, - { (char*) "America/Tegucigalpa" , 0x0399EC }, - { (char*) "America/Thule" , 0x039AF4 }, - { (char*) "America/Thunder_Bay" , 0x03A0EC }, - { (char*) "America/Tijuana" , 0x03AE9E }, - { (char*) "America/Toronto" , 0x03B853 }, - { (char*) "America/Tortola" , 0x03C623 }, - { (char*) "America/Vancouver" , 0x03C6C3 }, - { (char*) "America/Virgin" , 0x03D234 }, - { (char*) "America/Whitehorse" , 0x03D336 }, - { (char*) "America/Winnipeg" , 0x03D9A2 }, - { (char*) "America/Yakutat" , 0x03E4FF }, - { (char*) "America/Yellowknife" , 0x03EE1C }, - { (char*) "Antarctica/Casey" , 0x03F744 }, - { (char*) "Antarctica/Davis" , 0x03F8FC }, - { (char*) "Antarctica/DumontDUrville" , 0x03FA28 }, - { (char*) "Antarctica/Macquarie" , 0x03FAF8 }, - { (char*) "Antarctica/Mawson" , 0x0403E8 }, - { (char*) "Antarctica/McMurdo" , 0x0404B3 }, - { (char*) "Antarctica/Palmer" , 0x040CAE }, - { (char*) "Antarctica/Rothera" , 0x04123C }, - { (char*) "Antarctica/South_Pole" , 0x0412E5 }, - { (char*) "Antarctica/Syowa" , 0x041C76 }, - { (char*) "Antarctica/Troll" , 0x041D1E }, - { (char*) "Antarctica/Vostok" , 0x0421AB }, - { (char*) "Arctic/Longyearbyen" , 0x042292 }, - { (char*) "Asia/Aden" , 0x042B98 }, - { (char*) "Asia/Almaty" , 0x042C3B }, - { (char*) "Asia/Amman" , 0x043030 }, - { (char*) "Asia/Anadyr" , 0x0435D5 }, - { (char*) "Asia/Aqtau" , 0x043A8A }, - { (char*) "Asia/Aqtobe" , 0x043E74 }, - { (char*) "Asia/Ashgabat" , 0x044272 }, - { (char*) "Asia/Ashkhabad" , 0x0444DB }, - { (char*) "Asia/Atyrau" , 0x044744 }, - { (char*) "Asia/Baghdad" , 0x044B36 }, - { (char*) "Asia/Bahrain" , 0x044F0B }, - { (char*) "Asia/Baku" , 0x044FF6 }, - { (char*) "Asia/Bangkok" , 0x0454BF }, - { (char*) "Asia/Barnaul" , 0x045584 }, - { (char*) "Asia/Beirut" , 0x045A55 }, - { (char*) "Asia/Bishkek" , 0x0462CB }, - { (char*) "Asia/Brunei" , 0x0466A0 }, - { (char*) "Asia/Calcutta" , 0x046769 }, - { (char*) "Asia/Chita" , 0x046892 }, - { (char*) "Asia/Choibalsan" , 0x046D69 }, - { (char*) "Asia/Chongqing" , 0x0470E2 }, - { (char*) "Asia/Chungking" , 0x04731F }, - { (char*) "Asia/Colombo" , 0x04755C }, - { (char*) "Asia/Dacca" , 0x0476CE }, - { (char*) "Asia/Damascus" , 0x04781D }, - { (char*) "Asia/Dhaka" , 0x047F7A }, - { (char*) "Asia/Dili" , 0x0480C9 }, - { (char*) "Asia/Dubai" , 0x0481D6 }, - { (char*) "Asia/Dushanbe" , 0x048279 }, - { (char*) "Asia/Famagusta" , 0x0484C6 }, - { (char*) "Asia/Gaza" , 0x048CCD }, - { (char*) "Asia/Harbin" , 0x049BE7 }, - { (char*) "Asia/Hebron" , 0x049E24 }, - { (char*) "Asia/Ho_Chi_Minh" , 0x04AD59 }, - { (char*) "Asia/Hong_Kong" , 0x04AEB6 }, - { (char*) "Asia/Hovd" , 0x04B393 }, - { (char*) "Asia/Irkutsk" , 0x04B722 }, - { (char*) "Asia/Istanbul" , 0x04BC15 }, - { (char*) "Asia/Jakarta" , 0x04C3AE }, - { (char*) "Asia/Jayapura" , 0x04C546 }, - { (char*) "Asia/Jerusalem" , 0x04C665 }, - { (char*) "Asia/Kabul" , 0x04CFC5 }, - { (char*) "Asia/Kamchatka" , 0x04D093 }, - { (char*) "Asia/Karachi" , 0x04D531 }, - { (char*) "Asia/Kashgar" , 0x04D6B8 }, - { (char*) "Asia/Kathmandu" , 0x04D75B }, - { (char*) "Asia/Katmandu" , 0x04D82D }, - { (char*) "Asia/Khandyga" , 0x04D8FF }, - { (char*) "Asia/Kolkata" , 0x04DE12 }, - { (char*) "Asia/Krasnoyarsk" , 0x04DF3B }, - { (char*) "Asia/Kuala_Lumpur" , 0x04E409 }, - { (char*) "Asia/Kuching" , 0x04E5BA }, - { (char*) "Asia/Kuwait" , 0x04E7A9 }, - { (char*) "Asia/Macao" , 0x04E84C }, - { (char*) "Asia/Macau" , 0x04ED23 }, - { (char*) "Asia/Magadan" , 0x04F1FA }, - { (char*) "Asia/Makassar" , 0x04F6CE }, - { (char*) "Asia/Manila" , 0x04F821 }, - { (char*) "Asia/Muscat" , 0x04F9D3 }, - { (char*) "Asia/Nicosia" , 0x04FA76 }, - { (char*) "Asia/Novokuznetsk" , 0x050262 }, - { (char*) "Asia/Novosibirsk" , 0x0506FE }, - { (char*) "Asia/Omsk" , 0x050BD5 }, - { (char*) "Asia/Oral" , 0x051097 }, - { (char*) "Asia/Phnom_Penh" , 0x051491 }, - { (char*) "Asia/Pontianak" , 0x0515B6 }, - { (char*) "Asia/Pyongyang" , 0x051739 }, - { (char*) "Asia/Qatar" , 0x051832 }, - { (char*) "Asia/Qostanay" , 0x0518F7 }, - { (char*) "Asia/Qyzylorda" , 0x051D1E }, - { (char*) "Asia/Rangoon" , 0x05213A }, - { (char*) "Asia/Riyadh" , 0x052244 }, - { (char*) "Asia/Saigon" , 0x0522E7 }, - { (char*) "Asia/Sakhalin" , 0x052444 }, - { (char*) "Asia/Samarkand" , 0x05290C }, - { (char*) "Asia/Seoul" , 0x052B5C }, - { (char*) "Asia/Shanghai" , 0x052DD1 }, - { (char*) "Asia/Singapore" , 0x05301A }, - { (char*) "Asia/Srednekolymsk" , 0x0531B7 }, - { (char*) "Asia/Taipei" , 0x05368B }, - { (char*) "Asia/Tashkent" , 0x053990 }, - { (char*) "Asia/Tbilisi" , 0x053BEE }, - { (char*) "Asia/Tehran" , 0x053FF7 }, - { (char*) "Asia/Tel_Aviv" , 0x0544E3 }, - { (char*) "Asia/Thimbu" , 0x054E43 }, - { (char*) "Asia/Thimphu" , 0x054F0C }, - { (char*) "Asia/Tokyo" , 0x054FD5 }, - { (char*) "Asia/Tomsk" , 0x055116 }, - { (char*) "Asia/Ujung_Pandang" , 0x0555E7 }, - { (char*) "Asia/Ulaanbaatar" , 0x0556F1 }, - { (char*) "Asia/Ulan_Bator" , 0x055A7A }, - { (char*) "Asia/Urumqi" , 0x055DF3 }, - { (char*) "Asia/Ust-Nera" , 0x055EA3 }, - { (char*) "Asia/Vientiane" , 0x056399 }, - { (char*) "Asia/Vladivostok" , 0x0564DA }, - { (char*) "Asia/Yakutsk" , 0x0569A3 }, - { (char*) "Asia/Yangon" , 0x056E6B }, - { (char*) "Asia/Yekaterinburg" , 0x056F75 }, - { (char*) "Asia/Yerevan" , 0x05745C }, - { (char*) "Atlantic/Azores" , 0x0578D9 }, - { (char*) "Atlantic/Bermuda" , 0x05865D }, - { (char*) "Atlantic/Canary" , 0x058FC5 }, - { (char*) "Atlantic/Cape_Verde" , 0x059748 }, - { (char*) "Atlantic/Faeroe" , 0x059854 }, - { (char*) "Atlantic/Faroe" , 0x059F77 }, - { (char*) "Atlantic/Jan_Mayen" , 0x05A69A }, - { (char*) "Atlantic/Madeira" , 0x05AFA0 }, - { (char*) "Atlantic/Reykjavik" , 0x05BCEC }, - { (char*) "Atlantic/South_Georgia" , 0x05C182 }, - { (char*) "Atlantic/St_Helena" , 0x05C224 }, - { (char*) "Atlantic/Stanley" , 0x05C2E6 }, - { (char*) "Australia/ACT" , 0x05C7A2 }, - { (char*) "Australia/Adelaide" , 0x05D03C }, - { (char*) "Australia/Brisbane" , 0x05D8F7 }, - { (char*) "Australia/Broken_Hill" , 0x05DABD }, - { (char*) "Australia/Canberra" , 0x05E39A }, - { (char*) "Australia/Currie" , 0x05EC34 }, - { (char*) "Australia/Darwin" , 0x05F576 }, - { (char*) "Australia/Eucla" , 0x05F6D9 }, - { (char*) "Australia/Hobart" , 0x05F8C6 }, - { (char*) "Australia/LHI" , 0x060210 }, - { (char*) "Australia/Lindeman" , 0x060952 }, - { (char*) "Australia/Lord_Howe" , 0x060B58 }, - { (char*) "Australia/Melbourne" , 0x0612AA }, - { (char*) "Australia/North" , 0x061B4C }, - { (char*) "Australia/NSW" , 0x061C9D }, - { (char*) "Australia/Perth" , 0x062537 }, - { (char*) "Australia/Queensland" , 0x06271F }, - { (char*) "Australia/South" , 0x0628CE }, - { (char*) "Australia/Sydney" , 0x06317A }, - { (char*) "Australia/Tasmania" , 0x063A30 }, - { (char*) "Australia/Victoria" , 0x064372 }, - { (char*) "Australia/West" , 0x064C0C }, - { (char*) "Australia/Yancowinna" , 0x064DD6 }, - { (char*) "Brazil/Acre" , 0x065697 }, - { (char*) "Brazil/DeNoronha" , 0x065909 }, - { (char*) "Brazil/East" , 0x065BD3 }, - { (char*) "Brazil/West" , 0x066175 }, - { (char*) "Canada/Atlantic" , 0x0663CF }, - { (char*) "Canada/Central" , 0x06713B }, - { (char*) "Canada/Eastern" , 0x067C7B }, - { (char*) "Canada/Mountain" , 0x068A2D }, - { (char*) "Canada/Newfoundland" , 0x069355 }, - { (char*) "Canada/Pacific" , 0x06A1A8 }, - { (char*) "Canada/Saskatchewan" , 0x06AD00 }, - { (char*) "Canada/Yukon" , 0x06B0E0 }, - { (char*) "CET" , 0x06B73A }, - { (char*) "Chile/Continental" , 0x06C2BB }, - { (char*) "Chile/EasterIsland" , 0x06CC9A }, - { (char*) "CST6CDT" , 0x06D551 }, - { (char*) "Cuba" , 0x06E365 }, - { (char*) "EET" , 0x06ECE1 }, - { (char*) "Egypt" , 0x06F5C3 }, - { (char*) "Eire" , 0x06FF2E }, - { (char*) "EST" , 0x070CDE }, - { (char*) "EST5EDT" , 0x070DA0 }, - { (char*) "Etc/GMT" , 0x071B8C }, - { (char*) "Etc/GMT+0" , 0x071C0A }, - { (char*) "Etc/GMT+1" , 0x071C88 }, - { (char*) "Etc/GMT+10" , 0x071D08 }, - { (char*) "Etc/GMT+11" , 0x071D89 }, - { (char*) "Etc/GMT+12" , 0x071E0A }, - { (char*) "Etc/GMT+2" , 0x071E8B }, - { (char*) "Etc/GMT+3" , 0x071F0B }, - { (char*) "Etc/GMT+4" , 0x071F8B }, - { (char*) "Etc/GMT+5" , 0x07200B }, - { (char*) "Etc/GMT+6" , 0x07208B }, - { (char*) "Etc/GMT+7" , 0x07210B }, - { (char*) "Etc/GMT+8" , 0x07218B }, - { (char*) "Etc/GMT+9" , 0x07220B }, - { (char*) "Etc/GMT-0" , 0x07228B }, - { (char*) "Etc/GMT-1" , 0x072309 }, - { (char*) "Etc/GMT-10" , 0x07238A }, - { (char*) "Etc/GMT-11" , 0x07240C }, - { (char*) "Etc/GMT-12" , 0x07248E }, - { (char*) "Etc/GMT-13" , 0x072510 }, - { (char*) "Etc/GMT-14" , 0x072592 }, - { (char*) "Etc/GMT-2" , 0x072614 }, - { (char*) "Etc/GMT-3" , 0x072695 }, - { (char*) "Etc/GMT-4" , 0x072716 }, - { (char*) "Etc/GMT-5" , 0x072797 }, - { (char*) "Etc/GMT-6" , 0x072818 }, - { (char*) "Etc/GMT-7" , 0x072899 }, - { (char*) "Etc/GMT-8" , 0x07291A }, - { (char*) "Etc/GMT-9" , 0x07299B }, - { (char*) "Etc/GMT0" , 0x072A1C }, - { (char*) "Etc/Greenwich" , 0x072A9A }, - { (char*) "Etc/UCT" , 0x072B18 }, - { (char*) "Etc/Universal" , 0x072B96 }, - { (char*) "Etc/UTC" , 0x072C14 }, - { (char*) "Etc/Zulu" , 0x072C92 }, - { (char*) "Europe/Amsterdam" , 0x072D10 }, - { (char*) "Europe/Andorra" , 0x07387A }, - { (char*) "Europe/Astrakhan" , 0x073F54 }, - { (char*) "Europe/Athens" , 0x0743F1 }, - { (char*) "Europe/Belfast" , 0x074CD3 }, - { (char*) "Europe/Belgrade" , 0x075B2F }, - { (char*) "Europe/Berlin" , 0x0762BB }, - { (char*) "Europe/Bratislava" , 0x076BD0 }, - { (char*) "Europe/Brussels" , 0x0774D9 }, - { (char*) "Europe/Bucharest" , 0x07805A }, - { (char*) "Europe/Budapest" , 0x0788EE }, - { (char*) "Europe/Busingen" , 0x07923A }, - { (char*) "Europe/Chisinau" , 0x0799C3 }, - { (char*) "Europe/Copenhagen" , 0x07A325 }, - { (char*) "Europe/Dublin" , 0x07AB8A }, - { (char*) "Europe/Gibraltar" , 0x07B93A }, - { (char*) "Europe/Guernsey" , 0x07C542 }, - { (char*) "Europe/Helsinki" , 0x07D3E2 }, - { (char*) "Europe/Isle_of_Man" , 0x07DB5A }, - { (char*) "Europe/Istanbul" , 0x07E9A6 }, - { (char*) "Europe/Jersey" , 0x07F13F }, - { (char*) "Europe/Kaliningrad" , 0x07FFDF }, - { (char*) "Europe/Kiev" , 0x0805D4 }, - { (char*) "Europe/Kirov" , 0x080E28 }, - { (char*) "Europe/Kyiv" , 0x0812E3 }, - { (char*) "Europe/Lisbon" , 0x081B46 }, - { (char*) "Europe/Ljubljana" , 0x08292C }, - { (char*) "Europe/London" , 0x0830B8 }, - { (char*) "Europe/Luxembourg" , 0x083F14 }, - { (char*) "Europe/Madrid" , 0x084AA2 }, - { (char*) "Europe/Malta" , 0x0854F4 }, - { (char*) "Europe/Mariehamn" , 0x085F3C }, - { (char*) "Europe/Minsk" , 0x0866B4 }, - { (char*) "Europe/Monaco" , 0x086BDB }, - { (char*) "Europe/Moscow" , 0x087767 }, - { (char*) "Europe/Nicosia" , 0x087D86 }, - { (char*) "Europe/Oslo" , 0x088564 }, - { (char*) "Europe/Paris" , 0x088E24 }, - { (char*) "Europe/Podgorica" , 0x0899C2 }, - { (char*) "Europe/Prague" , 0x08A14E }, - { (char*) "Europe/Riga" , 0x08AA57 }, - { (char*) "Europe/Rome" , 0x08B2F9 }, - { (char*) "Europe/Samara" , 0x08BD56 }, - { (char*) "Europe/San_Marino" , 0x08C22C }, - { (char*) "Europe/Sarajevo" , 0x08CC89 }, - { (char*) "Europe/Saratov" , 0x08D415 }, - { (char*) "Europe/Simferopol" , 0x08D8C2 }, - { (char*) "Europe/Skopje" , 0x08DE91 }, - { (char*) "Europe/Sofia" , 0x08E61D }, - { (char*) "Europe/Stockholm" , 0x08EE46 }, - { (char*) "Europe/Tallinn" , 0x08F5C7 }, - { (char*) "Europe/Tirane" , 0x08FE37 }, - { (char*) "Europe/Tiraspol" , 0x090667 }, - { (char*) "Europe/Ulyanovsk" , 0x090FC9 }, - { (char*) "Europe/Uzhgorod" , 0x0914CC }, - { (char*) "Europe/Vaduz" , 0x091D20 }, - { (char*) "Europe/Vatican" , 0x09248C }, - { (char*) "Europe/Vienna" , 0x092EE9 }, - { (char*) "Europe/Vilnius" , 0x09378D }, - { (char*) "Europe/Volgograd" , 0x09400B }, - { (char*) "Europe/Warsaw" , 0x0944D2 }, - { (char*) "Europe/Zagreb" , 0x094F3C }, - { (char*) "Europe/Zaporozhye" , 0x0956C8 }, - { (char*) "Europe/Zurich" , 0x095F1C }, - { (char*) "Factory" , 0x09669D }, - { (char*) "GB" , 0x09671D }, - { (char*) "GB-Eire" , 0x097579 }, - { (char*) "GMT" , 0x0983D5 }, - { (char*) "GMT+0" , 0x098453 }, - { (char*) "GMT-0" , 0x0984D1 }, - { (char*) "GMT0" , 0x09854F }, - { (char*) "Greenwich" , 0x0985CD }, - { (char*) "Hongkong" , 0x09864B }, - { (char*) "HST" , 0x098B28 }, - { (char*) "Iceland" , 0x098C7D }, - { (char*) "Indian/Antananarivo" , 0x098D1D }, - { (char*) "Indian/Chagos" , 0x098E04 }, - { (char*) "Indian/Christmas" , 0x098EC9 }, - { (char*) "Indian/Cocos" , 0x098F6C }, - { (char*) "Indian/Comoro" , 0x099018 }, - { (char*) "Indian/Kerguelen" , 0x0990B9 }, - { (char*) "Indian/Mahe" , 0x09915C }, - { (char*) "Indian/Maldives" , 0x0991FF }, - { (char*) "Indian/Mauritius" , 0x0992C4 }, - { (char*) "Indian/Mayotte" , 0x0993B3 }, - { (char*) "Indian/Reunion" , 0x099454 }, - { (char*) "Iran" , 0x0994F7 }, - { (char*) "Israel" , 0x0999E3 }, - { (char*) "Jamaica" , 0x09A343 }, - { (char*) "Japan" , 0x09A531 }, - { (char*) "Kwajalein" , 0x09A672 }, - { (char*) "Libya" , 0x09A7AC }, - { (char*) "MET" , 0x09AA29 }, - { (char*) "Mexico/BajaNorte" , 0x09B5AA }, - { (char*) "Mexico/BajaSur" , 0x09BF50 }, - { (char*) "Mexico/General" , 0x09C380 }, - { (char*) "MST" , 0x09C852 }, - { (char*) "MST7MDT" , 0x09C9C6 }, - { (char*) "Navajo" , 0x09D36E }, - { (char*) "NZ" , 0x09DD16 }, - { (char*) "NZ-CHAT" , 0x09E6A7 }, - { (char*) "Pacific/Apia" , 0x09EEB9 }, - { (char*) "Pacific/Auckland" , 0x09F11B }, - { (char*) "Pacific/Bougainville" , 0x09FABF }, - { (char*) "Pacific/Chatham" , 0x09FBD5 }, - { (char*) "Pacific/Chuuk" , 0x0A03F6 }, - { (char*) "Pacific/Easter" , 0x0A0510 }, - { (char*) "Pacific/Efate" , 0x0A0DD4 }, - { (char*) "Pacific/Enderbury" , 0x0A0FEC }, - { (char*) "Pacific/Fakaofo" , 0x0A10D4 }, - { (char*) "Pacific/Fiji" , 0x0A119A }, - { (char*) "Pacific/Funafuti" , 0x0A13DA }, - { (char*) "Pacific/Galapagos" , 0x0A147E }, - { (char*) "Pacific/Gambier" , 0x0A157B }, - { (char*) "Pacific/Guadalcanal" , 0x0A162C }, - { (char*) "Pacific/Guam" , 0x0A16D0 }, - { (char*) "Pacific/Honolulu" , 0x0A18CA }, - { (char*) "Pacific/Johnston" , 0x0A1A25 }, - { (char*) "Pacific/Kanton" , 0x0A1B7A }, - { (char*) "Pacific/Kiritimati" , 0x0A1C71 }, - { (char*) "Pacific/Kosrae" , 0x0A1D69 }, - { (char*) "Pacific/Kwajalein" , 0x0A1ECC }, - { (char*) "Pacific/Majuro" , 0x0A200F }, - { (char*) "Pacific/Marquesas" , 0x0A215B }, - { (char*) "Pacific/Midway" , 0x0A2217 }, - { (char*) "Pacific/Nauru" , 0x0A230A }, - { (char*) "Pacific/Niue" , 0x0A2404 }, - { (char*) "Pacific/Norfolk" , 0x0A24CD }, - { (char*) "Pacific/Noumea" , 0x0A283B }, - { (char*) "Pacific/Pago_Pago" , 0x0A2969 }, - { (char*) "Pacific/Palau" , 0x0A2A24 }, - { (char*) "Pacific/Pitcairn" , 0x0A2AD6 }, - { (char*) "Pacific/Pohnpei" , 0x0A2B9E }, - { (char*) "Pacific/Ponape" , 0x0A2CD9 }, - { (char*) "Pacific/Port_Moresby" , 0x0A2D7D }, - { (char*) "Pacific/Rarotonga" , 0x0A2E4D }, - { (char*) "Pacific/Saipan" , 0x0A30A6 }, - { (char*) "Pacific/Samoa" , 0x0A3292 }, - { (char*) "Pacific/Tahiti" , 0x0A334D }, - { (char*) "Pacific/Tarawa" , 0x0A33FF }, - { (char*) "Pacific/Tongatapu" , 0x0A34B2 }, - { (char*) "Pacific/Truk" , 0x0A3624 }, - { (char*) "Pacific/Wake" , 0x0A36DC }, - { (char*) "Pacific/Wallis" , 0x0A378B }, - { (char*) "Pacific/Yap" , 0x0A382F }, - { (char*) "Poland" , 0x0A38E7 }, - { (char*) "Portugal" , 0x0A4351 }, - { (char*) "PRC" , 0x0A5124 }, - { (char*) "PST8PDT" , 0x0A5361 }, - { (char*) "ROC" , 0x0A5E91 }, - { (char*) "ROK" , 0x0A6196 }, - { (char*) "Singapore" , 0x0A640B }, - { (char*) "Turkey" , 0x0A65A8 }, - { (char*) "UCT" , 0x0A6D41 }, - { (char*) "Universal" , 0x0A6DBF }, - { (char*) "US/Alaska" , 0x0A6E3D }, - { (char*) "US/Aleutian" , 0x0A778C }, - { (char*) "US/Arizona" , 0x0A80CC }, - { (char*) "US/Central" , 0x0A8240 }, - { (char*) "US/East-Indiana" , 0x0A9054 }, - { (char*) "US/Eastern" , 0x0A96F2 }, - { (char*) "US/Hawaii" , 0x0AA4DE }, - { (char*) "US/Indiana-Starke" , 0x0AA633 }, - { (char*) "US/Michigan" , 0x0AAFCB }, - { (char*) "US/Mountain" , 0x0AB88D }, - { (char*) "US/Pacific" , 0x0AC235 }, - { (char*) "US/Samoa" , 0x0ACD65 }, - { (char*) "UTC" , 0x0ACE20 }, - { (char*) "W-SU" , 0x0ACE9E }, - { (char*) "WET" , 0x0AD4A9 }, - { (char*) "Zulu" , 0x0AE27C }, + { (char*) "America/Fort_Nelson" , 0x016399 }, + { (char*) "America/Fort_Wayne" , 0x016C79 }, + { (char*) "America/Fortaleza" , 0x017317 }, + { (char*) "America/Glace_Bay" , 0x017607 }, + { (char*) "America/Godthab" , 0x017EBE }, + { (char*) "America/Goose_Bay" , 0x01862B }, + { (char*) "America/Grand_Turk" , 0x0192E1 }, + { (char*) "America/Grenada" , 0x019A17 }, + { (char*) "America/Guadeloupe" , 0x019AB7 }, + { (char*) "America/Guatemala" , 0x019B57 }, + { (char*) "America/Guayaquil" , 0x019C7B }, + { (char*) "America/Guyana" , 0x019D81 }, + { (char*) "America/Halifax" , 0x019E85 }, + { (char*) "America/Havana" , 0x01AC0F }, + { (char*) "America/Hermosillo" , 0x01B58B }, + { (char*) "America/Indiana/Indianapolis" , 0x01B721 }, + { (char*) "America/Indiana/Knox" , 0x01BDD8 }, + { (char*) "America/Indiana/Marengo" , 0x01C785 }, + { (char*) "America/Indiana/Petersburg" , 0x01CE72 }, + { (char*) "America/Indiana/Tell_City" , 0x01D611 }, + { (char*) "America/Indiana/Vevay" , 0x01DCD5 }, + { (char*) "America/Indiana/Vincennes" , 0x01E291 }, + { (char*) "America/Indiana/Winamac" , 0x01E967 }, + { (char*) "America/Indianapolis" , 0x01F08B }, + { (char*) "America/Inuvik" , 0x01F729 }, + { (char*) "America/Iqaluit" , 0x01FF63 }, + { (char*) "America/Jamaica" , 0x020822 }, + { (char*) "America/Jujuy" , 0x020A10 }, + { (char*) "America/Juneau" , 0x020E26 }, + { (char*) "America/Kentucky/Louisville" , 0x021777 }, + { (char*) "America/Kentucky/Monticello" , 0x022285 }, + { (char*) "America/Knox_IN" , 0x022BE5 }, + { (char*) "America/Kralendijk" , 0x02357D }, + { (char*) "America/La_Paz" , 0x02367F }, + { (char*) "America/Lima" , 0x023765 }, + { (char*) "America/Los_Angeles" , 0x0238F9 }, + { (char*) "America/Louisville" , 0x024430 }, + { (char*) "America/Lower_Princes" , 0x024F20 }, + { (char*) "America/Maceio" , 0x025022 }, + { (char*) "America/Managua" , 0x025318 }, + { (char*) "America/Manaus" , 0x0254D2 }, + { (char*) "America/Marigot" , 0x02573B }, + { (char*) "America/Martinique" , 0x02583D }, + { (char*) "America/Matamoros" , 0x025931 }, + { (char*) "America/Mazatlan" , 0x025EF3 }, + { (char*) "America/Mendoza" , 0x026355 }, + { (char*) "America/Menominee" , 0x026787 }, + { (char*) "America/Merida" , 0x027094 }, + { (char*) "America/Metlakatla" , 0x02749D }, + { (char*) "America/Mexico_City" , 0x027A4F }, + { (char*) "America/Miquelon" , 0x027F2F }, + { (char*) "America/Moncton" , 0x0285AF }, + { (char*) "America/Monterrey" , 0x029225 }, + { (char*) "America/Montevideo" , 0x0296C1 }, + { (char*) "America/Montreal" , 0x029CA5 }, + { (char*) "America/Montserrat" , 0x02AA57 }, + { (char*) "America/Nassau" , 0x02AAF7 }, + { (char*) "America/New_York" , 0x02B457 }, + { (char*) "America/Nipigon" , 0x02C257 }, + { (char*) "America/Nome" , 0x02D009 }, + { (char*) "America/Noronha" , 0x02D961 }, + { (char*) "America/North_Dakota/Beulah" , 0x02DC3B }, + { (char*) "America/North_Dakota/Center" , 0x02E5B8 }, + { (char*) "America/North_Dakota/New_Salem" , 0x02EF35 }, + { (char*) "America/Nuuk" , 0x02F8B8 }, + { (char*) "America/Ojinaga" , 0x030036 }, + { (char*) "America/Panama" , 0x030652 }, + { (char*) "America/Pangnirtung" , 0x030714 }, + { (char*) "America/Paramaribo" , 0x030FBA }, + { (char*) "America/Phoenix" , 0x0310BE }, + { (char*) "America/Port-au-Prince" , 0x03124A }, + { (char*) "America/Port_of_Spain" , 0x0317F0 }, + { (char*) "America/Porto_Acre" , 0x031890 }, + { (char*) "America/Porto_Velho" , 0x031B02 }, + { (char*) "America/Puerto_Rico" , 0x031D48 }, + { (char*) "America/Punta_Arenas" , 0x031E4A }, + { (char*) "America/Rainy_River" , 0x0325D5 }, + { (char*) "America/Rankin_Inlet" , 0x033115 }, + { (char*) "America/Recife" , 0x033949 }, + { (char*) "America/Regina" , 0x033C1D }, + { (char*) "America/Resolute" , 0x034012 }, + { (char*) "America/Rio_Branco" , 0x034847 }, + { (char*) "America/Rosario" , 0x034ABD }, + { (char*) "America/Santa_Isabel" , 0x034EEF }, + { (char*) "America/Santarem" , 0x035A55 }, + { (char*) "America/Santiago" , 0x035CB8 }, + { (char*) "America/Santo_Domingo" , 0x0366A4 }, + { (char*) "America/Sao_Paulo" , 0x03687A }, + { (char*) "America/Scoresbysund" , 0x036E52 }, + { (char*) "America/Shiprock" , 0x03760A }, + { (char*) "America/Sitka" , 0x037FB2 }, + { (char*) "America/St_Barthelemy" , 0x0388EA }, + { (char*) "America/St_Johns" , 0x0389EC }, + { (char*) "America/St_Kitts" , 0x03985A }, + { (char*) "America/St_Lucia" , 0x0398FA }, + { (char*) "America/St_Thomas" , 0x0399BC }, + { (char*) "America/St_Vincent" , 0x039A5C }, + { (char*) "America/Swift_Current" , 0x039B1E }, + { (char*) "America/Tegucigalpa" , 0x039D6C }, + { (char*) "America/Thule" , 0x039E74 }, + { (char*) "America/Thunder_Bay" , 0x03A46C }, + { (char*) "America/Tijuana" , 0x03B21E }, + { (char*) "America/Toronto" , 0x03BD93 }, + { (char*) "America/Tortola" , 0x03CB63 }, + { (char*) "America/Vancouver" , 0x03CC03 }, + { (char*) "America/Virgin" , 0x03D774 }, + { (char*) "America/Whitehorse" , 0x03D876 }, + { (char*) "America/Winnipeg" , 0x03DEE2 }, + { (char*) "America/Yakutat" , 0x03EA3F }, + { (char*) "America/Yellowknife" , 0x03F35C }, + { (char*) "Antarctica/Casey" , 0x03FC84 }, + { (char*) "Antarctica/Davis" , 0x03FE3C }, + { (char*) "Antarctica/DumontDUrville" , 0x03FF68 }, + { (char*) "Antarctica/Macquarie" , 0x040038 }, + { (char*) "Antarctica/Mawson" , 0x040928 }, + { (char*) "Antarctica/McMurdo" , 0x0409F3 }, + { (char*) "Antarctica/Palmer" , 0x0411EE }, + { (char*) "Antarctica/Rothera" , 0x04177C }, + { (char*) "Antarctica/South_Pole" , 0x041825 }, + { (char*) "Antarctica/Syowa" , 0x0421B6 }, + { (char*) "Antarctica/Troll" , 0x04225E }, + { (char*) "Antarctica/Vostok" , 0x0426EB }, + { (char*) "Arctic/Longyearbyen" , 0x0427D2 }, + { (char*) "Asia/Aden" , 0x0430D8 }, + { (char*) "Asia/Almaty" , 0x04317B }, + { (char*) "Asia/Amman" , 0x043570 }, + { (char*) "Asia/Anadyr" , 0x043B15 }, + { (char*) "Asia/Aqtau" , 0x043FCA }, + { (char*) "Asia/Aqtobe" , 0x0443B4 }, + { (char*) "Asia/Ashgabat" , 0x0447B2 }, + { (char*) "Asia/Ashkhabad" , 0x044A1B }, + { (char*) "Asia/Atyrau" , 0x044C84 }, + { (char*) "Asia/Baghdad" , 0x045076 }, + { (char*) "Asia/Bahrain" , 0x04544B }, + { (char*) "Asia/Baku" , 0x045536 }, + { (char*) "Asia/Bangkok" , 0x0459FF }, + { (char*) "Asia/Barnaul" , 0x045AC4 }, + { (char*) "Asia/Beirut" , 0x045F95 }, + { (char*) "Asia/Bishkek" , 0x04680B }, + { (char*) "Asia/Brunei" , 0x046BE0 }, + { (char*) "Asia/Calcutta" , 0x046CA9 }, + { (char*) "Asia/Chita" , 0x046DD2 }, + { (char*) "Asia/Choibalsan" , 0x0472A9 }, + { (char*) "Asia/Chongqing" , 0x047622 }, + { (char*) "Asia/Chungking" , 0x04785F }, + { (char*) "Asia/Colombo" , 0x047A9C }, + { (char*) "Asia/Dacca" , 0x047C0E }, + { (char*) "Asia/Damascus" , 0x047D5D }, + { (char*) "Asia/Dhaka" , 0x0484BA }, + { (char*) "Asia/Dili" , 0x048609 }, + { (char*) "Asia/Dubai" , 0x048716 }, + { (char*) "Asia/Dushanbe" , 0x0487B9 }, + { (char*) "Asia/Famagusta" , 0x048A06 }, + { (char*) "Asia/Gaza" , 0x04920D }, + { (char*) "Asia/Harbin" , 0x04A127 }, + { (char*) "Asia/Hebron" , 0x04A364 }, + { (char*) "Asia/Ho_Chi_Minh" , 0x04B299 }, + { (char*) "Asia/Hong_Kong" , 0x04B3F6 }, + { (char*) "Asia/Hovd" , 0x04B8D3 }, + { (char*) "Asia/Irkutsk" , 0x04BC62 }, + { (char*) "Asia/Istanbul" , 0x04C155 }, + { (char*) "Asia/Jakarta" , 0x04C8EE }, + { (char*) "Asia/Jayapura" , 0x04CA86 }, + { (char*) "Asia/Jerusalem" , 0x04CBA5 }, + { (char*) "Asia/Kabul" , 0x04D505 }, + { (char*) "Asia/Kamchatka" , 0x04D5D3 }, + { (char*) "Asia/Karachi" , 0x04DA71 }, + { (char*) "Asia/Kashgar" , 0x04DBF8 }, + { (char*) "Asia/Kathmandu" , 0x04DC9B }, + { (char*) "Asia/Katmandu" , 0x04DD6D }, + { (char*) "Asia/Khandyga" , 0x04DE3F }, + { (char*) "Asia/Kolkata" , 0x04E352 }, + { (char*) "Asia/Krasnoyarsk" , 0x04E47B }, + { (char*) "Asia/Kuala_Lumpur" , 0x04E949 }, + { (char*) "Asia/Kuching" , 0x04EAFA }, + { (char*) "Asia/Kuwait" , 0x04ECE9 }, + { (char*) "Asia/Macao" , 0x04ED8C }, + { (char*) "Asia/Macau" , 0x04F263 }, + { (char*) "Asia/Magadan" , 0x04F73A }, + { (char*) "Asia/Makassar" , 0x04FC0E }, + { (char*) "Asia/Manila" , 0x04FD61 }, + { (char*) "Asia/Muscat" , 0x04FF13 }, + { (char*) "Asia/Nicosia" , 0x04FFB6 }, + { (char*) "Asia/Novokuznetsk" , 0x0507A2 }, + { (char*) "Asia/Novosibirsk" , 0x050C3E }, + { (char*) "Asia/Omsk" , 0x051115 }, + { (char*) "Asia/Oral" , 0x0515D7 }, + { (char*) "Asia/Phnom_Penh" , 0x0519D1 }, + { (char*) "Asia/Pontianak" , 0x051AF6 }, + { (char*) "Asia/Pyongyang" , 0x051C79 }, + { (char*) "Asia/Qatar" , 0x051D72 }, + { (char*) "Asia/Qostanay" , 0x051E37 }, + { (char*) "Asia/Qyzylorda" , 0x05225E }, + { (char*) "Asia/Rangoon" , 0x05267A }, + { (char*) "Asia/Riyadh" , 0x052784 }, + { (char*) "Asia/Saigon" , 0x052827 }, + { (char*) "Asia/Sakhalin" , 0x052984 }, + { (char*) "Asia/Samarkand" , 0x052E4C }, + { (char*) "Asia/Seoul" , 0x05309C }, + { (char*) "Asia/Shanghai" , 0x053311 }, + { (char*) "Asia/Singapore" , 0x05355A }, + { (char*) "Asia/Srednekolymsk" , 0x0536F7 }, + { (char*) "Asia/Taipei" , 0x053BCB }, + { (char*) "Asia/Tashkent" , 0x053ED0 }, + { (char*) "Asia/Tbilisi" , 0x05412E }, + { (char*) "Asia/Tehran" , 0x054537 }, + { (char*) "Asia/Tel_Aviv" , 0x054A23 }, + { (char*) "Asia/Thimbu" , 0x055383 }, + { (char*) "Asia/Thimphu" , 0x05544C }, + { (char*) "Asia/Tokyo" , 0x055515 }, + { (char*) "Asia/Tomsk" , 0x055656 }, + { (char*) "Asia/Ujung_Pandang" , 0x055B27 }, + { (char*) "Asia/Ulaanbaatar" , 0x055C31 }, + { (char*) "Asia/Ulan_Bator" , 0x055FBA }, + { (char*) "Asia/Urumqi" , 0x056333 }, + { (char*) "Asia/Ust-Nera" , 0x0563E3 }, + { (char*) "Asia/Vientiane" , 0x0568D9 }, + { (char*) "Asia/Vladivostok" , 0x056A1A }, + { (char*) "Asia/Yakutsk" , 0x056EE3 }, + { (char*) "Asia/Yangon" , 0x0573AB }, + { (char*) "Asia/Yekaterinburg" , 0x0574B5 }, + { (char*) "Asia/Yerevan" , 0x05799C }, + { (char*) "Atlantic/Azores" , 0x057E19 }, + { (char*) "Atlantic/Bermuda" , 0x058B9D }, + { (char*) "Atlantic/Canary" , 0x059505 }, + { (char*) "Atlantic/Cape_Verde" , 0x059C88 }, + { (char*) "Atlantic/Faeroe" , 0x059D94 }, + { (char*) "Atlantic/Faroe" , 0x05A4B7 }, + { (char*) "Atlantic/Jan_Mayen" , 0x05ABDA }, + { (char*) "Atlantic/Madeira" , 0x05B4E0 }, + { (char*) "Atlantic/Reykjavik" , 0x05C22C }, + { (char*) "Atlantic/South_Georgia" , 0x05C6C2 }, + { (char*) "Atlantic/St_Helena" , 0x05C764 }, + { (char*) "Atlantic/Stanley" , 0x05C826 }, + { (char*) "Australia/ACT" , 0x05CCE2 }, + { (char*) "Australia/Adelaide" , 0x05D57C }, + { (char*) "Australia/Brisbane" , 0x05DE37 }, + { (char*) "Australia/Broken_Hill" , 0x05DFFD }, + { (char*) "Australia/Canberra" , 0x05E8DA }, + { (char*) "Australia/Currie" , 0x05F174 }, + { (char*) "Australia/Darwin" , 0x05FAB6 }, + { (char*) "Australia/Eucla" , 0x05FC19 }, + { (char*) "Australia/Hobart" , 0x05FE06 }, + { (char*) "Australia/LHI" , 0x060750 }, + { (char*) "Australia/Lindeman" , 0x060E92 }, + { (char*) "Australia/Lord_Howe" , 0x061098 }, + { (char*) "Australia/Melbourne" , 0x0617EA }, + { (char*) "Australia/North" , 0x06208C }, + { (char*) "Australia/NSW" , 0x0621DD }, + { (char*) "Australia/Perth" , 0x062A77 }, + { (char*) "Australia/Queensland" , 0x062C5F }, + { (char*) "Australia/South" , 0x062E0E }, + { (char*) "Australia/Sydney" , 0x0636BA }, + { (char*) "Australia/Tasmania" , 0x063F70 }, + { (char*) "Australia/Victoria" , 0x0648B2 }, + { (char*) "Australia/West" , 0x06514C }, + { (char*) "Australia/Yancowinna" , 0x065316 }, + { (char*) "Brazil/Acre" , 0x065BD7 }, + { (char*) "Brazil/DeNoronha" , 0x065E49 }, + { (char*) "Brazil/East" , 0x066113 }, + { (char*) "Brazil/West" , 0x0666B5 }, + { (char*) "Canada/Atlantic" , 0x06690F }, + { (char*) "Canada/Central" , 0x06767B }, + { (char*) "Canada/Eastern" , 0x0681BB }, + { (char*) "Canada/Mountain" , 0x068F6D }, + { (char*) "Canada/Newfoundland" , 0x069895 }, + { (char*) "Canada/Pacific" , 0x06A6E8 }, + { (char*) "Canada/Saskatchewan" , 0x06B240 }, + { (char*) "Canada/Yukon" , 0x06B620 }, + { (char*) "CET" , 0x06BC7A }, + { (char*) "Chile/Continental" , 0x06C7FB }, + { (char*) "Chile/EasterIsland" , 0x06D1DA }, + { (char*) "CST6CDT" , 0x06DA91 }, + { (char*) "Cuba" , 0x06E8A5 }, + { (char*) "EET" , 0x06F221 }, + { (char*) "Egypt" , 0x06FB03 }, + { (char*) "Eire" , 0x07046E }, + { (char*) "EST" , 0x07121E }, + { (char*) "EST5EDT" , 0x0712E0 }, + { (char*) "Etc/GMT" , 0x0720CC }, + { (char*) "Etc/GMT+0" , 0x07214A }, + { (char*) "Etc/GMT+1" , 0x0721C8 }, + { (char*) "Etc/GMT+10" , 0x072248 }, + { (char*) "Etc/GMT+11" , 0x0722C9 }, + { (char*) "Etc/GMT+12" , 0x07234A }, + { (char*) "Etc/GMT+2" , 0x0723CB }, + { (char*) "Etc/GMT+3" , 0x07244B }, + { (char*) "Etc/GMT+4" , 0x0724CB }, + { (char*) "Etc/GMT+5" , 0x07254B }, + { (char*) "Etc/GMT+6" , 0x0725CB }, + { (char*) "Etc/GMT+7" , 0x07264B }, + { (char*) "Etc/GMT+8" , 0x0726CB }, + { (char*) "Etc/GMT+9" , 0x07274B }, + { (char*) "Etc/GMT-0" , 0x0727CB }, + { (char*) "Etc/GMT-1" , 0x072849 }, + { (char*) "Etc/GMT-10" , 0x0728CA }, + { (char*) "Etc/GMT-11" , 0x07294C }, + { (char*) "Etc/GMT-12" , 0x0729CE }, + { (char*) "Etc/GMT-13" , 0x072A50 }, + { (char*) "Etc/GMT-14" , 0x072AD2 }, + { (char*) "Etc/GMT-2" , 0x072B54 }, + { (char*) "Etc/GMT-3" , 0x072BD5 }, + { (char*) "Etc/GMT-4" , 0x072C56 }, + { (char*) "Etc/GMT-5" , 0x072CD7 }, + { (char*) "Etc/GMT-6" , 0x072D58 }, + { (char*) "Etc/GMT-7" , 0x072DD9 }, + { (char*) "Etc/GMT-8" , 0x072E5A }, + { (char*) "Etc/GMT-9" , 0x072EDB }, + { (char*) "Etc/GMT0" , 0x072F5C }, + { (char*) "Etc/Greenwich" , 0x072FDA }, + { (char*) "Etc/UCT" , 0x073058 }, + { (char*) "Etc/Universal" , 0x0730D6 }, + { (char*) "Etc/UTC" , 0x073154 }, + { (char*) "Etc/Zulu" , 0x0731D2 }, + { (char*) "Europe/Amsterdam" , 0x073250 }, + { (char*) "Europe/Andorra" , 0x073DBA }, + { (char*) "Europe/Astrakhan" , 0x074494 }, + { (char*) "Europe/Athens" , 0x074931 }, + { (char*) "Europe/Belfast" , 0x075213 }, + { (char*) "Europe/Belgrade" , 0x07606F }, + { (char*) "Europe/Berlin" , 0x0767FB }, + { (char*) "Europe/Bratislava" , 0x077110 }, + { (char*) "Europe/Brussels" , 0x077A19 }, + { (char*) "Europe/Bucharest" , 0x07859A }, + { (char*) "Europe/Budapest" , 0x078E2E }, + { (char*) "Europe/Busingen" , 0x07977A }, + { (char*) "Europe/Chisinau" , 0x079F03 }, + { (char*) "Europe/Copenhagen" , 0x07A865 }, + { (char*) "Europe/Dublin" , 0x07B0CA }, + { (char*) "Europe/Gibraltar" , 0x07BE7A }, + { (char*) "Europe/Guernsey" , 0x07CA82 }, + { (char*) "Europe/Helsinki" , 0x07D922 }, + { (char*) "Europe/Isle_of_Man" , 0x07E09A }, + { (char*) "Europe/Istanbul" , 0x07EEE6 }, + { (char*) "Europe/Jersey" , 0x07F67F }, + { (char*) "Europe/Kaliningrad" , 0x08051F }, + { (char*) "Europe/Kiev" , 0x080B14 }, + { (char*) "Europe/Kirov" , 0x081368 }, + { (char*) "Europe/Kyiv" , 0x081823 }, + { (char*) "Europe/Lisbon" , 0x082086 }, + { (char*) "Europe/Ljubljana" , 0x082E6C }, + { (char*) "Europe/London" , 0x0835F8 }, + { (char*) "Europe/Luxembourg" , 0x084454 }, + { (char*) "Europe/Madrid" , 0x084FE2 }, + { (char*) "Europe/Malta" , 0x085A34 }, + { (char*) "Europe/Mariehamn" , 0x08647C }, + { (char*) "Europe/Minsk" , 0x086BF4 }, + { (char*) "Europe/Monaco" , 0x08711B }, + { (char*) "Europe/Moscow" , 0x087CA7 }, + { (char*) "Europe/Nicosia" , 0x0882C6 }, + { (char*) "Europe/Oslo" , 0x088AA4 }, + { (char*) "Europe/Paris" , 0x089364 }, + { (char*) "Europe/Podgorica" , 0x089F02 }, + { (char*) "Europe/Prague" , 0x08A68E }, + { (char*) "Europe/Riga" , 0x08AF97 }, + { (char*) "Europe/Rome" , 0x08B839 }, + { (char*) "Europe/Samara" , 0x08C296 }, + { (char*) "Europe/San_Marino" , 0x08C76C }, + { (char*) "Europe/Sarajevo" , 0x08D1C9 }, + { (char*) "Europe/Saratov" , 0x08D955 }, + { (char*) "Europe/Simferopol" , 0x08DE02 }, + { (char*) "Europe/Skopje" , 0x08E3D1 }, + { (char*) "Europe/Sofia" , 0x08EB5D }, + { (char*) "Europe/Stockholm" , 0x08F386 }, + { (char*) "Europe/Tallinn" , 0x08FB07 }, + { (char*) "Europe/Tirane" , 0x090377 }, + { (char*) "Europe/Tiraspol" , 0x090BA7 }, + { (char*) "Europe/Ulyanovsk" , 0x091509 }, + { (char*) "Europe/Uzhgorod" , 0x091A0C }, + { (char*) "Europe/Vaduz" , 0x092260 }, + { (char*) "Europe/Vatican" , 0x0929CC }, + { (char*) "Europe/Vienna" , 0x093429 }, + { (char*) "Europe/Vilnius" , 0x093CCD }, + { (char*) "Europe/Volgograd" , 0x09454B }, + { (char*) "Europe/Warsaw" , 0x094A12 }, + { (char*) "Europe/Zagreb" , 0x09547C }, + { (char*) "Europe/Zaporozhye" , 0x095C08 }, + { (char*) "Europe/Zurich" , 0x09645C }, + { (char*) "Factory" , 0x096BDD }, + { (char*) "GB" , 0x096C5D }, + { (char*) "GB-Eire" , 0x097AB9 }, + { (char*) "GMT" , 0x098915 }, + { (char*) "GMT+0" , 0x098993 }, + { (char*) "GMT-0" , 0x098A11 }, + { (char*) "GMT0" , 0x098A8F }, + { (char*) "Greenwich" , 0x098B0D }, + { (char*) "Hongkong" , 0x098B8B }, + { (char*) "HST" , 0x099068 }, + { (char*) "Iceland" , 0x0991BD }, + { (char*) "Indian/Antananarivo" , 0x09925D }, + { (char*) "Indian/Chagos" , 0x099344 }, + { (char*) "Indian/Christmas" , 0x099409 }, + { (char*) "Indian/Cocos" , 0x0994AC }, + { (char*) "Indian/Comoro" , 0x099558 }, + { (char*) "Indian/Kerguelen" , 0x0995F9 }, + { (char*) "Indian/Mahe" , 0x09969C }, + { (char*) "Indian/Maldives" , 0x09973F }, + { (char*) "Indian/Mauritius" , 0x099804 }, + { (char*) "Indian/Mayotte" , 0x0998F3 }, + { (char*) "Indian/Reunion" , 0x099994 }, + { (char*) "Iran" , 0x099A37 }, + { (char*) "Israel" , 0x099F23 }, + { (char*) "Jamaica" , 0x09A883 }, + { (char*) "Japan" , 0x09AA71 }, + { (char*) "Kwajalein" , 0x09ABB2 }, + { (char*) "Libya" , 0x09ACEC }, + { (char*) "MET" , 0x09AF69 }, + { (char*) "Mexico/BajaNorte" , 0x09BAEA }, + { (char*) "Mexico/BajaSur" , 0x09C650 }, + { (char*) "Mexico/General" , 0x09CA80 }, + { (char*) "MST" , 0x09CF52 }, + { (char*) "MST7MDT" , 0x09D0C6 }, + { (char*) "Navajo" , 0x09DA6E }, + { (char*) "NZ" , 0x09E416 }, + { (char*) "NZ-CHAT" , 0x09EDA7 }, + { (char*) "Pacific/Apia" , 0x09F5B9 }, + { (char*) "Pacific/Auckland" , 0x09F81B }, + { (char*) "Pacific/Bougainville" , 0x0A01BF }, + { (char*) "Pacific/Chatham" , 0x0A02D5 }, + { (char*) "Pacific/Chuuk" , 0x0A0AF6 }, + { (char*) "Pacific/Easter" , 0x0A0C10 }, + { (char*) "Pacific/Efate" , 0x0A14D4 }, + { (char*) "Pacific/Enderbury" , 0x0A16EC }, + { (char*) "Pacific/Fakaofo" , 0x0A17D4 }, + { (char*) "Pacific/Fiji" , 0x0A189A }, + { (char*) "Pacific/Funafuti" , 0x0A1ADA }, + { (char*) "Pacific/Galapagos" , 0x0A1B7E }, + { (char*) "Pacific/Gambier" , 0x0A1C7B }, + { (char*) "Pacific/Guadalcanal" , 0x0A1D2C }, + { (char*) "Pacific/Guam" , 0x0A1DD0 }, + { (char*) "Pacific/Honolulu" , 0x0A1FCA }, + { (char*) "Pacific/Johnston" , 0x0A2125 }, + { (char*) "Pacific/Kanton" , 0x0A227A }, + { (char*) "Pacific/Kiritimati" , 0x0A2371 }, + { (char*) "Pacific/Kosrae" , 0x0A2469 }, + { (char*) "Pacific/Kwajalein" , 0x0A25CC }, + { (char*) "Pacific/Majuro" , 0x0A270F }, + { (char*) "Pacific/Marquesas" , 0x0A285B }, + { (char*) "Pacific/Midway" , 0x0A2917 }, + { (char*) "Pacific/Nauru" , 0x0A2A0A }, + { (char*) "Pacific/Niue" , 0x0A2B04 }, + { (char*) "Pacific/Norfolk" , 0x0A2BCD }, + { (char*) "Pacific/Noumea" , 0x0A2F3B }, + { (char*) "Pacific/Pago_Pago" , 0x0A3069 }, + { (char*) "Pacific/Palau" , 0x0A3124 }, + { (char*) "Pacific/Pitcairn" , 0x0A31D6 }, + { (char*) "Pacific/Pohnpei" , 0x0A329E }, + { (char*) "Pacific/Ponape" , 0x0A33D9 }, + { (char*) "Pacific/Port_Moresby" , 0x0A347D }, + { (char*) "Pacific/Rarotonga" , 0x0A354D }, + { (char*) "Pacific/Saipan" , 0x0A37A6 }, + { (char*) "Pacific/Samoa" , 0x0A3992 }, + { (char*) "Pacific/Tahiti" , 0x0A3A4D }, + { (char*) "Pacific/Tarawa" , 0x0A3AFF }, + { (char*) "Pacific/Tongatapu" , 0x0A3BB2 }, + { (char*) "Pacific/Truk" , 0x0A3D24 }, + { (char*) "Pacific/Wake" , 0x0A3DDC }, + { (char*) "Pacific/Wallis" , 0x0A3E8B }, + { (char*) "Pacific/Yap" , 0x0A3F2F }, + { (char*) "Poland" , 0x0A3FE7 }, + { (char*) "Portugal" , 0x0A4A51 }, + { (char*) "PRC" , 0x0A5824 }, + { (char*) "PST8PDT" , 0x0A5A61 }, + { (char*) "ROC" , 0x0A6591 }, + { (char*) "ROK" , 0x0A6896 }, + { (char*) "Singapore" , 0x0A6B0B }, + { (char*) "Turkey" , 0x0A6CA8 }, + { (char*) "UCT" , 0x0A7441 }, + { (char*) "Universal" , 0x0A74BF }, + { (char*) "US/Alaska" , 0x0A753D }, + { (char*) "US/Aleutian" , 0x0A7E8C }, + { (char*) "US/Arizona" , 0x0A87CC }, + { (char*) "US/Central" , 0x0A8940 }, + { (char*) "US/East-Indiana" , 0x0A9754 }, + { (char*) "US/Eastern" , 0x0A9DF2 }, + { (char*) "US/Hawaii" , 0x0AABDE }, + { (char*) "US/Indiana-Starke" , 0x0AAD33 }, + { (char*) "US/Michigan" , 0x0AB6CB }, + { (char*) "US/Mountain" , 0x0ABF8D }, + { (char*) "US/Pacific" , 0x0AC935 }, + { (char*) "US/Samoa" , 0x0AD465 }, + { (char*) "UTC" , 0x0AD520 }, + { (char*) "W-SU" , 0x0AD59E }, + { (char*) "WET" , 0x0ADBA9 }, + { (char*) "Zulu" , 0x0AE97C }, }; -const unsigned char timelib_timezone_db_data_builtin[713466] = { +const unsigned char timelib_timezone_db_data_builtin[715258] = { /* Africa/Abidjan */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x43, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -30736,15 +30808,23 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { /* America/Ensenada */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xA5, 0xB6, 0xE8, 0x70, +0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xA5, 0xB6, 0xE8, 0x70, 0xA9, 0x79, 0x4F, 0x70, 0xAF, 0xF1, 0x39, 0x80, 0xB6, 0x66, 0x64, 0x70, 0xB7, 0x1B, 0x10, 0x00, 0xB8, 0x0A, 0xF2, 0xF0, 0xCB, 0xEA, 0x8D, 0x80, 0xD2, 0x23, 0xF4, 0x70, 0xD2, 0x9D, 0xAE, 0xF0, 0xD7, 0x1B, 0x59, 0x00, 0xD8, 0x91, 0xB4, 0xF0, 0xDB, 0x00, 0x07, 0x00, 0xDB, 0xC0, 0x73, 0xF0, 0xDC, 0xDE, 0xB3, 0xA0, 0xDD, 0xA9, 0xAC, 0x90, 0xDE, 0xBE, 0x95, 0xA0, 0xDF, 0x89, 0x8E, 0x90, -0xE2, 0x7E, 0x4B, 0x90, 0xE3, 0x49, 0x52, 0x90, 0xE4, 0x5E, 0x2D, 0x90, 0xE5, 0x29, 0x34, 0x90, -0xE6, 0x47, 0x4A, 0x10, 0xE7, 0x12, 0x51, 0x10, 0xE8, 0x27, 0x2C, 0x10, 0xE8, 0xF2, 0x33, 0x10, -0xEA, 0x07, 0x0E, 0x10, 0xEA, 0xD2, 0x15, 0x10, 0xEB, 0xE6, 0xF0, 0x10, 0xEC, 0xB1, 0xF7, 0x10, -0xED, 0xC6, 0xD2, 0x10, 0xEE, 0x91, 0xD9, 0x10, 0x0B, 0xE0, 0xAF, 0xA0, 0x0C, 0xD9, 0xCD, 0x10, +0xE0, 0x9E, 0x69, 0x90, 0xE1, 0x69, 0x70, 0x90, 0xE2, 0x7E, 0x4B, 0x90, 0xE3, 0x49, 0x52, 0x90, +0xE4, 0x5E, 0x2D, 0x90, 0xE5, 0x29, 0x34, 0x90, 0xE6, 0x47, 0x4A, 0x10, 0xE7, 0x12, 0x51, 0x10, +0xE8, 0x27, 0x2C, 0x10, 0xE8, 0xF2, 0x33, 0x10, 0xEA, 0x07, 0x0E, 0x10, 0xEA, 0xD2, 0x15, 0x10, +0xEB, 0xE6, 0xF0, 0x10, 0xEC, 0xB1, 0xF7, 0x10, 0xED, 0xC6, 0xD2, 0x10, 0xEE, 0x91, 0xD9, 0x10, +0xEF, 0xAF, 0xEE, 0x90, 0xF0, 0x71, 0xBB, 0x10, 0xF1, 0x8F, 0xD0, 0x90, 0xF2, 0x7F, 0xC1, 0x90, +0xF3, 0x6F, 0xB2, 0x90, 0xF4, 0x5F, 0xA3, 0x90, 0xF5, 0x4F, 0x94, 0x90, 0xF6, 0x3F, 0x85, 0x90, +0xF7, 0x2F, 0x76, 0x90, 0xF8, 0x28, 0xA2, 0x10, 0xF9, 0x0F, 0x58, 0x90, 0xFA, 0x08, 0x84, 0x10, +0xFA, 0xF8, 0x83, 0x20, 0xFB, 0xE8, 0x66, 0x10, 0xFC, 0xD8, 0x65, 0x20, 0xFD, 0xC8, 0x48, 0x10, +0xFE, 0xB8, 0x47, 0x20, 0xFF, 0xA8, 0x2A, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0C, 0x10, +0x02, 0x78, 0x0B, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xA0, 0x05, 0x51, 0x0A, 0x90, +0x06, 0x41, 0x09, 0xA0, 0x07, 0x30, 0xEC, 0x90, 0x07, 0x8D, 0x43, 0xA0, 0x09, 0x10, 0xCE, 0x90, +0x09, 0xAD, 0xBF, 0x20, 0x0A, 0xF0, 0xB0, 0x90, 0x0B, 0xE0, 0xAF, 0xA0, 0x0C, 0xD9, 0xCD, 0x10, 0x0D, 0xC0, 0x91, 0xA0, 0x0E, 0xB9, 0xAF, 0x10, 0x0F, 0xA9, 0xAE, 0x20, 0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10, 0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20, 0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90, @@ -30785,6 +30865,8 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, +0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, +0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x14, 0xFF, 0xFF, 0x8F, @@ -30792,7 +30874,7 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x44, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50, 0x50, 0x54, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x00, +0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0xB6, 0xE8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xA9, 0x79, 0x4F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF1, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x66, 0x64, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1B, 0x10, 0x00, 0xFF, @@ -30802,13 +30884,29 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0xFF, 0xFF, 0xFF, 0xDB, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xC0, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0xDE, 0xB3, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xA9, 0xAC, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xBE, 0x95, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xE0, 0x9E, 0x69, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x69, 0x70, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x49, 0x52, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x5E, 0x2D, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE5, 0x29, 0x34, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE6, 0x47, 0x4A, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x12, 0x51, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x27, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF2, 0x33, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x07, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD2, 0x15, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xE6, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB1, 0xF7, 0x10, 0xFF, -0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0x00, +0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xEF, 0xAF, 0xEE, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x71, 0xBB, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xF1, 0x8F, 0xD0, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x7F, 0xC1, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF3, 0x6F, 0xB2, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x5F, 0xA3, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF5, 0x4F, 0x94, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0x3F, 0x85, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF7, 0x2F, 0x76, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x28, 0xA2, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xF9, 0x0F, 0x58, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x08, 0x84, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFA, 0xF8, 0x83, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xE8, 0x66, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFC, 0xD8, 0x65, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xC8, 0x48, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFE, 0xB8, 0x47, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x2A, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x0C, 0x10, 0x00, +0x00, 0x00, 0x00, 0x02, 0x78, 0x0B, 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, +0x00, 0x00, 0x00, 0x04, 0x61, 0x27, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0A, 0x90, 0x00, +0x00, 0x00, 0x00, 0x06, 0x41, 0x09, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, 0xEC, 0x90, 0x00, +0x00, 0x00, 0x00, 0x07, 0x8D, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xCE, 0x90, 0x00, +0x00, 0x00, 0x00, 0x09, 0xAD, 0xBF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xF0, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xCD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xAF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xAE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, @@ -30880,6 +30978,8 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, @@ -38972,15 +39072,23 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { /* America/Santa_Isabel */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xA5, 0xB6, 0xE8, 0x70, +0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xA5, 0xB6, 0xE8, 0x70, 0xA9, 0x79, 0x4F, 0x70, 0xAF, 0xF1, 0x39, 0x80, 0xB6, 0x66, 0x64, 0x70, 0xB7, 0x1B, 0x10, 0x00, 0xB8, 0x0A, 0xF2, 0xF0, 0xCB, 0xEA, 0x8D, 0x80, 0xD2, 0x23, 0xF4, 0x70, 0xD2, 0x9D, 0xAE, 0xF0, 0xD7, 0x1B, 0x59, 0x00, 0xD8, 0x91, 0xB4, 0xF0, 0xDB, 0x00, 0x07, 0x00, 0xDB, 0xC0, 0x73, 0xF0, 0xDC, 0xDE, 0xB3, 0xA0, 0xDD, 0xA9, 0xAC, 0x90, 0xDE, 0xBE, 0x95, 0xA0, 0xDF, 0x89, 0x8E, 0x90, -0xE2, 0x7E, 0x4B, 0x90, 0xE3, 0x49, 0x52, 0x90, 0xE4, 0x5E, 0x2D, 0x90, 0xE5, 0x29, 0x34, 0x90, -0xE6, 0x47, 0x4A, 0x10, 0xE7, 0x12, 0x51, 0x10, 0xE8, 0x27, 0x2C, 0x10, 0xE8, 0xF2, 0x33, 0x10, -0xEA, 0x07, 0x0E, 0x10, 0xEA, 0xD2, 0x15, 0x10, 0xEB, 0xE6, 0xF0, 0x10, 0xEC, 0xB1, 0xF7, 0x10, -0xED, 0xC6, 0xD2, 0x10, 0xEE, 0x91, 0xD9, 0x10, 0x0B, 0xE0, 0xAF, 0xA0, 0x0C, 0xD9, 0xCD, 0x10, +0xE0, 0x9E, 0x69, 0x90, 0xE1, 0x69, 0x70, 0x90, 0xE2, 0x7E, 0x4B, 0x90, 0xE3, 0x49, 0x52, 0x90, +0xE4, 0x5E, 0x2D, 0x90, 0xE5, 0x29, 0x34, 0x90, 0xE6, 0x47, 0x4A, 0x10, 0xE7, 0x12, 0x51, 0x10, +0xE8, 0x27, 0x2C, 0x10, 0xE8, 0xF2, 0x33, 0x10, 0xEA, 0x07, 0x0E, 0x10, 0xEA, 0xD2, 0x15, 0x10, +0xEB, 0xE6, 0xF0, 0x10, 0xEC, 0xB1, 0xF7, 0x10, 0xED, 0xC6, 0xD2, 0x10, 0xEE, 0x91, 0xD9, 0x10, +0xEF, 0xAF, 0xEE, 0x90, 0xF0, 0x71, 0xBB, 0x10, 0xF1, 0x8F, 0xD0, 0x90, 0xF2, 0x7F, 0xC1, 0x90, +0xF3, 0x6F, 0xB2, 0x90, 0xF4, 0x5F, 0xA3, 0x90, 0xF5, 0x4F, 0x94, 0x90, 0xF6, 0x3F, 0x85, 0x90, +0xF7, 0x2F, 0x76, 0x90, 0xF8, 0x28, 0xA2, 0x10, 0xF9, 0x0F, 0x58, 0x90, 0xFA, 0x08, 0x84, 0x10, +0xFA, 0xF8, 0x83, 0x20, 0xFB, 0xE8, 0x66, 0x10, 0xFC, 0xD8, 0x65, 0x20, 0xFD, 0xC8, 0x48, 0x10, +0xFE, 0xB8, 0x47, 0x20, 0xFF, 0xA8, 0x2A, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0C, 0x10, +0x02, 0x78, 0x0B, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xA0, 0x05, 0x51, 0x0A, 0x90, +0x06, 0x41, 0x09, 0xA0, 0x07, 0x30, 0xEC, 0x90, 0x07, 0x8D, 0x43, 0xA0, 0x09, 0x10, 0xCE, 0x90, +0x09, 0xAD, 0xBF, 0x20, 0x0A, 0xF0, 0xB0, 0x90, 0x0B, 0xE0, 0xAF, 0xA0, 0x0C, 0xD9, 0xCD, 0x10, 0x0D, 0xC0, 0x91, 0xA0, 0x0E, 0xB9, 0xAF, 0x10, 0x0F, 0xA9, 0xAE, 0x20, 0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10, 0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20, 0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90, @@ -39021,6 +39129,8 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, +0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, +0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x14, 0xFF, 0xFF, 0x8F, @@ -39028,7 +39138,7 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x44, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50, 0x50, 0x54, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x00, +0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0xB6, 0xE8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xA9, 0x79, 0x4F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF1, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x66, 0x64, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1B, 0x10, 0x00, 0xFF, @@ -39038,13 +39148,29 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0xFF, 0xFF, 0xFF, 0xDB, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xC0, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0xDE, 0xB3, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xA9, 0xAC, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xBE, 0x95, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xE0, 0x9E, 0x69, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x69, 0x70, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x49, 0x52, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x5E, 0x2D, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE5, 0x29, 0x34, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE6, 0x47, 0x4A, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x12, 0x51, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x27, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF2, 0x33, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x07, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD2, 0x15, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xE6, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB1, 0xF7, 0x10, 0xFF, -0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0x00, +0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xEF, 0xAF, 0xEE, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x71, 0xBB, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xF1, 0x8F, 0xD0, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x7F, 0xC1, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF3, 0x6F, 0xB2, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x5F, 0xA3, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF5, 0x4F, 0x94, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0x3F, 0x85, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF7, 0x2F, 0x76, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x28, 0xA2, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xF9, 0x0F, 0x58, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x08, 0x84, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFA, 0xF8, 0x83, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xE8, 0x66, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFC, 0xD8, 0x65, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xC8, 0x48, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFE, 0xB8, 0x47, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x2A, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x0C, 0x10, 0x00, +0x00, 0x00, 0x00, 0x02, 0x78, 0x0B, 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, +0x00, 0x00, 0x00, 0x04, 0x61, 0x27, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0A, 0x90, 0x00, +0x00, 0x00, 0x00, 0x06, 0x41, 0x09, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, 0xEC, 0x90, 0x00, +0x00, 0x00, 0x00, 0x07, 0x8D, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xCE, 0x90, 0x00, +0x00, 0x00, 0x00, 0x09, 0xAD, 0xBF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xF0, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xCD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xAF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xAE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, @@ -39116,6 +39242,8 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, @@ -40578,15 +40706,23 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { /* America/Tijuana */ 0x50, 0x48, 0x50, 0x32, 0x01, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xA5, 0xB6, 0xE8, 0x70, +0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xA5, 0xB6, 0xE8, 0x70, 0xA9, 0x79, 0x4F, 0x70, 0xAF, 0xF1, 0x39, 0x80, 0xB6, 0x66, 0x64, 0x70, 0xB7, 0x1B, 0x10, 0x00, 0xB8, 0x0A, 0xF2, 0xF0, 0xCB, 0xEA, 0x8D, 0x80, 0xD2, 0x23, 0xF4, 0x70, 0xD2, 0x9D, 0xAE, 0xF0, 0xD7, 0x1B, 0x59, 0x00, 0xD8, 0x91, 0xB4, 0xF0, 0xDB, 0x00, 0x07, 0x00, 0xDB, 0xC0, 0x73, 0xF0, 0xDC, 0xDE, 0xB3, 0xA0, 0xDD, 0xA9, 0xAC, 0x90, 0xDE, 0xBE, 0x95, 0xA0, 0xDF, 0x89, 0x8E, 0x90, -0xE2, 0x7E, 0x4B, 0x90, 0xE3, 0x49, 0x52, 0x90, 0xE4, 0x5E, 0x2D, 0x90, 0xE5, 0x29, 0x34, 0x90, -0xE6, 0x47, 0x4A, 0x10, 0xE7, 0x12, 0x51, 0x10, 0xE8, 0x27, 0x2C, 0x10, 0xE8, 0xF2, 0x33, 0x10, -0xEA, 0x07, 0x0E, 0x10, 0xEA, 0xD2, 0x15, 0x10, 0xEB, 0xE6, 0xF0, 0x10, 0xEC, 0xB1, 0xF7, 0x10, -0xED, 0xC6, 0xD2, 0x10, 0xEE, 0x91, 0xD9, 0x10, 0x0B, 0xE0, 0xAF, 0xA0, 0x0C, 0xD9, 0xCD, 0x10, +0xE0, 0x9E, 0x69, 0x90, 0xE1, 0x69, 0x70, 0x90, 0xE2, 0x7E, 0x4B, 0x90, 0xE3, 0x49, 0x52, 0x90, +0xE4, 0x5E, 0x2D, 0x90, 0xE5, 0x29, 0x34, 0x90, 0xE6, 0x47, 0x4A, 0x10, 0xE7, 0x12, 0x51, 0x10, +0xE8, 0x27, 0x2C, 0x10, 0xE8, 0xF2, 0x33, 0x10, 0xEA, 0x07, 0x0E, 0x10, 0xEA, 0xD2, 0x15, 0x10, +0xEB, 0xE6, 0xF0, 0x10, 0xEC, 0xB1, 0xF7, 0x10, 0xED, 0xC6, 0xD2, 0x10, 0xEE, 0x91, 0xD9, 0x10, +0xEF, 0xAF, 0xEE, 0x90, 0xF0, 0x71, 0xBB, 0x10, 0xF1, 0x8F, 0xD0, 0x90, 0xF2, 0x7F, 0xC1, 0x90, +0xF3, 0x6F, 0xB2, 0x90, 0xF4, 0x5F, 0xA3, 0x90, 0xF5, 0x4F, 0x94, 0x90, 0xF6, 0x3F, 0x85, 0x90, +0xF7, 0x2F, 0x76, 0x90, 0xF8, 0x28, 0xA2, 0x10, 0xF9, 0x0F, 0x58, 0x90, 0xFA, 0x08, 0x84, 0x10, +0xFA, 0xF8, 0x83, 0x20, 0xFB, 0xE8, 0x66, 0x10, 0xFC, 0xD8, 0x65, 0x20, 0xFD, 0xC8, 0x48, 0x10, +0xFE, 0xB8, 0x47, 0x20, 0xFF, 0xA8, 0x2A, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0C, 0x10, +0x02, 0x78, 0x0B, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xA0, 0x05, 0x51, 0x0A, 0x90, +0x06, 0x41, 0x09, 0xA0, 0x07, 0x30, 0xEC, 0x90, 0x07, 0x8D, 0x43, 0xA0, 0x09, 0x10, 0xCE, 0x90, +0x09, 0xAD, 0xBF, 0x20, 0x0A, 0xF0, 0xB0, 0x90, 0x0B, 0xE0, 0xAF, 0xA0, 0x0C, 0xD9, 0xCD, 0x10, 0x0D, 0xC0, 0x91, 0xA0, 0x0E, 0xB9, 0xAF, 0x10, 0x0F, 0xA9, 0xAE, 0x20, 0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10, 0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20, 0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90, @@ -40627,6 +40763,8 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, +0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, +0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x14, 0xFF, 0xFF, 0x8F, @@ -40634,7 +40772,7 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x44, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50, 0x50, 0x54, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x00, +0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0xB6, 0xE8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xA9, 0x79, 0x4F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF1, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x66, 0x64, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1B, 0x10, 0x00, 0xFF, @@ -40644,13 +40782,29 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0xFF, 0xFF, 0xFF, 0xDB, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xC0, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0xDE, 0xB3, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xA9, 0xAC, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xBE, 0x95, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xE0, 0x9E, 0x69, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x69, 0x70, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x49, 0x52, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x5E, 0x2D, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE5, 0x29, 0x34, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE6, 0x47, 0x4A, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x12, 0x51, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x27, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF2, 0x33, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x07, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD2, 0x15, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xE6, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB1, 0xF7, 0x10, 0xFF, -0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0x00, +0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xEF, 0xAF, 0xEE, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x71, 0xBB, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xF1, 0x8F, 0xD0, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x7F, 0xC1, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF3, 0x6F, 0xB2, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x5F, 0xA3, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF5, 0x4F, 0x94, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0x3F, 0x85, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF7, 0x2F, 0x76, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x28, 0xA2, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xF9, 0x0F, 0x58, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x08, 0x84, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFA, 0xF8, 0x83, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xE8, 0x66, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFC, 0xD8, 0x65, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xC8, 0x48, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFE, 0xB8, 0x47, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x2A, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x0C, 0x10, 0x00, +0x00, 0x00, 0x00, 0x02, 0x78, 0x0B, 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, +0x00, 0x00, 0x00, 0x04, 0x61, 0x27, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0A, 0x90, 0x00, +0x00, 0x00, 0x00, 0x06, 0x41, 0x09, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, 0xEC, 0x90, 0x00, +0x00, 0x00, 0x00, 0x07, 0x8D, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xCE, 0x90, 0x00, +0x00, 0x00, 0x00, 0x09, 0xAD, 0xBF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xF0, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xCD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xAF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xAE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, @@ -40722,6 +40876,8 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, @@ -66051,15 +66207,23 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { /* Mexico/BajaNorte */ 0x50, 0x48, 0x50, 0x32, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xA5, 0xB6, 0xE8, 0x70, +0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xA5, 0xB6, 0xE8, 0x70, 0xA9, 0x79, 0x4F, 0x70, 0xAF, 0xF1, 0x39, 0x80, 0xB6, 0x66, 0x64, 0x70, 0xB7, 0x1B, 0x10, 0x00, 0xB8, 0x0A, 0xF2, 0xF0, 0xCB, 0xEA, 0x8D, 0x80, 0xD2, 0x23, 0xF4, 0x70, 0xD2, 0x9D, 0xAE, 0xF0, 0xD7, 0x1B, 0x59, 0x00, 0xD8, 0x91, 0xB4, 0xF0, 0xDB, 0x00, 0x07, 0x00, 0xDB, 0xC0, 0x73, 0xF0, 0xDC, 0xDE, 0xB3, 0xA0, 0xDD, 0xA9, 0xAC, 0x90, 0xDE, 0xBE, 0x95, 0xA0, 0xDF, 0x89, 0x8E, 0x90, -0xE2, 0x7E, 0x4B, 0x90, 0xE3, 0x49, 0x52, 0x90, 0xE4, 0x5E, 0x2D, 0x90, 0xE5, 0x29, 0x34, 0x90, -0xE6, 0x47, 0x4A, 0x10, 0xE7, 0x12, 0x51, 0x10, 0xE8, 0x27, 0x2C, 0x10, 0xE8, 0xF2, 0x33, 0x10, -0xEA, 0x07, 0x0E, 0x10, 0xEA, 0xD2, 0x15, 0x10, 0xEB, 0xE6, 0xF0, 0x10, 0xEC, 0xB1, 0xF7, 0x10, -0xED, 0xC6, 0xD2, 0x10, 0xEE, 0x91, 0xD9, 0x10, 0x0B, 0xE0, 0xAF, 0xA0, 0x0C, 0xD9, 0xCD, 0x10, +0xE0, 0x9E, 0x69, 0x90, 0xE1, 0x69, 0x70, 0x90, 0xE2, 0x7E, 0x4B, 0x90, 0xE3, 0x49, 0x52, 0x90, +0xE4, 0x5E, 0x2D, 0x90, 0xE5, 0x29, 0x34, 0x90, 0xE6, 0x47, 0x4A, 0x10, 0xE7, 0x12, 0x51, 0x10, +0xE8, 0x27, 0x2C, 0x10, 0xE8, 0xF2, 0x33, 0x10, 0xEA, 0x07, 0x0E, 0x10, 0xEA, 0xD2, 0x15, 0x10, +0xEB, 0xE6, 0xF0, 0x10, 0xEC, 0xB1, 0xF7, 0x10, 0xED, 0xC6, 0xD2, 0x10, 0xEE, 0x91, 0xD9, 0x10, +0xEF, 0xAF, 0xEE, 0x90, 0xF0, 0x71, 0xBB, 0x10, 0xF1, 0x8F, 0xD0, 0x90, 0xF2, 0x7F, 0xC1, 0x90, +0xF3, 0x6F, 0xB2, 0x90, 0xF4, 0x5F, 0xA3, 0x90, 0xF5, 0x4F, 0x94, 0x90, 0xF6, 0x3F, 0x85, 0x90, +0xF7, 0x2F, 0x76, 0x90, 0xF8, 0x28, 0xA2, 0x10, 0xF9, 0x0F, 0x58, 0x90, 0xFA, 0x08, 0x84, 0x10, +0xFA, 0xF8, 0x83, 0x20, 0xFB, 0xE8, 0x66, 0x10, 0xFC, 0xD8, 0x65, 0x20, 0xFD, 0xC8, 0x48, 0x10, +0xFE, 0xB8, 0x47, 0x20, 0xFF, 0xA8, 0x2A, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0C, 0x10, +0x02, 0x78, 0x0B, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xA0, 0x05, 0x51, 0x0A, 0x90, +0x06, 0x41, 0x09, 0xA0, 0x07, 0x30, 0xEC, 0x90, 0x07, 0x8D, 0x43, 0xA0, 0x09, 0x10, 0xCE, 0x90, +0x09, 0xAD, 0xBF, 0x20, 0x0A, 0xF0, 0xB0, 0x90, 0x0B, 0xE0, 0xAF, 0xA0, 0x0C, 0xD9, 0xCD, 0x10, 0x0D, 0xC0, 0x91, 0xA0, 0x0E, 0xB9, 0xAF, 0x10, 0x0F, 0xA9, 0xAE, 0x20, 0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10, 0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20, 0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90, @@ -66100,6 +66264,8 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, +0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, +0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x14, 0xFF, 0xFF, 0x8F, @@ -66107,7 +66273,7 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x44, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50, 0x50, 0x54, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x54, 0x5A, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x00, +0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0xB6, 0xE8, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xA9, 0x79, 0x4F, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF1, 0x39, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xB6, 0x66, 0x64, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xB7, 0x1B, 0x10, 0x00, 0xFF, @@ -66117,13 +66283,29 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0xFF, 0xFF, 0xFF, 0xDB, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xC0, 0x73, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0xDE, 0xB3, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xA9, 0xAC, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xBE, 0x95, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x89, 0x8E, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xE0, 0x9E, 0x69, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x69, 0x70, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE2, 0x7E, 0x4B, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x49, 0x52, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x5E, 0x2D, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE5, 0x29, 0x34, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xE6, 0x47, 0x4A, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x12, 0x51, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0x27, 0x2C, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xE8, 0xF2, 0x33, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0x07, 0x0E, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD2, 0x15, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xE6, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xB1, 0xF7, 0x10, 0xFF, -0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0x00, +0xFF, 0xFF, 0xFF, 0xED, 0xC6, 0xD2, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x91, 0xD9, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xEF, 0xAF, 0xEE, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x71, 0xBB, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xF1, 0x8F, 0xD0, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x7F, 0xC1, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF3, 0x6F, 0xB2, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x5F, 0xA3, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF5, 0x4F, 0x94, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0x3F, 0x85, 0x90, 0xFF, +0xFF, 0xFF, 0xFF, 0xF7, 0x2F, 0x76, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x28, 0xA2, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xF9, 0x0F, 0x58, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x08, 0x84, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFA, 0xF8, 0x83, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xE8, 0x66, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFC, 0xD8, 0x65, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xC8, 0x48, 0x10, 0xFF, +0xFF, 0xFF, 0xFF, 0xFE, 0xB8, 0x47, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xA8, 0x2A, 0x10, 0x00, +0x00, 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x0C, 0x10, 0x00, +0x00, 0x00, 0x00, 0x02, 0x78, 0x0B, 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, +0x00, 0x00, 0x00, 0x04, 0x61, 0x27, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0A, 0x90, 0x00, +0x00, 0x00, 0x00, 0x06, 0x41, 0x09, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, 0xEC, 0x90, 0x00, +0x00, 0x00, 0x00, 0x07, 0x8D, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xCE, 0x90, 0x00, +0x00, 0x00, 0x00, 0x09, 0xAD, 0xBF, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xF0, 0xB0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xE0, 0xAF, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xD9, 0xCD, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xC0, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xB9, 0xAF, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xA9, 0xAE, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, @@ -66195,6 +66377,8 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, +0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0xFF, 0xFF, 0x92, 0x4C, 0x00, 0x00, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x08, 0xFF, 0xFF, 0x9D, 0x90, 0x00, 0x04, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x0C, 0xFF, 0xFF, 0x9D, 0x90, 0x01, 0x10, 0xFF, 0xFF, @@ -71071,4 +71255,4 @@ const unsigned char timelib_timezone_db_data_builtin[713466] = { }; #endif -const timelib_tzdb timezonedb_builtin = { "2025.2", 598, timezonedb_idx_builtin, timelib_timezone_db_data_builtin }; +const timelib_tzdb timezonedb_builtin = { "2025.3", 598, timezonedb_idx_builtin, timelib_timezone_db_data_builtin }; diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 692136bbad2ac..8f98589b2b47e 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -4063,7 +4063,7 @@ PHP_METHOD(DateTimeZone, __construct) } /* }}} */ -static bool php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, const HashTable *myht) /* {{{ */ +static bool php_date_timezone_initialize_from_hash(php_timezone_obj **tzobj, const HashTable *myht) /* {{{ */ { zval *z_timezone_type; @@ -4104,7 +4104,7 @@ PHP_METHOD(DateTimeZone, __set_state) php_date_instantiate(date_ce_timezone, return_value); tzobj = Z_PHPTIMEZONE_P(return_value); - if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) { + if (!php_date_timezone_initialize_from_hash(&tzobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); RETURN_THROWS(); } @@ -4124,7 +4124,7 @@ PHP_METHOD(DateTimeZone, __wakeup) myht = Z_OBJPROP_P(object); - if (!php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht)) { + if (!php_date_timezone_initialize_from_hash(&tzobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); RETURN_THROWS(); } @@ -4188,7 +4188,7 @@ PHP_METHOD(DateTimeZone, __unserialize) tzobj = Z_PHPTIMEZONE_P(object); - if (!php_date_timezone_initialize_from_hash(&object, &tzobj, myht)) { + if (!php_date_timezone_initialize_from_hash(&tzobj, myht)) { zend_throw_error(NULL, "Invalid serialization data for DateTimeZone object"); RETURN_THROWS(); } @@ -4613,7 +4613,7 @@ PHP_METHOD(DateInterval, __construct) } /* }}} */ -static void php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, const HashTable *myht) /* {{{ */ +static void php_date_interval_initialize_from_hash(php_interval_obj *intobj, const HashTable *myht) /* {{{ */ { /* If we have a date_string, use that instead */ const zval *date_str = zend_hash_str_find(myht, "date_string", strlen("date_string")); @@ -4635,15 +4635,15 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte } /* If ->diff is already set, then we need to free it first */ - if ((*intobj)->diff) { - timelib_rel_time_dtor((*intobj)->diff); + if (intobj->diff) { + timelib_rel_time_dtor(intobj->diff); } - (*intobj)->diff = timelib_rel_time_clone(&time->relative); - (*intobj)->initialized = true; - (*intobj)->civil_or_wall = PHP_DATE_CIVIL; - (*intobj)->from_string = true; - (*intobj)->date_string = zend_string_copy(Z_STR_P(date_str)); + intobj->diff = timelib_rel_time_clone(&time->relative); + intobj->initialized = true; + intobj->civil_or_wall = PHP_DATE_CIVIL; + intobj->from_string = true; + intobj->date_string = zend_string_copy(Z_STR_P(date_str)); timelib_time_dtor(time); timelib_error_container_dtor(err); @@ -4652,20 +4652,20 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte } /* If ->diff is already set, then we need to free it first */ - if ((*intobj)->diff) { - timelib_rel_time_dtor((*intobj)->diff); + if (intobj->diff) { + timelib_rel_time_dtor(intobj->diff); } /* Set new value */ - (*intobj)->diff = timelib_rel_time_ctor(); + intobj->diff = timelib_rel_time_ctor(); #define PHP_DATE_INTERVAL_READ_PROPERTY(element, member, itype, def) \ do { \ zval *z_arg = zend_hash_str_find(myht, element, sizeof(element) - 1); \ if (z_arg && Z_TYPE_P(z_arg) <= IS_STRING) { \ - (*intobj)->diff->member = (itype)zval_get_long(z_arg); \ + intobj->diff->member = (itype)zval_get_long(z_arg); \ } else { \ - (*intobj)->diff->member = (itype)def; \ + intobj->diff->member = (itype)def; \ } \ } while (0); @@ -4675,10 +4675,10 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte if (z_arg && Z_TYPE_P(z_arg) <= IS_STRING) { \ zend_string *tmp_str; \ zend_string *str = zval_get_tmp_string(z_arg, &tmp_str); \ - DATE_A64I((*intobj)->diff->member, ZSTR_VAL(str)); \ + DATE_A64I(intobj->diff->member, ZSTR_VAL(str)); \ zend_tmp_string_release(tmp_str); \ } else { \ - (*intobj)->diff->member = -1LL; \ + intobj->diff->member = -1LL; \ } \ } while (0); @@ -4686,14 +4686,14 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte do { \ zval *z_arg = zend_hash_str_find(myht, "days", sizeof("days") - 1); \ if (z_arg && Z_TYPE_P(z_arg) == IS_FALSE) { \ - (*intobj)->diff->member = TIMELIB_UNSET; \ + intobj->diff->member = TIMELIB_UNSET; \ } else if (z_arg && Z_TYPE_P(z_arg) <= IS_STRING) { \ zend_string *tmp_str; \ zend_string *str = zval_get_tmp_string(z_arg, &tmp_str); \ - DATE_A64I((*intobj)->diff->member, ZSTR_VAL(str)); \ + DATE_A64I(intobj->diff->member, ZSTR_VAL(str)); \ zend_tmp_string_release(tmp_str); \ } else { \ - (*intobj)->diff->member = -1LL; \ + intobj->diff->member = -1LL; \ } \ } while (0); @@ -4701,9 +4701,9 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte do { \ zval *z_arg = zend_hash_str_find(myht, element, sizeof(element) - 1); \ if (z_arg) { \ - (*intobj)->diff->member = (double)zval_get_double(z_arg); \ + intobj->diff->member = (double)zval_get_double(z_arg); \ } else { \ - (*intobj)->diff->member = (double)def; \ + intobj->diff->member = (double)def; \ } \ } while (0); @@ -4716,7 +4716,7 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte { const zval *z_arg = zend_hash_str_find(myht, "f", sizeof("f") - 1); if (z_arg) { - (*intobj)->diff->us = zend_dval_to_lval(zval_get_double(z_arg) * 1000000.0); + intobj->diff->us = zend_dval_to_lval(zval_get_double(z_arg) * 1000000.0); } } PHP_DATE_INTERVAL_READ_PROPERTY("weekday", weekday, int, -1) @@ -4730,14 +4730,14 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte PHP_DATE_INTERVAL_READ_PROPERTY("have_special_relative", have_special_relative, unsigned int, 0); { const zval *z_arg = zend_hash_str_find(myht, "civil_or_wall", sizeof("civil_or_wall") - 1); - (*intobj)->civil_or_wall = PHP_DATE_CIVIL; + intobj->civil_or_wall = PHP_DATE_CIVIL; if (z_arg) { zend_long val = zval_get_long(z_arg); - (*intobj)->civil_or_wall = val; + intobj->civil_or_wall = val; } } - (*intobj)->initialized = true; + intobj->initialized = true; } /* }}} */ /* {{{ */ @@ -4752,7 +4752,7 @@ PHP_METHOD(DateInterval, __set_state) php_date_instantiate(date_ce_interval, return_value); intobj = Z_PHPINTERVAL_P(return_value); - php_date_interval_initialize_from_hash(&return_value, &intobj, myht); + php_date_interval_initialize_from_hash(intobj, myht); } /* }}} */ @@ -4823,7 +4823,7 @@ PHP_METHOD(DateInterval, __unserialize) intervalobj = Z_PHPINTERVAL_P(object); - php_date_interval_initialize_from_hash(&object, &intervalobj, myht); + php_date_interval_initialize_from_hash(intervalobj, myht); restore_custom_dateinterval_properties(object, myht); } /* }}} */ @@ -4841,7 +4841,7 @@ PHP_METHOD(DateInterval, __wakeup) myht = Z_OBJPROP_P(object); - php_date_interval_initialize_from_hash(&return_value, &intobj, myht); + php_date_interval_initialize_from_hash(intobj, myht); } /* }}} */ diff --git a/ext/dom/node.c b/ext/dom/node.c index de80dba202e99..d89d49124fd9d 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -2081,6 +2081,97 @@ PHP_METHOD(DOMNode, lookupNamespaceURI) } /* }}} 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; @@ -2136,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(); } @@ -2158,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); @@ -2195,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; } } @@ -2264,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); + } } /* }}} */ 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/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/xml/XMLDocument_fromString_03.phpt b/ext/dom/tests/modern/xml/XMLDocument_fromString_03.phpt index 13359f4b28585..16db09547bff7 100644 --- a/ext/dom/tests/modern/xml/XMLDocument_fromString_03.phpt +++ b/ext/dom/tests/modern/xml/XMLDocument_fromString_03.phpt @@ -6,7 +6,7 @@ dom '); +$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_document.c b/ext/dom/xml_document.c index 4d941de0f0686..66fd1d707aa08 100644 --- a/ext/dom/xml_document.c +++ b/ext/dom/xml_document.c @@ -39,7 +39,6 @@ static bool check_options_validity(uint32_t arg_num, zend_long options) | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS - | XML_PARSE_XINCLUDE | XML_PARSE_NSCLEAN | XML_PARSE_NOCDATA | XML_PARSE_NONET @@ -60,7 +59,6 @@ static bool check_options_validity(uint32_t arg_num, zend_long options) "LIBXML_NOERROR, " "LIBXML_NOWARNING, " "LIBXML_NOBLANKS, " - "LIBXML_XINCLUDE, " "LIBXML_NSCLEAN, " "LIBXML_NOCDATA, " "LIBXML_NONET, " 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/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/fileinfo/fileinfo.c b/ext/fileinfo/fileinfo.c index baae757154950..50695981796e8 100644 --- a/ext/fileinfo/fileinfo.c +++ b/ext/fileinfo/fileinfo.c @@ -268,11 +268,12 @@ static const char* php_fileinfo_from_path(struct magic_set *magic, const zend_st if (php_stream_stat(stream, &ssb) == SUCCESS) { if (ssb.sb.st_mode & S_IFDIR) { ret_val = "directory"; - } else { - ret_val = magic_stream(magic, stream); - if (UNEXPECTED(ret_val == NULL)) { - php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); - } + } + } + if (!ret_val) { + ret_val = magic_stream(magic, stream); + if (UNEXPECTED(ret_val == NULL)) { + php_error_docref(NULL, E_WARNING, "Failed identify data %d:%s", magic_errno(magic), magic_error(magic)); } } diff --git a/ext/fileinfo/tests/magic b/ext/fileinfo/tests/magic index e8ad0f0ce7843..c8783aea05c71 100644 --- a/ext/fileinfo/tests/magic +++ b/ext/fileinfo/tests/magic @@ -39944,7 +39944,7 @@ # look for archive member RunTime.xml like in Microsoft.Windows.Cosa.Desktop.Client.ppkg >>>156 search/68233/s RunTime.xml \bWindows provisioning package) !:ext ppkg -# if is is not a Windows provisioning package, then it is a WIM +# if it is not a Windows provisioning package, then it is a WIM >>>156 default x \bWIM) image # second disk image part created by Microsoft's RecoveryDrive.exe has name Reconstruct.WIM2 !:ext wim/wim2 diff --git "a/ext/fileinfo/tests/magic\347\247\201\343\201\257\343\202\254\343\203\251\343\202\271\343\202\222\351\243\237\343\201\271\343\202\211\343\202\214\343\201\276\343\201\231" "b/ext/fileinfo/tests/magic\347\247\201\343\201\257\343\202\254\343\203\251\343\202\271\343\202\222\351\243\237\343\201\271\343\202\211\343\202\214\343\201\276\343\201\231" index e8ad0f0ce7843..c8783aea05c71 100644 --- "a/ext/fileinfo/tests/magic\347\247\201\343\201\257\343\202\254\343\203\251\343\202\271\343\202\222\351\243\237\343\201\271\343\202\211\343\202\214\343\201\276\343\201\231" +++ "b/ext/fileinfo/tests/magic\347\247\201\343\201\257\343\202\254\343\203\251\343\202\271\343\202\222\351\243\237\343\201\271\343\202\211\343\202\214\343\201\276\343\201\231" @@ -39944,7 +39944,7 @@ # look for archive member RunTime.xml like in Microsoft.Windows.Cosa.Desktop.Client.ppkg >>>156 search/68233/s RunTime.xml \bWindows provisioning package) !:ext ppkg -# if is is not a Windows provisioning package, then it is a WIM +# if it is not a Windows provisioning package, then it is a WIM >>>156 default x \bWIM) image # second disk image part created by Microsoft's RecoveryDrive.exe has name Reconstruct.WIM2 !:ext wim/wim2 diff --git a/ext/fileinfo/tests/remote_resource.phpt b/ext/fileinfo/tests/remote_resource.phpt new file mode 100644 index 0000000000000..b443393f826b4 --- /dev/null +++ b/ext/fileinfo/tests/remote_resource.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-20679 (finfo_file() doesn't work on remote resources) +--EXTENSIONS-- +fileinfo +--INI-- +allow_url_fopen=1 +--SKIPIF-- + +--FILE-- + $pid, 'uri' => $uri] = http_server([ + "data://text/plain,HTTP/1.0 200 Ok\r\n\r\nfoo", +], $output); + +$f = finfo_open(); +var_dump(finfo_file($f, $uri)); + +http_server_kill($pid); +?> +--EXPECT-- +string(51) "HTML document, ASCII text, with no line terminators" diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 60b2ad65bf65e..135cff7fcc639 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -4309,7 +4309,7 @@ PHP_FUNCTION(imageresolution) * * Stream Handling * Formerly contained within ext/gd/gd_ctx.c and included - * at the the top of this file + * at the top of this file * ********************************************************/ 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/tests/dateformat_format_code_datetime_objects.phpt b/ext/intl/tests/dateformat_format_code_datetime_objects.phpt new file mode 100644 index 0000000000000..eb0511c8a4a15 --- /dev/null +++ b/ext/intl/tests/dateformat_format_code_datetime_objects.phpt @@ -0,0 +1,134 @@ +--TEST-- +datefmt_format_code DateTime input +--EXTENSIONS-- +intl +--FILE-- +setTimezone(new DateTimeZone("America/Los_Angeles")); + + $dates = [$d1, $d2]; + $res_str = ''; + + foreach ($dates as $date_entry) { + foreach ($datetype_arr as $datetype_entry) { + $res_str .= "\n------------"; + $res_str .= "\nDate is: ".var_export($date_entry, true); + $res_str .= "\n------------"; + + $fmt = ut_datefmt_create($locale_entry, $datetype_entry, $datetype_entry, $timezone, IntlDateFormatter::GREGORIAN); + $formatted = ut_datefmt_format($fmt, $date_entry); + + // Replace narrow no-break space (U+202F) with regular space for consistent output. + // INTL doesn't seem to be very consistent about it either + $formatted = str_replace("\u{202F}", ' ', $formatted); + + if (intl_get_error_code() == U_ZERO_ERROR) { + $res_str .= "\nFormatted DateTime is : $formatted"; + } else { + $res_str .= "\nError while formatting as: '" . intl_get_error_message() . "'"; + } + } + } + + return $res_str; +} + +include_once 'ut_common.inc'; +ut_run(); +?> +--EXPECT-- +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2010-01-01 01:02:03.000000', + 'timezone_type' => 3, + 'timezone' => 'UTC', +)) +------------ +Formatted DateTime is : Thursday, December 31, 2009 at 3:02:03 PM GMT-10:00 +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2010-01-01 01:02:03.000000', + 'timezone_type' => 3, + 'timezone' => 'UTC', +)) +------------ +Formatted DateTime is : December 31, 2009 at 3:02:03 PM GMT-10 +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2010-01-01 01:02:03.000000', + 'timezone_type' => 3, + 'timezone' => 'UTC', +)) +------------ +Formatted DateTime is : Dec 31, 2009, 3:02:03 PM +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2010-01-01 01:02:03.000000', + 'timezone_type' => 3, + 'timezone' => 'UTC', +)) +------------ +Formatted DateTime is : 12/31/09, 3:02 PM +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2010-01-01 01:02:03.000000', + 'timezone_type' => 3, + 'timezone' => 'UTC', +)) +------------ +Formatted DateTime is : 20091231 03:02 PM +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2000-12-30 19:04:05.000000', + 'timezone_type' => 3, + 'timezone' => 'America/Los_Angeles', +)) +------------ +Formatted DateTime is : Saturday, December 30, 2000 at 5:04:05 PM GMT-10:00 +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2000-12-30 19:04:05.000000', + 'timezone_type' => 3, + 'timezone' => 'America/Los_Angeles', +)) +------------ +Formatted DateTime is : December 30, 2000 at 5:04:05 PM GMT-10 +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2000-12-30 19:04:05.000000', + 'timezone_type' => 3, + 'timezone' => 'America/Los_Angeles', +)) +------------ +Formatted DateTime is : Dec 30, 2000, 5:04:05 PM +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2000-12-30 19:04:05.000000', + 'timezone_type' => 3, + 'timezone' => 'America/Los_Angeles', +)) +------------ +Formatted DateTime is : 12/30/00, 5:04 PM +------------ +Date is: \DateTime::__set_state(array( + 'date' => '2000-12-30 19:04:05.000000', + 'timezone_type' => 3, + 'timezone' => 'America/Los_Angeles', +)) +------------ +Formatted DateTime is : 20001230 05:04 PM diff --git a/ext/intl/tests/dateformat_format_code_localtime_array.phpt b/ext/intl/tests/dateformat_format_code_localtime_array.phpt new file mode 100644 index 0000000000000..e2432a003bf91 --- /dev/null +++ b/ext/intl/tests/dateformat_format_code_localtime_array.phpt @@ -0,0 +1,130 @@ +--TEST-- +datefmt_format_code localtime array +--EXTENSIONS-- +intl +--FILE-- + 24, + 'tm_min' => 3, + 'tm_hour' => 19, + 'tm_mday' => 3, + 'tm_mon' => 3, + 'tm_year' => 105, + ], + [ + 'tm_sec' => 21, + 'tm_min' => 5, + 'tm_hour' => 7, + 'tm_mday' => 13, + 'tm_mon' => 4, + 'tm_year' => 205, + ], + [ + 'tm_sec' => 11, + 'tm_min' => 13, + 'tm_hour' => 0, + 'tm_mday' => 17, + 'tm_mon' => 11, + 'tm_year' => -5, + ], + ]; + + $res_str = ''; + + foreach ($localtime_arr as $localtime_entry) { + $res_str .= "\n------------\n"; + $res_str .= "\nInput localtime is : "; + $res_str .= implode(' , ', array_map( + function ($k, $v) { + return "$k : '$v'"; + }, + array_keys($localtime_entry), + $localtime_entry + )); + + $res_str .= "\n------------\n"; + + foreach ($datetype_arr as $datetype_entry) { + $res_str .= "\nIntlDateFormatter locale = $locale_entry, datetype = $datetype_entry, timetype = $datetype_entry"; + $fmt = ut_datefmt_create($locale_entry, $datetype_entry, $datetype_entry, $timezone, IntlDateFormatter::GREGORIAN); + $formatted = ut_datefmt_format($fmt, $localtime_entry); + + // Replace narrow no-break space (U+202F) with regular space for consistent output. + // INTL doesn't seem to be very consistent about it either + $formatted = str_replace("\u{202F}", ' ', $formatted); + + if (intl_get_error_code() == U_ZERO_ERROR) { + $res_str .= "\nFormatted localtime_array is : $formatted"; + } else { + $res_str .= "\nError while formatting as: '" . intl_get_error_message() . "'"; + } + } + } + + return $res_str; +} + +include_once 'ut_common.inc'; +ut_run(); +?> +--EXPECT-- +------------ + +Input localtime is : tm_sec : '24' , tm_min : '3' , tm_hour : '19' , tm_mday : '3' , tm_mon : '3' , tm_year : '105' +------------ + +IntlDateFormatter locale = en_US, datetype = 0, timetype = 0 +Formatted localtime_array is : Sunday, April 3, 2005 at 7:03:24 PM GMT-10:00 +IntlDateFormatter locale = en_US, datetype = 1, timetype = 1 +Formatted localtime_array is : April 3, 2005 at 7:03:24 PM GMT-10 +IntlDateFormatter locale = en_US, datetype = 2, timetype = 2 +Formatted localtime_array is : Apr 3, 2005, 7:03:24 PM +IntlDateFormatter locale = en_US, datetype = 3, timetype = 3 +Formatted localtime_array is : 4/3/05, 7:03 PM +IntlDateFormatter locale = en_US, datetype = -1, timetype = -1 +Formatted localtime_array is : 20050403 07:03 PM +------------ + +Input localtime is : tm_sec : '21' , tm_min : '5' , tm_hour : '7' , tm_mday : '13' , tm_mon : '4' , tm_year : '205' +------------ + +IntlDateFormatter locale = en_US, datetype = 0, timetype = 0 +Formatted localtime_array is : Wednesday, May 13, 2105 at 7:05:21 AM GMT-10:00 +IntlDateFormatter locale = en_US, datetype = 1, timetype = 1 +Formatted localtime_array is : May 13, 2105 at 7:05:21 AM GMT-10 +IntlDateFormatter locale = en_US, datetype = 2, timetype = 2 +Formatted localtime_array is : May 13, 2105, 7:05:21 AM +IntlDateFormatter locale = en_US, datetype = 3, timetype = 3 +Formatted localtime_array is : 5/13/05, 7:05 AM +IntlDateFormatter locale = en_US, datetype = -1, timetype = -1 +Formatted localtime_array is : 21050513 07:05 AM +------------ + +Input localtime is : tm_sec : '11' , tm_min : '13' , tm_hour : '0' , tm_mday : '17' , tm_mon : '11' , tm_year : '-5' +------------ + +IntlDateFormatter locale = en_US, datetype = 0, timetype = 0 +Formatted localtime_array is : Tuesday, December 17, 1895 at 12:13:11 AM GMT-10:00 +IntlDateFormatter locale = en_US, datetype = 1, timetype = 1 +Formatted localtime_array is : December 17, 1895 at 12:13:11 AM GMT-10 +IntlDateFormatter locale = en_US, datetype = 2, timetype = 2 +Formatted localtime_array is : Dec 17, 1895, 12:13:11 AM +IntlDateFormatter locale = en_US, datetype = 3, timetype = 3 +Formatted localtime_array is : 12/17/95, 12:13 AM +IntlDateFormatter locale = en_US, datetype = -1, timetype = -1 +Formatted localtime_array is : 18951217 12:13 AM diff --git a/ext/intl/tests/dateformat_format_code_timestamps.phpt b/ext/intl/tests/dateformat_format_code_timestamps.phpt new file mode 100644 index 0000000000000..ac07eb7c479f1 --- /dev/null +++ b/ext/intl/tests/dateformat_format_code_timestamps.phpt @@ -0,0 +1,175 @@ +--TEST-- +datefmt_format_code with timestamps +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +------------ + +Input timestamp is : 0 +------------ + +IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 +Formatted timestamp is : Wednesday, December 31, 1969 at 2:00:00 PM GMT-10:00 +IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 +Formatted timestamp is : December 31, 1969 at 2:00:00 PM GMT-10 +IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 +Formatted timestamp is : Dec 31, 1969, 2:00:00 PM +IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 +Formatted timestamp is : 12/31/69, 2:00 PM +IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 +Formatted timestamp is : 19691231 02:00 PM +------------ + +Input timestamp is : -1200000 +------------ + +IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 +Formatted timestamp is : Wednesday, December 17, 1969 at 4:40:00 PM GMT-10:00 +IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 +Formatted timestamp is : December 17, 1969 at 4:40:00 PM GMT-10 +IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 +Formatted timestamp is : Dec 17, 1969, 4:40:00 PM +IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 +Formatted timestamp is : 12/17/69, 4:40 PM +IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 +Formatted timestamp is : 19691217 04:40 PM +------------ + +Input timestamp is : 1200000 +------------ + +IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 +Formatted timestamp is : Wednesday, January 14, 1970 at 11:20:00 AM GMT-10:00 +IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 +Formatted timestamp is : January 14, 1970 at 11:20:00 AM GMT-10 +IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 +Formatted timestamp is : Jan 14, 1970, 11:20:00 AM +IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 +Formatted timestamp is : 1/14/70, 11:20 AM +IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 +Formatted timestamp is : 19700114 11:20 AM +------------ + +Input timestamp is : 2200000000 +------------ + +IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 +Formatted timestamp is : Sunday, September 18, 2039 at 1:06:40 PM GMT-10:00 +IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 +Formatted timestamp is : September 18, 2039 at 1:06:40 PM GMT-10 +IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 +Formatted timestamp is : Sep 18, 2039, 1:06:40 PM +IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 +Formatted timestamp is : 9/18/39, 1:06 PM +IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 +Formatted timestamp is : 20390918 01:06 PM +------------ + +Input timestamp is : -2200000000 +------------ + +IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 +Formatted timestamp is : Saturday, April 14, 1900 at 2:53:20 PM GMT-10:00 +IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 +Formatted timestamp is : April 14, 1900 at 2:53:20 PM GMT-10 +IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 +Formatted timestamp is : Apr 14, 1900, 2:53:20 PM +IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 +Formatted timestamp is : 4/14/00, 2:53 PM +IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 +Formatted timestamp is : 19000414 02:53 PM +------------ + +Input timestamp is : 90099999 +------------ + +IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 +Formatted timestamp is : Wednesday, November 8, 1972 at 9:46:39 AM GMT-10:00 +IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 +Formatted timestamp is : November 8, 1972 at 9:46:39 AM GMT-10 +IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 +Formatted timestamp is : Nov 8, 1972, 9:46:39 AM +IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 +Formatted timestamp is : 11/8/72, 9:46 AM +IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 +Formatted timestamp is : 19721108 09:46 AM +------------ + +Input timestamp is : 3600 +------------ + +IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 +Formatted timestamp is : Wednesday, December 31, 1969 at 3:00:00 PM GMT-10:00 +IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 +Formatted timestamp is : December 31, 1969 at 3:00:00 PM GMT-10 +IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 +Formatted timestamp is : Dec 31, 1969, 3:00:00 PM +IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 +Formatted timestamp is : 12/31/69, 3:00 PM +IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 +Formatted timestamp is : 19691231 03:00 PM +------------ + +Input timestamp is : -3600 +------------ + +IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 +Formatted timestamp is : Wednesday, December 31, 1969 at 1:00:00 PM GMT-10:00 +IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 +Formatted timestamp is : December 31, 1969 at 1:00:00 PM GMT-10 +IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 +Formatted timestamp is : Dec 31, 1969, 1:00:00 PM +IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 +Formatted timestamp is : 12/31/69, 1:00 PM +IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 +Formatted timestamp is : 19691231 01:00 PM diff --git a/ext/intl/tests/dateformat_format_variant3.phpt b/ext/intl/tests/dateformat_format_variant3.phpt deleted file mode 100644 index f889f5eef42b4..0000000000000 --- a/ext/intl/tests/dateformat_format_variant3.phpt +++ /dev/null @@ -1,388 +0,0 @@ ---TEST-- -datefmt_format_code() ---EXTENSIONS-- -intl ---XFAIL-- -This test assumes wrong data wrt PDT. It is also too big and needs splitting up. ---FILE-- - 24 , - 'tm_min' => 3, - 'tm_hour' => 19, - 'tm_mday' => 3, - 'tm_mon' => 3, - 'tm_year' => 105, - ); - $localtime_arr2 = array ( - 'tm_sec' => 21, - 'tm_min' => 5, - 'tm_hour' => 7, - 'tm_mday' => 13, - 'tm_mon' => 4, - 'tm_year' => 205, - ); - $localtime_arr3 = array ( - 'tm_sec' => 11, - 'tm_min' => 13, - 'tm_hour' => 0, - 'tm_mday' => 17, - 'tm_mon' => 11, - 'tm_year' => -5 - ); - - $localtime_arr = array ( - $localtime_arr1, - $localtime_arr2, - $localtime_arr3 - ); - - $d1 = new DateTime("2010-01-01 01:02:03", new DateTimeZone("UTC")); - $d2 = new DateTime("2000-12-31 03:04:05", new DateTimeZone("UTC")); - $d2->setTimezone(new DateTimeZone("PDT")); - - //Test format with input as a timestamp : integer - foreach( $time_arr as $timestamp_entry){ - $res_str .= "\n------------\n"; - $res_str .= "\nInput timestamp is : $timestamp_entry"; - $res_str .= "\n------------\n"; - foreach( $datetype_arr as $datetype_entry ) - { - $res_str .= "\nIntlDateFormatter locale= $locale_entry ,datetype = $datetype_entry ,timetype =$datetype_entry "; - $fmt = ut_datefmt_create( $locale_entry , $datetype_entry ,$datetype_entry, $timezone, IntlDateFormatter::GREGORIAN); - $formatted = ut_datefmt_format( $fmt , $timestamp_entry); - $res_str .= "\nFormatted timestamp is : $formatted"; - } - } - - //Test format with input as a localtime :array - foreach( $localtime_arr as $localtime_entry){ - $res_str .= "\n------------\n"; - $res_str .= "\nInput localtime is : "; - foreach( $localtime_entry as $key => $value){ - $res_str .= "$key : '$value' , "; - } - - $res_str .= "\n------------\n"; - foreach( $datetype_arr as $datetype_entry ) - { - $res_str .= "\nIntlDateFormatter locale= $locale_entry ,datetype = $datetype_entry ,timetype =$datetype_entry "; - $fmt = ut_datefmt_create( $locale_entry , $datetype_entry ,$datetype_entry, $timezone, IntlDateFormatter::GREGORIAN ); - $formatted1 = ut_datefmt_format( $fmt , $localtime_entry); - if( intl_get_error_code() == U_ZERO_ERROR){ - $res_str .= "\nFormatted localtime_array is : $formatted1"; - }else{ - $res_str .= "\nError while formatting as: '".intl_get_error_message()."'"; - } - } - } - - $dates = array( - $d1, - $d2, - ); - foreach($dates as $date_entry) { - foreach( $datetype_arr as $datetype_entry ) { - $res_str .= "\n------------"; - $res_str .= "\nDate is: ".var_export($date_entry, true); - $res_str .= "\n------------"; - - $fmt = ut_datefmt_create( $locale_entry , $datetype_entry ,$datetype_entry, $timezone, IntlDateFormatter::GREGORIAN ); - $formatted1 = ut_datefmt_format( $fmt , $date_entry); - if( intl_get_error_code() == U_ZERO_ERROR){ - $res_str .= "\nFormatted DateTime is : $formatted1"; - }else{ - $res_str .= "\nError while formatting as: '".intl_get_error_message()."'"; - } - } - } - - return $res_str; - -} - -include_once( 'ut_common.inc' ); - -// Run the test -ut_run(); -?> ---EXPECT-- ------------- - -Input timestamp is : 0 ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted timestamp is : Wednesday, December 31, 1969 at 2:00:00 PM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted timestamp is : December 31, 1969 at 2:00:00 PM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted timestamp is : Dec 31, 1969, 2:00:00 PM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted timestamp is : 12/31/69, 2:00 PM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted timestamp is : 19691231 02:00 PM ------------- - -Input timestamp is : -1200000 ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted timestamp is : Wednesday, December 17, 1969 at 4:40:00 PM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted timestamp is : December 17, 1969 at 4:40:00 PM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted timestamp is : Dec 17, 1969, 4:40:00 PM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted timestamp is : 12/17/69, 4:40 PM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted timestamp is : 19691217 04:40 PM ------------- - -Input timestamp is : 1200000 ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted timestamp is : Wednesday, January 14, 1970 at 11:20:00 AM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted timestamp is : January 14, 1970 at 11:20:00 AM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted timestamp is : Jan 14, 1970, 11:20:00 AM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted timestamp is : 1/14/70, 11:20 AM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted timestamp is : 19700114 11:20 AM ------------- - -Input timestamp is : 2200000000 ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted timestamp is : Sunday, September 18, 2039 at 1:06:40 PM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted timestamp is : September 18, 2039 at 1:06:40 PM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted timestamp is : Sep 18, 2039, 1:06:40 PM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted timestamp is : 9/18/39, 1:06 PM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted timestamp is : 20390918 01:06 PM ------------- - -Input timestamp is : -2200000000 ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted timestamp is : Saturday, April 14, 1900 at 2:53:20 PM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted timestamp is : April 14, 1900 at 2:53:20 PM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted timestamp is : Apr 14, 1900, 2:53:20 PM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted timestamp is : 4/14/00, 2:53 PM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted timestamp is : 19000414 02:53 PM ------------- - -Input timestamp is : 90099999 ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted timestamp is : Wednesday, November 8, 1972 at 9:46:39 AM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted timestamp is : November 8, 1972 at 9:46:39 AM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted timestamp is : Nov 8, 1972, 9:46:39 AM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted timestamp is : 11/8/72, 9:46 AM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted timestamp is : 19721108 09:46 AM ------------- - -Input timestamp is : 3600 ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted timestamp is : Wednesday, December 31, 1969 at 3:00:00 PM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted timestamp is : December 31, 1969 at 3:00:00 PM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted timestamp is : Dec 31, 1969, 3:00:00 PM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted timestamp is : 12/31/69, 3:00 PM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted timestamp is : 19691231 03:00 PM ------------- - -Input timestamp is : -3600 ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted timestamp is : Wednesday, December 31, 1969 at 1:00:00 PM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted timestamp is : December 31, 1969 at 1:00:00 PM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted timestamp is : Dec 31, 1969, 1:00:00 PM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted timestamp is : 12/31/69, 1:00 PM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted timestamp is : 19691231 01:00 PM ------------- - -Input localtime is : tm_sec : '24' , tm_min : '3' , tm_hour : '19' , tm_mday : '3' , tm_mon : '3' , tm_year : '105' , ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted localtime_array is : Sunday, April 3, 2005 at 7:03:24 PM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted localtime_array is : April 3, 2005 at 7:03:24 PM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted localtime_array is : Apr 3, 2005, 7:03:24 PM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted localtime_array is : 4/3/05, 7:03 PM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted localtime_array is : 20050403 07:03 PM ------------- - -Input localtime is : tm_sec : '21' , tm_min : '5' , tm_hour : '7' , tm_mday : '13' , tm_mon : '4' , tm_year : '205' , ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted localtime_array is : Wednesday, May 13, 2105 at 7:05:21 AM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted localtime_array is : May 13, 2105 at 7:05:21 AM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted localtime_array is : May 13, 2105, 7:05:21 AM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted localtime_array is : 5/13/05, 7:05 AM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted localtime_array is : 21050513 07:05 AM ------------- - -Input localtime is : tm_sec : '11' , tm_min : '13' , tm_hour : '0' , tm_mday : '17' , tm_mon : '11' , tm_year : '-5' , ------------- - -IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0 -Formatted localtime_array is : Tuesday, December 17, 1895 at 12:13:11 AM GMT-10:00 -IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1 -Formatted localtime_array is : December 17, 1895 at 12:13:11 AM GMT-10 -IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2 -Formatted localtime_array is : Dec 17, 1895, 12:13:11 AM -IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3 -Formatted localtime_array is : 12/17/95, 12:13 AM -IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1 -Formatted localtime_array is : 18951217 12:13 AM ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2010-01-01 01:02:03.000000', - 'timezone_type' => 3, - 'timezone' => 'UTC', -)) ------------- -Formatted DateTime is : Thursday, December 31, 2009 at 3:02:03 PM GMT-10:00 ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2010-01-01 01:02:03.000000', - 'timezone_type' => 3, - 'timezone' => 'UTC', -)) ------------- -Formatted DateTime is : December 31, 2009 at 3:02:03 PM GMT-10 ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2010-01-01 01:02:03.000000', - 'timezone_type' => 3, - 'timezone' => 'UTC', -)) ------------- -Formatted DateTime is : Dec 31, 2009, 3:02:03 PM ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2010-01-01 01:02:03.000000', - 'timezone_type' => 3, - 'timezone' => 'UTC', -)) ------------- -Formatted DateTime is : 12/31/09, 3:02 PM ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2010-01-01 01:02:03.000000', - 'timezone_type' => 3, - 'timezone' => 'UTC', -)) ------------- -Formatted DateTime is : 20091231 03:02 PM ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2000-12-30 19:04:05.000000', - 'timezone_type' => 2, - 'timezone' => 'PDT', -)) ------------- -Formatted DateTime is : Saturday, December 30, 2000 at 5:04:05 PM GMT-10:00 ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2000-12-30 19:04:05.000000', - 'timezone_type' => 2, - 'timezone' => 'PDT', -)) ------------- -Formatted DateTime is : December 30, 2000 at 5:04:05 PM GMT-10 ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2000-12-30 19:04:05.000000', - 'timezone_type' => 2, - 'timezone' => 'PDT', -)) ------------- -Formatted DateTime is : Dec 30, 2000, 5:04:05 PM ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2000-12-30 19:04:05.000000', - 'timezone_type' => 2, - 'timezone' => 'PDT', -)) ------------- -Formatted DateTime is : 12/30/00, 5:04 PM ------------- -Date is: \DateTime::__set_state(array( - 'date' => '2000-12-30 19:04:05.000000', - 'timezone_type' => 2, - 'timezone' => 'PDT', -)) ------------- -Formatted DateTime is : 20001230 05:04 PM 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/json/json.c b/ext/json/json.c index 9f91d39594ec7..079f67a5c4000 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -63,6 +63,8 @@ static PHP_GINIT_FUNCTION(json) #endif json_globals->encoder_depth = 0; json_globals->error_code = 0; + json_globals->error_line = 0; + json_globals->error_column = 0; json_globals->encode_max_depth = PHP_JSON_PARSER_DEFAULT_DEPTH; } /* }}} */ @@ -70,6 +72,8 @@ static PHP_GINIT_FUNCTION(json) static PHP_RINIT_FUNCTION(json) { JSON_G(error_code) = 0; + JSON_G(error_line) = 0; + JSON_G(error_column) = 0; return SUCCESS; } @@ -177,6 +181,18 @@ static const char *php_json_get_error_msg(php_json_error_code error_code) /* {{{ } /* }}} */ +static zend_string *php_json_get_error_msg_with_location(php_json_error_code error_code, size_t line, size_t column) /* {{{ */ +{ + const char *base_msg = php_json_get_error_msg(error_code); + + if (line > 0 && column > 0) { + return zend_strpprintf(0, "%s near location %zu:%zu", base_msg, line, column); + } + + return zend_string_init(base_msg, strlen(base_msg), 0); +} +/* }}} */ + PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */ { php_json_parser parser; @@ -185,10 +201,17 @@ PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); + size_t error_line = php_json_parser_error_line(&parser); + size_t error_column = php_json_parser_error_column(&parser); + if (!(options & PHP_JSON_THROW_ON_ERROR)) { JSON_G(error_code) = error_code; + JSON_G(error_line) = error_line; + JSON_G(error_column) = error_column; } else { - zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code); + zend_string *error_msg = php_json_get_error_msg_with_location(error_code, error_line, error_column); + zend_throw_exception(php_json_exception_ce, ZSTR_VAL(error_msg), error_code); + zend_string_release(error_msg); } RETVAL_NULL(); return FAILURE; @@ -208,7 +231,12 @@ PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_lon if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); + size_t error_line = php_json_parser_error_line(&parser); + size_t error_column = php_json_parser_error_column(&parser); + JSON_G(error_code) = error_code; + JSON_G(error_line) = error_line; + JSON_G(error_column) = error_column; return false; } @@ -274,11 +302,15 @@ PHP_FUNCTION(json_decode) if (!(options & PHP_JSON_THROW_ON_ERROR)) { JSON_G(error_code) = PHP_JSON_ERROR_NONE; + JSON_G(error_line) = 0; + JSON_G(error_column) = 0; } if (!str_len) { if (!(options & PHP_JSON_THROW_ON_ERROR)) { JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; + JSON_G(error_line) = 0; + JSON_G(error_column) = 0; } else { zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX); } @@ -331,10 +363,14 @@ PHP_FUNCTION(json_validate) if (!str_len) { JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; + JSON_G(error_line) = 0; + JSON_G(error_column) = 0; RETURN_FALSE; } JSON_G(error_code) = PHP_JSON_ERROR_NONE; + JSON_G(error_line) = 0; + JSON_G(error_column) = 0; if (depth <= 0) { zend_argument_value_error(2, "must be greater than 0"); @@ -364,6 +400,10 @@ PHP_FUNCTION(json_last_error_msg) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_STRING(php_json_get_error_msg(JSON_G(error_code))); + RETVAL_STR(php_json_get_error_msg_with_location( + JSON_G(error_code), + JSON_G(error_line), + JSON_G(error_column) + )); } /* }}} */ diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index d570cddc91e4b..2fd4edfe36937 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -41,6 +41,7 @@ int json_yydebug = 1; } +%locations %define api.prefix {php_json_yy} %define api.pure full %param { php_json_parser *parser } @@ -49,7 +50,6 @@ int json_yydebug = 1; zval value; } - %token PHP_JSON_T_NUL %token PHP_JSON_T_TRUE %token PHP_JSON_T_FALSE @@ -66,8 +66,8 @@ int json_yydebug = 1; %destructor { zval_ptr_dtor_nogc(&$$); } %code { -static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); -static void php_json_yyerror(php_json_parser *parser, char const *msg); +static int php_json_yylex(union YYSTYPE *value, YYLTYPE *location, php_json_parser *parser); +static void php_json_yyerror(YYLTYPE *location, php_json_parser *parser, char const *msg); static int php_json_parser_array_create(php_json_parser *parser, zval *array); static int php_json_parser_object_create(php_json_parser *parser, zval *array); @@ -277,7 +277,7 @@ static int php_json_parser_object_update_validate(php_json_parser *parser, zval return SUCCESS; } -static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) +static int php_json_yylex(union YYSTYPE *value, YYLTYPE *location, php_json_parser *parser) { int token = php_json_scan(&parser->scanner); @@ -293,10 +293,15 @@ static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) value->value = parser->scanner.value; } + location->first_column = PHP_JSON_SCANNER_LOCATION(parser->scanner, first_column); + location->first_line = PHP_JSON_SCANNER_LOCATION(parser->scanner, first_line); + location->last_column = PHP_JSON_SCANNER_LOCATION(parser->scanner, last_column); + location->last_line = PHP_JSON_SCANNER_LOCATION(parser->scanner, last_line); + return token; } -static void php_json_yyerror(php_json_parser *parser, char const *msg) +static void php_json_yyerror(YYLTYPE *location, php_json_parser *parser, char const *msg) { if (!parser->scanner.errcode) { parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; @@ -308,6 +313,16 @@ PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parse return parser->scanner.errcode; } +PHP_JSON_API size_t php_json_parser_error_line(const php_json_parser *parser) +{ + return parser->scanner.errloc.first_line; +} + +PHP_JSON_API size_t php_json_parser_error_column(const php_json_parser *parser) +{ + return parser->scanner.errloc.first_column; +} + static const php_json_parser_methods default_parser_methods = { php_json_parser_array_create, diff --git a/ext/json/json_scanner.re b/ext/json/json_scanner.re index 0debb3b03cb22..d6eaaf65b2e18 100644 --- a/ext/json/json_scanner.re +++ b/ext/json/json_scanner.re @@ -52,6 +52,8 @@ #define PHP_JSON_INT_MAX_LENGTH (MAX_LENGTH_OF_LONG - 1) +#define PHP_JSON_TOKEN_LENGTH() ((size_t) (s->cursor - s->token)) +#define PHP_JSON_TOKEN_LOCATION(location) (s)->errloc.location static void php_json_scanner_copy_string(php_json_scanner *s, size_t esc_size) { @@ -96,6 +98,10 @@ void php_json_scanner_init(php_json_scanner *s, const char *str, size_t str_len, s->cursor = (php_json_ctype *) str; s->limit = (php_json_ctype *) str + str_len; s->options = options; + PHP_JSON_TOKEN_LOCATION(first_column) = 1; + PHP_JSON_TOKEN_LOCATION(first_line) = 1; + PHP_JSON_TOKEN_LOCATION(last_column) = 1; + PHP_JSON_TOKEN_LOCATION(last_line) = 1; PHP_JSON_CONDITION_SET(JS); } @@ -104,6 +110,8 @@ int php_json_scan(php_json_scanner *s) ZVAL_NULL(&s->value); std: + PHP_JSON_TOKEN_LOCATION(first_column) = s->errloc.last_column; + PHP_JSON_TOKEN_LOCATION(first_line) = s->errloc.last_line; s->token = s->cursor; /*!re2c @@ -149,27 +157,50 @@ std: UTF16_3 = UTFPREF ( ( ( HEXC | [efEF] ) HEX ) | ( [dD] HEX7 ) ) HEX{2} ; UTF16_4 = UTFPREF [dD] [89abAB] HEX{2} UTFPREF [dD] [c-fC-F] HEX{2} ; - "{" { return '{'; } - "}" { return '}'; } - "[" { return '['; } - "]" { return ']'; } - ":" { return ':'; } - "," { return ','; } + "{" { + PHP_JSON_TOKEN_LOCATION(last_column)++; + return '{'; + } + "}" { + PHP_JSON_TOKEN_LOCATION(last_column)++; + return '}'; + } + "[" { + PHP_JSON_TOKEN_LOCATION(last_column)++; + return '['; + } + "]" { + PHP_JSON_TOKEN_LOCATION(last_column)++; + return ']'; + } + ":" { + PHP_JSON_TOKEN_LOCATION(last_column)++; + return ':'; + } + "," { + PHP_JSON_TOKEN_LOCATION(last_column)++; + return ','; + } "null" { + PHP_JSON_TOKEN_LOCATION(last_column) += 4; ZVAL_NULL(&s->value); return PHP_JSON_T_NUL; } "true" { + PHP_JSON_TOKEN_LOCATION(last_column) += 4; ZVAL_TRUE(&s->value); return PHP_JSON_T_TRUE; } "false" { + PHP_JSON_TOKEN_LOCATION(last_column) += 5; ZVAL_FALSE(&s->value); return PHP_JSON_T_FALSE; } INT { bool bigint = 0, negative = s->token[0] == '-'; - size_t digits = (size_t) (s->cursor - s->token - negative); + size_t digits = PHP_JSON_TOKEN_LENGTH(); + PHP_JSON_TOKEN_LOCATION(last_column) += digits; + digits -= negative; if (digits >= PHP_JSON_INT_MAX_LENGTH) { if (digits == PHP_JSON_INT_MAX_LENGTH) { int cmp = strncmp((char *) (s->token + negative), LONG_MIN_DIGITS, PHP_JSON_INT_MAX_LENGTH); @@ -192,10 +223,19 @@ std: } } FLOAT|EXP { + PHP_JSON_TOKEN_LOCATION(last_column) += PHP_JSON_TOKEN_LENGTH(); ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL)); return PHP_JSON_T_DOUBLE; } - NL|WS { goto std; } + NL { + PHP_JSON_TOKEN_LOCATION(last_line)++; + PHP_JSON_TOKEN_LOCATION(last_column) = 1; + goto std; + } + WS { + PHP_JSON_TOKEN_LOCATION(last_column) += PHP_JSON_TOKEN_LENGTH(); + goto std; + } EOI { if (s->limit < s->cursor) { return PHP_JSON_T_EOI; @@ -205,6 +245,7 @@ std: } } ["] { + PHP_JSON_TOKEN_LOCATION(last_column)++; s->str_start = s->cursor; s->str_esc = 0; s->utf8_invalid = 0; @@ -229,18 +270,22 @@ std: return PHP_JSON_T_ERROR; } UTF16_1 { + PHP_JSON_TOKEN_LOCATION(last_column) += 1; s->str_esc += 5; PHP_JSON_CONDITION_GOTO(STR_P1); } UTF16_2 { + PHP_JSON_TOKEN_LOCATION(last_column) += 1; s->str_esc += 4; PHP_JSON_CONDITION_GOTO(STR_P1); } UTF16_3 { + PHP_JSON_TOKEN_LOCATION(last_column) += 1; s->str_esc += 3; PHP_JSON_CONDITION_GOTO(STR_P1); } UTF16_4 { + PHP_JSON_TOKEN_LOCATION(last_column) += 1; s->str_esc += 8; PHP_JSON_CONDITION_GOTO(STR_P1); } @@ -249,6 +294,7 @@ std: return PHP_JSON_T_ERROR; } ESC { + PHP_JSON_TOKEN_LOCATION(last_column) += 2; s->str_esc++; PHP_JSON_CONDITION_GOTO(STR_P1); } @@ -257,6 +303,7 @@ std: return PHP_JSON_T_ERROR; } ["] { + PHP_JSON_TOKEN_LOCATION(last_column)++; zend_string *str; size_t len = (size_t)(s->cursor - s->str_start - s->str_esc - 1 + s->utf8_invalid_count); if (len == 0) { @@ -277,7 +324,22 @@ std: return PHP_JSON_T_STRING; } } - UTF8 { PHP_JSON_CONDITION_GOTO(STR_P1); } + UTF8_1 { + PHP_JSON_TOKEN_LOCATION(last_column)++; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + UTF8_2 { + PHP_JSON_TOKEN_LOCATION(last_column) += 1; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + UTF8_3 { + PHP_JSON_TOKEN_LOCATION(last_column) += 1; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + UTF8_4 { + PHP_JSON_TOKEN_LOCATION(last_column) += 1; + PHP_JSON_CONDITION_GOTO(STR_P1); + } ANY { if (s->options & (PHP_JSON_INVALID_UTF8_IGNORE | PHP_JSON_INVALID_UTF8_SUBSTITUTE)) { if (s->options & PHP_JSON_INVALID_UTF8_SUBSTITUTE) { @@ -295,7 +357,6 @@ std: s->errcode = PHP_JSON_ERROR_UTF8; return PHP_JSON_T_ERROR; } - UTF16_1 { int utf16 = php_json_ucs2_to_int(s, 2); PHP_JSON_SCANNER_COPY_UTF(); diff --git a/ext/json/php_json.h b/ext/json/php_json.h index b79c7c836f7a3..bbe8be9d60ada 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -86,6 +86,8 @@ ZEND_BEGIN_MODULE_GLOBALS(json) int encoder_depth; int encode_max_depth; php_json_error_code error_code; + size_t error_line; + size_t error_column; ZEND_END_MODULE_GLOBALS(json) PHP_JSON_API ZEND_EXTERN_MODULE_GLOBALS(json) diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index 8aedce9ac55d6..8fee3d11c6bf8 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -50,12 +50,20 @@ typedef struct _php_json_parser_methods { php_json_parser_func_object_end_t object_end; } php_json_parser_methods; + typedef struct _php_json_parser_location { + size_t first_line; + size_t first_column; + size_t last_line; + size_t last_column; +} php_json_parser_location; + struct _php_json_parser { php_json_scanner scanner; zval *return_value; int depth; int max_depth; php_json_parser_methods methods; + php_json_parser_location *location; }; PHP_JSON_API void php_json_parser_init_ex( @@ -77,6 +85,10 @@ PHP_JSON_API void php_json_parser_init( PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser); +PHP_JSON_API size_t php_json_parser_error_line(const php_json_parser *parser); + +PHP_JSON_API size_t php_json_parser_error_column(const php_json_parser *parser); + PHP_JSON_API int php_json_parse(php_json_parser *parser); int php_json_yyparse(php_json_parser *parser); diff --git a/ext/json/php_json_scanner.h b/ext/json/php_json_scanner.h index a49be68cd6328..a6de149391dc1 100644 --- a/ext/json/php_json_scanner.h +++ b/ext/json/php_json_scanner.h @@ -22,6 +22,17 @@ typedef unsigned char php_json_ctype; +typedef struct _php_json_error_location { + /** first column of the error */ + size_t first_column; + /** first line of the error */ + size_t first_line; + /** last column of the error */ + size_t last_column; + /** last line of the error */ + size_t last_line; +} php_json_error_location; + typedef struct _php_json_scanner { php_json_ctype *cursor; /* cursor position */ php_json_ctype *token; /* token position */ @@ -35,10 +46,12 @@ typedef struct _php_json_scanner { int state; /* condition state */ int options; /* options */ php_json_error_code errcode; /* error type if there is an error */ + php_json_error_location errloc; /* error location */ int utf8_invalid; /* whether utf8 is invalid */ int utf8_invalid_count; /* number of extra character for invalid utf8 */ } php_json_scanner; +#define PHP_JSON_SCANNER_LOCATION(scanner, slocation) (scanner).errloc.slocation void php_json_scanner_init(php_json_scanner *scanner, const char *str, size_t str_len, int options); int php_json_scan(php_json_scanner *s); diff --git a/ext/json/tests/007.phpt b/ext/json/tests/007.phpt index dea641317e97f..9a5ae654d6361 100644 --- a/ext/json/tests/007.phpt +++ b/ext/json/tests/007.phpt @@ -24,14 +24,14 @@ int(0) string(8) "No error" NULL int(1) -string(28) "Maximum stack depth exceeded" +string(46) "Maximum stack depth exceeded near location 1:2" NULL int(2) -string(42) "State mismatch (invalid or malformed JSON)" +string(60) "State mismatch (invalid or malformed JSON) near location 1:3" NULL int(3) -string(53) "Control character error, possibly incorrectly encoded" +string(71) "Control character error, possibly incorrectly encoded near location 1:2" NULL int(4) -string(12) "Syntax error" +string(30) "Syntax error near location 1:3" Done diff --git a/ext/json/tests/bug62010.phpt b/ext/json/tests/bug62010.phpt index 2591231dcdda1..862d7dc7e2c00 100644 --- a/ext/json/tests/bug62010.phpt +++ b/ext/json/tests/bug62010.phpt @@ -10,4 +10,4 @@ var_dump(json_last_error_msg()); --EXPECT-- NULL bool(true) -string(50) "Single unpaired UTF-16 surrogate in unicode escape" +string(68) "Single unpaired UTF-16 surrogate in unicode escape near location 1:1" diff --git a/ext/json/tests/bug68546.phpt b/ext/json/tests/bug68546.phpt index 8835a72c5eac7..1847eabf3a8e3 100644 --- a/ext/json/tests/bug68546.phpt +++ b/ext/json/tests/bug68546.phpt @@ -5,7 +5,7 @@ Bug #68546 (json_decode() Fatal error: Cannot access property started with '\0') var_dump(json_decode('{"key": {"\u0000": "aa"}}')); var_dump(json_last_error() === JSON_ERROR_INVALID_PROPERTY_NAME); -var_dump(json_decode('[{"key1": 0, "\u0000": 1}]')); +var_dump(json_decode('[{"key1": 0, "\u1234": 1, "\u0000": 1}]')); var_dump(json_last_error() === JSON_ERROR_INVALID_PROPERTY_NAME); var_dump(json_last_error_msg()); @@ -16,5 +16,5 @@ NULL bool(true) NULL bool(true) -string(36) "The decoded property name is invalid" +string(55) "The decoded property name is invalid near location 1:27" Done diff --git a/ext/json/tests/json_decode_exceptions.phpt b/ext/json/tests/json_decode_exceptions.phpt index 7dc2e7408a02c..d53941682e454 100644 --- a/ext/json/tests/json_decode_exceptions.phpt +++ b/ext/json/tests/json_decode_exceptions.phpt @@ -13,7 +13,7 @@ try { --EXPECTF-- object(JsonException)#1 (7) { ["message":protected]=> - string(12) "Syntax error" + string(30) "Syntax error near location 1:2" ["string":"Exception":private]=> string(0) "" ["code":protected]=> diff --git a/ext/json/tests/json_last_error_msg_error_location_001.phpt b/ext/json/tests/json_last_error_msg_error_location_001.phpt new file mode 100644 index 0000000000000..e0553f9f7d651 --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_001.phpt @@ -0,0 +1,121 @@ +--TEST-- +json_last_error_msg() - Error location reporting with ASCII characters +--FILE-- + +--EXPECT-- +Testing errors at various locations with ASCII characters + +Error at position 1:1: +bool(false) +int(4) +string(30) "Syntax error near location 1:1" + +Error at position 1:10: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error at position 1:9: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +Error at position 1:16: +bool(false) +int(4) +string(31) "Syntax error near location 1:16" + +Error at position 1:15: +bool(false) +int(4) +string(31) "Syntax error near location 1:15" + +Error at position 1:10: +bool(false) +int(4) +string(31) "Syntax error near location 1:10" + +Error at position 1:7: +bool(false) +int(4) +string(30) "Syntax error near location 1:7" + +Error at position 1:2: +bool(false) +int(4) +string(30) "Syntax error near location 1:2" + +Error at position 1:16: +bool(false) +int(4) +string(31) "Syntax error near location 1:16" + +Error at position 1:4: +bool(false) +int(4) +string(30) "Syntax error near location 1:4" + +Error at position 1:10: +bool(false) +int(4) +string(31) "Syntax error near location 1:10" + +Error at position 1:10: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + diff --git a/ext/json/tests/json_last_error_msg_error_location_002.phpt b/ext/json/tests/json_last_error_msg_error_location_002.phpt new file mode 100644 index 0000000000000..df7fc981ccbab --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_002.phpt @@ -0,0 +1,103 @@ +--TEST-- +json_last_error_msg() - Error location reporting with Unicode UTF-8 characters +--FILE-- + +--EXPECT-- +Testing error locations with Unicode UTF-8 characters + +Error after Japanese characters: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:12" + +Error after Russian characters: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:9" + +Error after Chinese characters: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:8" + +Error after Arabic characters: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:9" + +Error after Emoji: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:11" + +Error in mixed ASCII and UTF-8: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:27" + +Error with UTF-8 escaped sequences: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error in object with multiple UTF-8 keys: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:22" + +Error in array with UTF-8 strings: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:18" + +Error in nested object with UTF-8: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:15" + diff --git a/ext/json/tests/json_last_error_msg_error_location_003.phpt b/ext/json/tests/json_last_error_msg_error_location_003.phpt new file mode 100644 index 0000000000000..ec5e6b9b4d651 --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_003.phpt @@ -0,0 +1,72 @@ +--TEST-- +json_last_error_msg() - Error location reporting with multi-line JSON +--FILE-- + +--EXPECT-- +Testing error locations in multi-line JSON + +Error on line 2, column 13: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 2:13" + +Error on line 3, column 12: +bool(false) +int(4) +string(31) "Syntax error near location 3:12" + +Error on line 5, column 26: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 5:26" + +Error on line 7, column 1: +bool(false) +int(4) +string(30) "Syntax error near location 7:1" + diff --git a/ext/json/tests/json_last_error_msg_error_location_004.phpt b/ext/json/tests/json_last_error_msg_error_location_004.phpt new file mode 100644 index 0000000000000..165449600fb39 --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_004.phpt @@ -0,0 +1,93 @@ +--TEST-- +json_last_error_msg() - Error location reporting with deeply nested structures +--FILE-- + +--EXPECT-- +Testing error locations in deeply nested structures + +Error in deeply nested object: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:31" + +Error in deeply nested array: +bool(true) +int(0) +string(8) "No error" + +Error in mixed nested structures: +bool(true) +int(0) +string(8) "No error" + +Error at end of deep nesting: +bool(true) +int(0) +string(8) "No error" + +Error in middle of deep nesting: +bool(false) +int(4) +string(31) "Syntax error near location 1:21" + +Error in complex structure: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:93" + +Error in array of objects: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:68" + +Error in object with array values: +bool(false) +int(2) +string(61) "State mismatch (invalid or malformed JSON) near location 1:82" + diff --git a/ext/json/tests/json_last_error_msg_error_location_005.phpt b/ext/json/tests/json_last_error_msg_error_location_005.phpt new file mode 100644 index 0000000000000..d12ce387e73ea --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_005.phpt @@ -0,0 +1,103 @@ +--TEST-- +json_last_error_msg() - Error location reporting with UTF-16 surrogate pairs +--FILE-- + +--EXPECT-- +Testing error locations with UTF-16 surrogate pairs and escape sequences + +Error after UTF-16 escaped emoji: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:11" + +Error after multiple UTF-16 pairs: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error with mixed UTF-8 and UTF-16: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:11" + +Error with UTF-16 in key: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:9" + +Error with multiple UTF-16 keys: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:22" + +Error with BMP characters: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error with supplementary plane: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:11" + +Error in array with UTF-16: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:12" + +Error in nested structure with UTF-16: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:18" + +Error with UTF-16 and control chars: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + diff --git a/ext/json/tests/json_last_error_msg_error_location_006.phpt b/ext/json/tests/json_last_error_msg_error_location_006.phpt new file mode 100644 index 0000000000000..e6aab1af8f27e --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_006.phpt @@ -0,0 +1,152 @@ +--TEST-- +json_last_error_msg() - Error location reporting edge cases +--FILE-- + +--EXPECT-- +Testing error location edge cases + +Error at position 1:1: +bool(false) +int(4) +string(12) "Syntax error" + +Error at position 1:1 with invalid char: +bool(false) +int(4) +string(30) "Syntax error near location 1:1" + +Error after leading whitespace: +bool(false) +int(4) +string(30) "Syntax error near location 1:5" + +Error with tabs and spaces: +bool(false) +int(4) +string(30) "Syntax error near location 2:3" + +Error after multiple newlines: +bool(false) +int(4) +string(30) "Syntax error near location 4:2" + +Error at end of long string: +bool(false) +int(4) +string(33) "Syntax error near location 1:1011" + +Error with very long key: +bool(false) +int(3) +string(73) "Control character error, possibly incorrectly encoded near location 1:506" + +Error after empty object: +bool(false) +int(4) +string(30) "Syntax error near location 1:3" + +Error after empty array: +bool(false) +int(4) +string(30) "Syntax error near location 1:3" + +Error with multiple root values: +bool(false) +int(4) +string(30) "Syntax error near location 1:3" + +Error after valid number: +bool(false) +int(4) +string(30) "Syntax error near location 1:4" + +Error after valid boolean: +bool(false) +int(4) +string(30) "Syntax error near location 1:5" + +Error after valid null: +bool(false) +int(4) +string(30) "Syntax error near location 1:5" + +Error after valid string: +bool(false) +int(4) +string(30) "Syntax error near location 1:7" + +Error with mixed whitespace: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 3:2" + diff --git a/ext/json/tests/json_last_error_msg_error_location_007.phpt b/ext/json/tests/json_last_error_msg_error_location_007.phpt new file mode 100644 index 0000000000000..0e24889bbbbeb --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_007.phpt @@ -0,0 +1,178 @@ +--TEST-- +json_last_error_msg() - Error location with various error types +--FILE-- + +--EXPECT-- +Testing error locations with different error types + +State mismatch - expected value: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +State mismatch - expected key: +bool(false) +int(4) +string(30) "Syntax error near location 1:2" + +State mismatch - trailing comma in object: +bool(false) +int(4) +string(31) "Syntax error near location 1:17" + +State mismatch - trailing comma in array: +bool(false) +int(4) +string(31) "Syntax error near location 1:10" + +Invalid number format - leading zero: +bool(false) +int(4) +string(31) "Syntax error near location 1:10" + +Invalid number format - multiple decimals: +bool(false) +int(4) +string(31) "Syntax error near location 1:12" + +Invalid number format - incomplete exponent: +bool(false) +int(4) +string(31) "Syntax error near location 1:10" + +Invalid number format - double sign: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +Unclosed string: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:9" + +Invalid escape sequence: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +Incomplete unicode escape: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +Invalid unicode escape: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +Invalid true keyword: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +Invalid false keyword: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +Invalid null keyword: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + +Mismatched brackets - ] instead of }: +bool(false) +int(2) +string(61) "State mismatch (invalid or malformed JSON) near location 1:14" + +Mismatched brackets - } instead of ]: +bool(false) +int(2) +string(60) "State mismatch (invalid or malformed JSON) near location 1:7" + +Extra closing bracket: +bool(false) +int(4) +string(31) "Syntax error near location 1:15" + +Missing comma between elements: +bool(false) +int(4) +string(30) "Syntax error near location 1:4" + +Missing comma between object properties: +bool(false) +int(4) +string(30) "Syntax error near location 1:9" + diff --git a/ext/json/tests/json_last_error_msg_error_location_008.phpt b/ext/json/tests/json_last_error_msg_error_location_008.phpt new file mode 100644 index 0000000000000..4d8a1012316b4 --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_008.phpt @@ -0,0 +1,182 @@ +--TEST-- +json_last_error_msg() - Error location with mixed UTF-8 multi-byte characters +--FILE-- + +--EXPECT-- +Testing error locations with various UTF-8 multi-byte character widths + +Error with 2-byte UTF-8 (Latin Extended): +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error with 2-byte UTF-8 (Greek): +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:14" + +Error with 2-byte UTF-8 (Cyrillic): +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:12" + +Error with 3-byte UTF-8 (Chinese): +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:8" + +Error with 3-byte UTF-8 (Japanese Hiragana): +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error with 3-byte UTF-8 (Japanese Katakana): +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error with 3-byte UTF-8 (Korean): +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:8" + +Error with 4-byte UTF-8 (Emoji faces): +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:11" + +Error with 4-byte UTF-8 (Emoji objects): +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:13" + +Error with 4-byte UTF-8 (Mathematical symbols): +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error with mixed 1-2-3 byte UTF-8: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:9" + +Error with mixed 2-3-4 byte UTF-8: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:9" + +Error with all byte widths: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:9" + +Error with UTF-8 key at start: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:7" + +Error with multiple UTF-8 keys: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:35" + +Error in array with mixed UTF-8: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:25" + +Error in nested structure with various UTF-8: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:22" + +Error with combining diacritical marks: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error with Hebrew: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + +Error with Arabic with diacritics: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:11" + diff --git a/ext/json/tests/json_last_error_msg_error_location_009.phpt b/ext/json/tests/json_last_error_msg_error_location_009.phpt new file mode 100644 index 0000000000000..406179693ef69 --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_009.phpt @@ -0,0 +1,110 @@ +--TEST-- +json_last_error_msg() - Error location with depth errors and complex nesting +--FILE-- + +--EXPECT-- +Testing error locations with depth-related issues + +Max depth error at specific location: +bool(false) +int(1) +string(47) "Maximum stack depth exceeded near location 1:21" + +Max depth error in array: +bool(false) +int(1) +string(46) "Maximum stack depth exceeded near location 1:5" + +Max depth error with mixed structures: +bool(false) +int(1) +string(46) "Maximum stack depth exceeded near location 1:7" + +Syntax error at deep nesting level: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:31" + +Syntax error in deep array: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:6" + +Error after valid deep structure: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:48" + +Error in middle of nested structure: +bool(false) +int(4) +string(31) "Syntax error near location 1:29" + +Error in array with nested objects: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:30" + +Error in deep UTF-8 structure: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:16" + +Valid deep structure within limit: +bool(true) +int(0) +string(8) "No error" + diff --git a/ext/json/tests/json_last_error_msg_error_location_010.phpt b/ext/json/tests/json_last_error_msg_error_location_010.phpt new file mode 100644 index 0000000000000..1085702058387 --- /dev/null +++ b/ext/json/tests/json_last_error_msg_error_location_010.phpt @@ -0,0 +1,164 @@ +--TEST-- +json_last_error_msg() - Error location with whitespace variations +--FILE-- + +--EXPECT-- +Testing error locations with various whitespace patterns + +Error after multiple spaces: +bool(false) +int(4) +string(30) "Syntax error near location 1:7" + +Error after tabs: +bool(false) +int(4) +string(30) "Syntax error near location 1:5" + +Error after mixed whitespace: +bool(false) +int(4) +string(30) "Syntax error near location 1:7" + +Error on second line: +bool(false) +int(4) +string(30) "Syntax error near location 2:2" + +Error with CRLF line endings: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 2:8" + +Error after blank lines: +bool(false) +int(4) +string(30) "Syntax error near location 4:2" + +Error in string with spaces: +bool(false) +int(3) +string(71) "Control character error, possibly incorrectly encoded near location 1:9" + +Error with whitespace around colon: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:12" + +Error with whitespace around comma: +bool(true) +int(0) +string(8) "No error" + +Error in pretty printed JSON: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 4:11" + +Error in heavily indented JSON: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 5:26" + +Error with mixed tabs and spaces: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 3:12" + +Error after whitespace-only line: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 3:12" + +Error in compact JSON: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:22" + +Error with regular spaces: +bool(false) +int(3) +string(72) "Control character error, possibly incorrectly encoded near location 1:10" + diff --git a/ext/json/tests/json_validate_002.phpt b/ext/json/tests/json_validate_002.phpt index 53f4e4f2c2ea1..423564c4ad7c4 100644 --- a/ext/json/tests/json_validate_002.phpt +++ b/ext/json/tests/json_validate_002.phpt @@ -23,13 +23,13 @@ int(4) string(12) "Syntax error" bool(false) int(4) -string(12) "Syntax error" +string(30) "Syntax error near location 1:1" bool(false) int(4) string(12) "Syntax error" bool(false) int(1) -string(28) "Maximum stack depth exceeded" +string(46) "Maximum stack depth exceeded near location 1:1" bool(true) int(0) string(8) "No error" @@ -44,7 +44,7 @@ int(0) string(8) "No error" bool(false) int(4) -string(12) "Syntax error" +string(30) "Syntax error near location 1:1" bool(true) int(0) string(8) "No error" diff --git a/ext/json/tests/json_validate_004.phpt b/ext/json/tests/json_validate_004.phpt index d8a798d943278..bd807defa1404 100644 --- a/ext/json/tests/json_validate_004.phpt +++ b/ext/json/tests/json_validate_004.phpt @@ -23,16 +23,16 @@ json_validate_trycatchdump("[\"\xc1\xc1\",\"a\"]", 512, JSON_INVALID_UTF8_IGNORE Testing Invalid UTF-8 bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(74) "Malformed UTF-8 characters, possibly incorrectly encoded near location 1:1" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(74) "Malformed UTF-8 characters, possibly incorrectly encoded near location 1:1" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(74) "Malformed UTF-8 characters, possibly incorrectly encoded near location 1:1" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(74) "Malformed UTF-8 characters, possibly incorrectly encoded near location 1:2" bool(true) int(0) string(8) "No error" diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cjk.c b/ext/mbstring/libmbfl/filters/mbfilter_cjk.c index 716fec0c054d9..6a9c3803c4703 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cjk.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cjk.c @@ -4720,116 +4720,6 @@ const mbfl_encoding mbfl_encoding_2022kr = { * SJIS variants */ -static int mbfl_filt_conv_sjis_wchar(int c, mbfl_convert_filter *filter) -{ - int s1, s2, w; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* ASCII */ - CK((*filter->output_function)(c, filter->data)); - } else if (c > 0xA0 && c < 0xE0) { /* Kana */ - CK((*filter->output_function)(0xFEC0 + c, filter->data)); - } else if (c > 0x80 && c < 0xF0 && c != 0xA0) { /* Kanji, first byte */ - filter->status = 1; - filter->cache = c; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* Kanji, second byte */ - filter->status = 0; - int c1 = filter->cache; - if (c >= 0x40 && c <= 0xFC && c != 0x7F) { - SJIS_DECODE(c1, c, s1, s2); - w = (s1 - 0x21)*94 + s2 - 0x21; - if (w >= 0 && w < jisx0208_ucs_table_size) { - w = jisx0208_ucs_table[w]; - if (!w) - w = MBFL_BAD_INPUT; - } else { - w = MBFL_BAD_INPUT; - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - } - - return 0; -} - -static int mbfl_filt_conv_sjis_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status && filter->status != 4) { - (*filter->output_function)(MBFL_BAD_INPUT, filter->data); - } - filter->status = 0; - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_sjis(int c, mbfl_convert_filter *filter) -{ - int c1, c2, s1 = 0, s2; - - if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) { - s1 = ucs_a1_jis_table[c - ucs_a1_jis_table_min]; - } else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) { - s1 = ucs_a2_jis_table[c - ucs_a2_jis_table_min]; - } else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) { - s1 = ucs_i_jis_table[c - ucs_i_jis_table_min]; - } else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) { - s1 = ucs_r_jis_table[c - ucs_r_jis_table_min]; - } - if (s1 <= 0) { - if (c == 0xA5) { /* YEN SIGN */ - s1 = 0x216F; /* FULLWIDTH YEN SIGN */ - } else if (c == 0xAF || c == 0x203E) { /* U+00AF is MACRON, U+203E is OVERLINE */ - s1 = 0x2131; /* FULLWIDTH MACRON */ - } else if (c == 0xFF3C) { /* FULLWIDTH REVERSE SOLIDUS */ - s1 = 0x2140; - } else if (c == 0x2225) { /* PARALLEL TO */ - s1 = 0x2142; - } else if (c == 0xFF0D) { /* FULLWIDTH HYPHEN-MINUS */ - s1 = 0x215D; - } else if (c == 0xFFE0) { /* FULLWIDTH CENT SIGN */ - s1 = 0x2171; - } else if (c == 0xFFE1) { /* FULLWIDTH POUND SIGN */ - s1 = 0x2172; - } else if (c == 0xFFE2) { /* FULLWIDTH NOT SIGN */ - s1 = 0x224C; - } else if (c == 0) { - s1 = 0; - } else { - s1 = -1; - } - } else if (s1 >= 0x8080) { /* JIS X 0212; not supported */ - s1 = -1; - } - - if (s1 >= 0) { - if (s1 < 0x100) { /* Latin/Kana */ - CK((*filter->output_function)(s1, filter->data)); - } else { /* Kanji */ - c1 = (s1 >> 8) & 0xFF; - c2 = s1 & 0xFF; - SJIS_ENCODE(c1, c2, s1, s2); - CK((*filter->output_function)(s1, filter->data)); - CK((*filter->output_function)(s2, filter->data)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - static const unsigned short sjis_decode_tbl1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFFFF, 0, 188, 376, 564, 752, 940, 1128, 1316, 1504, 1692, 1880, 2068, 2256, 2444, 2632, 2820, 3008, 3196, 3384, 3572, 3760, 3948, 4136, 4324, 4512, 4700, 4888, 5076, 5264, 5452, 5640, 0xFFFF, -6016, -5828, -5640, -5452, -5264, -5076, -4888, -4700, -4512, -4324, -4136, -3948, -3760, -3572, -3384, -3196, -3008, -2820, -2632, -2444, -2256, -2068, -1880, -1692, -1504, -1316, -1128, -940, -752, -564, -376, -188, 0, 188, 376, 564, 752, 940, 1128, 1316, 1504, 1692, 1880, 2068, 2256, 2444, 2632, 2820, 3008, 3196, 3384, 3572, 3760, 3948, 4136, 4324, 4512, 4700, 4888, 5076, 5264, 5452, 5640, 5828, 6016, 6204, 6392, 6580, 6768, 6956, 7144, 7332, 7520, 7708, 7896, 8084, 8272, 8460, 8648, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; @@ -4955,1452 +4845,449 @@ static void mb_wchar_to_sjis(uint32_t *in, size_t len, mb_convert_buf *buf, bool MB_CONVERT_BUF_STORE(buf, out, limit); } -static int mbfl_filt_conv_sjis_mac_wchar(int c, mbfl_convert_filter *filter) +static size_t mb_sjismac_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { - int i, j, n; - int c1, s, s1, s2, w; + /* A single SJIS-Mac kuten code can convert to up to 5 Unicode codepoints, oh my! */ + ZEND_ASSERT(bufsize >= 5); - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80 && c != 0x5c) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (c > 0xa0 && c < 0xe0) { /* kana */ - CK((*filter->output_function)(0xfec0 + c, filter->data)); - } else if (c > 0x80 && c <= 0xed && c != 0xa0) { /* kanji first char */ - filter->status = 1; - filter->cache = c; - } else if (c == 0x5c) { - CK((*filter->output_function)(0x00a5, filter->data)); - } else if (c == 0x80) { - CK((*filter->output_function)(0x005c, filter->data)); - } else if (c == 0xa0) { - CK((*filter->output_function)(0x00a0, filter->data)); - } else if (c == 0xfd) { - CK((*filter->output_function)(0x00a9, filter->data)); - } else if (c == 0xfe) { - CK((*filter->output_function)(0x2122, filter->data)); - } else if (c == 0xff) { - CK((*filter->output_function)(0x2026, filter->data)); - CK((*filter->output_function)(0xf87f, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; - case 1: /* kanji second char */ - filter->status = 0; - c1 = filter->cache; - if (c >= 0x40 && c <= 0xfc && c != 0x7f) { - w = 0; - SJIS_DECODE(c1, c, s1, s2); - s = (s1 - 0x21)*94 + s2 - 0x21; - if (s <= 0x89) { - if (s == 0x1c) { - w = 0x2014; /* EM DASH */ - } else if (s == 0x1f) { - w = 0xff3c; /* FULLWIDTH REVERSE SOLIDUS */ - } else if (s == 0x20) { - w = 0x301c; /* FULLWIDTH TILDE */ - } else if (s == 0x21) { - w = 0x2016; /* PARALLEL TO */ - } else if (s == 0x3c) { - w = 0x2212; /* FULLWIDTH HYPHEN-MINUS */ - } else if (s == 0x50) { - w = 0x00a2; /* FULLWIDTH CENT SIGN */ - } else if (s == 0x51) { - w = 0x00a3; /* FULLWIDTH POUND SIGN */ - } else if (s == 0x89) { - w = 0x00ac; /* FULLWIDTH NOT SIGN */ - } - } - - /* apple gaiji area 0x8540 - 0x886d */ - if (w == 0) { - for (i=0; i<7; i++) { - if (s >= code_tbl[i][0] && s <= code_tbl[i][1]) { - w = s - code_tbl[i][0] + code_tbl[i][2]; - break; - } - } - } + while (p < e && out < limit) { + unsigned char c = *p++; - if (w == 0) { + if (c <= 0x80 || c == 0xA0) { + if (c == 0x5C) { + *out++ = 0xA5; + } else if (c == 0x80) { + *out++ = 0x5C; + } else { + *out++ = c; + } + } else if (c >= 0xA1 && c <= 0xDF) { + *out++ = 0xFEC0 + c; + } else if (c <= 0xED) { + if (p == e) { + *out++ = MBFL_BAD_INPUT; + break; + } + unsigned char c2 = *p++; + uint32_t w = sjis_decode_tbl1[c] + sjis_decode_tbl2[c2]; - for (i=0; ioutput_function)(code_tbl_m[i][j], filter->data)); + if (w <= 0x89) { + if (w == 0x1C) { + *out++ = 0x2014; /* EM DASH */ + continue; + } else if (w == 0x1F) { + *out++ = 0xFF3C; /* FULLWIDTH REVERSE SOLIDUS */ + continue; + } else if (w == 0x20) { + *out++ = 0x301C; /* FULLWIDTH TILDE */ + continue; + } else if (w == 0x21) { + *out++ = 0x2016; /* PARALLEL TO */ + continue; + } else if (w == 0x3C) { + *out++ = 0x2212; /* FULLWIDTH HYPHEN-MINUS */ + continue; + } else if (w == 0x50) { + *out++ = 0xA2; /* FULLWIDTH CENT SIGN */ + continue; + } else if (w == 0x51) { + *out++ = 0xA3; /* FULLWIDTH POUND SIGN */ + continue; + } else if (w == 0x89) { + *out++ = 0xAC; /* FULLWIDTH NOT SIGN */ + continue; + } + } else { + if (w >= 0x2F0 && w <= 0x3A3) { + for (int i = 0; i < 7; i++) { + if (w >= code_tbl[i][0] && w <= code_tbl[i][1]) { + *out++ = w - code_tbl[i][0] + code_tbl[i][2]; + goto next_iteration; } - w = code_tbl_m[i][n-1]; - break; } } - } - if (w == 0) { - for (i=0; i<8; i++) { - if (s >= code_ofst_tbl[i][0] && s <= code_ofst_tbl[i][1]) { - w = code_map[i][s - code_ofst_tbl[i][0]]; - if (w == 0) { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - return 0; - } - s2 = 0; - if (s >= 0x043e && s <= 0x0441) { - s2 = 0xf87a; - } else if (s == 0x03b1 || s == 0x03b7) { - s2 = 0xf87f; - } else if (s == 0x04b8 || s == 0x04b9 || s == 0x04c4) { - s2 = 0x20dd; - } else if (s == 0x1ed9 || s == 0x1eda || s == 0x1ee8 || s == 0x1ef3 || - (s >= 0x1ef5 && s <= 0x1efb) || s == 0x1f05 || s == 0x1f06 || - s == 0x1f18 || (s >= 0x1ff2 && s <= 0x20a5)) { - s2 = 0xf87e; + if (w >= 0x340 && w <= 0x523) { + for (int i = 0; i < code_tbl_m_len; i++) { + if (w == code_tbl_m[i][0]) { + int n = 5; + if (code_tbl_m[i][1] == 0xF860) { + n = 3; + } else if (code_tbl_m[i][1] == 0xF861) { + n = 4; + } + if ((limit - out) < n) { + p -= 2; + goto finished; + } + for (int j = 1; j <= n; j++) { + *out++ = code_tbl_m[i][j]; + } + goto next_iteration; } - if (s2 > 0) { - CK((*filter->output_function)(w, filter->data)); - w = s2; + } + } + + if (w >= 0x3AC && w <= 0x20A5) { + for (int i = 0; i < 8; i++) { + if (w >= code_ofst_tbl[i][0] && w <= code_ofst_tbl[i][1]) { + uint32_t w2 = code_map[i][w - code_ofst_tbl[i][0]]; + if (!w2) { + *out++ = MBFL_BAD_INPUT; + goto next_iteration; + } + if ((limit - out) < 2) { + p -= 2; + goto finished; + } + *out++ = w2; + if (w >= 0x43E && w <= 0x441) { + *out++ = 0xF87A; + } else if (w == 0x3B1 || w == 0x3B7) { + *out++ = 0xF87F; + } else if (w == 0x4B8 || w == 0x4B9 || w == 0x4C4) { + *out++ = 0x20DD; + } else if (w == 0x1ED9 || w == 0x1EDA || w == 0x1EE8 || w == 0x1EF3 || (w >= 0x1EF5 && w <= 0x1EFB) || w == 0x1F05 || w == 0x1F06 || w == 0x1F18 || (w >= 0x1FF2 && w <= 0x20A5)) { + *out++ = 0xF87E; + } + goto next_iteration; } - break; } } } - if (w == 0 && s >= 0 && s < jisx0208_ucs_table_size) { /* X 0208 */ - w = jisx0208_ucs_table[s]; + if (w < jisx0208_ucs_table_size) { + w = jisx0208_ucs_table[w]; + if (!w) + w = MBFL_BAD_INPUT; + *out++ = w; + } else { + *out++ = MBFL_BAD_INPUT; } - - if (w <= 0) { - w = MBFL_BAD_INPUT; + } else if (c == 0xFD) { + *out++ = 0xA9; + } else if (c == 0xFE) { + *out++ = 0x2122; + } else if (c == 0xFF) { + if ((limit - out) < 2) { + p--; + break; } - CK((*filter->output_function)(w, filter->data)); + *out++ = 0x2026; + *out++ = 0xF87F; } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); + *out++ = MBFL_BAD_INPUT; } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); +next_iteration: ; } - return 0; +finished: + *in_len = e - p; + *in = p; + return out - buf; } -static int mbfl_filt_conv_wchar_sjis_mac(int c, mbfl_convert_filter *filter) +static bool process_s_form(uint32_t w, uint32_t w2, unsigned int *s) { - int i, c1, c2, s1 = 0, s2 = 0, mode; - - // a1: U+0000 -> U+046F - // a2: U+2000 -> U+30FF - // i: U+4E00 -> U+9FFF - // r: U+FF00 -> U+FFFF - - switch (filter->status) { - case 1: - c1 = filter->cache; - filter->cache = filter->status = 0; - - if (c == 0xf87a) { - for (i = 0; i < 4; i++) { - if (c1 == s_form_tbl[i+34+3+3]) { - s1 = s_form_sjis_tbl[i+34+3+3]; - break; - } - } - if (s1 <= 0) { - s2 = c1; - } - } else if (c == 0x20dd) { - for (i = 0; i < 3; i++) { - if (c1 == s_form_tbl[i+34+3]) { - s1 = s_form_sjis_tbl[i+34+3]; - break; - } - } - if (s1 <= 0) { - s2 = c1; - } - } else if (c == 0xf87f) { - for (i = 0; i < 3; i++) { - if (c1 == s_form_tbl[i+34]) { - s1 = s_form_sjis_tbl[i+34]; - break; - } - } - if (s1 <= 0) { - s2 = c1; - s1 = -1; - } - } else if (c == 0xf87e) { - for (i = 0; i < 34; i++) { - if (c1 == s_form_tbl[i]) { - s1 = s_form_sjis_tbl[i]; - break; - } - } - if (s1 <= 0) { - s2 = c1; - s1 = -1; - } - } else { - s2 = c1; - s1 = c; - } - - if (s2 > 0) { - for (i = 0; i < s_form_tbl_len; i++) { - if (c1 == s_form_tbl[i]) { - s1 = s_form_sjis_fallback_tbl[i]; - break; - } + if (w2 == 0xF87A) { + for (int i = 0; i < 4; i++) { + if (w == s_form_tbl[i+34+3+3]) { + *s = s_form_sjis_tbl[i+34+3+3]; + return true; } } - - if (s1 >= 0) { - if (s1 < 0x100) { - CK((*filter->output_function)(s1, filter->data)); - } else { - CK((*filter->output_function)((s1 >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(s1 & 0xff, filter->data)); + } else if (w2 == 0x20DD) { + for (int i = 0; i < 3; i++) { + if (w == s_form_tbl[i+34+3]) { + *s = s_form_sjis_tbl[i+34+3]; + return true; } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - if (s2 <= 0 || s1 == -1) { - break; } - s1 = s2 = 0; - ZEND_FALLTHROUGH; - - case 0: - if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) { - s1 = ucs_a1_jis_table[c - ucs_a1_jis_table_min]; - if (c == 0x5c) { - s1 = 0x80; - } else if (c == 0xa9) { - s1 = 0xfd; - } - } else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) { - s1 = ucs_a2_jis_table[c - ucs_a2_jis_table_min]; - if (c == 0x2122) { - s1 = 0xfe; - } else if (c == 0x2014) { - s1 = 0x213d; - } else if (c == 0x2116) { - s1 = 0x2c1d; - } - } else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) { - s1 = ucs_i_jis_table[c - ucs_i_jis_table_min]; - } else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) { - s1 = ucs_r_jis_table[c - ucs_r_jis_table_min]; - } - - if (c >= 0x2000) { - for (i = 0; i < s_form_tbl_len; i++) { - if (c == s_form_tbl[i]) { - filter->status = 1; - filter->cache = c; - return 0; - } - } - - if (c == 0xf860 || c == 0xf861 || c == 0xf862) { - /* Apple 'transcoding hint' codepoints (from private use area) */ - filter->status = 2; - filter->cache = c; - return 0; + } else if (w2 == 0xF87F) { + for (int i = 0; i < 3; i++) { + if (w == s_form_tbl[i+34]) { + *s = s_form_sjis_tbl[i+34]; + return true; } } - - if (s1 <= 0) { - if (c == 0xa0) { - s1 = 0x00a0; - } else if (c == 0xa5) { /* YEN SIGN */ - /* Unicode has codepoint 0xFFE5 for a fullwidth Yen sign; - * convert codepoint 0xA5 to halfwidth Yen sign */ - s1 = 0x5c; /* HALFWIDTH YEN SIGN */ - } else if (c == 0xff3c) { /* FULLWIDTH REVERSE SOLIDUS */ - s1 = 0x2140; + } else if (w2 == 0xF87E) { + for (int i = 0; i < 34; i++) { + if (w == s_form_tbl[i]) { + *s = s_form_sjis_tbl[i]; + return true; } } + } - if (s1 <= 0) { - for (i=0; i= wchar2sjis_mac_r_tbl[i][0] && c <= wchar2sjis_mac_r_tbl[i][1]) { - s1 = c - wchar2sjis_mac_r_tbl[i][0] + wchar2sjis_mac_r_tbl[i][2]; - break; - } - } - - if (s1 <= 0) { - for (i=0; i= wchar2sjis_mac_r_map[i][0] && c <= wchar2sjis_mac_r_map[i][1]) { - s1 = wchar2sjis_mac_code_map[i][c-wchar2sjis_mac_r_map[i][0]]; - break; - } - } - } - - if (s1 <= 0) { - for (i=0; i 0) { - c1 = s1/94+0x21; - c2 = s1-94*(c1-0x21)+0x21; - s1 = (c1 << 8) | c2; - s2 = 1; - } - } +/* For codepoints F860-F862, which are treated specially in MacJapanese */ +static int transcoding_hint_cp_width[3] = { 3, 4, 5 }; - if ((s1 <= 0) || (s1 >= 0x8080 && s2 == 0)) { /* not found or X 0212 */ - s1 = -1; - c1 = 0; +static void mb_wchar_to_sjismac(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); - if (c == 0) { - s1 = 0; - } else if (s1 <= 0) { - s1 = -1; - } - } + uint32_t w; - if (s1 >= 0) { - if (s1 < 0x100) { /* latin or kana */ - CK((*filter->output_function)(s1, filter->data)); - } else { /* kanji */ - c1 = (s1 >> 8) & 0xff; - c2 = s1 & 0xff; - SJIS_ENCODE(c1, c2, s1, s2); - CK((*filter->output_function)(s1, filter->data)); - CK((*filter->output_function)(s2, filter->data)); - } + if (buf->state) { + w = buf->state & 0xFFFF; + if (buf->state & 0xFF000000L) { + goto resume_transcoding_hint; } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - break; - - case 2: - c1 = filter->cache; - filter->cache = 0; - filter->status = 0; - if (c1 == 0xf860) { - for (i = 0; i < 5; i++) { - if (c == code_tbl_m[i][2]) { - filter->cache = c | 0x10000; - filter->status = 3; - break; - } - } - } else if (c1 == 0xf861) { - for (i = 0; i < 3; i++) { - if (c == code_tbl_m[i+5][2]) { - filter->cache = c | 0x20000; - filter->status = 3; - break; - } - } - } else if (c1 == 0xf862) { - for (i = 0; i < 4; i++) { - if (c == code_tbl_m[i+5+3][2]) { - filter->cache = c | 0x40000; - filter->status = 3; - break; - } - } - } - - if (filter->status == 0) { - /* Didn't find any of expected codepoints after Apple transcoding hint */ - CK(mbfl_filt_conv_illegal_output(c1, filter)); - return mbfl_filt_conv_wchar_sjis_mac(c, filter); + buf->state = 0; + goto process_codepoint; } - break; - - case 3: - s1 = 0; - c1 = filter->cache & 0xffff; - mode = (filter->cache & 0xf0000) >> 16; - - filter->cache = filter->status = 0; + } - if (mode == 0x1) { - for (i = 0; i < 5; i++) { - if (c1 == code_tbl_m[i][2] && c == code_tbl_m[i][3]) { - s1 = code_tbl_m[i][0]; - break; - } - } + while (len--) { + w = *in++; +process_codepoint: ; + unsigned int s = 0; - if (s1 > 0) { - c1 = s1/94+0x21; - c2 = s1-94*(c1-0x21)+0x21; - SJIS_ENCODE(c1, c2, s1, s2); - CK((*filter->output_function)(s1, filter->data)); - CK((*filter->output_function)(s2, filter->data)); + if (w >= ucs_a1_jis_table_min && w < ucs_a1_jis_table_max) { + if (w == 0x5C) { + s = 0x80; + } else if (w == 0xA9) { + s = 0xFD; } else { - CK(mbfl_filt_conv_illegal_output(0xf860, filter)); - CK(mbfl_filt_conv_illegal_output(c1, filter)); - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - } else if (mode == 0x2) { - for (i = 0; i < 3; i++) { - if (c1 == code_tbl_m[i+5][2] && c == code_tbl_m[i+5][3]) { - filter->cache = c | 0x20000; - filter->status = 4; - break; - } + s = ucs_a1_jis_table[w - ucs_a1_jis_table_min]; } - } else if (mode == 0x4) { - for (i = 0; i < 4; i++) { - if (c1 == code_tbl_m[i+8][2] && c == code_tbl_m[i+8][3]) { - filter->cache = c | 0x40000; - filter->status = 4; - break; - } + } else if (w >= ucs_a2_jis_table_min && w < ucs_a2_jis_table_max) { + if (w == 0x2122) { + s = 0xFE; + } else if (w == 0x2014) { + s = 0x213D; + } else if (w == 0x2116) { + s = 0x2C1D; + } else { + s = ucs_a2_jis_table[w - ucs_a2_jis_table_min]; } + } else if (w >= ucs_i_jis_table_min && w < ucs_i_jis_table_max) { + s = ucs_i_jis_table[w - ucs_i_jis_table_min]; + } else if (w >= ucs_r_jis_table_min && w < ucs_r_jis_table_max) { + s = ucs_r_jis_table[w - ucs_r_jis_table_min]; } - break; - - case 4: - s1 = 0; - c1 = filter->cache & 0xffff; - mode = (filter->cache & 0xf0000) >> 16; - filter->cache = 0; - filter->status = 0; + if (w >= 0x2000) { + for (int i = 0; i < s_form_tbl_len; i++) { + if (w == s_form_tbl[i]) { + if (!len) { + if (end) { + s = s_form_sjis_fallback_tbl[i]; + if (s) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, 2); + out = mb_convert_buf_add2(out, (s >> 8) & 0xFF, s & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjismac); + } + } else { + buf->state = w; + } + MB_CONVERT_BUF_STORE(buf, out, limit); + return; + } + uint32_t w2 = *in++; + len--; - if (mode == 0x2) { - for (i = 0; i < 3; i++) { - if (c1 == code_tbl_m[i+5][3] && c == code_tbl_m[i+5][4]) { - s1 = code_tbl_m[i+5][0]; - break; - } - } + if (!process_s_form(w, w2, &s)) { + in--; len++; - if (s1 > 0) { - c1 = s1/94+0x21; - c2 = s1-94*(c1-0x21)+0x21; - SJIS_ENCODE(c1, c2, s1, s2); - CK((*filter->output_function)(s1, filter->data)); - CK((*filter->output_function)(s2, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(0xf861, filter)); - for (i = 0; i < 3; i++) { - if (c1 == code_tbl_m[i+5][3]) { - CK(mbfl_filt_conv_illegal_output(code_tbl_m[i+5][2], filter)); - break; + for (int i = 0; i < s_form_tbl_len; i++) { + if (w == s_form_tbl[i]) { + s = s_form_sjis_fallback_tbl[i]; + break; + } + } } - } - CK(mbfl_filt_conv_illegal_output(c1, filter)); - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - } else if (mode == 0x4) { - for (i = 0; i < 4; i++) { - if (c1 == code_tbl_m[i+8][3] && c == code_tbl_m[i+8][4]) { - filter->cache = c | 0x40000; - filter->status = 5; - break; - } - } - } - break; - case 5: - s1 = 0; - c1 = filter->cache & 0xffff; - mode = (filter->cache & 0xf0000) >> 16; - - filter->cache = filter->status = 0; + if (s <= 0xFF) { + out = mb_convert_buf_add(out, s); + } else { + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + out = mb_convert_buf_add2(out, (s >> 8) & 0xFF, s & 0xFF); + } - if (mode == 0x4) { - for (i = 0; i < 4; i++) { - if (c1 == code_tbl_m[i+8][4] && c == code_tbl_m[i+8][5]) { - s1 = code_tbl_m[i+8][0]; - break; + goto next_iteration; } } - if (s1 > 0) { - c1 = s1/94+0x21; - c2 = s1-94*(c1-0x21)+0x21; - SJIS_ENCODE(c1, c2, s1, s2); - CK((*filter->output_function)(s1, filter->data)); - CK((*filter->output_function)(s2, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(0xf862, filter)); - for (i = 0; i < 4; i++) { - if (c1 == code_tbl_m[i+8][4]) { - CK(mbfl_filt_conv_illegal_output( code_tbl_m[i+8][2], filter)); - CK(mbfl_filt_conv_illegal_output( code_tbl_m[i+8][3], filter)); - break; + if (w == 0xF860 || w == 0xF861 || w == 0xF862) { + /* Apple 'transcoding hint' codepoints (from private use area) */ + if (!len) { + if (end) { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjismac); + } else { + buf->state = w; } + MB_CONVERT_BUF_STORE(buf, out, limit); + return; } - CK(mbfl_filt_conv_illegal_output(c1, filter)); - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - return 0; -} + uint32_t w2 = *in++; + len--; -static int mbfl_filt_conv_wchar_sjis_mac_flush(mbfl_convert_filter *filter) -{ - int i, c1, s1 = 0; - if (filter->status == 1 && filter->cache > 0) { - c1 = filter->cache; - for (i=0;i 0) { - CK((*filter->output_function)((s1 >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(s1 & 0xff, filter->data)); - } - } - filter->cache = 0; - filter->status = 0; + for (int i = 0; i < code_tbl_m_len; i++) { + if (w == code_tbl_m[i][1] && w2 == code_tbl_m[i][2]) { + /* This might be a valid transcoding hint sequence */ + int index = 3; - if (filter->flush_function != NULL) { - return (*filter->flush_function)(filter->data); - } - - return 0; -} - -static size_t mb_sjismac_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) -{ - /* A single SJIS-Mac kuten code can convert to up to 5 Unicode codepoints, oh my! */ - ZEND_ASSERT(bufsize >= 5); - - unsigned char *p = *in, *e = p + *in_len; - uint32_t *out = buf, *limit = buf + bufsize; - - while (p < e && out < limit) { - unsigned char c = *p++; - - if (c <= 0x80 || c == 0xA0) { - if (c == 0x5C) { - *out++ = 0xA5; - } else if (c == 0x80) { - *out++ = 0x5C; - } else { - *out++ = c; - } - } else if (c >= 0xA1 && c <= 0xDF) { - *out++ = 0xFEC0 + c; - } else if (c <= 0xED) { - if (p == e) { - *out++ = MBFL_BAD_INPUT; - break; - } - unsigned char c2 = *p++; - uint32_t w = sjis_decode_tbl1[c] + sjis_decode_tbl2[c2]; - - if (w <= 0x89) { - if (w == 0x1C) { - *out++ = 0x2014; /* EM DASH */ - continue; - } else if (w == 0x1F) { - *out++ = 0xFF3C; /* FULLWIDTH REVERSE SOLIDUS */ - continue; - } else if (w == 0x20) { - *out++ = 0x301C; /* FULLWIDTH TILDE */ - continue; - } else if (w == 0x21) { - *out++ = 0x2016; /* PARALLEL TO */ - continue; - } else if (w == 0x3C) { - *out++ = 0x2212; /* FULLWIDTH HYPHEN-MINUS */ - continue; - } else if (w == 0x50) { - *out++ = 0xA2; /* FULLWIDTH CENT SIGN */ - continue; - } else if (w == 0x51) { - *out++ = 0xA3; /* FULLWIDTH POUND SIGN */ - continue; - } else if (w == 0x89) { - *out++ = 0xAC; /* FULLWIDTH NOT SIGN */ - continue; - } - } else { - if (w >= 0x2F0 && w <= 0x3A3) { - for (int i = 0; i < 7; i++) { - if (w >= code_tbl[i][0] && w <= code_tbl[i][1]) { - *out++ = w - code_tbl[i][0] + code_tbl[i][2]; - goto next_iteration; + if (buf->state) { +resume_transcoding_hint: + i = buf->state >> 24; + index = (buf->state >> 16) & 0xFF; + buf->state = 0; } - } - } - if (w >= 0x340 && w <= 0x523) { - for (int i = 0; i < code_tbl_m_len; i++) { - if (w == code_tbl_m[i][0]) { - int n = 5; - if (code_tbl_m[i][1] == 0xF860) { - n = 3; - } else if (code_tbl_m[i][1] == 0xF861) { - n = 4; - } - if ((limit - out) < n) { - p -= 2; - goto finished; - } - for (int j = 1; j <= n; j++) { - *out++ = code_tbl_m[i][j]; - } - goto next_iteration; - } - } - } + int expected = transcoding_hint_cp_width[w - 0xF860]; - if (w >= 0x3AC && w <= 0x20A5) { - for (int i = 0; i < 8; i++) { - if (w >= code_ofst_tbl[i][0] && w <= code_ofst_tbl[i][1]) { - uint32_t w2 = code_map[i][w - code_ofst_tbl[i][0]]; - if (!w2) { - *out++ = MBFL_BAD_INPUT; - goto next_iteration; - } - if ((limit - out) < 2) { - p -= 2; - goto finished; - } - *out++ = w2; - if (w >= 0x43E && w <= 0x441) { - *out++ = 0xF87A; - } else if (w == 0x3B1 || w == 0x3B7) { - *out++ = 0xF87F; - } else if (w == 0x4B8 || w == 0x4B9 || w == 0x4C4) { - *out++ = 0x20DD; - } else if (w == 0x1ED9 || w == 0x1EDA || w == 0x1EE8 || w == 0x1EF3 || (w >= 0x1EF5 && w <= 0x1EFB) || w == 0x1F05 || w == 0x1F06 || w == 0x1F18 || (w >= 0x1FF2 && w <= 0x20A5)) { - *out++ = 0xF87E; + while (index <= expected) { + if (!len) { + if (end) { + for (int j = 1; j < index; j++) { + MB_CONVERT_ERROR(buf, out, limit, code_tbl_m[i][j], mb_wchar_to_sjismac); + } + } else { + buf->state = (i << 24) | (index << 16) | (w & 0xFFFF); + } + MB_CONVERT_BUF_STORE(buf, out, limit); + return; } - goto next_iteration; - } - } - } - } - - if (w < jisx0208_ucs_table_size) { - w = jisx0208_ucs_table[w]; - if (!w) - w = MBFL_BAD_INPUT; - *out++ = w; - } else { - *out++ = MBFL_BAD_INPUT; - } - } else if (c == 0xFD) { - *out++ = 0xA9; - } else if (c == 0xFE) { - *out++ = 0x2122; - } else if (c == 0xFF) { - if ((limit - out) < 2) { - p--; - break; - } - *out++ = 0x2026; - *out++ = 0xF87F; - } else { - *out++ = MBFL_BAD_INPUT; - } -next_iteration: ; - } - -finished: - *in_len = e - p; - *in = p; - return out - buf; -} - -static bool process_s_form(uint32_t w, uint32_t w2, unsigned int *s) -{ - if (w2 == 0xF87A) { - for (int i = 0; i < 4; i++) { - if (w == s_form_tbl[i+34+3+3]) { - *s = s_form_sjis_tbl[i+34+3+3]; - return true; - } - } - } else if (w2 == 0x20DD) { - for (int i = 0; i < 3; i++) { - if (w == s_form_tbl[i+34+3]) { - *s = s_form_sjis_tbl[i+34+3]; - return true; - } - } - } else if (w2 == 0xF87F) { - for (int i = 0; i < 3; i++) { - if (w == s_form_tbl[i+34]) { - *s = s_form_sjis_tbl[i+34]; - return true; - } - } - } else if (w2 == 0xF87E) { - for (int i = 0; i < 34; i++) { - if (w == s_form_tbl[i]) { - *s = s_form_sjis_tbl[i]; - return true; - } - } - } - - return false; -} - -/* For codepoints F860-F862, which are treated specially in MacJapanese */ -static int transcoding_hint_cp_width[3] = { 3, 4, 5 }; - -static void mb_wchar_to_sjismac(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) -{ - unsigned char *out, *limit; - MB_CONVERT_BUF_LOAD(buf, out, limit); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len); - - uint32_t w; - - if (buf->state) { - w = buf->state & 0xFFFF; - if (buf->state & 0xFF000000L) { - goto resume_transcoding_hint; - } else { - buf->state = 0; - goto process_codepoint; - } - } - - while (len--) { - w = *in++; -process_codepoint: ; - unsigned int s = 0; - if (w >= ucs_a1_jis_table_min && w < ucs_a1_jis_table_max) { - if (w == 0x5C) { - s = 0x80; - } else if (w == 0xA9) { - s = 0xFD; - } else { - s = ucs_a1_jis_table[w - ucs_a1_jis_table_min]; - } - } else if (w >= ucs_a2_jis_table_min && w < ucs_a2_jis_table_max) { - if (w == 0x2122) { - s = 0xFE; - } else if (w == 0x2014) { - s = 0x213D; - } else if (w == 0x2116) { - s = 0x2C1D; - } else { - s = ucs_a2_jis_table[w - ucs_a2_jis_table_min]; - } - } else if (w >= ucs_i_jis_table_min && w < ucs_i_jis_table_max) { - s = ucs_i_jis_table[w - ucs_i_jis_table_min]; - } else if (w >= ucs_r_jis_table_min && w < ucs_r_jis_table_max) { - s = ucs_r_jis_table[w - ucs_r_jis_table_min]; - } - - if (w >= 0x2000) { - for (int i = 0; i < s_form_tbl_len; i++) { - if (w == s_form_tbl[i]) { - if (!len) { - if (end) { - s = s_form_sjis_fallback_tbl[i]; - if (s) { - MB_CONVERT_BUF_ENSURE(buf, out, limit, 2); - out = mb_convert_buf_add2(out, (s >> 8) & 0xFF, s & 0xFF); - } else { - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjismac); - } - } else { - buf->state = w; - } - MB_CONVERT_BUF_STORE(buf, out, limit); - return; - } - uint32_t w2 = *in++; - len--; - - if (!process_s_form(w, w2, &s)) { - in--; len++; - - for (int i = 0; i < s_form_tbl_len; i++) { - if (w == s_form_tbl[i]) { - s = s_form_sjis_fallback_tbl[i]; - break; - } - } - } - - if (s <= 0xFF) { - out = mb_convert_buf_add(out, s); - } else { - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); - out = mb_convert_buf_add2(out, (s >> 8) & 0xFF, s & 0xFF); - } - - goto next_iteration; - } - } - - if (w == 0xF860 || w == 0xF861 || w == 0xF862) { - /* Apple 'transcoding hint' codepoints (from private use area) */ - if (!len) { - if (end) { - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjismac); - } else { - buf->state = w; - } - MB_CONVERT_BUF_STORE(buf, out, limit); - return; - } - - uint32_t w2 = *in++; - len--; - - for (int i = 0; i < code_tbl_m_len; i++) { - if (w == code_tbl_m[i][1] && w2 == code_tbl_m[i][2]) { - /* This might be a valid transcoding hint sequence */ - int index = 3; - - if (buf->state) { -resume_transcoding_hint: - i = buf->state >> 24; - index = (buf->state >> 16) & 0xFF; - buf->state = 0; - } - - int expected = transcoding_hint_cp_width[w - 0xF860]; - - while (index <= expected) { - if (!len) { - if (end) { - for (int j = 1; j < index; j++) { - MB_CONVERT_ERROR(buf, out, limit, code_tbl_m[i][j], mb_wchar_to_sjismac); - } - } else { - buf->state = (i << 24) | (index << 16) | (w & 0xFFFF); - } - MB_CONVERT_BUF_STORE(buf, out, limit); - return; - } - - w2 = *in++; - len--; - - if (w2 != code_tbl_m[i][index]) { - /* Didn't match */ - for (int j = 1; j < index; j++) { - MB_CONVERT_ERROR(buf, out, limit, code_tbl_m[i][j], mb_wchar_to_sjismac); - } - MB_CONVERT_ERROR(buf, out, limit, w2, mb_wchar_to_sjismac); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len); - goto next_iteration; - } - - index++; - } - - /* Successful match, emit SJIS-mac bytes */ - s = code_tbl_m[i][0]; - unsigned int c1 = (s / 94) + 0x21, c2 = (s % 94) + 0x21, s1, s2; - SJIS_ENCODE(c1, c2, s1, s2); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); - out = mb_convert_buf_add2(out, s1, s2); - goto next_iteration; - } - } - - /* No valid transcoding hint sequence found */ - in--; len++; - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjismac); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len); - continue; - } - } - - if (!s) { - if (w == 0xA0) { - s = 0xA0; - } else if (w == 0xA5) { /* YEN SIGN */ - /* Unicode has codepoint 0xFFE5 for a fullwidth Yen sign; - * convert codepoint 0xA5 to halfwidth Yen sign */ - s = 0x5C; /* HALFWIDTH YEN SIGN */ - } else if (w == 0xFF3C) { /* FULLWIDTH REVERSE SOLIDUS */ - s = 0x2140; - } else { - for (int i = 0; i < wchar2sjis_mac_r_tbl_len; i++) { - if (w >= wchar2sjis_mac_r_tbl[i][0] && w <= wchar2sjis_mac_r_tbl[i][1]) { - s = w - wchar2sjis_mac_r_tbl[i][0] + wchar2sjis_mac_r_tbl[i][2]; - s = (((s / 94) + 0x21) << 8) | ((s % 94) + 0x21); - goto found_kuten_code; - } - } - - for (int i = 0; i < wchar2sjis_mac_r_map_len; i++) { - if (w >= wchar2sjis_mac_r_map[i][0] && w <= wchar2sjis_mac_r_map[i][1]) { - s = wchar2sjis_mac_code_map[i][w - wchar2sjis_mac_r_map[i][0]]; - if (s) { - s = (((s / 94) + 0x21) << 8) | ((s % 94) + 0x21); - goto found_kuten_code; - } - } - } - - for (int i = 0; i < wchar2sjis_mac_wchar_tbl_len; i++) { - if (w == wchar2sjis_mac_wchar_tbl[i][0]) { - s = wchar2sjis_mac_wchar_tbl[i][1]; - s = (((s / 94) + 0x21) << 8) | ((s % 94) + 0x21); - goto found_kuten_code; - } - } - } - } - -found_kuten_code: - if ((!s && w) || s >= 0x8080) { - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjismac); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len); - } else if (s <= 0xFF) { - out = mb_convert_buf_add(out, s); - } else { - unsigned int c1 = (s >> 8) & 0xFF, c2 = s & 0xFF, s1, s2; - SJIS_ENCODE(c1, c2, s1, s2); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); - out = mb_convert_buf_add2(out, s1, s2); - } - -next_iteration: ; - } - - MB_CONVERT_BUF_STORE(buf, out, limit); -} - -int mbfilter_sjis_emoji_docomo2unicode(int s, int *snd) -{ - /* All three mobile vendors had emoji for numbers on a telephone keypad - * Unicode doesn't have those, but it has a combining character which puts - * a 'keypad button' around the following character, making it look like - * a key on a telephone or keyboard. That combining char is codepoint 0x20E3. */ - if (s >= mb_tbl_code2uni_docomo1_min && s <= mb_tbl_code2uni_docomo1_max) { - if ((s >= DOCOMO_KEYPAD(1) && s <= DOCOMO_KEYPAD(9)) || s == DOCOMO_KEYPAD(0) || s == DOCOMO_KEYPAD_HASH) { - EMIT_KEYPAD_EMOJI(convert_emoji_cp(mb_tbl_code2uni_docomo1[s - mb_tbl_code2uni_docomo1_min])); - } else { - *snd = 0; - return convert_emoji_cp(mb_tbl_code2uni_docomo1[s - mb_tbl_code2uni_docomo1_min]); - } - } - return 0; -} - -int mbfilter_sjis_emoji_sb2unicode(int s, int *snd) -{ - if (s >= mb_tbl_code2uni_sb1_min && s <= mb_tbl_code2uni_sb1_max) { - if (s == 0x2817 || (s >= 0x2823 && s <= 0x282C)) { - EMIT_KEYPAD_EMOJI(mb_tbl_code2uni_sb1[s - mb_tbl_code2uni_sb1_min]); - } else { - *snd = 0; - return convert_emoji_cp(mb_tbl_code2uni_sb1[s - mb_tbl_code2uni_sb1_min]); - } - } else if (s >= mb_tbl_code2uni_sb2_min && s <= mb_tbl_code2uni_sb2_max) { - *snd = 0; - return convert_emoji_cp(mb_tbl_code2uni_sb2[s - mb_tbl_code2uni_sb2_min]); - } else if (s >= mb_tbl_code2uni_sb3_min && s <= mb_tbl_code2uni_sb3_max) { - if (s >= 0x2B02 && s <= 0x2B0B) { - EMIT_FLAG_EMOJI(nflags_sb[s - 0x2B02]); - } else { - *snd = 0; - return convert_emoji_cp(mb_tbl_code2uni_sb3[s - mb_tbl_code2uni_sb3_min]); - } - } - return 0; -} - -int mbfilter_unicode2sjis_emoji_docomo(int c, int *s1, mbfl_convert_filter *filter) -{ - /* When converting SJIS-Mobile to Unicode, we convert keypad symbol emoji - * to a sequence of 2 codepoints, one of which is a combining character which - * adds the 'key' image around the other - * - * In the other direction, look for such sequences and convert them to a - * single emoji */ - if (filter->status == 1) { - int c1 = filter->cache; - filter->cache = filter->status = 0; - if (c == 0x20E3) { - if (c1 == '#') { - *s1 = 0x2964; - } else if (c1 == '0') { - *s1 = 0x296F; - } else { /* Previous character was '1'-'9' */ - *s1 = 0x2966 + (c1 - '1'); - } - return 1; - } else { - /* This character wasn't combining character to make keypad symbol, - * so pass the previous character through... and proceed to process the - * current character as usual - * (Single-byte ASCII characters are valid in Shift-JIS...) */ - CK((*filter->output_function)(c1, filter->data)); - } - } - - if (c == '#' || (c >= '0' && c <= '9')) { - filter->status = 1; - filter->cache = c; - return 0; - } - - if (c == 0xA9) { /* Copyright sign */ - *s1 = 0x29B5; - return 1; - } else if (c == 0x00AE) { /* Registered sign */ - *s1 = 0x29BA; - return 1; - } else if (c >= mb_tbl_uni_docomo2code2_min && c <= mb_tbl_uni_docomo2code2_max) { - int i = mbfl_bisec_srch2(c, mb_tbl_uni_docomo2code2_key, mb_tbl_uni_docomo2code2_len); - if (i >= 0) { - *s1 = mb_tbl_uni_docomo2code2_value[i]; - return 1; - } - } else if (c >= mb_tbl_uni_docomo2code3_min && c <= mb_tbl_uni_docomo2code3_max) { - int i = mbfl_bisec_srch2(c - 0x10000, mb_tbl_uni_docomo2code3_key, mb_tbl_uni_docomo2code3_len); - if (i >= 0) { - *s1 = mb_tbl_uni_docomo2code3_value[i]; - return 1; - } - } else if (c >= mb_tbl_uni_docomo2code5_min && c <= mb_tbl_uni_docomo2code5_max) { - int i = mbfl_bisec_srch2(c - 0xF0000, mb_tbl_uni_docomo2code5_key, mb_tbl_uni_docomo2code5_len); - if (i >= 0) { - *s1 = mb_tbl_uni_docomo2code5_val[i]; - return 1; - } - } - return 0; -} - -int mbfilter_unicode2sjis_emoji_kddi_sjis(int c, int *s1, mbfl_convert_filter *filter) -{ - if (filter->status == 1) { - int c1 = filter->cache; - filter->cache = filter->status = 0; - if (c == 0x20E3) { - if (c1 == '#') { - *s1 = 0x25BC; - } else if (c1 == '0') { - *s1 = 0x2830; - } else { /* Previous character was '1'-'9' */ - *s1 = 0x27a6 + (c1 - '1'); - } - return 1; - } else { - CK((*filter->output_function)(c1, filter->data)); - } - } else if (filter->status == 2) { - int c1 = filter->cache; - filter->cache = filter->status = 0; - if (c >= NFLAGS('B') && c <= NFLAGS('U')) { /* B for GB, U for RU */ - for (int i = 0; i < 10; i++) { - if (c1 == NFLAGS(nflags_s[i][0]) && c == NFLAGS(nflags_s[i][1])) { - *s1 = nflags_code_kddi[i]; - return 1; - } - } - } - - /* If none of the KDDI national flag emoji matched, then we have no way - * to convert the previous codepoint... */ - mbfl_filt_conv_illegal_output(c1, filter); - } - - if (c == '#' || (c >= '0' && c <= '9')) { - filter->status = 1; - filter->cache = c; - return 0; - } else if (c >= NFLAGS('C') && c <= NFLAGS('U')) { /* C for CN, U for US */ - filter->status = 2; - filter->cache = c; - return 0; - } - - if (c == 0xA9) { /* Copyright sign */ - *s1 = 0x27DC; - return 1; - } else if (c == 0xAE) { /* Registered sign */ - *s1 = 0x27DD; - return 1; - } else if (c >= mb_tbl_uni_kddi2code2_min && c <= mb_tbl_uni_kddi2code2_max) { - int i = mbfl_bisec_srch2(c, mb_tbl_uni_kddi2code2_key, mb_tbl_uni_kddi2code2_len); - if (i >= 0) { - *s1 = mb_tbl_uni_kddi2code2_value[i]; - return 1; - } - } else if (c >= mb_tbl_uni_kddi2code3_min && c <= mb_tbl_uni_kddi2code3_max) { - int i = mbfl_bisec_srch2(c - 0x10000, mb_tbl_uni_kddi2code3_key, mb_tbl_uni_kddi2code3_len); - if (i >= 0) { - *s1 = mb_tbl_uni_kddi2code3_value[i]; - return 1; - } - } else if (c >= mb_tbl_uni_kddi2code5_min && c <= mb_tbl_uni_kddi2code5_max) { - int i = mbfl_bisec_srch2(c - 0xF0000, mb_tbl_uni_kddi2code5_key, mb_tbl_uni_kddi2code5_len); - if (i >= 0) { - *s1 = mb_tbl_uni_kddi2code5_val[i]; - return 1; - } - } - return 0; -} - -int mbfilter_unicode2sjis_emoji_sb(int c, int *s1, mbfl_convert_filter *filter) -{ - if (filter->status == 1) { - int c1 = filter->cache; - filter->cache = filter->status = 0; - if (c == 0x20E3) { - if (c1 == '#') { - *s1 = 0x2817; - } else if (c1 == '0') { - *s1 = 0x282c; - } else { /* Previous character was '1'-'9' */ - *s1 = 0x2823 + (c1 - '1'); - } - return 1; - } else { - (*filter->output_function)(c1, filter->data); - } - } else if (filter->status == 2) { - int c1 = filter->cache; - filter->cache = filter->status = 0; - if (c >= NFLAGS('B') && c <= NFLAGS('U')) { /* B for GB, U for RU */ - for (int i = 0; i < 10; i++) { - if (c1 == NFLAGS(nflags_s[i][0]) && c == NFLAGS(nflags_s[i][1])) { - *s1 = nflags_code_sb[i]; - return 1; - } - } - } - - /* If none of the SoftBank national flag emoji matched, then we have no way - * to convert the previous codepoint... */ - mbfl_filt_conv_illegal_output(c1, filter); - } - - if (c == '#' || (c >= '0' && c <= '9')) { - filter->status = 1; - filter->cache = c; - return 0; - } else if (c >= NFLAGS('C') && c <= NFLAGS('U')) { /* C for CN, U for US */ - filter->status = 2; - filter->cache = c; - return 0; - } - - if (c == 0xA9) { /* Copyright sign */ - *s1 = 0x2855; - return 1; - } else if (c == 0xAE) { /* Registered sign */ - *s1 = 0x2856; - return 1; - } else if (c >= mb_tbl_uni_sb2code2_min && c <= mb_tbl_uni_sb2code2_max) { - int i = mbfl_bisec_srch2(c, mb_tbl_uni_sb2code2_key, mb_tbl_uni_sb2code2_len); - if (i >= 0) { - *s1 = mb_tbl_uni_sb2code2_value[i]; - return 1; - } - } else if (c >= mb_tbl_uni_sb2code3_min && c <= mb_tbl_uni_sb2code3_max) { - int i = mbfl_bisec_srch2(c - 0x10000, mb_tbl_uni_sb2code3_key, mb_tbl_uni_sb2code3_len); - if (i >= 0) { - *s1 = mb_tbl_uni_sb2code3_value[i]; - return 1; - } - } else if (c >= mb_tbl_uni_sb2code5_min && c <= mb_tbl_uni_sb2code5_max) { - int i = mbfl_bisec_srch2(c - 0xF0000, mb_tbl_uni_sb2code5_key, mb_tbl_uni_sb2code5_len); - if (i >= 0) { - *s1 = mb_tbl_uni_sb2code5_val[i]; - return 1; - } - } - return 0; -} - -static int mbfl_filt_conv_sjis_mobile_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, s, s1, s2, w, snd = 0; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* ASCII */ - if (filter->from == &mbfl_encoding_sjis_sb && c == 0x1B) { - /* ESC; escape sequences were used on older SoftBank phones for emoji */ - filter->cache = c; - filter->status = 2; - } else { - CK((*filter->output_function)(c, filter->data)); - } - } else if (c > 0xA0 && c < 0xE0) { /* Kana */ - CK((*filter->output_function)(0xFEC0 + c, filter->data)); - } else if (c > 0x80 && c < 0xFD && c != 0xA0) { /* Kanji, first byte */ - filter->status = 1; - filter->cache = c; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* Kanji, second byte */ - filter->status = 0; - c1 = filter->cache; - if (c >= 0x40 && c <= 0xFC && c != 0x7F) { - w = 0; - SJIS_DECODE(c1, c, s1, s2); - s = ((s1 - 0x21) * 94) + s2 - 0x21; - if (s <= 137) { - if (s == 31) { - w = 0xFF3C; /* FULLWIDTH REVERSE SOLIDUS */ - } else if (s == 32) { - w = 0xFF5E; /* FULLWIDTH TILDE */ - } else if (s == 33) { - w = 0x2225; /* PARALLEL TO */ - } else if (s == 60) { - w = 0xFF0D; /* FULLWIDTH HYPHEN-MINUS */ - } else if (s == 80) { - w = 0xFFE0; /* FULLWIDTH CENT SIGN */ - } else if (s == 81) { - w = 0xFFE1; /* FULLWIDTH POUND SIGN */ - } else if (s == 137) { - w = 0xFFE2; /* FULLWIDTH NOT SIGN */ - } - } - if (w == 0) { - if (s >= cp932ext1_ucs_table_min && s < cp932ext1_ucs_table_max) { /* vendor ext1 (13ku) */ - w = cp932ext1_ucs_table[s - cp932ext1_ucs_table_min]; - } else if (s >= 0 && s < jisx0208_ucs_table_size) { /* X 0208 */ - w = jisx0208_ucs_table[s]; - } else if (s >= cp932ext2_ucs_table_min && s < cp932ext2_ucs_table_max) { /* vendor ext2 (89ku - 92ku) */ - w = cp932ext2_ucs_table[s - cp932ext2_ucs_table_min]; - } - - /* Emoji */ - if (filter->from == &mbfl_encoding_sjis_docomo && s >= mb_tbl_code2uni_docomo1_min && s <= mb_tbl_code2uni_docomo1_max) { - w = mbfilter_sjis_emoji_docomo2unicode(s, &snd); - if (snd > 0) { - CK((*filter->output_function)(snd, filter->data)); - } - } else if (filter->from == &mbfl_encoding_sjis_kddi && s >= mb_tbl_code2uni_kddi1_min && s <= mb_tbl_code2uni_kddi2_max) { - w = mbfilter_sjis_emoji_kddi2unicode(s, &snd); - if (snd > 0) { - CK((*filter->output_function)(snd, filter->data)); - } - } else if (filter->from == &mbfl_encoding_sjis_sb && s >= mb_tbl_code2uni_sb1_min && s <= mb_tbl_code2uni_sb3_max) { - w = mbfilter_sjis_emoji_sb2unicode(s, &snd); - if (snd > 0) { - CK((*filter->output_function)(snd, filter->data)); - } - } - - if (w == 0) { - if (s >= cp932ext3_ucs_table_min && s < cp932ext3_ucs_table_max) { /* vendor ext3 (115ku - 119ku) */ - w = cp932ext3_ucs_table[s - cp932ext3_ucs_table_min]; - } else if (s >= (94*94) && s < (114*94)) { /* user (95ku - 114ku) */ - w = s - (94*94) + 0xe000; - } - } - } - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - /* ESC: Softbank Emoji */ - case 2: - if (c == '$') { - filter->cache = c; - filter->status++; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - filter->status = filter->cache = 0; - } - break; - - /* ESC $: Softbank Emoji */ - case 3: - if ((c >= 'E' && c <= 'G') || (c >= 'O' && c <= 'Q')) { - filter->cache = c; - filter->status++; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - filter->status = filter->cache = 0; - } - break; - - /* ESC $ [GEFOPQ]: Softbank Emoji */ - case 4: - c1 = filter->cache; - if (c == 0xF) { /* Terminate sequence of emoji */ - filter->status = filter->cache = 0; - return 0; - } else { - if (c1 == 'G' && c >= 0x21 && c <= 0x7a) { - s1 = (0x91 - 0x21) * 94; - } else if (c1 == 'E' && c >= 0x21 && c <= 0x7A) { - s1 = (0x8D - 0x21) * 94; - } else if (c1 == 'F' && c >= 0x21 && c <= 0x7A) { - s1 = (0x8E - 0x21) * 94; - } else if (c1 == 'O' && c >= 0x21 && c <= 0x6D) { - s1 = (0x92 - 0x21) * 94; - } else if (c1 == 'P' && c >= 0x21 && c <= 0x6C) { - s1 = (0x95 - 0x21) * 94; - } else if (c1 == 'Q' && c >= 0x21 && c <= 0x5E) { - s1 = (0x96 - 0x21) * 94; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - filter->status = filter->cache = 0; - return 0; - } - - w = mbfilter_sjis_emoji_sb2unicode(s1 + c - 0x21, &snd); - if (w > 0) { - if (snd > 0) { - CK((*filter->output_function)(snd, filter->data)); - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - filter->status = filter->cache = 0; - } - } - } - - return 0; -} - -static int mbfl_filt_conv_wchar_sjis_mobile(int c, mbfl_convert_filter *filter) -{ - int c1, c2, s1 = 0, s2 = 0; - - if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) { - s1 = ucs_a1_jis_table[c - ucs_a1_jis_table_min]; - } else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) { - s1 = ucs_a2_jis_table[c - ucs_a2_jis_table_min]; - } else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) { - s1 = ucs_i_jis_table[c - ucs_i_jis_table_min]; - } else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) { - s1 = ucs_r_jis_table[c - ucs_r_jis_table_min]; - } else if (c >= 0xE000 && c < (0xE000 + 20*94)) { - /* Private User Area (95ku - 114ku) */ - s1 = c - 0xE000; - c1 = (s1 / 94) + 0x7F; - c2 = (s1 % 94) + 0x21; - s1 = (c1 << 8) | c2; - s2 = 1; - } - - if (s1 <= 0) { - if (c == 0xA5) { /* YEN SIGN */ - s1 = 0x216F; /* FULLWIDTH YEN SIGN */ - } else if (c == 0xFF3c) { /* FULLWIDTH REVERSE SOLIDUS */ - s1 = 0x2140; - } else if (c == 0x2225) { /* PARALLEL TO */ - s1 = 0x2142; - } else if (c == 0xFF0D) { /* FULLWIDTH HYPHEN-MINUS */ - s1 = 0x215D; - } else if (c == 0xFFE0) { /* FULLWIDTH CENT SIGN */ - s1 = 0x2171; - } else if (c == 0xFFE1) { /* FULLWIDTH POUND SIGN */ - s1 = 0x2172; - } else if (c == 0xFFE2) { /* FULLWIDTH NOT SIGN */ - s1 = 0x224C; - } - } + w2 = *in++; + len--; - if ((s1 <= 0) || (s1 >= 0x8080 && s2 == 0)) { /* not found or X 0212 */ - s1 = -1; + if (w2 != code_tbl_m[i][index]) { + /* Didn't match */ + for (int j = 1; j < index; j++) { + MB_CONVERT_ERROR(buf, out, limit, code_tbl_m[i][j], mb_wchar_to_sjismac); + } + MB_CONVERT_ERROR(buf, out, limit, w2, mb_wchar_to_sjismac); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + goto next_iteration; + } - /* CP932 vendor ext1 (13ku) */ - for (c1 = 0; c1 < cp932ext1_ucs_table_max - cp932ext1_ucs_table_min; c1++) { - if (c == cp932ext1_ucs_table[c1]) { - s1 = (((c1 / 94) + 0x2D) << 8) + (c1 % 94) + 0x21; - break; + index++; + } + + /* Successful match, emit SJIS-mac bytes */ + s = code_tbl_m[i][0]; + unsigned int c1 = (s / 94) + 0x21, c2 = (s % 94) + 0x21, s1, s2; + SJIS_ENCODE(c1, c2, s1, s2); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + out = mb_convert_buf_add2(out, s1, s2); + goto next_iteration; + } + } + + /* No valid transcoding hint sequence found */ + in--; len++; + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjismac); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + continue; } } - if (s1 <= 0) { - /* CP932 vendor ext2 (115ku - 119ku) */ - for (c1 = 0; c1 < cp932ext2_ucs_table_max - cp932ext2_ucs_table_min; c1++) { - if (c == cp932ext2_ucs_table[c1]) { - s1 = (((c1 / 94) + 0x79) << 8) + (c1 % 94) + 0x21; - break; + if (!s) { + if (w == 0xA0) { + s = 0xA0; + } else if (w == 0xA5) { /* YEN SIGN */ + /* Unicode has codepoint 0xFFE5 for a fullwidth Yen sign; + * convert codepoint 0xA5 to halfwidth Yen sign */ + s = 0x5C; /* HALFWIDTH YEN SIGN */ + } else if (w == 0xFF3C) { /* FULLWIDTH REVERSE SOLIDUS */ + s = 0x2140; + } else { + for (int i = 0; i < wchar2sjis_mac_r_tbl_len; i++) { + if (w >= wchar2sjis_mac_r_tbl[i][0] && w <= wchar2sjis_mac_r_tbl[i][1]) { + s = w - wchar2sjis_mac_r_tbl[i][0] + wchar2sjis_mac_r_tbl[i][2]; + s = (((s / 94) + 0x21) << 8) | ((s % 94) + 0x21); + goto found_kuten_code; + } + } + + for (int i = 0; i < wchar2sjis_mac_r_map_len; i++) { + if (w >= wchar2sjis_mac_r_map[i][0] && w <= wchar2sjis_mac_r_map[i][1]) { + s = wchar2sjis_mac_code_map[i][w - wchar2sjis_mac_r_map[i][0]]; + if (s) { + s = (((s / 94) + 0x21) << 8) | ((s % 94) + 0x21); + goto found_kuten_code; + } + } + } + + for (int i = 0; i < wchar2sjis_mac_wchar_tbl_len; i++) { + if (w == wchar2sjis_mac_wchar_tbl[i][0]) { + s = wchar2sjis_mac_wchar_tbl[i][1]; + s = (((s / 94) + 0x21) << 8) | ((s % 94) + 0x21); + goto found_kuten_code; + } } } } - if (c == 0) { - s1 = 0; +found_kuten_code: + if ((!s && w) || s >= 0x8080) { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjismac); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } else if (s <= 0xFF) { + out = mb_convert_buf_add(out, s); + } else { + unsigned int c1 = (s >> 8) & 0xFF, c2 = s & 0xFF, s1, s2; + SJIS_ENCODE(c1, c2, s1, s2); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + out = mb_convert_buf_add2(out, s1, s2); } - } - if ((filter->to == &mbfl_encoding_sjis_docomo && mbfilter_unicode2sjis_emoji_docomo(c, &s1, filter)) || - (filter->to == &mbfl_encoding_sjis_kddi && mbfilter_unicode2sjis_emoji_kddi_sjis(c, &s1, filter)) || - (filter->to == &mbfl_encoding_sjis_sb && mbfilter_unicode2sjis_emoji_sb(c, &s1, filter))) { - s1 = (((s1 / 94) + 0x21) << 8) | ((s1 % 94) + 0x21); +next_iteration: ; } - if (filter->status) { - return 0; - } + MB_CONVERT_BUF_STORE(buf, out, limit); +} - if (s1 >= 0) { - if (s1 < 0x100) { /* Latin/Kana */ - CK((*filter->output_function)(s1, filter->data)); - } else { /* Kanji */ - c1 = (s1 >> 8) & 0xff; - c2 = s1 & 0xff; - SJIS_ENCODE(c1, c2, s1, s2); - CK((*filter->output_function)(s1, filter->data)); - CK((*filter->output_function)(s2, filter->data)); +int mbfilter_sjis_emoji_docomo2unicode(int s, int *snd) +{ + /* All three mobile vendors had emoji for numbers on a telephone keypad + * Unicode doesn't have those, but it has a combining character which puts + * a 'keypad button' around the following character, making it look like + * a key on a telephone or keyboard. That combining char is codepoint 0x20E3. */ + if (s >= mb_tbl_code2uni_docomo1_min && s <= mb_tbl_code2uni_docomo1_max) { + if ((s >= DOCOMO_KEYPAD(1) && s <= DOCOMO_KEYPAD(9)) || s == DOCOMO_KEYPAD(0) || s == DOCOMO_KEYPAD_HASH) { + EMIT_KEYPAD_EMOJI(convert_emoji_cp(mb_tbl_code2uni_docomo1[s - mb_tbl_code2uni_docomo1_min])); + } else { + *snd = 0; + return convert_emoji_cp(mb_tbl_code2uni_docomo1[s - mb_tbl_code2uni_docomo1_min]); } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); } - return 0; } -int mbfl_filt_conv_sjis_mobile_flush(mbfl_convert_filter *filter) +int mbfilter_sjis_emoji_sb2unicode(int s, int *snd) { - int c1 = filter->cache; - if (filter->status == 1 && (c1 == '#' || (c1 >= '0' && c1 <= '9'))) { - filter->cache = filter->status = 0; - CK((*filter->output_function)(c1, filter->data)); - } else if (filter->status == 2) { - /* First of a pair of Regional Indicator codepoints came at the end of a string */ - filter->cache = filter->status = 0; - mbfl_filt_conv_illegal_output(c1, filter); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); + if (s >= mb_tbl_code2uni_sb1_min && s <= mb_tbl_code2uni_sb1_max) { + if (s == 0x2817 || (s >= 0x2823 && s <= 0x282C)) { + EMIT_KEYPAD_EMOJI(mb_tbl_code2uni_sb1[s - mb_tbl_code2uni_sb1_min]); + } else { + *snd = 0; + return convert_emoji_cp(mb_tbl_code2uni_sb1[s - mb_tbl_code2uni_sb1_min]); + } + } else if (s >= mb_tbl_code2uni_sb2_min && s <= mb_tbl_code2uni_sb2_max) { + *snd = 0; + return convert_emoji_cp(mb_tbl_code2uni_sb2[s - mb_tbl_code2uni_sb2_min]); + } else if (s >= mb_tbl_code2uni_sb3_min && s <= mb_tbl_code2uni_sb3_max) { + if (s >= 0x2B02 && s <= 0x2B0B) { + EMIT_FLAG_EMOJI(nflags_sb[s - 0x2B02]); + } else { + *snd = 0; + return convert_emoji_cp(mb_tbl_code2uni_sb3[s - mb_tbl_code2uni_sb3_min]); + } } - return 0; } @@ -7345,198 +6232,13 @@ process_codepoint: ; out = mb_convert_buf_add(out, s); } else { unsigned int c1 = (s >> 8) & 0xFF, c2 = s & 0xFF, s1, s2; - SJIS_ENCODE(c1, c2, s1, s2); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); - out = mb_convert_buf_add2(out, s1, s2); - } - } - - MB_CONVERT_BUF_STORE(buf, out, limit); -} - -static int mbfl_filt_conv_cp932_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, s, s1, s2, w; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (c > 0xa0 && c < 0xe0) { /* kana */ - CK((*filter->output_function)(0xfec0 + c, filter->data)); - } else if (c > 0x80 && c < 0xfd && c != 0xa0) { /* kanji first char */ - filter->status = 1; - filter->cache = c; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* kanji second char */ - filter->status = 0; - c1 = filter->cache; - if (c >= 0x40 && c <= 0xfc && c != 0x7f) { - w = 0; - SJIS_DECODE(c1, c, s1, s2); - s = (s1 - 0x21)*94 + s2 - 0x21; - if (s <= 137) { - if (s == 31) { - w = 0xff3c; /* FULLWIDTH REVERSE SOLIDUS */ - } else if (s == 32) { - w = 0xff5e; /* FULLWIDTH TILDE */ - } else if (s == 33) { - w = 0x2225; /* PARALLEL TO */ - } else if (s == 60) { - w = 0xff0d; /* FULLWIDTH HYPHEN-MINUS */ - } else if (s == 80) { - w = 0xffe0; /* FULLWIDTH CENT SIGN */ - } else if (s == 81) { - w = 0xffe1; /* FULLWIDTH POUND SIGN */ - } else if (s == 137) { - w = 0xffe2; /* FULLWIDTH NOT SIGN */ - } - } - if (w == 0) { - if (s >= cp932ext1_ucs_table_min && s < cp932ext1_ucs_table_max) { /* vendor ext1 (13ku) */ - w = cp932ext1_ucs_table[s - cp932ext1_ucs_table_min]; - } else if (s >= 0 && s < jisx0208_ucs_table_size) { /* X 0208 */ - w = jisx0208_ucs_table[s]; - } else if (s >= cp932ext2_ucs_table_min && s < cp932ext2_ucs_table_max) { /* vendor ext2 (89ku - 92ku) */ - w = cp932ext2_ucs_table[s - cp932ext2_ucs_table_min]; - } else if (s >= cp932ext3_ucs_table_min && s < cp932ext3_ucs_table_max) { /* vendor ext3 (115ku - 119ku) */ - w = cp932ext3_ucs_table[s - cp932ext3_ucs_table_min]; - } else if (s >= (94*94) && s < (114*94)) { /* user (95ku - 114ku) */ - w = s - (94*94) + 0xe000; - } - } - - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_cp932_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - (*filter->output_function)(MBFL_BAD_INPUT, filter->data); - filter->status = 0; - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_cp932(int c, mbfl_convert_filter *filter) -{ - int c1, c2, s1, s2; - - s1 = 0; - s2 = 0; - if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) { - s1 = ucs_a1_jis_table[c - ucs_a1_jis_table_min]; - } else if (c == 0x203E) { - s1 = 0x7E; - } else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) { - s1 = ucs_a2_jis_table[c - ucs_a2_jis_table_min]; - } else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) { - s1 = ucs_i_jis_table[c - ucs_i_jis_table_min]; - } else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) { - s1 = ucs_r_jis_table[c - ucs_r_jis_table_min]; - } else if (c >= 0xe000 && c < (0xe000 + 20*94)) { /* user (95ku - 114ku) */ - s1 = c - 0xe000; - c1 = s1/94 + 0x7f; - c2 = s1%94 + 0x21; - s1 = (c1 << 8) | c2; - s2 = 1; - } - if (s1 <= 0) { - if (c == 0xa5) { /* YEN SIGN */ - s1 = 0x5C; - } else if (c == 0xff3c) { /* FULLWIDTH REVERSE SOLIDUS */ - s1 = 0x2140; - } else if (c == 0x2225) { /* PARALLEL TO */ - s1 = 0x2142; - } else if (c == 0xff0d) { /* FULLWIDTH HYPHEN-MINUS */ - s1 = 0x215d; - } else if (c == 0xffe0) { /* FULLWIDTH CENT SIGN */ - s1 = 0x2171; - } else if (c == 0xffe1) { /* FULLWIDTH POUND SIGN */ - s1 = 0x2172; - } else if (c == 0xffe2) { /* FULLWIDTH NOT SIGN */ - s1 = 0x224c; - } - } - if ((s1 <= 0) || (s1 >= 0x8080 && s2 == 0)) { /* not found or X 0212 */ - s1 = -1; - c1 = 0; - c2 = cp932ext1_ucs_table_max - cp932ext1_ucs_table_min; - while (c1 < c2) { /* CP932 vendor ext1 (13ku) */ - if (c == cp932ext1_ucs_table[c1]) { - s1 = ((c1/94 + 0x2d) << 8) + (c1%94 + 0x21); - break; - } - c1++; - } - if (s1 <= 0) { - c1 = 0; - c2 = cp932ext3_ucs_table_max - cp932ext3_ucs_table_min; - while (c1 < c2) { /* CP932 vendor ext3 (115ku - 119ku) */ - if (c == cp932ext3_ucs_table[c1]) { - s1 = ((c1/94 + 0x93) << 8) + (c1%94 + 0x21); - break; - } - c1++; - } - } - if (c == 0) { - s1 = 0; - } else if (s1 <= 0) { - s1 = -1; - } - } - if (s1 >= 0) { - if (s1 < 0x100) { /* latin or kana */ - CK((*filter->output_function)(s1, filter->data)); - } else { /* kanji */ - c1 = (s1 >> 8) & 0xff; - c2 = s1 & 0xff; - SJIS_ENCODE(c1, c2, s1, s2); - CK((*filter->output_function)(s1, filter->data)); - CK((*filter->output_function)(s2, filter->data)); + SJIS_ENCODE(c1, c2, s1, s2); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + out = mb_convert_buf_add2(out, s1, s2); } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); } - return 0; -} - -static int mbfl_filt_conv_wchar_sjiswin(int c, mbfl_convert_filter *filter) -{ - if (c == 0xA5) { - CK((*filter->output_function)(0x81, filter->data)); - CK((*filter->output_function)(0x8F, filter->data)); - } else if (c == 0x203E) { - CK((*filter->output_function)(0x81, filter->data)); - CK((*filter->output_function)(0x50, filter->data)); - } else { - return mbfl_filt_conv_wchar_cp932(c, filter); - } - return 0; + MB_CONVERT_BUF_STORE(buf, out, limit); } static size_t mb_cp932_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) @@ -7823,26 +6525,6 @@ static const unsigned char mblen_table_sjis_mobile[] = { /* 0x81-0x9F,0xE0-0xFC static const char *mbfl_encoding_sjis_aliases[] = {"x-sjis", "SHIFT-JIS", NULL}; -static const struct mbfl_convert_vtbl vtbl_sjis_wchar = { - mbfl_no_encoding_sjis, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_sjis_wchar, - mbfl_filt_conv_sjis_wchar_flush, - NULL -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_sjis = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_sjis, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_sjis, - mbfl_filt_conv_common_flush, - NULL -}; - const mbfl_encoding mbfl_encoding_sjis = { mbfl_no_encoding_sjis, "SJIS", @@ -7850,8 +6532,8 @@ const mbfl_encoding mbfl_encoding_sjis = { mbfl_encoding_sjis_aliases, mblen_table_sjis, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_sjis_wchar, - &vtbl_wchar_sjis, + NULL, + NULL, mb_sjis_to_wchar, mb_wchar_to_sjis, NULL, @@ -7860,26 +6542,6 @@ const mbfl_encoding mbfl_encoding_sjis = { static const char *mbfl_encoding_sjis_mac_aliases[] = {"MacJapanese", "x-Mac-Japanese", NULL}; -static const struct mbfl_convert_vtbl vtbl_sjis_mac_wchar = { - mbfl_no_encoding_sjis_mac, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_sjis_mac_wchar, - mbfl_filt_conv_sjis_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_sjis_mac = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_sjis_mac, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_sjis_mac, - mbfl_filt_conv_wchar_sjis_mac_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_sjis_mac = { mbfl_no_encoding_sjis_mac, "SJIS-mac", @@ -7887,8 +6549,8 @@ const mbfl_encoding mbfl_encoding_sjis_mac = { mbfl_encoding_sjis_mac_aliases, mblen_table_sjismac, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_sjis_mac_wchar, - &vtbl_wchar_sjis_mac, + NULL, + NULL, mb_sjismac_to_wchar, mb_wchar_to_sjismac, NULL, @@ -7899,26 +6561,6 @@ static const char *mbfl_encoding_sjis_docomo_aliases[] = {"SJIS-DOCOMO", "shift_ static const char *mbfl_encoding_sjis_kddi_aliases[] = {"SJIS-KDDI", "shift_jis-kddi", "x-sjis-emoji-kddi", NULL}; static const char *mbfl_encoding_sjis_sb_aliases[] = {"SJIS-SOFTBANK", "shift_jis-softbank", "x-sjis-emoji-softbank", NULL}; -static const struct mbfl_convert_vtbl vtbl_sjis_docomo_wchar = { - mbfl_no_encoding_sjis_docomo, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_sjis_mobile_wchar, - mbfl_filt_conv_sjis_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_sjis_docomo = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_sjis_docomo, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_sjis_mobile, - mbfl_filt_conv_sjis_mobile_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_sjis_docomo = { mbfl_no_encoding_sjis_docomo, "SJIS-Mobile#DOCOMO", @@ -7926,31 +6568,11 @@ const mbfl_encoding mbfl_encoding_sjis_docomo = { mbfl_encoding_sjis_docomo_aliases, mblen_table_sjis_mobile, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_sjis_docomo_wchar, - &vtbl_wchar_sjis_docomo, - mb_sjis_docomo_to_wchar, - mb_wchar_to_sjis_docomo, - NULL, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_sjis_kddi_wchar = { - mbfl_no_encoding_sjis_kddi, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, NULL, - mbfl_filt_conv_sjis_mobile_wchar, - mbfl_filt_conv_sjis_wchar_flush, NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_sjis_kddi = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_sjis_kddi, - mbfl_filt_conv_common_ctor, + mb_sjis_docomo_to_wchar, + mb_wchar_to_sjis_docomo, NULL, - mbfl_filt_conv_wchar_sjis_mobile, - mbfl_filt_conv_sjis_mobile_flush, NULL, }; @@ -7961,31 +6583,11 @@ const mbfl_encoding mbfl_encoding_sjis_kddi = { mbfl_encoding_sjis_kddi_aliases, mblen_table_sjis_mobile, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_sjis_kddi_wchar, - &vtbl_wchar_sjis_kddi, - mb_sjis_kddi_to_wchar, - mb_wchar_to_sjis_kddi, - NULL, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_sjis_sb_wchar = { - mbfl_no_encoding_sjis_sb, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, NULL, - mbfl_filt_conv_sjis_mobile_wchar, - mbfl_filt_conv_sjis_wchar_flush, NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_sjis_sb = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_sjis_sb, - mbfl_filt_conv_common_ctor, + mb_sjis_kddi_to_wchar, + mb_wchar_to_sjis_kddi, NULL, - mbfl_filt_conv_wchar_sjis_mobile, - mbfl_filt_conv_sjis_mobile_flush, NULL, }; @@ -7996,8 +6598,8 @@ const mbfl_encoding mbfl_encoding_sjis_sb = { mbfl_encoding_sjis_sb_aliases, mblen_table_sjis_mobile, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_sjis_sb_wchar, - &vtbl_wchar_sjis_sb, + NULL, + NULL, mb_sjis_sb_to_wchar, mb_wchar_to_sjis_sb, NULL, @@ -8013,26 +6615,6 @@ const mbfl_encoding mbfl_encoding_sjis_sb = { static const char *mbfl_encoding_sjis2004_aliases[] = {"SJIS2004","Shift_JIS-2004", NULL}; -static const struct mbfl_convert_vtbl vtbl_sjis2004_wchar = { - mbfl_no_encoding_sjis2004, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_jis2004_wchar, - mbfl_filt_conv_jis2004_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_sjis2004 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_sjis2004, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_jis2004, - mbfl_filt_conv_wchar_jis2004_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_sjis2004 = { mbfl_no_encoding_sjis2004, "SJIS-2004", @@ -8040,8 +6622,8 @@ const mbfl_encoding mbfl_encoding_sjis2004 = { mbfl_encoding_sjis2004_aliases, mblen_table_sjis_mobile, /* Leading byte values used for SJIS-2004 are the same as mobile SJIS variants */ MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_sjis2004_wchar, - &vtbl_wchar_sjis2004, + NULL, + NULL, mb_sjis2004_to_wchar, mb_wchar_to_sjis2004, NULL, @@ -8075,252 +6657,64 @@ const mbfl_encoding mbfl_encoding_sjis2004 = { * our mappings for "CP932". * • When converting Shift-JIS to CP932, the conversion goes through Unicode. * Shift-JIS 0x7E converts to U+203E, so mapping U+203E to 0x7E means that - * 0x7E will go to 0x7E when converting Shift-JIS to CP932. - */ - -static const unsigned char mblen_table_sjiswin[] = { /* 0x81-0x9F,0xE0-0xFF */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 -}; - -static const char *mbfl_encoding_cp932_aliases[] = {"MS932", "Windows-31J", "MS_Kanji", NULL}; -static const char *mbfl_encoding_sjiswin_aliases[] = {"SJIS-ms", "SJIS-open", NULL}; - -static const struct mbfl_convert_vtbl vtbl_cp932_wchar = { - mbfl_no_encoding_cp932, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_cp932_wchar, - mbfl_filt_conv_cp932_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_cp932 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_cp932, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_cp932, - mbfl_filt_conv_common_flush, - NULL, -}; - -const mbfl_encoding mbfl_encoding_cp932 = { - mbfl_no_encoding_cp932, - "CP932", - "Shift_JIS", - mbfl_encoding_cp932_aliases, - mblen_table_sjiswin, - MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_cp932_wchar, - &vtbl_wchar_cp932, - mb_cp932_to_wchar, - mb_wchar_to_cp932, - NULL, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_sjiswin_wchar = { - mbfl_no_encoding_sjiswin, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_cp932_wchar, - mbfl_filt_conv_cp932_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_sjiswin = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_sjiswin, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_sjiswin, - mbfl_filt_conv_common_flush, - NULL, -}; - -const mbfl_encoding mbfl_encoding_sjiswin = { - mbfl_no_encoding_sjiswin, - "SJIS-win", - "Shift_JIS", - mbfl_encoding_sjiswin_aliases, - mblen_table_sjiswin, - MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_sjiswin_wchar, - &vtbl_wchar_sjiswin, - mb_cp932_to_wchar, - mb_wchar_to_sjiswin, - NULL, - NULL, -}; - -/* - * EUC variants - */ - -static int mbfl_filt_conv_eucjp_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, s, w = 0; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (c > 0xa0 && c < 0xff) { /* X 0208 first char */ - filter->status = 1; - filter->cache = c; - } else if (c == 0x8e) { /* kana first char */ - filter->status = 2; - } else if (c == 0x8f) { /* X 0212 first char */ - filter->status = 3; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* got first half */ - filter->status = 0; - c1 = filter->cache; - if (c > 0xa0 && c < 0xff) { - s = (c1 - 0xa1)*94 + c - 0xa1; - if (s >= 0 && s < jisx0208_ucs_table_size) { - w = jisx0208_ucs_table[s]; - if (!w) - w = MBFL_BAD_INPUT; - } else { - w = MBFL_BAD_INPUT; - } - - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 2: /* got 0x8e */ - filter->status = 0; - if (c > 0xa0 && c < 0xe0) { - w = 0xfec0 + c; - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 3: /* got 0x8f, JIS X 0212 first byte */ - filter->status++; - filter->cache = c; - break; - - case 4: /* got 0x8f, JIS X 0212 second byte */ - filter->status = 0; - c1 = filter->cache; - if (c > 0xA0 && c < 0xFF && c1 > 0xA0 && c1 < 0xFF) { - s = (c1 - 0xa1)*94 + c - 0xa1; - if (s >= 0 && s < jisx0212_ucs_table_size) { - w = jisx0212_ucs_table[s]; - if (!w) - w = MBFL_BAD_INPUT; - } else { - w = MBFL_BAD_INPUT; - } - - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_eucjp_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - (*filter->output_function)(MBFL_BAD_INPUT, filter->data); - filter->status = 0; - } + * 0x7E will go to 0x7E when converting Shift-JIS to CP932. + */ - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } +static const unsigned char mblen_table_sjiswin[] = { /* 0x81-0x9F,0xE0-0xFF */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +}; - return 0; -} +static const char *mbfl_encoding_cp932_aliases[] = {"MS932", "Windows-31J", "MS_Kanji", NULL}; +static const char *mbfl_encoding_sjiswin_aliases[] = {"SJIS-ms", "SJIS-open", NULL}; -static int mbfl_filt_conv_wchar_eucjp(int c, mbfl_convert_filter *filter) -{ - int s = 0; +const mbfl_encoding mbfl_encoding_cp932 = { + mbfl_no_encoding_cp932, + "CP932", + "Shift_JIS", + mbfl_encoding_cp932_aliases, + mblen_table_sjiswin, + MBFL_ENCTYPE_GL_UNSAFE, + NULL, + NULL, + mb_cp932_to_wchar, + mb_wchar_to_cp932, + NULL, + NULL, +}; - if (c == 0xAF) { /* U+00AF is MACRON */ - s = 0xA2B4; /* Use JIS X 0212 overline */ - } else if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) { - s = ucs_a1_jis_table[c - ucs_a1_jis_table_min]; - } else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) { - s = ucs_a2_jis_table[c - ucs_a2_jis_table_min]; - } else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) { - s = ucs_i_jis_table[c - ucs_i_jis_table_min]; - } else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) { - s = ucs_r_jis_table[c - ucs_r_jis_table_min]; - } - if (s <= 0) { - if (c == 0xff3c) { /* FULLWIDTH REVERSE SOLIDUS */ - s = 0x2140; - } else if (c == 0x2225) { /* PARALLEL TO */ - s = 0x2142; - } else if (c == 0xff0d) { /* FULLWIDTH HYPHEN-MINUS */ - s = 0x215d; - } else if (c == 0xffe0) { /* FULLWIDTH CENT SIGN */ - s = 0x2171; - } else if (c == 0xffe1) { /* FULLWIDTH POUND SIGN */ - s = 0x2172; - } else if (c == 0xffe2) { /* FULLWIDTH NOT SIGN */ - s = 0x224c; - } else if (c == 0) { - s = 0; - } else { - s = -1; - } - } - if (s >= 0) { - if (s < 0x80) { /* latin */ - CK((*filter->output_function)(s, filter->data)); - } else if (s < 0x100) { /* kana */ - CK((*filter->output_function)(0x8e, filter->data)); - CK((*filter->output_function)(s, filter->data)); - } else if (s < 0x8080) { /* X 0208 */ - CK((*filter->output_function)(((s >> 8) & 0xff) | 0x80, filter->data)); - CK((*filter->output_function)((s & 0xff) | 0x80, filter->data)); - } else { /* X 0212 */ - CK((*filter->output_function)(0x8f, filter->data)); - CK((*filter->output_function)(((s >> 8) & 0xff) | 0x80, filter->data)); - CK((*filter->output_function)((s & 0xff) | 0x80, filter->data)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } +const mbfl_encoding mbfl_encoding_sjiswin = { + mbfl_no_encoding_sjiswin, + "SJIS-win", + "Shift_JIS", + mbfl_encoding_sjiswin_aliases, + mblen_table_sjiswin, + MBFL_ENCTYPE_GL_UNSAFE, + NULL, + NULL, + mb_cp932_to_wchar, + mb_wchar_to_sjiswin, + NULL, + NULL, +}; - return 0; -} +/* + * EUC variants + */ static size_t mb_eucjp_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { @@ -8428,267 +6822,20 @@ static void mb_wchar_to_eucjp(uint32_t *in, size_t len, mb_convert_buf *buf, boo continue; } } - - if (s < 0x80) { - out = mb_convert_buf_add(out, s); - } else if (s < 0x100) { - out = mb_convert_buf_add2(out, 0x8E, s); - } else if (s < 0x8080) { - out = mb_convert_buf_add2(out, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); - } else { - MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 3); - out = mb_convert_buf_add3(out, 0x8F, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); - } - } - - MB_CONVERT_BUF_STORE(buf, out, limit); -} - -static int mbfl_filt_conv_eucjpwin_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, s, w, n; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (c >= 0xa1 && c <= 0xfe) { /* CP932 first char */ - filter->status = 1; - filter->cache = c; - } else if (c == 0x8e) { /* kana first char */ - filter->status = 2; - } else if (c == 0x8f) { /* X 0212 first char */ - filter->status = 3; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* got first half */ - filter->status = 0; - c1 = filter->cache; - if (c > 0xa0 && c < 0xff) { - w = 0; - s = (c1 - 0xa1)*94 + c - 0xa1; - if (s <= 137) { - if (s == 31) { - w = 0xff3c; /* FULLWIDTH REVERSE SOLIDUS */ - } else if (s == 32) { - w = 0xff5e; /* FULLWIDTH TILDE */ - } else if (s == 33) { - w = 0x2225; /* PARALLEL TO */ - } else if (s == 60) { - w = 0xff0d; /* FULLWIDTH HYPHEN-MINUS */ - } else if (s == 80) { - w = 0xffe0; /* FULLWIDTH CENT SIGN */ - } else if (s == 81) { - w = 0xffe1; /* FULLWIDTH POUND SIGN */ - } else if (s == 137) { - w = 0xffe2; /* FULLWIDTH NOT SIGN */ - } - } - - if (w == 0) { - if (s >= cp932ext1_ucs_table_min && s < cp932ext1_ucs_table_max) { /* vendor ext1 (13ku) */ - w = cp932ext1_ucs_table[s - cp932ext1_ucs_table_min]; - } else if (s >= 0 && s < jisx0208_ucs_table_size) { /* X 0208 */ - w = jisx0208_ucs_table[s]; - } else if (s >= (84 * 94)) { /* user (85ku - 94ku) */ - w = s - (84 * 94) + 0xe000; - } - } - - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 2: /* got 0x8e, X0201 kana */ - filter->status = 0; - if (c > 0xa0 && c < 0xe0) { - w = 0xfec0 + c; - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 3: /* got 0x8f, X 0212 first char */ - filter->status++; - filter->cache = c; - break; - - case 4: /* got 0x8f, X 0212 second char */ - filter->status = 0; - c1 = filter->cache; - if (c1 > 0xa0 && c1 < 0xff && c > 0xa0 && c < 0xff) { - s = (c1 - 0xa1)*94 + c - 0xa1; - - if (s >= 0 && s < jisx0212_ucs_table_size) { - w = jisx0212_ucs_table[s]; - - if (w == 0x007e) { - w = 0xff5e; /* FULLWIDTH TILDE */ - } - } else if (s >= (82*94) && s < (84*94)) { /* vender ext3 (83ku - 84ku) <-> CP932 (115ku -120ku) */ - s = (c1 << 8) | c; - w = 0; - n = 0; - while (n < cp932ext3_eucjp_table_size) { - if (s == cp932ext3_eucjp_table[n]) { - if (n < (cp932ext3_ucs_table_max - cp932ext3_ucs_table_min)) { - w = cp932ext3_ucs_table[n]; - } - break; - } - n++; - } - } else if (s >= (84*94)) { /* user (85ku - 94ku) */ - w = s - (84*94) + (0xe000 + (94*10)); - } else { - w = 0; - } - - if (w == 0x00A6) { - w = 0xFFE4; /* FULLWIDTH BROKEN BAR */ - } - - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_eucjpwin_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - (*filter->output_function)(MBFL_BAD_INPUT, filter->data); - filter->status = 0; - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_eucjpwin(int c, mbfl_convert_filter *filter) -{ - int c1, c2, s1 = 0; - - if (c == 0xAF) { /* U+00AF is MACRON */ - s1 = 0xA2B4; /* Use JIS X 0212 overline */ - } else if (c == 0x203E) { - s1 = 0x7E; - } else if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) { - s1 = ucs_a1_jis_table[c - ucs_a1_jis_table_min]; - } else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) { - s1 = ucs_a2_jis_table[c - ucs_a2_jis_table_min]; - } else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) { - s1 = ucs_i_jis_table[c - ucs_i_jis_table_min]; - } else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) { - s1 = ucs_r_jis_table[c - ucs_r_jis_table_min]; - } else if (c >= 0xe000 && c < (0xe000 + 10*94)) { /* user (X0208 85ku - 94ku) */ - s1 = c - 0xe000; - c1 = s1/94 + 0x75; - c2 = s1%94 + 0x21; - s1 = (c1 << 8) | c2; - } else if (c >= (0xe000 + 10*94) && c < (0xe000 + 20*94)) { /* user (X0212 85ku - 94ku) */ - s1 = c - (0xe000 + 10*94); - c1 = s1/94 + 0xf5; - c2 = s1%94 + 0xa1; - s1 = (c1 << 8) | c2; - } - - if (s1 == 0xa2f1) { - s1 = 0x2d62; /* NUMERO SIGN */ - } - - if (s1 <= 0) { - if (c == 0xa5) { /* YEN SIGN */ - s1 = 0x5C; - } else if (c == 0x2014) { - s1 = 0x213D; - } else if (c == 0xff3c) { /* FULLWIDTH REVERSE SOLIDUS */ - s1 = 0x2140; - } else if (c == 0x2225) { /* PARALLEL TO */ - s1 = 0x2142; - } else if (c == 0xff0d) { /* FULLWIDTH HYPHEN-MINUS */ - s1 = 0x215d; - } else if (c == 0xffe0) { /* FULLWIDTH CENT SIGN */ - s1 = 0x2171; - } else if (c == 0xffe1) { /* FULLWIDTH POUND SIGN */ - s1 = 0x2172; - } else if (c == 0xffe2) { /* FULLWIDTH NOT SIGN */ - s1 = 0x224c; - } else { - s1 = -1; - c1 = 0; - c2 = cp932ext1_ucs_table_max - cp932ext1_ucs_table_min; - while (c1 < c2) { /* CP932 vendor ext1 (13ku) */ - const int oh = cp932ext1_ucs_table_min / 94; - - if (c == cp932ext1_ucs_table[c1]) { - s1 = ((c1 / 94 + oh + 0x21) << 8) + (c1 % 94 + 0x21); - break; - } - c1++; - } - if (s1 < 0) { - c1 = 0; - c2 = cp932ext3_ucs_table_max - cp932ext3_ucs_table_min; - while (c1 < c2) { /* CP932 vendor ext3 (115ku - 119ku) */ - if (c == cp932ext3_ucs_table[c1]) { - if (c1 < cp932ext3_eucjp_table_size) { - s1 = cp932ext3_eucjp_table[c1]; - } - break; - } - c1++; - } - } - } - - if (c == 0) { - s1 = 0; - } else if (s1 <= 0) { - s1 = -1; - } - } - - if (s1 >= 0) { - if (s1 < 0x80) { /* latin */ - CK((*filter->output_function)(s1, filter->data)); - } else if (s1 < 0x100) { /* kana */ - CK((*filter->output_function)(0x8e, filter->data)); - CK((*filter->output_function)(s1, filter->data)); - } else if (s1 < 0x8080) { /* X 0208 */ - CK((*filter->output_function)(((s1 >> 8) & 0xff) | 0x80, filter->data)); - CK((*filter->output_function)((s1 & 0xff) | 0x80, filter->data)); - } else { /* X 0212 */ - CK((*filter->output_function)(0x8f, filter->data)); - CK((*filter->output_function)(((s1 >> 8) & 0xff) | 0x80, filter->data)); - CK((*filter->output_function)((s1 & 0xff) | 0x80, filter->data)); + + if (s < 0x80) { + out = mb_convert_buf_add(out, s); + } else if (s < 0x100) { + out = mb_convert_buf_add2(out, 0x8E, s); + } else if (s < 0x8080) { + out = mb_convert_buf_add2(out, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); + } else { + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 3); + out = mb_convert_buf_add3(out, 0x8F, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); } - return 0; + MB_CONVERT_BUF_STORE(buf, out, limit); } static size_t mb_eucjpwin_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) @@ -8884,175 +7031,6 @@ static void mb_wchar_to_eucjpwin(uint32_t *in, size_t len, mb_convert_buf *buf, MB_CONVERT_BUF_STORE(buf, out, limit); } -static int mbfl_filt_conv_cp51932_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, s, w; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (c >= 0xA1 && c <= 0xFE) { /* CP932, first byte */ - filter->status = 1; - filter->cache = c; - } else if (c == 0x8e) { /* kana first char */ - filter->status = 2; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* got first half */ - filter->status = 0; - c1 = filter->cache; - if (c > 0xa0 && c < 0xff) { - w = 0; - s = (c1 - 0xa1)*94 + c - 0xa1; - if (s <= 137) { - if (s == 31) { - w = 0xff3c; /* FULLWIDTH REVERSE SOLIDUS */ - } else if (s == 32) { - w = 0xff5e; /* FULLWIDTH TILDE */ - } else if (s == 33) { - w = 0x2225; /* PARALLEL TO */ - } else if (s == 60) { - w = 0xff0d; /* FULLWIDTH HYPHEN-MINUS */ - } else if (s == 80) { - w = 0xffe0; /* FULLWIDTH CENT SIGN */ - } else if (s == 81) { - w = 0xffe1; /* FULLWIDTH POUND SIGN */ - } else if (s == 137) { - w = 0xffe2; /* FULLWIDTH NOT SIGN */ - } - } - if (w == 0) { - if (s >= cp932ext1_ucs_table_min && s < cp932ext1_ucs_table_max) { /* vendor ext1 (13ku) */ - w = cp932ext1_ucs_table[s - cp932ext1_ucs_table_min]; - } else if (s >= 0 && s < jisx0208_ucs_table_size) { /* X 0208 */ - w = jisx0208_ucs_table[s]; - } else if (s >= cp932ext2_ucs_table_min && s < cp932ext2_ucs_table_max) { /* vendor ext2 (89ku - 92ku) */ - w = cp932ext2_ucs_table[s - cp932ext2_ucs_table_min]; - } - } - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 2: /* got 0x8e, X0201 kana */ - filter->status = 0; - if (c > 0xa0 && c < 0xe0) { - w = 0xfec0 + c; - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_cp51932_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - /* Input string was truncated */ - (*filter->output_function)(MBFL_BAD_INPUT, filter->data); - filter->status = 0; - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_cp51932(int c, mbfl_convert_filter *filter) -{ - int c1, c2, s1; - - s1 = 0; - if (c >= ucs_a1_jis_table_min && c < ucs_a1_jis_table_max) { - s1 = ucs_a1_jis_table[c - ucs_a1_jis_table_min]; - } else if (c >= ucs_a2_jis_table_min && c < ucs_a2_jis_table_max) { - s1 = ucs_a2_jis_table[c - ucs_a2_jis_table_min]; - } else if (c >= ucs_i_jis_table_min && c < ucs_i_jis_table_max) { - s1 = ucs_i_jis_table[c - ucs_i_jis_table_min]; - } else if (c >= ucs_r_jis_table_min && c < ucs_r_jis_table_max) { - s1 = ucs_r_jis_table[c - ucs_r_jis_table_min]; - } - if (s1 >= 0x8080) s1 = -1; /* we don't support JIS X0213 */ - if (s1 <= 0) { - if (c == 0xa5) { /* YEN SIGN */ - s1 = 0x216F; /* FULLWIDTH YEN SIGN */ - } else if (c == 0xff3c) { /* FULLWIDTH REVERSE SOLIDUS */ - s1 = 0x2140; - } else if (c == 0x2225) { /* PARALLEL TO */ - s1 = 0x2142; - } else if (c == 0xff0d) { /* FULLWIDTH HYPHEN-MINUS */ - s1 = 0x215d; - } else if (c == 0xffe0) { /* FULLWIDTH CENT SIGN */ - s1 = 0x2171; - } else if (c == 0xffe1) { /* FULLWIDTH POUND SIGN */ - s1 = 0x2172; - } else if (c == 0xffe2) { /* FULLWIDTH NOT SIGN */ - s1 = 0x224c; - } else { - s1 = -1; - c1 = 0; - c2 = cp932ext1_ucs_table_max - cp932ext1_ucs_table_min; - while (c1 < c2) { /* CP932 vendor ext1 (13ku) */ - if (c == cp932ext1_ucs_table[c1]) { - s1 = ((c1/94 + 0x2d) << 8) + (c1%94 + 0x21); - break; - } - c1++; - } - if (s1 < 0) { - c1 = 0; - c2 = cp932ext2_ucs_table_max - cp932ext2_ucs_table_min; - while (c1 < c2) { /* CP932 vendor ext3 (115ku - 119ku) */ - if (c == cp932ext2_ucs_table[c1]) { - s1 = ((c1/94 + 0x79) << 8) +(c1%94 + 0x21); - break; - } - c1++; - } - } - } - if (c == 0) { - s1 = 0; - } else if (s1 <= 0) { - s1 = -1; - } - } - - if (s1 >= 0) { - if (s1 < 0x80) { /* latin */ - CK((*filter->output_function)(s1, filter->data)); - } else if (s1 < 0x100) { /* kana */ - CK((*filter->output_function)(0x8e, filter->data)); - CK((*filter->output_function)(s1, filter->data)); - } else if (s1 < 0x8080) { /* X 0208 */ - CK((*filter->output_function)(((s1 >> 8) & 0xff) | 0x80, filter->data)); - CK((*filter->output_function)((s1 & 0xff) | 0x80, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - static size_t mb_cp51932_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -9357,188 +7335,60 @@ process_codepoint: ; } } } - - /* Check for Japanese chars in compressed mapping area: U+1E00-U+4DBF */ - if (!s && w >= ucs_c1_jisx0213_min && w <= ucs_c1_jisx0213_max) { - int k = mbfl_bisec_srch(w, ucs_c1_jisx0213_tbl, ucs_c1_jisx0213_tbl_len); - if (k >= 0) { - s = ucs_c1_jisx0213_ofst[k] + w - ucs_c1_jisx0213_tbl[2*k]; - } - } - - /* Check for Japanese chars in CJK Unified Ideographs ext.B (U+2XXXX) */ - if (!s && w >= jisx0213_u5_tbl_min && w <= jisx0213_u5_tbl_max) { - int k = mbfl_bisec_srch2(w - 0x20000, jisx0213_u5_jis_key, jisx0213_u5_tbl_len); - if (k >= 0) { - s = jisx0213_u5_jis_tbl[k]; - } - } - - if (!s) { - /* CJK Compatibility Forms: U+FE30-U+FE4F */ - if (w == 0xFE45) { - s = 0x233E; - } else if (w == 0xFE46) { - s = 0x233D; - } else if (w >= 0xF91D && w <= 0xF9DC) { - /* CJK Compatibility Ideographs: U+F900-U+F92A */ - int k = mbfl_bisec_srch2(w, ucs_r2b_jisx0213_cmap_key, ucs_r2b_jisx0213_cmap_len); - if (k >= 0) { - s = ucs_r2b_jisx0213_cmap_val[k]; - } - } - } - - if (!s && w) { - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_eucjp2004); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len); - } else if (s <= 0x7F) { - out = mb_convert_buf_add(out, s); - } else if (s <= 0xFF) { - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); - out = mb_convert_buf_add2(out, 0x8E, s); - } else if (s <= 0x7EFF) { - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); - out = mb_convert_buf_add2(out, ((s >> 8) & 0xFF) + 0x80, (s & 0xFF) + 0x80); - } else { - unsigned int s2 = s & 0xFF; - int k = ((s >> 8) & 0xFF) - 0x7F; - ZEND_ASSERT(k < jisx0213_p2_ofst_len); - s = jisx0213_p2_ofst[k] + 0x21; - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 3); - out = mb_convert_buf_add3(out, 0x8F, s | 0x80, s2 | 0x80); - } - } - - MB_CONVERT_BUF_STORE(buf, out, limit); -} - -static int mbfl_filt_conv_euccn_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, w; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if ((c >= 0xA1 && c <= 0xA9) || (c >= 0xB0 && c <= 0xF7)) { /* dbcs lead byte */ - filter->status = 1; - filter->cache = c; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* dbcs second byte */ - filter->status = 0; - c1 = filter->cache; - if (c > 0xA0 && c < 0xFF) { - w = (c1 - 0x81)*192 + c - 0x40; - ZEND_ASSERT(w < cp936_ucs_table_size); - if (w == 0x1864) { - w = 0x30FB; - } else if (w == 0x186A) { - w = 0x2015; - } else if ((w >= 0x1921 && w <= 0x192A) || w == 0x1963 || (w >= 0x1C59 && w <= 0x1C7E) || (w >= 0x1DBB && w <= 0x1DC4)) { - w = 0; - } else { - w = cp936_ucs_table[w]; - } - - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_euccn(int c, mbfl_convert_filter *filter) -{ - int s = 0; - - if (c >= ucs_a1_cp936_table_min && c < ucs_a1_cp936_table_max) { - if (c == 0xB7 || c == 0x144 || c == 0x148 || c == 0x251 || c == 0x261) { - s = 0; - } else { - s = ucs_a1_cp936_table[c - ucs_a1_cp936_table_min]; - } - } else if (c >= ucs_a2_cp936_table_min && c < ucs_a2_cp936_table_max) { - if (c == 0x2015) { - s = 0xA1AA; - } else if (c == 0x2014 || (c >= 0x2170 && c <= 0x2179)) { - s = 0; - } else { - s = ucs_a2_cp936_table[c - ucs_a2_cp936_table_min]; - } - } else if (c >= ucs_a3_cp936_table_min && c < ucs_a3_cp936_table_max) { - if (c == 0x30FB) { - s = 0xA1A4; - } else { - s = ucs_a3_cp936_table[c - ucs_a3_cp936_table_min]; - } - } else if (c >= ucs_i_cp936_table_min && c < ucs_i_cp936_table_max) { - s = ucs_i_cp936_table[c - ucs_i_cp936_table_min]; - } else if (c >= ucs_hff_cp936_table_min && c < ucs_hff_cp936_table_max) { - if (c == 0xFF04) { - s = 0xA1E7; - } else if (c == 0xFF5E) { - s = 0xA1AB; - } else if (c >= 0xFF01 && c <= 0xFF5D) { - s = c - 0xFF01 + 0xA3A1; - } else if (c >= 0xFFE0 && c <= 0xFFE5) { - s = ucs_hff_s_cp936_table[c - 0xFFE0]; + + /* Check for Japanese chars in compressed mapping area: U+1E00-U+4DBF */ + if (!s && w >= ucs_c1_jisx0213_min && w <= ucs_c1_jisx0213_max) { + int k = mbfl_bisec_srch(w, ucs_c1_jisx0213_tbl, ucs_c1_jisx0213_tbl_len); + if (k >= 0) { + s = ucs_c1_jisx0213_ofst[k] + w - ucs_c1_jisx0213_tbl[2*k]; + } } - } - /* exclude CP936 extensions */ - if (((s >> 8) & 0xFF) < 0xA1 || (s & 0xFF) < 0xA1) { - s = 0; - } + /* Check for Japanese chars in CJK Unified Ideographs ext.B (U+2XXXX) */ + if (!s && w >= jisx0213_u5_tbl_min && w <= jisx0213_u5_tbl_max) { + int k = mbfl_bisec_srch2(w - 0x20000, jisx0213_u5_jis_key, jisx0213_u5_tbl_len); + if (k >= 0) { + s = jisx0213_u5_jis_tbl[k]; + } + } - if (s <= 0) { - if (c < 0x80) { - s = c; - } else if (s <= 0) { - s = -1; + if (!s) { + /* CJK Compatibility Forms: U+FE30-U+FE4F */ + if (w == 0xFE45) { + s = 0x233E; + } else if (w == 0xFE46) { + s = 0x233D; + } else if (w >= 0xF91D && w <= 0xF9DC) { + /* CJK Compatibility Ideographs: U+F900-U+F92A */ + int k = mbfl_bisec_srch2(w, ucs_r2b_jisx0213_cmap_key, ucs_r2b_jisx0213_cmap_len); + if (k >= 0) { + s = ucs_r2b_jisx0213_cmap_val[k]; + } + } } - } - if (s >= 0) { - if (s < 0x80) { /* latin */ - CK((*filter->output_function)(s, filter->data)); + if (!s && w) { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_eucjp2004); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } else if (s <= 0x7F) { + out = mb_convert_buf_add(out, s); + } else if (s <= 0xFF) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + out = mb_convert_buf_add2(out, 0x8E, s); + } else if (s <= 0x7EFF) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + out = mb_convert_buf_add2(out, ((s >> 8) & 0xFF) + 0x80, (s & 0xFF) + 0x80); } else { - CK((*filter->output_function)((s >> 8) & 0xFF, filter->data)); - CK((*filter->output_function)(s & 0xFF, filter->data)); + unsigned int s2 = s & 0xFF; + int k = ((s >> 8) & 0xFF) - 0x7F; + ZEND_ASSERT(k < jisx0213_p2_ofst_len); + s = jisx0213_p2_ofst[k] + 0x21; + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 3); + out = mb_convert_buf_add3(out, 0x8F, s | 0x80, s2 | 0x80); } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - -static int mbfl_filt_conv_euccn_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status == 1) { - /* 2-byte character was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); } - return 0; + MB_CONVERT_BUF_STORE(buf, out, limit); } static size_t mb_euccn_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) @@ -9645,169 +7495,6 @@ static void mb_wchar_to_euccn(uint32_t *in, size_t len, mb_convert_buf *buf, boo MB_CONVERT_BUF_STORE(buf, out, limit); } -static int mbfl_filt_conv_euctw_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, s, w; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (((c >= 0xA1 && c <= 0xA6) || (c >= 0xC2 && c <= 0xFD)) && c != 0xC3) { /* 2-byte character, first byte */ - filter->status = 1; - filter->cache = c; - } else if (c == 0x8E) { /* 4-byte character, first byte */ - filter->status = 2; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* 2-byte character, second byte */ - filter->status = 0; - c1 = filter->cache; - if (c > 0xA0 && c < 0xFF) { - w = (c1 - 0xA1)*94 + (c - 0xA1); - if (w >= 0 && w < cns11643_1_ucs_table_size) { - w = cns11643_1_ucs_table[w]; - } else { - w = 0; - } - - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - - CK((*filter->output_function)(w, filter->data)); - } else { - filter->status = filter->cache = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 2: /* got 0x8e, second byte */ - if (c == 0xA1 || c == 0xA2 || c == 0xAE) { - filter->status = 3; - filter->cache = c - 0xA1; - } else { - filter->status = filter->cache = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 3: /* got 0x8e, third byte */ - filter->status = 0; - c1 = filter->cache; - if (c >= 0xA1 && ((c1 == 0 && ((c >= 0xA1 && c <= 0xA6) || (c >= 0xC2 && c <= 0xFD)) && c != 0xC3) || - (c1 == 1 && c <= 0xF2) || (c1 == 13 && c <= 0xE7))) { - filter->status = 4; - filter->cache = (c1 << 8) + c - 0xA1; - } else { - filter->status = filter->cache = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 4: /* multi-byte character, fourth byte */ - filter->status = 0; - c1 = filter->cache; - if (c1 <= 0xDFF && c > 0xA0 && c < 0xFF) { - int plane = (c1 & 0xF00) >> 8; /* This is actually the CNS-11643 plane minus one */ - s = (c1 & 0xFF)*94 + c - 0xA1; - w = 0; - if (s >= 0) { - /* A later version of CNS-11643 moved all the characters in "plane 14" to "plane 3", - * and added tens of thousands more characters in planes 4, 5, 6, and 7 - * We only support the older version of CNS-11643 - * This is the same as iconv from glibc 2.2 */ - if (plane == 0 && s < cns11643_1_ucs_table_size) { - w = cns11643_1_ucs_table[s]; - } else if (plane == 1 && s < cns11643_2_ucs_table_size) { - w = cns11643_2_ucs_table[s]; - } else if (plane == 13 && s < cns11643_14_ucs_table_size) { - w = cns11643_14_ucs_table[s]; - } - } - - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - - CK((*filter->output_function)(w, filter->data)); - } else { - filter->status = filter->cache = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_euctw(int c, mbfl_convert_filter *filter) -{ - int s = 0; - - if (c >= ucs_a1_cns11643_table_min && c < ucs_a1_cns11643_table_max) { - s = ucs_a1_cns11643_table[c - ucs_a1_cns11643_table_min]; - } else if (c >= ucs_a2_cns11643_table_min && c < ucs_a2_cns11643_table_max) { - s = ucs_a2_cns11643_table[c - ucs_a2_cns11643_table_min]; - } else if (c >= ucs_a3_cns11643_table_min && c < ucs_a3_cns11643_table_max) { - s = ucs_a3_cns11643_table[c - ucs_a3_cns11643_table_min]; - } else if (c >= ucs_i_cns11643_table_min && c < ucs_i_cns11643_table_max) { - s = ucs_i_cns11643_table[c - ucs_i_cns11643_table_min]; - } else if (c >= ucs_r_cns11643_table_min && c < ucs_r_cns11643_table_max) { - s = ucs_r_cns11643_table[c - ucs_r_cns11643_table_min]; - } - - if (s <= 0) { - if (c == 0) { - s = 0; - } else if (s <= 0) { - s = -1; - } - } - - if (s >= 0) { - int plane = (s & 0x1F0000) >> 16; - if (plane <= 1) { - if (s < 0x80) { /* latin */ - CK((*filter->output_function)(s, filter->data)); - } else { - s = (s & 0xFFFF) | 0x8080; - CK((*filter->output_function)((s >> 8) & 0xFF, filter->data)); - CK((*filter->output_function)(s & 0xFF, filter->data)); - } - } else { - s = (0x8EA00000 + (plane << 16)) | ((s & 0xFFFF) | 0x8080); - CK((*filter->output_function)(0x8e , filter->data)); - CK((*filter->output_function)((s >> 16) & 0xFF, filter->data)); - CK((*filter->output_function)((s >> 8) & 0xFF, filter->data)); - CK((*filter->output_function)(s & 0xFF, filter->data)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - return 0; -} - -static int mbfl_filt_conv_euctw_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - /* 2-byte or 4-byte character was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - static size_t mb_euctw_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -9870,172 +7557,59 @@ static size_t mb_euctw_to_wchar(unsigned char **in, size_t *in_len, uint32_t *bu *out++ = MBFL_BAD_INPUT; } else { *out++ = MBFL_BAD_INPUT; - } - } - - *in_len = e - p; - *in = p; - return out - buf; -} - -static void mb_wchar_to_euctw(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) -{ - unsigned char *out, *limit; - MB_CONVERT_BUF_LOAD(buf, out, limit); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); - - while (len--) { - uint32_t w = *in++; - unsigned int s = 0; - - if (w >= ucs_a1_cns11643_table_min && w < ucs_a1_cns11643_table_max) { - s = ucs_a1_cns11643_table[w - ucs_a1_cns11643_table_min]; - } else if (w >= ucs_a2_cns11643_table_min && w < ucs_a2_cns11643_table_max) { - s = ucs_a2_cns11643_table[w - ucs_a2_cns11643_table_min]; - } else if (w >= ucs_a3_cns11643_table_min && w < ucs_a3_cns11643_table_max) { - s = ucs_a3_cns11643_table[w - ucs_a3_cns11643_table_min]; - } else if (w >= ucs_i_cns11643_table_min && w < ucs_i_cns11643_table_max) { - s = ucs_i_cns11643_table[w - ucs_i_cns11643_table_min]; - } else if (w >= ucs_r_cns11643_table_min && w < ucs_r_cns11643_table_max) { - s = ucs_r_cns11643_table[w - ucs_r_cns11643_table_min]; - } - - if (!s) { - if (w == 0) { - out = mb_convert_buf_add(out, 0); - } else { - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_euctw); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); - } - } else { - unsigned int plane = s >> 16; - if (plane <= 1) { - if (s < 0x80) { - out = mb_convert_buf_add(out, s); - } else { - out = mb_convert_buf_add2(out, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); - } - } else { - MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); - out = mb_convert_buf_add4(out, 0x8E, 0xA0 + plane, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); - } - } - } - - MB_CONVERT_BUF_STORE(buf, out, limit); -} - -static int mbfl_filt_conv_euckr_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, w, flag; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (((c >= 0xA1 && c <= 0xAC) || (c >= 0xB0 && c <= 0xFD)) && c != 0xC9) { /* dbcs lead byte */ - filter->status = 1; - filter->cache = c; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* dbcs second byte */ - filter->status = 0; - c1 = filter->cache; - flag = 0; - if (c1 >= 0xa1 && c1 <= 0xc6) { - flag = 1; - } else if (c1 >= 0xc7 && c1 <= 0xfe && c1 != 0xc9) { - flag = 2; - } - if (flag > 0 && c >= 0xa1 && c <= 0xfe) { - if (flag == 1) { /* 1st: 0xa1..0xc6, 2nd: 0x41..0x7a, 0x81..0xfe */ - w = (c1 - 0x81)*190 + c - 0x41; - ZEND_ASSERT(w < uhc1_ucs_table_size); - w = uhc1_ucs_table[w]; - } else { /* 1st: 0xc7..0xc8,0xca..0xfe, 2nd: 0xa1..0xfe */ - w = (c1 - 0xc7)*94 + c - 0xa1; - ZEND_ASSERT(w < uhc3_ucs_table_size); - w = uhc3_ucs_table[w]; - } - - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); + } } - return 0; + *in_len = e - p; + *in = p; + return out - buf; } -static int mbfl_filt_conv_wchar_euckr(int c, mbfl_convert_filter *filter) +static void mb_wchar_to_euctw(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) { - int s = 0; - - if (c >= ucs_a1_uhc_table_min && c < ucs_a1_uhc_table_max) { - s = ucs_a1_uhc_table[c - ucs_a1_uhc_table_min]; - } else if (c >= ucs_a2_uhc_table_min && c < ucs_a2_uhc_table_max) { - s = ucs_a2_uhc_table[c - ucs_a2_uhc_table_min]; - } else if (c >= ucs_a3_uhc_table_min && c < ucs_a3_uhc_table_max) { - s = ucs_a3_uhc_table[c - ucs_a3_uhc_table_min]; - } else if (c >= ucs_i_uhc_table_min && c < ucs_i_uhc_table_max) { - s = ucs_i_uhc_table[c - ucs_i_uhc_table_min]; - } else if (c >= ucs_s_uhc_table_min && c < ucs_s_uhc_table_max) { - s = ucs_s_uhc_table[c - ucs_s_uhc_table_min]; - } else if (c >= ucs_r1_uhc_table_min && c < ucs_r1_uhc_table_max) { - s = ucs_r1_uhc_table[c - ucs_r1_uhc_table_min]; - } else if (c >= ucs_r2_uhc_table_min && c < ucs_r2_uhc_table_max) { - s = ucs_r2_uhc_table[c - ucs_r2_uhc_table_min]; - } + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); - /* exclude UHC extension area (although we are using the UHC conversion tables) */ - if (((s >> 8) & 0xFF) < 0xA1 || (s & 0xFF) < 0xA1) { - s = 0; - } + while (len--) { + uint32_t w = *in++; + unsigned int s = 0; - if (s <= 0) { - if (c < 0x80) { - s = c; - } else { - s = -1; + if (w >= ucs_a1_cns11643_table_min && w < ucs_a1_cns11643_table_max) { + s = ucs_a1_cns11643_table[w - ucs_a1_cns11643_table_min]; + } else if (w >= ucs_a2_cns11643_table_min && w < ucs_a2_cns11643_table_max) { + s = ucs_a2_cns11643_table[w - ucs_a2_cns11643_table_min]; + } else if (w >= ucs_a3_cns11643_table_min && w < ucs_a3_cns11643_table_max) { + s = ucs_a3_cns11643_table[w - ucs_a3_cns11643_table_min]; + } else if (w >= ucs_i_cns11643_table_min && w < ucs_i_cns11643_table_max) { + s = ucs_i_cns11643_table[w - ucs_i_cns11643_table_min]; + } else if (w >= ucs_r_cns11643_table_min && w < ucs_r_cns11643_table_max) { + s = ucs_r_cns11643_table[w - ucs_r_cns11643_table_min]; } - } - if (s >= 0) { - if (s < 0x80) { /* latin */ - CK((*filter->output_function)(s, filter->data)); + if (!s) { + if (w == 0) { + out = mb_convert_buf_add(out, 0); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_euctw); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + } } else { - CK((*filter->output_function)((s >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(s & 0xff, filter->data)); + unsigned int plane = s >> 16; + if (plane <= 1) { + if (s < 0x80) { + out = mb_convert_buf_add(out, s); + } else { + out = mb_convert_buf_add2(out, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); + } + } else { + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); + out = mb_convert_buf_add4(out, 0x8E, 0xA0 + plane, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); + } } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - -static int mbfl_filt_conv_euckr_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status == 1) { - /* 2-byte character was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); } - return 0; + MB_CONVERT_BUF_STORE(buf, out, limit); } static size_t mb_euckr_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) @@ -10129,101 +7703,6 @@ static void mb_wchar_to_euckr(uint32_t *in, size_t len, mb_convert_buf *buf, boo MB_CONVERT_BUF_STORE(buf, out, limit); } -static int mbfl_filt_conv_uhc_wchar(int c, mbfl_convert_filter *filter) -{ - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (c > 0x80 && c < 0xfe && c != 0xc9) { /* dbcs lead byte */ - filter->status = 1; - filter->cache = c; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* dbcs second byte */ - filter->status = 0; - int c1 = filter->cache, w = 0; - - if (c1 >= 0x81 && c1 <= 0xc6 && c >= 0x41 && c <= 0xfe) { - w = (c1 - 0x81)*190 + (c - 0x41); - if (w >= 0 && w < uhc1_ucs_table_size) { - w = uhc1_ucs_table[w]; - } - } else if (c1 >= 0xc7 && c1 < 0xfe && c >= 0xa1 && c <= 0xfe) { - w = (c1 - 0xc7)*94 + (c - 0xa1); - if (w >= 0 && w < uhc3_ucs_table_size) { - w = uhc3_ucs_table[w]; - } - } - - if (w == 0) { - w = MBFL_BAD_INPUT; - } - CK((*filter->output_function)(w, filter->data)); - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_uhc_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status == 1) { - /* 2-byte character was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_uhc(int c, mbfl_convert_filter *filter) -{ - int s = 0; - - if (c >= ucs_a1_uhc_table_min && c < ucs_a1_uhc_table_max) { - s = ucs_a1_uhc_table[c - ucs_a1_uhc_table_min]; - } else if (c >= ucs_a2_uhc_table_min && c < ucs_a2_uhc_table_max) { - s = ucs_a2_uhc_table[c - ucs_a2_uhc_table_min]; - } else if (c >= ucs_a3_uhc_table_min && c < ucs_a3_uhc_table_max) { - s = ucs_a3_uhc_table[c - ucs_a3_uhc_table_min]; - } else if (c >= ucs_i_uhc_table_min && c < ucs_i_uhc_table_max) { - s = ucs_i_uhc_table[c - ucs_i_uhc_table_min]; - } else if (c >= ucs_s_uhc_table_min && c < ucs_s_uhc_table_max) { - s = ucs_s_uhc_table[c - ucs_s_uhc_table_min]; - } else if (c >= ucs_r1_uhc_table_min && c < ucs_r1_uhc_table_max) { - s = ucs_r1_uhc_table[c - ucs_r1_uhc_table_min]; - } else if (c >= ucs_r2_uhc_table_min && c < ucs_r2_uhc_table_max) { - s = ucs_r2_uhc_table[c - ucs_r2_uhc_table_min]; - } - - if (s == 0 && c != 0) { - s = -1; - } - - if (s >= 0) { - if (s < 0x80) { /* latin */ - CK((*filter->output_function)(s, filter->data)); - } else { - CK((*filter->output_function)((s >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(s & 0xff, filter->data)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - static size_t mb_uhc_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -10345,26 +7824,6 @@ static const unsigned char mblen_table_eucjp[] = { /* 0xA1-0xFE */ static const char *mbfl_encoding_euc_jp_aliases[] = {"EUC", "EUC_JP", "eucJP", "x-euc-jp", NULL}; -static const struct mbfl_convert_vtbl vtbl_eucjp_wchar = { - mbfl_no_encoding_euc_jp, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_eucjp_wchar, - mbfl_filt_conv_eucjp_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_eucjp = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_euc_jp, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_eucjp, - mbfl_filt_conv_common_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_euc_jp = { mbfl_no_encoding_euc_jp, "EUC-JP", @@ -10372,8 +7831,8 @@ const mbfl_encoding mbfl_encoding_euc_jp = { mbfl_encoding_euc_jp_aliases, mblen_table_eucjp, 0, - &vtbl_eucjp_wchar, - &vtbl_wchar_eucjp, + NULL, + NULL, mb_eucjp_to_wchar, mb_wchar_to_eucjp, NULL, @@ -10382,26 +7841,6 @@ const mbfl_encoding mbfl_encoding_euc_jp = { static const char *mbfl_encoding_eucjp2004_aliases[] = {"EUC_JP-2004", NULL}; -static const struct mbfl_convert_vtbl vtbl_eucjp2004_wchar = { - mbfl_no_encoding_eucjp2004, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_jis2004_wchar, - mbfl_filt_conv_jis2004_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_eucjp2004 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_eucjp2004, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_jis2004, - mbfl_filt_conv_wchar_jis2004_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_eucjp2004 = { mbfl_no_encoding_eucjp2004, "EUC-JP-2004", @@ -10409,8 +7848,8 @@ const mbfl_encoding mbfl_encoding_eucjp2004 = { mbfl_encoding_eucjp2004_aliases, mblen_table_eucjp, 0, - &vtbl_eucjp2004_wchar, - &vtbl_wchar_eucjp2004, + NULL, + NULL, mb_eucjp2004_to_wchar, mb_wchar_to_eucjp2004, NULL, @@ -10419,26 +7858,6 @@ const mbfl_encoding mbfl_encoding_eucjp2004 = { static const char *mbfl_encoding_eucjp_win_aliases[] = {"eucJP-open", "eucJP-ms", NULL}; -static const struct mbfl_convert_vtbl vtbl_eucjpwin_wchar = { - mbfl_no_encoding_eucjp_win, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_eucjpwin_wchar, - mbfl_filt_conv_eucjpwin_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_eucjpwin = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_eucjp_win, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_eucjpwin, - mbfl_filt_conv_common_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_eucjp_win = { mbfl_no_encoding_eucjp_win, "eucJP-win", @@ -10446,8 +7865,8 @@ const mbfl_encoding mbfl_encoding_eucjp_win = { mbfl_encoding_eucjp_win_aliases, mblen_table_eucjp, 0, - &vtbl_eucjpwin_wchar, - &vtbl_wchar_eucjpwin, + NULL, + NULL, mb_eucjpwin_to_wchar, mb_wchar_to_eucjpwin, NULL, @@ -10456,26 +7875,6 @@ const mbfl_encoding mbfl_encoding_eucjp_win = { static const char *mbfl_encoding_cp51932_aliases[] = {"cp51932", NULL}; -static const struct mbfl_convert_vtbl vtbl_cp51932_wchar = { - mbfl_no_encoding_cp51932, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_cp51932_wchar, - mbfl_filt_conv_cp51932_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_cp51932 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_cp51932, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_cp51932, - mbfl_filt_conv_common_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_cp51932 = { mbfl_no_encoding_cp51932, "CP51932", @@ -10483,8 +7882,8 @@ const mbfl_encoding mbfl_encoding_cp51932 = { mbfl_encoding_cp51932_aliases, mblen_table_eucjp, 0, - &vtbl_cp51932_wchar, - &vtbl_wchar_cp51932, + NULL, + NULL, mb_cp51932_to_wchar, mb_wchar_to_cp51932, NULL, @@ -10512,26 +7911,6 @@ static const unsigned char mblen_table_euccn[] = { /* 0xA1-0xFE */ static const char *mbfl_encoding_euc_cn_aliases[] = {"CN-GB", "EUC_CN", "eucCN", "x-euc-cn", "gb2312", NULL}; -static const struct mbfl_convert_vtbl vtbl_euccn_wchar = { - mbfl_no_encoding_euc_cn, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_euccn_wchar, - mbfl_filt_conv_euccn_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_euccn = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_euc_cn, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_euccn, - mbfl_filt_conv_common_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_euc_cn = { mbfl_no_encoding_euc_cn, "EUC-CN", @@ -10539,35 +7918,15 @@ const mbfl_encoding mbfl_encoding_euc_cn = { mbfl_encoding_euc_cn_aliases, mblen_table_euccn, 0, - &vtbl_euccn_wchar, - &vtbl_wchar_euccn, - mb_euccn_to_wchar, - mb_wchar_to_euccn, NULL, NULL, -}; - -static const char *mbfl_encoding_euc_tw_aliases[] = {"EUC_TW", "eucTW", "x-euc-tw", NULL}; - -static const struct mbfl_convert_vtbl vtbl_euctw_wchar = { - mbfl_no_encoding_euc_tw, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, + mb_euccn_to_wchar, + mb_wchar_to_euccn, NULL, - mbfl_filt_conv_euctw_wchar, - mbfl_filt_conv_euctw_wchar_flush, NULL, }; -static const struct mbfl_convert_vtbl vtbl_wchar_euctw = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_euc_tw, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_euctw, - mbfl_filt_conv_common_flush, - NULL, -}; +static const char *mbfl_encoding_euc_tw_aliases[] = {"EUC_TW", "eucTW", "x-euc-tw", NULL}; const mbfl_encoding mbfl_encoding_euc_tw = { mbfl_no_encoding_euc_tw, @@ -10576,8 +7935,8 @@ const mbfl_encoding mbfl_encoding_euc_tw = { mbfl_encoding_euc_tw_aliases, mblen_table_euccn, 0, - &vtbl_euctw_wchar, - &vtbl_wchar_euctw, + NULL, + NULL, mb_euctw_to_wchar, mb_wchar_to_euctw, NULL, @@ -10586,26 +7945,6 @@ const mbfl_encoding mbfl_encoding_euc_tw = { static const char *mbfl_encoding_euc_kr_aliases[] = {"EUC_KR", "eucKR", "x-euc-kr", NULL}; -static const struct mbfl_convert_vtbl vtbl_euckr_wchar = { - mbfl_no_encoding_euc_kr, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_euckr_wchar, - mbfl_filt_conv_euckr_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_euckr = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_euc_kr, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_euckr, - mbfl_filt_conv_common_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_euc_kr = { mbfl_no_encoding_euc_kr, "EUC-KR", @@ -10613,8 +7952,8 @@ const mbfl_encoding mbfl_encoding_euc_kr = { mbfl_encoding_euc_kr_aliases, mblen_table_euccn, 0, - &vtbl_euckr_wchar, - &vtbl_wchar_euckr, + NULL, + NULL, mb_euckr_to_wchar, mb_wchar_to_euckr, NULL, @@ -10646,26 +7985,6 @@ static const unsigned char mblen_table_81_to_fe[] = { /* 0x81-0xFE */ static const char *mbfl_encoding_uhc_aliases[] = {"CP949", NULL}; -static const struct mbfl_convert_vtbl vtbl_uhc_wchar = { - mbfl_no_encoding_uhc, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_uhc_wchar, - mbfl_filt_conv_uhc_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_uhc = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_uhc, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_uhc, - mbfl_filt_conv_common_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_uhc = { mbfl_no_encoding_uhc, "UHC", @@ -10673,8 +7992,8 @@ const mbfl_encoding mbfl_encoding_uhc = { mbfl_encoding_uhc_aliases, mblen_table_81_to_fe, 0, - &vtbl_uhc_wchar, - &vtbl_wchar_uhc, + NULL, + NULL, mb_uhc_to_wchar, mb_wchar_to_uhc, NULL, @@ -10685,284 +8004,6 @@ const mbfl_encoding mbfl_encoding_uhc = { * GB18030/CP936 */ -static int mbfl_filt_conv_gb18030_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, c2, c3, w = -1; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (c > 0x80 && c < 0xff) { /* dbcs/qbcs lead byte */ - filter->status = 1; - filter->cache = c; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* dbcs/qbcs second byte */ - c1 = filter->cache; - filter->status = 0; - - if (c1 >= 0x81 && c1 <= 0x84 && c >= 0x30 && c <= 0x39) { - /* 4 byte range: Unicode BMP */ - filter->status = 2; - filter->cache = (c1 << 8) | c; - return 0; - } else if (c1 >= 0x90 && c1 <= 0xe3 && c >= 0x30 && c <= 0x39) { - /* 4 byte range: Unicode 16 planes */ - filter->status = 2; - filter->cache = (c1 << 8) | c; - return 0; - } else if (((c1 >= 0xaa && c1 <= 0xaf) || (c1 >= 0xf8 && c1 <= 0xfe)) && (c >= 0xa1 && c <= 0xfe)) { - /* UDA part 1,2: U+E000-U+E4C5 */ - w = 94*(c1 >= 0xf8 ? c1 - 0xf2 : c1 - 0xaa) + (c - 0xa1) + 0xe000; - CK((*filter->output_function)(w, filter->data)); - } else if (c1 >= 0xa1 && c1 <= 0xa7 && c >= 0x40 && c < 0xa1 && c != 0x7f) { - /* UDA part3 : U+E4C6-U+E765*/ - w = 96*(c1 - 0xa1) + c - (c >= 0x80 ? 0x41 : 0x40) + 0xe4c6; - CK((*filter->output_function)(w, filter->data)); - } - - c2 = (c1 << 8) | c; - - if (w <= 0 && ( - (c2 >= 0xa2ab && c2 <= 0xa9f0 + (0xe80f-0xe801)) || - (c2 >= 0xd7fa && c2 <= 0xd7fa + (0xe814-0xe810)) || - (c2 >= 0xfe50 && c2 <= 0xfe80 + (0xe864-0xe844)) - )) { - for (size_t offset = 0; offset < mbfl_gb18030_pua_tbl_max; offset++) { - if (c2 >= mbfl_gb18030_pua_tbl[offset][2] && c2 <= mbfl_gb18030_pua_tbl[offset][2] + mbfl_gb18030_pua_tbl[offset][1] - mbfl_gb18030_pua_tbl[offset][0]) { - w = c2 - mbfl_gb18030_pua_tbl[offset][2] + mbfl_gb18030_pua_tbl[offset][0]; - CK((*filter->output_function)(w, filter->data)); - break; - } - } - } - - if (w <= 0) { - if ((c1 >= 0xa1 && c1 <= 0xa9 && c >= 0xa1 && c <= 0xfe) || - (c1 >= 0xb0 && c1 <= 0xf7 && c >= 0xa1 && c <= 0xfe) || - (c1 >= 0x81 && c1 <= 0xa0 && c >= 0x40 && c <= 0xfe && c != 0x7f) || - (c1 >= 0xaa && c1 <= 0xfe && c >= 0x40 && c <= 0xa0 && c != 0x7f) || - (c1 >= 0xa8 && c1 <= 0xa9 && c >= 0x40 && c <= 0xa0 && c != 0x7f)) { - w = (c1 - 0x81)*192 + c - 0x40; - ZEND_ASSERT(w < cp936_ucs_table_size); - CK((*filter->output_function)(cp936_ucs_table[w], filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - } - break; - - case 2: /* qbcs third byte */ - c1 = (filter->cache >> 8) & 0xff; - c2 = filter->cache & 0xff; - filter->status = filter->cache = 0; - if (((c1 >= 0x81 && c1 <= 0x84) || (c1 >= 0x90 && c1 <= 0xe3)) && c2 >= 0x30 && c2 <= 0x39 && c >= 0x81 && c <= 0xfe) { - filter->cache = (c1 << 16) | (c2 << 8) | c; - filter->status = 3; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 3: /* qbcs fourth byte */ - c1 = (filter->cache >> 16) & 0xff; - c2 = (filter->cache >> 8) & 0xff; - c3 = filter->cache & 0xff; - filter->status = filter->cache = 0; - if (((c1 >= 0x81 && c1 <= 0x84) || (c1 >= 0x90 && c1 <= 0xe3)) && c2 >= 0x30 && c2 <= 0x39 && c3 >= 0x81 && c3 <= 0xfe && c >= 0x30 && c <= 0x39) { - if (c1 >= 0x90 && c1 <= 0xe3) { - w = ((((c1 - 0x90)*10 + (c2 - 0x30))*126 + (c3 - 0x81)))*10 + (c - 0x30) + 0x10000; - if (w > 0x10FFFF) { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - return 0; - } - } else { /* Unicode BMP */ - w = (((c1 - 0x81)*10 + (c2 - 0x30))*126 + (c3 - 0x81))*10 + (c - 0x30); - if (w >= 0 && w <= 39419) { - int k = mbfl_bisec_srch(w, mbfl_gb2uni_tbl, mbfl_gb_uni_max); - w += mbfl_gb_uni_ofst[k]; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - return 0; - } - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_gb18030_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - /* multi-byte character was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_gb18030(int c, mbfl_convert_filter *filter) -{ - int k, k1, k2; - int c1, s = 0, s1 = 0; - - if (c >= ucs_a1_cp936_table_min && c < ucs_a1_cp936_table_max) { - if (c == 0x01f9) { - s = 0xa8bf; - } else { - s = ucs_a1_cp936_table[c - ucs_a1_cp936_table_min]; - } - } else if (c >= ucs_a2_cp936_table_min && c < ucs_a2_cp936_table_max) { - if (c == 0x20ac) { /* euro-sign */ - s = 0xa2e3; - } else { - s = ucs_a2_cp936_table[c - ucs_a2_cp936_table_min]; - } - } else if (c >= ucs_a3_cp936_table_min && c < ucs_a3_cp936_table_max) { - s = ucs_a3_cp936_table[c - ucs_a3_cp936_table_min]; - } else if (c >= ucs_i_cp936_table_min && c < ucs_i_cp936_table_max) { - s = ucs_i_cp936_table[c - ucs_i_cp936_table_min]; - } else if (c >= ucs_ci_cp936_table_min && c < ucs_ci_cp936_table_max) { - /* U+F900-FA2F CJK Compatibility Ideographs */ - if (c == 0xf92c) { - s = 0xfd9c; - } else if (c == 0xf979) { - s = 0xfd9d; - } else if (c == 0xf995) { - s = 0xfd9e; - } else if (c == 0xf9e7) { - s = 0xfd9f; - } else if (c == 0xf9f1) { - s = 0xfda0; - } else if (c >= 0xfa0c && c <= 0xfa29) { - s = ucs_ci_s_cp936_table[c - 0xfa0c]; - } - } else if (c >= ucs_cf_cp936_table_min && c < ucs_cf_cp936_table_max) { - /* FE30h CJK Compatibility Forms */ - s = ucs_cf_cp936_table[c - ucs_cf_cp936_table_min]; - } else if (c >= ucs_sfv_cp936_table_min && c < ucs_sfv_cp936_table_max) { - /* U+FE50-FE6F Small Form Variants */ - s = ucs_sfv_cp936_table[c - ucs_sfv_cp936_table_min]; - } else if (c >= ucs_hff_cp936_table_min && c < ucs_hff_cp936_table_max) { - /* U+FF00-FFFF HW/FW Forms */ - if (c == 0xff04) { - s = 0xa1e7; - } else if (c == 0xff5e) { - s = 0xa1ab; - } else if (c >= 0xff01 && c <= 0xff5d) { - s = c - 0xff01 + 0xa3a1; - } else if (c >= 0xffe0 && c <= 0xffe5) { - s = ucs_hff_s_cp936_table[c-0xffe0]; - } - } - - /* While GB18030 and CP936 are very similar, some mappings are different between these encodings; - * do a binary search in a table of differing codepoints to see if we have one */ - if (s <= 0 && c >= mbfl_gb18030_c_tbl_key[0] && c <= mbfl_gb18030_c_tbl_key[mbfl_gb18030_c_tbl_max-1]) { - k1 = mbfl_bisec_srch2(c, mbfl_gb18030_c_tbl_key, mbfl_gb18030_c_tbl_max); - if (k1 >= 0) { - s = mbfl_gb18030_c_tbl_val[k1]; - } - } - - if (c >= 0xe000 && c <= 0xe864) { /* PUA */ - if (c < 0xe766) { - if (c < 0xe4c6) { - c1 = c - 0xe000; - s = (c1 % 94) + 0xa1; - c1 /= 94; - s |= (c1 < 0x06 ? c1 + 0xaa : c1 + 0xf2) << 8; - } else { - c1 = c - 0xe4c6; - s = ((c1 / 96) + 0xa1) << 8; - c1 %= 96; - s |= c1 + (c1 >= 0x3f ? 0x41 : 0x40); - } - } else { - /* U+E766..U+E864 */ - k1 = 0; - k2 = mbfl_gb18030_pua_tbl_max; - while (k1 < k2) { - k = (k1 + k2) >> 1; - if (c < mbfl_gb18030_pua_tbl[k][0]) { - k2 = k; - } else if (c > mbfl_gb18030_pua_tbl[k][1]) { - k1 = k + 1; - } else { - s = c - mbfl_gb18030_pua_tbl[k][0] + mbfl_gb18030_pua_tbl[k][2]; - break; - } - } - } - } - - /* If we have not yet found a suitable mapping for this codepoint, it requires a 4-byte code */ - if (s <= 0 && c >= 0x0080 && c <= 0xffff) { - /* BMP */ - s = mbfl_bisec_srch(c, mbfl_uni2gb_tbl, mbfl_gb_uni_max); - if (s >= 0) { - c1 = c - mbfl_gb_uni_ofst[s]; - s = (c1 % 10) + 0x30; - c1 /= 10; - s |= ((c1 % 126) + 0x81) << 8; - c1 /= 126; - s |= ((c1 % 10) + 0x30) << 16; - c1 /= 10; - s1 = c1 + 0x81; - } - } else if (c >= 0x10000 && c <= 0x10ffff) { - /* Code set 3: Unicode U+10000..U+10FFFF */ - c1 = c - 0x10000; - s = (c1 % 10) + 0x30; - c1 /= 10; - s |= ((c1 % 126) + 0x81) << 8; - c1 /= 126; - s |= ((c1 % 10) + 0x30) << 16; - c1 /= 10; - s1 = c1 + 0x90; - } - - if (c == 0) { - s = 0; - } else if (s == 0) { - s = -1; - } - - if (s >= 0) { - if (s <= 0x80) { /* latin */ - CK((*filter->output_function)(s, filter->data)); - } else if (s1 > 0) { /* qbcs */ - CK((*filter->output_function)(s1 & 0xff, filter->data)); - CK((*filter->output_function)((s >> 16) & 0xff, filter->data)); - CK((*filter->output_function)((s >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(s & 0xff, filter->data)); - } else { /* dbcs */ - CK((*filter->output_function)((s >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(s & 0xff, filter->data)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - static const unsigned short gb18030_pua_tbl3[] = { /* 0xFE50 */ 0x0000,0xE816,0xE817,0xE818,0x0000,0x0000,0x0000,0x0000, @@ -11184,216 +8225,37 @@ static void mb_wchar_to_gb18030(uint32_t *in, size_t len, mb_convert_buf *buf, b c1 /= 10; s |= ((c1 % 126) + 0x81) << 8; c1 /= 126; - s |= ((c1 % 10) + 0x30) << 16; - c1 /= 10; - s |= (c1 + 0x81) << 24; - } - } else if (w >= 0x10000 && w <= 0x10FFFF) { - /* Code set 3: Unicode U+10000-U+10FFFF */ - unsigned int c1 = w - 0x10000; - s = (c1 % 10) + 0x30; - c1 /= 10; - s |= ((c1 % 126) + 0x81) << 8; - c1 /= 126; - s |= ((c1 % 10) + 0x30) << 16; - c1 /= 10; - s |= (c1 + 0x90) << 24; - } - - if (!s) { - MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_gb18030); - MB_CONVERT_BUF_ENSURE(buf, out, limit, len); - } else if (s < 0x80) { - out = mb_convert_buf_add(out, s); - } else if (s > 0xFFFFFF) { - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 4); - out = mb_convert_buf_add4(out, (s >> 24) & 0xFF, (s >> 16) & 0xFF, (s >> 8) & 0xFF, s & 0xFF); - } else { - MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); - out = mb_convert_buf_add2(out, (s >> 8) & 0xFF, s & 0xFF); - } - } - - MB_CONVERT_BUF_STORE(buf, out, limit); -} - -static int mbfl_filt_conv_cp936_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, c2, w = -1; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (c == 0x80) { /* euro sign */ - CK((*filter->output_function)(0x20ac, filter->data)); - } else if (c < 0xff) { /* dbcs lead byte */ - filter->status = 1; - filter->cache = c; - } else { /* 0xff */ - CK((*filter->output_function)(0xf8f5, filter->data)); - } - break; - - case 1: /* dbcs second byte */ - filter->status = 0; - c1 = filter->cache; - - if (((c1 >= 0xaa && c1 <= 0xaf) || (c1 >= 0xf8 && c1 <= 0xfe)) && - (c >= 0xa1 && c <= 0xfe)) { - /* UDA part1,2: U+E000-U+E4C5 */ - w = 94*(c1 >= 0xf8 ? c1 - 0xf2 : c1 - 0xaa) + (c - 0xa1) + 0xe000; - CK((*filter->output_function)(w, filter->data)); - } else if (c1 >= 0xa1 && c1 <= 0xa7 && c >= 0x40 && c < 0xa1 && c != 0x7f) { - /* UDA part3 : U+E4C6-U+E765*/ - w = 96*(c1 - 0xa1) + c - (c >= 0x80 ? 0x41 : 0x40) + 0xe4c6; - CK((*filter->output_function)(w, filter->data)); - } - - c2 = (c1 << 8) | c; - - if (w <= 0 && ( - (c2 >= 0xa2ab && c2 <= 0xa9f0 + (0xe80f-0xe801)) || - (c2 >= 0xd7fa && c2 <= 0xd7fa + (0xe814-0xe810)) || - (c2 >= 0xfe50 && c2 <= 0xfe80 + (0xe864-0xe844)) - )) { - size_t k; - for (k = 0; k < mbfl_cp936_pua_tbl_max; k++) { - if (c2 >= mbfl_cp936_pua_tbl[k][2] && - c2 <= mbfl_cp936_pua_tbl[k][2] + - mbfl_cp936_pua_tbl[k][1] - mbfl_cp936_pua_tbl[k][0]) { - w = c2 - mbfl_cp936_pua_tbl[k][2] + mbfl_cp936_pua_tbl[k][0]; - CK((*filter->output_function)(w, filter->data)); - break; - } - } - } - - if (w <= 0) { - if (c1 < 0xff && c1 > 0x80 && c >= 0x40 && c < 0xff && c != 0x7f) { - w = (c1 - 0x81)*192 + c - 0x40; - ZEND_ASSERT(w < cp936_ucs_table_size); - CK((*filter->output_function)(cp936_ucs_table[w], filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_cp936_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - /* 2-byte character was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_cp936(int c, mbfl_convert_filter *filter) -{ - int k, k1, k2; - int c1, s = 0; - - if (c >= ucs_a1_cp936_table_min && c < ucs_a1_cp936_table_max) { - /* U+0000 - U+0451 */ - s = ucs_a1_cp936_table[c - ucs_a1_cp936_table_min]; - } else if (c >= ucs_a2_cp936_table_min && c < ucs_a2_cp936_table_max) { - /* U+2000 - U+26FF */ - if (c == 0x203e) { - s = 0xa3fe; - } else if (c == 0x2218) { - s = 0xa1e3; - } else if (c == 0x223c) { - s = 0xa1ab; - } else { - s = ucs_a2_cp936_table[c - ucs_a2_cp936_table_min]; - } - } else if (c >= ucs_a3_cp936_table_min && c < ucs_a3_cp936_table_max) { - /* U+2F00 - U+33FF */ - s = ucs_a3_cp936_table[c - ucs_a3_cp936_table_min]; - } else if (c >= ucs_i_cp936_table_min && c < ucs_i_cp936_table_max) { - /* U+4D00-9FFF CJK Unified Ideographs (+ Extension A) */ - s = ucs_i_cp936_table[c - ucs_i_cp936_table_min]; - } else if (c >= 0xe000 && c <= 0xe864) { /* PUA */ - if (c < 0xe766) { - if (c < 0xe4c6) { - c1 = c - 0xe000; - s = (c1 % 94) + 0xa1; c1 /= 94; - s |= (c1 < 0x06 ? c1 + 0xaa : c1 + 0xf2) << 8; - } else { - c1 = c - 0xe4c6; - s = ((c1 / 96) + 0xa1) << 8; c1 %= 96; - s |= c1 + (c1 >= 0x3f ? 0x41 : 0x40); - } - } else { - /* U+E766..U+E864 */ - k1 = 0; k2 = mbfl_cp936_pua_tbl_max; - while (k1 < k2) { - k = (k1 + k2) >> 1; - if (c < mbfl_cp936_pua_tbl[k][0]) { - k2 = k; - } else if (c > mbfl_cp936_pua_tbl[k][1]) { - k1 = k + 1; - } else { - s = c - mbfl_cp936_pua_tbl[k][0] + mbfl_cp936_pua_tbl[k][2]; - break; - } + s |= ((c1 % 10) + 0x30) << 16; + c1 /= 10; + s |= (c1 + 0x81) << 24; } + } else if (w >= 0x10000 && w <= 0x10FFFF) { + /* Code set 3: Unicode U+10000-U+10FFFF */ + unsigned int c1 = w - 0x10000; + s = (c1 % 10) + 0x30; + c1 /= 10; + s |= ((c1 % 126) + 0x81) << 8; + c1 /= 126; + s |= ((c1 % 10) + 0x30) << 16; + c1 /= 10; + s |= (c1 + 0x90) << 24; } - } else if (c == 0xf8f5) { - s = 0xff; - } else if (c >= ucs_ci_cp936_table_min && c < ucs_ci_cp936_table_max) { - /* U+F900-FA2F CJK Compatibility Ideographs */ - s = ucs_ci_cp936_table[c - ucs_ci_cp936_table_min]; - } else if (c >= ucs_cf_cp936_table_min && c < ucs_cf_cp936_table_max) { - s = ucs_cf_cp936_table[c - ucs_cf_cp936_table_min]; - } else if (c >= ucs_sfv_cp936_table_min && c < ucs_sfv_cp936_table_max) { - s = ucs_sfv_cp936_table[c - ucs_sfv_cp936_table_min]; /* U+FE50-FE6F Small Form Variants */ - } else if (c >= ucs_hff_cp936_table_min && c < ucs_hff_cp936_table_max) { - /* U+FF00-FFFF HW/FW Forms */ - if (c == 0xff04) { - s = 0xa1e7; - } else if (c == 0xff5e) { - s = 0xa1ab; - } else if (c >= 0xff01 && c <= 0xff5d) { - s = c - 0xff01 + 0xa3a1; - } else if (c >= 0xffe0 && c <= 0xffe5) { - s = ucs_hff_s_cp936_table[c-0xffe0]; - } - } - - if (s <= 0) { - if (c == 0) { - s = 0; - } else if (s <= 0) { - s = -1; - } - } - if (s >= 0) { - if (s <= 0x80 || s == 0xff) { /* latin */ - CK((*filter->output_function)(s, filter->data)); + if (!s) { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_gb18030); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } else if (s < 0x80) { + out = mb_convert_buf_add(out, s); + } else if (s > 0xFFFFFF) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 4); + out = mb_convert_buf_add4(out, (s >> 24) & 0xFF, (s >> 16) & 0xFF, (s >> 8) & 0xFF, s & 0xFF); } else { - CK((*filter->output_function)((s >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(s & 0xff, filter->data)); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + out = mb_convert_buf_add2(out, (s >> 8) & 0xFF, s & 0xFF); } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); } - return 0; + MB_CONVERT_BUF_STORE(buf, out, limit); } static size_t mb_cp936_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) @@ -11915,26 +8777,6 @@ static zend_string* mb_cut_gb18030(unsigned char *str, size_t from, size_t len, static const char *mbfl_encoding_gb18030_aliases[] = {"gb-18030", "gb-18030-2000", NULL}; -static const struct mbfl_convert_vtbl vtbl_gb18030_wchar = { - mbfl_no_encoding_gb18030, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_gb18030_wchar, - mbfl_filt_conv_gb18030_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_gb18030 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_gb18030, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_gb18030, - mbfl_filt_conv_common_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_gb18030 = { mbfl_no_encoding_gb18030, "GB18030", @@ -11942,8 +8784,8 @@ const mbfl_encoding mbfl_encoding_gb18030 = { mbfl_encoding_gb18030_aliases, NULL, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_gb18030_wchar, - &vtbl_wchar_gb18030, + NULL, + NULL, mb_gb18030_to_wchar, mb_wchar_to_gb18030, NULL, @@ -11952,26 +8794,6 @@ const mbfl_encoding mbfl_encoding_gb18030 = { static const char *mbfl_encoding_cp936_aliases[] = {"CP-936", "GBK", NULL}; -static const struct mbfl_convert_vtbl vtbl_cp936_wchar = { - mbfl_no_encoding_cp936, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_cp936_wchar, - mbfl_filt_conv_cp936_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_cp936 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_cp936, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_cp936, - mbfl_filt_conv_common_flush, - NULL, -}; - const mbfl_encoding mbfl_encoding_cp936 = { mbfl_no_encoding_cp936, "CP936", @@ -11979,8 +8801,8 @@ const mbfl_encoding mbfl_encoding_cp936 = { mbfl_encoding_cp936_aliases, mblen_table_81_to_fe, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_cp936_wchar, - &vtbl_wchar_cp936, + NULL, + NULL, mb_cp936_to_wchar, mb_wchar_to_cp936, NULL, @@ -12025,247 +8847,6 @@ static inline int is_in_cp950_pua(int c1, int c) return 0; } -static int mbfl_filt_conv_big5_wchar(int c, mbfl_convert_filter *filter) -{ - int c1, w; - - switch (filter->status) { - case 0: - if (c >= 0 && c < 0x80) { /* latin */ - CK((*filter->output_function)(c, filter->data)); - } else if (filter->from->no_encoding != mbfl_no_encoding_cp950 && c > 0xA0 && c <= 0xF9 && c != 0xC8) { - filter->status = 1; - filter->cache = c; - } else if (filter->from->no_encoding == mbfl_no_encoding_cp950 && c > 0x80 && c <= 0xFE) { - filter->status = 1; - filter->cache = c; - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - case 1: /* dbcs second byte */ - filter->status = 0; - c1 = filter->cache; - if ((c > 0x3f && c < 0x7f) || (c > 0xa0 && c < 0xff)) { - if (c < 0x7f) { - w = (c1 - 0xa1)*157 + (c - 0x40); - } else { - w = (c1 - 0xa1)*157 + (c - 0xa1) + 0x3f; - } - if (w >= 0 && w < big5_ucs_table_size) { - w = big5_ucs_table[w]; - } else { - w = 0; - } - - if (filter->from->no_encoding == mbfl_no_encoding_cp950) { - /* PUA for CP950 */ - if (is_in_cp950_pua(c1, c)) { - int c2 = (c1 << 8) | c; - - size_t k; - for (k = 0; k < sizeof(cp950_pua_tbl) / (sizeof(unsigned short)*4); k++) { - if (c2 >= cp950_pua_tbl[k][2] && c2 <= cp950_pua_tbl[k][3]) { - break; - } - } - - if ((cp950_pua_tbl[k][2] & 0xff) == 0x40) { - w = 157*(c1 - (cp950_pua_tbl[k][2]>>8)) + c - (c >= 0xa1 ? 0x62 : 0x40) + cp950_pua_tbl[k][0]; - } else { - w = c2 - cp950_pua_tbl[k][2] + cp950_pua_tbl[k][0]; - } - } else if (c1 == 0xA1) { - if (c == 0x45) { - w = 0x2027; - } else if (c == 0x4E) { - w = 0xFE51; - } else if (c == 0x5A) { - w = 0x2574; - } else if (c == 0xC2) { - w = 0x00AF; - } else if (c == 0xC3) { - w = 0xFFE3; - } else if (c == 0xC5) { - w = 0x02CD; - } else if (c == 0xE3) { - w = 0xFF5E; - } else if (c == 0xF2) { - w = 0x2295; - } else if (c == 0xF3) { - w = 0x2299; - } else if (c == 0xFE) { - w = 0xFF0F; - } - } else if (c1 == 0xA2) { - if (c == 0x40) { - w = 0xFF3C; - } else if (c == 0x41) { - w = 0x2215; - } else if (c == 0x42) { - w = 0xFE68; - } else if (c == 0x46) { - w = 0xFFE0; - } else if (c == 0x47) { - w = 0xFFE1; - } else if (c == 0xCC) { - w = 0x5341; - } else if (c == 0xCE) { - w = 0x5345; - } - } - } - - if (w <= 0) { - w = MBFL_BAD_INPUT; - } - CK((*filter->output_function)(w, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_big5_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status == 1) { - /* 2-byte character was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_big5(int c, mbfl_convert_filter *filter) -{ - int s = 0; - - if (c >= ucs_a1_big5_table_min && c < ucs_a1_big5_table_max) { - s = ucs_a1_big5_table[c - ucs_a1_big5_table_min]; - } else if (c >= ucs_a2_big5_table_min && c < ucs_a2_big5_table_max) { - s = ucs_a2_big5_table[c - ucs_a2_big5_table_min]; - } else if (c >= ucs_a3_big5_table_min && c < ucs_a3_big5_table_max) { - s = ucs_a3_big5_table[c - ucs_a3_big5_table_min]; - } else if (c >= ucs_i_big5_table_min && c < ucs_i_big5_table_max) { - s = ucs_i_big5_table[c - ucs_i_big5_table_min]; - } else if (c >= ucs_r1_big5_table_min && c < ucs_r1_big5_table_max) { - s = ucs_r1_big5_table[c - ucs_r1_big5_table_min]; - } else if (c >= ucs_r2_big5_table_min && c < ucs_r2_big5_table_max) { - s = ucs_r2_big5_table[c - ucs_r2_big5_table_min]; - } - - if (filter->to->no_encoding == mbfl_no_encoding_cp950) { - if (c >= 0xe000 && c <= 0xf848) { /* PUA for CP950 */ - size_t k; - for (k = 0; k < sizeof(cp950_pua_tbl) / (sizeof(unsigned short)*4); k++) { - if (c <= cp950_pua_tbl[k][1]) { - break; - } - } - - int c1 = c - cp950_pua_tbl[k][0]; - if ((cp950_pua_tbl[k][2] & 0xff) == 0x40) { - int c2 = cp950_pua_tbl[k][2] >> 8; - s = ((c1 / 157) + c2) << 8; - c1 %= 157; - s |= c1 + (c1 >= 0x3f ? 0x62 : 0x40); - } else { - s = c1 + cp950_pua_tbl[k][2]; - } - } else if (c == 0x00A2) { - s = 0; - } else if (c == 0x00A3) { - s = 0; - } else if (c == 0x00AF) { - s = 0xA1C2; - } else if (c == 0x02CD) { - s = 0xA1C5; - } else if (c == 0x0401) { - s = 0; - } else if (c >= 0x0414 && c <= 0x041C) { - s = 0; - } else if (c >= 0x0423 && c <= 0x044F) { - s = 0; - } else if (c == 0x0451) { - s = 0; - } else if (c == 0x2022) { - s = 0; - } else if (c == 0x2027) { - s = 0xA145; - } else if (c == 0x203E) { - s = 0; - } else if (c == 0x2215) { - s = 0xA241; - } else if (c == 0x223C) { - s = 0; - } else if (c == 0x2295) { - s = 0xA1F2; - } else if (c == 0x2299) { - s = 0xA1F3; - } else if (c >= 0x2460 && c <= 0x247D) { - s = 0; - } else if (c == 0x2574) { - s = 0xA15A; - } else if (c == 0x2609) { - s = 0; - } else if (c == 0x2641) { - s = 0; - } else if (c == 0x3005 || (c >= 0x302A && c <= 0x30FF)) { - s = 0; - } else if (c == 0xFE51) { - s = 0xA14E; - } else if (c == 0xFE68) { - s = 0xA242; - } else if (c == 0xFF3C) { - s = 0xA240; - } else if (c == 0xFF5E) { - s = 0xA1E3; - } else if (c == 0xFF64) { - s = 0; - } else if (c == 0xFFE0) { - s = 0xA246; - } else if (c == 0xFFE1) { - s = 0xA247; - } else if (c == 0xFFE3) { - s = 0xA1C3; - } else if (c == 0xFF0F) { - s = 0xA1FE; - } - } - - if (s <= 0) { - if (c == 0) { - s = 0; - } else { - s = -1; - } - } - - if (s >= 0) { - if (s <= 0x80) { /* latin */ - CK((*filter->output_function)(s, filter->data)); - } else { - CK((*filter->output_function)((s >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(s & 0xff, filter->data)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - static size_t mb_big5_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -12539,26 +9120,6 @@ static void mb_wchar_to_cp950(uint32_t *in, size_t len, mb_convert_buf *buf, boo static const char *mbfl_encoding_big5_aliases[] = {"CN-BIG5", "BIG-FIVE", "BIGFIVE", NULL}; -static const struct mbfl_convert_vtbl vtbl_big5_wchar = { - mbfl_no_encoding_big5, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_big5_wchar, - mbfl_filt_conv_big5_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_big5 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_big5, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_big5, - mbfl_filt_conv_common_flush, - NULL -}; - const mbfl_encoding mbfl_encoding_big5 = { mbfl_no_encoding_big5, "BIG-5", @@ -12566,31 +9127,11 @@ const mbfl_encoding mbfl_encoding_big5 = { mbfl_encoding_big5_aliases, mblen_table_81_to_fe, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_big5_wchar, - &vtbl_wchar_big5, - mb_big5_to_wchar, - mb_wchar_to_big5, NULL, NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_cp950_wchar = { - mbfl_no_encoding_cp950, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_big5_wchar, - mbfl_filt_conv_big5_wchar_flush, - NULL, -}; - -static const struct mbfl_convert_vtbl vtbl_wchar_cp950 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_cp950, - mbfl_filt_conv_common_ctor, + mb_big5_to_wchar, + mb_wchar_to_big5, NULL, - mbfl_filt_conv_wchar_big5, - mbfl_filt_conv_common_flush, NULL, }; @@ -12601,8 +9142,8 @@ const mbfl_encoding mbfl_encoding_cp950 = { NULL, mblen_table_81_to_fe, MBFL_ENCTYPE_GL_UNSAFE, - &vtbl_cp950_wchar, - &vtbl_wchar_cp950, + NULL, + NULL, mb_cp950_to_wchar, mb_wchar_to_cp950, NULL, diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cjk.h b/ext/mbstring/libmbfl/filters/mbfilter_cjk.h index bb0e672bef44d..f7e2184986c1f 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cjk.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_cjk.h @@ -42,8 +42,4 @@ int mbfilter_sjis_emoji_docomo2unicode(int s, int *snd); int mbfilter_sjis_emoji_kddi2unicode(int s, int *snd); int mbfilter_sjis_emoji_sb2unicode(int s, int *snd); -int mbfilter_unicode2sjis_emoji_docomo(int c, int *s1, mbfl_convert_filter *filter); -int mbfilter_unicode2sjis_emoji_kddi_sjis(int c, int *s1, mbfl_convert_filter *filter); -int mbfilter_unicode2sjis_emoji_sb(int c, int *s1, mbfl_convert_filter *filter); - #endif /* MBFL_MBFILTER_CJK_H */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp51932.h b/ext/mbstring/libmbfl/filters/mbfilter_cp51932.h index f48ec7cb3d4c0..6729edb272d61 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp51932.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp51932.h @@ -33,10 +33,5 @@ #include "mbfilter.h" extern const mbfl_encoding mbfl_encoding_cp51932; -extern const struct mbfl_convert_vtbl vtbl_cp51932_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_cp51932; - -int mbfl_filt_conv_cp51932_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_cp51932(int c, mbfl_convert_filter *filter); #endif /* MBFL_MBFILTER_CP51932_H */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c b/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c index 7ced00fa536e1..ebb44cc3154fc 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c @@ -21,61 +21,10 @@ static inline uint32_t coalesce(uint32_t a, uint32_t b) return a ? a : b; } -/* Helper for single-byte encodings which use a conversion table */ -static int mbfl_conv_singlebyte_table(int c, mbfl_convert_filter *filter, int tbl_min, const unsigned short tbl[]) -{ - if (c >= 0 && c < tbl_min) { - CK((*filter->output_function)(c, filter->data)); - } else if (c < 0) { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } else { - CK((*filter->output_function)(coalesce(tbl[c - tbl_min], MBFL_BAD_INPUT), filter->data)); - } - return 0; -} - -static int mbfl_conv_reverselookup_table(int c, mbfl_convert_filter *filter, int tbl_min, const unsigned short tbl[]) -{ - if (c >= 0 && c < tbl_min) { - CK((*filter->output_function)(c, filter->data)); - } else if (c < 0 || c == MBFL_BAD_INPUT) { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } else { - for (int i = 0; i < 256 - tbl_min; i++) { - if (c == tbl[i]) { - CK((*filter->output_function)(i + tbl_min, filter->data)); - return 0; - } - } - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - return 0; -} - /* Initialize data structures for a single-byte encoding */ #define DEF_SB(id, name, mime_name, aliases) \ - static int mbfl_filt_conv_##id##_wchar(int c, mbfl_convert_filter *filter); \ - static int mbfl_filt_conv_wchar_##id(int c, mbfl_convert_filter *filter); \ static size_t mb_##id##_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); \ static void mb_wchar_to_##id(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); \ - static const struct mbfl_convert_vtbl vtbl_##id##_wchar = { \ - mbfl_no_encoding_##id, \ - mbfl_no_encoding_wchar, \ - mbfl_filt_conv_common_ctor, \ - NULL, \ - mbfl_filt_conv_##id##_wchar, \ - mbfl_filt_conv_common_flush, \ - NULL \ - }; \ - static const struct mbfl_convert_vtbl vtbl_wchar_##id = { \ - mbfl_no_encoding_wchar, \ - mbfl_no_encoding_##id, \ - mbfl_filt_conv_common_ctor, \ - NULL, \ - mbfl_filt_conv_wchar_##id, \ - mbfl_filt_conv_common_flush, \ - NULL \ - }; \ const mbfl_encoding mbfl_encoding_##id = { \ mbfl_no_encoding_##id, \ name, \ @@ -83,8 +32,8 @@ static int mbfl_conv_reverselookup_table(int c, mbfl_convert_filter *filter, int aliases, \ NULL, \ MBFL_ENCTYPE_SBCS, \ - &vtbl_##id##_wchar, \ - &vtbl_wchar_##id, \ + NULL, \ + NULL, \ mb_##id##_to_wchar, \ mb_wchar_to_##id, \ NULL, \ @@ -93,12 +42,6 @@ static int mbfl_conv_reverselookup_table(int c, mbfl_convert_filter *filter, int /* For single-byte encodings which use a conversion table */ #define DEF_SB_TBL(id, name, mime_name, aliases, tbl_min, tbl) \ - static int mbfl_filt_conv_##id##_wchar(int c, mbfl_convert_filter *filter) { \ - return mbfl_conv_singlebyte_table(c, filter, tbl_min, tbl); \ - } \ - static int mbfl_filt_conv_wchar_##id(int c, mbfl_convert_filter *filter) { \ - return mbfl_conv_reverselookup_table(c, filter, tbl_min, tbl); \ - } \ static size_t mb_##id##_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) \ { \ unsigned char *p = *in, *e = p + *in_len; \ @@ -140,22 +83,6 @@ static int mbfl_conv_reverselookup_table(int c, mbfl_convert_filter *filter, int static const char *ascii_aliases[] = {"ANSI_X3.4-1968", "iso-ir-6", "ANSI_X3.4-1986", "ISO_646.irv:1991", "US-ASCII", "ISO646-US", "us", "IBM367", "IBM-367", "cp367", "csASCII", NULL}; DEF_SB(ascii, "ASCII", "US-ASCII", ascii_aliases); -static int mbfl_filt_conv_ascii_wchar(int c, mbfl_convert_filter *filter) -{ - CK((*filter->output_function)((c < 0x80) ? c : MBFL_BAD_INPUT, filter->data)); - return 0; -} - -static int mbfl_filt_conv_wchar_ascii(int c, mbfl_convert_filter *filter) -{ - if (c >= 0 && c < 0x80 && c != MBFL_BAD_INPUT) { - CK((*filter->output_function)(c, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - return 0; -} - static size_t mb_ascii_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -195,21 +122,6 @@ static void mb_wchar_to_ascii(uint32_t *in, size_t len, mb_convert_buf *buf, boo static const char *iso8859_1_aliases[] = {"ISO8859-1", "latin1", NULL}; DEF_SB(8859_1, "ISO-8859-1", "ISO-8859-1", iso8859_1_aliases); -static int mbfl_filt_conv_8859_1_wchar(int c, mbfl_convert_filter *filter) -{ - return (*filter->output_function)(c, filter->data); -} - -static int mbfl_filt_conv_wchar_8859_1(int c, mbfl_convert_filter *filter) -{ - if (c >= 0 && c < 0x100 && c != MBFL_BAD_INPUT) { - CK((*filter->output_function)(c, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - return 0; -} - static size_t mb_8859_1_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -494,38 +406,6 @@ static const unsigned short cp1252_ucs_table[] = { }; DEF_SB(cp1252, "Windows-1252", "Windows-1252", cp1252_aliases); -static int mbfl_filt_conv_wchar_cp1252(int c, mbfl_convert_filter *filter) -{ - if (c < 0 || c == MBFL_BAD_INPUT) { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } else if (c >= 0x100) { - for (int n = 0; n < 32; n++) { - if (c == cp1252_ucs_table[n]) { - CK((*filter->output_function)(0x80 + n, filter->data)); - return 0; - } - } - CK(mbfl_filt_conv_illegal_output(c, filter)); - } else if (c <= 0x7F || c >= 0xA0 || c == 0x81 || c == 0x8D || c == 0x8F || c == 0x90 || c == 0x9D) { - CK((*filter->output_function)(c, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - return 0; -} - -static int mbfl_filt_conv_cp1252_wchar(int c, mbfl_convert_filter *filter) -{ - int s; - if (c >= 0x80 && c < 0xA0) { - s = coalesce(cp1252_ucs_table[c - 0x80], MBFL_BAD_INPUT); - } else { - s = c; - } - CK((*filter->output_function)(s, filter->data)); - return 0; -} - static size_t mb_cp1252_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -701,32 +581,6 @@ static const unsigned char ucs_armscii8_table[] = { }; DEF_SB(armscii8, "ArmSCII-8", "ArmSCII-8", armscii8_aliases); -static int mbfl_filt_conv_armscii8_wchar(int c, mbfl_convert_filter *filter) -{ - CK((*filter->output_function)((c < 0xA0) ? c : coalesce(armscii8_ucs_table[c - 0xA0], MBFL_BAD_INPUT), filter->data)); - return 0; -} - -static int mbfl_filt_conv_wchar_armscii8(int c, mbfl_convert_filter *filter) -{ - if (c >= 0x28 && c <= 0x2F) { - CK((*filter->output_function)(ucs_armscii8_table[c - 0x28], filter->data)); - } else if (c < 0 || c == MBFL_BAD_INPUT) { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } else if (c < 0xA0) { - CK((*filter->output_function)(c, filter->data)); - } else { - for (int n = 0; n < 0x60; n++) { - if (c == armscii8_ucs_table[n]) { - CK((*filter->output_function)(0xA0 + n, filter->data)); - return 0; - } - } - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - return 0; -} - static size_t mb_armscii8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c b/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c index 01b569482b601..7639412253554 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c @@ -30,7 +30,6 @@ #include "mbfilter.h" #include "mbfilter_ucs2.h" -static int mbfl_filt_conv_ucs2_wchar_flush(mbfl_convert_filter *filter); static size_t mb_ucs2_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static size_t mb_ucs2be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static void mb_wchar_to_ucs2be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); @@ -53,8 +52,8 @@ const mbfl_encoding mbfl_encoding_ucs2 = { mbfl_encoding_ucs2_aliases, NULL, MBFL_ENCTYPE_WCS2, - &vtbl_ucs2_wchar, - &vtbl_wchar_ucs2, + NULL, + NULL, mb_ucs2_to_wchar, mb_wchar_to_ucs2be, NULL, @@ -68,8 +67,8 @@ const mbfl_encoding mbfl_encoding_ucs2be = { mbfl_encoding_ucs2be_aliases, NULL, MBFL_ENCTYPE_WCS2, - &vtbl_ucs2be_wchar, - &vtbl_wchar_ucs2be, + NULL, + NULL, mb_ucs2be_to_wchar, mb_wchar_to_ucs2be, NULL, @@ -83,158 +82,14 @@ const mbfl_encoding mbfl_encoding_ucs2le = { mbfl_encoding_ucs2le_aliases, NULL, MBFL_ENCTYPE_WCS2, - &vtbl_ucs2le_wchar, - &vtbl_wchar_ucs2le, - mb_ucs2le_to_wchar, - mb_wchar_to_ucs2le, NULL, NULL, -}; - -const struct mbfl_convert_vtbl vtbl_ucs2_wchar = { - mbfl_no_encoding_ucs2, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_ucs2_wchar, - mbfl_filt_conv_ucs2_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_ucs2 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_ucs2, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_ucs2be, - mbfl_filt_conv_common_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_ucs2be_wchar = { - mbfl_no_encoding_ucs2be, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_ucs2be_wchar, - mbfl_filt_conv_ucs2_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_ucs2be = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_ucs2be, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_ucs2be, - mbfl_filt_conv_common_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_ucs2le_wchar = { - mbfl_no_encoding_ucs2le, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_ucs2le_wchar, - mbfl_filt_conv_ucs2_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_ucs2le = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_ucs2le, - mbfl_filt_conv_common_ctor, + mb_ucs2le_to_wchar, + mb_wchar_to_ucs2le, NULL, - mbfl_filt_conv_wchar_ucs2le, - mbfl_filt_conv_common_flush, NULL, }; -#define CK(statement) do { if ((statement) < 0) return (-1); } while (0) - -int mbfl_filt_conv_ucs2_wchar(int c, mbfl_convert_filter *filter) -{ - if (filter->status == 0) { - filter->status = 1; - filter->cache = c & 0xFF; - } else { - filter->status = 0; - int n = (filter->cache << 8) | (c & 0xFF); - if (n == 0xFFFE) { - /* Found little-endian byte order mark */ - filter->filter_function = mbfl_filt_conv_ucs2le_wchar; - } else { - filter->filter_function = mbfl_filt_conv_ucs2be_wchar; - if (n != 0xFEFF) { - CK((*filter->output_function)(n, filter->data)); - } - } - } - return 0; -} - -int mbfl_filt_conv_ucs2be_wchar(int c, mbfl_convert_filter *filter) -{ - if (filter->status == 0) { - filter->status = 1; - filter->cache = (c & 0xFF) << 8; - } else { - filter->status = 0; - CK((*filter->output_function)((c & 0xFF) | filter->cache, filter->data)); - } - return 0; -} - -int mbfl_filt_conv_wchar_ucs2be(int c, mbfl_convert_filter *filter) -{ - if (c >= 0 && c < MBFL_WCSPLANE_UCS2MAX) { - CK((*filter->output_function)((c >> 8) & 0xFF, filter->data)); - CK((*filter->output_function)(c & 0xFF, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - return 0; -} - -int mbfl_filt_conv_ucs2le_wchar(int c, mbfl_convert_filter *filter) -{ - if (filter->status == 0) { - filter->status = 1; - filter->cache = c & 0xFF; - } else { - filter->status = 0; - CK((*filter->output_function)(((c & 0xFF) << 8) | filter->cache, filter->data)); - } - return 0; -} - -int mbfl_filt_conv_wchar_ucs2le(int c, mbfl_convert_filter *filter) -{ - if (c >= 0 && c < MBFL_WCSPLANE_UCS2MAX) { - CK((*filter->output_function)(c & 0xFF, filter->data)); - CK((*filter->output_function)((c >> 8) & 0xFF, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - return 0; -} - -static int mbfl_filt_conv_ucs2_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - /* Input string was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - #define DETECTED_BE 1 #define DETECTED_LE 2 diff --git a/ext/mbstring/libmbfl/filters/mbfilter_ucs2.h b/ext/mbstring/libmbfl/filters/mbfilter_ucs2.h index bbf567a49339b..7e2993d8fbb52 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_ucs2.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_ucs2.h @@ -35,17 +35,5 @@ extern const mbfl_encoding mbfl_encoding_ucs2; extern const mbfl_encoding mbfl_encoding_ucs2be; extern const mbfl_encoding mbfl_encoding_ucs2le; -extern const struct mbfl_convert_vtbl vtbl_ucs2_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_ucs2; -extern const struct mbfl_convert_vtbl vtbl_ucs2be_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_ucs2be; -extern const struct mbfl_convert_vtbl vtbl_ucs2le_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_ucs2le; - -int mbfl_filt_conv_ucs2_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_ucs2be_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_ucs2be(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_ucs2le_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_ucs2le(int c, mbfl_convert_filter *filter); #endif /* MBFL_MBFILTER_UCS2_H */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c b/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c index 10b57061f7d9c..1731eb48add76 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c @@ -44,8 +44,6 @@ static const char *mbfl_encoding_ucs4_aliases[] = {"ISO-10646-UCS-4", "UCS4", NU static const char *mbfl_encoding_ucs4be_aliases[] = {"byte4be", NULL}; static const char *mbfl_encoding_ucs4le_aliases[] = {"byte4le", NULL}; -static int mbfl_filt_conv_ucs4_wchar_flush(mbfl_convert_filter *filter); - const mbfl_encoding mbfl_encoding_ucs4 = { mbfl_no_encoding_ucs4, "UCS-4", @@ -53,8 +51,8 @@ const mbfl_encoding mbfl_encoding_ucs4 = { mbfl_encoding_ucs4_aliases, NULL, MBFL_ENCTYPE_WCS4, - &vtbl_ucs4_wchar, - &vtbl_wchar_ucs4, + NULL, + NULL, mb_ucs4_to_wchar, mb_wchar_to_ucs4be, NULL, @@ -68,8 +66,8 @@ const mbfl_encoding mbfl_encoding_ucs4be = { mbfl_encoding_ucs4be_aliases, NULL, MBFL_ENCTYPE_WCS4, - &vtbl_ucs4be_wchar, - &vtbl_wchar_ucs4be, + NULL, + NULL, mb_ucs4be_to_wchar, mb_wchar_to_ucs4be, NULL, @@ -83,239 +81,14 @@ const mbfl_encoding mbfl_encoding_ucs4le = { mbfl_encoding_ucs4le_aliases, NULL, MBFL_ENCTYPE_WCS4, - &vtbl_ucs4le_wchar, - &vtbl_wchar_ucs4le, - mb_ucs4le_to_wchar, - mb_wchar_to_ucs4le, - NULL, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_ucs4_wchar = { - mbfl_no_encoding_ucs4, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_ucs4_wchar, - mbfl_filt_conv_ucs4_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_ucs4 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_ucs4, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_ucs4be, - mbfl_filt_conv_common_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_ucs4be_wchar = { - mbfl_no_encoding_ucs4be, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_ucs4be_wchar, - mbfl_filt_conv_ucs4_wchar_flush, NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_ucs4be = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_ucs4be, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_ucs4be, - mbfl_filt_conv_common_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_ucs4le_wchar = { - mbfl_no_encoding_ucs4le, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_ucs4le_wchar, - mbfl_filt_conv_ucs4_wchar_flush, NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_ucs4le = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_ucs4le, - mbfl_filt_conv_common_ctor, + mb_ucs4le_to_wchar, + mb_wchar_to_ucs4le, NULL, - mbfl_filt_conv_wchar_ucs4le, - mbfl_filt_conv_common_flush, NULL, }; - -#define CK(statement) do { if ((statement) < 0) return (-1); } while (0) - -/* - * UCS-4 => wchar - */ -int mbfl_filt_conv_ucs4_wchar(int c, mbfl_convert_filter *filter) -{ - int n, endian; - - endian = filter->status & 0xff00; - switch (filter->status & 0xff) { - case 0: - if (endian) { - n = c & 0xff; - } else { - n = (c & 0xffu) << 24; - } - filter->cache = n; - filter->status++; - break; - case 1: - if (endian) { - n = (c & 0xff) << 8; - } else { - n = (c & 0xff) << 16; - } - filter->cache |= n; - filter->status++; - break; - case 2: - if (endian) { - n = (c & 0xff) << 16; - } else { - n = (c & 0xff) << 8; - } - filter->cache |= n; - filter->status++; - break; - default: - if (endian) { - n = (c & 0xffu) << 24; - } else { - n = c & 0xff; - } - n |= filter->cache; - filter->status &= ~0xff; - if ((n & 0xffff) == 0 && ((n >> 16) & 0xffff) == 0xfffe) { - if (endian) { - filter->status = 0; /* big-endian */ - } else { - filter->status = 0x100; /* little-endian */ - } - } else if (n != 0xfeff) { - CK((*filter->output_function)(n, filter->data)); - } - break; - } - - return 0; -} - -/* - * UCS-4BE => wchar - */ -int mbfl_filt_conv_ucs4be_wchar(int c, mbfl_convert_filter *filter) -{ - int n; - - if (filter->status == 0) { - filter->status = 1; - n = (c & 0xffu) << 24; - filter->cache = n; - } else if (filter->status == 1) { - filter->status = 2; - n = (c & 0xff) << 16; - filter->cache |= n; - } else if (filter->status == 2) { - filter->status = 3; - n = (c & 0xff) << 8; - filter->cache |= n; - } else { - filter->status = 0; - n = (c & 0xff) | filter->cache; - CK((*filter->output_function)(n, filter->data)); - } - return 0; -} - -/* - * wchar => UCS-4BE - */ -int mbfl_filt_conv_wchar_ucs4be(int c, mbfl_convert_filter *filter) -{ - if (c != MBFL_BAD_INPUT) { - CK((*filter->output_function)((c >> 24) & 0xff, filter->data)); - CK((*filter->output_function)((c >> 16) & 0xff, filter->data)); - CK((*filter->output_function)((c >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(c & 0xff, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - -/* - * UCS-4LE => wchar - */ -int mbfl_filt_conv_ucs4le_wchar(int c, mbfl_convert_filter *filter) -{ - int n; - - if (filter->status == 0) { - filter->status = 1; - n = (c & 0xff); - filter->cache = n; - } else if (filter->status == 1) { - filter->status = 2; - n = (c & 0xff) << 8; - filter->cache |= n; - } else if (filter->status == 2) { - filter->status = 3; - n = (c & 0xff) << 16; - filter->cache |= n; - } else { - filter->status = 0; - n = ((c & 0xffu) << 24) | filter->cache; - CK((*filter->output_function)(n, filter->data)); - } - return 0; -} - -/* - * wchar => UCS-4LE - */ -int mbfl_filt_conv_wchar_ucs4le(int c, mbfl_convert_filter *filter) -{ - if (c != MBFL_BAD_INPUT) { - CK((*filter->output_function)(c & 0xff, filter->data)); - CK((*filter->output_function)((c >> 8) & 0xff, filter->data)); - CK((*filter->output_function)((c >> 16) & 0xff, filter->data)); - CK((*filter->output_function)((c >> 24) & 0xff, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - -static int mbfl_filt_conv_ucs4_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status & 0xF) { - /* Input string was truncated */ - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - filter->status = 0; - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - #define DETECTED_BE 1 #define DETECTED_LE 2 diff --git a/ext/mbstring/libmbfl/filters/mbfilter_ucs4.h b/ext/mbstring/libmbfl/filters/mbfilter_ucs4.h index b5280f1bfb336..8b825784664df 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_ucs4.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_ucs4.h @@ -33,17 +33,5 @@ extern const mbfl_encoding mbfl_encoding_ucs4; extern const mbfl_encoding mbfl_encoding_ucs4le; extern const mbfl_encoding mbfl_encoding_ucs4be; -extern const struct mbfl_convert_vtbl vtbl_ucs4_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_ucs4; -extern const struct mbfl_convert_vtbl vtbl_ucs4be_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_ucs4be; -extern const struct mbfl_convert_vtbl vtbl_ucs4le_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_ucs4le; - -int mbfl_filt_conv_ucs4_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_ucs4be_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_ucs4be(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_ucs4le_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_ucs4le(int c, mbfl_convert_filter *filter); #endif /* MBFL_MBFILTER_UCS4_H */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf16.c b/ext/mbstring/libmbfl/filters/mbfilter_utf16.c index 5f5958ad19b3e..29c4caeb8d94f 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf16.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf16.c @@ -173,7 +173,6 @@ static void mb_wchar_to_utf16le_default(uint32_t *in, size_t len, mb_convert_buf #endif -static int mbfl_filt_conv_utf16_wchar_flush(mbfl_convert_filter *filter); static size_t mb_utf16_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static zend_string* mb_cut_utf16(unsigned char *str, size_t from, size_t len, unsigned char *end); static zend_string* mb_cut_utf16be(unsigned char *str, size_t from, size_t len, unsigned char *end); @@ -188,8 +187,8 @@ const mbfl_encoding mbfl_encoding_utf16 = { mbfl_encoding_utf16_aliases, NULL, 0, - &vtbl_utf16_wchar, - &vtbl_wchar_utf16, + NULL, + NULL, mb_utf16_to_wchar, mb_wchar_to_utf16be, NULL, @@ -203,8 +202,8 @@ const mbfl_encoding mbfl_encoding_utf16be = { NULL, NULL, 0, - &vtbl_utf16be_wchar, - &vtbl_wchar_utf16be, + NULL, + NULL, mb_utf16be_to_wchar, mb_wchar_to_utf16be, NULL, @@ -218,270 +217,14 @@ const mbfl_encoding mbfl_encoding_utf16le = { NULL, NULL, 0, - &vtbl_utf16le_wchar, - &vtbl_wchar_utf16le, + NULL, + NULL, mb_utf16le_to_wchar, mb_wchar_to_utf16le, NULL, mb_cut_utf16le }; -const struct mbfl_convert_vtbl vtbl_utf16_wchar = { - mbfl_no_encoding_utf16, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf16_wchar, - mbfl_filt_conv_utf16_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf16 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf16, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf16be, - mbfl_filt_conv_common_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_utf16be_wchar = { - mbfl_no_encoding_utf16be, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf16be_wchar, - mbfl_filt_conv_utf16_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf16be = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf16be, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf16be, - mbfl_filt_conv_common_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_utf16le_wchar = { - mbfl_no_encoding_utf16le, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf16le_wchar, - mbfl_filt_conv_utf16_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf16le = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf16le, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf16le, - mbfl_filt_conv_common_flush, - NULL, -}; - -#define CK(statement) do { if ((statement) < 0) return (-1); } while (0) - -int mbfl_filt_conv_utf16_wchar(int c, mbfl_convert_filter *filter) -{ - /* Start with the assumption that the string is big-endian; - * If we find a little-endian BOM, then we will change that assumption */ - if (filter->status == 0) { - filter->cache = c & 0xFF; - filter->status = 1; - } else { - int n = (filter->cache << 8) | (c & 0xFF); - filter->cache = filter->status = 0; - if (n == 0xFFFE) { - /* Switch to little-endian mode */ - filter->filter_function = mbfl_filt_conv_utf16le_wchar; - } else { - filter->filter_function = mbfl_filt_conv_utf16be_wchar; - if (n >= 0xD800 && n <= 0xDBFF) { - filter->cache = n & 0x3FF; /* Pick out 10 data bits */ - filter->status = 2; - return 0; - } else if (n >= 0xDC00 && n <= 0xDFFF) { - /* This is wrong; second part of surrogate pair has come first */ - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } else if (n != 0xFEFF) { - CK((*filter->output_function)(n, filter->data)); - } - } - } - - return 0; -} - -int mbfl_filt_conv_utf16be_wchar(int c, mbfl_convert_filter *filter) -{ - int n; - - switch (filter->status) { - case 0: /* First byte */ - filter->cache = c & 0xFF; - filter->status = 1; - break; - - case 1: /* Second byte */ - n = (filter->cache << 8) | (c & 0xFF); - if (n >= 0xD800 && n <= 0xDBFF) { - filter->cache = n & 0x3FF; /* Pick out 10 data bits */ - filter->status = 2; - } else if (n >= 0xDC00 && n <= 0xDFFF) { - /* This is wrong; second part of surrogate pair has come first */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } else { - filter->status = 0; - CK((*filter->output_function)(n, filter->data)); - } - break; - - case 2: /* Second part of surrogate, first byte */ - filter->cache = (filter->cache << 8) | (c & 0xFF); - filter->status = 3; - break; - - case 3: /* Second part of surrogate, second byte */ - n = ((filter->cache & 0xFF) << 8) | (c & 0xFF); - if (n >= 0xD800 && n <= 0xDBFF) { - /* Wrong; that's the first half of a surrogate pair, not the second */ - filter->cache = n & 0x3FF; - filter->status = 2; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } else if (n >= 0xDC00 && n <= 0xDFFF) { - filter->status = 0; - n = ((filter->cache & 0x3FF00) << 2) + (n & 0x3FF) + 0x10000; - CK((*filter->output_function)(n, filter->data)); - } else { - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - CK((*filter->output_function)(n, filter->data)); - } - } - - return 0; -} - -int mbfl_filt_conv_wchar_utf16be(int c, mbfl_convert_filter *filter) -{ - int n; - - if (c >= 0 && c < MBFL_WCSPLANE_UCS2MAX) { - CK((*filter->output_function)((c >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(c & 0xff, filter->data)); - } else if (c >= MBFL_WCSPLANE_SUPMIN && c < MBFL_WCSPLANE_SUPMAX) { - n = ((c >> 10) - 0x40) | 0xd800; - CK((*filter->output_function)((n >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(n & 0xff, filter->data)); - n = (c & 0x3ff) | 0xdc00; - CK((*filter->output_function)((n >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(n & 0xff, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - -int mbfl_filt_conv_utf16le_wchar(int c, mbfl_convert_filter *filter) -{ - int n; - - switch (filter->status) { - case 0: - filter->cache = c & 0xff; - filter->status = 1; - break; - - case 1: - if ((c & 0xfc) == 0xd8) { - /* Looks like we have a surrogate pair here */ - filter->cache += ((c & 0x3) << 8); - filter->status = 2; - } else if ((c & 0xfc) == 0xdc) { - /* This is wrong; the second part of the surrogate pair has come first */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } else { - filter->status = 0; - CK((*filter->output_function)(filter->cache + ((c & 0xff) << 8), filter->data)); - } - break; - - case 2: - filter->cache = (filter->cache << 10) + (c & 0xff); - filter->status = 3; - break; - - case 3: - n = (filter->cache & 0xFF) | ((c & 0xFF) << 8); - if (n >= 0xD800 && n <= 0xDBFF) { - /* We previously saw the first part of a surrogate pair and were - * expecting the second part; this is another first part */ - filter->cache = n & 0x3FF; - filter->status = 2; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } else if (n >= 0xDC00 && n <= 0xDFFF) { - n = filter->cache + ((c & 0x3) << 8) + 0x10000; - filter->status = 0; - CK((*filter->output_function)(n, filter->data)); - } else { - /* The first part of a surrogate pair was followed by some other codepoint - * which is not part of a surrogate pair at all */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - CK((*filter->output_function)(n, filter->data)); - } - break; - } - - return 0; -} - -int mbfl_filt_conv_wchar_utf16le(int c, mbfl_convert_filter *filter) -{ - int n; - - if (c >= 0 && c < MBFL_WCSPLANE_UCS2MAX) { - CK((*filter->output_function)(c & 0xff, filter->data)); - CK((*filter->output_function)((c >> 8) & 0xff, filter->data)); - } else if (c >= MBFL_WCSPLANE_SUPMIN && c < MBFL_WCSPLANE_SUPMAX) { - n = ((c >> 10) - 0x40) | 0xd800; - CK((*filter->output_function)(n & 0xff, filter->data)); - CK((*filter->output_function)((n >> 8) & 0xff, filter->data)); - n = (c & 0x3ff) | 0xdc00; - CK((*filter->output_function)(n & 0xff, filter->data)); - CK((*filter->output_function)((n >> 8) & 0xff, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - -static int mbfl_filt_conv_utf16_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - /* Input string was truncated */ - filter->status = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - #define DETECTED_BE 1 #define DETECTED_LE 2 diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf16.h b/ext/mbstring/libmbfl/filters/mbfilter_utf16.h index 291628549debe..227912a495564 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf16.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf16.h @@ -34,19 +34,6 @@ extern const mbfl_encoding mbfl_encoding_utf16; extern const mbfl_encoding mbfl_encoding_utf16be; extern const mbfl_encoding mbfl_encoding_utf16le; -extern const struct mbfl_convert_vtbl vtbl_utf16_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf16; -extern const struct mbfl_convert_vtbl vtbl_utf16be_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf16be; -extern const struct mbfl_convert_vtbl vtbl_utf16le_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf16le; - -int mbfl_filt_conv_utf16_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_utf16be_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_utf16be(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_utf16le_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_utf16le(int c, mbfl_convert_filter *filter); - #ifdef ZEND_INTRIN_AVX2_FUNC_PTR void init_convert_utf16(void); #endif diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf32.c b/ext/mbstring/libmbfl/filters/mbfilter_utf32.c index 81057d8c6e95d..e82d5df5706c1 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf32.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf32.c @@ -30,7 +30,6 @@ #include "mbfilter.h" #include "mbfilter_utf32.h" -static int mbfl_filt_conv_utf32_wchar_flush(mbfl_convert_filter *filter); static size_t mb_utf32_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static size_t mb_utf32be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static void mb_wchar_to_utf32be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); @@ -46,8 +45,8 @@ const mbfl_encoding mbfl_encoding_utf32 = { mbfl_encoding_utf32_aliases, NULL, MBFL_ENCTYPE_WCS4, - &vtbl_utf32_wchar, - &vtbl_wchar_utf32, + NULL, + NULL, mb_utf32_to_wchar, mb_wchar_to_utf32be, NULL, @@ -61,8 +60,8 @@ const mbfl_encoding mbfl_encoding_utf32be = { NULL, NULL, MBFL_ENCTYPE_WCS4, - &vtbl_utf32be_wchar, - &vtbl_wchar_utf32be, + NULL, + NULL, mb_utf32be_to_wchar, mb_wchar_to_utf32be, NULL, @@ -76,178 +75,14 @@ const mbfl_encoding mbfl_encoding_utf32le = { NULL, NULL, MBFL_ENCTYPE_WCS4, - &vtbl_utf32le_wchar, - &vtbl_wchar_utf32le, - mb_utf32le_to_wchar, - mb_wchar_to_utf32le, - NULL, NULL, -}; - -const struct mbfl_convert_vtbl vtbl_utf32_wchar = { - mbfl_no_encoding_utf32, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, NULL, - mbfl_filt_conv_utf32_wchar, - mbfl_filt_conv_utf32_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf32 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf32, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf32be, - mbfl_filt_conv_common_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_utf32be_wchar = { - mbfl_no_encoding_utf32be, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf32be_wchar, - mbfl_filt_conv_utf32_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf32be = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf32be, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf32be, - mbfl_filt_conv_common_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_utf32le_wchar = { - mbfl_no_encoding_utf32le, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf32le_wchar, - mbfl_filt_conv_utf32_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf32le = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf32le, - mbfl_filt_conv_common_ctor, + mb_utf32le_to_wchar, + mb_wchar_to_utf32le, NULL, - mbfl_filt_conv_wchar_utf32le, - mbfl_filt_conv_common_flush, NULL, }; -#define CK(statement) do { if ((statement) < 0) return (-1); } while (0) - -static int emit_char_if_valid(int n, mbfl_convert_filter *filter) -{ - if (n >= 0 && n < MBFL_WCSPLANE_UTF32MAX && (n < 0xD800 || n > 0xDFFF)) { - CK((*filter->output_function)(n, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - return 0; -} - -int mbfl_filt_conv_utf32_wchar(int c, mbfl_convert_filter *filter) -{ - if (filter->status < 3) { - filter->cache = (filter->cache << 8) | (c & 0xFF); - filter->status++; - } else { - int n = ((unsigned int)filter->cache << 8) | (c & 0xFF); - filter->cache = filter->status = 0; - - if (n == 0xFFFE0000) { - /* Found a little-endian byte order mark */ - filter->filter_function = mbfl_filt_conv_utf32le_wchar; - } else { - filter->filter_function = mbfl_filt_conv_utf32be_wchar; - if (n != 0xFEFF) { - CK(emit_char_if_valid(n, filter)); - } - } - } - - return 0; -} - -int mbfl_filt_conv_utf32be_wchar(int c, mbfl_convert_filter *filter) -{ - if (filter->status < 3) { - filter->cache = (filter->cache << 8) | (c & 0xFF); - filter->status++; - } else { - int n = ((unsigned int)filter->cache << 8) | (c & 0xFF); - filter->cache = filter->status = 0; - CK(emit_char_if_valid(n, filter)); - } - return 0; -} - -int mbfl_filt_conv_wchar_utf32be(int c, mbfl_convert_filter *filter) -{ - if (c >= 0 && c < MBFL_WCSPLANE_UTF32MAX) { - CK((*filter->output_function)((c >> 24) & 0xff, filter->data)); - CK((*filter->output_function)((c >> 16) & 0xff, filter->data)); - CK((*filter->output_function)((c >> 8) & 0xff, filter->data)); - CK((*filter->output_function)(c & 0xff, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - -int mbfl_filt_conv_utf32le_wchar(int c, mbfl_convert_filter *filter) -{ - if (filter->status < 3) { - filter->cache |= ((c & 0xFFU) << (8 * filter->status)); - filter->status++; - } else { - int n = ((c & 0xFFU) << 24) | filter->cache; - filter->cache = filter->status = 0; - CK(emit_char_if_valid(n, filter)); - } - return 0; -} - -int mbfl_filt_conv_wchar_utf32le(int c, mbfl_convert_filter *filter) -{ - if (c >= 0 && c < MBFL_WCSPLANE_UTF32MAX) { - CK((*filter->output_function)(c & 0xff, filter->data)); - CK((*filter->output_function)((c >> 8) & 0xff, filter->data)); - CK((*filter->output_function)((c >> 16) & 0xff, filter->data)); - CK((*filter->output_function)((c >> 24) & 0xff, filter->data)); - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - -static int mbfl_filt_conv_utf32_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - /* Input string was truncated */ - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } - filter->cache = filter->status = 0; - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - #define DETECTED_BE 1 #define DETECTED_LE 2 diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf32.h b/ext/mbstring/libmbfl/filters/mbfilter_utf32.h index 58c69d72f16d3..5f75851116987 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf32.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf32.h @@ -34,17 +34,4 @@ extern const mbfl_encoding mbfl_encoding_utf32; extern const mbfl_encoding mbfl_encoding_utf32be; extern const mbfl_encoding mbfl_encoding_utf32le; -extern const struct mbfl_convert_vtbl vtbl_utf32_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf32; -extern const struct mbfl_convert_vtbl vtbl_utf32be_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf32be; -extern const struct mbfl_convert_vtbl vtbl_utf32le_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf32le; - -int mbfl_filt_conv_utf32_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_utf32be_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_utf32be(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_utf32le_wchar(int c, mbfl_convert_filter *filter); -int mbfl_filt_conv_wchar_utf32le(int c, mbfl_convert_filter *filter); - #endif /* MBFL_MBFILTER_UTF32_H */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8.c b/ext/mbstring/libmbfl/filters/mbfilter_utf8.c index 41ffb97e58f16..80ac36be6dd47 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8.c @@ -52,14 +52,6 @@ const unsigned char mblen_table_utf8[] = { }; extern int mbfl_bisec_srch2(int w, const unsigned short tbl[], int n); -extern int mbfl_filt_conv_sjis_mobile_flush(mbfl_convert_filter *filter); - -static int mbfl_filt_conv_utf8_mobile_wchar(int c, mbfl_convert_filter *filter); -static int mbfl_filt_conv_wchar_utf8_mobile(int c, mbfl_convert_filter *filter); - -static int mbfl_filt_conv_utf8_wchar(int c, mbfl_convert_filter *filter); -static int mbfl_filt_conv_wchar_utf8(int c, mbfl_convert_filter *filter); -static int mbfl_filt_conv_utf8_wchar_flush(mbfl_convert_filter *filter); static size_t mb_utf8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); static void mb_wchar_to_utf8(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); @@ -143,34 +135,14 @@ const mbfl_encoding mbfl_encoding_utf8 = { mbfl_encoding_utf8_aliases, mblen_table_utf8, 0, - &vtbl_utf8_wchar, - &vtbl_wchar_utf8, + NULL, + NULL, mb_utf8_to_wchar, mb_wchar_to_utf8, NULL, mb_cut_utf8 }; -const struct mbfl_convert_vtbl vtbl_utf8_wchar = { - mbfl_no_encoding_utf8, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf8_wchar, - mbfl_filt_conv_utf8_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf8 = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf8, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf8, - mbfl_filt_conv_common_flush, - NULL, -}; - static const char *mbfl_encoding_utf8_docomo_aliases[] = {"UTF-8-DOCOMO", "UTF8-DOCOMO", NULL}; static const char *mbfl_encoding_utf8_kddi_b_aliases[] = {"UTF-8-Mobile#KDDI", "UTF-8-KDDI", "UTF8-KDDI", NULL}; static const char *mbfl_encoding_utf8_sb_aliases[] = {"UTF-8-SOFTBANK", "UTF8-SOFTBANK", NULL}; @@ -182,8 +154,8 @@ const mbfl_encoding mbfl_encoding_utf8_docomo = { mbfl_encoding_utf8_docomo_aliases, mblen_table_utf8, 0, - &vtbl_utf8_docomo_wchar, - &vtbl_wchar_utf8_docomo, + NULL, + NULL, mb_utf8_docomo_to_wchar, mb_wchar_to_utf8_docomo, NULL, @@ -197,8 +169,8 @@ const mbfl_encoding mbfl_encoding_utf8_kddi_a = { NULL, mblen_table_utf8, 0, - &vtbl_utf8_kddi_a_wchar, - &vtbl_wchar_utf8_kddi_a, + NULL, + NULL, mb_utf8_kddi_a_to_wchar, mb_wchar_to_utf8_kddi_a, NULL, @@ -212,8 +184,8 @@ const mbfl_encoding mbfl_encoding_utf8_kddi_b = { mbfl_encoding_utf8_kddi_b_aliases, mblen_table_utf8, 0, - &vtbl_utf8_kddi_b_wchar, - &vtbl_wchar_utf8_kddi_b, + NULL, + NULL, mb_utf8_kddi_b_to_wchar, mb_wchar_to_utf8_kddi_b, NULL, @@ -227,222 +199,14 @@ const mbfl_encoding mbfl_encoding_utf8_sb = { mbfl_encoding_utf8_sb_aliases, mblen_table_utf8, 0, - &vtbl_utf8_sb_wchar, - &vtbl_wchar_utf8_sb, + NULL, + NULL, mb_utf8_sb_to_wchar, mb_wchar_to_utf8_sb, NULL, mb_cut_utf8, }; -const struct mbfl_convert_vtbl vtbl_utf8_docomo_wchar = { - mbfl_no_encoding_utf8_docomo, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf8_mobile_wchar, - mbfl_filt_conv_utf8_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf8_docomo = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf8_docomo, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf8_mobile, - mbfl_filt_conv_sjis_mobile_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_utf8_kddi_a_wchar = { - mbfl_no_encoding_utf8_kddi_a, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf8_mobile_wchar, - mbfl_filt_conv_utf8_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf8_kddi_a = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf8_kddi_a, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf8_mobile, - mbfl_filt_conv_sjis_mobile_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_utf8_kddi_b_wchar = { - mbfl_no_encoding_utf8_kddi_b, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf8_mobile_wchar, - mbfl_filt_conv_utf8_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf8_kddi_b = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf8_kddi_b, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf8_mobile, - mbfl_filt_conv_sjis_mobile_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_utf8_sb_wchar = { - mbfl_no_encoding_utf8_sb, - mbfl_no_encoding_wchar, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_utf8_mobile_wchar, - mbfl_filt_conv_utf8_wchar_flush, - NULL, -}; - -const struct mbfl_convert_vtbl vtbl_wchar_utf8_sb = { - mbfl_no_encoding_wchar, - mbfl_no_encoding_utf8_sb, - mbfl_filt_conv_common_ctor, - NULL, - mbfl_filt_conv_wchar_utf8_mobile, - mbfl_filt_conv_sjis_mobile_flush, - NULL, -}; - -#define CK(statement) do { if ((statement) < 0) return (-1); } while (0) - -static int mbfl_filt_put_invalid_char(mbfl_convert_filter *filter) -{ - filter->status = filter->cache = 0; - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - return 0; -} - -static int mbfl_filt_conv_utf8_wchar(int c, mbfl_convert_filter *filter) -{ - int s, c1; - -retry: - switch (filter->status) { - case 0x00: - if (c < 0x80) { - CK((*filter->output_function)(c, filter->data)); - } else if (c >= 0xc2 && c <= 0xdf) { /* 2byte code first char: 0xc2-0xdf */ - filter->status = 0x10; - filter->cache = c & 0x1f; - } else if (c >= 0xe0 && c <= 0xef) { /* 3byte code first char: 0xe0-0xef */ - filter->status = 0x20; - filter->cache = c & 0xf; - } else if (c >= 0xf0 && c <= 0xf4) { /* 3byte code first char: 0xf0-0xf4 */ - filter->status = 0x30; - filter->cache = c & 0x7; - } else { - CK(mbfl_filt_put_invalid_char(filter)); - } - break; - case 0x10: /* 2byte code 2nd char: 0x80-0xbf */ - case 0x21: /* 3byte code 3rd char: 0x80-0xbf */ - case 0x32: /* 4byte code 4th char: 0x80-0xbf */ - if (c >= 0x80 && c <= 0xbf) { - s = (filter->cache<<6) | (c & 0x3f); - filter->status = filter->cache = 0; - CK((*filter->output_function)(s, filter->data)); - } else { - CK(mbfl_filt_put_invalid_char(filter)); - goto retry; - } - break; - case 0x20: /* 3byte code 2nd char: 0:0xa0-0xbf,D:0x80-9F,1-C,E-F:0x80-0x9f */ - s = (filter->cache<<6) | (c & 0x3f); - c1 = filter->cache & 0xf; - - if ((c >= 0x80 && c <= 0xbf) && - ((c1 == 0x0 && c >= 0xa0) || - (c1 == 0xd && c < 0xa0) || - (c1 > 0x0 && c1 != 0xd))) { - filter->cache = s; - filter->status++; - } else { - CK(mbfl_filt_put_invalid_char(filter)); - goto retry; - } - break; - case 0x30: /* 4byte code 2nd char: 0:0x90-0xbf,1-3:0x80-0xbf,4:0x80-0x8f */ - s = (filter->cache<<6) | (c & 0x3f); - c1 = filter->cache & 0x7; - - if ((c >= 0x80 && c <= 0xbf) && - ((c1 == 0x0 && c >= 0x90) || - (c1 == 0x4 && c < 0x90) || - (c1 > 0x0 && c1 != 0x4))) { - filter->cache = s; - filter->status++; - } else { - CK(mbfl_filt_put_invalid_char(filter)); - goto retry; - } - break; - case 0x31: /* 4byte code 3rd char: 0x80-0xbf */ - if (c >= 0x80 && c <= 0xbf) { - filter->cache = (filter->cache<<6) | (c & 0x3f); - filter->status++; - } else { - CK(mbfl_filt_put_invalid_char(filter)); - goto retry; - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_utf8_wchar_flush(mbfl_convert_filter *filter) -{ - if (filter->status) { - (*filter->output_function)(MBFL_BAD_INPUT, filter->data); - filter->status = 0; - } - - if (filter->flush_function) { - (*filter->flush_function)(filter->data); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_utf8(int c, mbfl_convert_filter *filter) -{ - if (c >= 0 && c < 0x110000) { - if (c < 0x80) { - CK((*filter->output_function)(c, filter->data)); - } else if (c < 0x800) { - CK((*filter->output_function)(((c >> 6) & 0x1f) | 0xc0, filter->data)); - CK((*filter->output_function)((c & 0x3f) | 0x80, filter->data)); - } else if (c < 0x10000) { - CK((*filter->output_function)(((c >> 12) & 0x0f) | 0xe0, filter->data)); - CK((*filter->output_function)(((c >> 6) & 0x3f) | 0x80, filter->data)); - CK((*filter->output_function)((c & 0x3f) | 0x80, filter->data)); - } else { - CK((*filter->output_function)(((c >> 18) & 0x07) | 0xf0, filter->data)); - CK((*filter->output_function)(((c >> 12) & 0x3f) | 0x80, filter->data)); - CK((*filter->output_function)(((c >> 6) & 0x3f) | 0x80, filter->data)); - CK((*filter->output_function)((c & 0x3f) | 0x80, filter->data)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - static size_t mb_utf8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) { unsigned char *p = *in, *e = p + *in_len; @@ -581,143 +345,6 @@ static zend_string* mb_cut_utf8(unsigned char *str, size_t from, size_t len, uns return zend_string_init_fast((char*)start, _end - start); } -static int mbfl_filt_conv_utf8_mobile_wchar(int c, mbfl_convert_filter *filter) -{ - int s, s1 = 0, c1 = 0, snd = 0; - -retry: - switch (filter->status & 0xff) { - case 0x00: - if (c < 0x80) { - CK((*filter->output_function)(c, filter->data)); - } else if (c >= 0xc2 && c <= 0xdf) { /* 2byte code first char: 0xc2-0xdf */ - filter->status = 0x10; - filter->cache = c & 0x1f; - } else if (c >= 0xe0 && c <= 0xef) { /* 3byte code first char: 0xe0-0xef */ - filter->status = 0x20; - filter->cache = c & 0xf; - } else if (c >= 0xf0 && c <= 0xf4) { /* 3byte code first char: 0xf0-0xf4 */ - filter->status = 0x30; - filter->cache = c & 0x7; - } else { - CK(mbfl_filt_put_invalid_char(filter)); - } - break; - - case 0x10: /* 2byte code 2nd char: 0x80-0xbf */ - case 0x21: /* 3byte code 3rd char: 0x80-0xbf */ - case 0x32: /* 4byte code 4th char: 0x80-0xbf */ - filter->status = 0; - if (c >= 0x80 && c <= 0xbf) { - s = (filter->cache << 6) | (c & 0x3f); - filter->cache = 0; - - if (filter->from->no_encoding == mbfl_no_encoding_utf8_docomo && mbfilter_conv_r_map_tbl(s, &s1, 4, mbfl_docomo2uni_pua)) { - s = mbfilter_sjis_emoji_docomo2unicode(s1, &snd); - } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_kddi_a && mbfilter_conv_r_map_tbl(s, &s1, 7, mbfl_kddi2uni_pua)) { - s = mbfilter_sjis_emoji_kddi2unicode(s1, &snd); - } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_kddi_b && mbfilter_conv_r_map_tbl(s, &s1, 8, mbfl_kddi2uni_pua_b)) { - s = mbfilter_sjis_emoji_kddi2unicode(s1, &snd); - } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_sb && mbfilter_conv_r_map_tbl(s, &s1, 6, mbfl_sb2uni_pua)) { - s = mbfilter_sjis_emoji_sb2unicode(s1, &snd); - } - - if (snd > 0) { - CK((*filter->output_function)(snd, filter->data)); - } - CK((*filter->output_function)(s, filter->data)); - } else { - CK(mbfl_filt_put_invalid_char(filter)); - goto retry; - } - break; - - case 0x20: /* 3byte code 2nd char: 0:0xa0-0xbf,D:0x80-9F,1-C,E-F:0x80-0x9f */ - s = (filter->cache << 6) | (c & 0x3f); - c1 = filter->cache & 0xf; - - if ((c >= 0x80 && c <= 0xbf) && - ((c1 == 0x0 && c >= 0xa0) || - (c1 == 0xd && c < 0xa0) || - (c1 > 0x0 && c1 != 0xd))) { - filter->cache = s; - filter->status++; - } else { - CK(mbfl_filt_put_invalid_char(filter)); - goto retry; - } - break; - - case 0x30: /* 4byte code 2nd char: 0:0x90-0xbf,1-3:0x80-0xbf,4:0x80-0x8f */ - s = (filter->cache << 6) | (c & 0x3f); - c1 = filter->cache & 0x7; - - if ((c >= 0x80 && c <= 0xbf) && - ((c1 == 0x0 && c >= 0x90) || - (c1 == 0x4 && c < 0x90) || - (c1 > 0x0 && c1 != 0x4))) { - filter->cache = s; - filter->status++; - } else { - CK(mbfl_filt_put_invalid_char(filter)); - goto retry; - } - break; - - case 0x31: /* 4byte code 3rd char: 0x80-0xbf */ - if (c >= 0x80 && c <= 0xbf) { - filter->cache = (filter->cache << 6) | (c & 0x3f); - filter->status++; - } else { - CK(mbfl_filt_put_invalid_char(filter)); - goto retry; - } - break; - - EMPTY_SWITCH_DEFAULT_CASE(); - } - - return 0; -} - -static int mbfl_filt_conv_wchar_utf8_mobile(int c, mbfl_convert_filter *filter) -{ - if (c >= 0 && c < 0x110000) { - int s1, c1; - - if ((filter->to->no_encoding == mbfl_no_encoding_utf8_docomo && mbfilter_unicode2sjis_emoji_docomo(c, &s1, filter) > 0 && mbfilter_conv_map_tbl(s1, &c1, 4, mbfl_docomo2uni_pua)) || - (filter->to->no_encoding == mbfl_no_encoding_utf8_kddi_a && mbfilter_unicode2sjis_emoji_kddi_sjis(c, &s1, filter) > 0 && mbfilter_conv_map_tbl(s1, &c1, 7, mbfl_kddi2uni_pua)) || - (filter->to->no_encoding == mbfl_no_encoding_utf8_kddi_b && mbfilter_unicode2sjis_emoji_kddi_sjis(c, &s1, filter) > 0 && mbfilter_conv_map_tbl(s1, &c1, 8, mbfl_kddi2uni_pua_b)) || - (filter->to->no_encoding == mbfl_no_encoding_utf8_sb && mbfilter_unicode2sjis_emoji_sb(c, &s1, filter) > 0 && mbfilter_conv_map_tbl(s1, &c1, 6, mbfl_sb2uni_pua))) { - c = c1; - } - - if (filter->status) { - return 0; - } - - if (c < 0x80) { - CK((*filter->output_function)(c, filter->data)); - } else if (c < 0x800) { - CK((*filter->output_function)(((c >> 6) & 0x1f) | 0xc0, filter->data)); - CK((*filter->output_function)((c & 0x3f) | 0x80, filter->data)); - } else if (c < 0x10000) { - CK((*filter->output_function)(((c >> 12) & 0x0f) | 0xe0, filter->data)); - CK((*filter->output_function)(((c >> 6) & 0x3f) | 0x80, filter->data)); - CK((*filter->output_function)((c & 0x3f) | 0x80, filter->data)); - } else { - CK((*filter->output_function)(((c >> 18) & 0x07) | 0xf0, filter->data)); - CK((*filter->output_function)(((c >> 12) & 0x3f) | 0x80, filter->data)); - CK((*filter->output_function)(((c >> 6) & 0x3f) | 0x80, filter->data)); - CK((*filter->output_function)((c & 0x3f) | 0x80, filter->data)); - } - } else { - CK(mbfl_filt_conv_illegal_output(c, filter)); - } - - return 0; -} - /* Regional Indicator Unicode codepoints are from 0x1F1E6-0x1F1FF * These correspond to the letters A-Z * To display the flag emoji for a country, two unicode codepoints are combined, diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8.h b/ext/mbstring/libmbfl/filters/mbfilter_utf8.h index a1282515f34f1..e574aebf89582 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8.h @@ -31,21 +31,9 @@ #define MBFL_MBFILTER_UTF8_H extern const mbfl_encoding mbfl_encoding_utf8; -extern const struct mbfl_convert_vtbl vtbl_utf8_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf8; - extern const mbfl_encoding mbfl_encoding_utf8_docomo; extern const mbfl_encoding mbfl_encoding_utf8_kddi_a; extern const mbfl_encoding mbfl_encoding_utf8_kddi_b; extern const mbfl_encoding mbfl_encoding_utf8_sb; -extern const struct mbfl_convert_vtbl vtbl_utf8_docomo_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf8_docomo; -extern const struct mbfl_convert_vtbl vtbl_utf8_kddi_a_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf8_kddi_a; -extern const struct mbfl_convert_vtbl vtbl_utf8_kddi_b_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf8_kddi_b; -extern const struct mbfl_convert_vtbl vtbl_utf8_sb_wchar; -extern const struct mbfl_convert_vtbl vtbl_wchar_utf8_sb; - #endif /* MBFL_MBFILTER_UTF8_H */ diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter.c b/ext/mbstring/libmbfl/mbfl/mbfilter.c index 1c30c9f417755..d2d68795fa0d4 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter.c @@ -103,7 +103,6 @@ mbfl_strcut( size_t from, size_t length) { - const mbfl_encoding *encoding = string->encoding; mbfl_memory_device device; if (from >= string->len) { @@ -113,145 +112,97 @@ mbfl_strcut( mbfl_string_init(result); result->encoding = string->encoding; - if ((encoding->flag & (MBFL_ENCTYPE_SBCS | MBFL_ENCTYPE_WCS2 | MBFL_ENCTYPE_WCS4)) || encoding->mblen_table != NULL) { - const unsigned char *start = NULL; - const unsigned char *end = NULL; - unsigned char *w; - size_t sz; - - if (encoding->flag & MBFL_ENCTYPE_WCS2) { - from &= -2; - - if (length >= string->len - from) { - length = string->len - from; - } - - start = string->val + from; - end = start + (length & -2); - } else if (encoding->flag & MBFL_ENCTYPE_WCS4) { - from &= -4; - - if (length >= string->len - from) { - length = string->len - from; - } - - start = string->val + from; - end = start + (length & -4); - } else if ((encoding->flag & MBFL_ENCTYPE_SBCS)) { - if (length >= string->len - from) { - length = string->len - from; - } - - start = string->val + from; - end = start + length; - } else if (encoding->mblen_table != NULL) { - const unsigned char *mbtab = encoding->mblen_table; - const unsigned char *p, *q; - int m; - - /* search start position */ - for (m = 0, p = string->val, q = p + from; - p < q; p += (m = mbtab[*p])); - - if (p > q) { - p -= m; - } - - start = p; + mbfl_convert_filter *encoder = NULL; + mbfl_convert_filter *decoder = NULL; + const unsigned char *p, *q, *r; + struct { + mbfl_convert_filter encoder; + mbfl_convert_filter decoder; + const unsigned char *p; + size_t pos; + } bk, _bk; + + /* output code filter */ + if (!(decoder = mbfl_convert_filter_new( + &mbfl_encoding_wchar, + string->encoding, + mbfl_memory_device_output, 0, &device))) { + return NULL; + } - /* search end position */ - if (length >= string->len - (start - string->val)) { - end = string->val + string->len; - } else { - for (q = p + length; p < q; p += (m = mbtab[*p])); + /* wchar filter */ + if (!(encoder = mbfl_convert_filter_new( + string->encoding, + &mbfl_encoding_wchar, + mbfl_filter_output_null, + NULL, NULL))) { + mbfl_convert_filter_delete(decoder); + return NULL; + } - if (p > q) { - p -= m; - } - end = p; - } - } else { - /* never reached */ - return NULL; - } + mbfl_memory_device_init(&device, length + 8, 0); - /* allocate memory and copy string */ - sz = end - start; - w = ecalloc(sz + 8, sizeof(unsigned char)); + p = string->val; - memcpy(w, start, sz); - w[sz] = '\0'; - w[sz + 1] = '\0'; - w[sz + 2] = '\0'; - w[sz + 3] = '\0'; + /* search start position */ + for (q = string->val + from; p < q; p++) { + (*encoder->filter_function)(*p, encoder); + } - result->val = w; - result->len = sz; - } else { - mbfl_convert_filter *encoder = NULL; - mbfl_convert_filter *decoder = NULL; - const unsigned char *p, *q, *r; - struct { - mbfl_convert_filter encoder; - mbfl_convert_filter decoder; - const unsigned char *p; - size_t pos; - } bk, _bk; - - /* output code filter */ - if (!(decoder = mbfl_convert_filter_new( - &mbfl_encoding_wchar, - string->encoding, - mbfl_memory_device_output, 0, &device))) { - return NULL; - } + /* switch the drain direction */ + encoder->output_function = (output_function_t)decoder->filter_function; + encoder->flush_function = (flush_function_t)decoder->filter_flush; + encoder->data = decoder; - /* wchar filter */ - if (!(encoder = mbfl_convert_filter_new( - string->encoding, - &mbfl_encoding_wchar, - mbfl_filter_output_null, - NULL, NULL))) { - mbfl_convert_filter_delete(decoder); - return NULL; - } + q = string->val + string->len; - mbfl_memory_device_init(&device, length + 8, 0); + /* save the encoder, decoder state and the pointer */ + mbfl_convert_filter_copy(decoder, &_bk.decoder); + mbfl_convert_filter_copy(encoder, &_bk.encoder); + _bk.p = p; + _bk.pos = device.pos; - p = string->val; + if (length > q - p) { + length = q - p; + } - /* search start position */ - for (q = string->val + from; p < q; p++) { + if (length >= 20) { + /* output a little shorter than "length" */ + /* XXX: the constant "20" was determined purely on the heuristics. */ + for (r = p + length - 20; p < r; p++) { (*encoder->filter_function)(*p, encoder); } - /* switch the drain direction */ - encoder->output_function = (output_function_t)decoder->filter_function; - encoder->flush_function = (flush_function_t)decoder->filter_flush; - encoder->data = decoder; - - q = string->val + string->len; - - /* save the encoder, decoder state and the pointer */ - mbfl_convert_filter_copy(decoder, &_bk.decoder); - mbfl_convert_filter_copy(encoder, &_bk.encoder); - _bk.p = p; - _bk.pos = device.pos; - - if (length > q - p) { - length = q - p; - } + /* if the offset of the resulting string exceeds the length, + * then restore the state */ + if (device.pos > length) { + p = _bk.p; + device.pos = _bk.pos; + if (decoder->filter_dtor) + decoder->filter_dtor(decoder); + if (encoder->filter_dtor) + encoder->filter_dtor(encoder); + mbfl_convert_filter_copy(&_bk.decoder, decoder); + mbfl_convert_filter_copy(&_bk.encoder, encoder); + bk = _bk; + } else { + /* save the encoder, decoder state and the pointer */ + mbfl_convert_filter_copy(decoder, &bk.decoder); + mbfl_convert_filter_copy(encoder, &bk.encoder); + bk.p = p; + bk.pos = device.pos; - if (length >= 20) { - /* output a little shorter than "length" */ - /* XXX: the constant "20" was determined purely on the heuristics. */ - for (r = p + length - 20; p < r; p++) { - (*encoder->filter_function)(*p, encoder); - } + /* flush the stream */ + (*encoder->filter_flush)(encoder); /* if the offset of the resulting string exceeds the length, * then restore the state */ if (device.pos > length) { + if (bk.decoder.filter_dtor) + bk.decoder.filter_dtor(&bk.decoder); + if (bk.encoder.filter_dtor) + bk.encoder.filter_dtor(&bk.encoder); + p = _bk.p; device.pos = _bk.pos; if (decoder->filter_dtor) @@ -262,86 +213,11 @@ mbfl_strcut( mbfl_convert_filter_copy(&_bk.encoder, encoder); bk = _bk; } else { - /* save the encoder, decoder state and the pointer */ - mbfl_convert_filter_copy(decoder, &bk.decoder); - mbfl_convert_filter_copy(encoder, &bk.encoder); - bk.p = p; - bk.pos = device.pos; - - /* flush the stream */ - (*encoder->filter_flush)(encoder); - - /* if the offset of the resulting string exceeds the length, - * then restore the state */ - if (device.pos > length) { - if (bk.decoder.filter_dtor) - bk.decoder.filter_dtor(&bk.decoder); - if (bk.encoder.filter_dtor) - bk.encoder.filter_dtor(&bk.encoder); - - p = _bk.p; - device.pos = _bk.pos; - if (decoder->filter_dtor) - decoder->filter_dtor(decoder); - if (encoder->filter_dtor) - encoder->filter_dtor(encoder); - mbfl_convert_filter_copy(&_bk.decoder, decoder); - mbfl_convert_filter_copy(&_bk.encoder, encoder); - bk = _bk; - } else { - if (_bk.decoder.filter_dtor) - _bk.decoder.filter_dtor(&_bk.decoder); - if (_bk.encoder.filter_dtor) - _bk.encoder.filter_dtor(&_bk.encoder); - - p = bk.p; - device.pos = bk.pos; - if (decoder->filter_dtor) - decoder->filter_dtor(decoder); - if (encoder->filter_dtor) - encoder->filter_dtor(encoder); - mbfl_convert_filter_copy(&bk.decoder, decoder); - mbfl_convert_filter_copy(&bk.encoder, encoder); - } - } - } else { - bk = _bk; - } - - /* detect end position */ - while (p < q) { - (*encoder->filter_function)(*p, encoder); - - if (device.pos > length) { - /* restore filter */ - p = bk.p; - device.pos = bk.pos; - if (decoder->filter_dtor) - decoder->filter_dtor(decoder); - if (encoder->filter_dtor) - encoder->filter_dtor(encoder); - mbfl_convert_filter_copy(&bk.decoder, decoder); - mbfl_convert_filter_copy(&bk.encoder, encoder); - break; - } - - p++; - - /* backup current state */ - mbfl_convert_filter_copy(decoder, &_bk.decoder); - mbfl_convert_filter_copy(encoder, &_bk.encoder); - _bk.pos = device.pos; - _bk.p = p; - - (*encoder->filter_flush)(encoder); - - if (device.pos > length) { if (_bk.decoder.filter_dtor) _bk.decoder.filter_dtor(&_bk.decoder); if (_bk.encoder.filter_dtor) _bk.encoder.filter_dtor(&_bk.encoder); - /* restore filter */ p = bk.p; device.pos = bk.pos; if (decoder->filter_dtor) @@ -350,39 +226,86 @@ mbfl_strcut( encoder->filter_dtor(encoder); mbfl_convert_filter_copy(&bk.decoder, decoder); mbfl_convert_filter_copy(&bk.encoder, encoder); - break; } + } + } else { + bk = _bk; + } - if (bk.decoder.filter_dtor) - bk.decoder.filter_dtor(&bk.decoder); - if (bk.encoder.filter_dtor) - bk.encoder.filter_dtor(&bk.encoder); + /* detect end position */ + while (p < q) { + (*encoder->filter_function)(*p, encoder); - p = _bk.p; - device.pos = _bk.pos; + if (device.pos > length) { + /* restore filter */ + p = bk.p; + device.pos = bk.pos; if (decoder->filter_dtor) decoder->filter_dtor(decoder); if (encoder->filter_dtor) encoder->filter_dtor(encoder); - mbfl_convert_filter_copy(&_bk.decoder, decoder); - mbfl_convert_filter_copy(&_bk.encoder, encoder); - - bk = _bk; + mbfl_convert_filter_copy(&bk.decoder, decoder); + mbfl_convert_filter_copy(&bk.encoder, encoder); + break; } - decoder->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE; + p++; + + /* backup current state */ + mbfl_convert_filter_copy(decoder, &_bk.decoder); + mbfl_convert_filter_copy(encoder, &_bk.encoder); + _bk.pos = device.pos; + _bk.p = p; + (*encoder->filter_flush)(encoder); + if (device.pos > length) { + if (_bk.decoder.filter_dtor) + _bk.decoder.filter_dtor(&_bk.decoder); + if (_bk.encoder.filter_dtor) + _bk.encoder.filter_dtor(&_bk.encoder); + + /* restore filter */ + p = bk.p; + device.pos = bk.pos; + if (decoder->filter_dtor) + decoder->filter_dtor(decoder); + if (encoder->filter_dtor) + encoder->filter_dtor(encoder); + mbfl_convert_filter_copy(&bk.decoder, decoder); + mbfl_convert_filter_copy(&bk.encoder, encoder); + break; + } + if (bk.decoder.filter_dtor) bk.decoder.filter_dtor(&bk.decoder); if (bk.encoder.filter_dtor) bk.encoder.filter_dtor(&bk.encoder); - result = mbfl_memory_device_result(&device, result); + p = _bk.p; + device.pos = _bk.pos; + if (decoder->filter_dtor) + decoder->filter_dtor(decoder); + if (encoder->filter_dtor) + encoder->filter_dtor(encoder); + mbfl_convert_filter_copy(&_bk.decoder, decoder); + mbfl_convert_filter_copy(&_bk.encoder, encoder); - mbfl_convert_filter_delete(encoder); - mbfl_convert_filter_delete(decoder); + bk = _bk; } + decoder->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE; + (*encoder->filter_flush)(encoder); + + if (bk.decoder.filter_dtor) + bk.decoder.filter_dtor(&bk.decoder); + if (bk.encoder.filter_dtor) + bk.encoder.filter_dtor(&bk.encoder); + + result = mbfl_memory_device_result(&device, result); + + mbfl_convert_filter_delete(encoder); + mbfl_convert_filter_delete(decoder); + return result; } diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 118986411a8bb..baacbed32a862 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -2107,8 +2107,34 @@ static zend_string* mb_get_substr_slow(unsigned char *in, size_t in_len, size_t uint32_t wchar_buf[128]; unsigned int state = 0; + /* For the below call to mb_convert_buf_init, we need to estimate how many bytes the output of this operation will need. + * If possible, we want to initialize the output buffer with enough space, so it is not necessary to grow it dynamically; + * At the same time, we don't want to make it huge and waste a lot of memory. + * + * `len` is the requested number of codepoints; we optimistically guess that each codepoint can be encoded in one byte. + * However, the caller may have requested a huge number of codepoints, more than are actually present in the input string; + * so we also use a 2nd estimate to avoid unnecessary, huge allocations: + * + * `in_len` is the number of input bytes, `from` is the number of codepoints to skip; again, if each leading codepoint is + * encoded in one byte, then there may be as many as `in_len - from` bytes remaining after skipping leading codepoints; + * that gives our 2nd estimate of the needed output buffer size. + * + * If `len == MBFL_SUBSTR_UNTIL_END`, then `len` will be the largest possible `size_t` value, and the `in_len - from` + * estimate will certainly be used instead. */ + + size_t initial_buf_size; + if (from > in_len) { + /* Normally, if `from > in_len`, then the output will definitely be empty, and in fact, `mb_get_substr` uses + * this fact to (usually) just return an empty string in such situations. + * But for SJIS-Mac, one byte can decode to more than one codepoint, so we can't assume the output will + * definitely be empty. If it's not... then our output buffer will be dynamically resized. */ + initial_buf_size = 0; + } else { + initial_buf_size = MIN(len, in_len - from); + } + mb_convert_buf buf; - mb_convert_buf_init(&buf, MIN(len, in_len - from), MBSTRG(current_filter_illegal_substchar), MBSTRG(current_filter_illegal_mode)); + mb_convert_buf_init(&buf, initial_buf_size, MBSTRG(current_filter_illegal_substchar), MBSTRG(current_filter_illegal_mode)); while (in_len && len) { size_t out_len = enc->to_wchar(&in, &in_len, wchar_buf, 128, &state); @@ -2448,7 +2474,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) { @@ -2471,7 +2497,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); @@ -3703,11 +3729,26 @@ PHP_FUNCTION(mb_convert_kana) RETVAL_STR(jp_kana_convert(str, enc, opt)); } +static zend_always_inline bool mb_check_stack_limit(void) +{ +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + return true; + } +#endif + return false; +} + static unsigned int mb_recursive_count_strings(zval *var) { unsigned int count = 0; ZVAL_DEREF(var); + if (mb_check_stack_limit()) { + return 0; + } + if (Z_TYPE_P(var) == IS_STRING) { count++; } else if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) { @@ -3738,6 +3779,10 @@ static bool mb_recursive_find_strings(zval *var, const unsigned char **val_list, { ZVAL_DEREF(var); + if (mb_check_stack_limit()) { + return true; + } + if (Z_TYPE_P(var) == IS_STRING) { val_list[*count] = (const unsigned char*)Z_STRVAL_P(var); len_list[*count] = Z_STRLEN_P(var); @@ -3775,6 +3820,10 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e { zval *entry, *orig_var; + if (mb_check_stack_limit()) { + return true; + } + orig_var = var; ZVAL_DEREF(var); @@ -3783,17 +3832,25 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e zval_ptr_dtor(orig_var); ZVAL_STR(orig_var, ret); } else if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) { - if (Z_TYPE_P(var) == IS_ARRAY) { - SEPARATE_ARRAY(var); - } - if (Z_REFCOUNTED_P(var)) { - if (Z_IS_RECURSIVE_P(var)) { + HashTable *ht = HASH_OF(var); + HashTable *orig_ht = ht; + + if (ht) { + if (GC_IS_RECURSIVE(ht)) { return true; } - Z_PROTECT_RECURSION_P(var); + + GC_TRY_PROTECT_RECURSION(ht); } - HashTable *ht = HASH_OF(var); + if (Z_TYPE_P(var) == IS_ARRAY) { + SEPARATE_ARRAY(var); + ht = Z_ARRVAL_P(var); + + if (ht && ht != orig_ht && !GC_IS_RECURSIVE(ht)) { + GC_TRY_PROTECT_RECURSION(ht); + } + } if (ht != NULL) { ZEND_HASH_FOREACH_VAL(ht, entry) { /* Can be a typed property declaration, in which case we need to remove the reference from the source list. @@ -3812,16 +3869,22 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e } if (mb_recursive_convert_variable(entry, from_encoding, to_encoding)) { - if (Z_REFCOUNTED_P(var)) { - Z_UNPROTECT_RECURSION_P(var); + if (ht && ht != orig_ht) { + GC_TRY_UNPROTECT_RECURSION(ht); + } + if (orig_ht) { + GC_TRY_UNPROTECT_RECURSION(orig_ht); } return true; } } ZEND_HASH_FOREACH_END(); } - if (Z_REFCOUNTED_P(var)) { - Z_UNPROTECT_RECURSION_P(var); + if (ht && ht != orig_ht) { + GC_TRY_UNPROTECT_RECURSION(ht); + } + if (orig_ht) { + GC_TRY_UNPROTECT_RECURSION(orig_ht); } } @@ -3895,7 +3958,9 @@ PHP_FUNCTION(mb_convert_variables) efree(ZEND_VOIDP(elist)); efree(ZEND_VOIDP(val_list)); efree(len_list); - php_error_docref(NULL, E_WARNING, "Cannot handle recursive references"); + if (!EG(exception)) { + php_error_docref(NULL, E_WARNING, "Cannot handle recursive references"); + } RETURN_FALSE; } } @@ -3917,7 +3982,9 @@ PHP_FUNCTION(mb_convert_variables) zval *zv = &args[n]; ZVAL_DEREF(zv); if (mb_recursive_convert_variable(zv, from_encoding, to_encoding)) { - php_error_docref(NULL, E_WARNING, "Cannot handle recursive references"); + if (!EG(exception)) { + php_error_docref(NULL, E_WARNING, "Cannot handle recursive references"); + } RETURN_FALSE; } } @@ -4703,7 +4770,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); @@ -5856,6 +5923,11 @@ PHP_FUNCTION(mb_str_pad) } size_t pad_length = mb_get_strlen(pad, encoding); + if (pad_length == 0) { + /* Possible with invalidly encoded padding string. */ + zend_argument_must_not_be_empty_error(3); + RETURN_THROWS(); + } size_t num_mb_pad_chars = pad_to_length - input_length; diff --git a/ext/mbstring/php_unicode.c b/ext/mbstring/php_unicode.c index 988f5e9cc921b..f4944312bdf5f 100644 --- a/ext/mbstring/php_unicode.c +++ b/ext/mbstring/php_unicode.c @@ -180,7 +180,9 @@ static unsigned php_unicode_totitle_raw(unsigned code, const mbfl_encoding *enc) static unsigned php_unicode_tofold_raw(unsigned code, const mbfl_encoding *enc) { - if (code < 0x80) { + /* After the ASCII characters, the first codepoint with an special case-folded version + * is 0xB5 (MICRO SIGN) */ + if (code < 0xB5) { /* Fast path for ASCII */ if (code >= 0x41 && code <= 0x5A) { if (UNEXPECTED(enc == &mbfl_encoding_8859_9 && code == 0x49)) { diff --git a/ext/mbstring/tests/gh20832.phpt b/ext/mbstring/tests/gh20832.phpt new file mode 100644 index 0000000000000..9a076dc4fe70d --- /dev/null +++ b/ext/mbstring/tests/gh20832.phpt @@ -0,0 +1,10 @@ +--TEST-- +Ensure mb_substr does not crash with MacJapanese input, when codepoints to skip are more than number of bytes in input string +--EXTENSIONS-- +mbstring +--FILE-- + +--EXPECT-- +string(1) "V" diff --git a/ext/mbstring/tests/gh20833.phpt b/ext/mbstring/tests/gh20833.phpt new file mode 100644 index 0000000000000..099aa3379238f --- /dev/null +++ b/ext/mbstring/tests/gh20833.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-20833 (mb_str_pad() divide by zero if padding string is invalid in the encoding) +--EXTENSIONS-- +mbstring +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +ValueError: mb_str_pad(): Argument #3 ($pad_string) must not be empty diff --git a/ext/mbstring/tests/gh20836.phpt b/ext/mbstring/tests/gh20836.phpt new file mode 100644 index 0000000000000..60b6a4ce8d4f0 --- /dev/null +++ b/ext/mbstring/tests/gh20836.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-20836 (Stack overflow in mb_convert_variables with recursive array references) +--EXTENSIONS-- +mbstring +--FILE-- + ['level2' => ['level3' => 'data']]]; +var_dump(mb_convert_variables('utf-8', 'utf-8', $d)); + +echo "Done\n"; +?> +--EXPECTF-- +Warning: mb_convert_variables(): Cannot handle recursive references in %s on line %d +bool(false) + +Warning: mb_convert_variables(): Cannot handle recursive references in %s on line %d +bool(false) +string(5) "UTF-8" +string(5) "UTF-8" +Done diff --git a/ext/mbstring/tests/gh20836_stack_limit.phpt b/ext/mbstring/tests/gh20836_stack_limit.phpt new file mode 100644 index 0000000000000..b58833ff80cf8 --- /dev/null +++ b/ext/mbstring/tests/gh20836_stack_limit.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-20836 (Stack overflow in mb_convert_variables with recursive array references, stack limit case) +--EXTENSIONS-- +mbstring +--SKIPIF-- + +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- + createDeepArray($depth - 1)]; +} + +// Create a deeply nested array that will trigger stack limit +$deepArray = createDeepArray(15000); + +mb_convert_variables('utf-8', 'utf-8', $deepArray); + +echo "Done\n"; +?> +--EXPECTF-- +Fatal error: Uncaught Error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion? in %s:%d +Stack trace: +#0 %s(%d): mb_convert_variables('utf-8', 'utf-8', Array) +#1 {main} + thrown in %s on line %d 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/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 7acb14b778f8d..ebfdce43841bb 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -26,7 +26,9 @@ #include "zend_compile.h" #include "ZendAccelerator.h" #include "zend_modules.h" +#include "zend_operators.h" #include "zend_persist.h" +#include "zend_portability.h" #include "zend_shared_alloc.h" #include "zend_accelerator_module.h" #include "zend_accelerator_blacklist.h" @@ -50,6 +52,7 @@ #include "zend_system_id.h" #include "ext/pcre/php_pcre.h" #include "ext/standard/basic_functions.h" +#include "zend_vm_opcodes.h" #ifdef ZEND_WIN32 # include "ext/hash/php_hash.h" @@ -2014,6 +2017,219 @@ static int check_persistent_script_access(zend_persistent_script *persistent_scr } } +static const char hexchars[] = "0123456789abcdef"; + +static char *zend_accel_uintptr_hex(char *dest, uintptr_t n) +{ + char *start = dest; + dest += sizeof(uintptr_t)*2; + + while (n > 0) { + *--dest = hexchars[n % strlen(hexchars)]; + n /= strlen(hexchars); + } + while (dest > start) { + *--dest = '0'; + } + + return dest + sizeof(uintptr_t)*2; +} + +/* Prevents collisions with real scripts, as we don't cache paths prefixed with + * a scheme, except file:// and phar://. */ +#define PFA_KEY_PREFIX "pfa://" + +static zend_string *zend_accel_pfa_key(const zend_op *declaring_opline, + const zend_function *called_function) +{ + size_t key_len = strlen(PFA_KEY_PREFIX) + (sizeof(uintptr_t)*2) + strlen(":") + (sizeof(uintptr_t)*2); + zend_string *key = zend_string_alloc(key_len, 0); + char *dest = ZSTR_VAL(key); + + dest = zend_mempcpy(ZSTR_VAL(key), PFA_KEY_PREFIX, strlen(PFA_KEY_PREFIX)); + dest = zend_accel_uintptr_hex(dest, (uintptr_t)declaring_opline); + *dest++ = ':'; + + const void *ptr; + if ((called_function->common.fn_flags & ZEND_ACC_CLOSURE) + && called_function->type == ZEND_USER_FUNCTION) { + /* Can not use 'called_function' as part of the key, as it's an inner + * pointer to a Closure, which may be freed. Use its opcodes instead. + * zend_accel_compile_pfa() ensures to extend the lifetime of opcodes + * in this case. */ + ptr = called_function->op_array.opcodes; + } else { + ptr = called_function; + } + dest = zend_accel_uintptr_hex(dest, (uintptr_t)ptr); + + ZEND_ASSERT(dest == ZSTR_VAL(key) + key_len); + + ZSTR_VAL(key)[key_len] = 0; + ZSTR_LEN(key) = key_len; + + return key; +} + +const zend_op_array *zend_accel_pfa_cache_get(const zend_op_array *declaring_op_array, + const zend_op *declaring_opline, const zend_function *called_function) +{ + zend_string *key = zend_accel_pfa_key(declaring_opline, called_function); + zend_op_array *op_array = NULL; + + /* A PFA is SHM-cacheable if the declaring_op_array and called_function are + * cached. */ + if (ZCG(accelerator_enabled) + && !file_cache_only + && !declaring_op_array->refcount + && (called_function->type != ZEND_USER_FUNCTION || !called_function->op_array.refcount)) { + zend_persistent_script *persistent_script = zend_accel_hash_find(&ZCSG(hash), key); + if (persistent_script) { + op_array = persistent_script->script.main_op_array.dynamic_func_defs[0]; + if (persistent_script->num_warnings) { + zend_emit_recorded_errors_ex(persistent_script->num_warnings, + persistent_script->warnings); + } + } + } else { + op_array = zend_hash_find_ptr(&EG(partial_function_application_cache), key); + } + + zend_string_release(key); + + return op_array; +} + +zend_op_array *zend_accel_compile_pfa(zend_ast *ast, + const zend_op_array *declaring_op_array, + const zend_op *declaring_opline, + const zend_function *called_function, + zend_string *pfa_func_name) +{ + zend_begin_record_errors(); + zend_op_array *op_array; + + uint32_t orig_compiler_options = CG(compiler_options); + + zend_try { + CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY; + CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING; + CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION; + CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES; + CG(compiler_options) |= ZEND_COMPILE_IGNORE_OBSERVER; +#ifdef ZEND_WIN32 + /* On Windows, don't compile with internal classes. Shm may be attached from different + * processes with internal classes living in different addresses. */ + CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES; +#endif + + op_array = zend_compile_ast(ast, ZEND_USER_FUNCTION, declaring_op_array->filename); + + ZEND_ASSERT(op_array->num_dynamic_func_defs == 1); + + CG(compiler_options) = orig_compiler_options; + } zend_catch { + op_array = NULL; + CG(compiler_options) = orig_compiler_options; + EG(record_errors) = false; + zend_free_recorded_errors(); + zend_bailout(); + } zend_end_try(); + + if (!op_array) { + zend_emit_recorded_errors(); + zend_free_recorded_errors(); + return NULL; + } + + ZEND_ASSERT(op_array->num_dynamic_func_defs == 1); + + zend_string_release(op_array->dynamic_func_defs[0]->function_name); + op_array->dynamic_func_defs[0]->function_name = pfa_func_name; + + zend_string *key = zend_accel_pfa_key(declaring_opline, called_function); + + /* Cache op_array only if the declaring op_array and the called function + * are cached */ + if (!ZCG(accelerator_enabled) + || file_cache_only + || declaring_op_array->refcount + || (called_function->type == ZEND_USER_FUNCTION && called_function->op_array.refcount) + || (ZCSG(restart_in_progress) && accel_restart_is_active()) + || (!ZCG(counted) && accel_activate_add() == FAILURE)) { + zend_op_array *script_op_array = op_array; + zend_op_array *op_array = script_op_array->dynamic_func_defs[0]; + GC_ADDREF(op_array->function_name); + (*op_array->refcount)++; + destroy_op_array(script_op_array); + efree(script_op_array); + + if ((called_function->common.fn_flags & ZEND_ACC_CLOSURE) + && called_function->type == ZEND_USER_FUNCTION + && called_function->op_array.refcount) { + /* Extend the lifetime of the called opcodes if + * the called function is a closure. + * See comment in zend_accel_pfa_key(). */ + zend_op_array *copy = zend_arena_alloc(&CG(arena), sizeof(zend_function)); + memcpy(copy, called_function, sizeof(zend_op_array)); + zend_string_addref(copy->function_name); + (*copy->refcount)++; + /* Reference the copy in op_array->dynamic_func_defs so that it's + * destroyed when op_array is destroyed. */ + ZEND_ASSERT(!op_array->dynamic_func_defs && !op_array->num_dynamic_func_defs); + op_array->dynamic_func_defs = emalloc(sizeof(zend_op_array*)); + op_array->dynamic_func_defs[0] = copy; + op_array->num_dynamic_func_defs = 1; + } + + zend_hash_add_new_ptr(&EG(partial_function_application_cache), key, op_array); + zend_string_release(key); + + zend_emit_recorded_errors(); + zend_free_recorded_errors(); + + return op_array; + } + + zend_persistent_script *new_persistent_script = create_persistent_script(); + new_persistent_script->script.main_op_array = *op_array; + efree_size(op_array, sizeof(zend_op_array)); + new_persistent_script->script.filename = key; + + if (ZCG(accel_directives).record_warnings) { + new_persistent_script->num_warnings = EG(num_errors); + new_persistent_script->warnings = EG(errors); + } + + HANDLE_BLOCK_INTERRUPTIONS(); + SHM_UNPROTECT(); + + bool from_shared_memory; + /* See GH-17246: we disable GC so that user code cannot be executed during the optimizer run. */ + bool orig_gc_state = gc_enable(false); + char *orig_file_cache = ZCG(accel_directives).file_cache; + /* Disable file_cache temporarily, as we can't guarantee consistency. */ + ZCG(accel_directives).file_cache = false; + new_persistent_script = cache_script_in_shared_memory(new_persistent_script, NULL, &from_shared_memory); + ZCG(accel_directives).file_cache = orig_file_cache; + gc_enable(orig_gc_state); + + SHM_PROTECT(); + HANDLE_UNBLOCK_INTERRUPTIONS(); + + /* We may have switched to an existing persistent script that was persisted in + * the meantime. Make sure to use its warnings if available. */ + if (ZCG(accel_directives).record_warnings) { + EG(record_errors) = false; + zend_emit_recorded_errors_ex(new_persistent_script->num_warnings, new_persistent_script->warnings); + } else { + zend_emit_recorded_errors(); + } + zend_free_recorded_errors(); + + return new_persistent_script->script.main_op_array.dynamic_func_defs[0]; +} + /* zend_compile() replacement */ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type) { @@ -4663,7 +4879,6 @@ static zend_result accel_preload(const char *config, bool in_child) zend_destroy_file_handle(&file_handle); if (op_array) { zend_execute(op_array, NULL); - zend_exception_restore(); if (UNEXPECTED(EG(exception))) { if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { zend_user_exception_handler(); diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index 524a6f5e12139..97cdadfad5f02 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -336,6 +336,16 @@ zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str); uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name); +const zend_op_array *zend_accel_pfa_cache_get(const zend_op_array *declaring_op_array, + const zend_op *declaring_opline, + const zend_function *called_function); + +zend_op_array *zend_accel_compile_pfa(zend_ast *ast, + const zend_op_array *declaring_op_array, + const zend_op *declaring_opline, + const zend_function *called_function, + zend_string *pfa_func_name); + END_EXTERN_C() /* memory write protection */ diff --git a/ext/opcache/jit/ir/ir.h b/ext/opcache/jit/ir/ir.h index a96650597055a..a274ceb5b1673 100644 --- a/ext/opcache/jit/ir/ir.h +++ b/ext/opcache/jit/ir/ir.h @@ -539,38 +539,38 @@ void ir_strtab_apply(const ir_strtab *strtab, ir_strtab_apply_t func); void ir_strtab_free(ir_strtab *strtab); /* IR Context Flags */ -#define IR_FUNCTION (1<<0) /* Generate a function. */ -#define IR_FASTCALL_FUNC (1<<1) /* Generate a function with fastcall calling convention, x86 32-bit only. */ -#define IR_VARARG_FUNC (1<<2) -#define IR_BUILTIN_FUNC (1<<3) -#define IR_STATIC (1<<4) -#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 */ - -#define IR_SKIP_PROLOGUE (1<<8) /* Don't generate function prologue. */ -#define IR_USE_FRAME_POINTER (1<<9) -#define IR_PREALLOCATED_STACK (1<<10) -#define IR_NO_STACK_COMBINE (1<<11) -#define IR_START_BR_TARGET (1<<12) -#define IR_ENTRY_BR_TARGET (1<<13) -#define IR_GEN_ENDBR (1<<14) -#define IR_MERGE_EMPTY_ENTRIES (1<<15) - -#define IR_OPT_INLINE (1<<16) -#define IR_OPT_FOLDING (1<<17) -#define IR_OPT_CFG (1<<18) /* merge BBs, by remove END->BEGIN nodes during CFG construction */ -#define IR_OPT_MEM2SSA (1<<19) -#define IR_OPT_CODEGEN (1<<20) -#define IR_GEN_NATIVE (1<<21) -#define IR_GEN_CODE (1<<22) /* C or LLVM */ - -#define IR_GEN_CACHE_DEMOTE (1<<23) /* Demote the generated code from closest CPU caches */ +#define IR_PROTO_MASK 0xff +#define IR_CALL_CONV_MASK 0x0f + +#define IR_VARARG_FUNC (1<<4) +#define IR_CONST_FUNC (1<<5) +#define IR_PURE_FUNC (1<<6) + +#define IR_CONST (1<<5) +#define IR_INITIALIZED (1<<6) /* sym data flag: constant or an initialized variable */ +#define IR_CONST_STRING (1<<7) /* sym data flag: constant string */ + +#define IR_FUNCTION (1<<8) /* Generate a function. */ +#define IR_STATIC (1<<9) +#define IR_EXTERN (1<<10) + +#define IR_USE_FRAME_POINTER (1<<11) +#define IR_NO_STACK_COMBINE (1<<12) +#define IR_GEN_ENDBR (1<<13) +#define IR_GEN_CACHE_DEMOTE (1<<14) /* Demote the generated code from closest CPU caches */ + +#define IR_SKIP_PROLOGUE (1<<15) /* Don't generate function prologue. */ +#define IR_START_BR_TARGET (1<<16) +#define IR_ENTRY_BR_TARGET (1<<17) +#define IR_MERGE_EMPTY_ENTRIES (1<<18) + +#define IR_OPT_INLINE (1<<19) +#define IR_OPT_FOLDING (1<<20) +#define IR_OPT_CFG (1<<21) /* merge BBs, by remove END->BEGIN nodes during CFG construction */ +#define IR_OPT_MEM2SSA (1<<22) +#define IR_OPT_CODEGEN (1<<23) +#define IR_GEN_NATIVE (1<<24) +#define IR_GEN_CODE (1<<25) /* debug related */ #ifdef IR_DEBUG @@ -582,6 +582,24 @@ void ir_strtab_free(ir_strtab *strtab); # define IR_DEBUG_BB_SCHEDULE (1U<<31) #endif +/* Calling Conventions */ +#define IR_CC_DEFAULT 0x00 +#define IR_CC_BUILTIN 0x01 +#define IR_CC_FASTCALL 0x02 +#define IR_CC_PRESERVE_NONE 0x03 + +#if defined(IR_TARGET_X64) +# define IR_CC_X86_64_SYSV 0x08 +# define IR_CC_X86_64_MS 0x09 +#elif defined(IR_TARGET_AARCH64) +# define IR_CC_AARCH64_SYSV 0x08 +# define IR_CC_AARCH64_DARWIN 0x09 +#endif + +/* Deprecated constants */ +#define IR_BUILTIN_FUNC IR_CC_BUILTIN +#define IR_FASTCALL_FUNC IR_CC_FASTCALL + typedef struct _ir_ctx ir_ctx; typedef struct _ir_use_list ir_use_list; typedef struct _ir_block ir_block; @@ -728,7 +746,7 @@ const char *ir_get_strl(const ir_ctx *ctx, ir_ref idx, size_t *len); #define IR_MAX_PROTO_PARAMS 255 typedef struct _ir_proto_t { - uint8_t flags; + uint8_t flags; /* first 8 bits of ir_ctx.flags */ uint8_t ret_type; uint8_t params_count; uint8_t param_types[5]; diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc index b553243309f54..88996cb6f98e1 100644 --- a/ext/opcache/jit/ir/ir_aarch64.dasc +++ b/ext/opcache/jit/ir/ir_aarch64.dasc @@ -213,14 +213,21 @@ static bool aarch64_may_encode_addr_offset(int64_t offset, uint32_t type_size) |.endmacro typedef struct _ir_backend_data { - ir_reg_alloc_data ra_data; - uint32_t dessa_from_block; + ir_reg_alloc_data ra_data; dasm_State *dasm_state; ir_bitset emit_constants; int rodata_label, jmp_table_label; bool resolved_label_syms; } ir_backend_data; +typedef struct _ir_aarch64_sysv_va_list { + void *stack; + void *gr_top; + void *vr_top; + int32_t gr_offset; + int32_t vr_offset; +} ir_aarch64_sysv_va_list; + #define IR_GP_REG_NAME(code, name64, name32) \ #name64, #define IR_GP_REG_NAME32(code, name64, name32) \ @@ -230,9 +237,11 @@ typedef struct _ir_backend_data { #define IR_FP_REG_NAME32(code, name64, name32, name16, name8) \ #name32, -static const char *_ir_reg_name[IR_REG_NUM] = { +static const char *_ir_reg_name[] = { IR_GP_REGS(IR_GP_REG_NAME) IR_FP_REGS(IR_FP_REG_NAME) + "ALL", + "SCRATCH", }; static const char *_ir_reg_name32[IR_REG_NUM] = { @@ -240,38 +249,11 @@ static const char *_ir_reg_name32[IR_REG_NUM] = { IR_FP_REGS(IR_FP_REG_NAME32) }; -/* Calling Convention */ -static const int8_t _ir_int_reg_params[IR_REG_INT_ARGS] = { - IR_REG_INT_ARG1, - IR_REG_INT_ARG2, - IR_REG_INT_ARG3, - IR_REG_INT_ARG4, - IR_REG_INT_ARG5, - IR_REG_INT_ARG6, - IR_REG_INT_ARG7, - IR_REG_INT_ARG8, -}; - -static const int8_t _ir_fp_reg_params[IR_REG_FP_ARGS] = { - IR_REG_FP_ARG1, - IR_REG_FP_ARG2, - IR_REG_FP_ARG3, - IR_REG_FP_ARG4, - IR_REG_FP_ARG5, - IR_REG_FP_ARG6, - IR_REG_FP_ARG7, - IR_REG_FP_ARG8, -}; - const char *ir_reg_name(int8_t reg, ir_type type) { if (reg >= IR_REG_NUM) { - if (reg == IR_REG_SCRATCH) { - return "SCRATCH"; - } else { - IR_ASSERT(reg == IR_REG_ALL); - return "ALL"; - } + IR_ASSERT((uint8_t)reg < sizeof(_ir_reg_name) / sizeof(_ir_reg_name[0])); + return _ir_reg_name[reg]; } IR_ASSERT(reg >= 0 && reg < IR_REG_NUM); if (type == IR_VOID) { @@ -284,6 +266,82 @@ const char *ir_reg_name(int8_t reg, ir_type type) } } +/* Calling Conventions */ +#define IR_REG_SCRATCH_AARCH64 IR_REG_SET_1 + +#define IR_REGSET_SCRATCH_AARCH64 \ + (IR_REGSET_INTERVAL(IR_REG_X0, IR_REG_X18) | \ + IR_REGSET_INTERVAL(IR_REG_V0, IR_REG_V7) | \ + IR_REGSET_INTERVAL(IR_REG_V16, IR_REG_V31)) + +const ir_regset ir_scratch_regset[] = { + IR_REGSET_GP | IR_REGSET_FP, + IR_REGSET_SCRATCH_AARCH64, +}; + +const ir_call_conv_dsc ir_call_conv_aarch64_sysv = { + 0, /* cleanup_stack_by_callee */ + 0, /* pass_struct_by_val */ + 1, /* sysv_varargs */ + 0, /* shadow_param_regs */ + 0, /* shadow_store_size */ + 8, /* int_param_regs_count */ + 8, /* fp_param_regs_count */ + IR_REG_X0 , /* int_ret_reg */ + IR_REG_V0, /* fp_ret_reg */ + IR_REG_NONE, /* fp_varargs_reg */ + IR_REG_SCRATCH_AARCH64, + (const int8_t[8]){IR_REG_X0, IR_REG_X1, IR_REG_X2, IR_REG_X3, IR_REG_X4, IR_REG_X5, IR_REG_X6, IR_REG_X7}, + (const int8_t[8]){IR_REG_V0, IR_REG_V1, IR_REG_V2, IR_REG_V3, IR_REG_V4, IR_REG_V5, IR_REG_V6, IR_REG_V7}, + IR_REGSET_INTERVAL(IR_REG_X19, IR_REG_X30) | IR_REGSET_INTERVAL(IR_REG_V8, IR_REG_V15), + +}; + +const ir_call_conv_dsc ir_call_conv_aarch64_darwin = { + 0, /* cleanup_stack_by_callee */ + 0, /* pass_struct_by_val */ + 0, /* sysv_varargs */ + 0, /* shadow_param_regs */ + 0, /* shadow_store_size */ + 8, /* int_param_regs_count */ + 8, /* fp_param_regs_count */ + IR_REG_X0 , /* int_ret_reg */ + IR_REG_V0, /* fp_ret_reg */ + IR_REG_NONE, /* fp_varargs_reg */ + IR_REG_SCRATCH_AARCH64, + (const int8_t[8]){IR_REG_X0, IR_REG_X1, IR_REG_X2, IR_REG_X3, IR_REG_X4, IR_REG_X5, IR_REG_X6, IR_REG_X7}, + (const int8_t[8]){IR_REG_V0, IR_REG_V1, IR_REG_V2, IR_REG_V3, IR_REG_V4, IR_REG_V5, IR_REG_V6, IR_REG_V7}, + IR_REGSET_INTERVAL(IR_REG_X19, IR_REG_X30) | IR_REGSET_INTERVAL(IR_REG_V8, IR_REG_V15), + +}; + +const ir_call_conv_dsc ir_call_conv_aarch64_preserve_none = { + 0, /* cleanup_stack_by_callee */ + 0, /* pass_struct_by_val */ + 1, /* sysv_varargs */ + 0, /* shadow_param_regs */ + 0, /* shadow_store_size */ + 23, /* int_param_regs_count */ + 8, /* fp_param_regs_count */ + IR_REG_X0 , /* int_ret_reg */ + IR_REG_V0, /* fp_ret_reg */ + IR_REG_NONE, /* fp_varargs_reg */ + IR_REG_ALL, + (const int8_t[23]){IR_REG_X20, IR_REG_X21, IR_REG_X22, IR_REG_X23, IR_REG_X24, IR_REG_X25, IR_REG_X26, IR_REG_X27, + IR_REG_X28, + IR_REG_X0, IR_REG_X1, IR_REG_X2, IR_REG_X3, IR_REG_X4, IR_REG_X5, IR_REG_X6, IR_REG_X7, + IR_REG_X10, IR_REG_X11, IR_REG_X12, IR_REG_X13, IR_REG_X14, IR_REG_X9}, + (const int8_t[8]){IR_REG_V0, IR_REG_V1, IR_REG_V2, IR_REG_V3, IR_REG_V4, IR_REG_V5, IR_REG_V6, IR_REG_V7}, + IR_REGSET_EMPTY, + +}; + +#ifdef __APPLE__ +# define ir_call_conv_default ir_call_conv_aarch64_darwin +#else +# define ir_call_conv_default ir_call_conv_aarch64_sysv +#endif + #define IR_RULES(_) \ _(CMP_INT) \ _(CMP_FP) \ @@ -342,6 +400,8 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co const ir_insn *insn; int n = 0; int flags = IR_USE_MUST_BE_IN_REG | IR_OP1_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG | IR_OP3_MUST_BE_IN_REG; + const ir_proto_t *proto; + const ir_call_conv_dsc *cc; constraints->def_reg = IR_REG_NONE; constraints->hints_count = 0; @@ -584,20 +644,33 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co n++; break; case IR_ARGVAL: - constraints->tmp_regs[0] = IR_SCRATCH_REG(IR_REG_SCRATCH, IR_DEF_SUB_REF - IR_SUB_REFS_COUNT, IR_USE_SUB_REF); + /* memcpy() clobbers all scratch registers */ + constraints->tmp_regs[0] = IR_SCRATCH_REG(IR_REG_SCRATCH_AARCH64, IR_DEF_SUB_REF - IR_SUB_REFS_COUNT, IR_USE_SUB_REF); n = 1; break; case IR_CALL: insn = &ctx->ir_base[ref]; - constraints->def_reg = (IR_IS_TYPE_INT(insn->type)) ? IR_REG_INT_RET1 : IR_REG_FP_RET1; - constraints->tmp_regs[0] = IR_SCRATCH_REG(IR_REG_SCRATCH, IR_USE_SUB_REF, IR_DEF_SUB_REF); + proto = ir_call_proto(ctx, insn); + cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + if (insn->type != IR_VOID) { + constraints->def_reg = (IR_IS_TYPE_INT(insn->type)) ? + cc->int_ret_reg : cc->fp_ret_reg; + } + constraints->tmp_regs[0] = IR_SCRATCH_REG(cc->scratch_reg, IR_USE_SUB_REF, IR_DEF_SUB_REF); n = 1; - IR_FALLTHROUGH; + if (insn->inputs_count > 2) { + goto get_arg_hints; + } + flags = IR_USE_SHOULD_BE_IN_REG | IR_OP2_MUST_BE_IN_REG | IR_OP3_SHOULD_BE_IN_REG; + break; case IR_TAILCALL: insn = &ctx->ir_base[ref]; if (insn->inputs_count > 2) { + proto = ir_call_proto(ctx, insn); + cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); +get_arg_hints: constraints->hints[2] = IR_REG_NONE; - constraints->hints_count = ir_get_args_regs(ctx, insn, constraints->hints); + constraints->hints_count = ir_get_args_regs(ctx, insn, cc, constraints->hints); if (!IR_IS_CONST_REF(insn->op2)) { constraints->tmp_regs[n] = IR_TMP_REG(1, IR_ADDR, IR_LOAD_SUB_REF, IR_USE_SUB_REF); n++; @@ -658,19 +731,22 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co flags = IR_USE_SHOULD_BE_IN_REG; break; case IR_EXITCALL: - constraints->def_reg = IR_REG_INT_RET1; + cc = ir_get_call_conv_dsc(ctx->flags); + constraints->def_reg = cc->int_ret_reg; break; case IR_RSTORE: flags = IR_OP3_SHOULD_BE_IN_REG; break; case IR_RETURN_INT: + cc = ir_get_call_conv_dsc(ctx->flags); flags = IR_OP2_SHOULD_BE_IN_REG; - constraints->hints[2] = IR_REG_INT_RET1; + constraints->hints[2] = cc->int_ret_reg; constraints->hints_count = 3; break; case IR_RETURN_FP: + cc = ir_get_call_conv_dsc(ctx->flags); flags = IR_OP2_SHOULD_BE_IN_REG; - constraints->hints[2] = IR_REG_FP_RET1; + constraints->hints[2] = cc->fp_ret_reg; constraints->hints_count = 3; break; case IR_SNAPSHOT: @@ -1798,72 +1874,73 @@ static void ir_emit_prologue(ir_ctx *ctx) } } } + if ((ctx->flags & IR_VARARG_FUNC) && (ctx->flags2 & IR_HAS_VA_START)) { -#ifndef __APPLE__ - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; - ir_reg fp; - int offset; - int i; + const ir_call_conv_dsc *cc = data->ra_data.cc; - if (ctx->flags & IR_USE_FRAME_POINTER) { - fp = IR_REG_FRAME_POINTER; + if (cc->sysv_varargs) { + ir_reg fp; + int offset; + int i; - offset = ctx->locals_area_size + sizeof(void*) * 2; - } else { - fp = IR_REG_STACK_POINTER; - offset = ctx->locals_area_size + ctx->call_stack_size; - } + if (ctx->flags & IR_USE_FRAME_POINTER) { + fp = IR_REG_FRAME_POINTER; - if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < IR_REG_INT_ARGS) { - ir_reg prev = IR_REG_NONE; + offset = ctx->locals_area_size + sizeof(void*) * 2; + } else { + fp = IR_REG_STACK_POINTER; + offset = ctx->locals_area_size + ctx->call_stack_size; + } + + if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < cc->int_param_regs_count) { + ir_reg prev = IR_REG_NONE; - /* skip named args */ - offset += sizeof(void*) * ctx->gp_reg_params; - for (i = ctx->gp_reg_params; i < IR_REG_INT_ARGS; i++) { + /* skip named args */ + offset += sizeof(void*) * ctx->gp_reg_params; + for (i = ctx->gp_reg_params; i < cc->int_param_regs_count; i++) { + if (prev != IR_REG_NONE) { + if (aarch64_may_encode_imm7_addr_offset(offset, 8)) { + | stp Rx(prev), Rx(cc->int_param_regs[i]), [Rx(fp), #offset] + } else if (aarch64_may_encode_addr_offset(offset + 8, 8)) { + | str Rx(prev), [Rx(fp), #offset] + | str Rx(cc->int_param_regs[i]), [Rx(fp), #(offset+8)] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + | add Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 + | str Rx(cc->int_param_regs[i]), [Rx(fp), Rx(IR_REG_INT_TMP)] + } + prev = IR_REG_NONE; + offset += sizeof(void*) * 2; + } else { + prev = cc->int_param_regs[i]; + } + } if (prev != IR_REG_NONE) { - if (aarch64_may_encode_imm7_addr_offset(offset, 8)) { - | stp Rx(prev), Rx(int_reg_params[i]), [Rx(fp), #offset] - } else if (aarch64_may_encode_addr_offset(offset + 8, 8)) { + if (aarch64_may_encode_addr_offset(offset + 8, 8)) { | str Rx(prev), [Rx(fp), #offset] - | str Rx(int_reg_params[i]), [Rx(fp), #(offset+8)] } else { ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] - | add Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 - | str Rx(int_reg_params[i]), [Rx(fp), Rx(IR_REG_INT_TMP)] } - prev = IR_REG_NONE; - offset += sizeof(void*) * 2; - } else { - prev = int_reg_params[i]; + offset += sizeof(void*); } } - if (prev != IR_REG_NONE) { - if (aarch64_may_encode_addr_offset(offset + 8, 8)) { - | str Rx(prev), [Rx(fp), #offset] - } else { - ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); - | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] - } - offset += sizeof(void*); - } - } - if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < IR_REG_FP_ARGS) { - /* skip named args */ - offset += 16 * ctx->fp_reg_params; - for (i = ctx->fp_reg_params; i < IR_REG_FP_ARGS; i++) { - // TODO: Rd->Rq stur->str ??? - 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)] + if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < cc->fp_param_regs_count) { + /* skip named args */ + offset += 16 * ctx->fp_reg_params; + for (i = ctx->fp_reg_params; i < cc->fp_param_regs_count; i++) { + // TODO: Rd->Rq stur->str ??? + if (aarch64_may_encode_addr_offset(offset, 8)) { + | str Rd(cc->fp_param_regs[i]-IR_REG_FP_FIRST), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rd(cc->fp_param_regs[i]-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] + } + offset += 16; } - offset += 16; } } -#endif } } @@ -3257,10 +3334,6 @@ static void ir_emit_jcc(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn, uint break; case IR_UNORDERED: | bvs =>true_block -// case IR_ULT: fprintf(stderr, "\tjb .LL%d\n", true_block); break; -// case IR_UGE: fprintf(stderr, "\tjae .LL%d\n", true_block); break; -// case IR_ULE: fprintf(stderr, "\tjbe .LL%d\n", true_block); break; -// case IR_UGT: fprintf(stderr, "\tja .LL%d\n", true_block); break; } } if (false_block) { @@ -3434,15 +3507,17 @@ static void ir_emit_return_void(ir_ctx *ctx) static void ir_emit_return_int(ir_ctx *ctx, ir_ref ref, ir_insn *insn) { + ir_backend_data *data = ctx->data; + ir_reg ret_reg = data->ra_data.cc->int_ret_reg; ir_reg op2_reg = ctx->regs[ref][2]; - if (op2_reg != IR_REG_INT_RET1) { + if (op2_reg != ret_reg) { ir_type type = ctx->ir_base[insn->op2].type; if (op2_reg != IR_REG_NONE && !IR_REG_SPILLED(op2_reg)) { - ir_emit_mov(ctx, type, IR_REG_INT_RET1, op2_reg); + ir_emit_mov(ctx, type, ret_reg, op2_reg); } else { - ir_emit_load(ctx, type, IR_REG_INT_RET1, insn->op2); + ir_emit_load(ctx, type, ret_reg, insn->op2); } } ir_emit_return_void(ctx); @@ -3450,14 +3525,16 @@ static void ir_emit_return_int(ir_ctx *ctx, ir_ref ref, ir_insn *insn) static void ir_emit_return_fp(ir_ctx *ctx, ir_ref ref, ir_insn *insn) { + ir_backend_data *data = ctx->data; + ir_reg ret_reg = data->ra_data.cc->fp_ret_reg; ir_reg op2_reg = ctx->regs[ref][2]; ir_type type = ctx->ir_base[insn->op2].type; - if (op2_reg != IR_REG_FP_RET1) { + if (op2_reg != ret_reg) { if (op2_reg != IR_REG_NONE && !IR_REG_SPILLED(op2_reg)) { - ir_emit_fp_mov(ctx, type, IR_REG_FP_RET1, op2_reg); + ir_emit_fp_mov(ctx, type, ret_reg, op2_reg); } else { - ir_emit_load(ctx, type, IR_REG_FP_RET1, insn->op2); + ir_emit_load(ctx, type, ret_reg, insn->op2); } } ir_emit_return_void(ctx); @@ -4461,281 +4538,281 @@ static void ir_emit_frame_addr(ir_ctx *ctx, ir_ref def) static void ir_emit_va_start(ir_ctx *ctx, ir_ref def, ir_insn *insn) { -#ifdef __APPLE__ ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; dasm_State **Dst = &data->dasm_state; - ir_reg fp; - int arg_area_offset; - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg tmp_reg = ctx->regs[def][3]; - int32_t offset; - IR_ASSERT(tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + if (!cc->sysv_varargs) { + ir_reg fp; + int arg_area_offset; + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg tmp_reg = ctx->regs[def][3]; + int32_t offset; + + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (ctx->flags & IR_USE_FRAME_POINTER) { - fp = IR_REG_FRAME_POINTER; - arg_area_offset = ctx->stack_frame_size + sizeof(void*) * 2 + ctx->param_stack_size; + if (ctx->flags & IR_USE_FRAME_POINTER) { + fp = IR_REG_FRAME_POINTER; + arg_area_offset = ctx->stack_frame_size + sizeof(void*) * 2 + ctx->param_stack_size; + } else { + fp = IR_REG_STACK_POINTER; + arg_area_offset = ctx->call_stack_size + ctx->stack_frame_size + ctx->param_stack_size; + } + | add Rx(tmp_reg), Rx(fp), #arg_area_offset + | str Rx(tmp_reg), [Rx(op2_reg), #offset] } else { - fp = IR_REG_STACK_POINTER; - arg_area_offset = ctx->call_stack_size + ctx->stack_frame_size + ctx->param_stack_size; - } - | add Rx(tmp_reg), Rx(fp), #arg_area_offset - | str Rx(tmp_reg), [Rx(op2_reg), #offset] -#else - ir_backend_data *data = ctx->data; - dasm_State **Dst = &data->dasm_state; - ir_reg fp; - int reg_save_area_offset; - int overflow_arg_area_offset; - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg tmp_reg = ctx->regs[def][3]; - int32_t offset; + ir_reg fp; + int reg_save_area_offset; + int overflow_arg_area_offset; + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg tmp_reg = ctx->regs[def][3]; + int32_t offset; - IR_ASSERT(tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (ctx->flags & IR_USE_FRAME_POINTER) { - fp = IR_REG_FRAME_POINTER; - reg_save_area_offset = ctx->locals_area_size + sizeof(void*) * 2; - overflow_arg_area_offset = ctx->stack_frame_size + sizeof(void*) * 2 + ctx->param_stack_size; - } else { - fp = IR_REG_STACK_POINTER; - reg_save_area_offset = ctx->locals_area_size + ctx->call_stack_size; - overflow_arg_area_offset = ctx->call_stack_size + ctx->stack_frame_size + ctx->param_stack_size; - } - - /* Set va_list.stack */ - | add Rx(tmp_reg), Rx(fp), #overflow_arg_area_offset - | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))] - if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < IR_REG_INT_ARGS) { - reg_save_area_offset += sizeof(void*) * IR_REG_INT_ARGS; - /* Set va_list.gr_top */ - if (overflow_arg_area_offset != reg_save_area_offset) { - | add Rx(tmp_reg), Rx(fp), #reg_save_area_offset - } - | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, gr_top))] - /* Set va_list.gr_offset */ - | movn Rw(tmp_reg), #~(0 - (sizeof(void*) * (IR_REG_INT_ARGS - ctx->gp_reg_params))) - | str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, gr_offset))] - } else { - /* Set va_list.gr_offset */ - | str wzr, [Rx(op2_reg), #(offset+offsetof(ir_va_list, gr_offset))] - } - 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 || 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))] - /* Set va_list.vr_offset */ - | movn Rw(tmp_reg), #~(0 - (16 * (IR_REG_FP_ARGS - ctx->fp_reg_params))) - | str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, vr_offset))] - } else { - /* Set va_list.vr_offset */ - | str wzr, [Rx(op2_reg), #(offset+offsetof(ir_va_list, vr_offset))] + if (ctx->flags & IR_USE_FRAME_POINTER) { + fp = IR_REG_FRAME_POINTER; + reg_save_area_offset = ctx->locals_area_size + sizeof(void*) * 2; + overflow_arg_area_offset = ctx->stack_frame_size + sizeof(void*) * 2 + ctx->param_stack_size; + } else { + fp = IR_REG_STACK_POINTER; + reg_save_area_offset = ctx->locals_area_size + ctx->call_stack_size; + overflow_arg_area_offset = ctx->call_stack_size + ctx->stack_frame_size + ctx->param_stack_size; + } + + /* Set va_list.stack */ + | add Rx(tmp_reg), Rx(fp), #overflow_arg_area_offset + | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, stack))] + if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < cc->int_param_regs_count) { + reg_save_area_offset += sizeof(void*) * cc->int_param_regs_count; + /* Set va_list.gr_top */ + if (overflow_arg_area_offset != reg_save_area_offset) { + | add Rx(tmp_reg), Rx(fp), #reg_save_area_offset + } + | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, gr_top))] + /* Set va_list.gr_offset */ + | movn Rw(tmp_reg), #~(0 - (sizeof(void*) * (cc->int_param_regs_count - ctx->gp_reg_params))) + | str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, gr_offset))] + } else { + /* Set va_list.gr_offset */ + | str wzr, [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, gr_offset))] + } + if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < cc->fp_param_regs_count) { + reg_save_area_offset += 16 * cc->fp_param_regs_count; + /* Set va_list.vr_top */ + if (overflow_arg_area_offset != reg_save_area_offset || ctx->gp_reg_params < cc->int_param_regs_count) { + | add Rx(tmp_reg), Rx(fp), #reg_save_area_offset + } + | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, vr_top))] + /* Set va_list.vr_offset */ + | movn Rw(tmp_reg), #~(0 - (16 * (cc->fp_param_regs_count - ctx->fp_reg_params))) + | str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, vr_offset))] + } else { + /* Set va_list.vr_offset */ + | str wzr, [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, vr_offset))] + } } -#endif } static void ir_emit_va_copy(ir_ctx *ctx, ir_ref def, ir_insn *insn) { -#ifdef __APPLE__ ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; dasm_State **Dst = &data->dasm_state; - ir_reg tmp_reg = ctx->regs[def][1]; - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg op3_reg = ctx->regs[def][3]; - int32_t op2_offset, op3_offset; - IR_ASSERT(tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + if (!cc->sysv_varargs) { + ir_reg tmp_reg = ctx->regs[def][1]; + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg op3_reg = ctx->regs[def][3]; + int32_t op2_offset, op3_offset; + + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + op2_offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + op2_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - op2_offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - op2_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (op3_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op3_reg)) { - op3_reg = IR_REG_NUM(op3_reg); - ir_emit_load(ctx, IR_ADDR, op3_reg, insn->op3); + if (op3_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op3_reg)) { + op3_reg = IR_REG_NUM(op3_reg); + ir_emit_load(ctx, IR_ADDR, op3_reg, insn->op3); + } + op3_offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA); + op3_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + op3_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op3]); } - op3_offset = 0; + | ldr Rx(tmp_reg), [Rx(op3_reg), #op3_offset] + | str Rx(tmp_reg), [Rx(op2_reg), #op2_offset] } else { - IR_ASSERT(ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA); - op3_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - op3_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op3]); - } - | ldr Rx(tmp_reg), [Rx(op3_reg), #op3_offset] - | str Rx(tmp_reg), [Rx(op2_reg), #op2_offset] -#else - ir_backend_data *data = ctx->data; - dasm_State **Dst = &data->dasm_state; - ir_reg tmp_reg = ctx->regs[def][1]; - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg op3_reg = ctx->regs[def][3]; - int32_t op2_offset, op3_offset; + ir_reg tmp_reg = ctx->regs[def][1]; + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg op3_reg = ctx->regs[def][3]; + int32_t op2_offset, op3_offset; - IR_ASSERT(tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + op2_offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + op2_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - op2_offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - op2_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); + if (op3_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op3_reg)) { + op3_reg = IR_REG_NUM(op3_reg); + ir_emit_load(ctx, IR_ADDR, op3_reg, insn->op3); + } + op3_offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA); + op3_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + op3_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op3]); + } + | ldr Rx(tmp_reg), [Rx(op3_reg), #op3_offset] + | str Rx(tmp_reg), [Rx(op2_reg), #op2_offset] + | ldr Rx(tmp_reg), [Rx(op3_reg), #(op3_offset+8)] + | str Rx(tmp_reg), [Rx(op2_reg), #(op2_offset+8)] + | ldr Rx(tmp_reg), [Rx(op3_reg), #(op3_offset+16)] + | str Rx(tmp_reg), [Rx(op2_reg), #(op2_offset+16)] + | ldr Rx(tmp_reg), [Rx(op3_reg), #(op3_offset+24)] + | str Rx(tmp_reg), [Rx(op2_reg), #(op2_offset+24)] } - if (op3_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op3_reg)) { - op3_reg = IR_REG_NUM(op3_reg); - ir_emit_load(ctx, IR_ADDR, op3_reg, insn->op3); - } - op3_offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA); - op3_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - op3_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op3]); - } - | ldr Rx(tmp_reg), [Rx(op3_reg), #op3_offset] - | str Rx(tmp_reg), [Rx(op2_reg), #op2_offset] - | ldr Rx(tmp_reg), [Rx(op3_reg), #(op3_offset+8)] - | str Rx(tmp_reg), [Rx(op2_reg), #(op2_offset+8)] - | ldr Rx(tmp_reg), [Rx(op3_reg), #(op3_offset+16)] - | str Rx(tmp_reg), [Rx(op2_reg), #(op2_offset+16)] - | ldr Rx(tmp_reg), [Rx(op3_reg), #(op3_offset+24)] - | str Rx(tmp_reg), [Rx(op2_reg), #(op2_offset+24)] -#endif } static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn) { -#ifdef __APPLE__ ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; dasm_State **Dst = &data->dasm_state; - ir_type type = insn->type; - ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg tmp_reg = ctx->regs[def][3]; - int32_t offset; - IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); - } - offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - | ldr Rx(tmp_reg), [Rx(op2_reg), #offset] - if (def_reg != IR_REG_NONE) { - ir_emit_load_mem(ctx, type, def_reg, IR_MEM_BO(tmp_reg, 0)); - } - | add Rx(tmp_reg), Rx(tmp_reg), #IR_MAX(ir_type_size[type], sizeof(void*)) - | str Rx(tmp_reg), [Rx(op2_reg), #offset] - if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) { - ir_emit_store(ctx, type, def, def_reg); - } -#else - ir_backend_data *data = ctx->data; - dasm_State **Dst = &data->dasm_state; - ir_type type = insn->type; - ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg tmp_reg = ctx->regs[def][3]; - int32_t offset; + if (!cc->sysv_varargs) { + ir_type type = insn->type; + ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg tmp_reg = ctx->regs[def][3]; + int32_t offset; - IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (IR_IS_TYPE_INT(type)) { - | ldr Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, gr_offset))] - | cmp Rw(tmp_reg), wzr - | bge >1 - | ldr Rx(IR_REG_INT_TMP), [Rx(op2_reg), #(offset+offsetof(ir_va_list, gr_top))] - | sxtw Rx(tmp_reg), Rw(tmp_reg) - | add Rx(IR_REG_INT_TMP), Rx(tmp_reg), Rx(IR_REG_INT_TMP) + | ldr Rx(tmp_reg), [Rx(op2_reg), #offset] if (def_reg != IR_REG_NONE) { - | ldr Rx(def_reg), [Rx(IR_REG_INT_TMP)] + ir_emit_load_mem(ctx, type, def_reg, IR_MEM_BO(tmp_reg, 0)); } - | add Rw(tmp_reg), Rw(tmp_reg), #sizeof(void*) - | str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, gr_offset))] - | b >2 - |1: - | ldr Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))] - if (def_reg != IR_REG_NONE) { - | ldr Rx(def_reg), [Rx(tmp_reg)] + | add Rx(tmp_reg), Rx(tmp_reg), #IR_MAX(ir_type_size[type], sizeof(void*)) + | str Rx(tmp_reg), [Rx(op2_reg), #offset] + if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) { + ir_emit_store(ctx, type, def, def_reg); } - | add Rx(tmp_reg), Rx(tmp_reg), #sizeof(void*) - | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))] - |2: } else { - | ldr Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, vr_offset))] - | cmp Rw(tmp_reg), wzr - | bge >1 - | ldr Rx(IR_REG_INT_TMP), [Rx(op2_reg), #(offset+offsetof(ir_va_list, vr_top))] - | sxtw Rx(tmp_reg), Rw(tmp_reg) - | add Rx(IR_REG_INT_TMP), Rx(tmp_reg), Rx(IR_REG_INT_TMP) - if (def_reg != IR_REG_NONE) { - | ldr Rd(def_reg-IR_REG_FP_FIRST), [Rx(IR_REG_INT_TMP)] + ir_type type = insn->type; + ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg tmp_reg = ctx->regs[def][3]; + int32_t offset; + + IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - | add Rw(tmp_reg), Rw(tmp_reg), #16 - | str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, vr_offset))] - | b >2 - |1: - | ldr Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))] - if (def_reg != IR_REG_NONE) { - | ldr Rd(def_reg-IR_REG_FP_FIRST), [Rx(tmp_reg)] + if (IR_IS_TYPE_INT(type)) { + | ldr Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, gr_offset))] + | cmp Rw(tmp_reg), wzr + | bge >1 + | ldr Rx(IR_REG_INT_TMP), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, gr_top))] + | sxtw Rx(tmp_reg), Rw(tmp_reg) + | add Rx(IR_REG_INT_TMP), Rx(tmp_reg), Rx(IR_REG_INT_TMP) + if (def_reg != IR_REG_NONE) { + | ldr Rx(def_reg), [Rx(IR_REG_INT_TMP)] + } + | add Rw(tmp_reg), Rw(tmp_reg), #sizeof(void*) + | str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, gr_offset))] + | b >2 + |1: + | ldr Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, stack))] + if (def_reg != IR_REG_NONE) { + | ldr Rx(def_reg), [Rx(tmp_reg)] + } + | add Rx(tmp_reg), Rx(tmp_reg), #sizeof(void*) + | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, stack))] + |2: + } else { + | ldr Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, vr_offset))] + | cmp Rw(tmp_reg), wzr + | bge >1 + | ldr Rx(IR_REG_INT_TMP), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, vr_top))] + | sxtw Rx(tmp_reg), Rw(tmp_reg) + | add Rx(IR_REG_INT_TMP), Rx(tmp_reg), Rx(IR_REG_INT_TMP) + if (def_reg != IR_REG_NONE) { + | ldr Rd(def_reg-IR_REG_FP_FIRST), [Rx(IR_REG_INT_TMP)] + } + | add Rw(tmp_reg), Rw(tmp_reg), #16 + | str Rw(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, vr_offset))] + | b >2 + |1: + | ldr Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, stack))] + if (def_reg != IR_REG_NONE) { + | ldr Rd(def_reg-IR_REG_FP_FIRST), [Rx(tmp_reg)] + } + | add Rx(tmp_reg), Rx(tmp_reg), #sizeof(void*) + | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_aarch64_sysv_va_list, stack))] + |2: + } + if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) { + ir_emit_store(ctx, type, def, def_reg); } - | add Rx(tmp_reg), Rx(tmp_reg), #sizeof(void*) - | str Rx(tmp_reg), [Rx(op2_reg), #(offset+offsetof(ir_va_list, stack))] - |2: } - if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) { - ir_emit_store(ctx, type, def, def_reg); - } -#endif } static void ir_emit_switch(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn) @@ -4958,19 +5035,23 @@ static void ir_emit_switch(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn) } } -static int32_t ir_call_used_stack(ir_ctx *ctx, ir_insn *insn, int32_t *copy_stack_ptr) +static int32_t ir_call_used_stack(ir_ctx *ctx, ir_insn *insn, const ir_call_conv_dsc *cc, int32_t *copy_stack_ptr) { int j, n; ir_type type; int int_param = 0; int fp_param = 0; - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; int32_t used_stack = 0, copy_stack = 0; -#ifdef __APPLE__ - const ir_proto_t *proto = ir_call_proto(ctx, insn); - int last_named_input = (proto && (proto->flags & IR_VARARG_FUNC)) ? proto->params_count + 2 : insn->inputs_count; -#endif + + /* On APPLE "unnamed" arguments always passed through stack */ + int last_named_input; + + if (!cc->sysv_varargs) { + const ir_proto_t *proto = ir_call_proto(ctx, insn); + last_named_input = (proto && (proto->flags & IR_VARARG_FUNC)) ? proto->params_count + 2 : insn->inputs_count; + } else { + last_named_input = insn->inputs_count; + } n = insn->inputs_count; for (j = 3; j <= n; j++) { @@ -4984,19 +5065,16 @@ static int32_t ir_call_used_stack(ir_ctx *ctx, ir_insn *insn, int32_t *copy_stac copy_stack = IR_ALIGNED_SIZE(copy_stack, align); type = IR_ADDR; } -#ifdef __APPLE__ if (j > last_named_input) { used_stack += IR_MAX(sizeof(void*), ir_type_size[type]); - } else -#endif - if (IR_IS_TYPE_INT(type)) { - if (int_param >= int_reg_params_count) { + } else if (IR_IS_TYPE_INT(type)) { + if (int_param >= cc->int_param_regs_count) { used_stack += IR_MAX(sizeof(void*), ir_type_size[type]); } int_param++; } else { IR_ASSERT(IR_IS_TYPE_FP(type)); - if (fp_param >= fp_reg_params_count) { + if (fp_param >= cc->fp_param_regs_count) { used_stack += IR_MAX(sizeof(void*), ir_type_size[type]); } fp_param++; @@ -5008,7 +5086,7 @@ static int32_t ir_call_used_stack(ir_ctx *ctx, ir_insn *insn, int32_t *copy_stac return used_stack + copy_stack; } -static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg tmp_reg) +static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const ir_call_conv_dsc *cc, ir_reg tmp_reg) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; @@ -5020,10 +5098,6 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg int int_param = 0; int fp_param = 0; int count = 0; - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; int32_t used_stack, copy_stack = 0, stack_offset = 0, copy_stack_offset = 0; ir_copy *copies; bool do_pass3 = 0; @@ -5043,7 +5117,7 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg // TODO: support for preallocated stack used_stack = 0; } else { - used_stack = ir_call_used_stack(ctx, insn, ©_stack); + used_stack = ir_call_used_stack(ctx, insn, cc, ©_stack); /* Stack must be 16 byte aligned */ used_stack = IR_ALIGNED_SIZE(used_stack, 16); if (ctx->fixed_call_stack_size && used_stack <= ctx->fixed_call_stack_size) { @@ -5061,10 +5135,15 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg } } -#ifdef __APPLE__ - const ir_proto_t *proto = ir_call_proto(ctx, insn); - int last_named_input = (proto && (proto->flags & IR_VARARG_FUNC)) ? proto->params_count + 2 : insn->inputs_count; -#endif + /* On APPLE "unnamed" arguments always passed through stack */ + int last_named_input; + + if (!cc->sysv_varargs) { + const ir_proto_t *proto = ir_call_proto(ctx, insn); + last_named_input = (proto && (proto->flags & IR_VARARG_FUNC)) ? proto->params_count + 2 : insn->inputs_count; + } else { + last_named_input = insn->inputs_count; + } if (copy_stack) { /* Copy struct arguments */ @@ -5085,17 +5164,17 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg copy_stack_offset = IR_ALIGNED_SIZE(copy_stack_offset, align); src_reg = ctx->regs[arg][1]; - | add Rx(IR_REG_INT_ARG1), sp, #(used_stack - copy_stack_offset) + | add Rx(ir_call_conv_default.int_param_regs[0]), sp, #(used_stack - copy_stack_offset) if (src_reg != IR_REG_NONE) { if (IR_REG_SPILLED(src_reg)) { src_reg = IR_REG_NUM(src_reg); ir_emit_load(ctx, IR_ADDR, src_reg, arg_insn->op1); } - | mov Rx(IR_REG_INT_ARG2), Rx(src_reg) + | mov Rx(ir_call_conv_default.int_param_regs[1]), Rx(src_reg) } else { - ir_emit_load(ctx, IR_ADDR, IR_REG_INT_ARG2, arg_insn->op1); + ir_emit_load(ctx, IR_ADDR, ir_call_conv_default.int_param_regs[1], arg_insn->op1); } - ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_ARG3, size); + ir_emit_load_imm_int(ctx, IR_ADDR, ir_call_conv_default.int_param_regs[2], size); if (aarch64_may_use_b(ctx->code_buffer, addr)) { | bl &addr @@ -5117,18 +5196,15 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg arg_insn = &ctx->ir_base[arg]; type = arg_insn->type; -#ifdef __APPLE__ if (j > last_named_input) { if (arg_insn->op == IR_ARGVAL) { do_pass3 = 1; continue; } dst_reg = IR_REG_NONE; /* pass argument through stack */ - } else -#endif - if (IR_IS_TYPE_INT(type)) { - if (int_param < int_reg_params_count) { - dst_reg = int_reg_params[int_param]; + } else if (IR_IS_TYPE_INT(type)) { + if (int_param < cc->int_param_regs_count) { + dst_reg = cc->int_param_regs[int_param]; } else { dst_reg = IR_REG_NONE; /* pass argument through stack */ } @@ -5139,8 +5215,8 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg } } else { IR_ASSERT(IR_IS_TYPE_FP(type)); - if (fp_param < fp_reg_params_count) { - dst_reg = fp_reg_params[fp_param]; + if (fp_param < cc->fp_param_regs_count) { + dst_reg = cc->fp_param_regs[fp_param]; } else { dst_reg = IR_REG_NONE; /* pass argument through stack */ } @@ -5149,7 +5225,7 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg if (dst_reg != IR_REG_NONE) { if (IR_IS_CONST_REF(arg) || src_reg == IR_REG_NONE || - (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(IR_REGSET_PRESERVED, IR_REG_NUM(src_reg)))) { + (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) { /* delay CONST->REG and MEM->REG moves to third pass */ do_pass3 = 1; } else { @@ -5201,14 +5277,11 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg copy_stack_offset += size; align = IR_MAX((int)sizeof(void*), align); copy_stack_offset = IR_ALIGNED_SIZE(copy_stack_offset, align); -#ifdef __APPLE__ if (j > last_named_input) { | add Rx(tmp_reg), sp, #(used_stack - copy_stack_offset) ir_emit_store_mem_int(ctx, IR_ADDR, IR_MEM_BO(IR_REG_STACK_POINTER, stack_offset), tmp_reg); - } else -#endif - if (int_param < int_reg_params_count) { - dst_reg = int_reg_params[int_param]; + } else if (int_param < cc->int_param_regs_count) { + dst_reg = cc->int_param_regs[int_param]; | add Rx(dst_reg), sp, #(used_stack - copy_stack_offset) } else { | add Rx(tmp_reg), sp, #(used_stack - copy_stack_offset) @@ -5218,22 +5291,19 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg int_param++; continue; } -#ifdef __APPLE__ if (j > last_named_input) { dst_reg = IR_REG_NONE; /* pass argument through stack */ - } else -#endif - if (IR_IS_TYPE_INT(type)) { - if (int_param < int_reg_params_count) { - dst_reg = int_reg_params[int_param]; + } else if (IR_IS_TYPE_INT(type)) { + if (int_param < cc->int_param_regs_count) { + dst_reg = cc->int_param_regs[int_param]; } else { dst_reg = IR_REG_NONE; /* argument already passed through stack */ } int_param++; } else { IR_ASSERT(IR_IS_TYPE_FP(type)); - if (fp_param < fp_reg_params_count) { - dst_reg = fp_reg_params[fp_param]; + if (fp_param < cc->fp_param_regs_count) { + dst_reg = cc->fp_param_regs[fp_param]; } else { dst_reg = IR_REG_NONE; /* argument already passed through stack */ } @@ -5242,7 +5312,7 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg if (dst_reg != IR_REG_NONE) { if (IR_IS_CONST_REF(arg) || src_reg == IR_REG_NONE || - (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(IR_REGSET_PRESERVED, IR_REG_NUM(src_reg)))) { + (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) { if (IR_IS_CONST_REF(arg) && IR_IS_TYPE_INT(type)) { if (ir_type_size[type] == 1) { type = IR_ADDR; @@ -5282,7 +5352,7 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg return used_stack; } -static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, int32_t used_stack) +static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, const ir_call_conv_dsc *cc, int32_t used_stack) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; @@ -5317,27 +5387,27 @@ static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, int32_t used if (IR_IS_TYPE_INT(insn->type)) { def_reg = IR_REG_NUM(ctx->regs[def][0]); if (def_reg != IR_REG_NONE) { - if (def_reg != IR_REG_INT_RET1) { - ir_emit_mov(ctx, insn->type, def_reg, IR_REG_INT_RET1); + if (def_reg != cc->int_ret_reg) { + ir_emit_mov(ctx, insn->type, def_reg, cc->int_ret_reg); } if (IR_REG_SPILLED(ctx->regs[def][0])) { ir_emit_store(ctx, insn->type, def, def_reg); } } else if (ctx->use_lists[def].count > 1) { - ir_emit_store(ctx, insn->type, def, IR_REG_INT_RET1); + ir_emit_store(ctx, insn->type, def, cc->int_ret_reg); } } else { IR_ASSERT(IR_IS_TYPE_FP(insn->type)); def_reg = IR_REG_NUM(ctx->regs[def][0]); if (def_reg != IR_REG_NONE) { - if (def_reg != IR_REG_FP_RET1) { - ir_emit_fp_mov(ctx, insn->type, def_reg, IR_REG_FP_RET1); + if (def_reg != cc->fp_ret_reg) { + ir_emit_fp_mov(ctx, insn->type, def_reg, cc->fp_ret_reg); } if (IR_REG_SPILLED(ctx->regs[def][0])) { ir_emit_store(ctx, insn->type, def, def_reg); } } else if (ctx->use_lists[def].count > 1) { - ir_emit_store(ctx, insn->type, def, IR_REG_FP_RET1); + ir_emit_store(ctx, insn->type, def, cc->fp_ret_reg); } } } @@ -5345,18 +5415,22 @@ static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, int32_t used static void ir_emit_call(ir_ctx *ctx, ir_ref def, ir_insn *insn) { - int32_t used_stack = ir_emit_arguments(ctx, def, insn, ctx->regs[def][1]); - ir_emit_call_ex(ctx, def, insn, used_stack); + const ir_proto_t *proto = ir_call_proto(ctx, insn); + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + int32_t used_stack = ir_emit_arguments(ctx, def, insn, cc, ctx->regs[def][1]); + ir_emit_call_ex(ctx, def, insn, cc, used_stack); } static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; - int32_t used_stack = ir_emit_arguments(ctx, def, insn, ctx->regs[def][1]); + const ir_proto_t *proto = ir_call_proto(ctx, insn); + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + int32_t used_stack = ir_emit_arguments(ctx, def, insn, cc, ctx->regs[def][1]); if (used_stack != 0) { - ir_emit_call_ex(ctx, def, insn, used_stack); + ir_emit_call_ex(ctx, def, insn, cc, used_stack); ir_emit_return_void(ctx); return; } @@ -5578,15 +5652,23 @@ static void ir_emit_guard_jcc(ir_ctx *ctx, uint8_t op, void *addr, bool int_cmp) case IR_GT: | bgt &addr break; + case IR_ULT: + | blt &addr + break; + case IR_UGE: + | bhs &addr + break; + case IR_ULE: + | ble &addr + break; + case IR_UGT: + | bhi &addr + break; case IR_ORDERED: | bvc &addr break; case IR_UNORDERED: | bvs &addr -// case IR_ULT: fprintf(stderr, "\tjb .LL%d\n", true_block); break; -// case IR_UGE: fprintf(stderr, "\tjae .LL%d\n", true_block); break; -// case IR_ULE: fprintf(stderr, "\tjbe .LL%d\n", true_block); break; -// case IR_UGT: fprintf(stderr, "\tja .LL%d\n", true_block); break; } } } @@ -5660,7 +5742,11 @@ static void ir_emit_guard_cmp_fp(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *i void *addr = ir_jmp_addr(ctx, insn, &ctx->ir_base[insn->op3]); if (insn->op == IR_GUARD) { - op ^= 1; // reverse + if (op == IR_EQ || op == IR_NE || op == IR_ORDERED || op == IR_UNORDERED) { + op ^= 1; // reverse + } else { + op ^= 5; // reverse + } } ir_emit_guard_jcc(ctx, op, addr, 0); } @@ -5746,6 +5832,7 @@ static void ir_emit_tls(ir_ctx *ctx, ir_ref def, ir_insn *insn) static void ir_emit_exitcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) { ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = &ir_call_conv_default; dasm_State **Dst = &data->dasm_state; ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); @@ -5785,10 +5872,10 @@ static void ir_emit_exitcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) | stp x2, x3, [sp, #-16]! | stp x0, x1, [sp, #-16]! - | mov Rx(IR_REG_INT_ARG2), sp - | add Rx(IR_REG_INT_ARG1), Rx(IR_REG_INT_ARG2), #(32*8+32*8) - | str Rx(IR_REG_INT_ARG1), [sp, #(31*8)] - | mov Rx(IR_REG_INT_ARG1), Rx(IR_REG_INT_TMP) + | mov Rx(cc->int_param_regs[1]), sp + | add Rx(cc->int_param_regs[0]), Rx(cc->int_param_regs[1]), #(32*8+32*8) + | str Rx(cc->int_param_regs[0]), [sp, #(31*8)] + | mov Rx(cc->int_param_regs[0]), Rx(IR_REG_INT_TMP) if (IR_IS_CONST_REF(insn->op2)) { void *addr = ir_call_addr(ctx, insn, &ctx->ir_base[insn->op2]); @@ -5805,8 +5892,8 @@ static void ir_emit_exitcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) | add sp, sp, #(32*8+32*8) - if (def_reg != IR_REG_INT_RET1) { - ir_emit_mov(ctx, insn->type, def_reg, IR_REG_INT_RET1); + if (def_reg != cc->int_ret_reg) { + ir_emit_mov(ctx, insn->type, def_reg, cc->int_ret_reg); } if (IR_REG_SPILLED(ctx->regs[def][0])) { ir_emit_store(ctx, insn->type, def, def_reg); @@ -5852,11 +5939,8 @@ static void ir_emit_load_params(ir_ctx *ctx) int fp_param_num = 0; ir_reg src_reg; ir_reg dst_reg; - // TODO: Calling convention specific - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; + ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; int32_t stack_offset = 0; int32_t stack_start = ctx->stack_frame_size; @@ -5866,15 +5950,15 @@ static void ir_emit_load_params(ir_ctx *ctx) insn = &ctx->ir_base[use]; if (insn->op == IR_PARAM) { if (IR_IS_TYPE_INT(insn->type)) { - if (int_param_num < int_reg_params_count) { - src_reg = int_reg_params[int_param_num]; + if (int_param_num < cc->int_param_regs_count) { + src_reg = cc->int_param_regs[int_param_num]; } else { src_reg = IR_REG_NONE; } int_param_num++; } else { - if (fp_param_num < fp_reg_params_count) { - src_reg = fp_reg_params[fp_param_num]; + if (fp_param_num < cc->fp_param_regs_count) { + src_reg = cc->fp_param_regs[fp_param_num]; } else { src_reg = IR_REG_NONE; } @@ -5914,10 +5998,9 @@ static ir_reg ir_get_free_reg(ir_type type, ir_regset available) return IR_REGSET_FIRST(available); } -static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to) +static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to, void *dessa_from_block) { - ir_backend_data *data = ctx->data; - ir_ref ref = ctx->cfg_blocks[data->dessa_from_block].end; + ir_ref ref = ctx->cfg_blocks[(intptr_t)dessa_from_block].end; if (to == 0) { if (IR_IS_TYPE_INT(type)) { @@ -5953,11 +6036,8 @@ static void ir_fix_param_spills(ir_ctx *ctx) int int_param_num = 0; int fp_param_num = 0; ir_reg src_reg; - // TODO: Calling convention specific - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; + ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; int32_t stack_offset = 0; int32_t stack_start = ctx->stack_frame_size; @@ -5967,15 +6047,15 @@ static void ir_fix_param_spills(ir_ctx *ctx) insn = &ctx->ir_base[use]; if (insn->op == IR_PARAM) { if (IR_IS_TYPE_INT(insn->type)) { - if (int_param_num < int_reg_params_count) { - src_reg = int_reg_params[int_param_num]; + if (int_param_num < cc->int_param_regs_count) { + src_reg = cc->int_param_regs[int_param_num]; } else { src_reg = IR_REG_NONE; } int_param_num++; } else { - if (fp_param_num < fp_reg_params_count) { - src_reg = fp_reg_params[fp_param_num]; + if (fp_param_num < cc->fp_param_regs_count) { + src_reg = cc->fp_param_regs[fp_param_num]; } else { src_reg = IR_REG_NONE; } @@ -5999,8 +6079,8 @@ 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->gp_reg_params = IR_MIN(int_param_num, cc->int_param_regs_count); + ctx->fp_reg_params = IR_MIN(fp_param_num, cc->fp_param_regs_count); ctx->param_stack_size = stack_offset; } @@ -6011,11 +6091,13 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) ir_insn *insn; ir_ref i, n, j, *p; uint32_t *rule, insn_flags; - ir_backend_data *data = ctx->data; ir_regset available = 0; ir_target_constraints constraints; uint32_t def_flags; ir_reg reg; + ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; + ir_regset scratch = ir_scratch_regset[cc->scratch_reg - IR_REG_NUM]; ctx->regs = ir_mem_malloc(sizeof(ir_regs) * ctx->insns_count); memset(ctx->regs, IR_REG_NONE, sizeof(ir_regs) * ctx->insns_count); @@ -6051,7 +6133,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) && *rule != IR_CMP_AND_BRANCH_FP && *rule != IR_GUARD_CMP_INT && *rule != IR_GUARD_CMP_FP) { - available = IR_REGSET_SCRATCH; + available = scratch; } if (ctx->vregs[i]) { reg = constraints.def_reg; @@ -6081,7 +6163,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) if (insn->op == IR_PARAM && reg == IR_REG_NONE) { ival->flags |= IR_LIVE_INTERVAL_MEM_PARAM; } else { - ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type, &data->ra_data); + ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type); } } else if (insn->op == IR_PARAM) { IR_ASSERT(0 && "unexpected PARAM"); @@ -6092,7 +6174,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) ir_ref n = use_list->count; if (n > 0) { - int32_t stack_spill_pos = insn->op3 = ir_allocate_spill_slot(ctx, insn->type, &data->ra_data); + int32_t stack_spill_pos = insn->op3 = ir_allocate_spill_slot(ctx, insn->type); ir_ref i, *p, use; ir_insn *use_insn; @@ -6147,10 +6229,13 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) } } ctx->regs[i][constraints.tmp_regs[n].num] = reg; - } else if (constraints.tmp_regs[n].reg == IR_REG_SCRATCH) { - available = IR_REGSET_DIFFERENCE(available, IR_REGSET_SCRATCH); } else { - IR_REGSET_EXCL(available, constraints.tmp_regs[n].reg); + reg = constraints.tmp_regs[n].reg; + if (reg >= IR_REG_NUM) { + available = IR_REGSET_DIFFERENCE(available, ir_scratch_regset[reg - IR_REG_NUM]); + } else { + IR_REGSET_EXCL(available, reg); + } } } while (n); } @@ -6186,8 +6271,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) rule += n; } if (bb->flags & IR_BB_DESSA_MOVES) { - data->dessa_from_block = b; - ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps); + ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps, (void*)(intptr_t)b); } } @@ -6204,8 +6288,11 @@ static void ir_preallocate_call_stack(ir_ctx *ctx) for (i = 1, insn = ctx->ir_base + 1; i < ctx->insns_count;) { if (insn->op == IR_CALL) { + const ir_proto_t *proto = ir_call_proto(ctx, insn); + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); int32_t copy_stack; - call_stack_size = ir_call_used_stack(ctx, insn, ©_stack); + + call_stack_size = ir_call_used_stack(ctx, insn, cc, ©_stack); if (call_stack_size > peak_call_stack_size) { peak_call_stack_size = call_stack_size; } @@ -6237,11 +6324,14 @@ void ir_fix_stack_frame(ir_ctx *ctx) } if ((ctx->flags & IR_VARARG_FUNC) && (ctx->flags2 & IR_HAS_VA_START)) { - if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < IR_REG_INT_ARGS) { - additional_size += sizeof(void*) * IR_REG_INT_ARGS; + ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; + + if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < cc->int_param_regs_count) { + additional_size += sizeof(void*) * cc->int_param_regs_count; } - if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < IR_REG_FP_ARGS) { - additional_size += 16 * IR_REG_FP_ARGS; + if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < cc->fp_param_regs_count) { + additional_size += 16 * cc->int_param_regs_count; } } @@ -6308,6 +6398,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) ir_ref igoto_dup_ref = IR_UNUSED; uint32_t igoto_dup_block = 0; + data.ra_data.cc = ir_get_call_conv_dsc(ctx->flags); data.ra_data.unused_slot_4 = 0; data.ra_data.unused_slot_2 = 0; data.ra_data.unused_slot_1 = 0; diff --git a/ext/opcache/jit/ir/ir_aarch64.h b/ext/opcache/jit/ir/ir_aarch64.h index 9da64b9249f72..e0817f9b3303f 100644 --- a/ext/opcache/jit/ir/ir_aarch64.h +++ b/ext/opcache/jit/ir/ir_aarch64.h @@ -87,14 +87,15 @@ enum _ir_reg { IR_GP_REGS(IR_GP_REG_ENUM) IR_FP_REGS(IR_FP_REG_ENUM) IR_REG_NUM, + IR_REG_ALL = IR_REG_NUM, /* special name for regset */ + IR_REG_SET_1, /* special name for regset */ + IR_REG_SET_NUM, }; #define IR_REG_GP_FIRST IR_REG_X0 #define IR_REG_FP_FIRST IR_REG_V0 #define IR_REG_GP_LAST (IR_REG_FP_FIRST - 1) #define IR_REG_FP_LAST (IR_REG_NUM - 1) -#define IR_REG_SCRATCH (IR_REG_NUM) /* special name for regset */ -#define IR_REG_ALL (IR_REG_NUM + 1) /* special name for regset */ #define IR_REGSET_64BIT 1 @@ -125,65 +126,4 @@ enum _ir_reg { #define IR_REG_LR IR_REG_X30 #define IR_REG_ZR IR_REG_X31 -/* Calling Convention */ -#define IR_REG_INT_RET1 IR_REG_X0 -#define IR_REG_FP_RET1 IR_REG_V0 -#define IR_REG_INT_ARGS 8 -#define IR_REG_FP_ARGS 8 -#define IR_REG_INT_ARG1 IR_REG_X0 -#define IR_REG_INT_ARG2 IR_REG_X1 -#define IR_REG_INT_ARG3 IR_REG_X2 -#define IR_REG_INT_ARG4 IR_REG_X3 -#define IR_REG_INT_ARG5 IR_REG_X4 -#define IR_REG_INT_ARG6 IR_REG_X5 -#define IR_REG_INT_ARG7 IR_REG_X6 -#define IR_REG_INT_ARG8 IR_REG_X7 -#define IR_REG_FP_ARG1 IR_REG_V0 -#define IR_REG_FP_ARG2 IR_REG_V1 -#define IR_REG_FP_ARG3 IR_REG_V2 -#define IR_REG_FP_ARG4 IR_REG_V3 -#define IR_REG_FP_ARG5 IR_REG_V4 -#define IR_REG_FP_ARG6 IR_REG_V5 -#define IR_REG_FP_ARG7 IR_REG_V6 -#define IR_REG_FP_ARG8 IR_REG_V7 -#define IR_MAX_REG_ARGS 16 -#define IR_SHADOW_ARGS 0 - -# define IR_REGSET_SCRATCH \ - (IR_REGSET_INTERVAL(IR_REG_X0, IR_REG_X18) \ - | IR_REGSET_INTERVAL(IR_REG_V0, IR_REG_V7) \ - | IR_REGSET_INTERVAL(IR_REG_V16, IR_REG_V31)) - -# define IR_REGSET_PRESERVED \ - (IR_REGSET_INTERVAL(IR_REG_X19, IR_REG_X30) \ - | IR_REGSET_INTERVAL(IR_REG_V8, IR_REG_V15)) - -#ifndef __APPLE__ -typedef struct _ir_va_list { - void *stack; - void *gr_top; - void *vr_top; - int32_t gr_offset; - int32_t vr_offset; -} ir_va_list; -#endif - -typedef struct _ir_tmp_reg { - union { - uint8_t num; - int8_t reg; - }; - uint8_t type; - int8_t start; - int8_t end; -} ir_tmp_reg; - -struct _ir_target_constraints { - int8_t def_reg; - uint8_t tmps_count; - uint8_t hints_count; - ir_tmp_reg tmp_regs[3]; - int8_t hints[IR_MAX_REG_ARGS + 3]; -}; - #endif /* IR_AARCH64_H */ diff --git a/ext/opcache/jit/ir/ir_dump.c b/ext/opcache/jit/ir/ir_dump.c index 5cc732927d412..92962313d9992 100644 --- a/ext/opcache/jit/ir/ir_dump.c +++ b/ext/opcache/jit/ir/ir_dump.c @@ -8,6 +8,14 @@ #include "ir.h" #include "ir_private.h" +#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64) +# include "ir_x86.h" +#elif defined(IR_TARGET_AARCH64) +# include "ir_aarch64.h" +#else +# error "Unknown IR target" +#endif + void ir_dump(const ir_ctx *ctx, FILE *f) { ir_ref i, j, n, ref, *p; @@ -456,8 +464,8 @@ void ir_dump_live_ranges(const ir_ctx *ctx, FILE *f) } } #if 1 - n = ctx->vregs_count + ir_regs_number() + 2; - for (i = ctx->vregs_count + 1; i <= n; i++) { + n = ctx->vregs_count + 1 + IR_REG_SET_NUM; + for (i = ctx->vregs_count + 1; i < n; i++) { ir_live_interval *ival = ctx->live_intervals[i]; if (ival) { diff --git a/ext/opcache/jit/ir/ir_emit.c b/ext/opcache/jit/ir/ir_emit.c index 847ca375b5bd0..a6dfde77f576c 100644 --- a/ext/opcache/jit/ir/ir_emit.c +++ b/ext/opcache/jit/ir/ir_emit.c @@ -63,18 +63,7 @@ typedef struct _ir_dessa_copy { int32_t to; /* [0..IR_REG_NUM) - CPU reg, [IR_REG_NUM...) - virtual reg */ } ir_dessa_copy; -#if IR_REG_INT_ARGS -static const int8_t _ir_int_reg_params[IR_REG_INT_ARGS]; -#else -static const int8_t *_ir_int_reg_params; -#endif -#if IR_REG_FP_ARGS -static const int8_t _ir_fp_reg_params[IR_REG_FP_ARGS]; -#else -static const int8_t *_ir_fp_reg_params; -#endif - -static const ir_proto_t *ir_call_proto(const ir_ctx *ctx, ir_insn *insn) +const ir_proto_t *ir_call_proto(const ir_ctx *ctx, const ir_insn *insn) { if (IR_IS_CONST_REF(insn->op2)) { const ir_insn *func = &ctx->ir_base[insn->op2]; @@ -90,49 +79,6 @@ static const ir_proto_t *ir_call_proto(const ir_ctx *ctx, ir_insn *insn) return NULL; } -#ifdef IR_HAVE_FASTCALL -static const int8_t _ir_int_fc_reg_params[IR_REG_INT_FCARGS]; -static const int8_t *_ir_fp_fc_reg_params; - -bool ir_is_fastcall(const ir_ctx *ctx, const ir_insn *insn) -{ - if (sizeof(void*) == 4) { - if (IR_IS_CONST_REF(insn->op2)) { - const ir_insn *func = &ctx->ir_base[insn->op2]; - - if (func->op == IR_FUNC || func->op == IR_FUNC_ADDR) { - if (func->proto) { - const ir_proto_t *proto = (const ir_proto_t *)ir_get_str(ctx, func->proto); - - return (proto->flags & IR_FASTCALL_FUNC) != 0; - } - } - } else if (ctx->ir_base[insn->op2].op == IR_PROTO) { - const ir_proto_t *proto = (const ir_proto_t *)ir_get_str(ctx, ctx->ir_base[insn->op2].op2); - - return (proto->flags & IR_FASTCALL_FUNC) != 0; - } - return 0; - } - return 0; -} -#else -bool ir_is_fastcall(const ir_ctx *ctx, const ir_insn *insn) -{ - return 0; -} -#endif - -bool ir_is_vararg(const ir_ctx *ctx, ir_insn *insn) -{ - const ir_proto_t *proto = ir_call_proto(ctx, insn); - - if (proto) { - return (proto->flags & IR_VARARG_FUNC) != 0; - } - return 0; -} - IR_ALWAYS_INLINE uint32_t ir_rule(const ir_ctx *ctx, ir_ref ref) { IR_ASSERT(!IR_IS_CONST_REF(ref)); @@ -153,19 +99,7 @@ static ir_reg ir_get_param_reg(const ir_ctx *ctx, ir_ref ref) ir_insn *insn; int int_param = 0; int fp_param = 0; - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; - -#ifdef IR_HAVE_FASTCALL - if (sizeof(void*) == 4 && (ctx->flags & IR_FASTCALL_FUNC)) { - int_reg_params_count = IR_REG_INT_FCARGS; - fp_reg_params_count = IR_REG_FP_FCARGS; - int_reg_params = _ir_int_fc_reg_params; - fp_reg_params = _ir_fp_fc_reg_params; - } -#endif + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(ctx->flags); for (i = use_list->count, p = &ctx->use_edges[use_list->refs]; i > 0; p++, i--) { use = *p; @@ -173,70 +107,48 @@ static ir_reg ir_get_param_reg(const ir_ctx *ctx, ir_ref ref) if (insn->op == IR_PARAM) { if (IR_IS_TYPE_INT(insn->type)) { if (use == ref) { -#if defined(IR_TARGET_X64) || defined(IR_TARGET_X86) - if (ctx->value_params && ctx->value_params[insn->op3 - 1].align) { + if (ctx->value_params && ctx->value_params[insn->op3 - 1].align && cc->pass_struct_by_val) { /* struct passed by value on stack */ return IR_REG_NONE; - } else -#endif - if (int_param < int_reg_params_count) { - return int_reg_params[int_param]; + } else if (int_param < cc->int_param_regs_count) { + return cc->int_param_regs[int_param]; } else { return IR_REG_NONE; } -#if defined(IR_TARGET_X64) || defined(IR_TARGET_X86) - } else { - if (ctx->value_params && ctx->value_params[insn->op3 - 1].align) { - /* struct passed by value on stack */ - continue; - } -#endif + } else if (ctx->value_params && ctx->value_params[insn->op3 - 1].align && cc->pass_struct_by_val) { + /* struct passed by value on stack */ + continue; } int_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param++; -#endif + if (cc->shadow_param_regs) { + fp_param++; + } } else { IR_ASSERT(IR_IS_TYPE_FP(insn->type)); if (use == ref) { - if (fp_param < fp_reg_params_count) { - return fp_reg_params[fp_param]; + if (fp_param < cc->fp_param_regs_count) { + return cc->fp_param_regs[fp_param]; } else { return IR_REG_NONE; } } fp_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - int_param++; -#endif + if (cc->shadow_param_regs) { + int_param++; + } } } } return IR_REG_NONE; } -static int ir_get_args_regs(const ir_ctx *ctx, const ir_insn *insn, int8_t *regs) +static int ir_get_args_regs(const ir_ctx *ctx, const ir_insn *insn, const ir_call_conv_dsc *cc, int8_t *regs) { int j, n; ir_type type; int int_param = 0; int fp_param = 0; int count = 0; - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; - -#ifdef IR_HAVE_FASTCALL - if (sizeof(void*) == 4 && ir_is_fastcall(ctx, insn)) { - int_reg_params_count = IR_REG_INT_FCARGS; - fp_reg_params_count = IR_REG_FP_FCARGS; - int_reg_params = _ir_int_fc_reg_params; - fp_reg_params = _ir_fp_fc_reg_params; - } -#endif n = insn->inputs_count; n = IR_MIN(n, IR_MAX_REG_ARGS + 2); @@ -244,27 +156,25 @@ 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 (int_param < int_reg_params_count && arg->op != IR_ARGVAL) { - regs[j] = int_reg_params[int_param]; + if (int_param < cc->int_param_regs_count && arg->op != IR_ARGVAL) { + regs[j] = cc->int_param_regs[int_param]; count = j + 1; int_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param++; -#endif + if (cc->shadow_param_regs) { + fp_param++; + } } else { regs[j] = IR_REG_NONE; } } else { IR_ASSERT(IR_IS_TYPE_FP(type)); - if (fp_param < fp_reg_params_count) { - regs[j] = fp_reg_params[fp_param]; + if (fp_param < cc->fp_param_regs_count) { + regs[j] = cc->fp_param_regs[fp_param]; count = j + 1; fp_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - int_param++; -#endif + if (cc->shadow_param_regs) { + int_param++; + } } else { regs[j] = IR_REG_NONE; } @@ -419,7 +329,6 @@ static void ir_emit_dessa_moves(ir_ctx *ctx, int b, ir_block *bb); typedef struct _ir_common_backend_data { ir_reg_alloc_data ra_data; - uint32_t dessa_from_block; dasm_State *dasm_state; ir_bitset emit_constants; } ir_common_backend_data; @@ -1071,3 +980,32 @@ int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref) IR_ASSERT(offset != -1); return IR_SPILL_POS_TO_OFFSET(offset); } + +const ir_call_conv_dsc *ir_get_call_conv_dsc(uint32_t flags) +{ +#ifdef IR_TARGET_X86 + if ((flags & IR_CALL_CONV_MASK) == IR_CC_FASTCALL) { + return &ir_call_conv_x86_fastcall; + } +#elif defined(IR_TARGET_X64) + switch (flags & IR_CALL_CONV_MASK) { + case IR_CC_DEFAULT: return &ir_call_conv_default; + case IR_CC_FASTCALL: return &ir_call_conv_default; + case IR_CC_PRESERVE_NONE: return &ir_call_conv_x86_64_preserve_none; + case IR_CC_X86_64_SYSV: return &ir_call_conv_x86_64_sysv; + case IR_CC_X86_64_MS: return &ir_call_conv_x86_64_ms; + default: break; + } +#elif defined(IR_TARGET_AARCH64) + switch (flags & IR_CALL_CONV_MASK) { + case IR_CC_DEFAULT: return &ir_call_conv_default; + case IR_CC_FASTCALL: return &ir_call_conv_default; + case IR_CC_PRESERVE_NONE: return &ir_call_conv_aarch64_preserve_none; + case IR_CC_AARCH64_SYSV: return &ir_call_conv_aarch64_sysv; + case IR_CC_AARCH64_DARWIN: return &ir_call_conv_aarch64_darwin; + default: break; + } +#endif + IR_ASSERT((flags & IR_CALL_CONV_MASK) == IR_CC_DEFAULT || (flags & IR_CALL_CONV_MASK) == IR_CC_BUILTIN); + return &ir_call_conv_default; +} diff --git a/ext/opcache/jit/ir/ir_gcm.c b/ext/opcache/jit/ir/ir_gcm.c index e6486ba64a1c5..67c97611eaac4 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++; } } @@ -413,7 +413,8 @@ static bool ir_split_partially_dead_node(ir_ctx *ctx, ir_ref ref, uint32_t b) n = ctx->use_lists[ref].refs; for (i = 0; i < clones_count; i++) { clone = clones[i].ref; - if (clones[i].use_count == 1 + if (clones[i].block + && clones[i].use_count == 1 && ctx->cfg_blocks[clones[i].block].loop_depth >= ctx->cfg_blocks[uses[clones[i].use].block].loop_depth) { /* TOTALLY_USEFUL block may be a head of a diamond above the real usage. * Sink it down to the real usage block. diff --git a/ext/opcache/jit/ir/ir_private.h b/ext/opcache/jit/ir/ir_private.h index dbacc3967d0f7..acd7e41a3e9a5 100644 --- a/ext/opcache/jit/ir/ir_private.h +++ b/ext/opcache/jit/ir/ir_private.h @@ -1015,6 +1015,8 @@ IR_ALWAYS_INLINE uint32_t ir_insn_len(const ir_insn *insn) #define IR_HAS_FP_RET_SLOT (1<<10) #define IR_16B_FRAME_ALIGNMENT (1<<11) #define IR_HAS_BLOCK_ADDR (1<<12) +#define IR_PREALLOCATED_STACK (1<<13) + /* Temporary: MEM2SSA -> SCCP */ #define IR_MEM2SSA_VARS (1<<25) @@ -1275,9 +1277,9 @@ struct _ir_live_interval { ir_live_interval *list_next; /* linked list of active, inactive or unhandled intervals */ }; -typedef int (*emit_copy_t)(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to); +typedef int (*emit_copy_t)(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to, void *data); -int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy); +int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy, void *data); #if defined(IR_REGSET_64BIT) @@ -1363,16 +1365,44 @@ IR_ALWAYS_INLINE ir_reg ir_regset_pop_first(ir_regset *set) #endif /* defined(IR_REGSET_64BIT) */ +/*** Calling Conventions ***/ +#if defined(IR_REGSET_64BIT) +struct _ir_call_conv_dsc { + bool cleanup_stack_by_callee: 1; /* use "retn $size" to return */ + bool pass_struct_by_val: 1; /* pass aggreagate by value, otherwise their copies are passed by ref */ + bool sysv_varargs: 1; /* Use SysV varargs ABI */ + bool shadow_param_regs: 1; /* registers for INT and FP parametrs shadow each other */ + /* (WIN64: 1-st arg is passed in %rcx/%xmm0, 2-nd in %rdx/%xmm1) */ + uint8_t shadow_store_size; /* reserved stack space to keep arguemnts passed in registers (WIN64) */ + uint8_t int_param_regs_count; /* number of registers for INT parameters */ + uint8_t fp_param_regs_count; /* number of registers for FP parameters */ + int8_t int_ret_reg; /* register to return INT value */ + int8_t fp_ret_reg; /* register to return FP value */ + int8_t fp_varargs_reg; /* register to pass number of fp register arguments into vararg func */ + int8_t scratch_reg; /* pseudo register to reffer srcatch regset (clobbered by call) */ + const int8_t *int_param_regs; /* registers for INT parameters */ + const int8_t *fp_param_regs; /* registers for FP parameters */ + ir_regset preserved_regs; /* preserved or callee-saved registers */ +}; + +extern const ir_regset ir_scratch_regset[]; +#endif + +typedef struct _ir_call_conv_dsc ir_call_conv_dsc; + +const ir_call_conv_dsc *ir_get_call_conv_dsc(uint32_t flags); + /*** IR Register Allocation ***/ /* Flags for ctx->regs[][] (low bits are used for register number itself) */ typedef struct _ir_reg_alloc_data { + const ir_call_conv_dsc *cc; int32_t unused_slot_4; int32_t unused_slot_2; int32_t unused_slot_1; ir_live_interval **handled; } ir_reg_alloc_data; -int32_t ir_allocate_spill_slot(ir_ctx *ctx, ir_type type, ir_reg_alloc_data *data); +int32_t ir_allocate_spill_slot(ir_ctx *ctx, ir_type type); IR_ALWAYS_INLINE void ir_set_alocated_reg(ir_ctx *ctx, ir_ref ref, int op_num, int8_t reg) { @@ -1406,9 +1436,27 @@ IR_ALWAYS_INLINE int8_t ir_get_alocated_reg(const ir_ctx *ctx, ir_ref ref, int o #define IR_RULE_MASK 0xff +#define IR_MAX_REG_ARGS 64 + extern const char *ir_rule_name[]; -typedef struct _ir_target_constraints ir_target_constraints; +typedef struct _ir_tmp_reg { + union { + uint8_t num; + int8_t reg; + }; + uint8_t type; + int8_t start; + int8_t end; +} ir_tmp_reg; + +typedef struct { + int8_t def_reg; + uint8_t tmps_count; + uint8_t hints_count; + ir_tmp_reg tmp_regs[3]; + int8_t hints[IR_MAX_REG_ARGS + 3]; +} ir_target_constraints; #define IR_TMP_REG(_num, _type, _start, _end) \ (ir_tmp_reg){.num=(_num), .type=(_type), .start=(_start), .end=(_end)} @@ -1421,8 +1469,8 @@ void ir_fix_stack_frame(ir_ctx *ctx); /* Utility */ ir_type ir_get_return_type(ir_ctx *ctx); -bool ir_is_fastcall(const ir_ctx *ctx, const ir_insn *insn); -bool ir_is_vararg(const ir_ctx *ctx, ir_insn *insn); +const ir_proto_t *ir_call_proto(const ir_ctx *ctx, const ir_insn *insn); +void ir_print_call_conv(uint32_t flags, FILE *f); //#define IR_BITSET_LIVENESS diff --git a/ext/opcache/jit/ir/ir_ra.c b/ext/opcache/jit/ir/ir_ra.c index 2e8a8e3f34f3f..23f44482cb8b5 100644 --- a/ext/opcache/jit/ir/ir_ra.c +++ b/ext/opcache/jit/ir/ir_ra.c @@ -610,8 +610,8 @@ int ir_compute_live_ranges(ir_ctx *ctx) len = ir_bitset_len(ctx->vregs_count + 1); bb_live = ir_mem_malloc((ctx->cfg_blocks_count + 1) * len * sizeof(ir_bitset_base_t)); - /* vregs + tmp + fixed + SRATCH + ALL */ - ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 2, sizeof(ir_live_interval*)); + /* vregs + tmp + fixed + ALL + SCRATCH_N */ + ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_SET_NUM, sizeof(ir_live_interval*)); #ifdef IR_DEBUG visited = ir_bitset_malloc(ctx->cfg_blocks_count + 1); @@ -1265,8 +1265,8 @@ int ir_compute_live_ranges(ir_ctx *ctx) /* Compute Live Ranges */ ctx->flags2 &= ~IR_LR_HAVE_DESSA_MOVES; - /* vregs + tmp + fixed + SRATCH + ALL */ - ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 2, sizeof(ir_live_interval*)); + /* vregs + tmp + fixed + ALL + SCRATCH_N */ + ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_SET_NUM, sizeof(ir_live_interval*)); if (!ctx->arena) { ctx->arena = ir_arena_create(16 * 1024); @@ -2037,8 +2037,8 @@ int ir_coalesce(ir_ctx *ctx) n--; if (n != ctx->vregs_count) { j = ctx->vregs_count - n; - /* vregs + tmp + fixed + SRATCH + ALL */ - for (i = n + 1; i <= n + IR_REG_NUM + 2; i++) { + /* vregs + tmp + fixed + ALL + SCRATCH_N */ + for (i = n + 1; i <= n + IR_REG_SET_NUM; i++) { ctx->live_intervals[i] = ctx->live_intervals[i + j]; if (ctx->live_intervals[i]) { ctx->live_intervals[i]->vreg = i; @@ -2105,7 +2105,7 @@ int ir_compute_dessa_moves(ir_ctx *ctx) * 2009 International Symposium on Code Generation and Optimization, Seattle, WA, USA, 2009, * pp. 114-125, doi: 10.1109/CGO.2009.19. */ -int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy) +int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy, void *data) { uint32_t succ, k, n = 0; ir_block *bb, *succ_bb; @@ -2180,7 +2180,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy) while ((b = ir_bitset_pop_first(ready, len)) >= 0) { a = pred[b]; c = loc[a]; - emit_copy(ctx, ctx->ir_base[dst[b]].type, src[c], dst[b]); + emit_copy(ctx, ctx->ir_base[dst[b]].type, src[c], dst[b], data); ir_bitset_excl(todo, b); loc[a] = b; src[b] = dst[b]; @@ -2193,7 +2193,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy) break; } IR_ASSERT(b != loc[pred[b]]); - emit_copy(ctx, ctx->ir_base[src[b]].type, src[b], 0); + emit_copy(ctx, ctx->ir_base[src[b]].type, src[b], 0, data); loc[b] = 0; ir_bitset_incl(ready, b); } @@ -2211,7 +2211,7 @@ int ir_gen_dessa_moves(ir_ctx *ctx, uint32_t b, emit_copy_t emit_copy) if (insn->op == IR_PHI) { input = ir_insn_op(insn, k); if (IR_IS_CONST_REF(input) || !ctx->vregs[input]) { - emit_copy(ctx, insn->type, input, ref); + emit_copy(ctx, insn->type, input, ref, data); } } } @@ -2501,8 +2501,9 @@ static ir_live_interval *ir_split_interval_at(ir_ctx *ctx, ir_live_interval *iva return child; } -static int32_t ir_allocate_small_spill_slot(ir_ctx *ctx, size_t size, ir_reg_alloc_data *data) +static int32_t ir_allocate_small_spill_slot(ir_ctx *ctx, size_t size) { + ir_reg_alloc_data *data = ctx->data; int32_t ret; IR_ASSERT(size == 0 || size == 1 || size == 2 || size == 4 || size == 8); @@ -2601,12 +2602,12 @@ static int32_t ir_allocate_small_spill_slot(ir_ctx *ctx, size_t size, ir_reg_all return ret; } -int32_t ir_allocate_spill_slot(ir_ctx *ctx, ir_type type, ir_reg_alloc_data *data) +int32_t ir_allocate_spill_slot(ir_ctx *ctx, ir_type type) { - return ir_allocate_small_spill_slot(ctx, ir_type_size[type], data); + return ir_allocate_small_spill_slot(ctx, ir_type_size[type]); } -static int32_t ir_allocate_big_spill_slot(ir_ctx *ctx, int32_t size, ir_reg_alloc_data *data) +static int32_t ir_allocate_big_spill_slot(ir_ctx *ctx, int32_t size) { int32_t ret; @@ -2616,7 +2617,7 @@ static int32_t ir_allocate_big_spill_slot(ir_ctx *ctx, int32_t size, ir_reg_allo } else if (size > 4 && size < 8) { size = 8; } - return ir_allocate_small_spill_slot(ctx, size, data); + return ir_allocate_small_spill_slot(ctx, size); } /* Align stack allocated data to 16 byte */ @@ -2836,13 +2837,8 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l /* freeUntilPos[it.reg] = 0 */ reg = other->reg; IR_ASSERT(reg >= 0); - if (reg >= IR_REG_SCRATCH) { - if (reg == IR_REG_SCRATCH) { - available = IR_REGSET_DIFFERENCE(available, IR_REGSET_SCRATCH); - } else { - IR_ASSERT(reg == IR_REG_ALL); - available = IR_REGSET_EMPTY; - } + if (reg >= IR_REG_NUM) { + available = IR_REGSET_DIFFERENCE(available, ir_scratch_regset[reg - IR_REG_NUM]); } else { IR_REGSET_EXCL(available, reg); } @@ -2864,15 +2860,8 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l if (next) { reg = other->reg; IR_ASSERT(reg >= 0); - if (reg >= IR_REG_SCRATCH) { - ir_regset regset; - - if (reg == IR_REG_SCRATCH) { - regset = IR_REGSET_INTERSECTION(available, IR_REGSET_SCRATCH); - } else { - IR_ASSERT(reg == IR_REG_ALL); - regset = available; - } + if (reg >= IR_REG_NUM) { + ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]); overlapped = IR_REGSET_UNION(overlapped, regset); IR_REGSET_FOREACH(regset, reg) { if (next < freeUntilPos[reg]) { @@ -2922,7 +2911,8 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l } /* prefer caller-saved registers to avoid save/restore in prologue/epilogue */ - scratch = IR_REGSET_INTERSECTION(available, IR_REGSET_SCRATCH); + scratch = IR_REGSET_INTERSECTION(available, + ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM]); if (scratch != IR_REGSET_EMPTY) { /* prefer registers that don't conflict with the hints for the following unhandled intervals */ if (1) { @@ -2970,8 +2960,8 @@ static ir_reg ir_try_allocate_free_reg(ir_ctx *ctx, ir_live_interval *ival, ir_l pos = freeUntilPos[i]; reg = i; } else if (freeUntilPos[i] == pos - && !IR_REGSET_IN(IR_REGSET_SCRATCH, reg) - && IR_REGSET_IN(IR_REGSET_SCRATCH, i)) { + && !IR_REGSET_IN(ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM], reg) + && IR_REGSET_IN(ir_scratch_regset[((ir_reg_alloc_data*)(ctx->data))->cc->scratch_reg - IR_REG_NUM], i)) { /* prefer caller-saved registers to avoid save/restore in prologue/epilogue */ pos = freeUntilPos[i]; reg = i; @@ -3077,15 +3067,8 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li /* nextUsePos[it.reg] = next use of it after start of current */ reg = other->reg; IR_ASSERT(reg >= 0); - if (reg >= IR_REG_SCRATCH) { - ir_regset regset; - - if (reg == IR_REG_SCRATCH) { - regset = IR_REGSET_INTERSECTION(available, IR_REGSET_SCRATCH); - } else { - IR_ASSERT(reg == IR_REG_ALL); - regset = available; - } + if (reg >= IR_REG_NUM) { + ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]); IR_REGSET_FOREACH(regset, reg) { blockPos[reg] = nextUsePos[reg] = 0; } IR_REGSET_FOREACH_END(); @@ -3109,18 +3092,11 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li /* freeUntilPos[it.reg] = next intersection of it with current */ reg = other->reg; IR_ASSERT(reg >= 0); - if (reg >= IR_REG_SCRATCH) { + if (reg >= IR_REG_NUM) { ir_live_pos overlap = ir_ivals_overlap(&ival->range, other->current_range); if (overlap) { - ir_regset regset; - - if (reg == IR_REG_SCRATCH) { - regset = IR_REGSET_INTERSECTION(available, IR_REGSET_SCRATCH); - } else { - IR_ASSERT(reg == IR_REG_ALL); - regset = available; - } + ir_regset regset = IR_REGSET_INTERSECTION(available, ir_scratch_regset[reg - IR_REG_NUM]); IR_REGSET_FOREACH(regset, reg) { if (overlap < nextUsePos[reg]) { nextUsePos[reg] = overlap; @@ -3325,9 +3301,9 @@ static ir_reg ir_allocate_blocked_reg(ir_ctx *ctx, ir_live_interval *ival, ir_li return reg; } -static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to) +static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to, void *data) { - ir_block *bb = ctx->data; + ir_block *bb = data; ir_tmp_reg tmp_reg; if (to == 0) { @@ -3365,7 +3341,7 @@ static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to) return 1; } -static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival, ir_reg_alloc_data *data) +static bool ir_ival_spill_for_fuse_load(ir_ctx *ctx, ir_live_interval *ival) { ir_use_pos *use_pos = ival->use_pos; @@ -3417,7 +3393,7 @@ static void ir_assign_bound_spill_slots(ir_ctx *ctx) } } -static int ir_linear_scan(ir_ctx *ctx) +static int ir_linear_scan(ir_ctx *ctx, ir_ref vars) { uint32_t b; ir_block *bb; @@ -3428,8 +3404,6 @@ static int ir_linear_scan(ir_ctx *ctx) int j; ir_live_pos position; ir_reg reg; - ir_reg_alloc_data data; - ir_ref vars = ctx->vars; if (!ctx->live_intervals) { return 0; @@ -3440,19 +3414,11 @@ static int ir_linear_scan(ir_ctx *ctx) for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) { IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE)); if (bb->flags & IR_BB_DESSA_MOVES) { - ctx->data = bb; - ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps); + ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps, bb); } } } - ctx->data = &data; - ctx->stack_frame_size = 0; - data.unused_slot_4 = 0; - data.unused_slot_2 = 0; - data.unused_slot_1 = 0; - data.handled = NULL; - while (vars) { ir_ref var = vars; ir_insn *insn = &ctx->ir_base[var]; @@ -3461,7 +3427,7 @@ static int ir_linear_scan(ir_ctx *ctx) vars = insn->op3; /* list next */ if (insn->op == IR_VAR) { - ir_ref slot = ir_allocate_spill_slot(ctx, insn->type, &data);; + ir_ref slot = ir_allocate_spill_slot(ctx, insn->type); ir_use_list *use_list; ir_ref n, *p; @@ -3484,7 +3450,7 @@ static int ir_linear_scan(ir_ctx *ctx) IR_ASSERT(IR_IS_TYPE_UNSIGNED(val->type) || val->val.i64 >= 0); IR_ASSERT(val->val.i64 < 0x7fffffff); - insn->op3 = ir_allocate_big_spill_slot(ctx, val->val.i32, &data); + insn->op3 = ir_allocate_big_spill_slot(ctx, val->val.i32); } } @@ -3492,7 +3458,7 @@ static int ir_linear_scan(ir_ctx *ctx) ival = ctx->live_intervals[j]; if (ival) { if (!(ival->flags & IR_LIVE_INTERVAL_MEM_PARAM) - || !ir_ival_spill_for_fuse_load(ctx, ival, &data)) { + || !ir_ival_spill_for_fuse_load(ctx, ival)) { ir_add_to_unhandled(&unhandled, ival); } } @@ -3503,8 +3469,8 @@ static int ir_linear_scan(ir_ctx *ctx) ir_merge_to_unhandled(&unhandled, ival); } - /* vregs + tmp + fixed + SRATCH + ALL */ - for (j = ctx->vregs_count + 1; j <= ctx->vregs_count + IR_REG_NUM + 2; j++) { + /* vregs + tmp + fixed + ALL + SCRATCH_N */ + for (j = ctx->vregs_count + 1; j <= ctx->vregs_count + IR_REG_SET_NUM; j++) { ival = ctx->live_intervals[j]; if (ival) { ival->current_range = &ival->range; @@ -3663,7 +3629,7 @@ static int ir_linear_scan(ir_ctx *ctx) ir_live_interval *handled[9] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; ir_live_interval *old; - data.handled = handled; + ((ir_reg_alloc_data*)(ctx->data))->handled = handled; active = NULL; while (unhandled) { ival = unhandled; @@ -3701,7 +3667,7 @@ static int ir_linear_scan(ir_ctx *ctx) other = prev ? prev->list_next : active; } - ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type, &data); + ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type); if (unhandled && ival->end > unhandled->range.start) { ival->list_next = active; active = ival; @@ -3721,15 +3687,16 @@ static int ir_linear_scan(ir_ctx *ctx) } } } - data.handled = NULL; + ((ir_reg_alloc_data*)(ctx->data))->handled = NULL; } } #ifdef IR_TARGET_X86 if (ctx->flags2 & IR_HAS_FP_RET_SLOT) { - ctx->ret_slot = ir_allocate_spill_slot(ctx, IR_DOUBLE, &data); - } else if (ctx->ret_type == IR_FLOAT || ctx->ret_type == IR_DOUBLE) { - ctx->ret_slot = ir_allocate_spill_slot(ctx, ctx->ret_type, &data); + ctx->ret_slot = ir_allocate_spill_slot(ctx, IR_DOUBLE); + } else if ((ctx->ret_type == IR_FLOAT || ctx->ret_type == IR_DOUBLE) + && ((ir_reg_alloc_data*)(ctx->data))->cc->fp_ret_reg == IR_REG_NONE) { + ctx->ret_slot = ir_allocate_spill_slot(ctx, ctx->ret_type); } else { ctx->ret_slot = -1; } @@ -4033,17 +4000,18 @@ static void assign_regs(ir_ctx *ctx) } while (ival); } + const ir_call_conv_dsc *cc = ((ir_reg_alloc_data*)(ctx->data))->cc; if (ctx->fixed_stack_frame_size != -1) { ctx->used_preserved_regs = (ir_regset)ctx->fixed_save_regset; - if (IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, IR_REGSET_PRESERVED), + if (IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, cc->preserved_regs), ctx->used_preserved_regs)) { // TODO: Preserved reg and fixed frame conflict ??? // IR_ASSERT(0 && "Preserved reg and fixed frame conflict"); } } else { ctx->used_preserved_regs = IR_REGSET_UNION((ir_regset)ctx->fixed_save_regset, - IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, IR_REGSET_PRESERVED), - (ctx->flags & IR_FUNCTION) ? (ir_regset)ctx->fixed_regset : IR_REGSET_PRESERVED)); + IR_REGSET_DIFFERENCE(IR_REGSET_INTERSECTION(used_regs, cc->preserved_regs), + (ctx->flags & IR_FUNCTION) ? (ir_regset)ctx->fixed_regset : cc->preserved_regs)); } ir_fix_stack_frame(ctx); @@ -4051,9 +4019,24 @@ static void assign_regs(ir_ctx *ctx) int ir_reg_alloc(ir_ctx *ctx) { - if (ir_linear_scan(ctx)) { + ir_reg_alloc_data data; + ir_ref vars = ctx->vars; + + data.cc = ir_get_call_conv_dsc(ctx->flags); + data.unused_slot_4 = 0; + data.unused_slot_2 = 0; + data.unused_slot_1 = 0; + data.handled = NULL; + + ctx->data = &data; + ctx->stack_frame_size = 0; + + if (ir_linear_scan(ctx, vars)) { assign_regs(ctx); + ctx->data = NULL; return 1; } + + ctx->data = NULL; return 0; } diff --git a/ext/opcache/jit/ir/ir_save.c b/ext/opcache/jit/ir/ir_save.c index dd955172950c8..51d7f96e518fa 100644 --- a/ext/opcache/jit/ir/ir_save.c +++ b/ext/opcache/jit/ir/ir_save.c @@ -18,6 +18,38 @@ void ir_print_proto(const ir_ctx *ctx, ir_ref func_proto, FILE *f) } } +void ir_print_call_conv(uint32_t flags, FILE *f) +{ + switch (flags & IR_CALL_CONV_MASK) { + case IR_CC_BUILTIN: + fprintf(f, " __builtin"); + break; + case IR_CC_FASTCALL: + fprintf(f, " __fastcall"); + break; + case IR_CC_PRESERVE_NONE: + fprintf(f, " __preserve_none"); + break; +#if defined(IR_TARGET_X64) + case IR_CC_X86_64_SYSV: + fprintf(f, " __sysv"); + break; + case IR_CC_X86_64_MS: + fprintf(f, " __win64"); + break; +#elif defined(IR_TARGET_AARCH64) + case IR_CC_AARCH64_SYSV: + fprintf(f, " __sysv"); + break; + case IR_CC_AARCH64_DARWIN: + fprintf(f, " __darwin"); + break; +#endif + default: + IR_ASSERT((flags & IR_CALL_CONV_MASK) == IR_CC_DEFAULT); + } +} + void ir_print_proto_ex(uint8_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f) { uint32_t j; @@ -35,11 +67,7 @@ void ir_print_proto_ex(uint8_t flags, ir_type ret_type, uint32_t params_count, c fprintf(f, "..."); } fprintf(f, "): %s", ir_type_cname[ret_type]); - if (flags & IR_FASTCALL_FUNC) { - fprintf(f, " __fastcall"); - } else if (flags & IR_BUILTIN_FUNC) { - fprintf(f, " __builtin"); - } + ir_print_call_conv(flags, f); if (flags & IR_CONST_FUNC) { fprintf(f, " __const"); } else if (flags & IR_PURE_FUNC) { diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc index 7f714dd11d27c..9072b0dd59147 100644 --- a/ext/opcache/jit/ir/ir_x86.dasc +++ b/ext/opcache/jit/ir/ir_x86.dasc @@ -882,8 +882,7 @@ IR_ALWAYS_INLINE ir_mem IR_MEM(ir_reg base, int32_t offset, ir_reg index, int32_ |.endmacro typedef struct _ir_backend_data { - ir_reg_alloc_data ra_data; - uint32_t dessa_from_block; + ir_reg_alloc_data ra_data; dasm_State *dasm_state; ir_bitset emit_constants; int rodata_label, jmp_table_label; @@ -897,6 +896,13 @@ typedef struct _ir_backend_data { bool resolved_label_syms; } ir_backend_data; +typedef struct _ir_x86_64_sysv_va_list { + uint32_t gp_offset; + uint32_t fp_offset; + void *overflow_arg_area; + void *reg_save_area; +} ir_x86_64_sysv_va_list; + #define IR_GP_REG_NAME(code, name64, name32, name16, name8, name8h) \ #name64, #define IR_GP_REG_NAME32(code, name64, name32, name16, name8, name8h) \ @@ -908,9 +914,19 @@ typedef struct _ir_backend_data { #define IR_FP_REG_NAME(code, name) \ #name, -static const char *_ir_reg_name[IR_REG_NUM] = { +static const char *_ir_reg_name[] = { IR_GP_REGS(IR_GP_REG_NAME) IR_FP_REGS(IR_FP_REG_NAME) + "ALL", + "SCRATCH", +#ifdef IR_TARGET_X64 +# ifdef _WIN64 + "SCRATCH_SYSV", +# else + "SCRATCH_MS", +# endif + "SCRATCH_PN", /* preserve none */ +#endif }; static const char *_ir_reg_name32[IR_REG_NUM] = { @@ -925,66 +941,11 @@ static const char *_ir_reg_name8[IR_REG_NUM] = { IR_GP_REGS(IR_GP_REG_NAME8) }; -/* Calling Convention */ -#ifdef _WIN64 - -static const int8_t _ir_int_reg_params[IR_REG_INT_ARGS] = { - IR_REG_INT_ARG1, - IR_REG_INT_ARG2, - IR_REG_INT_ARG3, - IR_REG_INT_ARG4, -}; - -static const int8_t _ir_fp_reg_params[IR_REG_FP_ARGS] = { - IR_REG_FP_ARG1, - IR_REG_FP_ARG2, - IR_REG_FP_ARG3, - IR_REG_FP_ARG4, -}; - -#elif defined(IR_TARGET_X64) - -static const int8_t _ir_int_reg_params[IR_REG_INT_ARGS] = { - IR_REG_INT_ARG1, - IR_REG_INT_ARG2, - IR_REG_INT_ARG3, - IR_REG_INT_ARG4, - IR_REG_INT_ARG5, - IR_REG_INT_ARG6, -}; - -static const int8_t _ir_fp_reg_params[IR_REG_FP_ARGS] = { - IR_REG_FP_ARG1, - IR_REG_FP_ARG2, - IR_REG_FP_ARG3, - IR_REG_FP_ARG4, - IR_REG_FP_ARG5, - IR_REG_FP_ARG6, - IR_REG_FP_ARG7, - IR_REG_FP_ARG8, -}; - -#else - -static const int8_t *_ir_int_reg_params = NULL; -static const int8_t *_ir_fp_reg_params = NULL; -static const int8_t _ir_int_fc_reg_params[IR_REG_INT_FCARGS] = { - IR_REG_INT_FCARG1, - IR_REG_INT_FCARG2, -}; -static const int8_t *_ir_fp_fc_reg_params = NULL; - -#endif - const char *ir_reg_name(int8_t reg, ir_type type) { if (reg >= IR_REG_NUM) { - if (reg == IR_REG_SCRATCH) { - return "SCRATCH"; - } else { - IR_ASSERT(reg == IR_REG_ALL); - return "ALL"; - } + IR_ASSERT((uint8_t)reg < sizeof(_ir_reg_name) / sizeof(_ir_reg_name[0])); + return _ir_reg_name[reg]; } IR_ASSERT(reg >= 0 && reg < IR_REG_NUM); if (type == IR_VOID) { @@ -1002,6 +963,159 @@ const char *ir_reg_name(int8_t reg, ir_type type) } } +/* Calling Conventions */ +#ifdef IR_TARGET_X64 + +# ifdef _WIN64 +# define IR_REG_SCRATH_X86_64_MS IR_REG_SET_1 +# define IR_REG_SCRATH_X86_64_SYSV IR_REG_SET_2 +# define IR_REG_SCRATH_X86_64_PN IR_REG_SET_3 +# else +# define IR_REG_SCRATH_X86_64_SYSV IR_REG_SET_1 +# define IR_REG_SCRATH_X86_64_MS IR_REG_SET_2 +# define IR_REG_SCRATH_X86_64_PN IR_REG_SET_3 +# endif + +# define IR_REGSET_SCRATCH_X86_64_SYSV \ + (IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) | \ + IR_REGSET_INTERVAL(IR_REG_RSI, IR_REG_RDI) | \ + IR_REGSET_INTERVAL(IR_REG_R8, IR_REG_R11) | \ + IR_REGSET_FP) + +# define IR_REGSET_SCRATCH_X86_64_WIN \ + (IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) | \ + IR_REGSET_INTERVAL(IR_REG_R8, IR_REG_R11) | \ + IR_REGSET_INTERVAL(IR_REG_XMM0, IR_REG_XMM5)) + +# define IR_REGSET_SCRATCH_X86_64_PN \ + (IR_REGSET_DIFFERENCE(IR_REGSET_GP, IR_REGSET(IR_REG_RBP)) | IR_REGSET_FP) + +const ir_regset ir_scratch_regset[] = { + IR_REGSET_GP | IR_REGSET_FP, +# ifdef _WIN64 + IR_REGSET_SCRATCH_X86_64_WIN, + IR_REGSET_SCRATCH_X86_64_SYSV, +# else + IR_REGSET_SCRATCH_X86_64_SYSV, + IR_REGSET_SCRATCH_X86_64_WIN, +# endif + IR_REGSET_SCRATCH_X86_64_PN, +}; + +const ir_call_conv_dsc ir_call_conv_x86_64_ms = { + 0, /* cleanup_stack_by_callee */ + 0, /* pass_struct_by_val */ + 0, /* sysv_varargs */ + 1, /* shadow_param_regs */ + 32, /* shadow_store_size */ + 4, /* int_param_regs_count */ + 4, /* fp_param_regs_count */ + IR_REG_RAX, /* int_ret_reg */ + IR_REG_XMM0, /* fp_ret_reg */ + IR_REG_NONE, /* fp_varargs_reg */ + IR_REG_SCRATH_X86_64_MS, + (const int8_t[4]){IR_REG_RCX, IR_REG_RDX, IR_REG_R8, IR_REG_R9}, + (const int8_t[4]){IR_REG_XMM0, IR_REG_XMM1, IR_REG_XMM2, IR_REG_XMM3}, + IR_REGSET(IR_REG_RBX) | IR_REGSET(IR_REG_RBP) | IR_REGSET(IR_REG_RSI) | IR_REGSET(IR_REG_RDI) | + IR_REGSET_INTERVAL(IR_REG_R12, IR_REG_R15) | IR_REGSET_INTERVAL(IR_REG_XMM6, IR_REG_XMM15), +}; + +const ir_call_conv_dsc ir_call_conv_x86_64_sysv = { + 0, /* cleanup_stack_by_callee */ + 1, /* pass_struct_by_val */ + 1, /* sysv_varargs */ + 0, /* shadow_param_regs */ + 0, /* shadow_store_size */ + 6, /* int_param_regs_count */ + 8, /* fp_param_regs_count */ + IR_REG_RAX, /* int_ret_reg */ + IR_REG_XMM0, /* fp_ret_reg */ + IR_REG_RAX, /* fp_varargs_reg */ + IR_REG_SCRATH_X86_64_SYSV, + (const int8_t[6]){IR_REG_RDI, IR_REG_RSI, IR_REG_RDX, IR_REG_RCX, IR_REG_R8, IR_REG_R9}, + (const int8_t[8]){IR_REG_XMM0, IR_REG_XMM1, IR_REG_XMM2, IR_REG_XMM3, + IR_REG_XMM4, IR_REG_XMM5, IR_REG_XMM6, IR_REG_XMM7}, + IR_REGSET(IR_REG_RBX) | IR_REGSET(IR_REG_RBP) | IR_REGSET_INTERVAL(IR_REG_R12, IR_REG_R15), + +}; + +const ir_call_conv_dsc ir_call_conv_x86_64_preserve_none = { + 0, /* cleanup_stack_by_callee */ + 1, /* pass_struct_by_val */ + 1, /* sysv_varargs */ + 0, /* shadow_param_regs */ + 0, /* shadow_store_size */ + 12, /* int_param_regs_count */ + 8, /* fp_param_regs_count */ + IR_REG_RAX, /* int_ret_reg */ + IR_REG_XMM0, /* fp_ret_reg */ + IR_REG_RAX, /* fp_varargs_reg */ + IR_REG_SCRATH_X86_64_PN, + (const int8_t[12]){IR_REG_R12, IR_REG_R13, IR_REG_R14, IR_REG_R15, + IR_REG_RDI, IR_REG_RSI, IR_REG_RDX, IR_REG_RCX, IR_REG_R8, IR_REG_R9, + IR_REG_R11, IR_REG_RAX}, + (const int8_t[8]){IR_REG_XMM0, IR_REG_XMM1, IR_REG_XMM2, IR_REG_XMM3, + IR_REG_XMM4, IR_REG_XMM5, IR_REG_XMM6, IR_REG_XMM7}, + IR_REGSET(IR_REG_RBP), + +}; + +# ifdef _WIN64 +# define ir_call_conv_default ir_call_conv_x86_64_ms +# else +# define ir_call_conv_default ir_call_conv_x86_64_sysv +# endif + +#else + +# define IR_REG_SCRATCH_X86 IR_REG_SET_1 + +# define IR_REGSET_SCRATCH_X86 \ + (IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) | IR_REGSET_FP) + +const ir_regset ir_scratch_regset[] = { + IR_REGSET_INTERVAL(IR_REG_GP_FIRST, IR_REG_FP_LAST), + IR_REGSET_SCRATCH_X86, +}; + +const ir_call_conv_dsc ir_call_conv_x86_cdecl = { + 0, /* cleanup_stack_by_callee */ + 1, /* pass_struct_by_val */ + 0, /* sysv_varargs */ + 0, /* shadow_param_regs */ + 0, /* shadow_store_size */ + 0, /* int_param_regs_count */ + 0, /* fp_param_regs_count */ + IR_REG_RAX, /* int_ret_reg */ + IR_REG_NONE, /* fp_ret_reg */ + IR_REG_NONE, /* fp_varargs_reg */ + IR_REG_SCRATCH_X86, + NULL, + NULL, + IR_REGSET(IR_REG_RBX) | IR_REGSET(IR_REG_RBP) | IR_REGSET(IR_REG_RSI) | IR_REGSET(IR_REG_RDI), +}; + +const ir_call_conv_dsc ir_call_conv_x86_fastcall = { + 1, /* cleanup_stack_by_callee */ + 1, /* pass_struct_by_val */ + 0, /* sysv_varargs */ + 0, /* shadow_param_regs */ + 0, /* shadow_store_size */ + 2, /* int_param_regs_count */ + 0, /* fp_param_regs_count */ + IR_REG_RAX, /* int_ret_reg */ + IR_REG_NONE, /* fp_ret_reg */ + IR_REG_NONE, /* fp_varargs_reg */ + IR_REG_SCRATCH_X86, + (const int8_t[4]){IR_REG_RCX, IR_REG_RDX}, + NULL, + IR_REGSET(IR_REG_RBX) | IR_REGSET(IR_REG_RBP) | IR_REGSET(IR_REG_RSI) | IR_REGSET(IR_REG_RDI), +}; + +# define ir_call_conv_default ir_call_conv_x86_cdecl + +#endif + #define IR_RULES(_) \ _(CMP_INT) \ _(CMP_FP) \ @@ -1156,6 +1270,8 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co const ir_insn *insn; int n = 0; int flags = IR_USE_MUST_BE_IN_REG | IR_OP1_MUST_BE_IN_REG | IR_OP2_MUST_BE_IN_REG | IR_OP3_MUST_BE_IN_REG; + const ir_proto_t *proto; + const ir_call_conv_dsc *cc; constraints->def_reg = IR_REG_NONE; constraints->hints_count = 0; @@ -1391,21 +1507,48 @@ op2_const: break; case IR_CALL: insn = &ctx->ir_base[ref]; - if (IR_IS_TYPE_INT(insn->type)) { - constraints->def_reg = IR_REG_INT_RET1; -#ifdef IR_REG_FP_RET1 - } else { - constraints->def_reg = IR_REG_FP_RET1; + proto = ir_call_proto(ctx, insn); + cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + if (insn->type != IR_VOID) { + if (IR_IS_TYPE_INT(insn->type)) { + constraints->def_reg = cc->int_ret_reg; + } else { + IR_ASSERT(IR_IS_TYPE_FP(insn->type)); +#ifdef IR_TARGET_X86 + if (cc->fp_ret_reg == IR_REG_NONE) { + ctx->flags2 |= IR_HAS_FP_RET_SLOT; + } else #endif + { + constraints->def_reg = cc->fp_ret_reg; + } + } } - constraints->tmp_regs[0] = IR_SCRATCH_REG(IR_REG_SCRATCH, IR_USE_SUB_REF, IR_DEF_SUB_REF); + constraints->tmp_regs[0] = IR_SCRATCH_REG(cc->scratch_reg, IR_USE_SUB_REF, IR_DEF_SUB_REF); n = 1; - IR_FALLTHROUGH; + if (!IR_IS_CONST_REF(insn->op2) + && proto && (proto->flags & IR_VARARG_FUNC) && cc->fp_varargs_reg != IR_REG_NONE) { + constraints->tmp_regs[n] = IR_SCRATCH_REG(cc->fp_varargs_reg, IR_LOAD_SUB_REF, IR_USE_SUB_REF); + n++; + } + if (insn->inputs_count > 2) { + goto get_arg_hints; + } + flags = IR_USE_SHOULD_BE_IN_REG | IR_OP2_SHOULD_BE_IN_REG | IR_OP3_SHOULD_BE_IN_REG; + break; case IR_TAILCALL: insn = &ctx->ir_base[ref]; + proto = ir_call_proto(ctx, insn); + cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + if (!IR_IS_CONST_REF(insn->op2) + && proto && (proto->flags & IR_VARARG_FUNC) && cc->fp_varargs_reg != IR_REG_NONE) { + constraints->tmp_regs[n] = IR_SCRATCH_REG(cc->fp_varargs_reg, IR_LOAD_SUB_REF, IR_USE_SUB_REF); + n++; + } if (insn->inputs_count > 2) { +get_arg_hints: constraints->hints[2] = IR_REG_NONE; - constraints->hints_count = ir_get_args_regs(ctx, insn, constraints->hints); + constraints->hints_count = ir_get_args_regs(ctx, insn, cc, constraints->hints); if (!IR_IS_CONST_REF(insn->op2)) { constraints->tmp_regs[n] = IR_TMP_REG(1, IR_ADDR, IR_LOAD_SUB_REF, IR_USE_SUB_REF); n++; @@ -1533,7 +1676,8 @@ op2_const: break; case IR_EXITCALL: flags = IR_USE_MUST_BE_IN_REG; - constraints->def_reg = IR_REG_INT_RET1; + cc = ir_get_call_conv_dsc(ctx->flags); + constraints->def_reg = cc->int_ret_reg; break; case IR_IF_INT: case IR_GUARD: @@ -1548,16 +1692,21 @@ op2_const: flags = IR_OP3_SHOULD_BE_IN_REG; break; case IR_RETURN_INT: + cc = ir_get_call_conv_dsc(ctx->flags); flags = IR_OP2_SHOULD_BE_IN_REG; - constraints->hints[2] = IR_REG_INT_RET1; + constraints->hints[2] = cc->int_ret_reg; constraints->hints_count = 3; break; case IR_RETURN_FP: -#ifdef IR_REG_FP_RET1 - flags = IR_OP2_SHOULD_BE_IN_REG; - constraints->hints[2] = IR_REG_FP_RET1; - constraints->hints_count = 3; + cc = ir_get_call_conv_dsc(ctx->flags); +#ifdef IR_TARGET_X86 + if (cc->fp_ret_reg != IR_REG_NONE) #endif + { + flags = IR_OP2_SHOULD_BE_IN_REG; + constraints->hints[2] = cc->fp_ret_reg; + constraints->hints_count = 3; + } break; case IR_SNAPSHOT: flags = 0; @@ -1888,20 +2037,12 @@ static void ir_match_fuse_load_cmp_fp(ir_ctx *ctx, ir_insn *insn, ir_ref root) } } -static void ir_match_fuse_load_cmp_fp_br(ir_ctx *ctx, ir_insn *insn, ir_ref root, bool direct) +static void ir_match_fuse_load_cmp_fp_br(ir_ctx *ctx, ir_insn *insn, ir_ref root) { - if (direct) { - if (insn->op == IR_LT || insn->op == IR_LE) { - /* swap operands to avoid P flag check */ - ir_swap_ops(insn); - insn->op ^= 3; - } - } else { - if (insn->op == IR_GT || insn->op == IR_GE) { - /* swap operands to avoid P flag check */ - ir_swap_ops(insn); - insn->op ^= 3; - } + if (insn->op == IR_LT || insn->op == IR_LE || insn->op == IR_UGT || insn->op == IR_UGE) { + /* swap operands to avoid P flag check */ + ir_swap_ops(insn); + insn->op ^= 3; } if (IR_IS_CONST_REF(insn->op2) && !IR_IS_FP_ZERO(ctx->ir_base[insn->op2])) { /* pass */ @@ -1926,7 +2067,7 @@ static uint32_t ir_match_builtin_call(ir_ctx *ctx, const ir_insn *func) { const ir_proto_t *proto = (const ir_proto_t *)ir_get_str(ctx, func->proto); - if (proto->flags & IR_BUILTIN_FUNC) { + if ((proto->flags & IR_CALL_CONV_MASK) == IR_CC_BUILTIN) { size_t name_len; const char *name = ir_get_strl(ctx, func->val.name, &name_len); @@ -2452,15 +2593,23 @@ binop_fp: } } ctx->flags2 |= IR_HAS_CALLS | IR_16B_FRAME_ALIGNMENT; -#ifndef IR_REG_FP_RET1 - if (IR_IS_TYPE_FP(insn->type)) { - ctx->flags2 |= IR_HAS_FP_RET_SLOT; - } -#endif IR_FALLTHROUGH; case IR_TAILCALL: case IR_IJMP: - ir_match_fuse_load(ctx, insn->op2, ref); + if (!IR_IS_CONST_REF(insn->op2)) { + if (ctx->ir_base[insn->op2].op == IR_PROTO) { + if (IR_IS_CONST_REF(ctx->ir_base[insn->op2].op1)) { + ctx->rules[insn->op2] = IR_FUSED | IR_SIMPLE | IR_PROTO; + } else { + ir_match_fuse_load(ctx, ctx->ir_base[insn->op2].op1, ref); + if (ctx->rules[ctx->ir_base[insn->op2].op1] & IR_FUSED) { + ctx->rules[insn->op2] = IR_FUSED | IR_SIMPLE | IR_PROTO; + } + } + } else { + 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) { @@ -2478,11 +2627,12 @@ binop_fp: case IR_VAR: return IR_STATIC_ALLOCA; case IR_PARAM: -#ifndef _WIN64 if (ctx->value_params && ctx->value_params[insn->op3 - 1].align) { - return IR_STATIC_ALLOCA; + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(ctx->flags); + if (cc->pass_struct_by_val) { + return IR_STATIC_ALLOCA; + } } -#endif return ctx->use_lists[ref].count > 0 ? IR_PARAM : IR_SKIPPED | IR_PARAM; case IR_ALLOCA: /* alloca() may be used only in functions */ @@ -2767,7 +2917,7 @@ store_int: return IR_CMP_AND_BRANCH_INT; } else { /* c = CMP(_, _) ... IF(c) => SKIP_CMP ... CMP_AND_BRANCH */ - ir_match_fuse_load_cmp_fp_br(ctx, op2_insn, ref, 1); + ir_match_fuse_load_cmp_fp_br(ctx, op2_insn, ref); ctx->rules[insn->op2] = IR_FUSED | IR_CMP_FP; return IR_CMP_AND_BRANCH_FP; } @@ -2864,7 +3014,7 @@ store_int: ctx->rules[insn->op1] = IR_FUSED | IR_CMP_INT; return IR_COND_CMP_INT; } else { - ir_match_fuse_load_cmp_fp_br(ctx, op1_insn, ref, 1); + ir_match_fuse_load_cmp_fp_br(ctx, op1_insn, ref); ctx->rules[insn->op1] = IR_FUSED | IR_CMP_FP; return IR_COND_CMP_FP; } @@ -2956,7 +3106,7 @@ store_int: return IR_GUARD_CMP_INT; } else { /* c = CMP(_, _) ... GUARD(c) => SKIP_CMP ... GUARD_CMP */ - ir_match_fuse_load_cmp_fp_br(ctx, op2_insn, ref, insn->op == IR_GUARD_NOT); + ir_match_fuse_load_cmp_fp_br(ctx, op2_insn, ref); ctx->rules[insn->op2] = IR_FUSED | IR_CMP_FP; return IR_GUARD_CMP_FP; } @@ -3907,59 +4057,68 @@ static void ir_emit_prologue(ir_ctx *ctx) } } if ((ctx->flags & IR_VARARG_FUNC) && (ctx->flags2 & IR_HAS_VA_START)) { -#if defined(_WIN64) - ir_reg fp; - int offset; + const ir_call_conv_dsc *cc = data->ra_data.cc; - if (ctx->flags & IR_USE_FRAME_POINTER) { - fp = IR_REG_FRAME_POINTER; - offset = sizeof(void*) * 2; - } else { - fp = IR_REG_STACK_POINTER; - offset = ctx->stack_frame_size + ctx->call_stack_size + sizeof(void*); + if (cc->shadow_store_size) { + ir_reg fp; + int shadow_store; + int offset = 0; + int n = 0; + + if (ctx->flags & IR_USE_FRAME_POINTER) { + fp = IR_REG_FRAME_POINTER; + shadow_store = sizeof(void*) * 2; + } else { + fp = IR_REG_STACK_POINTER; + shadow_store = ctx->stack_frame_size + ctx->call_stack_size + sizeof(void*); + } + + while (offset < cc->shadow_store_size && n < cc->int_param_regs_count) { + | mov [Ra(fp)+shadow_store+offset], Ra(cc->int_param_regs[n]) + n++; + offset += sizeof(void*); + } } - | mov [Ra(fp)+offset], Ra(IR_REG_INT_ARG1) - | mov [Ra(fp)+offset+8], Ra(IR_REG_INT_ARG2) - | mov [Ra(fp)+offset+16], Ra(IR_REG_INT_ARG3) - | mov [Ra(fp)+offset+24], Ra(IR_REG_INT_ARG4) -#elif defined(IR_TARGET_X64) + + if (cc->sysv_varargs) { + IR_ASSERT(sizeof(void*) == 8); +#ifdef IR_TARGET_X64 |.if X64 - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; - uint32_t i; - ir_reg fp; - int offset; + int32_t i; + ir_reg fp; + int offset; - if (ctx->flags & IR_USE_FRAME_POINTER) { - fp = IR_REG_FRAME_POINTER; + if (ctx->flags & IR_USE_FRAME_POINTER) { + fp = IR_REG_FRAME_POINTER; - offset = -(ctx->stack_frame_size - ctx->locals_area_size); - } else { - fp = IR_REG_STACK_POINTER; - offset = ctx->locals_area_size + ctx->call_stack_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; + } - if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < IR_REG_INT_ARGS) { - /* skip named args */ - offset += sizeof(void*) * ctx->gp_reg_params; - for (i = ctx->gp_reg_params; i < IR_REG_INT_ARGS; i++) { - | mov qword [Ra(fp)+offset], Rq(int_reg_params[i]) - offset += sizeof(void*); + if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < cc->int_param_regs_count) { + /* skip named args */ + offset += sizeof(void*) * ctx->gp_reg_params; + for (i = ctx->gp_reg_params; i < cc->int_param_regs_count; i++) { + | mov qword [Ra(fp)+offset], Rq(cc->int_param_regs[i]) + offset += sizeof(void*); + } } - } - if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < IR_REG_FP_ARGS) { - | test al, al - | je >1 - /* skip named args */ - offset += 16 * ctx->fp_reg_params; - for (i = ctx->fp_reg_params; i < IR_REG_FP_ARGS; i++) { - | movaps [Ra(fp)+offset], xmm(fp_reg_params[i]-IR_REG_FP_FIRST) - offset += 16; + if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < cc->fp_param_regs_count) { + | test al, al + | je >1 + /* skip named args */ + offset += 16 * ctx->fp_reg_params; + for (i = ctx->fp_reg_params; i < cc->fp_param_regs_count; i++) { + | movaps [Ra(fp)+offset], xmm(cc->fp_param_regs[i]-IR_REG_FP_FIRST) + offset += 16; + } + |1: } - |1: - } |.endif #endif + } } } @@ -6995,27 +7154,26 @@ static void ir_emit_return_void(ir_ctx *ctx) ir_emit_epilogue(ctx); -#ifdef IR_TARGET_X86 - if (sizeof(void*) == 4 && (ctx->flags & IR_FASTCALL_FUNC) && ctx->param_stack_size) { + if (data->ra_data.cc->cleanup_stack_by_callee && ctx->param_stack_size) { | ret ctx->param_stack_size - return; + } else { + | ret } -#endif - - | ret } static void ir_emit_return_int(ir_ctx *ctx, ir_ref ref, ir_insn *insn) { + ir_backend_data *data = ctx->data; + ir_reg ret_reg = data->ra_data.cc->int_ret_reg; ir_reg op2_reg = ctx->regs[ref][2]; - if (op2_reg != IR_REG_INT_RET1) { + if (op2_reg != ret_reg) { ir_type type = ctx->ir_base[insn->op2].type; if (op2_reg != IR_REG_NONE && !IR_REG_SPILLED(op2_reg)) { - ir_emit_mov(ctx, type, IR_REG_INT_RET1, op2_reg); + ir_emit_mov(ctx, type, ret_reg, op2_reg); } else { - ir_emit_load(ctx, type, IR_REG_INT_RET1, insn->op2); + ir_emit_load(ctx, type, ret_reg, insn->op2); } } ir_emit_return_void(ctx); @@ -7023,64 +7181,68 @@ static void ir_emit_return_int(ir_ctx *ctx, ir_ref ref, ir_insn *insn) static void ir_emit_return_fp(ir_ctx *ctx, ir_ref ref, ir_insn *insn) { + ir_backend_data *data = ctx->data; ir_reg op2_reg = ctx->regs[ref][2]; ir_type type = ctx->ir_base[insn->op2].type; + ir_reg ret_reg = data->ra_data.cc->fp_ret_reg; -#ifdef IR_REG_FP_RET1 - if (op2_reg != IR_REG_FP_RET1) { + if (op2_reg != ret_reg && ret_reg != IR_REG_NONE) { if (op2_reg != IR_REG_NONE && !IR_REG_SPILLED(op2_reg)) { - ir_emit_fp_mov(ctx, type, IR_REG_FP_RET1, op2_reg); + ir_emit_fp_mov(ctx, type, ret_reg, op2_reg); } else { - ir_emit_load(ctx, type, IR_REG_FP_RET1, insn->op2); + ir_emit_load(ctx, type, ret_reg, insn->op2); } } -#else - ir_backend_data *data = ctx->data; - dasm_State **Dst = &data->dasm_state; - if (IR_IS_CONST_REF(insn->op2)) { - ir_insn *value = &ctx->ir_base[insn->op2]; +#ifdef IR_TARGET_X86 + if (ret_reg == IR_REG_NONE) { + dasm_State **Dst = &data->dasm_state; - if ((type == IR_FLOAT && value->val.f == 0.0) || (type == IR_DOUBLE && value->val.d == 0.0)) { - | fldz - } else if ((type == IR_FLOAT && value->val.f == 1.0) || (type == IR_DOUBLE && value->val.d == 1.0)) { - | fld1 - } else { - int label = ir_get_const_label(ctx, insn->op2); + if (IR_IS_CONST_REF(insn->op2)) { + ir_insn *value = &ctx->ir_base[insn->op2]; + + if ((type == IR_FLOAT && value->val.f == 0.0) || (type == IR_DOUBLE && value->val.d == 0.0)) { + | fldz + } else if ((type == IR_FLOAT && value->val.f == 1.0) || (type == IR_DOUBLE && value->val.d == 1.0)) { + | fld1 + } else { + int label = ir_get_const_label(ctx, insn->op2); + + if (type == IR_DOUBLE) { + | fld qword [=>label] + } else { + IR_ASSERT(type == IR_FLOAT); + | fld dword [=>label] + } + } + } else if (op2_reg == IR_REG_NONE || IR_REG_SPILLED(op2_reg)) { + ir_reg fp; + int32_t offset = ir_ref_spill_slot_offset(ctx, insn->op2, &fp); if (type == IR_DOUBLE) { - | fld qword [=>label] + | fld qword [Ra(fp)+offset] } else { IR_ASSERT(type == IR_FLOAT); - | fld dword [=>label] + | fld dword [Ra(fp)+offset] } - } - } else if (op2_reg == IR_REG_NONE || IR_REG_SPILLED(op2_reg)) { - ir_reg fp; - int32_t offset = ir_ref_spill_slot_offset(ctx, insn->op2, &fp); - - if (type == IR_DOUBLE) { - | fld qword [Ra(fp)+offset] } else { - IR_ASSERT(type == IR_FLOAT); - | fld dword [Ra(fp)+offset] - } - } else { - int32_t offset = ctx->ret_slot; - ir_reg fp; + int32_t offset = ctx->ret_slot; + ir_reg fp; - IR_ASSERT(offset != -1); - offset = IR_SPILL_POS_TO_OFFSET(offset); - fp = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - ir_emit_store_mem_fp(ctx, type, IR_MEM_BO(fp, offset), op2_reg); - if (type == IR_DOUBLE) { - | fld qword [Ra(fp)+offset] - } else { - IR_ASSERT(type == IR_FLOAT); - | fld dword [Ra(fp)+offset] + IR_ASSERT(offset != -1); + offset = IR_SPILL_POS_TO_OFFSET(offset); + fp = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + ir_emit_store_mem_fp(ctx, type, IR_MEM_BO(fp, offset), op2_reg); + if (type == IR_DOUBLE) { + | fld qword [Ra(fp)+offset] + } else { + IR_ASSERT(type == IR_FLOAT); + | fld dword [Ra(fp)+offset] + } } } #endif + ir_emit_return_void(ctx); } @@ -8555,327 +8717,323 @@ static void ir_emit_frame_addr(ir_ctx *ctx, ir_ref def) static void ir_emit_va_start(ir_ctx *ctx, ir_ref def, ir_insn *insn) { -#if defined(_WIN64) || defined(IR_TARGET_X86) ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; dasm_State **Dst = &data->dasm_state; - ir_reg fp; - int arg_area_offset; - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg tmp_reg = ctx->regs[def][3]; - int32_t offset; - IR_ASSERT(tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + if (!cc->sysv_varargs) { + ir_reg fp; + int arg_area_offset; + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg tmp_reg = ctx->regs[def][3]; + int32_t offset; + + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (ctx->flags & IR_USE_FRAME_POINTER) { - fp = IR_REG_FRAME_POINTER; - arg_area_offset = sizeof(void*) * 2 + ctx->param_stack_size; + if (ctx->flags & IR_USE_FRAME_POINTER) { + fp = IR_REG_FRAME_POINTER; + arg_area_offset = sizeof(void*) * 2 + ctx->param_stack_size; + } else { + fp = IR_REG_STACK_POINTER; + arg_area_offset = ctx->stack_frame_size + ctx->call_stack_size + sizeof(void*) + ctx->param_stack_size; + } + | lea Ra(tmp_reg), aword [Ra(fp)+arg_area_offset] + | mov aword [Ra(op2_reg)+offset], Ra(tmp_reg) } else { - fp = IR_REG_STACK_POINTER; - arg_area_offset = ctx->stack_frame_size + ctx->call_stack_size + sizeof(void*) + ctx->param_stack_size; - } - | lea Ra(tmp_reg), aword [Ra(fp)+arg_area_offset] - | mov aword [Ra(op2_reg)+offset], Ra(tmp_reg) -#elif defined(IR_TARGET_X64) + IR_ASSERT(sizeof(void*) == 8); +#ifdef IR_TARGET_X64 |.if X64 - ir_backend_data *data = ctx->data; - dasm_State **Dst = &data->dasm_state; - ir_reg fp; - int reg_save_area_offset; - int overflow_arg_area_offset; - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg tmp_reg = ctx->regs[def][3]; - bool have_reg_save_area = 0; - int32_t offset; + ir_reg fp; + int reg_save_area_offset; + int overflow_arg_area_offset; + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg tmp_reg = ctx->regs[def][3]; + bool have_reg_save_area = 0; + int32_t offset; - IR_ASSERT(tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (ctx->flags & IR_USE_FRAME_POINTER) { - fp = IR_REG_FRAME_POINTER; - 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; - reg_save_area_offset = ctx->locals_area_size + ctx->call_stack_size; - overflow_arg_area_offset = ctx->stack_frame_size + ctx->call_stack_size + sizeof(void*) + ctx->param_stack_size; - } + if (ctx->flags & IR_USE_FRAME_POINTER) { + fp = IR_REG_FRAME_POINTER; + 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; + reg_save_area_offset = ctx->locals_area_size + ctx->call_stack_size; + overflow_arg_area_offset = ctx->stack_frame_size + ctx->call_stack_size + sizeof(void*) + ctx->param_stack_size; + } - if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < IR_REG_INT_ARGS) { - | lea Ra(tmp_reg), aword [Ra(fp)+reg_save_area_offset] - have_reg_save_area = 1; - /* Set va_list.gp_offset */ - | mov dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, gp_offset))], sizeof(void*) * ctx->gp_reg_params - } else { - reg_save_area_offset -= sizeof(void*) * IR_REG_INT_ARGS; - /* Set va_list.gp_offset */ - | mov dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, gp_offset))], sizeof(void*) * IR_REG_INT_ARGS - } - if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < IR_REG_FP_ARGS) { - if (!have_reg_save_area) { + if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < cc->int_param_regs_count) { | lea Ra(tmp_reg), aword [Ra(fp)+reg_save_area_offset] have_reg_save_area = 1; + /* Set va_list.gp_offset */ + | mov dword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, gp_offset))], sizeof(void*) * ctx->gp_reg_params + } else { + reg_save_area_offset -= sizeof(void*) * cc->int_param_regs_count; + /* Set va_list.gp_offset */ + | mov dword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, gp_offset))], sizeof(void*) * cc->int_param_regs_count } - /* Set va_list.fp_offset */ - | mov dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, fp_offset))], sizeof(void*) * IR_REG_INT_ARGS + 16 * ctx->fp_reg_params - } else { - /* Set va_list.fp_offset */ - | mov dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, fp_offset))], sizeof(void*) * IR_REG_INT_ARGS + 16 * IR_REG_FP_ARGS - } - if (have_reg_save_area) { - /* Set va_list.reg_save_area */ - | mov qword [Ra(op2_reg)+(offset+offsetof(ir_va_list, reg_save_area))], Ra(tmp_reg) - } - | lea Ra(tmp_reg), aword [Ra(fp)+overflow_arg_area_offset] - /* Set va_list.overflow_arg_area */ - | mov qword [Ra(op2_reg)+(offset+offsetof(ir_va_list, overflow_arg_area))], Ra(tmp_reg) + if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < cc->fp_param_regs_count) { + if (!have_reg_save_area) { + | lea Ra(tmp_reg), aword [Ra(fp)+reg_save_area_offset] + have_reg_save_area = 1; + } + /* Set va_list.fp_offset */ + | mov dword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, fp_offset))], sizeof(void*) * cc->int_param_regs_count + 16 * ctx->fp_reg_params + } else { + /* Set va_list.fp_offset */ + | mov dword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, fp_offset))], sizeof(void*) * cc->int_param_regs_count + 16 * cc->fp_param_regs_count + } + if (have_reg_save_area) { + /* Set va_list.reg_save_area */ + | mov qword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, reg_save_area))], Ra(tmp_reg) + } + | lea Ra(tmp_reg), aword [Ra(fp)+overflow_arg_area_offset] + /* Set va_list.overflow_arg_area */ + | mov qword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, overflow_arg_area))], Ra(tmp_reg) |.endif -#else - IR_ASSERT(0 && "NIY va_start"); #endif + } } static void ir_emit_va_copy(ir_ctx *ctx, ir_ref def, ir_insn *insn) { -#if defined(_WIN64) || defined(IR_TARGET_X86) ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; dasm_State **Dst = &data->dasm_state; - ir_reg tmp_reg = ctx->regs[def][1]; - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg op3_reg = ctx->regs[def][3]; - int32_t op2_offset, op3_offset; - IR_ASSERT(tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + if (!cc->sysv_varargs) { + ir_reg tmp_reg = ctx->regs[def][1]; + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg op3_reg = ctx->regs[def][3]; + int32_t op2_offset, op3_offset; + + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + op2_offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + op2_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - op2_offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - op2_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (op3_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op3_reg)) { - op3_reg = IR_REG_NUM(op3_reg); - ir_emit_load(ctx, IR_ADDR, op3_reg, insn->op3); + if (op3_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op3_reg)) { + op3_reg = IR_REG_NUM(op3_reg); + ir_emit_load(ctx, IR_ADDR, op3_reg, insn->op3); + } + op3_offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA); + op3_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + op3_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op3]); } - op3_offset = 0; + | mov Ra(tmp_reg), aword [Ra(op3_reg)+op3_offset] + | mov aword [Ra(op2_reg)+op2_offset], Ra(tmp_reg) } else { - IR_ASSERT(ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA); - op3_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - op3_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op3]); - } - | mov Ra(tmp_reg), aword [Ra(op3_reg)+op3_offset] - | mov aword [Ra(op2_reg)+op2_offset], Ra(tmp_reg) -#elif defined(IR_TARGET_X64) + IR_ASSERT(sizeof(void*) == 8); +#ifdef IR_TARGET_X64 |.if X64 - ir_backend_data *data = ctx->data; - dasm_State **Dst = &data->dasm_state; - ir_reg tmp_reg = ctx->regs[def][1]; - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg op3_reg = ctx->regs[def][3]; - int32_t op2_offset, op3_offset; + ir_reg tmp_reg = ctx->regs[def][1]; + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg op3_reg = ctx->regs[def][3]; + int32_t op2_offset, op3_offset; - IR_ASSERT(tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); - } - op2_offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - op2_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (op3_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op3_reg)) { - op3_reg = IR_REG_NUM(op3_reg); - ir_emit_load(ctx, IR_ADDR, op3_reg, insn->op3); + IR_ASSERT(tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + op2_offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + op2_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - op3_offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA); - op3_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - op3_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op3]); - } - | mov Rd(tmp_reg), dword [Ra(op3_reg)+(op3_offset+offsetof(ir_va_list, gp_offset))] - | mov dword [Ra(op2_reg)+(op2_offset+offsetof(ir_va_list, gp_offset))], Rd(tmp_reg) - | mov Rd(tmp_reg), dword [Ra(op3_reg)+(op3_offset+offsetof(ir_va_list, fp_offset))] - | mov aword [Ra(op2_reg)+(op2_offset+offsetof(ir_va_list, fp_offset))], Ra(tmp_reg) - | mov Ra(tmp_reg), aword [Ra(op3_reg)+(op3_offset+offsetof(ir_va_list, overflow_arg_area))] - | mov aword [Ra(op2_reg)+(op2_offset+offsetof(ir_va_list, overflow_arg_area))], Ra(tmp_reg) - | mov Ra(tmp_reg), aword [Ra(op3_reg)+(op3_offset+offsetof(ir_va_list, reg_save_area))] - | mov aword [Ra(op2_reg)+(op2_offset+offsetof(ir_va_list, reg_save_area))], Ra(tmp_reg) + if (op3_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op3_reg)) { + op3_reg = IR_REG_NUM(op3_reg); + ir_emit_load(ctx, IR_ADDR, op3_reg, insn->op3); + } + op3_offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op3) == IR_STATIC_ALLOCA); + op3_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + op3_offset = ir_local_offset(ctx, &ctx->ir_base[insn->op3]); + } + | mov Rd(tmp_reg), dword [Ra(op3_reg)+(op3_offset+offsetof(ir_x86_64_sysv_va_list, gp_offset))] + | mov dword [Ra(op2_reg)+(op2_offset+offsetof(ir_x86_64_sysv_va_list, gp_offset))], Rd(tmp_reg) + | mov Rd(tmp_reg), dword [Ra(op3_reg)+(op3_offset+offsetof(ir_x86_64_sysv_va_list, fp_offset))] + | mov aword [Ra(op2_reg)+(op2_offset+offsetof(ir_x86_64_sysv_va_list, fp_offset))], Ra(tmp_reg) + | mov Ra(tmp_reg), aword [Ra(op3_reg)+(op3_offset+offsetof(ir_x86_64_sysv_va_list, overflow_arg_area))] + | mov aword [Ra(op2_reg)+(op2_offset+offsetof(ir_x86_64_sysv_va_list, overflow_arg_area))], Ra(tmp_reg) + | mov Ra(tmp_reg), aword [Ra(op3_reg)+(op3_offset+offsetof(ir_x86_64_sysv_va_list, reg_save_area))] + | mov aword [Ra(op2_reg)+(op2_offset+offsetof(ir_x86_64_sysv_va_list, reg_save_area))], Ra(tmp_reg) |.endif -#else - IR_ASSERT(0 && "NIY va_copy"); #endif + } } static void ir_emit_va_arg(ir_ctx *ctx, ir_ref def, ir_insn *insn) { -#if defined(_WIN64) || defined(IR_TARGET_X86) ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; dasm_State **Dst = &data->dasm_state; - ir_type type = insn->type; - ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg tmp_reg = ctx->regs[def][3]; - int32_t offset; - IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + if (!cc->sysv_varargs) { + ir_type type = insn->type; + ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg tmp_reg = ctx->regs[def][3]; + int32_t offset; + + IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); } - offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - | mov Ra(tmp_reg), aword [Ra(op2_reg)+offset] -#ifdef _WIN64 - if (def_reg != IR_REG_NONE) { - ir_emit_load_mem(ctx, type, def_reg, IR_MEM_B(tmp_reg)); - } - | add Ra(tmp_reg), IR_MAX(ir_type_size[type], sizeof(void*)) -#else - if (!insn->op3) { - if (def_reg != IR_REG_NONE) { - ir_emit_load_mem(ctx, type, def_reg, IR_MEM_B(tmp_reg)); + | mov Ra(tmp_reg), aword [Ra(op2_reg)+offset] + if (!cc->pass_struct_by_val || !insn->op3) { + if (def_reg != IR_REG_NONE) { + ir_emit_load_mem(ctx, type, def_reg, IR_MEM_B(tmp_reg)); + } + | add Ra(tmp_reg), IR_MAX(ir_type_size[type], sizeof(void*)) + } else { + int size = IR_VA_ARG_SIZE(insn->op3); + + if (def_reg != IR_REG_NONE) { + IR_ASSERT(type == IR_ADDR); + int align = IR_VA_ARG_ALIGN(insn->op3); + + if (align > (int)sizeof(void*)) { + | add Ra(tmp_reg), (align-1) + | and Ra(tmp_reg), ~(align-1) + } + | mov Ra(def_reg), Ra(tmp_reg) + } + | add Ra(tmp_reg), IR_ALIGNED_SIZE(size, sizeof(void*)) + } + | mov aword [Ra(op2_reg)+offset], Ra(tmp_reg) + if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) { + ir_emit_store(ctx, type, def, def_reg); } - | add Ra(tmp_reg), IR_MAX(ir_type_size[type], sizeof(void*)) } else { - int size = IR_VA_ARG_SIZE(insn->op3); + IR_ASSERT(sizeof(void*) == 8); +#ifdef IR_TARGET_X64 +|.if X64 + ir_type type = insn->type; + ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); + ir_reg op2_reg = ctx->regs[def][2]; + ir_reg tmp_reg = ctx->regs[def][3]; + int32_t offset; - if (def_reg != IR_REG_NONE) { + IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE); + if (op2_reg != IR_REG_NONE) { + if (IR_REG_SPILLED(op2_reg)) { + op2_reg = IR_REG_NUM(op2_reg); + ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + } + offset = 0; + } else { + IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); + op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; + offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); + } + if (insn->op3) { + /* long struct arguemnt */ IR_ASSERT(type == IR_ADDR); 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_x86_64_sysv_va_list, overflow_arg_area))] if (align > (int)sizeof(void*)) { | add Ra(tmp_reg), (align-1) | and Ra(tmp_reg), ~(align-1) } - | mov Ra(def_reg), Ra(tmp_reg) - } - | add Ra(tmp_reg), IR_ALIGNED_SIZE(size, sizeof(void*)) - } -#endif - | mov aword [Ra(op2_reg)+offset], Ra(tmp_reg) - 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) -|.if X64 - ir_backend_data *data = ctx->data; - dasm_State **Dst = &data->dasm_state; - ir_type type = insn->type; - ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); - ir_reg op2_reg = ctx->regs[def][2]; - ir_reg tmp_reg = ctx->regs[def][3]; - int32_t offset; - - IR_ASSERT((def_reg != IR_REG_NONE || ctx->use_lists[def].count == 1) && tmp_reg != IR_REG_NONE); - if (op2_reg != IR_REG_NONE) { - if (IR_REG_SPILLED(op2_reg)) { - op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); - } - offset = 0; - } else { - IR_ASSERT(ir_rule(ctx, insn->op2) == IR_STATIC_ALLOCA); - op2_reg = (ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FRAME_POINTER : IR_REG_STACK_POINTER; - offset = ir_local_offset(ctx, &ctx->ir_base[insn->op2]); - } - if (insn->op3) { - /* long struct arguemnt */ - IR_ASSERT(type == IR_ADDR); - 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*)) { - | add Ra(tmp_reg), (align-1) - | and Ra(tmp_reg), ~(align-1) - } - if (def_reg != IR_REG_NONE) { - | mov Ra(def_reg), Ra(tmp_reg) - } - | add Ra(tmp_reg), IR_ALIGNED_SIZE(size, sizeof(void*)) - | mov aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, overflow_arg_area))], Ra(tmp_reg) - } else if (IR_IS_TYPE_INT(type)) { - | mov Rd(tmp_reg), dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, gp_offset))] - | cmp Rd(tmp_reg), sizeof(void*)*IR_REG_INT_ARGS - | jge >1 - | add Rd(tmp_reg), sizeof(void*) - | mov dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, gp_offset))], Rd(tmp_reg) - | add Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, reg_save_area))] - | jmp >2 - |1: - | mov Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, overflow_arg_area))] - | add Ra(tmp_reg), sizeof(void*) - | mov aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, overflow_arg_area))], Ra(tmp_reg) - |2: - if (def_reg != IR_REG_NONE) { - if (ir_type_size[type] == 8) { - | mov Rq(def_reg), qword [Ra(tmp_reg)-sizeof(void*)] - } else { - | mov Rd(def_reg), dword [Ra(tmp_reg)-sizeof(void*)] + if (def_reg != IR_REG_NONE) { + | mov Ra(def_reg), Ra(tmp_reg) + } + | add Ra(tmp_reg), IR_ALIGNED_SIZE(size, sizeof(void*)) + | mov aword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, overflow_arg_area))], Ra(tmp_reg) + } else if (IR_IS_TYPE_INT(type)) { + | mov Rd(tmp_reg), dword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, gp_offset))] + | cmp Rd(tmp_reg), sizeof(void*) * cc->int_param_regs_count + | jge >1 + | add Rd(tmp_reg), sizeof(void*) + | mov dword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, gp_offset))], Rd(tmp_reg) + | add Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, reg_save_area))] + | jmp >2 + |1: + | mov Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, overflow_arg_area))] + | add Ra(tmp_reg), sizeof(void*) + | mov aword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, overflow_arg_area))], Ra(tmp_reg) + |2: + if (def_reg != IR_REG_NONE) { + if (ir_type_size[type] == 8) { + | mov Rq(def_reg), qword [Ra(tmp_reg)-sizeof(void*)] + } else { + | mov Rd(def_reg), dword [Ra(tmp_reg)-sizeof(void*)] + } } + } else { + | mov Rd(tmp_reg), dword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, fp_offset))] + | cmp Rd(tmp_reg), sizeof(void*) * cc->int_param_regs_count + 16 * cc->fp_param_regs_count + | jge >1 + | add Rd(tmp_reg), 16 + | mov dword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, fp_offset))], Rd(tmp_reg) + | add Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, reg_save_area))] + if (def_reg != IR_REG_NONE) { + ir_emit_load_mem_fp(ctx, type, def_reg, IR_MEM_BO(tmp_reg, -16)); + } + | jmp >2 + |1: + | mov Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, overflow_arg_area))] + if (def_reg != IR_REG_NONE) { + ir_emit_load_mem_fp(ctx, type, def_reg, IR_MEM_BO(tmp_reg, 0)); + } + | add Ra(tmp_reg), 8 + | mov aword [Ra(op2_reg)+(offset+offsetof(ir_x86_64_sysv_va_list, overflow_arg_area))], Ra(tmp_reg) + |2: } - } else { - | mov Rd(tmp_reg), dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, fp_offset))] - | cmp Rd(tmp_reg), sizeof(void*) * IR_REG_INT_ARGS + 16 * IR_REG_FP_ARGS - | jge >1 - | add Rd(tmp_reg), 16 - | mov dword [Ra(op2_reg)+(offset+offsetof(ir_va_list, fp_offset))], Rd(tmp_reg) - | add Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, reg_save_area))] - if (def_reg != IR_REG_NONE) { - ir_emit_load_mem_fp(ctx, type, def_reg, IR_MEM_BO(tmp_reg, -16)); - } - | jmp >2 - |1: - | mov Ra(tmp_reg), aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, overflow_arg_area))] - if (def_reg != IR_REG_NONE) { - ir_emit_load_mem_fp(ctx, type, def_reg, IR_MEM_BO(tmp_reg, 0)); + if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) { + ir_emit_store(ctx, type, def, def_reg); } - | add Ra(tmp_reg), 8 - | mov aword [Ra(op2_reg)+(offset+offsetof(ir_va_list, overflow_arg_area))], Ra(tmp_reg) - |2: - } - if (def_reg != IR_REG_NONE && IR_REG_SPILLED(ctx->regs[def][0])) { - ir_emit_store(ctx, type, def, def_reg); - } |.endif -#else - IR_ASSERT(0 && "NIY va_arg"); #endif + } } static void ir_emit_switch(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn) @@ -9104,7 +9262,9 @@ static void ir_emit_switch(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn) val = &ctx->ir_base[use_insn->op2]; IR_ASSERT(!IR_IS_SYM_CONST(val->op)); label = ir_skip_empty_target_blocks(ctx, use_block); - if (IR_IS_32BIT(type, val->val)) { + if (val->val.u64 == 0) { + | ASM_REG_REG_OP test, type, op2_reg, op2_reg + } else if (IR_IS_32BIT(type, val->val)) { | ASM_REG_IMM_OP cmp, type, op2_reg, val->val.i32 } else { IR_ASSERT(sizeof(void*) == 8); @@ -9158,25 +9318,14 @@ static void ir_emit_switch(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn) } } -static int32_t ir_call_used_stack(ir_ctx *ctx, ir_insn *insn, int *copy_stack_ptr) +static int32_t ir_call_used_stack(ir_ctx *ctx, ir_insn *insn, const ir_call_conv_dsc *cc, int *copy_stack_ptr) { int j, n; ir_type type; int int_param = 0; int fp_param = 0; - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; int32_t used_stack = 0; -#ifdef _WIN64 int32_t copy_stack = 0; -#endif - -#ifdef IR_HAVE_FASTCALL - if (sizeof(void*) == 4 && ir_is_fastcall(ctx, insn)) { - int_reg_params_count = IR_REG_INT_FCARGS; - fp_reg_params_count = IR_REG_FP_FCARGS; - } -#endif n = insn->inputs_count; for (j = 3; j <= n; j++) { @@ -9187,55 +9336,49 @@ static int32_t ir_call_used_stack(ir_ctx *ctx, ir_insn *insn, int *copy_stack_pt int size = arg->op2; int align = arg->op3; -#ifdef _WIN64 - copy_stack += size; - align = IR_MAX((int)sizeof(void*), align); - copy_stack = IR_ALIGNED_SIZE(copy_stack, align); - type = IR_ADDR; -#else - align = IR_MAX((int)sizeof(void*), align); - used_stack = IR_ALIGNED_SIZE(used_stack, align); - used_stack += size; - used_stack = IR_ALIGNED_SIZE(used_stack, sizeof(void*)); - continue; -#endif + if (!cc->pass_struct_by_val) { + copy_stack += size; + align = IR_MAX((int)sizeof(void*), align); + copy_stack = IR_ALIGNED_SIZE(copy_stack, align); + type = IR_ADDR; + } else { + align = IR_MAX((int)sizeof(void*), align); + used_stack = IR_ALIGNED_SIZE(used_stack, align); + used_stack += size; + used_stack = IR_ALIGNED_SIZE(used_stack, sizeof(void*)); + continue; + } } - if (int_param >= int_reg_params_count) { + if (int_param >= cc->int_param_regs_count) { used_stack += IR_MAX(sizeof(void*), ir_type_size[type]); } int_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param++; -#endif + if (cc->shadow_param_regs) { + fp_param++; + } } else { IR_ASSERT(IR_IS_TYPE_FP(type)); - if (fp_param >= fp_reg_params_count) { + if (fp_param >= cc->fp_param_regs_count) { used_stack += IR_MAX(sizeof(void*), ir_type_size[type]); } fp_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - int_param++; -#endif + if (cc->shadow_param_regs) { + int_param++; + } } } /* Reserved "home space" or "shadow store" for register arguments (used in Windows64 ABI) */ - used_stack += IR_SHADOW_ARGS; + used_stack += cc->shadow_store_size; -#ifdef _WIN64 copy_stack = IR_ALIGNED_SIZE(copy_stack, 16); used_stack += copy_stack; *copy_stack_ptr = copy_stack; -#else - *copy_stack_ptr = 0; -#endif return used_stack; } -static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg tmp_reg) +static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const ir_proto_t *proto, const ir_call_conv_dsc *cc, ir_reg tmp_reg) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; @@ -9247,11 +9390,7 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg int int_param = 0; int fp_param = 0; int count = 0; - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; - int32_t used_stack, copy_stack = 0, stack_offset = IR_SHADOW_ARGS; + int32_t used_stack, copy_stack = 0, stack_offset = cc->shadow_store_size; ir_copy *copies; bool do_pass3 = 0; /* For temporaries we may use any scratch registers except for registers used for parameters */ @@ -9266,40 +9405,24 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg tmp_reg = IR_REG_RAX; } -#ifdef IR_HAVE_FASTCALL - if (sizeof(void*) == 4 && ir_is_fastcall(ctx, insn)) { - int_reg_params_count = IR_REG_INT_FCARGS; - fp_reg_params_count = IR_REG_FP_FCARGS; - int_reg_params = _ir_int_fc_reg_params; - fp_reg_params = _ir_fp_fc_reg_params; - } -#endif - if (insn->op == IR_CALL - && (ctx->flags & IR_PREALLOCATED_STACK) -#ifdef IR_HAVE_FASTCALL - && !ir_is_fastcall(ctx, insn) /* fast call functions restore stack pointer */ -#endif - ) { - // TODO: support for preallocated stack -#ifdef _WIN64 - used_stack = ir_call_used_stack(ctx, insn, ©_stack); -#else - used_stack = 0; -#endif + && (ctx->flags2 & IR_PREALLOCATED_STACK) + && !cc->cleanup_stack_by_callee) { + if (!cc->pass_struct_by_val) { + used_stack = ir_call_used_stack(ctx, insn, cc, ©_stack); + } else { + used_stack = 0; + } } else { - used_stack = ir_call_used_stack(ctx, insn, ©_stack); - if (IR_SHADOW_ARGS + used_stack = ir_call_used_stack(ctx, insn, cc, ©_stack); + if (cc->shadow_store_size && insn->op == IR_TAILCALL - && used_stack == IR_SHADOW_ARGS) { + && used_stack == cc->shadow_store_size) { used_stack = 0; } if (ctx->fixed_call_stack_size && used_stack <= ctx->fixed_call_stack_size -#ifdef IR_HAVE_FASTCALL - && !ir_is_fastcall(ctx, insn) /* fast call functions restore stack pointer */ -#endif - ) { + && !cc->cleanup_stack_by_callee) { used_stack = 0; } else { /* Stack must be 16 byte aligned */ @@ -9311,10 +9434,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg } } -#ifdef _WIN64 -|.if X64 if (copy_stack) { /* Copy struct arguments */ + IR_ASSERT(sizeof(void*) == 8); +|.if X64 int copy_stack_offset = 0; for (j = 3; j <= n; j++) { @@ -9347,9 +9470,8 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg | rep; movsb } } - } |.endif -#endif + } /* 1. move all register arguments that should be passed through stack * and collect arguments that should be passed through registers */ @@ -9360,8 +9482,7 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg arg_insn = &ctx->ir_base[arg]; type = arg_insn->type; if (IR_IS_TYPE_INT(type)) { -#ifndef _WIN64 - if (arg_insn->op == IR_ARGVAL) { + if (arg_insn->op == IR_ARGVAL && cc->pass_struct_by_val) { int size = arg_insn->op2; int align = arg_insn->op3; align = IR_MAX((int)sizeof(void*), align); @@ -9408,38 +9529,35 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg stack_offset = IR_ALIGNED_SIZE(stack_offset, sizeof(void*)); continue; } -#endif - if (int_param < int_reg_params_count) { - dst_reg = int_reg_params[int_param]; + if (int_param < cc->int_param_regs_count) { + dst_reg = cc->int_param_regs[int_param]; } else { dst_reg = IR_REG_NONE; /* pass argument through stack */ } int_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param++; - if (arg_insn->op == IR_ARGVAL) { + if (cc->shadow_param_regs) { + fp_param++; + } + if (arg_insn->op == IR_ARGVAL && !cc->pass_struct_by_val) { do_pass3 = 3; continue; } -#endif } else { IR_ASSERT(IR_IS_TYPE_FP(type)); - if (fp_param < fp_reg_params_count) { - dst_reg = fp_reg_params[fp_param]; + if (fp_param < cc->fp_param_regs_count) { + dst_reg = cc->fp_param_regs[fp_param]; } else { dst_reg = IR_REG_NONE; /* pass argument through stack */ } fp_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - int_param++; -#endif + if (cc->shadow_param_regs) { + int_param++; + } } if (dst_reg != IR_REG_NONE) { if (IR_IS_CONST_REF(arg) || src_reg == IR_REG_NONE || - (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(IR_REGSET_PRESERVED, IR_REG_NUM(src_reg)))) { + (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) { /* delay CONST->REG and MEM->REG moves to third pass */ do_pass3 = 1; } else { @@ -9474,11 +9592,9 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg /* 3. move the remaining memory and immediate values */ if (do_pass3) { -#ifdef _WIN64 int copy_stack_offset = 0; -#endif - stack_offset = IR_SHADOW_ARGS; + stack_offset = cc->shadow_store_size; int_param = 0; fp_param = 0; for (j = 3; j <= n; j++) { @@ -9491,60 +9607,57 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg int size = arg_insn->op2; int align = arg_insn->op3; -#ifndef _WIN64 - align = IR_MAX((int)sizeof(void*), align); - stack_offset = IR_ALIGNED_SIZE(stack_offset, align); - stack_offset += size; - stack_offset = IR_ALIGNED_SIZE(stack_offset, sizeof(void*)); - continue; -#else -|.if X64 - /* pass pointer to the copy on stack */ - copy_stack_offset += size; - align = IR_MAX((int)sizeof(void*), align); - copy_stack_offset = IR_ALIGNED_SIZE(copy_stack_offset, align); - if (int_param < int_reg_params_count) { - dst_reg = int_reg_params[int_param]; - | lea Ra(dst_reg), [rsp + (used_stack - copy_stack_offset)] + if (cc->pass_struct_by_val) { + align = IR_MAX((int)sizeof(void*), align); + stack_offset = IR_ALIGNED_SIZE(stack_offset, align); + stack_offset += size; + stack_offset = IR_ALIGNED_SIZE(stack_offset, sizeof(void*)); + continue; } else { - | lea Ra(tmp_reg), [rsp + (used_stack - copy_stack_offset)] - ir_emit_store_mem_int(ctx, IR_ADDR, IR_MEM_BO(IR_REG_STACK_POINTER, stack_offset), tmp_reg); - stack_offset += sizeof(void*); + /* pass pointer to the copy on stack */ + copy_stack_offset += size; + align = IR_MAX((int)sizeof(void*), align); + copy_stack_offset = IR_ALIGNED_SIZE(copy_stack_offset, align); + if (int_param < cc->int_param_regs_count) { + dst_reg = cc->int_param_regs[int_param]; + | lea Ra(dst_reg), [r4 + (used_stack - copy_stack_offset)] + } else { + | lea Ra(tmp_reg), [r4 + (used_stack - copy_stack_offset)] + ir_emit_store_mem_int(ctx, IR_ADDR, IR_MEM_BO(IR_REG_STACK_POINTER, stack_offset), tmp_reg); + stack_offset += sizeof(void*); + } + int_param++; + if (cc->shadow_param_regs) { + fp_param++; + } + continue; } - int_param++; - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param++; - continue; -|.endif -#endif } - if (int_param < int_reg_params_count) { - dst_reg = int_reg_params[int_param]; + if (int_param < cc->int_param_regs_count) { + dst_reg = cc->int_param_regs[int_param]; } else { dst_reg = IR_REG_NONE; /* argument already passed through stack */ } int_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param++; -#endif + if (cc->shadow_param_regs) { + fp_param++; + } } else { IR_ASSERT(IR_IS_TYPE_FP(type)); - if (fp_param < fp_reg_params_count) { - dst_reg = fp_reg_params[fp_param]; + if (fp_param < cc->fp_param_regs_count) { + dst_reg = cc->fp_param_regs[fp_param]; } else { dst_reg = IR_REG_NONE; /* argument already passed through stack */ } fp_param++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - int_param++; -#endif + if (cc->shadow_param_regs) { + int_param++; + } } if (dst_reg != IR_REG_NONE) { if (IR_IS_CONST_REF(arg) || src_reg == IR_REG_NONE || - (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(IR_REGSET_PRESERVED, IR_REG_NUM(src_reg)))) { + (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) { if (IR_IS_TYPE_INT(type)) { if (IR_IS_CONST_REF(arg)) { if (type == IR_I8 || type == IR_I16) { @@ -9612,17 +9725,16 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg } } -#ifdef _WIN64 /* WIN64 calling convention requires duplcation of parameters passed in FP register into GP ones */ - if (ir_is_vararg(ctx, insn)) { - n = IR_MIN(n, IR_MAX_REG_ARGS + 2); + if (proto && (proto->flags & IR_VARARG_FUNC) && cc->shadow_param_regs) { + n = IR_MIN(n, IR_MIN(cc->int_param_regs_count, cc->fp_param_regs_count) + 2); for (j = 3; j <= n; j++) { arg = ir_insn_op(insn, j); arg_insn = &ctx->ir_base[arg]; type = arg_insn->type; if (IR_IS_TYPE_FP(type)) { - src_reg = fp_reg_params[j-3]; - dst_reg = int_reg_params[j-3]; + src_reg = cc->fp_param_regs[j-3]; + dst_reg = cc->int_param_regs[j-3]; |.if X64 if (ctx->mflags & IR_X86_AVX) { | vmovd Rq(dst_reg), xmm(src_reg-IR_REG_FP_FIRST) @@ -9633,41 +9745,46 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg } } } - if (insn->op == IR_CALL && (ctx->flags & IR_PREALLOCATED_STACK)) { + + if (insn->op == IR_CALL && (ctx->flags2 & IR_PREALLOCATED_STACK)) { used_stack = 0; } -#endif -#ifdef IR_REG_VARARG_FP_REGS - /* set hidden argument to specify the number of vector registers used */ - if (ir_is_vararg(ctx, insn)) { - fp_param = IR_MIN(fp_param, fp_reg_params_count); - | mov Rd(IR_REG_VARARG_FP_REGS), fp_param + + if (proto && (proto->flags & IR_VARARG_FUNC) && cc->fp_varargs_reg != IR_REG_NONE) { + /* set hidden argument to specify the number of vector registers used */ + fp_param = IR_MIN(fp_param, cc->fp_param_regs_count); + if (fp_param) { + | mov Rd(cc->fp_varargs_reg), fp_param + } else { + | xor Rd(cc->fp_varargs_reg), Rd(cc->fp_varargs_reg) + } } -#endif return used_stack; } -static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, int32_t used_stack) +static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, const ir_proto_t *proto, const ir_call_conv_dsc *cc, int32_t used_stack) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; ir_reg def_reg; + ir_ref func = insn->op2; - if (IR_IS_CONST_REF(insn->op2)) { - void *addr = ir_call_addr(ctx, insn, &ctx->ir_base[insn->op2]); + if (!IR_IS_CONST_REF(func) && ctx->rules[func] == (IR_FUSED | IR_SIMPLE | IR_PROTO)) { + func = ctx->ir_base[func].op1; + } + if (IR_IS_CONST_REF(func)) { + void *addr = ir_call_addr(ctx, insn, &ctx->ir_base[func]); if (sizeof(void*) == 4 || IR_MAY_USE_32BIT_ADDR(ctx->code_buffer, addr)) { | call aword &addr } else { |.if X64 -|| ir_reg tmp_reg = IR_REG_RAX; - -#ifdef IR_REG_VARARG_FP_REGS -|| if (ir_is_vararg(ctx, insn)) { -|| tmp_reg = IR_REG_R11; +|| ir_reg tmp_reg = cc->int_ret_reg; +|| +|| if (proto && (proto->flags & IR_VARARG_FUNC) && tmp_reg == cc->fp_varargs_reg) { +|| tmp_reg = IR_REG_R11; // TODO: avoid usage of hardcoded temporary register ??? || } -#endif || if (IR_IS_SIGNED_32BIT(addr)) { | mov Rq(tmp_reg), ((ptrdiff_t)addr) // 0x48 0xc7 0xc0 || } else { @@ -9682,16 +9799,16 @@ static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, int32_t used if (op2_reg != IR_REG_NONE) { if (IR_REG_SPILLED(op2_reg)) { op2_reg = IR_REG_NUM(op2_reg); - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + ir_emit_load(ctx, IR_ADDR, op2_reg, func); } | call Ra(op2_reg) } else { ir_mem mem; - if (ir_rule(ctx, insn->op2) & IR_FUSED) { - mem = ir_fuse_load(ctx, def, insn->op2); + if (ir_rule(ctx, func) & IR_FUSED) { + mem = ir_fuse_load(ctx, def, func); } else { - mem = ir_ref_spill_slot(ctx, insn->op2); + mem = ir_ref_spill_slot(ctx, func); } | ASM_TMEM_OP call, aword, mem @@ -9702,7 +9819,7 @@ static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, int32_t used int32_t aligned_stack = IR_ALIGNED_SIZE(used_stack, 16); ctx->call_stack_size -= aligned_stack; - if (ir_is_fastcall(ctx, insn)) { + if (cc->cleanup_stack_by_callee) { aligned_stack -= used_stack; if (aligned_stack) { | add Ra(IR_REG_RSP), aligned_stack @@ -9716,31 +9833,32 @@ static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, int32_t used if (IR_IS_TYPE_INT(insn->type)) { def_reg = IR_REG_NUM(ctx->regs[def][0]); if (def_reg != IR_REG_NONE) { - if (def_reg != IR_REG_INT_RET1) { - ir_emit_mov(ctx, insn->type, def_reg, IR_REG_INT_RET1); + if (def_reg != cc->int_ret_reg) { + ir_emit_mov(ctx, insn->type, def_reg, cc->int_ret_reg); } if (IR_REG_SPILLED(ctx->regs[def][0])) { ir_emit_store(ctx, insn->type, def, def_reg); } } else if (ctx->use_lists[def].count > 1) { - ir_emit_store(ctx, insn->type, def, IR_REG_INT_RET1); + ir_emit_store(ctx, insn->type, def, cc->int_ret_reg); } } else { IR_ASSERT(IR_IS_TYPE_FP(insn->type)); def_reg = IR_REG_NUM(ctx->regs[def][0]); -#ifdef IR_REG_FP_RET1 - if (def_reg != IR_REG_NONE) { - if (def_reg != IR_REG_FP_RET1) { - ir_emit_fp_mov(ctx, insn->type, def_reg, IR_REG_FP_RET1); - } - if (IR_REG_SPILLED(ctx->regs[def][0])) { - ir_emit_store(ctx, insn->type, def, def_reg); + if (cc->fp_ret_reg != IR_REG_NONE) { + if (def_reg != IR_REG_NONE) { + if (def_reg != cc->fp_ret_reg) { + ir_emit_fp_mov(ctx, insn->type, def_reg, cc->fp_ret_reg); + } + if (IR_REG_SPILLED(ctx->regs[def][0])) { + ir_emit_store(ctx, insn->type, def, def_reg); + } + } else if (ctx->use_lists[def].count > 1) { + ir_emit_store(ctx, insn->type, def, cc->fp_ret_reg); } - } else if (ctx->use_lists[def].count > 1) { - ir_emit_store(ctx, insn->type, def, IR_REG_FP_RET1); } -#else - if (ctx->use_lists[def].count > 1) { +#ifdef IR_TARGET_X86 + if (ctx->use_lists[def].count > 1 && cc->fp_ret_reg == IR_REG_NONE) { int32_t offset; ir_reg fp; @@ -9776,18 +9894,23 @@ static void ir_emit_call_ex(ir_ctx *ctx, ir_ref def, ir_insn *insn, int32_t used static void ir_emit_call(ir_ctx *ctx, ir_ref def, ir_insn *insn) { - int32_t used_stack = ir_emit_arguments(ctx, def, insn, ctx->regs[def][1]); - ir_emit_call_ex(ctx, def, insn, used_stack); + const ir_proto_t *proto = ir_call_proto(ctx, insn); + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + int32_t used_stack = ir_emit_arguments(ctx, def, insn, proto, cc, ctx->regs[def][1]); + ir_emit_call_ex(ctx, def, insn, proto, cc, used_stack); } static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) { ir_backend_data *data = ctx->data; dasm_State **Dst = &data->dasm_state; - int32_t used_stack = ir_emit_arguments(ctx, def, insn, ctx->regs[def][1]); + const ir_proto_t *proto = ir_call_proto(ctx, insn); + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + int32_t used_stack = ir_emit_arguments(ctx, def, insn, proto, cc, ctx->regs[def][1]); + ir_ref func = insn->op2; if (used_stack != 0) { - ir_emit_call_ex(ctx, def, insn, used_stack); + ir_emit_call_ex(ctx, def, insn, proto, cc, used_stack); ir_emit_return_void(ctx); return; } @@ -9797,7 +9920,10 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) ir_reg op2_reg = IR_REG_NONE; ir_mem mem = IR_MEM_B(IR_REG_NONE); - if (!IR_IS_CONST_REF(insn->op2)) { + if (!IR_IS_CONST_REF(func) && ctx->rules[func] == (IR_FUSED | IR_SIMPLE | IR_PROTO)) { + func = ctx->ir_base[func].op1; + } + if (!IR_IS_CONST_REF(func)) { op2_reg = ctx->regs[def][2]; ir_regset preserved_regs = (ir_regset)ctx->used_preserved_regs | IR_REGSET(IR_REG_STACK_POINTER); @@ -9807,7 +9933,7 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) bool is_spill_slot = op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg) - && ctx->vregs[insn->op2]; + && ctx->vregs[func]; if (op2_reg != IR_REG_NONE && !is_spill_slot) { if (IR_REGSET_IN(preserved_regs, IR_REG_NUM(op2_reg))) { @@ -9815,20 +9941,20 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) op2_reg = IR_REG_RAX; if (IR_REG_SPILLED(orig_op2_reg)) { - ir_emit_load(ctx, IR_ADDR, op2_reg, insn->op2); + ir_emit_load(ctx, IR_ADDR, op2_reg, func); } else { - ir_type type = ctx->ir_base[insn->op2].type; + ir_type type = ctx->ir_base[func].type; | ASM_REG_REG_OP mov, type, op2_reg, IR_REG_NUM(orig_op2_reg) } } else { op2_reg = IR_REG_NUM(op2_reg); } } else { - if (ir_rule(ctx, insn->op2) & IR_FUSED) { + if (ir_rule(ctx, func) & IR_FUSED) { IR_ASSERT(op2_reg == IR_REG_NONE); - mem = ir_fuse_load(ctx, def, insn->op2); + mem = ir_fuse_load(ctx, def, func); } else { - mem = ir_ref_spill_slot(ctx, insn->op2); + mem = ir_ref_spill_slot(ctx, func); } ir_reg base = IR_MEM_BASE(mem); ir_reg index = IR_MEM_INDEX(mem); @@ -9836,7 +9962,7 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) (index != IR_REG_NONE && IR_REGSET_IN(preserved_regs, index))) { op2_reg = IR_REG_RAX; - ir_type type = ctx->ir_base[insn->op2].type; + ir_type type = ctx->ir_base[func].type; ir_emit_load_mem_int(ctx, type, op2_reg, mem); } else { op2_reg = IR_REG_NONE; @@ -9846,20 +9972,18 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) ir_emit_epilogue(ctx); - if (IR_IS_CONST_REF(insn->op2)) { - void *addr = ir_call_addr(ctx, insn, &ctx->ir_base[insn->op2]); + if (IR_IS_CONST_REF(func)) { + void *addr = ir_call_addr(ctx, insn, &ctx->ir_base[func]); if (sizeof(void*) == 4 || IR_MAY_USE_32BIT_ADDR(ctx->code_buffer, addr)) { | jmp aword &addr } else { |.if X64 -|| ir_reg tmp_reg = IR_REG_RAX; - -#ifdef IR_REG_VARARG_FP_REGS -|| if (ir_is_vararg(ctx, insn)) { -|| tmp_reg = IR_REG_R11; +|| ir_reg tmp_reg = cc->int_ret_reg; +|| +|| if (proto && (proto->flags & IR_VARARG_FUNC) && tmp_reg == cc->fp_varargs_reg) { +|| tmp_reg = IR_REG_R11; // TODO: avoid usage of hardcoded temporary register ??? || } -#endif || if (IR_IS_SIGNED_32BIT(addr)) { | mov Rq(tmp_reg), ((ptrdiff_t)addr) // 0x48 0xc7 0xc0 || } else { @@ -10020,6 +10144,20 @@ static bool ir_emit_guard_jcc(ir_ctx *ctx, uint32_t b, ir_ref def, uint32_t next | jp &addr | jbe =>target break; + case IR_ULT: + | jp =>target + | jae =>target + break; + case IR_UGE: + | jb =>target + break; + case IR_ULE: + | jp =>target + | ja =>target + break; + case IR_UGT: + | jbe =>target + break; case IR_ORDERED: | jnp =>target break; @@ -10105,6 +10243,20 @@ static bool ir_emit_guard_jcc(ir_ctx *ctx, uint32_t b, ir_ref def, uint32_t next | jp &addr | jbe &target_addr break; + case IR_ULT: + | jp &target_addr + | jae &target_addr + break; + case IR_UGE: + | jb &target_addr + break; + case IR_ULE: + | jp &target_addr + | ja &target_addr + break; + case IR_UGT: + | jbe &target_addr + break; case IR_ORDERED: | jnp &target_addr break; @@ -10190,16 +10342,26 @@ static bool ir_emit_guard_jcc(ir_ctx *ctx, uint32_t b, ir_ref def, uint32_t next case IR_GT: | ja &addr break; + case IR_ULT: + | jb &addr + break; + case IR_UGE: + | jp &addr + | jae &addr + break; + case IR_ULE: + | jbe &addr + break; + case IR_UGT: + | jp &addr + | ja &addr + break; case IR_ORDERED: | jp &addr break; case IR_UNORDERED: | jnp &addr break; -// case IR_ULT: fprintf(stderr, "\tjb .LL%d\n", true_block); break; -// case IR_UGE: fprintf(stderr, "\tjae .LL%d\n", true_block); break; -// case IR_ULE: fprintf(stderr, "\tjbe .LL%d\n", true_block); break; -// case IR_UGT: fprintf(stderr, "\tja .LL%d\n", true_block); break; } } return 0; @@ -10348,7 +10510,11 @@ static bool ir_emit_guard_cmp_fp(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *i void *addr = ir_jmp_addr(ctx, insn, &ctx->ir_base[insn->op3]); if (insn->op == IR_GUARD) { - op ^= 1; // reverse + if (op == IR_EQ || op == IR_NE || op == IR_ORDERED || op == IR_UNORDERED) { + op ^= 1; // reverse + } else { + op ^= 5; // reverse + } } return ir_emit_guard_jcc(ctx, b, def, next_block, op, addr, 0, 0); } @@ -10565,6 +10731,11 @@ static void ir_emit_sse_round(ir_ctx *ctx, ir_ref def, ir_insn *insn, int round_ static void ir_emit_exitcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) { ir_backend_data *data = ctx->data; +#ifdef IR_TARGET_X86 + const ir_call_conv_dsc *cc = &ir_call_conv_x86_fastcall; +#else + const ir_call_conv_dsc *cc = &ir_call_conv_default; +#endif dasm_State **Dst = &data->dasm_state; ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); @@ -10604,13 +10775,13 @@ static void ir_emit_exitcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) | movsd qword [rsp+16*8+14*8], xmm14 | movsd qword [rsp+16*8+15*8], xmm15 | - | mov Ra(IR_REG_INT_ARG2), rsp - | lea Ra(IR_REG_INT_ARG1), [rsp+16*8+16*8+16] - | mov aword [rsp+4*8], Ra(IR_REG_INT_ARG1) - | mov Ra(IR_REG_INT_ARG1), [rsp+16*8+16*8+8] - |.if X64WIN - | sub rsp, 32 /* shadow space */ - |.endif + | mov Ra(cc->int_param_regs[1]), rsp + | lea Ra(cc->int_param_regs[0]), [rsp+16*8+16*8+16] + | mov aword [rsp+4*8], Ra(cc->int_param_regs[0]) + | mov Ra(cc->int_param_regs[0]), [rsp+16*8+16*8+8] + || if (cc->shadow_store_size) { + | sub rsp, cc->shadow_store_size /* shadow space */ + || } |.else | sub esp, 8*4+8*8+12 /* CPU regs + SSE regs */ | mov aword [esp+0*4], eax @@ -10629,10 +10800,10 @@ static void ir_emit_exitcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) | movsd qword [esp+8*4+6*8], xmm6 | movsd qword [esp+8*4+7*8], xmm7 | - | mov Ra(IR_REG_INT_FCARG2), esp - | lea Ra(IR_REG_INT_FCARG1), [esp+8*4+8*8+16] - | mov aword [esp+4*4], Ra(IR_REG_INT_FCARG1) - | mov Ra(IR_REG_INT_FCARG1), [esp+8*4+8*8+12] + | mov Ra(cc->int_param_regs[1]), esp + | lea Ra(cc->int_param_regs[0]), [esp+8*4+8*8+16] + | mov aword [esp+4*4], Ra(cc->int_param_regs[0]) + | mov Ra(cc->int_param_regs[0]), [esp+8*4+8*8+12] |.endif if (IR_IS_CONST_REF(insn->op2)) { @@ -10655,16 +10826,14 @@ static void ir_emit_exitcall(ir_ctx *ctx, ir_ref def, ir_insn *insn) } // restore SP - |.if X64WIN - | add rsp, 32+16*8+16*8+16 /* shadow space + CPU regs + SSE regs */ - |.elif X64 - | add rsp, 16*8+16*8+16 /* CPU regs + SSE regs */ + |.if X64 + | add rsp, cc->shadow_store_size+16*8+16*8+16 /* shadow space + CPU regs + SSE regs */ |.else | add esp, 8*4+8*8+16 /* CPU regs + SSE regs */ |.endif - if (def_reg != IR_REG_INT_RET1) { - ir_emit_mov(ctx, insn->type, def_reg, IR_REG_INT_RET1); + if (def_reg != cc->int_ret_reg) { + ir_emit_mov(ctx, insn->type, def_reg, cc->int_ret_reg); } if (IR_REG_SPILLED(ctx->regs[def][0])) { ir_emit_store(ctx, insn->type, def, def_reg); @@ -10710,23 +10879,11 @@ static void ir_emit_load_params(ir_ctx *ctx) int fp_param_num = 0; ir_reg src_reg; ir_reg dst_reg; - // TODO: Calling convention specific - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; + ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; int32_t stack_offset = 0; int32_t stack_start = 0; -#ifdef IR_TARGET_X86 - if (sizeof(void*) == 4 && (ctx->flags & IR_FASTCALL_FUNC)) { - int_reg_params_count = IR_REG_INT_FCARGS; - fp_reg_params_count = IR_REG_FP_FCARGS; - int_reg_params = _ir_int_fc_reg_params; - fp_reg_params = _ir_fp_fc_reg_params; - } -#endif - if (ctx->flags & IR_USE_FRAME_POINTER) { /* skip old frame pointer and return address */ stack_start = sizeof(void*) * 2 + ctx->stack_frame_size; @@ -10749,27 +10906,25 @@ static void ir_emit_load_params(ir_ctx *ctx) stack_offset += ctx->value_params[insn->op3 - 1].size; stack_offset = IR_ALIGNED_SIZE(stack_offset, sizeof(void*)); continue; - } else if (int_param_num < int_reg_params_count) { - src_reg = int_reg_params[int_param_num]; + } else if (int_param_num < cc->int_param_regs_count) { + src_reg = cc->int_param_regs[int_param_num]; } else { src_reg = IR_REG_NONE; } int_param_num++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param_num++; -#endif + if (cc->shadow_param_regs) { + fp_param_num++; + } } else { - if (fp_param_num < fp_reg_params_count) { - src_reg = fp_reg_params[fp_param_num]; + if (fp_param_num < cc->fp_param_regs_count) { + src_reg = cc->fp_param_regs[fp_param_num]; } else { src_reg = IR_REG_NONE; } fp_param_num++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - int_param_num++; -#endif + if (cc->shadow_param_regs) { + int_param_num++; + } } if (ctx->vregs[use]) { dst_reg = IR_REG_NUM(ctx->regs[use][0]); @@ -10805,10 +10960,9 @@ static ir_reg ir_get_free_reg(ir_type type, ir_regset available) return IR_REGSET_FIRST(available); } -static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to) +static int ir_fix_dessa_tmps(ir_ctx *ctx, uint8_t type, ir_ref from, ir_ref to, void *dessa_from_block) { - ir_backend_data *data = ctx->data; - ir_ref ref = ctx->cfg_blocks[data->dessa_from_block].end; + ir_ref ref = ctx->cfg_blocks[(intptr_t)dessa_from_block].end; if (to == 0) { if (IR_IS_TYPE_INT(type)) { @@ -10844,23 +10998,11 @@ static void ir_fix_param_spills(ir_ctx *ctx) int int_param_num = 0; int fp_param_num = 0; ir_reg src_reg; - // TODO: Calling convention specific - int int_reg_params_count = IR_REG_INT_ARGS; - int fp_reg_params_count = IR_REG_FP_ARGS; - const int8_t *int_reg_params = _ir_int_reg_params; - const int8_t *fp_reg_params = _ir_fp_reg_params; + ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; int32_t stack_start = 0; int32_t stack_offset = 0; -#ifdef IR_TARGET_X86 - if (sizeof(void*) == 4 && (ctx->flags & IR_FASTCALL_FUNC)) { - int_reg_params_count = IR_REG_INT_FCARGS; - fp_reg_params_count = IR_REG_FP_FCARGS; - int_reg_params = _ir_int_fc_reg_params; - fp_reg_params = _ir_fp_fc_reg_params; - } -#endif - if (ctx->flags & IR_USE_FRAME_POINTER) { /* skip old frame pointer and return address */ stack_start = sizeof(void*) * 2 + ctx->stack_frame_size; @@ -10874,8 +11016,7 @@ static void ir_fix_param_spills(ir_ctx *ctx) insn = &ctx->ir_base[use]; if (insn->op == IR_PARAM) { if (IR_IS_TYPE_INT(insn->type)) { -#ifndef _WIN64 - if (ctx->value_params && ctx->value_params[insn->op3 - 1].align) { + if (ctx->value_params && ctx->value_params[insn->op3 - 1].align && cc->pass_struct_by_val) { /* struct passed by value on stack */ size_t align = ctx->value_params[insn->op3 - 1].align; @@ -10886,28 +11027,25 @@ static void ir_fix_param_spills(ir_ctx *ctx) stack_offset = IR_ALIGNED_SIZE(stack_offset, sizeof(void*)); continue; } -#endif - if (int_param_num < int_reg_params_count) { - src_reg = int_reg_params[int_param_num]; + if (int_param_num < cc->int_param_regs_count) { + src_reg = cc->int_param_regs[int_param_num]; } else { src_reg = IR_REG_NONE; } int_param_num++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - fp_param_num++; -#endif + if (cc->shadow_param_regs) { + fp_param_num++; + } } else { - if (fp_param_num < fp_reg_params_count) { - src_reg = fp_reg_params[fp_param_num]; + if (fp_param_num < cc->fp_param_regs_count) { + src_reg = cc->fp_param_regs[fp_param_num]; } else { src_reg = IR_REG_NONE; } fp_param_num++; -#ifdef _WIN64 - /* WIN64 calling convention use common couter for int and fp registers */ - int_param_num++; -#endif + if (cc->shadow_param_regs) { + int_param_num++; + } } if (src_reg == IR_REG_NONE) { if (ctx->vregs[use]) { @@ -10927,12 +11065,13 @@ static void ir_fix_param_spills(ir_ctx *ctx) } } -#ifdef _WIN64 - /* WIN64 uses shsow area for registers */ - stack_offset += IR_MIN(int_param_num, int_reg_params_count) * sizeof(void*); -#endif - 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); + if (cc->shadow_store_size) { + /* WIN64 uses shadow area for registers */ + stack_offset += IR_MIN(int_param_num, cc->int_param_regs_count) * sizeof(void*); + } + + ctx->gp_reg_params = IR_MIN(int_param_num, cc->int_param_regs_count); + ctx->fp_reg_params = IR_MIN(fp_param_num, cc->fp_param_regs_count); ctx->param_stack_size = stack_offset; } @@ -10943,17 +11082,20 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) ir_insn *insn; ir_ref i, n, j, *p; uint32_t *rule, insn_flags; - ir_backend_data *data = ctx->data; ir_regset available = 0; ir_target_constraints constraints; uint32_t def_flags; ir_reg reg; + ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; + ir_regset scratch = ir_scratch_regset[cc->scratch_reg - IR_REG_NUM]; -#ifndef IR_REG_FP_RET1 +#ifdef IR_TARGET_X86 if (ctx->flags2 & IR_HAS_FP_RET_SLOT) { - ctx->ret_slot = ir_allocate_spill_slot(ctx, IR_DOUBLE, &data->ra_data); - } else if (ctx->ret_type == IR_FLOAT || ctx->ret_type == IR_DOUBLE) { - ctx->ret_slot = ir_allocate_spill_slot(ctx, ctx->ret_type, &data->ra_data); + ctx->ret_slot = ir_allocate_spill_slot(ctx, IR_DOUBLE); + } else if ((ctx->ret_type == IR_FLOAT || ctx->ret_type == IR_DOUBLE) + && cc->fp_ret_reg == IR_REG_NONE) { + ctx->ret_slot = ir_allocate_spill_slot(ctx, ctx->ret_type); } else { ctx->ret_slot = -1; } @@ -10986,10 +11128,16 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) case IR_LOOP_END: case IR_IGOTO_DUP: break; -#ifndef IR_REG_FP_RET1 +#ifdef IR_TARGET_X86 case IR_CALL: - if (ctx->ret_slot == -1 && (insn->type == IR_FLOAT || insn->type == IR_DOUBLE)) { - ctx->ret_slot = ir_allocate_spill_slot(ctx, IR_DOUBLE, &data->ra_data); + if (ctx->ret_slot == -1 + && (insn->type == IR_FLOAT || insn->type == IR_DOUBLE)) { + const ir_proto_t *proto = ir_call_proto(ctx, insn); + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + + if (cc->fp_ret_reg == IR_REG_NONE) { + ctx->ret_slot = ir_allocate_spill_slot(ctx, IR_DOUBLE); + } } #endif IR_FALLTHROUGH; @@ -11001,7 +11149,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) && *rule != IR_TEST_AND_BRANCH_INT && *rule != IR_GUARD_CMP_INT && *rule != IR_GUARD_CMP_FP) { - available = IR_REGSET_SCRATCH; + available = scratch; } if (ctx->vregs[i]) { reg = constraints.def_reg; @@ -11031,7 +11179,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) if (insn->op == IR_PARAM && reg == IR_REG_NONE) { ival->flags |= IR_LIVE_INTERVAL_MEM_PARAM; } else { - ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type, &data->ra_data); + ival->stack_spill_pos = ir_allocate_spill_slot(ctx, ival->type); } } else if (insn->op == IR_PARAM) { IR_ASSERT(0 && "unexpected PARAM"); @@ -11042,7 +11190,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) ir_ref n = use_list->count; if (n > 0) { - int32_t stack_spill_pos = insn->op3 = ir_allocate_spill_slot(ctx, insn->type, &data->ra_data); + int32_t stack_spill_pos = insn->op3 = ir_allocate_spill_slot(ctx, insn->type); ir_ref i, *p, use; ir_insn *use_insn; @@ -11097,10 +11245,14 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) } } ctx->regs[i][constraints.tmp_regs[n].num] = reg; - } else if (constraints.tmp_regs[n].reg == IR_REG_SCRATCH) { - available = IR_REGSET_DIFFERENCE(available, IR_REGSET_SCRATCH); } else { - IR_REGSET_EXCL(available, constraints.tmp_regs[n].reg); + ir_reg reg = constraints.tmp_regs[n].reg; + + if (reg > IR_REG_NUM) { + available = IR_REGSET_DIFFERENCE(available, ir_scratch_regset[reg - IR_REG_NUM]); + } else { + IR_REGSET_EXCL(available, reg); + } } } while (n); } @@ -11136,8 +11288,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx) rule += n; } if (bb->flags & IR_BB_DESSA_MOVES) { - data->dessa_from_block = b; - ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps); + ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps, (void*)(intptr_t)b); } } @@ -11154,12 +11305,12 @@ static void ir_preallocate_call_stack(ir_ctx *ctx) for (i = 1, insn = ctx->ir_base + 1; i < ctx->insns_count;) { if (insn->op == IR_CALL) { - call_stack_size = ir_call_used_stack(ctx, insn, ©_stack); + const ir_proto_t *proto = ir_call_proto(ctx, insn); + const ir_call_conv_dsc *cc = ir_get_call_conv_dsc(proto ? proto->flags : IR_CC_DEFAULT); + + call_stack_size = ir_call_used_stack(ctx, insn, cc, ©_stack); if (call_stack_size > peak_call_stack_size -#ifdef IR_HAVE_FASTCALL - && !ir_is_fastcall(ctx, insn) /* fast call functions restore stack pointer */ -#endif - ) { + && !cc->cleanup_stack_by_callee) { peak_call_stack_size = call_stack_size; } } @@ -11169,7 +11320,7 @@ static void ir_preallocate_call_stack(ir_ctx *ctx) } if (peak_call_stack_size) { ctx->call_stack_size = peak_call_stack_size; - ctx->flags |= IR_PREALLOCATED_STACK; + ctx->flags2 |= IR_PREALLOCATED_STACK; } } @@ -11179,19 +11330,22 @@ void ir_fix_stack_frame(ir_ctx *ctx) ctx->locals_area_size = ctx->stack_frame_size; -#if defined(IR_TARGET_X64) && !defined(_WIN64) if ((ctx->flags & IR_VARARG_FUNC) && (ctx->flags2 & IR_HAS_VA_START)) { - ctx->flags2 |= IR_16B_FRAME_ALIGNMENT; - ctx->stack_frame_size = IR_ALIGNED_SIZE(ctx->stack_frame_size, 16); - ctx->locals_area_size = ctx->stack_frame_size; - if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < IR_REG_INT_ARGS) { - additional_size += sizeof(void*) * IR_REG_INT_ARGS; - } - if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < IR_REG_FP_ARGS) { - additional_size += 16 * IR_REG_FP_ARGS; + ir_backend_data *data = ctx->data; + const ir_call_conv_dsc *cc = data->ra_data.cc; + + if (cc->sysv_varargs) { + ctx->flags2 |= IR_16B_FRAME_ALIGNMENT; + ctx->stack_frame_size = IR_ALIGNED_SIZE(ctx->stack_frame_size, 16); + ctx->locals_area_size = ctx->stack_frame_size; + if ((ctx->flags2 & (IR_HAS_VA_ARG_GP|IR_HAS_VA_COPY)) && ctx->gp_reg_params < cc->int_param_regs_count) { + additional_size += sizeof(void*) * cc->int_param_regs_count; + } + if ((ctx->flags2 & (IR_HAS_VA_ARG_FP|IR_HAS_VA_COPY)) && ctx->fp_reg_params < cc->fp_param_regs_count) { + additional_size += 16 * cc->fp_param_regs_count; + } } } -#endif if (ctx->used_preserved_regs) { ir_regset used_preserved_regs = (ir_regset)ctx->used_preserved_regs; @@ -11259,6 +11413,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) ir_ref igoto_dup_ref = IR_UNUSED; uint32_t igoto_dup_block = 0; + data.ra_data.cc = ir_get_call_conv_dsc(ctx->flags); data.ra_data.unused_slot_4 = 0; data.ra_data.unused_slot_2 = 0; data.ra_data.unused_slot_1 = 0; diff --git a/ext/opcache/jit/ir/ir_x86.h b/ext/opcache/jit/ir/ir_x86.h index 06bfa951cf21d..6399ca107fddc 100644 --- a/ext/opcache/jit/ir/ir_x86.h +++ b/ext/opcache/jit/ir/ir_x86.h @@ -82,14 +82,17 @@ enum _ir_reg { IR_GP_REGS(IR_GP_REG_ENUM) IR_FP_REGS(IR_FP_REG_ENUM) IR_REG_NUM, + IR_REG_ALL = IR_REG_NUM, /* special name for regset */ + IR_REG_SET_1, /* special name for regset */ + IR_REG_SET_2, /* special name for regset */ + IR_REG_SET_3, /* special name for regset */ + IR_REG_SET_NUM, }; #define IR_REG_GP_FIRST IR_REG_R0 #define IR_REG_FP_FIRST IR_REG_XMM0 #define IR_REG_GP_LAST (IR_REG_FP_FIRST - 1) #define IR_REG_FP_LAST (IR_REG_NUM - 1) -#define IR_REG_SCRATCH (IR_REG_NUM) /* special name for regset */ -#define IR_REG_ALL (IR_REG_NUM + 1) /* special name for regset */ #define IR_REGSET_64BIT 0 @@ -113,121 +116,4 @@ enum _ir_reg { #define IR_REG_RSI IR_REG_R6 #define IR_REG_RDI IR_REG_R7 -/* Calling Convention */ -#ifdef _WIN64 - -# define IR_REG_INT_RET1 IR_REG_RAX -# define IR_REG_FP_RET1 IR_REG_XMM0 -# define IR_REG_INT_ARGS 4 -# define IR_REG_FP_ARGS 4 -# define IR_REG_INT_ARG1 IR_REG_RCX -# define IR_REG_INT_ARG2 IR_REG_RDX -# define IR_REG_INT_ARG3 IR_REG_R8 -# define IR_REG_INT_ARG4 IR_REG_R9 -# define IR_REG_FP_ARG1 IR_REG_XMM0 -# define IR_REG_FP_ARG2 IR_REG_XMM1 -# define IR_REG_FP_ARG3 IR_REG_XMM2 -# define IR_REG_FP_ARG4 IR_REG_XMM3 -# define IR_MAX_REG_ARGS 4 -# define IR_SHADOW_ARGS 32 /* Reserved space in bytes - "home space" or "shadow store" for register arguments */ - -# define IR_REGSET_SCRATCH \ - (IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) \ - | IR_REGSET_INTERVAL(IR_REG_R8, IR_REG_R11) \ - | IR_REGSET_INTERVAL(IR_REG_XMM0, IR_REG_XMM5)) - -# define IR_REGSET_PRESERVED \ - (IR_REGSET(IR_REG_RBX) \ - | IR_REGSET_INTERVAL(IR_REG_RBP, IR_REG_RDI) \ - | IR_REGSET_INTERVAL(IR_REG_R12, IR_REG_R15) \ - | IR_REGSET_INTERVAL(IR_REG_XMM6, IR_REG_XMM15)) - -#elif defined(IR_TARGET_X64) - -# define IR_REG_INT_RET1 IR_REG_RAX -# define IR_REG_FP_RET1 IR_REG_XMM0 -# define IR_REG_INT_ARGS 6 -# define IR_REG_FP_ARGS 8 -# define IR_REG_INT_ARG1 IR_REG_RDI -# define IR_REG_INT_ARG2 IR_REG_RSI -# define IR_REG_INT_ARG3 IR_REG_RDX -# define IR_REG_INT_ARG4 IR_REG_RCX -# define IR_REG_INT_ARG5 IR_REG_R8 -# define IR_REG_INT_ARG6 IR_REG_R9 -# define IR_REG_FP_ARG1 IR_REG_XMM0 -# define IR_REG_FP_ARG2 IR_REG_XMM1 -# define IR_REG_FP_ARG3 IR_REG_XMM2 -# define IR_REG_FP_ARG4 IR_REG_XMM3 -# define IR_REG_FP_ARG5 IR_REG_XMM4 -# define IR_REG_FP_ARG6 IR_REG_XMM5 -# define IR_REG_FP_ARG7 IR_REG_XMM6 -# define IR_REG_FP_ARG8 IR_REG_XMM7 -# define IR_MAX_REG_ARGS 14 -# define IR_SHADOW_ARGS 0 - -# define IR_REG_VARARG_FP_REGS IR_REG_RAX /* hidden argument to specify the number of vector registers used */ - -# define IR_REGSET_SCRATCH \ - (IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) \ - | IR_REGSET_INTERVAL(IR_REG_RSI, IR_REG_RDI) \ - | IR_REGSET_INTERVAL(IR_REG_R8, IR_REG_R11) \ - | IR_REGSET_FP) - -# define IR_REGSET_PRESERVED \ - (IR_REGSET(IR_REG_RBX) \ - | IR_REGSET(IR_REG_RBP) \ - | IR_REGSET_INTERVAL(IR_REG_R12, IR_REG_R15)) - -typedef struct _ir_va_list { - uint32_t gp_offset; - uint32_t fp_offset; - void *overflow_arg_area; - void *reg_save_area; -} ir_va_list; - -#elif defined(IR_TARGET_X86) - -# define IR_REG_INT_RET1 IR_REG_RAX -# define IR_REG_INT_RET2 IR_REG_RDX -# define IR_REG_INT_ARGS 0 -# define IR_REG_FP_ARGS 0 - -# define IR_HAVE_FASTCALL 1 -# define IR_REG_INT_FCARGS 2 -# define IR_REG_FP_FCARGS 0 -# define IR_REG_INT_FCARG1 IR_REG_RCX -# define IR_REG_INT_FCARG2 IR_REG_RDX -# define IR_MAX_REG_ARGS 2 -# define IR_SHADOW_ARGS 0 - -# define IR_REGSET_SCRATCH \ - (IR_REGSET_INTERVAL(IR_REG_RAX, IR_REG_RDX) | IR_REGSET_FP) - -# define IR_REGSET_PRESERVED \ - (IR_REGSET(IR_REG_RBX) \ - | IR_REGSET(IR_REG_RBP) \ - | IR_REGSET_INTERVAL(IR_REG_RSI, IR_REG_RDI)) - -#else -# error "Unsupported target architecture" -#endif - -typedef struct _ir_tmp_reg { - union { - uint8_t num; - int8_t reg; - }; - uint8_t type; - int8_t start; - int8_t end; -} ir_tmp_reg; - -struct _ir_target_constraints { - int8_t def_reg; - uint8_t tmps_count; - uint8_t hints_count; - ir_tmp_reg tmp_regs[3]; - int8_t hints[IR_MAX_REG_ARGS + 3]; -}; - #endif /* IR_X86_H */ diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 3ffb669e84742..42236f0af90fe 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -303,6 +303,7 @@ static int zend_jit_needs_call_chain(zend_call_info *call_info, uint32_t b, cons case ZEND_DO_FCALL_BY_NAME: case ZEND_DO_FCALL: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: return 0; case ZEND_SEND_VAL: case ZEND_SEND_VAR: @@ -388,6 +389,7 @@ static int zend_jit_needs_call_chain(zend_call_info *call_info, uint32_t b, cons case ZEND_DO_FCALL_BY_NAME: case ZEND_DO_FCALL: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: end = opline; if (end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) { /* INIT_FCALL and DO_FCALL in different BasicBlocks */ @@ -867,6 +869,7 @@ static bool zend_jit_dec_call_level(uint8_t opcode) case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: case ZEND_CALLABLE_CONVERT: + case ZEND_CALLABLE_CONVERT_PARTIAL: return true; default: return false; diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 1c5cab899e783..0bcf972447a93 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -10078,7 +10078,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen } bool may_have_extra_named_params = - opline->extended_value == ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS && + (opline->extended_value & ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS) && (!func || func->common.fn_flags & ZEND_ACC_VARIADIC); if (!jit->reuse_ip) { diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index bed5ab59992ed..da1ac594e5e95 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -1059,7 +1059,8 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, TRACE_RECORD(ZEND_JIT_TRACE_DO_ICALL, 0, func); } } else if (opline->opcode == ZEND_INCLUDE_OR_EVAL - || opline->opcode == ZEND_CALLABLE_CONVERT) { + || opline->opcode == ZEND_CALLABLE_CONVERT + || opline->opcode == ZEND_CALLABLE_CONVERT_PARTIAL) { /* TODO: Support tracing JIT for ZEND_CALLABLE_CONVERT. */ stop = ZEND_JIT_TRACE_STOP_INTERPRETER; break; diff --git a/ext/opcache/tests/jit/gh20880.phpt b/ext/opcache/tests/jit/gh20880.phpt new file mode 100644 index 0000000000000..e8d0388fe66b6 --- /dev/null +++ b/ext/opcache/tests/jit/gh20880.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-20880 (JIT (tracing): NAN float comparisons incorrectly return true) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + $max) { + return $value; + } + return $max; +} + + +$max = 0.0; +for ($i = 0; $i < 100000; $i++) { + $max = observe(1.0, $max); + $max = observe(3.0, $max); +} + +$max = observe(4.0, $max); +$max = observe(NAN, $max); +var_dump($max); +?> +--EXPECT-- +float(4) diff --git a/ext/opcache/tests/opt/gh11245_2.phpt b/ext/opcache/tests/opt/gh11245_2.phpt index ade810c453b13..74aec8d7f8a84 100644 --- a/ext/opcache/tests/opt/gh11245_2.phpt +++ b/ext/opcache/tests/opt/gh11245_2.phpt @@ -28,11 +28,11 @@ $_main: 0000 T1 = PRE_INC_STATIC_PROP string("prop") string("X") 0001 T2 = ISSET_ISEMPTY_CV (empty) CV0($xx) 0002 JMPZ T2 0005 -0003 FREE T1 +0003 FREE T1 loop-end(+2) 0004 RETURN null 0005 FREE T1 0006 RETURN int(1) LIVE RANGES: - 1: 0001 - 0005 (tmp/var) + 1: 0001 - 0003 (tmp/var) Deprecated: Increment on non-numeric string is deprecated, use str_increment() instead in %s on line %d diff --git a/ext/opcache/tests/oss-fuzz-472563272.phpt b/ext/opcache/tests/oss-fuzz-472563272.phpt new file mode 100644 index 0000000000000..39519abe9ae05 --- /dev/null +++ b/ext/opcache/tests/oss-fuzz-472563272.phpt @@ -0,0 +1,14 @@ +--TEST-- +OSS-Fuzz #472563272: Borked block_pass JMP[N]Z optimization +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + +===DONE=== +--EXPECT-- +===DONE=== diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index d430f4833d3ca..3114e5b92712c 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -384,6 +384,12 @@ static void zend_file_cache_serialize_ast(zend_ast *ast, } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { zend_ast_fcc *fcc = (zend_ast_fcc*)ast; ZEND_MAP_PTR_INIT(fcc->fptr, NULL); + if (!IS_SERIALIZED(fcc->args)) { + SERIALIZE_PTR(fcc->args); + tmp = fcc->args; + UNSERIALIZE_PTR(tmp); + zend_file_cache_serialize_ast(tmp, script, info, buf); + } } else if (zend_ast_is_decl(ast)) { /* Not implemented. */ ZEND_UNREACHABLE(); @@ -1304,6 +1310,10 @@ static void zend_file_cache_unserialize_ast(zend_ast *ast, } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { zend_ast_fcc *fcc = (zend_ast_fcc*)ast; ZEND_MAP_PTR_NEW(fcc->fptr); + if (!IS_UNSERIALIZED(fcc->args)) { + UNSERIALIZE_PTR(fcc->args); + zend_file_cache_unserialize_ast(fcc->args, script, buf); + } } else if (zend_ast_is_decl(ast)) { /* Not implemented. */ ZEND_UNREACHABLE(); @@ -2109,7 +2119,7 @@ void zend_file_cache_invalidate(zend_string *full_path) if (ZCG(accel_directives).file_cache_read_only) { return; } - + char *filename; filename = zend_file_cache_get_bin_file_path(full_path); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index ef69cceb0250b..9bc2496837ce4 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -197,6 +197,7 @@ static zend_ast *zend_persist_ast(zend_ast *ast) node = (zend_ast *) copy; } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { zend_ast_fcc *copy = zend_shared_memdup(ast, sizeof(zend_ast_fcc)); + copy->args = zend_persist_ast(copy->args); node = (zend_ast *) copy; } else if (zend_ast_is_decl(ast)) { /* Not implemented. */ diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index c638d66619d0f..0b0ff51d0d4df 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -92,7 +92,9 @@ static void zend_persist_ast_calc(zend_ast *ast) ZVAL_PTR(&z, zend_ast_get_op_array(ast)->op_array); zend_persist_op_array_calc(&z); } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { + zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast; ADD_SIZE(sizeof(zend_ast_fcc)); + zend_persist_ast_calc(fcc_ast->args); } else if (zend_ast_is_decl(ast)) { /* Not implemented. */ ZEND_UNREACHABLE(); diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 2c09b89e31200..d00efbfe5c2ce 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1003,6 +1003,8 @@ PHP_FUNCTION(openssl_x509_parse) bool useshortnames = 1; char * tmpstr; zval subitem; + zval critext; + int critcount = 0; X509_EXTENSION *extension; X509_NAME *subject_name; char *cert_name; @@ -1115,18 +1117,22 @@ PHP_FUNCTION(openssl_x509_parse) add_assoc_zval(return_value, "purposes", &subitem); array_init(&subitem); - + array_init(&critext); for (i = 0; i < X509_get_ext_count(cert); i++) { int nid; extension = X509_get_ext(cert, i); nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension)); if (nid != NID_undef) { - extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension))); + extname = (char *)OBJ_nid2sn(nid); } else { OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1); extname = buf; } + if (X509_EXTENSION_get_critical(extension)) { + add_next_index_string(&critext, extname); + critcount++; + } bio_out = BIO_new(BIO_s_mem()); if (bio_out == NULL) { php_openssl_store_errors(); @@ -1150,6 +1156,11 @@ PHP_FUNCTION(openssl_x509_parse) BIO_free(bio_out); } add_assoc_zval(return_value, "extensions", &subitem); + if (critcount > 0) { + add_assoc_zval(return_value, "criticalExtensions", &critext); + } else { + zval_ptr_dtor(&critext); + } if (cert_str) { X509_free(cert); } diff --git a/ext/openssl/tests/crit.crt b/ext/openssl/tests/crit.crt new file mode 100644 index 0000000000000..b56df4051d1e5 --- /dev/null +++ b/ext/openssl/tests/crit.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC4DCCAkmgAwIBAgIUXulKXzpxr33sV/2LwI0+yhpUAZgwDQYJKoZIhvcNAQEF +BQAwgYExHjAcBgNVBAMMFUhlbnJpcXVlIGRvIE4uIEFuZ2VsbzELMAkGA1UEBhMC +QlIxGjAYBgNVBAgMEVJpbyBHcmFuZGUgZG8gU3VsMRUwEwYDVQQHDAxQb3J0byBB +bGVncmUxHzAdBgkqhkiG9w0BCQEWEGhuYW5nZWxvQHBocC5uZXQwHhcNMjUxMDAy +MTgwNjMwWhcNMjYxMDAyMTgwNjMwWjCBgTEeMBwGA1UEAwwVSGVucmlxdWUgZG8g +Ti4gQW5nZWxvMQswCQYDVQQGEwJCUjEaMBgGA1UECAwRUmlvIEdyYW5kZSBkbyBT +dWwxFTATBgNVBAcMDFBvcnRvIEFsZWdyZTEfMB0GCSqGSIb3DQEJARYQaG5hbmdl +bG9AcGhwLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAy16ej5ArW6Vf +j9YMBUFh+hM9FPN7hJkvCBp6XiPBZPK2P7xzmc2WWsUQsPpaMnN+NqggyEIXjDgj +ZuRZHr89Oqu+e/6KKIi0d8q8mBioihtSGSIqZZrbAveaCq81EipOtMLiNZm4KTFD ++Syov078XrOT5pFLV34ps9qoJHlHD6UCAwEAAaNTMFEwHQYDVR0OBBYEFNt+QHK9 +XDWF7CkpgRLoYmhqtz99MB8GA1UdIwQYMBaAFNt+QHK9XDWF7CkpgRLoYmhqtz99 +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAc6jR36JD6xkzq2r0 +uIEjhiieDfFXcAVgisqymPHt6DDMSajRskfWPO58ayBKmT2J1yPxx2vdjAZxIRcg +2a06ef2OxE62X4+WNm6skIKLCXmc3AgkT//cqCjOs54EQMpdCJ/mkkYo9gZMB1aQ +jgozP+80FNIaioaDWVZsTsg3q0Q= +-----END CERTIFICATE----- diff --git a/ext/openssl/tests/gh20802.phpt b/ext/openssl/tests/gh20802.phpt new file mode 100644 index 0000000000000..786679c41c6a5 --- /dev/null +++ b/ext/openssl/tests/gh20802.phpt @@ -0,0 +1,62 @@ +--TEST-- +GH-20802: undefined behavior with invalid SNI_server_certs option values +--EXTENSIONS-- +openssl +--SKIPIF-- + +--FILE-- + [ + 'local_cert' => '%s', + 'allow_self_signed' => true, + 'verify_peer_name' => false, + 'verify_peer' => false, + 'SNI_enabled' => true, + 'SNI_server_certs' => [ + 'localhost' => &$localhost, + ] + ] + ]); + $server = stream_socket_server('tls://127.0.0.1:12443', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); + stream_socket_accept($server, 3); +CODE; +$serverCode = sprintf($serverCode, $certFile); + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + +$ctx = stream_context_create([ + 'ssl' => [ + 'SNI_enabled' => true, + 'verify_peer_name' => false, + 'verify_peer' => false + ] + ]); + @stream_socket_client("tls://127.0.0.1:12443", $errno, $errstr, 1, $flags, $ctx); +CODE; + +include 'CertificateGenerator.inc'; +$certificateGenerator = new CertificateGenerator(); +$certificateGenerator->saveNewCertAsFileWithKey('gh20802-snioptions', $certFile); + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--CLEAN-- + +--EXPECTF-- +%a +PHP Warning: stream_socket_accept(): Failed to enable crypto in %s(%d) : eval()'d code on line %d +PHP Warning: stream_socket_accept(): Accept failed: Cannot enable crypto in %s(%d) : eval()'d code on line %d diff --git a/ext/openssl/tests/openssl_x509_parse_basic.phpt b/ext/openssl/tests/openssl_x509_parse_basic.phpt index ef63f0f85f497..7170b1a08aca2 100644 --- a/ext/openssl/tests/openssl_x509_parse_basic.phpt +++ b/ext/openssl/tests/openssl_x509_parse_basic.phpt @@ -8,7 +8,7 @@ if (OPENSSL_VERSION_NUMBER >= 0x30200000) die('skip For OpenSSL < 3.2'); ?> --FILE-- --EXPECTF-- bool(true) -array(16) { +array(17) { ["name"]=> - string(96) "/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net" + string(96) "/CN=Henrique do N. Angelo/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/emailAddress=hnangelo@php.net" ["subject"]=> array(5) { + ["CN"]=> + string(21) "Henrique do N. Angelo" ["C"]=> string(2) "BR" ["ST"]=> string(17) "Rio Grande do Sul" ["L"]=> string(12) "Porto Alegre" - ["CN"]=> - string(21) "Henrique do N. Angelo" ["emailAddress"]=> string(16) "hnangelo@php.net" } @@ -37,31 +37,31 @@ array(16) { string(8) "%s" ["issuer"]=> array(5) { + ["CN"]=> + string(21) "Henrique do N. Angelo" ["C"]=> string(2) "BR" ["ST"]=> string(17) "Rio Grande do Sul" ["L"]=> string(12) "Porto Alegre" - ["CN"]=> - string(21) "Henrique do N. Angelo" ["emailAddress"]=> string(16) "hnangelo@php.net" } ["version"]=> int(2) ["serialNumber"]=> - string(20) "12593567369101004962" + string(42) "0x5EE94A5F3A71AF7DEC57FD8BC08D3ECA1A540198" ["serialNumberHex"]=> - string(16) "AEC556CC723750A2" + string(40) "5EE94A5F3A71AF7DEC57FD8BC08D3ECA1A540198" ["validFrom"]=> - string(13) "080630102843Z" + string(13) "251002180630Z" ["validTo"]=> - string(13) "080730102843Z" + string(13) "261002180630Z" ["validFrom_time_t"]=> - int(1214821723) + int(1759428390) ["validTo_time_t"]=> - int(1217413723) + int(1790964390) ["signatureTypeSN"]=> string(8) "RSA-SHA1" ["signatureTypeLN"]=> @@ -157,26 +157,29 @@ array(16) { ["subjectKeyIdentifier"]=> string(59) "DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D" ["authorityKeyIdentifier"]=> - string(%d) "keyid:DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D -DirName:/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net -serial:AE:C5:56:CC:72:37:50:A2%A" + string(%d) "DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D" ["basicConstraints"]=> string(7) "CA:TRUE" } + ["criticalExtensions"]=> + array(1) { + [0]=> + string(16) "basicConstraints" + } } -array(16) { +array(17) { ["name"]=> - string(96) "/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net" + string(96) "/CN=Henrique do N. Angelo/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/emailAddress=hnangelo@php.net" ["subject"]=> array(5) { + ["commonName"]=> + string(21) "Henrique do N. Angelo" ["countryName"]=> string(2) "BR" ["stateOrProvinceName"]=> string(17) "Rio Grande do Sul" ["localityName"]=> string(12) "Porto Alegre" - ["commonName"]=> - string(21) "Henrique do N. Angelo" ["emailAddress"]=> string(16) "hnangelo@php.net" } @@ -184,31 +187,31 @@ array(16) { string(8) "%s" ["issuer"]=> array(5) { + ["commonName"]=> + string(21) "Henrique do N. Angelo" ["countryName"]=> string(2) "BR" ["stateOrProvinceName"]=> string(17) "Rio Grande do Sul" ["localityName"]=> string(12) "Porto Alegre" - ["commonName"]=> - string(21) "Henrique do N. Angelo" ["emailAddress"]=> string(16) "hnangelo@php.net" } ["version"]=> int(2) ["serialNumber"]=> - string(20) "12593567369101004962" + string(42) "0x5EE94A5F3A71AF7DEC57FD8BC08D3ECA1A540198" ["serialNumberHex"]=> - string(16) "AEC556CC723750A2" + string(40) "5EE94A5F3A71AF7DEC57FD8BC08D3ECA1A540198" ["validFrom"]=> - string(13) "080630102843Z" + string(13) "251002180630Z" ["validTo"]=> - string(13) "080730102843Z" + string(13) "261002180630Z" ["validFrom_time_t"]=> - int(1214821723) + int(1759428390) ["validTo_time_t"]=> - int(1217413723) + int(1790964390) ["signatureTypeSN"]=> string(8) "RSA-SHA1" ["signatureTypeLN"]=> @@ -304,10 +307,13 @@ array(16) { ["subjectKeyIdentifier"]=> string(59) "DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D" ["authorityKeyIdentifier"]=> - string(%d) "keyid:DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D -DirName:/C=BR/ST=Rio Grande do Sul/L=Porto Alegre/CN=Henrique do N. Angelo/emailAddress=hnangelo@php.net -serial:AE:C5:56:CC:72:37:50:A2%A" + string(%d) "DB:7E:40:72:BD:5C:35:85:EC:29:29:81:12:E8:62:68:6A:B7:3F:7D" ["basicConstraints"]=> string(7) "CA:TRUE" } + ["criticalExtensions"]=> + array(1) { + [0]=> + string(16) "basicConstraints" + } } diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 62929246a07f0..bd174f30095c6 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -1335,7 +1335,7 @@ static zend_result php_openssl_enable_server_sni( zend_ulong key_index; int i = 0; char resolved_path_buff[MAXPATHLEN]; - SSL_CTX *ctx; + SSL_CTX *ctx = NULL; /* If the stream ctx disables SNI we're finished here */ if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) { @@ -1377,6 +1377,8 @@ static zend_result php_openssl_enable_server_sni( return FAILURE; } + ZVAL_DEREF(current); + if (Z_TYPE_P(current) == IS_ARRAY) { zval *local_pk, *local_cert; zend_string *local_pk_str, *local_cert_str; @@ -1431,17 +1433,17 @@ static zend_result php_openssl_enable_server_sni( zend_string_release(local_pk_str); ctx = php_openssl_create_sni_server_ctx(resolved_cert_path_buff, resolved_pk_path_buff); - - } else if (php_openssl_check_path_str_ex( - Z_STR_P(current), resolved_path_buff, 0, false, false, - "SNI_server_certs in ssl stream context")) { - ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff); + } else if (Z_TYPE_P(current) == IS_STRING) { + if (php_openssl_check_path_str_ex(Z_STR_P(current), resolved_path_buff, 0, false, false, "SNI_server_certs in ssl stream context")) { + ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff); + } else { + php_error_docref(NULL, E_WARNING, + "Failed setting local cert chain file `%s'; file not found", + Z_STRVAL_P(current) + ); + } } else { - php_error_docref(NULL, E_WARNING, - "Failed setting local cert chain file `%s'; file not found", - Z_STRVAL_P(current) - ); - return FAILURE; + php_error_docref(NULL, E_WARNING, "SNI_server_certs options values must be of type array|string"); } if (ctx == NULL) { @@ -2219,25 +2221,32 @@ static int php_openssl_sockop_stat(php_stream *stream, php_stream_statbuf *ssb) static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_netstream_data_t *sock, php_stream_xport_param *xparam STREAMS_DC) /* {{{ */ { - bool nodelay = false; + php_sockvals sockvals = {0}; zval *tmpzval = NULL; xparam->outputs.client = NULL; - if (PHP_STREAM_CONTEXT(stream) && - (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL && - zend_is_true(tmpzval)) { - nodelay = true; + if (PHP_STREAM_CONTEXT(stream)) { + tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay"); + if (tmpzval != NULL && zend_is_true(tmpzval)) { + sockvals.mask |= PHP_SOCKVAL_TCP_NODELAY; + sockvals.tcp_nodelay = 1; + } + tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepidle"); + if (tmpzval != NULL) { + sockvals.mask |= PHP_SOCKVAL_TCP_KEEPIDLE; + sockvals.keepalive.keepidle = (int)zval_get_long(tmpzval); + } } - php_socket_t clisock = php_network_accept_incoming(sock->s.socket, + php_socket_t clisock = php_network_accept_incoming_ex(sock->s.socket, xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, xparam->want_addr ? &xparam->outputs.addr : NULL, xparam->want_addr ? &xparam->outputs.addrlen : NULL, xparam->inputs.timeout, xparam->want_errortext ? &xparam->outputs.error_text : NULL, &xparam->outputs.error_code, - nodelay); + &sockvals); if (clisock != SOCK_ERR) { php_openssl_netstream_data_t *clisockdata = (php_openssl_netstream_data_t*) emalloc(sizeof(*clisockdata)); 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/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/tests/pdo_fetch_class_change_ctor_args_during_fetch2.phpt b/ext/pdo/tests/pdo_fetch_class_change_ctor_args_during_fetch2.phpt index 23b91210d9dab..819b452ad808f 100644 --- a/ext/pdo/tests/pdo_fetch_class_change_ctor_args_during_fetch2.phpt +++ b/ext/pdo/tests/pdo_fetch_class_change_ctor_args_during_fetch2.phpt @@ -27,7 +27,6 @@ class Test { } } -// TODO Rename pdo_fetch_class_change_ctor_two table to pdo_fetch_class_change_ctor_two in PHP-8.4 $db->exec('CREATE TABLE pdo_fetch_class_change_ctor_two(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10))'); $db->exec("INSERT INTO pdo_fetch_class_change_ctor_two VALUES(1, 'A', 'alpha')"); $db->exec("INSERT INTO pdo_fetch_class_change_ctor_two VALUES(2, 'B', 'beta')"); 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/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/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 77425b25aee17..4bcea1e3e6572 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) { @@ -5679,7 +5663,7 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t goto cleanup; } if (opt & PGSQL_DML_ESCAPE) { - tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1); + tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld)); if (tmp == NULL) { php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld)); goto cleanup; @@ -5864,7 +5848,7 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr, return -1; } if (opt & PGSQL_DML_ESCAPE) { - char *tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1); + char *tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld)); if (tmp == NULL) { php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld)); return -1; diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 30c3b371e6bbd..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); } @@ -1571,7 +1577,7 @@ static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_l 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) { @@ -1589,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)") } @@ -2310,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; @@ -2326,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)); diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 144a3c1359f90..5ed213fb03e16 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -216,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 */ @@ -439,7 +440,7 @@ 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 */ diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index cd00880a0bf01..5dd1dc4090cd5 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1384,12 +1384,12 @@ static int phar_build(zend_object_iterator *iter, void *puser) /* {{{ */ zval *value; bool close_fp = true; struct _phar_t *p_obj = (struct _phar_t*) puser; - size_t str_key_len, base_len = ZSTR_LEN(p_obj->base); + size_t str_key_len, base_len = p_obj->base ? ZSTR_LEN(p_obj->base) : 0; phar_entry_data *data; php_stream *fp; size_t fname_len; size_t contents_len; - char *fname = NULL, *error = NULL, *base = ZSTR_VAL(p_obj->base), *save = NULL, *temp = NULL; + char *fname = NULL, *error = NULL, *base = p_obj->base ? ZSTR_VAL(p_obj->base) : NULL, *save = NULL, *temp = NULL; zend_string *opened; char *str_key; zend_class_entry *ce = p_obj->c; @@ -1828,7 +1828,7 @@ PHP_METHOD(Phar, buildFromIterator) zend_string *base = ZSTR_EMPTY_ALLOC(); struct _phar_t pass; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|S!", &obj, zend_ce_traversable, &base) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|P!", &obj, zend_ce_traversable, &base) == FAILURE) { RETURN_THROWS(); } @@ -4441,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; @@ -4486,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 08da1847cd9ce..4bd1e85666b85 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -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; diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 01ab3f2dd47ff..91b6b04996d67 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -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 */ 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/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/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/gh20882.phpt b/ext/phar/tests/gh20882.phpt new file mode 100644 index 0000000000000..8928178a22a9e --- /dev/null +++ b/ext/phar/tests/gh20882.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-20882 (phar buildFromIterator breaks with missing base directory) +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +--FILE-- +buildFromIterator( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(__DIR__.'/test79082', FilesystemIterator::SKIP_DOTS) + ), + null + ); +} catch (BadMethodCallException $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Iterator RecursiveIteratorIterator returns an SplFileInfo object, so base directory must be specified 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 82c784e621712..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) { @@ -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 660cd0a98782e..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 */ 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/random/tests/03_randomizer/methods/getBytesFromString_fast_path.phpt b/ext/random/tests/03_randomizer/methods/getBytesFromString_fast_path.phpt index 84c8ec611db80..7d7b98f1b27a9 100644 --- a/ext/random/tests/03_randomizer/methods/getBytesFromString_fast_path.phpt +++ b/ext/random/tests/03_randomizer/methods/getBytesFromString_fast_path.phpt @@ -41,7 +41,7 @@ for ($i = 1; $i <= strlen($allBytes); $i *= 2) { } // We also expect that each possible value appears at least once, if - // not is is very likely that some bits were erroneously masked away. + // not it is very likely that some bits were erroneously masked away. var_dump(count($count)); echo PHP_EOL; @@ -67,7 +67,7 @@ for ($i = 1; ($i + 1) <= strlen($allBytes); $i *= 2) { } // We expect that each possible value appears at least once, if - // not is is very likely that some bits were erroneously masked away. + // not it is very likely that some bits were erroneously masked away. var_dump(count($count)); echo PHP_EOL; @@ -90,7 +90,7 @@ for ($j = 0; $j < strlen($result); $j++) { } // We also expect that each possible value appears at least once, if -// not is is very likely that some bits were erroneously masked away. +// not it is very likely that some bits were erroneously masked away. var_dump(count($count)); ?> diff --git a/ext/readline/readline.c b/ext/readline/readline.c index d292921856909..838c74da86ce7 100644 --- a/ext/readline/readline.c +++ b/ext/readline/readline.c @@ -47,6 +47,11 @@ static zval _prepped_callback; static zval _readline_completion; static zval _readline_array; +ZEND_TLS char *php_readline_custom_readline_name = NULL; +#if defined(PHP_WIN32) || defined(HAVE_LIBEDIT) +ZEND_TLS char *php_readline_custom_line_buffer = NULL; +#endif + PHP_MINIT_FUNCTION(readline); PHP_MSHUTDOWN_FUNCTION(readline); PHP_RSHUTDOWN_FUNCTION(readline); @@ -146,7 +151,6 @@ PHP_FUNCTION(readline_info) zend_string *what = NULL; zval *value = NULL; size_t oldval; - char *oldstr; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!z!", &what, &value) == FAILURE) { RETURN_THROWS(); @@ -181,35 +185,29 @@ PHP_FUNCTION(readline_info) add_assoc_long(return_value,"attempted_completion_over",rl_attempted_completion_over); } else { if (zend_string_equals_literal_ci(what,"line_buffer")) { - oldstr = strdup(rl_line_buffer ? rl_line_buffer : ""); + RETVAL_STRING(SAFE_STRING(rl_line_buffer)); if (value) { if (!try_convert_to_string(value)) { RETURN_THROWS(); } + /* XXX: These stores would need to be atomic ideally or use a memory barrier */ #if !defined(PHP_WIN32) && !defined(HAVE_LIBEDIT) - if (!rl_line_buffer) { - rl_line_buffer = malloc(Z_STRLEN_P(value) + 1); - } else if (strlen(oldstr) < Z_STRLEN_P(value)) { - rl_extend_line_buffer(Z_STRLEN_P(value) + 1); - free(oldstr); - oldstr = strdup(rl_line_buffer ? rl_line_buffer : ""); + rl_extend_line_buffer(Z_STRLEN_P(value) + 1); + if (EXPECTED(rl_line_buffer)) { + memcpy(rl_line_buffer, Z_STRVAL_P(value), Z_STRLEN_P(value) + 1); } - memcpy(rl_line_buffer, Z_STRVAL_P(value), Z_STRLEN_P(value) + 1); #else - char *tmp = strdup(Z_STRVAL_P(value)); - if (tmp) { - if (rl_line_buffer) { - free(rl_line_buffer); - } - rl_line_buffer = tmp; + char *copy = strdup(Z_STRVAL_P(value)); + rl_line_buffer = copy; + if (php_readline_custom_line_buffer) { + free(php_readline_custom_line_buffer); } + php_readline_custom_line_buffer = copy; #endif #if !defined(PHP_WIN32) rl_end = Z_STRLEN_P(value); #endif } - RETVAL_STRING(SAFE_STRING(oldstr)); - free(oldstr); } else if (zend_string_equals_literal_ci(what, "point")) { RETVAL_LONG(rl_point); #ifndef PHP_WIN32 @@ -268,15 +266,19 @@ PHP_FUNCTION(readline_info) RETVAL_STRING((char *)SAFE_STRING(rl_library_version)); #endif } else if (zend_string_equals_literal_ci(what, "readline_name")) { - oldstr = (char*)rl_readline_name; + RETVAL_STRING(SAFE_STRING(rl_readline_name)); if (value) { - /* XXX if (rl_readline_name) free(rl_readline_name); */ if (!try_convert_to_string(value)) { RETURN_THROWS(); } - rl_readline_name = strdup(Z_STRVAL_P(value)); + char *copy = strdup(Z_STRVAL_P(value)); + /* XXX: This store would need to be atomic ideally or use a memory barrier */ + rl_readline_name = copy; + if (php_readline_custom_readline_name) { + free(php_readline_custom_readline_name); + } + php_readline_custom_readline_name = copy; } - RETVAL_STRING(SAFE_STRING(oldstr)); } else if (zend_string_equals_literal_ci(what, "attempted_completion_over")) { oldval = rl_attempted_completion_over; if (value) { diff --git a/ext/readline/tests/gh18139.phpt b/ext/readline/tests/gh18139.phpt new file mode 100644 index 0000000000000..a2de1f9720c79 --- /dev/null +++ b/ext/readline/tests/gh18139.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-18139 (Memory leak when overriding some settings via readline_info()) +--EXTENSIONS-- +readline +--FILE-- + +--EXPECTF-- +string(%d) "%S" +string(5) "first" +string(%d) "%S" +string(5) "third" diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index c6f681ee2276c..64e79651913fb 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -7112,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. */ @@ -7970,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/tests/gh20895.phpt b/ext/reflection/tests/gh20895.phpt new file mode 100644 index 0000000000000..f281078de4463 --- /dev/null +++ b/ext/reflection/tests/gh20895.phpt @@ -0,0 +1,108 @@ +--TEST-- +GH-20895: ReflectionProperty does not return the PHPDoc of a property if it contains an attribute with a Closure +--FILE-- +getDocComment()); +foreach ((new ReflectionClass(Foo::class))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionProperty(Foo::class, 'bar'))->getDocComment()); +foreach ((new ReflectionProperty(Foo::class, 'bar'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionMethod(Foo::class, 'bar'))->getDocComment()); +foreach ((new ReflectionMethod(Foo::class, 'bar'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionFunction('foo'))->getDocComment()); +foreach ((new ReflectionFunction('foo'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionFunction('bar'))->getDocComment()); +foreach ((new ReflectionFunction('bar'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionFunction('baz'))->getDocComment()); +foreach ((new ReflectionFunction('baz'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} + +?> +--EXPECT-- +string(10) "/** Foo */" +string(16) "/** Closure 1 */" +string(16) "/** Closure 2 */" +string(16) "/** Foo::$bar */" +string(16) "/** Closure 3 */" +string(16) "/** Closure 4 */" +string(16) "/** Closure 5 */" +string(17) "/** Foo::bar() */" +string(16) "/** Closure 6 */" +string(12) "/** foo() */" +string(16) "/** Closure 7 */" +string(12) "/** bar() */" +string(16) "/** Closure 8 */" +string(12) "/** baz() */" +bool(false) 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/sockets/sockets.c b/ext/sockets/sockets.c index 4a9332498c3cc..54f862d55366f 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 + } } @@ -2727,8 +2749,7 @@ PHP_FUNCTION(socket_export_stream) /* {{{ Gets array with contents of getaddrinfo about the given hostname. */ PHP_FUNCTION(socket_addrinfo_lookup) { - char *service = NULL; - size_t service_len = 0; + zend_string *service = NULL; zend_string *hostname, *key; zval *hint, *zhints = NULL; @@ -2738,7 +2759,7 @@ PHP_FUNCTION(socket_addrinfo_lookup) ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STR(hostname) Z_PARAM_OPTIONAL - Z_PARAM_STRING_OR_NULL(service, service_len) + Z_PARAM_STR_OR_NULL(service) Z_PARAM_ARRAY(zhints) ZEND_PARSE_PARAMETERS_END(); @@ -2802,14 +2823,16 @@ PHP_FUNCTION(socket_addrinfo_lookup) // Some platforms support also PF_LOCAL/AF_UNIX (e.g. FreeBSD) but the security concerns implied // make it not worth handling it (e.g. unwarranted write permissions on the socket). // Note existing socket_addrinfo* api already forbid such case. + if (val != AF_UNSPEC) { #ifdef HAVE_IPV6 - if (val != AF_INET && val != AF_INET6) { - zend_argument_value_error(3, "\"ai_family\" key must be AF_INET or AF_INET6"); + if (val != AF_INET && val != AF_INET6) { + zend_argument_value_error(3, "\"ai_family\" key must be AF_INET or AF_INET6"); #else - if (val != AF_INET) { - zend_argument_value_error(3, "\"ai_family\" key must be AF_INET"); + if (val != AF_INET) { + zend_argument_value_error(3, "\"ai_family\" key must be AF_INET"); #endif - RETURN_THROWS(); + RETURN_THROWS(); + } } hints.ai_family = (int)val; } else { @@ -2825,7 +2848,7 @@ PHP_FUNCTION(socket_addrinfo_lookup) } ZEND_HASH_FOREACH_END(); } - if (getaddrinfo(ZSTR_VAL(hostname), service, &hints, &result) != 0) { + if (getaddrinfo(ZSTR_VAL(hostname), service ? ZSTR_VAL(service) : NULL, &hints, &result) != 0) { RETURN_FALSE; } @@ -2833,7 +2856,11 @@ PHP_FUNCTION(socket_addrinfo_lookup) zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); for (rp = result; rp != NULL; rp = rp->ai_next) { - if (rp->ai_family != AF_UNSPEC) { + if (rp->ai_family == AF_INET +#ifdef HAVE_IPV6 + || rp->ai_family == AF_INET6 +#endif + ) { zval zaddr; object_init_ex(&zaddr, address_info_ce); diff --git a/ext/sockets/sockets.stub.php b/ext/sockets/sockets.stub.php index 3df9b598a1e8f..0f645da25ce59 100644 --- a/ext/sockets/sockets.stub.php +++ b/ext/sockets/sockets.stub.php @@ -19,6 +19,13 @@ */ const AF_INET6 = UNKNOWN; #endif +#ifdef AF_UNSPEC +/** + * @var int + * @cvalue AF_UNSPEC + */ +const AF_UNSPEC = UNKNOWN; +#endif #ifdef AF_DIVERT /** * @var int @@ -602,6 +609,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..50a81c5ee3a74 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: a89c4e54ab913728e10baf8f32b45323495d685b */ 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) @@ -317,6 +317,9 @@ static void register_sockets_symbols(int module_number) #if defined(HAVE_IPV6) REGISTER_LONG_CONSTANT("AF_INET6", AF_INET6, CONST_PERSISTENT); #endif +#if defined(AF_UNSPEC) + REGISTER_LONG_CONSTANT("AF_UNSPEC", AF_UNSPEC, CONST_PERSISTENT); +#endif #if defined(AF_DIVERT) REGISTER_LONG_CONSTANT("AF_DIVERT", AF_DIVERT, CONST_PERSISTENT); #endif @@ -527,6 +530,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/sodium/libsodium.c b/ext/sodium/libsodium.c index 2404f8aebb472..7d36fbb892884 100644 --- a/ext/sodium/libsodium.c +++ b/ext/sodium/libsodium.c @@ -2603,7 +2603,7 @@ PHP_FUNCTION(sodium_crypto_scalarmult) RETURN_THROWS(); } if (p_len != crypto_scalarmult_BYTES) { - zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SCALARMULT_SCALARBYTES bytes long"); + zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_SCALARMULT_BYTES bytes long"); RETURN_THROWS(); } q = zend_string_alloc(crypto_scalarmult_BYTES, 0); @@ -2674,7 +2674,7 @@ PHP_FUNCTION(sodium_crypto_scalarmult_ristretto255_base) zend_argument_error(sodium_exception_ce, 1, "must not be zero", 0); RETURN_THROWS(); } - ZSTR_VAL(q)[crypto_scalarmult_BYTES] = 0; + ZSTR_VAL(q)[crypto_scalarmult_ristretto255_BYTES] = 0; RETURN_NEW_STR(q); } @@ -3214,7 +3214,7 @@ PHP_FUNCTION(sodium_crypto_kdf_derive_from_key) RETURN_THROWS(); } if (key_len != crypto_kdf_KEYBYTES) { - zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_KDF_BYTES_MIN bytes long"); + zend_argument_error(sodium_exception_ce, 4, "must be SODIUM_CRYPTO_KDF_KEYBYTES bytes long"); RETURN_THROWS(); } memcpy(ctx_padded, ctx, crypto_kdf_CONTEXTBYTES); diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 867f492fab16d..5eceff88dfab6 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -75,12 +75,7 @@ struct _spl_dllist_object { spl_ptr_llist_element *traverse_pointer; int traverse_position; int flags; - zend_function *fptr_offset_get; - zend_function *fptr_offset_set; - zend_function *fptr_offset_has; - zend_function *fptr_offset_del; zend_function *fptr_count; - zend_class_entry *ce_get_iterator; zend_object std; }; @@ -322,7 +317,6 @@ static zend_object *spl_dllist_object_new_ex(zend_class_entry *class_type, zend_ if (orig) { spl_dllist_object *other = spl_dllist_from_obj(orig); - intern->ce_get_iterator = other->ce_get_iterator; if (clone_orig) { intern->llist = spl_ptr_llist_init(); @@ -360,22 +354,6 @@ static zend_object *spl_dllist_object_new_ex(zend_class_entry *class_type, zend_ ZEND_ASSERT(parent); if (inherited) { - intern->fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1); - if (intern->fptr_offset_get->common.scope == parent) { - intern->fptr_offset_get = NULL; - } - intern->fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1); - if (intern->fptr_offset_set->common.scope == parent) { - intern->fptr_offset_set = NULL; - } - intern->fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1); - if (intern->fptr_offset_has->common.scope == parent) { - intern->fptr_offset_has = NULL; - } - intern->fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1); - if (intern->fptr_offset_del->common.scope == parent) { - intern->fptr_offset_del = NULL; - } /* Find count() method */ intern->fptr_count = zend_hash_find_ptr(&class_type->function_table, ZSTR_KNOWN(ZEND_STR_COUNT)); if (intern->fptr_count->common.scope == parent) { @@ -750,11 +728,10 @@ PHP_METHOD(SplDoublyLinkedList, offsetUnset) element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); if (element != NULL) { - /* connect the neighbors */ + /* disconnect the neighbours */ if (element->prev) { element->prev->next = element->next; } - if (element->next) { element->next->prev = element->prev; } @@ -768,6 +745,10 @@ PHP_METHOD(SplDoublyLinkedList, offsetUnset) llist->tail = element->prev; } + /* Keep consistency if element is kept alive. */ + element->prev = NULL; + element->next = NULL; + /* finally, delete the element */ llist->count--; diff --git a/ext/spl/tests/gh20856.phpt b/ext/spl/tests/gh20856.phpt new file mode 100644 index 0000000000000..8bc1b3c95827c --- /dev/null +++ b/ext/spl/tests/gh20856.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-20856 (heap-use-after-free in SplDoublyLinkedList iterator when modifying during iteration) +--CREDITS-- +vi3tL0u1s +iluuu1994 +--FILE-- + +--EXPECTF-- +object(SplStack)#%d (%d) { + ["flags":"SplDoublyLinkedList":private]=> + int(6) + ["dllist":"SplDoublyLinkedList":private]=> + array(0) { + } +} diff --git a/ext/standard/array.c b/ext/standard/array.c index f1b25387db060..893e07dd8f99a 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -4156,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) @@ -4176,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; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index e0c4230dae27c..dc6146aec9d9c 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,42 +1330,36 @@ 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; -} -/* }}} */ - -/* 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); + RETURN_BOOL(_php_error_log((int) erropt, message, opt, headers) == SUCCESS); } /* }}} */ -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; + const char *hdrs = NULL; switch (opt_err) { case 1: /*send an email */ - if (!php_mail(opt, "PHP error_log message", message, headers, NULL)) { + if (!opt) { + return FAILURE; + } + + hdrs = headers ? ZSTR_VAL(headers) : NULL; + if (!php_mail(ZSTR_VAL(opt), "PHP error_log message", ZSTR_VAL(message), hdrs, NULL)) { return FAILURE; } break; @@ -1375,27 +1369,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 +2133,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 +2177,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 +2204,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 +2316,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 8c8c6ba58dfd6..e5b85fbc2d53c 100644 --- a/ext/standard/basic_functions.h +++ b/ext/standard/basic_functions.h @@ -46,9 +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 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 fdeabd1872d20..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); } /* }}} */ @@ -1555,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/html_tables/html_table_gen.php b/ext/standard/html_tables/html_table_gen.php index 02fc0c26d3d85..bc76f6f7e945f 100755 --- a/ext/standard/html_tables/html_table_gen.php +++ b/ext/standard/html_tables/html_table_gen.php @@ -180,7 +180,7 @@ enum entity_charset charset; /* process file */ $map = array(); - $lines = explode("\n", file_get_contents($e{'file'})); + $lines = explode("\n", file_get_contents($e['file'])); foreach ($lines as $l) { if (preg_match("/^0x([0-9A-Z]{2})\t0x([0-9A-Z]{2,})/i", $l, $matches)) $map[] = array($matches[1], $matches[2]); @@ -323,7 +323,7 @@ enum entity_charset charset; /* process file */ $map = array(); - $lines = explode("\n", file_get_contents($e{'file'})); + $lines = explode("\n", file_get_contents($e['file'])); foreach ($lines as $l) { if (preg_match("/^0x([0-9A-Z]{2})\t0x([0-9A-Z]{2,})\s+#\s*(.*)$/i", $l, $matches)) $map[] = array($matches[1], $matches[2], rtrim($matches[3])); 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/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/array_map_foreach_optimization_001.phpt b/ext/standard/tests/array/array_map_foreach_optimization_001.phpt new file mode 100644 index 0000000000000..49031942d20e4 --- /dev/null +++ b/ext/standard/tests/array/array_map_foreach_optimization_001.phpt @@ -0,0 +1,82 @@ +--TEST-- +array_map(): foreach optimization +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL int(1) 1 +0002 SEND_VAL int(10) 2 +0003 V2 = DO_ICALL +0004 ASSIGN CV0($array) V2 +0005 TYPE_ASSERT 131079 string("array_map") CV0($array) +0006 T2 = INIT_ARRAY 0 (packed) NEXT +0007 V3 = FE_RESET_R CV0($array) 0014 +0008 T5 = FE_FETCH_R V3 T4 0014 +0009 INIT_FCALL 1 %d string("plus1") +0010 SEND_VAL T4 1 +0011 V4 = DO_UCALL +0012 T2 = ADD_ARRAY_ELEMENT V4 T5 +0013 JMP 0008 +0014 FE_FREE V3 +0015 ASSIGN CV1($foo) T2 +0016 INIT_FCALL 1 %d string("var_dump") +0017 SEND_VAR CV1($foo) 1 +0018 DO_ICALL +0019 RETURN int(1) +LIVE RANGES: + 2: 0007 - 0015 (tmp/var) + 3: 0008 - 0014 (loop) + 4: 0009 - 0010 (tmp/var) + 5: 0009 - 0012 (tmp/var) + +plus1: + ; (lines=3, args=1, vars=1, tmps=1) + ; (after optimizer) + ; %s +0000 CV0($x) = RECV 1 +0001 T1 = ADD CV0($x) int(1) +0002 RETURN T1 +array(10) { + [0]=> + int(2) + [1]=> + int(3) + [2]=> + int(4) + [3]=> + int(5) + [4]=> + int(6) + [5]=> + int(7) + [6]=> + int(8) + [7]=> + int(9) + [8]=> + int(10) + [9]=> + int(11) +} diff --git a/ext/standard/tests/array/array_map_foreach_optimization_002.phpt b/ext/standard/tests/array/array_map_foreach_optimization_002.phpt new file mode 100644 index 0000000000000..79b7df08b6108 --- /dev/null +++ b/ext/standard/tests/array/array_map_foreach_optimization_002.phpt @@ -0,0 +1,73 @@ +--TEST-- +array_map(): foreach optimization - Error +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL int(1) 1 +0002 SEND_VAL int(10) 2 +0003 V2 = DO_ICALL +0004 ASSIGN CV0($array) V2 +0005 V5 = NEW 1 string("ArrayIterator") +0006 SEND_VAR%S CV0($array) 1 +0007 DO_FCALL +0008 TYPE_ASSERT 131079 string("array_map") V5 +0009 T2 = INIT_ARRAY 0 (packed) NEXT +0010 V3 = FE_RESET_R V5 0017 +0011 T5 = FE_FETCH_R V3 T4 0017 +0012 INIT_FCALL 1 %d string("plus1") +0013 SEND_VAL T4 1 +0014 V4 = DO_UCALL +0015 T2 = ADD_ARRAY_ELEMENT V4 T5 +0016 JMP 0011 +0017 FE_FREE V3 +0018 ASSIGN CV1($foo) T2 +0019 INIT_FCALL 1 %d string("var_dump") +0020 SEND_VAR CV1($foo) 1 +0021 DO_ICALL +0022 RETURN int(1) +LIVE RANGES: + 5: 0006 - 0008 (new) + 5: 0008 - 0010 (tmp/var) + 2: 0010 - 0018 (tmp/var) + 3: 0011 - 0017 (loop) + 4: 0012 - 0013 (tmp/var) + 5: 0012 - 0015 (tmp/var) + +plus1: + ; (lines=3, args=1, vars=1, tmps=1) + ; (after optimizer) + ; %s +0000 CV0($x) = RECV 1 +0001 T1 = ADD CV0($x) int(1) +0002 RETURN T1 + +Fatal error: Uncaught TypeError: array_map(): Argument #2 ($array) must be of type array, ArrayIterator given in %s:9 +Stack trace: +#0 {main} + thrown in %s on line 9 diff --git a/ext/standard/tests/array/array_map_foreach_optimization_003.phpt b/ext/standard/tests/array/array_map_foreach_optimization_003.phpt new file mode 100644 index 0000000000000..7a287f54f783e --- /dev/null +++ b/ext/standard/tests/array/array_map_foreach_optimization_003.phpt @@ -0,0 +1,73 @@ +--TEST-- +array_map(): foreach optimization - const array +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 TYPE_ASSERT 131079 string("array_map") array(...) +0001 T1 = INIT_ARRAY 0 (packed) NEXT +0002 V2 = FE_RESET_R array(...) 0009 +0003 T4 = FE_FETCH_R V2 T3 0009 +0004 INIT_FCALL 1 %d string("plus1") +0005 SEND_VAL T3 1 +0006 V3 = DO_UCALL +0007 T1 = ADD_ARRAY_ELEMENT V3 T4 +0008 JMP 0003 +0009 FE_FREE V2 +0010 ASSIGN CV0($foo) T1 +0011 INIT_FCALL 1 %d string("var_dump") +0012 SEND_VAR CV0($foo) 1 +0013 DO_ICALL +0014 RETURN int(1) +LIVE RANGES: + 1: 0002 - 0010 (tmp/var) + 2: 0003 - 0009 (loop) + +plus1: + ; (lines=3, args=1, vars=1, tmps=1) + ; (after optimizer) + ; %s +0000 CV0($x) = RECV 1 +0001 T1 = ADD CV0($x) int(1) +0002 RETURN T1 +array(10) { + [0]=> + int(2) + [1]=> + int(3) + [2]=> + int(4) + [3]=> + int(5) + [4]=> + int(6) + [5]=> + int(7) + [6]=> + int(8) + [7]=> + int(9) + [8]=> + int(10) + [9]=> + int(11) +} diff --git a/ext/standard/tests/array/array_map_foreach_optimization_004.phpt b/ext/standard/tests/array/array_map_foreach_optimization_004.phpt new file mode 100644 index 0000000000000..b97ed1e31d3df --- /dev/null +++ b/ext/standard/tests/array/array_map_foreach_optimization_004.phpt @@ -0,0 +1,57 @@ +--TEST-- +array_map(): foreach optimization - unused refcounted result +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL int(1) 1 +0002 SEND_VAL int(10) 2 +0003 V1 = DO_ICALL +0004 ASSIGN CV0($array) V1 +0005 TYPE_ASSERT 131079 string("array_map") CV0($array) +0006 T1 = INIT_ARRAY 0 (packed) NEXT +0007 V2 = FE_RESET_R CV0($array) 0014 +0008 T4 = FE_FETCH_R V2 T3 0014 +0009 INIT_FCALL 1 %d string("stdclass") +0010 SEND_VAL T3 1 +0011 V3 = DO_UCALL +0012 T1 = ADD_ARRAY_ELEMENT V3 T4 +0013 JMP 0008 +0014 FE_FREE V2 +0015 FREE T1 +0016 RETURN int(1) +LIVE RANGES: + 1: 0007 - 0015 (tmp/var) + 2: 0008 - 0014 (loop) + 3: 0009 - 0010 (tmp/var) + 4: 0009 - 0012 (tmp/var) + +stdClass: + ; (lines=3, args=0, vars=0, tmps=1) + ; (after optimizer) + ; %s +0000 V0 = NEW 0 string("stdClass") +0001 DO_FCALL +0002 RETURN V0 +LIVE RANGES: + 0: 0001 - 0002 (new) diff --git a/ext/standard/tests/array/array_map_foreach_optimization_005.phpt b/ext/standard/tests/array/array_map_foreach_optimization_005.phpt new file mode 100644 index 0000000000000..6f7cf45021371 --- /dev/null +++ b/ext/standard/tests/array/array_map_foreach_optimization_005.phpt @@ -0,0 +1,84 @@ +--TEST-- +array_map(): foreach optimization - static call +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL int(1) 1 +0002 SEND_VAL int(10) 2 +0003 V2 = DO_ICALL +0004 ASSIGN CV0($array) V2 +0005 TYPE_ASSERT 131079 string("array_map") CV0($array) +0006 T2 = INIT_ARRAY 0 (packed) NEXT +0007 V3 = FE_RESET_R CV0($array) 0014 +0008 T5 = FE_FETCH_R V3 T4 0014 +0009 INIT_STATIC_METHOD_CALL 1 string("Adder") string("plus1") +0010 SEND_VAL T4 1 +0011 V4 = DO_UCALL +0012 T2 = ADD_ARRAY_ELEMENT V4 T5 +0013 JMP 0008 +0014 FE_FREE V3 +0015 ASSIGN CV1($foo) T2 +0016 INIT_FCALL 1 %d string("var_dump") +0017 SEND_VAR CV1($foo) 1 +0018 DO_ICALL +0019 RETURN int(1) +LIVE RANGES: + 2: 0007 - 0015 (tmp/var) + 3: 0008 - 0014 (loop) + 4: 0009 - 0010 (tmp/var) + 5: 0009 - 0012 (tmp/var) + +Adder::plus1: + ; (lines=3, args=1, vars=1, tmps=1) + ; (after optimizer) + ; %s +0000 CV0($x) = RECV 1 +0001 T1 = ADD CV0($x) int(1) +0002 RETURN T1 +array(10) { + [0]=> + int(2) + [1]=> + int(3) + [2]=> + int(4) + [3]=> + int(5) + [4]=> + int(6) + [5]=> + int(7) + [6]=> + int(8) + [7]=> + int(9) + [8]=> + int(10) + [9]=> + int(11) +} diff --git a/ext/standard/tests/array/array_map_foreach_optimization_006.phpt b/ext/standard/tests/array/array_map_foreach_optimization_006.phpt new file mode 100644 index 0000000000000..d354f1d5ec70c --- /dev/null +++ b/ext/standard/tests/array/array_map_foreach_optimization_006.phpt @@ -0,0 +1,84 @@ +--TEST-- +array_map(): foreach optimization - PFA +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL int(1) 1 +0002 SEND_VAL int(10) 2 +0003 V2 = DO_ICALL +0004 ASSIGN CV0($array) V2 +0005 TYPE_ASSERT 131079 string("array_map") CV0($array) +0006 T2 = INIT_ARRAY 0 (packed) NEXT +0007 V3 = FE_RESET_R CV0($array) 0015 +0008 T5 = FE_FETCH_R V3 T4 0015 +0009 INIT_FCALL 2 %d string("plusn") +0010 SEND_VAL T4 1 +0011 SEND_VAL int(2) 2 +0012 V4 = DO_UCALL +0013 T2 = ADD_ARRAY_ELEMENT V4 T5 +0014 JMP 0008 +0015 FE_FREE V3 +0016 ASSIGN CV1($foo) T2 +0017 INIT_FCALL 1 %d string("var_dump") +0018 SEND_VAR CV1($foo) 1 +0019 DO_ICALL +0020 RETURN int(1) +LIVE RANGES: + 2: 0007 - 0016 (tmp/var) + 3: 0008 - 0015 (loop) + 4: 0009 - 0010 (tmp/var) + 5: 0009 - 0013 (tmp/var) + +plusn: + ; (lines=4, args=2, vars=2, tmps=1) + ; (after optimizer) + ; %s +0000 CV0($x) = RECV 1 +0001 CV1($n) = RECV 2 +0002 T2 = ADD CV0($x) CV1($n) +0003 RETURN T2 +array(10) { + [0]=> + int(3) + [1]=> + int(4) + [2]=> + int(5) + [3]=> + int(6) + [4]=> + int(7) + [5]=> + int(8) + [6]=> + int(9) + [7]=> + int(10) + [8]=> + int(11) + [9]=> + int(12) +} diff --git a/ext/standard/tests/array/array_map_foreach_optimization_007.phpt b/ext/standard/tests/array/array_map_foreach_optimization_007.phpt new file mode 100644 index 0000000000000..d2dbf7f722529 --- /dev/null +++ b/ext/standard/tests/array/array_map_foreach_optimization_007.phpt @@ -0,0 +1,109 @@ +--TEST-- +array_map(): foreach optimization - unoptimizable PFA +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--FILE-- + +--EXPECTF-- +$_main: + ; (lines=%d, args=0, vars=%d, tmps=%d) + ; (after optimizer) + ; %s +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL int(1) 1 +0002 SEND_VAL int(10) 2 +0003 V2 = DO_ICALL +0004 ASSIGN CV0($array) V2 +0005 INIT_FCALL 2 %d string("array_map") +0006 INIT_FCALL 0 %d string("plusn") +0007 SEND_VAL int(2) string("n") +0008 T2 = CALLABLE_CONVERT_PARTIAL 2 +0009 SEND_VAL T2 1 +0010 SEND_VAR CV0($array) 2 +0011 V2 = DO_ICALL +0012 ASSIGN CV1($foo) V2 +0013 INIT_FCALL 1 %d string("var_dump") +0014 SEND_VAR CV1($foo) 1 +0015 DO_ICALL +0016 RETURN int(1) + +plusn: + ; (lines=4, args=2, vars=2, tmps=1) + ; (after optimizer) + ; %s +0000 CV0($x) = RECV 1 +0001 CV1($n) = RECV 2 +0002 T2 = ADD CV0($x) CV1($n) +0003 RETURN T2 + +$_main: + ; (lines=4, args=0, vars=1, tmps=1) + ; (after optimizer) + ; %s:1-9 +0000 T1 = DECLARE_LAMBDA_FUNCTION 0 +0001 BIND_LEXICAL T1 CV0($n) +0002 FREE T1 +0003 RETURN int(1) +LIVE RANGES: + 1: 0001 - 0002 (tmp/var) + +{closure:pfa:%s:9}: + ; (lines=18, args=1, vars=2, tmps=2) + ; (after optimizer) + ; %s:9-9 +0000 CV0($x) = RECV 1 +0001 BIND_STATIC CV1($n) +0002 T3 = FUNC_NUM_ARGS +0003 T2 = IS_SMALLER_OR_EQUAL T3 int(1) +0004 JMPZ T2 0010 +0005 INIT_FCALL 2 %d string("plusn") +0006 SEND_VAR CV0($x) 1 +0007 SEND_VAR CV1($n) 2 +0008 V2 = DO_UCALL +0009 RETURN V2 +0010 INIT_FCALL 2 %d string("plusn") +0011 SEND_VAR CV0($x) 1 +0012 SEND_VAR CV1($n) 2 +0013 T2 = FUNC_GET_ARGS int(1) +0014 SEND_UNPACK T2 +0015 CHECK_UNDEF_ARGS +0016 V2 = DO_UCALL +0017 RETURN V2 +array(10) { + [0]=> + int(3) + [1]=> + int(4) + [2]=> + int(5) + [3]=> + int(6) + [4]=> + int(7) + [5]=> + int(8) + [6]=> + int(9) + [7]=> + int(10) + [8]=> + int(11) + [9]=> + int(12) +} diff --git a/ext/standard/tests/file/bug52820.phpt b/ext/standard/tests/file/bug52820.phpt index 2d3cedad87944..06aa3463c4ed0 100644 --- a/ext/standard/tests/file/bug52820.phpt +++ b/ext/standard/tests/file/bug52820.phpt @@ -45,22 +45,22 @@ echo "\nDone.\n"; --EXPECTREGEX-- temp stream \(close after\): About to rewind! -(\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ +(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/ \* [Cc]losing connection( #?-?\d+)? memory stream \(close after\): About to rewind! -(\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ +(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/ \* [Cc]losing connection( #?-?\d+)? temp stream \(leak\): About to rewind! -(\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ +(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/ \* [Cc]losing connection( #?-?\d+)? memory stream \(leak\): About to rewind! -(\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ +(\* processing: file:\/\/\/i_dont_exist\/\n)?\* (Couldn't|Could not) open file \/i_dont_exist\/ \* [Cc]losing connection( #?-?\d+)? Done\. diff --git a/ext/standard/tests/file/bug69442.phpt b/ext/standard/tests/file/bug69442.phpt index 82e186eec9ef9..d1b1affe646e8 100644 --- a/ext/standard/tests/file/bug69442.phpt +++ b/ext/standard/tests/file/bug69442.phpt @@ -1,5 +1,6 @@ --TEST-- proc_open with PTY closes incorrect file descriptor +--FLAKY-- --SKIPIF-- +--FILE-- + +--CLEAN-- + +--EXPECT-- +int(1000) 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 @@ +--INI-- +zend.max_allowed_stack_size=512K +--FILE-- +next = $newNode; + $node = $newNode; +} + +$buffer = ''; +ob_start(function ($chunk) use (&$buffer) { + $buffer .= $chunk; + $buffer = preg_replace('(\s*object\(Node\)#\d+ \(\d+\) \{\s*)', '', $buffer); + $buffer = preg_replace('(\s*\["next"\]=>\s*)', '', $buffer); + $buffer = preg_replace('(\s*\}\s*)', '', $buffer); +}); +var_dump($firstNode); +ob_end_flush(); +echo $buffer; + +while ($next = $firstNode->next) { + $firstNode->next = $next->next; +} +?> +--EXPECT-- +nesting level too deep diff --git a/ext/standard/tests/general_functions/intval.phpt b/ext/standard/tests/general_functions/intval.phpt index 83377d85a099a..c570d8f36ae5e 100644 --- a/ext/standard/tests/general_functions/intval.phpt +++ b/ext/standard/tests/general_functions/intval.phpt @@ -221,19 +221,11 @@ int(-2147483648) int(2147483647) *** Testing intval() on non integer types *** - -Warning: The float-string "-2147483649" is not representable as an int, cast occurred in %s on line %d int(-2147483648) - -Warning: The float-string "2147483648" is not representable as an int, cast occurred in %s on line %d int(2147483647) int(0) int(0) - -Warning: The float-string "020000000001" is not representable as an int, cast occurred in %s on line %d int(2147483647) - -Warning: The float-string "-020000000001" is not representable as an int, cast occurred in %s on line %d int(-2147483648) int(0) int(0) diff --git a/ext/standard/tests/image/gh20582.phpt b/ext/standard/tests/image/gh20582.phpt new file mode 100644 index 0000000000000..499f70e372603 --- /dev/null +++ b/ext/standard/tests/image/gh20582.phpt @@ -0,0 +1,54 @@ +--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/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/network/so_keepalive.phpt b/ext/standard/tests/network/so_keepalive.phpt new file mode 100644 index 0000000000000..a437d16694b3b --- /dev/null +++ b/ext/standard/tests/network/so_keepalive.phpt @@ -0,0 +1,151 @@ +--TEST-- +stream_socket_server() and stream_socket_client() SO_KEEPALIVE context option test +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- + [ + 'so_keepalive' => true, + 'tcp_keepidle' => 60, + 'tcp_keepintvl' => 10, + 'tcp_keepcnt' => 5, + ] +]); + +$server = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, + STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $server_context); + +if (!$server) { + die('Unable to create server'); +} + +$addr = stream_socket_get_name($server, false); +$port = (int)substr(strrchr($addr, ':'), 1); + +// Test client with SO_KEEPALIVE enabled +$client_context = stream_context_create([ + 'socket' => [ + 'so_keepalive' => true, + 'tcp_keepidle' => 30, + 'tcp_keepintvl' => 5, + 'tcp_keepcnt' => 3, + ] +]); + +$client = stream_socket_client("tcp://127.0.0.1:$port", $errno, $errstr, 30, + STREAM_CLIENT_CONNECT, $client_context); + +if (!$client) { + die('Unable to create client'); +} + +$accepted = stream_socket_accept($server, 1); + +if (!$accepted) { + die('Unable to accept connection'); +} + +// Verify server side (accepted connection) +$server_sock = socket_import_stream($accepted); +$server_keepalive = socket_get_option($server_sock, SOL_SOCKET, SO_KEEPALIVE); +echo "Server SO_KEEPALIVE: " . ($server_keepalive ? "enabled" : "disabled") . "\n"; + +if (defined('TCP_KEEPIDLE')) { + $server_idle = socket_get_option($server_sock, SOL_TCP, TCP_KEEPIDLE); + echo "Server TCP_KEEPIDLE: $server_idle\n"; +} else { + $server_idle = socket_get_option($server_sock, SOL_TCP, TCP_KEEPALIVE); + echo "Server TCP_KEEPIDLE: $server_idle\n"; +} + +$server_intvl = socket_get_option($server_sock, SOL_TCP, TCP_KEEPINTVL); +echo "Server TCP_KEEPINTVL: $server_intvl\n"; + +$server_cnt = socket_get_option($server_sock, SOL_TCP, TCP_KEEPCNT); +echo "Server TCP_KEEPCNT: $server_cnt\n"; + +// Verify client side +$client_sock = socket_import_stream($client); +$client_keepalive = socket_get_option($client_sock, SOL_SOCKET, SO_KEEPALIVE); +echo "Client SO_KEEPALIVE: " . ($client_keepalive ? "enabled" : "disabled") . "\n"; + +if (defined('TCP_KEEPIDLE')) { + $client_idle = socket_get_option($client_sock, SOL_TCP, TCP_KEEPIDLE); + echo "Client TCP_KEEPIDLE: $client_idle\n"; +} else { + $client_idle = socket_get_option($client_sock, SOL_TCP, TCP_KEEPALIVE); + echo "Client TCP_KEEPIDLE: $client_idle\n"; +} + +$client_intvl = socket_get_option($client_sock, SOL_TCP, TCP_KEEPINTVL); +echo "Client TCP_KEEPINTVL: $client_intvl\n"; + +$client_cnt = socket_get_option($client_sock, SOL_TCP, TCP_KEEPCNT); +echo "Client TCP_KEEPCNT: $client_cnt\n"; + +fclose($accepted); +fclose($client); +fclose($server); + +// Test server with SO_KEEPALIVE disabled +$server2_context = stream_context_create(['socket' => ['so_keepalive' => false]]); +$server2 = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, + STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $server2_context); + +$addr2 = stream_socket_get_name($server2, false); +$port2 = (int)substr(strrchr($addr2, ':'), 1); + +$client2 = stream_socket_client("tcp://127.0.0.1:$port2"); +$accepted2 = stream_socket_accept($server2, 1); + +$server2_sock = socket_import_stream($accepted2); +$server2_keepalive = socket_get_option($server2_sock, SOL_SOCKET, SO_KEEPALIVE); +echo "Server disabled SO_KEEPALIVE: " . ($server2_keepalive ? "enabled" : "disabled") . "\n"; + +fclose($accepted2); +fclose($client2); +fclose($server2); + +// Test client with SO_KEEPALIVE disabled +$server3 = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, + STREAM_SERVER_BIND | STREAM_SERVER_LISTEN); + +$addr3 = stream_socket_get_name($server3, false); +$port3 = (int)substr(strrchr($addr3, ':'), 1); + +$client3_context = stream_context_create(['socket' => ['so_keepalive' => false]]); +$client3 = stream_socket_client("tcp://127.0.0.1:$port3", $errno, $errstr, 30, + STREAM_CLIENT_CONNECT, $client3_context); + +$client3_sock = socket_import_stream($client3); +$client3_keepalive = socket_get_option($client3_sock, SOL_SOCKET, SO_KEEPALIVE); +echo "Client disabled SO_KEEPALIVE: " . ($client3_keepalive ? "enabled" : "disabled") . "\n"; + +fclose($client3); +fclose($server3); +?> +--EXPECT-- +Server SO_KEEPALIVE: enabled +Server TCP_KEEPIDLE: 60 +Server TCP_KEEPINTVL: 10 +Server TCP_KEEPCNT: 5 +Client SO_KEEPALIVE: enabled +Client TCP_KEEPIDLE: 30 +Client TCP_KEEPINTVL: 5 +Client TCP_KEEPCNT: 3 +Server disabled SO_KEEPALIVE: disabled +Client disabled SO_KEEPALIVE: disabled diff --git a/ext/standard/tests/network/so_keepalive_string.phpt b/ext/standard/tests/network/so_keepalive_string.phpt new file mode 100644 index 0000000000000..19cb2f9c6dec9 --- /dev/null +++ b/ext/standard/tests/network/so_keepalive_string.phpt @@ -0,0 +1,151 @@ +--TEST-- +stream_socket_server() and stream_socket_client() keepalive option test with string values +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- + [ + 'so_keepalive' => true, + 'tcp_keepidle' => '80', + 'tcp_keepintvl' => '12', + 'tcp_keepcnt' => '6', + ] +]); + +$server = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, + STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $server_context); + +if (!$server) { + die('Unable to create server'); +} + +$addr = stream_socket_get_name($server, false); +$port = (int)substr(strrchr($addr, ':'), 1); + +// Test client with SO_KEEPALIVE enabled +$client_context = stream_context_create([ + 'socket' => [ + 'so_keepalive' => true, + 'tcp_keepidle' => '31', + 'tcp_keepintvl' => '6', + 'tcp_keepcnt' => '4', + ] +]); + +$client = stream_socket_client("tcp://127.0.0.1:$port", $errno, $errstr, 30, + STREAM_CLIENT_CONNECT, $client_context); + +if (!$client) { + die('Unable to create client'); +} + +$accepted = stream_socket_accept($server, 1); + +if (!$accepted) { + die('Unable to accept connection'); +} + +// Verify server side (accepted connection) +$server_sock = socket_import_stream($accepted); +$server_keepalive = socket_get_option($server_sock, SOL_SOCKET, SO_KEEPALIVE); +echo "Server SO_KEEPALIVE: " . ($server_keepalive ? "enabled" : "disabled") . "\n"; + +if (defined('TCP_KEEPIDLE')) { + $server_idle = socket_get_option($server_sock, SOL_TCP, TCP_KEEPIDLE); + echo "Server TCP_KEEPIDLE: $server_idle\n"; +} else { + $server_idle = socket_get_option($server_sock, SOL_TCP, TCP_KEEPALIVE); + echo "Server TCP_KEEPIDLE: $server_idle\n"; +} + +$server_intvl = socket_get_option($server_sock, SOL_TCP, TCP_KEEPINTVL); +echo "Server TCP_KEEPINTVL: $server_intvl\n"; + +$server_cnt = socket_get_option($server_sock, SOL_TCP, TCP_KEEPCNT); +echo "Server TCP_KEEPCNT: $server_cnt\n"; + +// Verify client side +$client_sock = socket_import_stream($client); +$client_keepalive = socket_get_option($client_sock, SOL_SOCKET, SO_KEEPALIVE); +echo "Client SO_KEEPALIVE: " . ($client_keepalive ? "enabled" : "disabled") . "\n"; + +if (defined('TCP_KEEPIDLE')) { + $client_idle = socket_get_option($client_sock, SOL_TCP, TCP_KEEPIDLE); + echo "Client TCP_KEEPIDLE: $client_idle\n"; +} else { + $client_idle = socket_get_option($client_sock, SOL_TCP, TCP_KEEPALIVE); + echo "Client TCP_KEEPIDLE: $client_idle\n"; +} + +$client_intvl = socket_get_option($client_sock, SOL_TCP, TCP_KEEPINTVL); +echo "Client TCP_KEEPINTVL: $client_intvl\n"; + +$client_cnt = socket_get_option($client_sock, SOL_TCP, TCP_KEEPCNT); +echo "Client TCP_KEEPCNT: $client_cnt\n"; + +fclose($accepted); +fclose($client); +fclose($server); + +// Test server with SO_KEEPALIVE disabled +$server2_context = stream_context_create(['socket' => ['so_keepalive' => false]]); +$server2 = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, + STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $server2_context); + +$addr2 = stream_socket_get_name($server2, false); +$port2 = (int)substr(strrchr($addr2, ':'), 1); + +$client2 = stream_socket_client("tcp://127.0.0.1:$port2"); +$accepted2 = stream_socket_accept($server2, 1); + +$server2_sock = socket_import_stream($accepted2); +$server2_keepalive = socket_get_option($server2_sock, SOL_SOCKET, SO_KEEPALIVE); +echo "Server disabled SO_KEEPALIVE: " . ($server2_keepalive ? "enabled" : "disabled") . "\n"; + +fclose($accepted2); +fclose($client2); +fclose($server2); + +// Test client with SO_KEEPALIVE disabled +$server3 = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, + STREAM_SERVER_BIND | STREAM_SERVER_LISTEN); + +$addr3 = stream_socket_get_name($server3, false); +$port3 = (int)substr(strrchr($addr3, ':'), 1); + +$client3_context = stream_context_create(['socket' => ['so_keepalive' => false]]); +$client3 = stream_socket_client("tcp://127.0.0.1:$port3", $errno, $errstr, 30, + STREAM_CLIENT_CONNECT, $client3_context); + +$client3_sock = socket_import_stream($client3); +$client3_keepalive = socket_get_option($client3_sock, SOL_SOCKET, SO_KEEPALIVE); +echo "Client disabled SO_KEEPALIVE: " . ($client3_keepalive ? "enabled" : "disabled") . "\n"; + +fclose($client3); +fclose($server3); +?> +--EXPECT-- +Server SO_KEEPALIVE: enabled +Server TCP_KEEPIDLE: 80 +Server TCP_KEEPINTVL: 12 +Server TCP_KEEPCNT: 6 +Client SO_KEEPALIVE: enabled +Client TCP_KEEPIDLE: 31 +Client TCP_KEEPINTVL: 6 +Client TCP_KEEPCNT: 4 +Server disabled SO_KEEPALIVE: disabled +Client disabled SO_KEEPALIVE: disabled diff --git a/ext/standard/tests/skipif_no_root.inc b/ext/standard/tests/skipif_no_root.inc new file mode 100644 index 0000000000000..ef60c14745ba6 --- /dev/null +++ b/ext/standard/tests/skipif_no_root.inc @@ -0,0 +1,16 @@ + 0) { + echo fread($file, 1024) . "\n"; + } +} else { + echo "stream_select failed\n"; +} + +fclose($file); +?> +--EXPECT-- +stream_select succeeded +Hello World diff --git a/ext/standard/tests/streams/stream_select_filtered_base64_buffered.phpt b/ext/standard/tests/streams/stream_select_filtered_base64_buffered.phpt new file mode 100644 index 0000000000000..4d11bf718a1bd --- /dev/null +++ b/ext/standard/tests/streams/stream_select_filtered_base64_buffered.phpt @@ -0,0 +1,59 @@ +--TEST-- +stream_select() base64-decode filter buffered data usage +--FILE-- + 0) { + $content = fread($read_pipe, 1024); + echo "Decoded content: " . $content . "\n"; +} + +fclose($read_pipe); +fclose($write_pipe); +?> +--EXPECT-- +Decoded content (before select): Hel +After incomplete data - select result: 0 +After incomplete data - readable streams: 0 +After complete data - select result: 1 +After complete data - readable streams: 1 +Decoded content: lo diff --git a/ext/standard/var.c b/ext/standard/var.c index a1ef60410a338..c415efd2afc61 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -56,6 +56,12 @@ static void php_object_property_dump(zend_property_info *prop_info, zval *zv, ze { const char *prop_name, *class_name; +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + php_printf("%*cnesting level too deep", level + 1, ' '); + return; + } +#endif if (key == NULL) { /* numeric key */ php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index); } else { /* string key */ diff --git a/ext/tidy/tests/gh20374.phpt b/ext/tidy/tests/gh20374.phpt index 39c3ba06d315e..73299856b081a 100644 --- a/ext/tidy/tests/gh20374.phpt +++ b/ext/tidy/tests/gh20374.phpt @@ -75,8 +75,6 @@ foreach ($values as $key => $value) { --- double overflow --- - -Warning: The float-string "1.2089258196146E+24" is not representable as an int, cast occurred in %s on line %d diff --git a/ext/uri/config.m4 b/ext/uri/config.m4 index 390d8eb223cb9..dda586b752aa1 100644 --- a/ext/uri/config.m4 +++ b/ext/uri/config.m4 @@ -34,7 +34,7 @@ if test "$PHP_EXTERNAL_URIPARSER" = "no"; then URI_CFLAGS="-DURI_STATIC_BUILD" else PKG_CHECK_MODULES([LIBURIPARSER], [liburiparser >= 1.0.0]) - PHP_EVAL_LIBLINE([$LIBURIPARSER_LIBS], [URI_SHARED_LIBADD]) + PHP_EVAL_LIBLINE([$LIBURIPARSER_LIBS]) PHP_EVAL_INCLINE([$LIBURIPARSER_CFLAGS]) fi diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index 29b26f7b8ce27..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; diff --git a/ext/uri/tests/036.phpt b/ext/uri/tests/036.phpt deleted file mode 100644 index 2942730739d0c..0000000000000 --- a/ext/uri/tests/036.phpt +++ /dev/null @@ -1,39 +0,0 @@ ---TEST-- -Test URI equality checks ---EXTENSIONS-- -uri ---FILE-- -equals(new Uri\Rfc3986\Uri("https://example.com"))); // true: identical URIs -var_dump(new Uri\Rfc3986\Uri("https://example.com#foo")->equals(new Uri\Rfc3986\Uri("https://example.com#bar"), Uri\UriComparisonMode::ExcludeFragment)); // true: fragment differs, but fragment is excluded -var_dump(new Uri\Rfc3986\Uri("https://example.com#foo")->equals(new Uri\Rfc3986\Uri("https://example.com#bar"), Uri\UriComparisonMode::IncludeFragment)); // false: fragment differs and fragment is included -var_dump(new Uri\Rfc3986\Uri("https://example.com/foo/..")->equals(new Uri\Rfc3986\Uri("https://example.com"))); // false: first URI becomes https://example.com/ after normalization -var_dump(new Uri\Rfc3986\Uri("https://example.com/foo/..")->equals(new Uri\Rfc3986\Uri("https://example.com/"))); // true: both URIs are https://example.com/ after normalization -var_dump(new Uri\Rfc3986\Uri("http://example%2ecom/foo%2fb%61r")->equals(new Uri\Rfc3986\Uri("http://example%2ecom/foo/bar"))); // false: "/" in the path should not be decoded -var_dump(new Uri\Rfc3986\Uri("http://example%2ecom/foo/b%61r")->equals(new Uri\Rfc3986\Uri("http://example%2ecom/foo/bar"))); // true: percent-decoding during normalization gives same URIs - -var_dump(new Uri\WhatWg\Url("https://example.com")->equals(new Uri\WhatWg\Url("https://example.com"))); // true: identical URIs -var_dump(new Uri\WhatWg\Url("https://example.com#foo")->equals(new Uri\WhatWg\Url("https://example.com#bar"), Uri\UriComparisonMode::ExcludeFragment)); // true: fragment differs, but fragment is excluded -var_dump(new Uri\WhatWg\Url("https://example.com#foo")->equals(new Uri\WhatWg\Url("https://example.com#bar"), Uri\UriComparisonMode::IncludeFragment)); // false: fragment differs and fragment is included -var_dump(new Uri\WhatWg\Url("https://example.com/foo/..")->equals(new Uri\WhatWg\Url("https://example.com"))); // true: both URIs are https://example.com/ after normalization -var_dump(new Uri\WhatWg\Url("https://example.com/foo/..")->equals(new Uri\WhatWg\Url("https://example.com/"))); // true: both URIs are https://example.com/ after normalization -var_dump(new Uri\WhatWg\Url("http://example%2ecom/foo%2fb%61r")->equals(new Uri\WhatWg\Url("http://example%2ecom/foo/bar"))); // false: WHATWG doesn't percent-decode the path during normalization -var_dump(new Uri\WhatWg\Url("http://example%2ecom/foo/b%61r")->equals(new Uri\WhatWg\Url("http://example.com/foo/b%61r"))); // true: WHATWG percent-decodes the host during normalization - -?> ---EXPECT-- -bool(true) -bool(true) -bool(false) -bool(false) -bool(true) -bool(false) -bool(true) -bool(true) -bool(true) -bool(false) -bool(true) -bool(true) -bool(false) -bool(true) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_host.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_host.phpt new file mode 100644 index 0000000000000..b4e6cffcaf1f3 --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_false_host.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns false - host is different +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_path.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_path.phpt new file mode 100644 index 0000000000000..562719537f73a --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_false_path.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns false - path is different +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_port.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_port.phpt new file mode 100644 index 0000000000000..3743dd686a248 --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_false_port.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns false - port is different +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_query.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_query.phpt new file mode 100644 index 0000000000000..cb4fbcd9d6d12 --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_false_query.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns false - query is different +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_query2.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_query2.phpt new file mode 100644 index 0000000000000..b97988d9ce3c9 --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_false_query2.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns false - query differs in casing +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_scheme.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_scheme.phpt new file mode 100644 index 0000000000000..143fbff97ee29 --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_false_scheme.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns false - scheme is different +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_userinfo.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_userinfo.phpt new file mode 100644 index 0000000000000..1d965c01eee12 --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_false_userinfo.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns false - userinfo is different +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_fragment_different.phpt b/ext/uri/tests/rfc3986/equivalence/equals_fragment_different.phpt new file mode 100644 index 0000000000000..0219002fcb61d --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_fragment_different.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - different fragment - include fragment variation +--FILE-- +equals($uri2, Uri\UriComparisonMode::IncludeFragment)); +var_dump($uri2->equals($uri1, Uri\UriComparisonMode::IncludeFragment)); + +var_dump($uri1->equals($uri2, Uri\UriComparisonMode::ExcludeFragment)); +var_dump($uri2->equals($uri1, Uri\UriComparisonMode::ExcludeFragment)); + +?> +--EXPECT-- +bool(false) +bool(false) +bool(true) +bool(true) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_true_identical.phpt b/ext/uri/tests/rfc3986/equivalence/equals_true_identical.phpt new file mode 100644 index 0000000000000..dc2839e3b8214 --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_true_identical.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns true - identical URIs +--FILE-- +equals($uri2, Uri\UriComparisonMode::IncludeFragment)); +var_dump($uri2->equals($uri1, Uri\UriComparisonMode::IncludeFragment)); + +var_dump($uri1->equals($uri2, Uri\UriComparisonMode::ExcludeFragment)); +var_dump($uri2->equals($uri1, Uri\UriComparisonMode::ExcludeFragment)); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_true_normalization1.phpt b/ext/uri/tests/rfc3986/equivalence/equals_true_normalization1.phpt new file mode 100644 index 0000000000000..063ee977c5d28 --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_true_normalization1.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns true - after multiple normalization steps +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/uri/tests/rfc3986/equivalence/equals_true_normalization2.phpt b/ext/uri/tests/rfc3986/equivalence/equals_true_normalization2.phpt new file mode 100644 index 0000000000000..e9b4d647f4a2f --- /dev/null +++ b/ext/uri/tests/rfc3986/equivalence/equals_true_normalization2.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\Rfc3986\Uri equivalence - returns true - after IPv6 normalization +--FILE-- +equals($uri2)); +var_dump($uri2->equals($uri1)); + +?> +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_host.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_host.phpt new file mode 100644 index 0000000000000..9bea45ce2b841 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_false_host.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns false - host is different +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_password.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_password.phpt new file mode 100644 index 0000000000000..3ef38d9b2d870 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_false_password.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns false - password is different +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_path.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_path.phpt new file mode 100644 index 0000000000000..aed0639a3c31b --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_false_path.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns false - path is different +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_path_percent_encoded.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_path_percent_encoded.phpt new file mode 100644 index 0000000000000..03dfc43e02e95 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_false_path_percent_encoded.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns false - path is not percent-decoded during normalization +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_port.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_port.phpt new file mode 100644 index 0000000000000..f632cb403f6ed --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_false_port.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns false - port is different +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_query.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_query.phpt new file mode 100644 index 0000000000000..befed30ae2bfa --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_false_query.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns false - query is different +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_query2.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_query2.phpt new file mode 100644 index 0000000000000..b155a1214dfc1 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_false_query2.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns false - query differs in casing +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_user.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_user.phpt new file mode 100644 index 0000000000000..c0f815fa93687 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_false_user.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns false - user is different +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(false) +bool(false) diff --git a/ext/uri/tests/whatwg/equivalence/equals_fragment_different.phpt b/ext/uri/tests/whatwg/equivalence/equals_fragment_different.phpt new file mode 100644 index 0000000000000..daa6a7e8ea611 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_fragment_different.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - different fragment - include fragment variation +--FILE-- +equals($url2, Uri\UriComparisonMode::IncludeFragment)); +var_dump($url2->equals($url1, Uri\UriComparisonMode::IncludeFragment)); + +var_dump($url1->equals($url2, Uri\UriComparisonMode::ExcludeFragment)); +var_dump($url2->equals($url1, Uri\UriComparisonMode::ExcludeFragment)); + +?> +--EXPECT-- +bool(false) +bool(false) +bool(true) +bool(true) diff --git a/ext/uri/tests/whatwg/equivalence/equals_true_identical.phpt b/ext/uri/tests/whatwg/equivalence/equals_true_identical.phpt new file mode 100644 index 0000000000000..4dffda8138cba --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_true_identical.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns true - identical URIs +--FILE-- +equals($url2, Uri\UriComparisonMode::IncludeFragment)); +var_dump($url2->equals($url1, Uri\UriComparisonMode::IncludeFragment)); + +var_dump($url1->equals($url2, Uri\UriComparisonMode::ExcludeFragment)); +var_dump($url2->equals($url1, Uri\UriComparisonMode::ExcludeFragment)); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/uri/tests/whatwg/equivalence/equals_true_normalization1.phpt b/ext/uri/tests/whatwg/equivalence/equals_true_normalization1.phpt new file mode 100644 index 0000000000000..79736f760be27 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_true_normalization1.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns true - after multiple normalization steps +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/uri/tests/whatwg/equivalence/equals_true_normalization2.phpt b/ext/uri/tests/whatwg/equivalence/equals_true_normalization2.phpt new file mode 100644 index 0000000000000..2f5c767f97586 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_true_normalization2.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns true - after IPv6 normalization +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/uri/tests/whatwg/equivalence/equals_true_normalization3.phpt b/ext/uri/tests/whatwg/equivalence/equals_true_normalization3.phpt new file mode 100644 index 0000000000000..bbcf15512c4c1 --- /dev/null +++ b/ext/uri/tests/whatwg/equivalence/equals_true_normalization3.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\Url equivalence - returns true - after empty path normalization +--FILE-- +equals($url2)); +var_dump($url2->equals($url1)); + +?> +--EXPECT-- +bool(true) +bool(true) 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/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index 69bd6ef9ecdc4..a047c63a708dd 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -595,6 +595,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_string *php_uri_parser_rfc3986_to_string(void const char *pos = zend_memrchr(ZSTR_VAL(uri_string), '#', ZSTR_LEN(uri_string)); if (pos != NULL) { uri_string = zend_string_truncate(uri_string, (pos - ZSTR_VAL(uri_string)), false); + ZSTR_VAL(uri_string)[ZSTR_LEN(uri_string)] = '\0'; } } diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index 2e9ffad22d463..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: diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index fd1a51c5776c3..31a14f219acbf 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -74,6 +74,7 @@ static zend_class_entry *zend_test_ns2_ns_foo_class; static zend_class_entry *zend_test_unit_enum; static zend_class_entry *zend_test_string_enum; static zend_class_entry *zend_test_int_enum; +static zend_class_entry *zend_test_enum_with_interface; static zend_class_entry *zend_test_magic_call; static zend_object_handlers zend_test_class_handlers; @@ -1576,6 +1577,7 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_unit_enum = register_class_ZendTestUnitEnum(); zend_test_string_enum = register_class_ZendTestStringEnum(); zend_test_int_enum = register_class_ZendTestIntEnum(); + zend_test_enum_with_interface = register_class_ZendTestEnumWithInterface(zend_test_interface); zend_test_magic_call = register_class__ZendTestMagicCall(); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index d0c0c64b8b1d0..e93362cebe07f 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -208,6 +208,11 @@ enum ZendTestIntEnum: int { case Baz = -1; } + enum ZendTestEnumWithInterface implements _ZendTestInterface { + case Foo; + case Bar; + } + function zend_trigger_bailout(): never {} function zend_test_array_return(): array {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 683b3b38648b6..681dca973b3fb 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a8dae89983ccbcd5dd36d1cdee736d40af4fd33c */ + * Stub hash: 25b63d5be5822cf0b717150dde07625cdd503c24 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_trigger_bailout, 0, 0, IS_NEVER, 0) ZEND_END_ARG_INFO() @@ -1265,6 +1265,20 @@ static zend_class_entry *register_class_ZendTestIntEnum(void) } #endif +#if (PHP_VERSION_ID >= 80100) +static zend_class_entry *register_class_ZendTestEnumWithInterface(zend_class_entry *class_entry__ZendTestInterface) +{ + zend_class_entry *class_entry = zend_register_internal_enum("ZendTestEnumWithInterface", IS_UNDEF, NULL); + zend_class_implements(class_entry, 1, class_entry__ZendTestInterface); + + zend_enum_add_case_cstr(class_entry, "Foo", NULL); + + zend_enum_add_case_cstr(class_entry, "Bar", NULL); + + return class_entry; +} +#endif + static zend_class_entry *register_class_ZendTestNS_Foo(void) { zend_class_entry ce, *class_entry; 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_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/fastcgi.c b/main/fastcgi.c index 448576a978598..bee1fa47e662e 100644 --- a/main/fastcgi.c +++ b/main/fastcgi.c @@ -944,7 +944,7 @@ static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t coun return n; } -static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count) +static inline ssize_t safe_read(fcgi_request *req, void *buf, size_t count) { int ret; size_t n = 0; diff --git a/main/main.stub.php b/main/main.stub.php index 2732ccd290fa4..af19a7f73731d 100644 --- a/main/main.stub.php +++ b/main/main.stub.php @@ -104,7 +104,7 @@ * @cvalue PHP_SBINDIR */ const PHP_SBINDIR = UNKNOWN; -#ifndef PHP_WIN32 +#ifdef PHP_MANDIR /** * @var string * @cvalue PHP_MANDIR diff --git a/main/main_arginfo.h b/main/main_arginfo.h index 3aa0b07e42c87..068ee4b173185 100644 --- a/main/main_arginfo.h +++ b/main/main_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e8b81aa6f03d36f35def2bb1fcc3563b284a113b */ + * Stub hash: 22b4c7412680888c122886bccd21e3d38953ce33 */ static void register_main_symbols(int module_number) { @@ -24,7 +24,7 @@ static void register_main_symbols(int module_number) REGISTER_STRING_CONSTANT("PHP_PREFIX", PHP_PREFIX, CONST_PERSISTENT); REGISTER_STRING_CONSTANT("PHP_BINDIR", PHP_BINDIR, CONST_PERSISTENT); REGISTER_STRING_CONSTANT("PHP_SBINDIR", PHP_SBINDIR, CONST_PERSISTENT); -#if !defined(PHP_WIN32) +#if defined(PHP_MANDIR) REGISTER_STRING_CONSTANT("PHP_MANDIR", PHP_MANDIR, CONST_PERSISTENT); #endif REGISTER_STRING_CONSTANT("PHP_LIBDIR", PHP_LIBDIR, CONST_PERSISTENT); diff --git a/main/network.c b/main/network.c index 96953531c3761..c4e2ab2e67daa 100644 --- a/main/network.c +++ b/main/network.c @@ -452,9 +452,9 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd, /* Bind to a local IP address. * Returns the bound socket, or -1 on failure. * */ -/* {{{ php_network_bind_socket_to_local_addr */ -php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port, - int socktype, long sockopts, zend_string **error_string, int *error_code +php_socket_t php_network_bind_socket_to_local_addr_ex(const char *host, unsigned port, + int socktype, long sockopts, php_sockvals *sockvals, zend_string **error_string, + int *error_code ) { int num_addrs, n, err = 0; @@ -533,6 +533,35 @@ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned po setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&sockoptval, sizeof(sockoptval)); } #endif +#ifdef SO_KEEPALIVE + if (sockopts & STREAM_SOCKOP_SO_KEEPALIVE) { + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&sockoptval, sizeof(sockoptval)); + } +#endif + + /* Set socket values if provided */ + if (sockvals != NULL) { +#if defined(TCP_KEEPIDLE) + if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) { + setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle)); + } +#elif defined(TCP_KEEPALIVE) + /* macOS uses TCP_KEEPALIVE instead of TCP_KEEPIDLE */ + if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) { + setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle)); + } +#endif +#ifdef TCP_KEEPINTVL + if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPINTVL) { + setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&sockvals->keepalive.keepintvl, sizeof(sockvals->keepalive.keepintvl)); + } +#endif +#ifdef TCP_KEEPCNT + if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPCNT) { + setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (char*)&sockvals->keepalive.keepcnt, sizeof(sockvals->keepalive.keepcnt)); + } +#endif + } n = bind(sock, sa, socklen); @@ -560,7 +589,13 @@ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned po return sock; } -/* }}} */ + +php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port, + int socktype, long sockopts, zend_string **error_string, int *error_code + ) +{ + return php_network_bind_socket_to_local_addr_ex(host, port, socktype, sockopts, NULL, error_string, error_code); +} PHPAPI zend_result php_network_parse_network_address_with_port(const char *addr, size_t addrlen, struct sockaddr *sa, socklen_t *sl) { @@ -766,15 +801,22 @@ PHPAPI int php_network_get_sock_name(php_socket_t sock, * version of the address will be emalloc'd and returned. * */ -/* {{{ php_network_accept_incoming */ -PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, + /* Accept a client connection from a server socket, + * using an optional timeout. + * Returns the peer address in addr/addrlen (it will emalloc + * these, so be sure to efree the result). + * If you specify textaddr, a text-printable + * version of the address will be emalloc'd and returned. + * */ + +PHPAPI php_socket_t php_network_accept_incoming_ex(php_socket_t srvsock, zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen, struct timeval *timeout, zend_string **error_string, int *error_code, - int tcp_nodelay + php_sockvals *sockvals ) { php_socket_t clisock = -1; @@ -798,11 +840,19 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, textaddr, addr, addrlen ); - if (tcp_nodelay) { #ifdef TCP_NODELAY + if (PHP_SOCKVAL_IS_SET(sockvals, PHP_SOCKVAL_TCP_NODELAY)) { + int tcp_nodelay = 1; setsockopt(clisock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcp_nodelay, sizeof(tcp_nodelay)); + } #endif +#ifdef TCP_KEEPALIVE + /* MacOS does not inherit TCP_KEEPALIVE so it needs to be set */ + if (PHP_SOCKVAL_IS_SET(sockvals, PHP_SOCKVAL_TCP_KEEPIDLE)) { + setsockopt(clisock, IPPROTO_TCP, TCP_KEEPALIVE, + (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle)); } +#endif } else { error = php_socket_errno(); } @@ -817,18 +867,31 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, return clisock; } -/* }}} */ + +PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, + zend_string **textaddr, + struct sockaddr **addr, + socklen_t *addrlen, + struct timeval *timeout, + zend_string **error_string, + int *error_code, + int tcp_nodelay + ) +{ + php_sockvals sockvals = { .mask = tcp_nodelay ? PHP_SOCKVAL_TCP_NODELAY : 0 }; + + return php_network_accept_incoming_ex(srvsock, textaddr, addr, addrlen, timeout, error_string, + error_code, &sockvals); +} /* Connect to a remote host using an interruptible connect with optional timeout. * Optionally, the connect can be made asynchronously, which will implicitly * enable non-blocking mode on the socket. * Returns the connected (or connecting) socket, or -1 on failure. * */ - -/* {{{ php_network_connect_socket_to_host */ -php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port, +php_socket_t php_network_connect_socket_to_host_ex(const char *host, unsigned short port, int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string, - int *error_code, const char *bindto, unsigned short bindport, long sockopts + int *error_code, const char *bindto, unsigned short bindport, long sockopts, php_sockvals *sockvals ) { int num_addrs, n, fatal = 0; @@ -952,6 +1015,40 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short } } #endif + +#ifdef SO_KEEPALIVE + { + int val = 1; + if (sockopts & STREAM_SOCKOP_SO_KEEPALIVE) { + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val)); + } + } +#endif + + /* Set socket values if provided */ + if (sockvals != NULL) { +#if defined(TCP_KEEPIDLE) + if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) { + setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle)); + } +#elif defined(TCP_KEEPALIVE) + /* macOS uses TCP_KEEPALIVE instead of TCP_KEEPIDLE */ + if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) { + setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle)); + } +#endif +#ifdef TCP_KEEPINTVL + if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPINTVL) { + setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&sockvals->keepalive.keepintvl, sizeof(sockvals->keepalive.keepintvl)); + } +#endif +#ifdef TCP_KEEPCNT + if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPCNT) { + setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (char*)&sockvals->keepalive.keepcnt, sizeof(sockvals->keepalive.keepcnt)); + } +#endif + } + n = php_network_connect_socket(sock, sa, socklen, asynchronous, timeout ? &working_timeout : NULL, error_string, error_code); @@ -998,7 +1095,15 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short return sock; } -/* }}} */ + +php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port, + int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string, + int *error_code, const char *bindto, unsigned short bindport, long sockopts + ) +{ + return php_network_connect_socket_to_host_ex(host, port, socktype, asynchronous, timeout, + error_string, error_code, bindto, bindport, sockopts, NULL); +} /* {{{ php_any_addr * Fills any (wildcard) address into php_sockaddr_storage diff --git a/main/output.c b/main/output.c index 653b457e9b641..32de70862c2d8 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)); @@ -534,6 +538,10 @@ PHPAPI zend_result php_output_handler_start(php_output_handler *handler) HashTable *rconflicts; php_output_handler_conflict_check_t conflict; + if (!(OG(flags) & PHP_OUTPUT_ACTIVATED)) { + return FAILURE; + } + if (php_output_lock_error(PHP_OUTPUT_HANDLER_START) || !handler) { return FAILURE; } @@ -718,10 +726,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); } } /* }}} */ diff --git a/main/php_network.h b/main/php_network.h index 45e1e1902631d..6700ab42dd3fa 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -124,6 +124,7 @@ typedef int php_socket_t; #define STREAM_SOCKOP_IPV6_V6ONLY_ENABLED (1 << 4) #define STREAM_SOCKOP_TCP_NODELAY (1 << 5) #define STREAM_SOCKOP_SO_REUSEADDR (1 << 6) +#define STREAM_SOCKOP_SO_KEEPALIVE (1 << 7) /* uncomment this to debug poll(2) emulation on systems that have poll(2) */ /* #define PHP_USE_POLL_2_EMULATION 1 */ @@ -266,10 +267,32 @@ typedef struct { } php_sockaddr_storage; #endif +#define PHP_SOCKVAL_TCP_NODELAY (1 << 0) +#define PHP_SOCKVAL_TCP_KEEPIDLE (1 << 1) +#define PHP_SOCKVAL_TCP_KEEPCNT (1 << 2) +#define PHP_SOCKVAL_TCP_KEEPINTVL (1 << 3) + +#define PHP_SOCKVAL_IS_SET(sockvals, opt) ((sockvals)->mask & (opt)) + +typedef struct { + unsigned int mask; + int tcp_nodelay; + struct { + int keepidle; + int keepcnt; + int keepintvl; + } keepalive; +} php_sockvals; + BEGIN_EXTERN_C() PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string); PHPAPI void php_network_freeaddresses(struct sockaddr **sal); +PHPAPI php_socket_t php_network_connect_socket_to_host_ex(const char *host, unsigned short port, + int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string, + int *error_code, const char *bindto, unsigned short bindport, long sockopts, php_sockvals *sockvals + ); + PHPAPI php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port, int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string, int *error_code, const char *bindto, unsigned short bindport, long sockopts @@ -286,10 +309,24 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd, #define php_connect_nonb(sock, addr, addrlen, timeout) \ php_network_connect_socket((sock), (addr), (addrlen), 0, (timeout), NULL, NULL) +PHPAPI php_socket_t php_network_bind_socket_to_local_addr_ex(const char *host, unsigned port, + int socktype, long sockopts, php_sockvals *sockvals, zend_string **error_string, int *error_code + ); + PHPAPI php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port, int socktype, long sockopts, zend_string **error_string, int *error_code ); +PHPAPI php_socket_t php_network_accept_incoming_ex(php_socket_t srvsock, + zend_string **textaddr, + struct sockaddr **addr, + socklen_t *addrlen, + struct timeval *timeout, + zend_string **error_string, + int *error_code, + php_sockvals *sockvals + ); + PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, zend_string **textaddr, struct sockaddr **addr, diff --git a/main/streams/cast.c b/main/streams/cast.c index 4b7183024571b..4dc8ddb5f6a30 100644 --- a/main/streams/cast.c +++ b/main/streams/cast.c @@ -297,7 +297,7 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret, } } - if (php_stream_is_filtered(stream)) { + if (php_stream_is_filtered(stream) && castas != PHP_STREAM_AS_FD_FOR_SELECT) { if (show_err) { php_error_docref(NULL, E_WARNING, "Cannot cast a filtered stream on this system"); } diff --git a/main/streams/memory.c b/main/streams/memory.c index 785109db6582c..2f411ff8e8c9c 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -247,8 +247,8 @@ static int php_stream_memory_set_option(php_stream *stream, int option, int valu size_t old_size = ZSTR_LEN(ms->data); ms->data = zend_string_realloc(ms->data, newsize, 0); memset(ZSTR_VAL(ms->data) + old_size, 0, newsize - old_size); - ZSTR_VAL(ms->data)[ZSTR_LEN(ms->data)] = '\0'; } + ZSTR_VAL(ms->data)[ZSTR_LEN(ms->data)] = '\0'; return PHP_STREAM_OPTION_RETURN_OK; } } diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index db35a9b7952c8..edf1751ec33b5 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -16,7 +16,7 @@ #include "php.h" #include "ext/standard/file.h" -#include "streams/php_streams_int.h" +#include "php_streams.h" #include "php_network.h" #if defined(PHP_WIN32) || defined(__riscos__) @@ -48,8 +48,18 @@ static const php_stream_ops php_stream_udp_socket_ops; #ifdef AF_UNIX static const php_stream_ops php_stream_unix_socket_ops; static const php_stream_ops php_stream_unixdg_socket_ops; -#endif +#define PHP_STREAM_XPORT_IS_UNIX_DG(stream) php_stream_is(stream, &php_stream_unixdg_socket_ops) +#define PHP_STREAM_XPORT_IS_UNIX_ST(stream) php_stream_is(stream, &php_stream_unix_socket_ops) +#define PHP_STREAM_XPORT_IS_UNIX(stream) \ + (PHP_STREAM_XPORT_IS_UNIX_DG(stream) || PHP_STREAM_XPORT_IS_UNIX_ST(stream)) +#else +#define PHP_STREAM_XPORT_IS_UNIX_DG(stream) false +#define PHP_STREAM_XPORT_IS_UNIX_STD(stream) false +#define PHP_STREAM_XPORT_IS_UNIX(stream) false +#endif +#define PHP_STREAM_XPORT_IS_UDP(stream) (php_stream_is(stream, &php_stream_udp_socket_ops)) +#define PHP_STREAM_XPORT_IS_TCP(stream) (!PHP_STREAM_XPORT_IS_UNIX(stream) && !PHP_STREAM_XPORT_IS_UDP(stream)) static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam); @@ -669,18 +679,19 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t * int portno, err; long sockopts = STREAM_SOCKOP_NONE; zval *tmpzval = NULL; + php_sockvals sockvals = {0}; #ifdef AF_UNIX - if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) { + if (PHP_STREAM_XPORT_IS_UNIX(stream)) { struct sockaddr_un unix_addr; - sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0); + sock->socket = socket(PF_UNIX, PHP_STREAM_XPORT_IS_UNIX_ST(stream) ? SOCK_STREAM : SOCK_DGRAM, 0); if (sock->socket == SOCK_ERR) { if (xparam->want_errortext) { char errstr[256]; xparam->outputs.error_text = strpprintf(0, "Failed to create unix%s socket %s", - stream->ops == &php_stream_unix_socket_ops ? "" : "datagram", + PHP_STREAM_XPORT_IS_UNIX_ST(stream) ? "" : " datagram", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return -1; @@ -729,7 +740,7 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t * #endif #ifdef SO_BROADCAST - if (stream->ops == &php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */ + if (PHP_STREAM_XPORT_IS_UDP(stream) /* SO_BROADCAST is only applicable for UDP */ && PHP_STREAM_CONTEXT(stream) && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_broadcast")) != NULL && zend_is_true(tmpzval) @@ -738,9 +749,50 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t * } #endif - sock->socket = php_network_bind_socket_to_local_addr(host, portno, - stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM, +#ifdef SO_KEEPALIVE + if (PHP_STREAM_XPORT_IS_TCP(stream) /* SO_KEEPALIVE is only applicable for TCP */ + && PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_keepalive")) != NULL + && zend_is_true(tmpzval) + ) { + sockopts |= STREAM_SOCKOP_SO_KEEPALIVE; + } +#endif + + /* Parse TCP keepalive parameters - only for TCP streams */ + if (PHP_STREAM_XPORT_IS_TCP(stream)) { +#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) + if (PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepidle")) != NULL + ) { + sockvals.mask |= PHP_SOCKVAL_TCP_KEEPIDLE; + sockvals.keepalive.keepidle = (int)zval_get_long(tmpzval); + } +#endif + +#ifdef TCP_KEEPINTVL + if (PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepintvl")) != NULL + ) { + sockvals.mask |= PHP_SOCKVAL_TCP_KEEPINTVL; + sockvals.keepalive.keepintvl = (int)zval_get_long(tmpzval); + } +#endif + +#ifdef TCP_KEEPCNT + if (PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepcnt")) != NULL + ) { + sockvals.mask |= PHP_SOCKVAL_TCP_KEEPCNT; + sockvals.keepalive.keepcnt = (int)zval_get_long(tmpzval); + } +#endif + } + + sock->socket = php_network_bind_socket_to_local_addr_ex(host, portno, + PHP_STREAM_XPORT_IS_UDP(stream) ? SOCK_DGRAM : SOCK_STREAM, sockopts, + sockvals.mask ? &sockvals : NULL, xparam->want_errortext ? &xparam->outputs.error_text : NULL, &err ); @@ -761,12 +813,13 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ int ret; zval *tmpzval = NULL; long sockopts = STREAM_SOCKOP_NONE; + php_sockvals sockvals = {0}; #ifdef AF_UNIX - if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) { + if (PHP_STREAM_XPORT_IS_UNIX(stream)) { struct sockaddr_un unix_addr; - sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0); + sock->socket = socket(PF_UNIX, PHP_STREAM_XPORT_IS_UNIX_ST(stream) ? SOCK_STREAM : SOCK_DGRAM, 0); if (sock->socket == SOCK_ERR) { if (xparam->want_errortext) { @@ -807,7 +860,7 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ } #ifdef SO_BROADCAST - if (stream->ops == &php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */ + if (PHP_STREAM_XPORT_IS_UDP(stream) /* SO_BROADCAST is only applicable for UDP */ && PHP_STREAM_CONTEXT(stream) && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_broadcast")) != NULL && zend_is_true(tmpzval) @@ -816,11 +869,7 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ } #endif - if (stream->ops != &php_stream_udp_socket_ops /* TCP_NODELAY is only applicable for TCP */ -#ifdef AF_UNIX - && stream->ops != &php_stream_unix_socket_ops - && stream->ops != &php_stream_unixdg_socket_ops -#endif + if (PHP_STREAM_XPORT_IS_TCP(stream) /* TCP_NODELAY is only applicable for TCP */ && PHP_STREAM_CONTEXT(stream) && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL && zend_is_true(tmpzval) @@ -828,19 +877,60 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ sockopts |= STREAM_SOCKOP_TCP_NODELAY; } +#ifdef SO_KEEPALIVE + if (PHP_STREAM_XPORT_IS_TCP(stream) /* SO_KEEPALIVE is only applicable for TCP */ + && PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_keepalive")) != NULL + && zend_is_true(tmpzval) + ) { + sockopts |= STREAM_SOCKOP_SO_KEEPALIVE; + } +#endif + + /* Parse TCP keepalive parameters - only for TCP streams */ + if (PHP_STREAM_XPORT_IS_TCP(stream)) { +#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) + if (PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepidle")) != NULL + ) { + sockvals.mask |= PHP_SOCKVAL_TCP_KEEPIDLE; + sockvals.keepalive.keepidle = (int)zval_get_long(tmpzval); + } +#endif + +#ifdef TCP_KEEPINTVL + if (PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepintvl")) != NULL + ) { + sockvals.mask |= PHP_SOCKVAL_TCP_KEEPINTVL; + sockvals.keepalive.keepintvl = (int)zval_get_long(tmpzval); + } +#endif + +#ifdef TCP_KEEPCNT + if (PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepcnt")) != NULL + ) { + sockvals.mask |= PHP_SOCKVAL_TCP_KEEPCNT; + sockvals.keepalive.keepcnt = (int)zval_get_long(tmpzval); + } +#endif + } + /* Note: the test here for php_stream_udp_socket_ops is important, because we * want the default to be TCP sockets so that the openssl extension can * re-use this code. */ - sock->socket = php_network_connect_socket_to_host(host, portno, - stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM, + sock->socket = php_network_connect_socket_to_host_ex(host, portno, + PHP_STREAM_XPORT_IS_UDP(stream) ? SOCK_DGRAM : SOCK_STREAM, xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC, xparam->inputs.timeout, xparam->want_errortext ? &xparam->outputs.error_text : NULL, &err, bindto, bindport, - sockopts + sockopts, + sockvals.mask ? &sockvals : NULL ); ret = sock->socket == -1 ? -1 : 0; @@ -868,25 +958,32 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock, php_stream_xport_param *xparam STREAMS_DC) { - bool nodelay = 0; + php_sockvals sockvals = {0}; zval *tmpzval = NULL; xparam->outputs.client = NULL; - if ((NULL != PHP_STREAM_CONTEXT(stream)) && - (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL && - zend_is_true(tmpzval)) { - nodelay = 1; + if (PHP_STREAM_CONTEXT(stream)) { + tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay"); + if (tmpzval != NULL && zend_is_true(tmpzval)) { + sockvals.mask |= PHP_SOCKVAL_TCP_NODELAY; + sockvals.tcp_nodelay = 1; + } + tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepidle"); + if (tmpzval != NULL) { + sockvals.mask |= PHP_SOCKVAL_TCP_KEEPIDLE; + sockvals.keepalive.keepidle = (int)zval_get_long(tmpzval); + } } - php_socket_t clisock = php_network_accept_incoming(sock->socket, + php_socket_t clisock = php_network_accept_incoming_ex(sock->socket, xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, xparam->want_addr ? &xparam->outputs.addr : NULL, xparam->want_addr ? &xparam->outputs.addrlen : NULL, xparam->inputs.timeout, xparam->want_errortext ? &xparam->outputs.error_text : NULL, &xparam->outputs.error_code, - nodelay); + &sockvals); if (clisock != SOCK_ERR) { php_netstream_data_t *clisockdata = (php_netstream_data_t*) emalloc(sizeof(*clisockdata)); diff --git a/run-tests.php b/run-tests.php index d0befa3738df1..d7cd07f7c6637 100755 --- a/run-tests.php +++ b/run-tests.php @@ -1821,8 +1821,8 @@ function run_test(string $php, $file, array $env): string $skipCache = new SkipCache($enableSkipCache, $cfg['keep']['skip']); } - $orig_php = $php; $php = escapeshellarg($php); + $orig_php = $php; $retried = false; retry: diff --git a/sapi/fpm/fpm/events/kqueue.c b/sapi/fpm/fpm/events/kqueue.c index 09f5da12799be..21939d3414182 100644 --- a/sapi/fpm/fpm/events/kqueue.c +++ b/sapi/fpm/fpm/events/kqueue.c @@ -150,7 +150,7 @@ static int fpm_event_kqueue_wait(struct fpm_event_queue_s *queue, unsigned long /* }}} */ /* - * Add a FD to to kevent queue + * Add a FD to kevent queue */ static int fpm_event_kqueue_add(struct fpm_event_s *ev) /* {{{ */ { diff --git a/sapi/fuzzer/fuzzer-execute-common.h b/sapi/fuzzer/fuzzer-execute-common.h index 338c771e551a3..ef2ff4ee79bab 100644 --- a/sapi/fuzzer/fuzzer-execute-common.h +++ b/sapi/fuzzer/fuzzer-execute-common.h @@ -134,7 +134,6 @@ ZEND_ATTRIBUTE_UNUSED static void create_file(void) { ZEND_ATTRIBUTE_UNUSED static void opcache_invalidate(void) { steps_left = MAX_STEPS; - zend_exception_save(); zval retval, args[2]; zend_function *fn = zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("opcache_invalidate")); ZEND_ASSERT(fn != NULL); @@ -145,5 +144,4 @@ ZEND_ATTRIBUTE_UNUSED static void opcache_invalidate(void) { ZEND_ASSERT(Z_TYPE(retval) == IS_TRUE); zval_ptr_dtor(&args[0]); zval_ptr_dtor(&retval); - zend_exception_restore(); } diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 7215888cb25ec..9566c1abd4eec 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -716,10 +716,6 @@ static inline void phpdbg_handle_exception(void) /* {{{ */ phpdbg_writeln("%s", ZSTR_VAL(msg)); zend_string_release(msg); - if (EG(prev_exception)) { - OBJ_RELEASE(EG(prev_exception)); - EG(prev_exception) = 0; - } OBJ_RELEASE(ex); EG(opline_before_exception) = NULL; @@ -876,7 +872,6 @@ PHPDBG_COMMAND(run) /* {{{ */ } zend_end_try(); if (restore) { - zend_exception_restore(); zend_try { zend_try_exception_handler(); PHPDBG_G(in_execution) = 1; diff --git a/scripts/dev/bless_tests.php b/scripts/dev/bless_tests.php index 58baeac402462..7493a504729c4 100755 --- a/scripts/dev/bless_tests.php +++ b/scripts/dev/bless_tests.php @@ -124,7 +124,7 @@ function insertOutput(string $phpt, string $out): string { } /** - * Implementation of the the Myers diff algorithm. + * Implementation of the Myers diff algorithm. * * Myers, Eugene W. "An O (ND) difference algorithm and its variations." * Algorithmica 1.1 (1986): 251-266. diff --git a/tests/basic/gh20858.phpt b/tests/basic/gh20858.phpt new file mode 100644 index 0000000000000..0ac13fdfa936a --- /dev/null +++ b/tests/basic/gh20858.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-20858 Null pointer dereference in php_mail_detect_multiple_crlf via error_log +--INI-- +sendmail_path={MAIL:{PWD}/gh20858.eml} +mail.add_x_header=off +--FILE-- +\n"; +$headers .= "Cc: test \n"; +$headers .= 'X-Mailer: PHP/' . phpversion(); + +// Send mail with nothing set +var_dump(error_log("Error message", 1, null)); + +// Send mail with destination set +var_dump(error_log("Error message with dest", 1, "default@domain.tld", null)); + +// Send mail with custom headers and no mailer to +var_dump(error_log("Error message cust headers", 1, null, $headers)); + +// Send mail with destination set + custom headers +var_dump(error_log("Error message with both", 1, "default@domain.tld", $headers)); +?> +--CLEAN-- + +--EXPECTF-- +bool(false) +bool(true) +bool(false) +bool(true) diff --git a/tests/output/gh20352.phpt b/tests/output/gh20352.phpt new file mode 100644 index 0000000000000..3074add99d360 --- /dev/null +++ b/tests/output/gh20352.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-20352 (UAF in php_output_handler_free via re-entrant ob_start() during error deactivation) +--FILE-- + +--EXPECTF-- +%r(Notice: ob_start\(\): Failed to create buffer in [^\r\n]+ on line \d+\r?\n(\r?\n)?)+%r +Notice: ob_start(): Failed to create buffer in %s on line %d + +Fatal error: ob_start(): Cannot use output buffering in output buffering display handlers in %s on line %d diff --git a/tests/output/gh20837.phpt b/tests/output/gh20837.phpt new file mode 100644 index 0000000000000..0952e4ef7b910 --- /dev/null +++ b/tests/output/gh20837.phpt @@ -0,0 +1,23 @@ +--TEST-- +ob_start(): NULL dereference when calling ob_start() in shutdown function triggered by bailout in php_output_lock_error() +--FILE-- + +--EXPECTF-- +Fatal error: ob_start(): Cannot use output buffering in output buffering display handlers in %s on line %d + +Notice: ob_start(): Failed to create buffer in %s on line %d diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 403f0aa6efbfe..1efdc57bca4da 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -241,7 +241,7 @@ ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c \ zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_observer.c zend_system_id.c \ zend_enum.c zend_fibers.c zend_atomic.c zend_hrtime.c zend_frameless_function.c zend_property_hooks.c \ - zend_lazy_objects.c"); + zend_lazy_objects.c zend_partial.c"); ADD_SOURCES("Zend\\Optimizer", "zend_optimizer.c pass1.c pass3.c optimize_func_calls.c block_pass.c optimize_temp_vars_5.c nop_removal.c compact_literals.c zend_cfg.c zend_dfg.c dfa_pass.c zend_ssa.c zend_inference.c zend_func_info.c zend_call_graph.c zend_dump.c escape_analysis.c compact_vars.c dce.c sccp.c scdf.c"); var PHP_ASSEMBLER = PATH_PROG({ diff --git a/win32/sendmail.c b/win32/sendmail.c index 80dff3f390772..f267d1fae85ab 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,16 +112,16 @@ 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); -/* This function is meant to unify the headers passed to to mail() +/* This function is meant to unify the headers passed to mail() * This means, use PCRE to transform single occurrences of \n or \r in \r\n * As a second step we also eliminate all \r\n occurrences which are: * 1) At the start of the header @@ -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 */